diff --git a/docker-compose-multi-instance.yml b/docker-compose-multi-instance.yml index 734bc8cc..0092b5c6 100644 --- a/docker-compose-multi-instance.yml +++ b/docker-compose-multi-instance.yml @@ -90,7 +90,7 @@ services: - ./docker/mongo/b_create_indexes.js:/docker-entrypoint-initdb.d/b_create_indexes.js healthcheck: test: | - test $$(mongosh --username ${MONGO_INITDB_ROOT_USERNAME} --password ${MONGO_INITDB_ROOT_PASSWORD} --quiet --eval "try { rs.initiate({ _id: 'rs0', members: [{ _id: 0, host: '${DB_HOST_IP}' }] }).ok } catch (_) { rs.status().ok }") -eq 1 + test $$(mongosh --username ${MONGO_INITDB_ROOT_USERNAME} --password ${MONGO_INITDB_ROOT_PASSWORD} --quiet --eval "db.runCommand({ping:1}).ok") -eq 1 interval: 10s start_period: 30s entrypoint: diff --git a/docker-compose.yml b/docker-compose.yml index 8a610a91..1baddcc8 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -77,13 +77,13 @@ services: volumes: - mongodb_data_container:/data/db - ./docker/mongo/manage-volume-cron:/docker-entrypoint-initdb.d/manage-volume-cron - - ./docker/mongo/keyfile.txt:/data/keyfile.txt + - ./docker/mongo/keyfile.txt:/data/keyfile-import.txt - ./docker/mongo/a_init_replicas.js:/docker-entrypoint-initdb.d/a_init_replicas.js - ./docker/mongo/b_create_indexes.js:/docker-entrypoint-initdb.d/b_create_indexes.js - ./docker/mongo/manage_volume.js:/docker-entrypoint-initdb.d/manage_volume.js healthcheck: test: | - test $$(mongosh --username ${MONGO_INITDB_ROOT_USERNAME} --password ${MONGO_INITDB_ROOT_PASSWORD} --quiet --eval "try { rs.initiate({ _id: 'rs0', members: [{ _id: 0, host: '${DB_HOST_IP}' }] }).ok } catch (_) { rs.status().ok }") -eq 1 + test $$(mongosh --username ${MONGO_INITDB_ROOT_USERNAME} --password ${MONGO_INITDB_ROOT_PASSWORD} --quiet --eval "db.runCommand({ping:1}).ok") -eq 1 interval: 10s start_period: 60s entrypoint: @@ -98,6 +98,7 @@ services: dos2unix /etc/cron.d/manage-volume-cron chmod 644 /etc/cron.d/manage-volume-cron systemctl restart cron + cp /data/keyfile-import.txt /data/keyfile.txt chmod 400 /data/keyfile.txt chown 999:999 /data/keyfile.txt diff --git a/docker/connect/connect_start.sh b/docker/connect/connect_start.sh index 03428ed1..9849f9a4 100644 --- a/docker/connect/connect_start.sh +++ b/docker/connect/connect_start.sh @@ -16,6 +16,8 @@ declare -A OdeRawEncodedBSMJson=([name]="topic.OdeRawEncodedBSMJson" [collection [convert_timestamp]=false [timefield]="" [use_key]=false [key]="" [add_timestamp]=true) declare -A OdeBsmJson=([name]="topic.OdeBsmJson" [collection]="OdeBsmJson" [convert_timestamp]=false [timefield]="" [use_key]=false [key]="" [add_timestamp]=true) +declare -A ProcessedBsm=([name]="topic.ProcessedBsm" [collection]="ProcessedBsm" + [convert_timestamp]=false [timefield]="" [use_key]=false [key]="" [add_timestamp]=true) # Record Map Data declare -A OdeMapJson=([name]="topic.DeduplicatedOdeMapJson" [collection]="OdeMapJson" @@ -89,6 +91,9 @@ declare -A CmMapMinimumDataEvents=([name]="topic.CmMapMinimumDataEvents" [collec [convert_timestamp]=true [timefield]="eventGeneratedAt" [use_key]=false [key]="" [add_timestamp]=false) declare -A CmSpatBroadcastRateEvents=([name]="topic.CmSpatBroadcastRateEvents" [collection]="CmSpatBroadcastRateEvents" [convert_timestamp]=true [timefield]="eventGeneratedAt" [use_key]=false [key]="" [add_timestamp]=false) +declare -A CmTimestampDeltaEvent=([name]="topic.CmTimestampDeltaEvent" [collection]="CmTimestampDeltaEvent" + [convert_timestamp]=true [timefield]="eventGeneratedAt" [use_key]=false [key]="" [add_timestamp]=false) + # Record BSM Events declare -A CmBsmEvents=([name]="topic.CmBsmEvents" [collection]="CmBsmEvents" @@ -125,6 +130,8 @@ declare -A CmStopLineStopNotification=([name]="topic.CmStopLineStopNotification" [convert_timestamp]=true [timefield]="notificationGeneratedAt" [use_key]=true [key]="key" [add_timestamp]=false) declare -A CmStopLinePassageNotification=([name]="topic.CmStopLinePassageNotification" [collection]="CmStopLinePassageNotification" [convert_timestamp]=true [timefield]="notificationGeneratedAt" [use_key]=true [key]="key" [add_timestamp]=false) +declare -A CmTimestampDeltaNotification=([name]="topic.CmTimestampDeltaNotification" [collection]="CmTimestampDeltaNotification" + [convert_timestamp]=true [timefield]="notificationGeneratedAt" [use_key]=true [key]="key" [add_timestamp]=false) function createSink() { local -n topic=$1 @@ -209,6 +216,7 @@ function createSink() { createSink OdeRawEncodedBSMJson createSink OdeBsmJson +createSink ProcessedBsm createSink OdeMapJson createSink ProcessedMap @@ -245,6 +253,7 @@ createSink CmSpatMinimumDataEvents createSink CmMapBroadcastRateEvents createSink CmMapMinimumDataEvents createSink CmSpatBroadcastRateEvents +createSink CmTimestampDeltaEvent createSink CmBsmEvents @@ -262,6 +271,7 @@ createSink CmSignalGroupAlignmentNotification createSink CmNotification createSink CmStopLineStopNotification createSink CmStopLinePassageNotification +createSink CmTimestampDeltaNotification echo "----------------------------------" diff --git a/docker/mongo/b_create_indexes.js b/docker/mongo/b_create_indexes.js index fb294f5f..b861d9f7 100644 --- a/docker/mongo/b_create_indexes.js +++ b/docker/mongo/b_create_indexes.js @@ -66,6 +66,7 @@ const collections = [ // GeoJson Converter Data {name: "ProcessedMap", ttlField: "recordGeneratedAt", timeField: "properties.timeStamp", intersectionField: "properties.intersectionId"}, {name: "ProcessedSpat", ttlField: "recordGeneratedAt", timeField: "utcTimeStamp", intersectionField: "intersectionId"}, + {name: "ProcessedBsm", ttlField: "recordGeneratedAt", timeField: "timeStamp", geoSpatialField: "features.geometry.coordinates"}, // Conflict Monitor Events { name: "CmStopLineStopEvent", ttlField: "eventGeneratedAt", timeField: "eventGeneratedAt", intersectionField: "intersectionID" }, @@ -145,6 +146,7 @@ do { createTimeIntersectionIndex(collection); createTimeRsuIpIndex(collection); createTimeIndex(collection); + createGeoSpatialIndex(collection); }else{ missing_collection_count++; console.log("Collection " + collection.name + " does not exist yet"); @@ -318,6 +320,38 @@ function createTimeIntersectionIndex(collection){ } } +function createGeoSpatialIndex(collection){ + if(geoSpatialIndexExists(collection)){ + return; + } + + if(collection.hasOwnProperty("timeField") && collection.timeField != null && collection.hasOwnProperty("geoSpatialField") && collection.geoSpatialField != null){ + const collectionName = collection.name; + const timeField = collection.timeField; + const geoSpatialField = collection.geoSpatialField; + console.log("Creating GeoSpatial index for " + collectionName); + + var indexJson = {}; + indexJson[geoSpatialField] = "2dsphere"; + indexJson[timeField] = -1; + + + try { + db[collectionName].createIndex(indexJson); + console.log("Created time geospatial index for " + collectionName + " using the field: " + timeField + " as the timestamp and : " + geoSpatialField + " as the GeoSpatial Field"); + } catch (err) { + db.runCommand({ + "collMod": collectionName, + "index": { + keyPattern: indexJson + } + }); + console.log("Updated time geospatial index for " + collectionName + " using the field: " + timeField + " as the timestamp and : " + geoSpatialField + " as the GeoSpatial Field"); + } + } + +} + function ttlIndexExists(collection) { return db[collection.name].getIndexes().find((idx) => idx.hasOwnProperty("expireAfterSeconds")) !== undefined; } @@ -333,3 +367,7 @@ function timeRsuIpIndexExists(collection){ function timeIndexExists(collection){ return db[collection.name].getIndexes().find((idx) => idx.name == collection.timeField + "_-1") !== undefined; } + +function geoSpatialIndexExists(collection){ + return db[collection.name].getIndexes().find((idx) => idx.name == collection.geoSpatialField + "_2dsphere_timeStamp_-1") !== undefined; +} diff --git a/docs/KafkaStreamsVisualizations/README.md b/docs/KafkaStreamsVisualizations/README.md new file mode 100644 index 00000000..7e98e292 --- /dev/null +++ b/docs/KafkaStreamsVisualizations/README.md @@ -0,0 +1,75 @@ +# Kafka Streams Visualization Tools + +Endpoints for describing Kafka Streams internals are available at: + +http://localhost:8082/health/topologies + +with the Conflict Monitor running in Docker. + +## Topology Overviews + +The `topologies/simple` endpoints produce GraphViz `dot` files that represent the input and output topics of topologies, connections between topologies, and associated state stores. + +To visualize the current state of all Kafka Streams download the `all.dot` file from: + +http://localhost:8082/health/topologies/simple/all + +To see a simple view of the inputs and outpus of a single topology select one of the `topologies/simple` endpoints, for example: + +http://localhost:8082/health/topologies/simple/mapValidation + +To create images from the dot files, install the GraphViz command line tool from: + +https://graphviz.org/download/ + +and run the `dot` command, for example: + +Create SVG: +```bash +dot -Tsvg all.dot > all.svg +``` + +Create PNG: +```bash +dot -Tpng all.dot > all.png +``` + +### Examples +#### MapValidation Topology Overview +![MAP Validation Topology Overview](./mapValidation.svg) + +#### Spat Validation Topology Overview +![SPaT Validation Topology Overview](./spatValidation.svg) + +#### All Topologies Overview + +Open the image in a separate tab to zoom in + +![All Topologies Overview](./all.svg) + + +## Topology Details + +To view detailed internals for one topology select one of the `topologies/detail` endpoints, for example: + +http://localhost:8082/health/topologies/detail/mapValidation + +Save the response to a text file. This file is the result of calling the Topology.describe() method. This format can be visualized using the online Kafka Streams Topology Visualizer here: + +https://zz85.github.io/kafka-streams-viz/ + +#### Example: MAP Validation Topology Details +![MAP Validation detailed topology](mapValidation_detail.jpg) + + + + + + + + + + + + + diff --git a/docs/KafkaStreamsVisualizations/all.svg b/docs/KafkaStreamsVisualizations/all.svg new file mode 100644 index 00000000..580266ac --- /dev/null +++ b/docs/KafkaStreamsVisualizations/all.svg @@ -0,0 +1,1700 @@ + + + + + + +G + + + +bsmEvent_subtopology_0 + +bsmEvent subtopology 0 + + + +bsmEvent_bsm_event_state_store + + +bsm-event-state-store + + + +bsmEvent_subtopology_0->bsmEvent_bsm_event_state_store + + + + + +topic_CmBsmEvents + +topic.CmBsmEvents + + + +bsmEvent_subtopology_0->topic_CmBsmEvents + + + + + +topic_CmBsmIntersection + +topic.CmBsmIntersection + + + +bsmEvent_subtopology_0->topic_CmBsmIntersection + + + + + +topic_CmBsmJsonRepartition + +topic.CmBsmJsonRepartition + + + +topic_CmBsmJsonRepartition->bsmEvent_subtopology_0 + + + + + +bsmRevisionCounter_subtopology_0 + +bsmRevisionCounter subtopology 0 + + + +topic_CmBsmJsonRepartition->bsmRevisionCounter_subtopology_0 + + + + + +bsmEvent_bsm_event_state_store->bsmEvent_subtopology_0 + + + + + +intersectionEvent_subtopology_4 + +intersectionEvent subtopology 4 + + + +topic_CmBsmEvents->intersectionEvent_subtopology_4 + + + + + +intersectionEvent_subtopology_0 + +intersectionEvent subtopology 0 + + + +topic_CmBsmIntersection->intersectionEvent_subtopology_0 + + + + + +bsmRevisionCounter_KSTREAM_AGGREGATE_STATE_STORE_0000000001 + + +KSTREAM-AGGREGATE-STATE-STORE-0000000001 + + + +bsmRevisionCounter_subtopology_0->bsmRevisionCounter_KSTREAM_AGGREGATE_STATE_STORE_0000000001 + + + + + +topic_CmBsmRevisionCounterEvents + +topic.CmBsmRevisionCounterEvents + + + +bsmRevisionCounter_subtopology_0->topic_CmBsmRevisionCounterEvents + + + + + +bsmRevisionCounter_KSTREAM_AGGREGATE_STATE_STORE_0000000001->bsmRevisionCounter_subtopology_0 + + + + + +config_subtopology_global + +config subtopology global + + + +config_default_config + + +default-config + + + +config_subtopology_global->config_default_config + + + + + +config_intersection_config + + +intersection-config + + + +config_subtopology_global->config_intersection_config + + + + + +topic_CmMergedConfigTable + +topic.CmMergedConfigTable + + + +topic_CmMergedConfigTable->config_subtopology_global + + + + + +config_default_config->config_subtopology_global + + + + + +topic_CmIntersectionConfigTable + +topic.CmIntersectionConfigTable + + + +topic_CmIntersectionConfigTable->config_subtopology_global + + + + + +config_intersection_config->config_subtopology_global + + + + + +config_subtopology_0 + +config subtopology 0 + + + +config_subtopology_0->topic_CmMergedConfigTable + + + + + +config_topic_CmDefaultConfigTable_STATE_STORE_0000000000 + + +topic.CmDefaultConfigTable-STATE-STORE-0000000000 + + + +config_subtopology_0->config_topic_CmDefaultConfigTable_STATE_STORE_0000000000 + + + + + +config_topic_CmCustomConfigTable_STATE_STORE_0000000003 + + +topic.CmCustomConfigTable-STATE-STORE-0000000003 + + + +config_subtopology_0->config_topic_CmCustomConfigTable_STATE_STORE_0000000003 + + + + + +topic_CmDefaultConfigTable + +topic.CmDefaultConfigTable + + + +topic_CmDefaultConfigTable->config_subtopology_0 + + + + + +topic_CmCustomConfigTable + +topic.CmCustomConfigTable + + + +topic_CmCustomConfigTable->config_subtopology_0 + + + + + +config_topic_CmDefaultConfigTable_STATE_STORE_0000000000->config_subtopology_0 + + + + + +config_topic_CmCustomConfigTable_STATE_STORE_0000000003->config_subtopology_0 + + + + + +connectionOfTravelAssessment_subtopology_0 + +connectionOfTravelAssessment subtopology 0 + + + +connectionOfTravelAssessment_connectionOfTravelAssessments + + +connectionOfTravelAssessments + + + +connectionOfTravelAssessment_subtopology_0->connectionOfTravelAssessment_connectionOfTravelAssessments + + + + + +ConnectionOfTravelNotification_repartition + +ConnectionOfTravelNotification-repartition + + + +connectionOfTravelAssessment_subtopology_0->ConnectionOfTravelNotification_repartition + + + + + +topic_CmConnectionOfTravelAssessment + +topic.CmConnectionOfTravelAssessment + + + +connectionOfTravelAssessment_subtopology_0->topic_CmConnectionOfTravelAssessment + + + + + +topic_CmConnectionOfTravelEvent + +topic.CmConnectionOfTravelEvent + + + +topic_CmConnectionOfTravelEvent->connectionOfTravelAssessment_subtopology_0 + + + + + +connectionOfTravelAssessment_connectionOfTravelAssessments->connectionOfTravelAssessment_subtopology_0 + + + + + +connectionOfTravelAssessment_subtopology_1 + +connectionOfTravelAssessment subtopology 1 + + + +ConnectionOfTravelNotification_repartition->connectionOfTravelAssessment_subtopology_1 + + + + + +connectionOfTravelAssessment_ConnectionOfTravelNotification + + +ConnectionOfTravelNotification + + + +connectionOfTravelAssessment_subtopology_1->connectionOfTravelAssessment_ConnectionOfTravelNotification + + + + + +topic_CmConnectionOfTravelNotification + +topic.CmConnectionOfTravelNotification + + + +connectionOfTravelAssessment_subtopology_1->topic_CmConnectionOfTravelNotification + + + + + +connectionOfTravelAssessment_ConnectionOfTravelNotification->connectionOfTravelAssessment_subtopology_1 + + + + + +notification_subtopology_0 + +notification subtopology 0 + + + +topic_CmConnectionOfTravelNotification->notification_subtopology_0 + + + + + +intersectionEvent_subtopology_global + +intersectionEvent subtopology global + + + +intersectionEvent_MapSpatialIndexStore + + +MapSpatialIndexStore + + + +intersectionEvent_subtopology_global->intersectionEvent_MapSpatialIndexStore + + + + + +topic_CmMapBoundingBox + +topic.CmMapBoundingBox + + + +topic_CmMapBoundingBox->intersectionEvent_subtopology_global + + + + + +intersectionEvent_MapSpatialIndexStore->intersectionEvent_subtopology_global + + + + + +intersectionEvent_BsmWindowStore + + +BsmWindowStore + + + +intersectionEvent_subtopology_0->intersectionEvent_BsmWindowStore + + + + + +intersectionEvent_BsmWindowStore->intersectionEvent_subtopology_0 + + + + + +intersectionEvent_subtopology_1 + +intersectionEvent subtopology 1 + + + +intersectionEvent_SpatWindowStore + + +SpatWindowStore + + + +intersectionEvent_subtopology_1->intersectionEvent_SpatWindowStore + + + + + +topic_ProcessedSpat + +topic.ProcessedSpat + + + +topic_ProcessedSpat->intersectionEvent_subtopology_1 + + + + + +mapSpatAlignment_subtopology_0 + +mapSpatAlignment subtopology 0 + + + +topic_ProcessedSpat->mapSpatAlignment_subtopology_0 + + + + + +spatRevisionCounter_subtopology_0 + +spatRevisionCounter subtopology 0 + + + +topic_ProcessedSpat->spatRevisionCounter_subtopology_0 + + + + + +spatTimeChangeDetails_subtopology_0 + +spatTimeChangeDetails subtopology 0 + + + +topic_ProcessedSpat->spatTimeChangeDetails_subtopology_0 + + + + + +spatValidation_subtopology_0 + +spatValidation subtopology 0 + + + +topic_ProcessedSpat->spatValidation_subtopology_0 + + + + + +intersectionEvent_SpatWindowStore->intersectionEvent_subtopology_1 + + + + + +intersectionEvent_subtopology_2 + +intersectionEvent subtopology 2 + + + +intersectionEvent_subtopology_2->topic_CmMapBoundingBox + + + + + +intersectionEvent_ProcessedMapWindowStore + + +ProcessedMapWindowStore + + + +intersectionEvent_subtopology_2->intersectionEvent_ProcessedMapWindowStore + + + + + +topic_ProcessedMap + +topic.ProcessedMap + + + +topic_ProcessedMap->intersectionEvent_subtopology_2 + + + + + +mapRevisionCounter_subtopology_0 + +mapRevisionCounter subtopology 0 + + + +topic_ProcessedMap->mapRevisionCounter_subtopology_0 + + + + + +topic_ProcessedMap->mapSpatAlignment_subtopology_0 + + + + + +mapValidation_subtopology_0 + +mapValidation subtopology 0 + + + +topic_ProcessedMap->mapValidation_subtopology_0 + + + + + +intersectionEvent_ProcessedMapWindowStore->intersectionEvent_subtopology_2 + + + + + +intersectionEvent_subtopology_4->topic_CmBsmEvents + + + + + +intersectionEvent_subtopology_4->topic_CmConnectionOfTravelEvent + + + + + +intersectionEvent_bsm_event_deduplicate_store + + +bsm-event-deduplicate-store + + + +intersectionEvent_subtopology_4->intersectionEvent_bsm_event_deduplicate_store + + + + + +topic_CmLaneDirectionOfTravelEvent + +topic.CmLaneDirectionOfTravelEvent + + + +intersectionEvent_subtopology_4->topic_CmLaneDirectionOfTravelEvent + + + + + +topic_CmStopLinePassageEvent + +topic.CmStopLinePassageEvent + + + +intersectionEvent_subtopology_4->topic_CmStopLinePassageEvent + + + + + +topic_CmStopLineStopEvent + +topic.CmStopLineStopEvent + + + +intersectionEvent_subtopology_4->topic_CmStopLineStopEvent + + + + + +intersectionEvent_bsm_event_deduplicate_store->intersectionEvent_subtopology_4 + + + + + +laneDirectionOfTravelAssessment_subtopology_0 + +laneDirectionOfTravelAssessment subtopology 0 + + + +topic_CmLaneDirectionOfTravelEvent->laneDirectionOfTravelAssessment_subtopology_0 + + + + + +signalStateEventAssessment_subtopology_0 + +signalStateEventAssessment subtopology 0 + + + +topic_CmStopLinePassageEvent->signalStateEventAssessment_subtopology_0 + + + + + +stopLineStopAssessment_subtopology_0 + +stopLineStopAssessment subtopology 0 + + + +topic_CmStopLineStopEvent->stopLineStopAssessment_subtopology_0 + + + + + +laneDirectionOfTravelAssessment_laneDirectionOfTravelEventAssessments + + +laneDirectionOfTravelEventAssessments + + + +laneDirectionOfTravelAssessment_subtopology_0->laneDirectionOfTravelAssessment_laneDirectionOfTravelEventAssessments + + + + + +topic_CmLaneDirectionOfTravelAssessment + +topic.CmLaneDirectionOfTravelAssessment + + + +laneDirectionOfTravelAssessment_subtopology_0->topic_CmLaneDirectionOfTravelAssessment + + + + + +LaneDirectionOfTravelAssessmentNotification_repartition + +LaneDirectionOfTravelAssessmentNotification-repartition + + + +laneDirectionOfTravelAssessment_subtopology_0->LaneDirectionOfTravelAssessmentNotification_repartition + + + + + +laneDirectionOfTravelAssessment_laneDirectionOfTravelEventAssessments->laneDirectionOfTravelAssessment_subtopology_0 + + + + + +laneDirectionOfTravelAssessment_subtopology_1 + +laneDirectionOfTravelAssessment subtopology 1 + + + +LaneDirectionOfTravelAssessmentNotification_repartition->laneDirectionOfTravelAssessment_subtopology_1 + + + + + +laneDirectionOfTravelAssessment_LaneDirectionOfTravelAssessmentNotification + + +LaneDirectionOfTravelAssessmentNotification + + + +laneDirectionOfTravelAssessment_subtopology_1->laneDirectionOfTravelAssessment_LaneDirectionOfTravelAssessmentNotification + + + + + +topic_CmLaneDirectionOfTravelNotification + +topic.CmLaneDirectionOfTravelNotification + + + +laneDirectionOfTravelAssessment_subtopology_1->topic_CmLaneDirectionOfTravelNotification + + + + + +laneDirectionOfTravelAssessment_LaneDirectionOfTravelAssessmentNotification->laneDirectionOfTravelAssessment_subtopology_1 + + + + + +topic_CmLaneDirectionOfTravelNotification->notification_subtopology_0 + + + + + +mapRevisionCounter_KSTREAM_AGGREGATE_STATE_STORE_0000000001 + + +KSTREAM-AGGREGATE-STATE-STORE-0000000001 + + + +mapRevisionCounter_subtopology_0->mapRevisionCounter_KSTREAM_AGGREGATE_STATE_STORE_0000000001 + + + + + +topic_CmMapRevisionCounterEvents + +topic.CmMapRevisionCounterEvents + + + +mapRevisionCounter_subtopology_0->topic_CmMapRevisionCounterEvents + + + + + +mapRevisionCounter_KSTREAM_AGGREGATE_STATE_STORE_0000000001->mapRevisionCounter_subtopology_0 + + + + + +mapSpatAlignment_topic_ProcessedMap_STATE_STORE_0000000001 + + +topic.ProcessedMap-STATE-STORE-0000000001 + + + +mapSpatAlignment_subtopology_0->mapSpatAlignment_topic_ProcessedMap_STATE_STORE_0000000001 + + + + + +KSTREAM_TOTABLE_0000000006_repartition + +KSTREAM-TOTABLE-0000000006-repartition + + + +mapSpatAlignment_subtopology_0->KSTREAM_TOTABLE_0000000006_repartition + + + + + +topic_CmSignalGroupAlignmentEvents + +topic.CmSignalGroupAlignmentEvents + + + +mapSpatAlignment_subtopology_0->topic_CmSignalGroupAlignmentEvents + + + + + +topic_CmSignalStateConflictEvents + +topic.CmSignalStateConflictEvents + + + +mapSpatAlignment_subtopology_0->topic_CmSignalStateConflictEvents + + + + + +SignalGroupAlignmentNotification_repartition + +SignalGroupAlignmentNotification-repartition + + + +mapSpatAlignment_subtopology_0->SignalGroupAlignmentNotification_repartition + + + + + +SignalStateConflictNotification_repartition + +SignalStateConflictNotification-repartition + + + +mapSpatAlignment_subtopology_0->SignalStateConflictNotification_repartition + + + + + +spat_maps_joined_rsu_repartition + +spat-maps-joined-rsu-repartition + + + +mapSpatAlignment_subtopology_0->spat_maps_joined_rsu_repartition + + + + + +mapSpatAlignment_topic_ProcessedMap_STATE_STORE_0000000001->mapSpatAlignment_subtopology_0 + + + + + +mapSpatAlignment_subtopology_1 + +mapSpatAlignment subtopology 1 + + + +KSTREAM_TOTABLE_0000000006_repartition->mapSpatAlignment_subtopology_1 + + + + + +mapSpatAlignment_subtopology_3 + +mapSpatAlignment subtopology 3 + + + +SignalGroupAlignmentNotification_repartition->mapSpatAlignment_subtopology_3 + + + + + +mapSpatAlignment_subtopology_4 + +mapSpatAlignment subtopology 4 + + + +SignalStateConflictNotification_repartition->mapSpatAlignment_subtopology_4 + + + + + +spat_maps_joined_rsu_repartition->mapSpatAlignment_subtopology_1 + + + + + +mapSpatAlignment_KSTREAM_TOTABLE_STATE_STORE_0000000007 + + +KSTREAM-TOTABLE-STATE-STORE-0000000007 + + + +mapSpatAlignment_subtopology_1->mapSpatAlignment_KSTREAM_TOTABLE_STATE_STORE_0000000007 + + + + + +IntersectionReferenceAlignmentNotification_repartition + +IntersectionReferenceAlignmentNotification-repartition + + + +mapSpatAlignment_subtopology_1->IntersectionReferenceAlignmentNotification_repartition + + + + + +topic_CmIntersectionReferenceAlignmentEvents + +topic.CmIntersectionReferenceAlignmentEvents + + + +mapSpatAlignment_subtopology_1->topic_CmIntersectionReferenceAlignmentEvents + + + + + +mapSpatAlignment_KSTREAM_TOTABLE_STATE_STORE_0000000007->mapSpatAlignment_subtopology_1 + + + + + +mapSpatAlignment_subtopology_2 + +mapSpatAlignment subtopology 2 + + + +IntersectionReferenceAlignmentNotification_repartition->mapSpatAlignment_subtopology_2 + + + + + +mapSpatAlignment_IntersectionReferenceAlignmentNotification + + +IntersectionReferenceAlignmentNotification + + + +mapSpatAlignment_subtopology_2->mapSpatAlignment_IntersectionReferenceAlignmentNotification + + + + + +topic_CmIntersectionReferenceAlignmentNotification + +topic.CmIntersectionReferenceAlignmentNotification + + + +mapSpatAlignment_subtopology_2->topic_CmIntersectionReferenceAlignmentNotification + + + + + +mapSpatAlignment_IntersectionReferenceAlignmentNotification->mapSpatAlignment_subtopology_2 + + + + + +topic_CmIntersectionReferenceAlignmentNotification->notification_subtopology_0 + + + + + +mapSpatAlignment_SignalGroupAlignmentNotification + + +SignalGroupAlignmentNotification + + + +mapSpatAlignment_subtopology_3->mapSpatAlignment_SignalGroupAlignmentNotification + + + + + +topic_CmSignalGroupAlignmentNotification + +topic.CmSignalGroupAlignmentNotification + + + +mapSpatAlignment_subtopology_3->topic_CmSignalGroupAlignmentNotification + + + + + +mapSpatAlignment_SignalGroupAlignmentNotification->mapSpatAlignment_subtopology_3 + + + + + +topic_CmSignalGroupAlignmentNotification->notification_subtopology_0 + + + + + +mapSpatAlignment_SignalStateConflictNotification + + +SignalStateConflictNotification + + + +mapSpatAlignment_subtopology_4->mapSpatAlignment_SignalStateConflictNotification + + + + + +topic_CmSignalStateConflictNotification + +topic.CmSignalStateConflictNotification + + + +mapSpatAlignment_subtopology_4->topic_CmSignalStateConflictNotification + + + + + +mapSpatAlignment_SignalStateConflictNotification->mapSpatAlignment_subtopology_4 + + + + + +topic_CmSignalStateConflictNotification->notification_subtopology_0 + + + + + +mapValidation_map_counts + + +map-counts + + + +mapValidation_subtopology_0->mapValidation_map_counts + + + + + +mapValidation_KTABLE_SUPPRESS_STATE_STORE_0000000017 + + +KTABLE-SUPPRESS-STATE-STORE-0000000017 + + + +mapValidation_subtopology_0->mapValidation_KTABLE_SUPPRESS_STATE_STORE_0000000017 + + + + + +mapValidation_mapTimestampDeltaEventStore + + +mapTimestampDeltaEventStore + + + +mapValidation_subtopology_0->mapValidation_mapTimestampDeltaEventStore + + + + + +mapValidation_mapTimestampDeltaKeyStore + + +mapTimestampDeltaKeyStore + + + +mapValidation_subtopology_0->mapValidation_mapTimestampDeltaKeyStore + + + + + +mapValidation_latest_timestamp_store + + +latest-timestamp-store + + + +mapValidation_subtopology_0->mapValidation_latest_timestamp_store + + + + + +topic_CmTimestampDeltaEvent + +topic.CmTimestampDeltaEvent + + + +mapValidation_subtopology_0->topic_CmTimestampDeltaEvent + + + + + +topic_CmTimestampDeltaNotification + +topic.CmTimestampDeltaNotification + + + +mapValidation_subtopology_0->topic_CmTimestampDeltaNotification + + + + + +topic_CmMapMinimumDataEvents + +topic.CmMapMinimumDataEvents + + + +mapValidation_subtopology_0->topic_CmMapMinimumDataEvents + + + + + +topic_CmMapBroadcastRateEvents + +topic.CmMapBroadcastRateEvents + + + +mapValidation_subtopology_0->topic_CmMapBroadcastRateEvents + + + + + +mapValidation_map_counts->mapValidation_subtopology_0 + + + + + +mapValidation_KTABLE_SUPPRESS_STATE_STORE_0000000017->mapValidation_subtopology_0 + + + + + +mapValidation_mapTimestampDeltaEventStore->mapValidation_subtopology_0 + + + + + +mapValidation_mapTimestampDeltaKeyStore->mapValidation_subtopology_0 + + + + + +mapValidation_latest_timestamp_store->mapValidation_subtopology_0 + + + + + +topic_CmTimestampDeltaNotification->notification_subtopology_0 + + + + + +topic_CmNotification + +topic.CmNotification + + + +notification_subtopology_0->topic_CmNotification + + + + + +topic_CmSpatTimeChangeDetailsNotification + +topic.CmSpatTimeChangeDetailsNotification + + + +topic_CmSpatTimeChangeDetailsNotification->notification_subtopology_0 + + + + + +repartition_subtopology_0 + +repartition subtopology 0 + + + +repartition_subtopology_0->topic_CmBsmJsonRepartition + + + + + +topic_OdeBsmJson + +topic.OdeBsmJson + + + +topic_OdeBsmJson->repartition_subtopology_0 + + + + + +signalStateEventAssessment_stopLinePassageAssessments + + +stopLinePassageAssessments + + + +signalStateEventAssessment_subtopology_0->signalStateEventAssessment_stopLinePassageAssessments + + + + + +topic_CmSignalStateEventAssessment + +topic.CmSignalStateEventAssessment + + + +signalStateEventAssessment_subtopology_0->topic_CmSignalStateEventAssessment + + + + + +StopLinePassageNotification_repartition + +StopLinePassageNotification-repartition + + + +signalStateEventAssessment_subtopology_0->StopLinePassageNotification_repartition + + + + + +signalStateEventAssessment_stopLinePassageAssessments->signalStateEventAssessment_subtopology_0 + + + + + +signalStateEventAssessment_subtopology_1 + +signalStateEventAssessment subtopology 1 + + + +StopLinePassageNotification_repartition->signalStateEventAssessment_subtopology_1 + + + + + +signalStateEventAssessment_StopLinePassageNotification + + +StopLinePassageNotification + + + +signalStateEventAssessment_subtopology_1->signalStateEventAssessment_StopLinePassageNotification + + + + + +topic_CmStopLinePassageNotification + +topic.CmStopLinePassageNotification + + + +signalStateEventAssessment_subtopology_1->topic_CmStopLinePassageNotification + + + + + +signalStateEventAssessment_StopLinePassageNotification->signalStateEventAssessment_subtopology_1 + + + + + +spatRevisionCounter_KSTREAM_AGGREGATE_STATE_STORE_0000000001 + + +KSTREAM-AGGREGATE-STATE-STORE-0000000001 + + + +spatRevisionCounter_subtopology_0->spatRevisionCounter_KSTREAM_AGGREGATE_STATE_STORE_0000000001 + + + + + +topic_CmSpatRevisionCounterEvents + +topic.CmSpatRevisionCounterEvents + + + +spatRevisionCounter_subtopology_0->topic_CmSpatRevisionCounterEvents + + + + + +spatRevisionCounter_KSTREAM_AGGREGATE_STATE_STORE_0000000001->spatRevisionCounter_subtopology_0 + + + + + +spatTimeChangeDetails_spat_time_change_detail_state_store + + +spat-time-change-detail-state-store + + + +spatTimeChangeDetails_subtopology_0->spatTimeChangeDetails_spat_time_change_detail_state_store + + + + + +topic_CmSpatTimeChangeDetailsEvent + +topic.CmSpatTimeChangeDetailsEvent + + + +spatTimeChangeDetails_subtopology_0->topic_CmSpatTimeChangeDetailsEvent + + + + + +spatTimeChangeDetails_spat_time_change_detail_state_store->spatTimeChangeDetails_subtopology_0 + + + + + +spatValidation_subtopology_0->topic_CmTimestampDeltaEvent + + + + + +spatValidation_subtopology_0->topic_CmTimestampDeltaNotification + + + + + +spatValidation_spat_counts + + +spat-counts + + + +spatValidation_subtopology_0->spatValidation_spat_counts + + + + + +spatValidation_KTABLE_SUPPRESS_STATE_STORE_0000000017 + + +KTABLE-SUPPRESS-STATE-STORE-0000000017 + + + +spatValidation_subtopology_0->spatValidation_KTABLE_SUPPRESS_STATE_STORE_0000000017 + + + + + +spatValidation_spatTimestampDeltaEventStore + + +spatTimestampDeltaEventStore + + + +spatValidation_subtopology_0->spatValidation_spatTimestampDeltaEventStore + + + + + +spatValidation_spatTimestampDeltaKeyStore + + +spatTimestampDeltaKeyStore + + + +spatValidation_subtopology_0->spatValidation_spatTimestampDeltaKeyStore + + + + + +spatValidation_latest_timestamp_store + + +latest-timestamp-store + + + +spatValidation_subtopology_0->spatValidation_latest_timestamp_store + + + + + +topic_CmSpatMinimumDataEvents + +topic.CmSpatMinimumDataEvents + + + +spatValidation_subtopology_0->topic_CmSpatMinimumDataEvents + + + + + +topic_CmSpatBroadcastRateEvents + +topic.CmSpatBroadcastRateEvents + + + +spatValidation_subtopology_0->topic_CmSpatBroadcastRateEvents + + + + + +spatValidation_spat_counts->spatValidation_subtopology_0 + + + + + +spatValidation_KTABLE_SUPPRESS_STATE_STORE_0000000017->spatValidation_subtopology_0 + + + + + +spatValidation_spatTimestampDeltaEventStore->spatValidation_subtopology_0 + + + + + +spatValidation_spatTimestampDeltaKeyStore->spatValidation_subtopology_0 + + + + + +spatValidation_latest_timestamp_store->spatValidation_subtopology_0 + + + + + +stopLineStopAssessment_stopLineStopEventAssessments + + +stopLineStopEventAssessments + + + +stopLineStopAssessment_subtopology_0->stopLineStopAssessment_stopLineStopEventAssessments + + + + + +topic_CmStopLineStopAssessment + +topic.CmStopLineStopAssessment + + + +stopLineStopAssessment_subtopology_0->topic_CmStopLineStopAssessment + + + + + +StopLineStopNotification_repartition + +StopLineStopNotification-repartition + + + +stopLineStopAssessment_subtopology_0->StopLineStopNotification_repartition + + + + + +stopLineStopAssessment_stopLineStopEventAssessments->stopLineStopAssessment_subtopology_0 + + + + + +stopLineStopAssessment_subtopology_1 + +stopLineStopAssessment subtopology 1 + + + +StopLineStopNotification_repartition->stopLineStopAssessment_subtopology_1 + + + + + +stopLineStopAssessment_StopLineStopNotification + + +StopLineStopNotification + + + +stopLineStopAssessment_subtopology_1->stopLineStopAssessment_StopLineStopNotification + + + + + +topic_CmStopLineStopNotification + +topic.CmStopLineStopNotification + + + +stopLineStopAssessment_subtopology_1->topic_CmStopLineStopNotification + + + + + +stopLineStopAssessment_StopLineStopNotification->stopLineStopAssessment_subtopology_1 + + + + + diff --git a/docs/KafkaStreamsVisualizations/mapValidation.svg b/docs/KafkaStreamsVisualizations/mapValidation.svg new file mode 100644 index 00000000..f5570b14 --- /dev/null +++ b/docs/KafkaStreamsVisualizations/mapValidation.svg @@ -0,0 +1,174 @@ + + + + + + +G + + + +mapValidation_subtopology_0 + +mapValidation subtopology 0 + + + +mapValidation_map_counts + + +map-counts + + + +mapValidation_subtopology_0->mapValidation_map_counts + + + + + +mapValidation_KTABLE_SUPPRESS_STATE_STORE_0000000017 + + +KTABLE-SUPPRESS-STATE-STORE-0000000017 + + + +mapValidation_subtopology_0->mapValidation_KTABLE_SUPPRESS_STATE_STORE_0000000017 + + + + + +mapValidation_mapTimestampDeltaEventStore + + +mapTimestampDeltaEventStore + + + +mapValidation_subtopology_0->mapValidation_mapTimestampDeltaEventStore + + + + + +mapValidation_mapTimestampDeltaKeyStore + + +mapTimestampDeltaKeyStore + + + +mapValidation_subtopology_0->mapValidation_mapTimestampDeltaKeyStore + + + + + +mapValidation_latest_timestamp_store + + +latest-timestamp-store + + + +mapValidation_subtopology_0->mapValidation_latest_timestamp_store + + + + + +topic_CmTimestampDeltaEvent + +topic.CmTimestampDeltaEvent + + + +mapValidation_subtopology_0->topic_CmTimestampDeltaEvent + + + + + +topic_CmTimestampDeltaNotification + +topic.CmTimestampDeltaNotification + + + +mapValidation_subtopology_0->topic_CmTimestampDeltaNotification + + + + + +topic_CmMapMinimumDataEvents + +topic.CmMapMinimumDataEvents + + + +mapValidation_subtopology_0->topic_CmMapMinimumDataEvents + + + + + +topic_CmMapBroadcastRateEvents + +topic.CmMapBroadcastRateEvents + + + +mapValidation_subtopology_0->topic_CmMapBroadcastRateEvents + + + + + +topic_ProcessedMap + +topic.ProcessedMap + + + +topic_ProcessedMap->mapValidation_subtopology_0 + + + + + +mapValidation_map_counts->mapValidation_subtopology_0 + + + + + +mapValidation_KTABLE_SUPPRESS_STATE_STORE_0000000017->mapValidation_subtopology_0 + + + + + +mapValidation_mapTimestampDeltaEventStore->mapValidation_subtopology_0 + + + + + +mapValidation_mapTimestampDeltaKeyStore->mapValidation_subtopology_0 + + + + + +mapValidation_latest_timestamp_store->mapValidation_subtopology_0 + + + + + diff --git a/docs/KafkaStreamsVisualizations/mapValidation_detail.jpg b/docs/KafkaStreamsVisualizations/mapValidation_detail.jpg new file mode 100644 index 00000000..84d747f5 Binary files /dev/null and b/docs/KafkaStreamsVisualizations/mapValidation_detail.jpg differ diff --git a/docs/KafkaStreamsVisualizations/spatValidation.svg b/docs/KafkaStreamsVisualizations/spatValidation.svg new file mode 100644 index 00000000..8c755613 --- /dev/null +++ b/docs/KafkaStreamsVisualizations/spatValidation.svg @@ -0,0 +1,174 @@ + + + + + + +G + + + +spatValidation_subtopology_0 + +spatValidation subtopology 0 + + + +spatValidation_spat_counts + + +spat-counts + + + +spatValidation_subtopology_0->spatValidation_spat_counts + + + + + +spatValidation_KTABLE_SUPPRESS_STATE_STORE_0000000017 + + +KTABLE-SUPPRESS-STATE-STORE-0000000017 + + + +spatValidation_subtopology_0->spatValidation_KTABLE_SUPPRESS_STATE_STORE_0000000017 + + + + + +spatValidation_spatTimestampDeltaEventStore + + +spatTimestampDeltaEventStore + + + +spatValidation_subtopology_0->spatValidation_spatTimestampDeltaEventStore + + + + + +spatValidation_spatTimestampDeltaKeyStore + + +spatTimestampDeltaKeyStore + + + +spatValidation_subtopology_0->spatValidation_spatTimestampDeltaKeyStore + + + + + +spatValidation_latest_timestamp_store + + +latest-timestamp-store + + + +spatValidation_subtopology_0->spatValidation_latest_timestamp_store + + + + + +topic_CmTimestampDeltaEvent + +topic.CmTimestampDeltaEvent + + + +spatValidation_subtopology_0->topic_CmTimestampDeltaEvent + + + + + +topic_CmTimestampDeltaNotification + +topic.CmTimestampDeltaNotification + + + +spatValidation_subtopology_0->topic_CmTimestampDeltaNotification + + + + + +topic_CmSpatMinimumDataEvents + +topic.CmSpatMinimumDataEvents + + + +spatValidation_subtopology_0->topic_CmSpatMinimumDataEvents + + + + + +topic_CmSpatBroadcastRateEvents + +topic.CmSpatBroadcastRateEvents + + + +spatValidation_subtopology_0->topic_CmSpatBroadcastRateEvents + + + + + +topic_ProcessedSpat + +topic.ProcessedSpat + + + +topic_ProcessedSpat->spatValidation_subtopology_0 + + + + + +spatValidation_spat_counts->spatValidation_subtopology_0 + + + + + +spatValidation_KTABLE_SUPPRESS_STATE_STORE_0000000017->spatValidation_subtopology_0 + + + + + +spatValidation_spatTimestampDeltaEventStore->spatValidation_subtopology_0 + + + + + +spatValidation_spatTimestampDeltaKeyStore->spatValidation_subtopology_0 + + + + + +spatValidation_latest_timestamp_store->spatValidation_subtopology_0 + + + + + diff --git a/docs/ModularArchitecture.md b/docs/ModularArchitecture.md new file mode 100644 index 00000000..8d4c696a --- /dev/null +++ b/docs/ModularArchitecture.md @@ -0,0 +1,75 @@ +## Modular Architecture + +The suggested method for creating a modular Streams algorithm is to create an interface containing one or more methods to perform inline streams processing. The signatures of these methods depends on the specific application. The interface then plugs into another larger interface that contains it. + +For example, suppose we have an existing streams algorithm, named `SuperStreamsAlgorithm`, that we want to add additional functionality to. Suppose the new functionality needs to consume two existing streams and produce a KTable that will be used in the larger algorithm. + +We create a hierarchy of interfaces for the new algorithm. To the `SubStreamsAlgorithm` interface we add a method that describes the inputs and outputs, like: + +```java +// Note the base sub-algoirithm extends "ConfigurableAlgorithm", +// because this algorithm can't be independently started and stopped +public interface SubAlgorithm + extends ConfigurableAlgorithm { +} + +public interface SubStreamsAlgorithm extends SubAlgorithm { + + KTable buildTopology(KStream inputStream1, KStream inputStream2); + +} +``` + +Then we add get/set methods to the larger algorithm interface for the sub-algorithm to plug into: + +```java +// Note the super-algorithm extends Algorithm which includes start/stop methods +public interface SuperAlgorithm + extends Algorithm { + + SubAlgorithm getSubAlgorithm(); + void setSubAlgorithm(SubAlgorithm subAlgorithm); + +} + +public interface SuperStreamsAlgorithm + extends SuperAlgorithm { +} +``` + +And within the topology that implements `SuperStreamsAlgorithm` we call `SubStreamsAlgorithm.buildTopology()` at the appropriate place, something like: + +```java +public class SuperTopology implements SuperStreamsAlgorithm, BaseStreamsTopology { + + private SubStreamsTopology subStreamsTopology; + + public Topology buildTopology() { + + StreamsBuilder builder = new StreamsBuilder(); + + // Do stuff + + KStream stream1 = builder.stream(inputTopic1); + KStream stream2 = builder.stream(inputTopic2); + + // SubAlgorithm runs here + KTable table = subStreamsTopology.buildTopology(stream1, stream2); + + // Do something with the table + table.join(// yada yada... + + // Do more stuff + + return builder.build(); + } + + +} +``` + + + + + + diff --git a/jpo-conflictmonitor/pom.xml b/jpo-conflictmonitor/pom.xml index c65c43c1..0ae2953f 100644 --- a/jpo-conflictmonitor/pom.xml +++ b/jpo-conflictmonitor/pom.xml @@ -4,12 +4,12 @@ org.springframework.boot spring-boot-starter-parent - 3.1.3 + 3.3.2 usdot.jpo.ode jpo-conflictmonitor - 1.3.1-SNAPSHOT + 1.4.1-SNAPSHOT jar jpo-conflictmonitor http://maven.apache.org @@ -99,18 +99,40 @@ usdot.jpo.ode jpo-ode-core - 2.1.0-SNAPSHOT + 3.0.0-SNAPSHOT usdot.jpo.ode jpo-ode-plugins - 2.1.0-SNAPSHOT + 3.0.0-SNAPSHOT usdot.jpo.ode jpo-geojsonconverter - 1.3.1-SNAPSHOT + 1.4.2-SNAPSHOT jpo-geojsonconverter + + + + org.apache.kafka + kafka-streams + + + org.apache.kafka + kafka-streams-test-utils + + + + + org.apache.kafka + kafka-streams-test-utils + 3.7.1 + test + + + org.apache.kafka + kafka-streams + 3.7.1 junit @@ -166,6 +188,16 @@ 1.18.30 + + org.jgrapht + jgrapht-core + 1.5.2 + + + org.jgrapht + jgrapht-io + 1.5.2 + diff --git a/jpo-conflictmonitor/scripts/ConfigController_Tests/concurrent_permissive/deleteIntersection_concurrentPermissiveList.http b/jpo-conflictmonitor/scripts/ConfigController_Tests/concurrent_permissive/deleteIntersection_concurrentPermissiveList.http new file mode 100644 index 00000000..c60b6ea9 --- /dev/null +++ b/jpo-conflictmonitor/scripts/ConfigController_Tests/concurrent_permissive/deleteIntersection_concurrentPermissiveList.http @@ -0,0 +1,2 @@ +DELETE http://localhost:8082/config/intersection/10/101010/map.spat.message.assessment.concurrentPermissiveList + diff --git a/jpo-conflictmonitor/scripts/ConfigController_Tests/concurrent_permissive/getDefault_concurrentPermissiveList.http b/jpo-conflictmonitor/scripts/ConfigController_Tests/concurrent_permissive/getDefault_concurrentPermissiveList.http new file mode 100644 index 00000000..0814e42f --- /dev/null +++ b/jpo-conflictmonitor/scripts/ConfigController_Tests/concurrent_permissive/getDefault_concurrentPermissiveList.http @@ -0,0 +1,2 @@ +GET http://localhost:8082/config/default/map.spat.message.assessment.concurrentPermissiveList +Accept: application/json \ No newline at end of file diff --git a/jpo-conflictmonitor/scripts/ConfigController_Tests/concurrent_permissive/getIntersection_concurrentPermissiveList.http b/jpo-conflictmonitor/scripts/ConfigController_Tests/concurrent_permissive/getIntersection_concurrentPermissiveList.http new file mode 100644 index 00000000..34eb51c2 --- /dev/null +++ b/jpo-conflictmonitor/scripts/ConfigController_Tests/concurrent_permissive/getIntersection_concurrentPermissiveList.http @@ -0,0 +1,2 @@ +GET http://localhost:8082/config/intersection/10/101010/map.spat.message.assessment.concurrentPermissiveList +Accept: application/json diff --git a/jpo-conflictmonitor/scripts/ConfigController_Tests/concurrent_permissive/postIntersection_concurrentPermissiveList.http b/jpo-conflictmonitor/scripts/ConfigController_Tests/concurrent_permissive/postIntersection_concurrentPermissiveList.http new file mode 100644 index 00000000..db8a352e --- /dev/null +++ b/jpo-conflictmonitor/scripts/ConfigController_Tests/concurrent_permissive/postIntersection_concurrentPermissiveList.http @@ -0,0 +1,35 @@ +POST http://localhost:8082/config/intersection/10/101010/map.spat.message.assessment.concurrentPermissiveList +Content-Type: application/json + +{ + "key": "map.spat.message.assessment.concurrentPermissiveList", + "category": "", + "roadRegulatorID": 10, + "intersectionID": 101010, + "value": [ + { + "first": { + "ingressLaneID": 1, + "egressLaneID": 2 + }, + "second": { + "ingressLaneID": 3, + "egressLaneID": 4 + } + }, + { + "first": { + "ingressLaneID": 9, + "egressLaneID": 10 + }, + "second": { + "ingressLaneID": 11, + "egressLaneID": 12 + } + } + ], + "type": "us.dot.its.jpo.conflictmonitor.monitor.models.concurrent_permissive.ConnectedLanesPairList", + "units": "NONE", + "description": "List of pairs of lane connections that are allowed concurrently permissive for an intersection.", + "updateType": "INTERSECTION" +} \ No newline at end of file diff --git a/jpo-conflictmonitor/scripts/IntegrationTestScripts/BSM_Revisions.csv b/jpo-conflictmonitor/scripts/IntegrationTestScripts/BSM_Revisions.csv new file mode 100644 index 00000000..93c27c2f --- /dev/null +++ b/jpo-conflictmonitor/scripts/IntegrationTestScripts/BSM_Revisions.csv @@ -0,0 +1,7 @@ +BSM,1000,{"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":"","bundleSize":1,"bundleId":0,"recordId":0,"serialNumber":0},"odeReceivedAt":"@ISO_DATE_TIME@","schemaVersion":6,"maxDurationTime":0,"recordGeneratedAt":"","sanitized":false,"odePacketID":"","odeTimStartDateTime":"","originIp":"10.11.81.28"},"payload":{"data":{"coreData":{"msgCnt":56,"id":"@TEMP_ID@","secMark":"@MILLI_OF_MINUTE@","position":{"latitude":39.644797,"longitude":-105.0816018,"elevation":0},"accelSet":{"accelLong":0,"accelYaw":0},"accuracy":{"semiMajor":0,"semiMinor":0,"orientation":0},"transmission":"UNAVAILABLE","speed":22.42,"heading":180.5,"brakes":{"wheelBrakes":{"leftFront":false,"rightFront":false,"unavailable":true,"leftRear":false,"rightRear":false},"traction":"unavailable","abs":"off","scs":"unavailable","brakeBoost":"unavailable","auxBrakes":"unavailable"},"size":{"width":0,"length":0}},"partII":[{"id":"VehicleSafetyExtensions","value":{"pathHistory":{"crumbData":[]},"pathPrediction":{"confidence":0,"radiusOfCurve":0}}}]},"dataType":"us.dot.its.jpo.ode.plugin.j2735.J2735Bsm"}} +BSM,1000,{"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":"","bundleSize":1,"bundleId":0,"recordId":0,"serialNumber":0},"odeReceivedAt":"@ISO_DATE_TIME@","schemaVersion":6,"maxDurationTime":0,"recordGeneratedAt":"","sanitized":false,"odePacketID":"","odeTimStartDateTime":"","originIp":"10.11.81.28"},"payload":{"data":{"coreData":{"msgCnt":56,"id":"@TEMP_ID@","secMark":"@MILLI_OF_MINUTE@","position":{"latitude":39.644797,"longitude":-105.0816018,"elevation":0},"accelSet":{"accelLong":0,"accelYaw":0},"accuracy":{"semiMajor":0,"semiMinor":0,"orientation":0},"transmission":"UNAVAILABLE","speed":22.42,"heading":180.5,"brakes":{"wheelBrakes":{"leftFront":false,"rightFront":false,"unavailable":true,"leftRear":false,"rightRear":false},"traction":"unavailable","abs":"off","scs":"unavailable","brakeBoost":"unavailable","auxBrakes":"unavailable"},"size":{"width":0,"length":0}},"partII":[{"id":"VehicleSafetyExtensions","value":{"pathHistory":{"crumbData":[]},"pathPrediction":{"confidence":0,"radiusOfCurve":0}}}]},"dataType":"us.dot.its.jpo.ode.plugin.j2735.J2735Bsm"}} +BSM,2000,{"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":"","bundleSize":1,"bundleId":0,"recordId":0,"serialNumber":0},"odeReceivedAt":"@ISO_DATE_TIME@","schemaVersion":6,"maxDurationTime":0,"recordGeneratedAt":"","sanitized":false,"odePacketID":"","odeTimStartDateTime":"","originIp":"10.11.81.28"},"payload":{"data":{"coreData":{"msgCnt":56,"id":"@TEMP_ID@","secMark":"@MILLI_OF_MINUTE@","position":{"latitude":39.644797,"longitude":-105.0816018,"elevation":0},"accelSet":{"accelLong":0,"accelYaw":0},"accuracy":{"semiMajor":0,"semiMinor":0,"orientation":0},"transmission":"UNAVAILABLE","speed":22.42,"heading":180.5,"brakes":{"wheelBrakes":{"leftFront":false,"rightFront":false,"unavailable":true,"leftRear":false,"rightRear":false},"traction":"unavailable","abs":"off","scs":"unavailable","brakeBoost":"unavailable","auxBrakes":"unavailable"},"size":{"width":0,"length":0}},"partII":[{"id":"VehicleSafetyExtensions","value":{"pathHistory":{"crumbData":[]},"pathPrediction":{"confidence":0,"radiusOfCurve":0}}}]},"dataType":"us.dot.its.jpo.ode.plugin.j2735.J2735Bsm"}} +BSM,3000,{"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":"","bundleSize":1,"bundleId":0,"recordId":0,"serialNumber":0},"odeReceivedAt":"@ISO_DATE_TIME@","schemaVersion":6,"maxDurationTime":0,"recordGeneratedAt":"","sanitized":false,"odePacketID":"","odeTimStartDateTime":"","originIp":"10.11.81.28"},"payload":{"data":{"coreData":{"msgCnt":57,"id":"@TEMP_ID@","secMark":"@MILLI_OF_MINUTE@","position":{"latitude":39.644797,"longitude":-105.0816018,"elevation":0},"accelSet":{"accelLong":0,"accelYaw":0},"accuracy":{"semiMajor":0,"semiMinor":0,"orientation":0},"transmission":"UNAVAILABLE","speed":22.42,"heading":180.5,"brakes":{"wheelBrakes":{"leftFront":false,"rightFront":false,"unavailable":true,"leftRear":false,"rightRear":false},"traction":"unavailable","abs":"off","scs":"unavailable","brakeBoost":"unavailable","auxBrakes":"unavailable"},"size":{"width":0,"length":0}},"partII":[{"id":"VehicleSafetyExtensions","value":{"pathHistory":{"crumbData":[]},"pathPrediction":{"confidence":0,"radiusOfCurve":0}}}]},"dataType":"us.dot.its.jpo.ode.plugin.j2735.J2735Bsm"}} +BSM,4000,{"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":"","bundleSize":1,"bundleId":0,"recordId":0,"serialNumber":0},"odeReceivedAt":"@ISO_DATE_TIME@","schemaVersion":6,"maxDurationTime":0,"recordGeneratedAt":"","sanitized":false,"odePacketID":"","odeTimStartDateTime":"","originIp":"10.11.81.28"},"payload":{"data":{"coreData":{"msgCnt":58,"id":"@TEMP_ID@","secMark":"@MILLI_OF_MINUTE@","position":{"latitude":39.644797,"longitude":-105.0816018,"elevation":0},"accelSet":{"accelLong":0,"accelYaw":0},"accuracy":{"semiMajor":0,"semiMinor":0,"orientation":0},"transmission":"UNAVAILABLE","speed":22.42,"heading":190.5,"brakes":{"wheelBrakes":{"leftFront":false,"rightFront":false,"unavailable":true,"leftRear":false,"rightRear":false},"traction":"unavailable","abs":"off","scs":"unavailable","brakeBoost":"unavailable","auxBrakes":"unavailable"},"size":{"width":0,"length":0}},"partII":[{"id":"VehicleSafetyExtensions","value":{"pathHistory":{"crumbData":[]},"pathPrediction":{"confidence":0,"radiusOfCurve":0}}}]},"dataType":"us.dot.its.jpo.ode.plugin.j2735.J2735Bsm"}} +BSM,5000,{"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":"","bundleSize":1,"bundleId":0,"recordId":0,"serialNumber":0},"odeReceivedAt":"@ISO_DATE_TIME@","schemaVersion":6,"maxDurationTime":0,"recordGeneratedAt":"","sanitized":false,"odePacketID":"","odeTimStartDateTime":"","originIp":"10.11.81.28"},"payload":{"data":{"coreData":{"msgCnt":59,"id":"@TEMP_ID@","secMark":"@MILLI_OF_MINUTE@","position":{"latitude":39.644797,"longitude":-105.0816018,"elevation":0},"accelSet":{"accelLong":0,"accelYaw":0},"accuracy":{"semiMajor":0,"semiMinor":0,"orientation":0},"transmission":"UNAVAILABLE","speed":22.42,"heading":190.5,"brakes":{"wheelBrakes":{"leftFront":false,"rightFront":false,"unavailable":true,"leftRear":false,"rightRear":false},"traction":"unavailable","abs":"on","scs":"unavailable","brakeBoost":"unavailable","auxBrakes":"unavailable"},"size":{"width":0,"length":0}},"partII":[{"id":"VehicleSafetyExtensions","value":{"pathHistory":{"crumbData":[]},"pathPrediction":{"confidence":0,"radiusOfCurve":0}}}]},"dataType":"us.dot.its.jpo.ode.plugin.j2735.J2735Bsm"}} +BSM,6000,{"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":"","bundleSize":1,"bundleId":0,"recordId":0,"serialNumber":0},"odeReceivedAt":"@ISO_DATE_TIME@","schemaVersion":7,"maxDurationTime":0,"recordGeneratedAt":"","sanitized":false,"odePacketID":"","odeTimStartDateTime":"","originIp":"10.11.81.28"},"payload":{"data":{"coreData":{"msgCnt":59,"id":"@TEMP_ID@","secMark":"@MILLI_OF_MINUTE@","position":{"latitude":39.644797,"longitude":-105.0816018,"elevation":0},"accelSet":{"accelLong":0,"accelYaw":0},"accuracy":{"semiMajor":0,"semiMinor":0,"orientation":0},"transmission":"UNAVAILABLE","speed":22.42,"heading":190.5,"brakes":{"wheelBrakes":{"leftFront":false,"rightFront":false,"unavailable":true,"leftRear":false,"rightRear":false},"traction":"unavailable","abs":"on","scs":"unavailable","brakeBoost":"unavailable","auxBrakes":"unavailable"},"size":{"width":0,"length":0}},"partII":[{"id":"VehicleSafetyExtensions","value":{"pathHistory":{"crumbData":[]},"pathPrediction":{"confidence":0,"radiusOfCurve":0}}}]},"dataType":"us.dot.its.jpo.ode.plugin.j2735.J2735Bsm"}} diff --git a/jpo-conflictmonitor/scripts/IntegrationTestScripts/ProcessedMap_Revisions.csv b/jpo-conflictmonitor/scripts/IntegrationTestScripts/ProcessedMap_Revisions.csv new file mode 100644 index 00000000..ed14fbd6 --- /dev/null +++ b/jpo-conflictmonitor/scripts/IntegrationTestScripts/ProcessedMap_Revisions.csv @@ -0,0 +1,8 @@ +ProcessedMap;10.164.6.16;6311,1000,{"mapFeatureCollection":{"type":"FeatureCollection","features":[{"type":"Feature","id":10,"geometry":{"coordinates":[[-111.6948409,40.2969746],[-111.6947006,40.2966582],[-111.6945681,40.2963382],[-111.6942976,40.2956952],[-111.6937336,40.2944205]],"type":"LineString"},"properties":{"nodes":[{"delta":[1433,-1984],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1189,-3515],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1123,-3555],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[2292,-7144],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[4780,-14163],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":10,"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":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":31,"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":null}]}},{"type":"Feature","id":11,"geometry":{"coordinates":[[-111.6948823,40.2969752],[-111.6947416,40.2966568],[-111.6946104,40.2963317],[-111.6943345,40.2956892],[-111.6937694,40.2944109]],"type":"LineString"},"properties":{"nodes":[{"delta":[1082,-1978],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1192,-3538],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1112,-3612],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[2338,-7139],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[4789,-14203],"stopLine":null,"dwidth":null,"delevation":null}],"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":3,"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":30,"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":null}]}},{"type":"Feature","id":8,"geometry":{"coordinates":[[-111.6947447,40.296975],[-111.6945987,40.2966224],[-111.6945415,40.296375]],"type":"LineString"},"properties":{"nodes":[{"delta":[2248,-1980],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1237,-3918],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[485,-2749],"stopLine":null,"dwidth":null,"delevation":null}],"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":false,"maneuverUTurnAllowed":false,"maneuverLeftTurnOnRedAllowed":false,"reserved1":false,"maneuverRightAllowed":true,"maneuverLaneChangeAllowed":false,"yieldAllwaysRequired":false,"maneuverRightTurnOnRedAllowed":false,"caution":false},"connectsTo":[{"connectingLane":{"lane":7,"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":2,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":12,"geometry":{"coordinates":[[-111.6949207,40.2969747],[-111.6946355,40.2963144],[-111.6945628,40.2962224]],"type":"LineString"},"properties":{"nodes":[{"delta":[757,-1983],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[2417,-7337],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[616,-1022],"stopLine":null,"dwidth":null,"delevation":null}],"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":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":23,"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":5,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":13,"geometry":{"coordinates":[[-111.6949654,40.2969755],[-111.6946693,40.2963075],[-111.694563,40.2962226]],"type":"LineString"},"properties":{"nodes":[{"delta":[378,-1974],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[2509,-7422],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[901,-943],"stopLine":null,"dwidth":null,"delevation":null}],"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":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":22,"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":5,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":9,"geometry":{"coordinates":[[-111.6947945,40.2969755],[-111.6946603,40.2966635],[-111.6945311,40.2963445],[-111.6942586,40.2957025],[-111.6936955,40.2944313]],"type":"LineString"},"properties":{"nodes":[{"delta":[1826,-1974],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1137,-3467],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1095,-3544],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[2309,-7133],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[4772,-14124],"stopLine":null,"dwidth":null,"delevation":null}],"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":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":32,"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":null}]}},{"type":"Feature","id":16,"geometry":{"coordinates":[[-111.6950993,40.2969606],[-111.6950831,40.2969207]],"type":"LineString"},"properties":{"nodes":[{"delta":[-757,-2140],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[137,-443],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":16,"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":15,"geometry":{"coordinates":[[-111.6950597,40.2969678],[-111.6950435,40.2969279]],"type":"LineString"},"properties":{"nodes":[{"delta":[-421,-2060],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[137,-443],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":15,"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":14,"geometry":{"coordinates":[[-111.6950119,40.2969764],[-111.6949964,40.2969345]],"type":"LineString"},"properties":{"nodes":[{"delta":[-16,-1964],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[131,-466],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":14,"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":6,"geometry":{"coordinates":[[-111.6947034,40.2971076],[-111.6946516,40.2971061]],"type":"LineString"},"properties":{"nodes":[{"delta":[2598,-507],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[439,-17],"stopLine":null,"dwidth":null,"delevation":null}],"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":7,"geometry":{"coordinates":[[-111.6946927,40.2970769],[-111.6946416,40.2970759]],"type":"LineString"},"properties":{"nodes":[{"delta":[2689,-848],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[433,-11],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":7,"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":2,"geometry":{"coordinates":[[-111.6947591,40.2972387],[-111.6935683,40.2972245]],"type":"LineString"},"properties":{"nodes":[{"delta":[2126,950],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[10091,-158],"stopLine":null,"dwidth":null,"delevation":null}],"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":23,"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":8,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":3,"geometry":{"coordinates":[[-111.6947502,40.2972093],[-111.6935675,40.2971992]],"type":"LineString"},"properties":{"nodes":[{"delta":[2202,623],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[10023,-112],"stopLine":null,"dwidth":null,"delevation":null}],"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":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":22,"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":8,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":4,"geometry":{"coordinates":[[-111.694738,40.2971788],[-111.6941318,40.2971713],[-111.6939017,40.2971989]],"type":"LineString"},"properties":{"nodes":[{"delta":[2305,284],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[5137,-83],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1950,307],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":4,"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":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":3,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":5,"geometry":{"coordinates":[[-111.6947267,40.2971466],[-111.6943028,40.2971432],[-111.6941317,40.2971719]],"type":"LineString"},"properties":{"nodes":[{"delta":[2401,-73],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[3592,-38],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1450,319],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":5,"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":14,"maneuver":{"maneuverStraightAllowed":false,"maneuverNoStoppingAllowed":false,"goWithHalt":false,"maneuverLeftAllowed":true,"maneuverUTurnAllowed":true,"maneuverLeftTurnOnRedAllowed":false,"reserved1":false,"maneuverRightAllowed":false,"maneuverLaneChangeAllowed":false,"yieldAllwaysRequired":false,"maneuverRightTurnOnRedAllowed":false,"caution":false}},"remoteIntersection":null,"signalGroup":3,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":1,"geometry":{"coordinates":[[-111.6947696,40.2972705],[-111.693782,40.2972623],[-111.6935771,40.2972531]],"type":"LineString"},"properties":{"nodes":[{"delta":[2037,1303],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[8369,-91],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1736,-102],"stopLine":null,"dwidth":null,"delevation":null}],"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":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":32,"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":8,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":25,"geometry":{"coordinates":[[-111.6952664,40.2973429],[-111.6958094,40.2986271],[-111.6963738,40.2999056]],"type":"LineString"},"properties":{"nodes":[{"delta":[-2173,2108],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-4602,14269],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-4783,14206],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":25,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":7,"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":16,"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":null}]}},{"type":"Feature","id":26,"geometry":{"coordinates":[[-111.6952202,40.2973406],[-111.6957689,40.2986334],[-111.6963331,40.2999146]],"type":"LineString"},"properties":{"nodes":[{"delta":[-1781,2082],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-4650,14364],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-4781,14235],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":26,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":7,"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}},"remoteIntersection":null,"signalGroup":6,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":27,"geometry":{"coordinates":[[-111.6951807,40.29734],[-111.6957307,40.2986348],[-111.6962926,40.2999237]],"type":"LineString"},"properties":{"nodes":[{"delta":[-1447,2076],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-4661,14387],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-4762,14321],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":27,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":7,"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}},"remoteIntersection":null,"signalGroup":6,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":28,"geometry":{"coordinates":[[-111.6951353,40.2973366],[-111.6953943,40.2979223],[-111.6955086,40.2981114]],"type":"LineString"},"properties":{"nodes":[{"delta":[-1062,2038],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-2195,6508],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-969,2101],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":28,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":7,"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":7,"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":1,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":29,"geometry":{"coordinates":[[-111.6950935,40.2973366],[-111.695294,40.2977961],[-111.6953949,40.2979228]],"type":"LineString"},"properties":{"nodes":[{"delta":[-708,2038],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-1699,5105],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-855,1408],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":29,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":7,"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":6,"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":1,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":24,"geometry":{"coordinates":[[-111.6953144,40.2973433],[-111.695503,40.2977839],[-111.6955422,40.2979969]],"type":"LineString"},"properties":{"nodes":[{"delta":[-2580,2112],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-1598,4895],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-332,2367],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":24,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":7,"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":23,"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":6,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":30,"geometry":{"coordinates":[[-111.6950442,40.2973389],[-111.695059,40.2973747]],"type":"LineString"},"properties":{"nodes":[{"delta":[-290,2063],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-125,398],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":30,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":8,"ingressApproach":0,"ingressPath":false,"egressPath":true}},{"type":"Feature","id":31,"geometry":{"coordinates":[[-111.6950017,40.2973394],[-111.6950186,40.2973803]],"type":"LineString"},"properties":{"nodes":[{"delta":[70,2069],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-143,454],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":31,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":8,"ingressApproach":0,"ingressPath":false,"egressPath":true}},{"type":"Feature","id":32,"geometry":{"coordinates":[[-111.6949588,40.2973389],[-111.6949763,40.2973803]],"type":"LineString"},"properties":{"nodes":[{"delta":[434,2063],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-148,460],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":32,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":8,"ingressApproach":0,"ingressPath":false,"egressPath":true}},{"type":"Feature","id":23,"geometry":{"coordinates":[[-111.6953705,40.2972489],[-111.695425,40.2972494]],"type":"LineString"},"properties":{"nodes":[{"delta":[-3055,1063],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-462,6],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":23,"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":22,"geometry":{"coordinates":[[-111.6953725,40.2972147],[-111.695425,40.2972162]],"type":"LineString"},"properties":{"nodes":[{"delta":[-3072,683],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-445,17],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":22,"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":18,"geometry":{"coordinates":[[-111.6952746,40.2970877],[-111.6964743,40.297086]],"type":"LineString"},"properties":{"nodes":[{"delta":[-2242,-728],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-10167,-19],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":18,"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":7,"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":4,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":19,"geometry":{"coordinates":[[-111.6952907,40.2971174],[-111.6964756,40.2971145]],"type":"LineString"},"properties":{"nodes":[{"delta":[-2379,-398],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-10041,-32],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":19,"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":6,"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":4,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":20,"geometry":{"coordinates":[[-111.6953089,40.297147],[-111.6961141,40.2971495],[-111.6962917,40.2971163]],"type":"LineString"},"properties":{"nodes":[{"delta":[-2533,-69],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-6824,28],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-1505,-369],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":20,"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":true,"maneuverUTurnAllowed":false,"maneuverLeftTurnOnRedAllowed":false,"reserved1":false,"maneuverRightAllowed":false,"maneuverLaneChangeAllowed":false,"yieldAllwaysRequired":false,"maneuverRightTurnOnRedAllowed":false,"caution":false},"connectsTo":[{"connectingLane":{"lane":31,"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":7,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":21,"geometry":{"coordinates":[[-111.6953236,40.2971756],[-111.6959863,40.2971761],[-111.6961141,40.29715]],"type":"LineString"},"properties":{"nodes":[{"delta":[-2658,249],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-5616,6],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-1083,-290],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":21,"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":true,"maneuverUTurnAllowed":false,"maneuverLeftTurnOnRedAllowed":false,"reserved1":false,"maneuverRightAllowed":false,"maneuverLaneChangeAllowed":false,"yieldAllwaysRequired":false,"maneuverRightTurnOnRedAllowed":false,"caution":false},"connectsTo":[{"connectingLane":{"lane":30,"maneuver":{"maneuverStraightAllowed":false,"maneuverNoStoppingAllowed":false,"goWithHalt":false,"maneuverLeftAllowed":true,"maneuverUTurnAllowed":true,"maneuverLeftTurnOnRedAllowed":false,"reserved1":false,"maneuverRightAllowed":false,"maneuverLaneChangeAllowed":false,"yieldAllwaysRequired":false,"maneuverRightTurnOnRedAllowed":false,"caution":false}},"remoteIntersection":null,"signalGroup":7,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":17,"geometry":{"coordinates":[[-111.6952574,40.2970542],[-111.6959705,40.2970588],[-111.6961326,40.2970849]],"type":"LineString"},"properties":{"nodes":[{"delta":[-2097,-1100],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-6043,51],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-1374,290],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":17,"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":16,"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":4,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":34,"geometry":{"coordinates":[[-111.694707,40.2970001],[-111.6951879,40.2969977]],"type":"LineString"},"properties":{"nodes":[{"delta":[2568,-1701],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-4075,-27],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":34,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":0,"ingressPath":false,"egressPath":false}},{"type":"Feature","id":35,"geometry":{"coordinates":[[-111.6952023,40.2970198],[-111.6953688,40.2973123]],"type":"LineString"},"properties":{"nodes":[{"delta":[-1630,-1482],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-1411,3250],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":35,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":0,"ingressPath":false,"egressPath":false}},{"type":"Feature","id":36,"geometry":{"coordinates":[[-111.6953605,40.2973241],[-111.6948565,40.2973006]],"type":"LineString"},"properties":{"nodes":[{"delta":[-2970,1899],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[4271,-261],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":36,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":0,"ingressPath":false,"egressPath":false}},{"type":"Feature","id":33,"geometry":{"coordinates":[[-111.694819,40.2972895],[-111.6946964,40.2970125]],"type":"LineString"},"properties":{"nodes":[{"delta":[1619,1514],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1039,-3078],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":33,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":0,"ingressPath":false,"egressPath":false}}]},"connectingLanesFeatureCollection":{"type":"FeatureCollection","features":[{"type":"Feature","id":"10-31","geometry":{"coordinates":[[-111.6948409,40.2969746],[-111.6950017,40.2973394]],"type":"LineString"},"properties":{"signalGroupId":2,"ingressLaneId":10,"egressLaneId":31}},{"type":"Feature","id":"11-30","geometry":{"coordinates":[[-111.6948823,40.2969752],[-111.6950442,40.2973389]],"type":"LineString"},"properties":{"signalGroupId":2,"ingressLaneId":11,"egressLaneId":30}},{"type":"Feature","id":"8-7","geometry":{"coordinates":[[-111.6947447,40.296975],[-111.6946927,40.2970769]],"type":"LineString"},"properties":{"signalGroupId":2,"ingressLaneId":8,"egressLaneId":7}},{"type":"Feature","id":"12-23","geometry":{"coordinates":[[-111.6949207,40.2969747],[-111.6953705,40.2972489]],"type":"LineString"},"properties":{"signalGroupId":5,"ingressLaneId":12,"egressLaneId":23}},{"type":"Feature","id":"13-22","geometry":{"coordinates":[[-111.6949654,40.2969755],[-111.6953725,40.2972147]],"type":"LineString"},"properties":{"signalGroupId":5,"ingressLaneId":13,"egressLaneId":22}},{"type":"Feature","id":"9-32","geometry":{"coordinates":[[-111.6947945,40.2969755],[-111.6949588,40.2973389]],"type":"LineString"},"properties":{"signalGroupId":2,"ingressLaneId":9,"egressLaneId":32}},{"type":"Feature","id":"2-23","geometry":{"coordinates":[[-111.6947591,40.2972387],[-111.6953705,40.2972489]],"type":"LineString"},"properties":{"signalGroupId":8,"ingressLaneId":2,"egressLaneId":23}},{"type":"Feature","id":"3-22","geometry":{"coordinates":[[-111.6947502,40.2972093],[-111.6953725,40.2972147]],"type":"LineString"},"properties":{"signalGroupId":8,"ingressLaneId":3,"egressLaneId":22}},{"type":"Feature","id":"4-15","geometry":{"coordinates":[[-111.694738,40.2971788],[-111.6950597,40.2969678]],"type":"LineString"},"properties":{"signalGroupId":3,"ingressLaneId":4,"egressLaneId":15}},{"type":"Feature","id":"5-14","geometry":{"coordinates":[[-111.6947267,40.2971466],[-111.6950119,40.2969764]],"type":"LineString"},"properties":{"signalGroupId":3,"ingressLaneId":5,"egressLaneId":14}},{"type":"Feature","id":"1-32","geometry":{"coordinates":[[-111.6947696,40.2972705],[-111.6949588,40.2973389]],"type":"LineString"},"properties":{"signalGroupId":8,"ingressLaneId":1,"egressLaneId":32}},{"type":"Feature","id":"25-16","geometry":{"coordinates":[[-111.6952664,40.2973429],[-111.6950993,40.2969606]],"type":"LineString"},"properties":{"signalGroupId":6,"ingressLaneId":25,"egressLaneId":16}},{"type":"Feature","id":"26-15","geometry":{"coordinates":[[-111.6952202,40.2973406],[-111.6950597,40.2969678]],"type":"LineString"},"properties":{"signalGroupId":6,"ingressLaneId":26,"egressLaneId":15}},{"type":"Feature","id":"27-14","geometry":{"coordinates":[[-111.6951807,40.29734],[-111.6950119,40.2969764]],"type":"LineString"},"properties":{"signalGroupId":6,"ingressLaneId":27,"egressLaneId":14}},{"type":"Feature","id":"28-7","geometry":{"coordinates":[[-111.6951353,40.2973366],[-111.6946927,40.2970769]],"type":"LineString"},"properties":{"signalGroupId":1,"ingressLaneId":28,"egressLaneId":7}},{"type":"Feature","id":"29-6","geometry":{"coordinates":[[-111.6950935,40.2973366],[-111.6947034,40.2971076]],"type":"LineString"},"properties":{"signalGroupId":1,"ingressLaneId":29,"egressLaneId":6}},{"type":"Feature","id":"24-23","geometry":{"coordinates":[[-111.6953144,40.2973433],[-111.6953705,40.2972489]],"type":"LineString"},"properties":{"signalGroupId":6,"ingressLaneId":24,"egressLaneId":23}},{"type":"Feature","id":"18-7","geometry":{"coordinates":[[-111.6952746,40.2970877],[-111.6946927,40.2970769]],"type":"LineString"},"properties":{"signalGroupId":4,"ingressLaneId":18,"egressLaneId":7}},{"type":"Feature","id":"19-6","geometry":{"coordinates":[[-111.6952907,40.2971174],[-111.6947034,40.2971076]],"type":"LineString"},"properties":{"signalGroupId":4,"ingressLaneId":19,"egressLaneId":6}},{"type":"Feature","id":"20-31","geometry":{"coordinates":[[-111.6953089,40.297147],[-111.6950017,40.2973394]],"type":"LineString"},"properties":{"signalGroupId":7,"ingressLaneId":20,"egressLaneId":31}},{"type":"Feature","id":"21-30","geometry":{"coordinates":[[-111.6953236,40.2971756],[-111.6950442,40.2973389]],"type":"LineString"},"properties":{"signalGroupId":7,"ingressLaneId":21,"egressLaneId":30}},{"type":"Feature","id":"17-16","geometry":{"coordinates":[[-111.6952574,40.2970542],[-111.6950993,40.2969606]],"type":"LineString"},"properties":{"signalGroupId":4,"ingressLaneId":17,"egressLaneId":16}}]},"properties":{"messageType":"MAP","odeReceivedAt":"@ISO_DATE_TIME@","originIp":"10.164.6.16","intersectionName":"N State St & E Center St","intersectionId":6311,"msgIssueRevision":0,"revision":4,"refPoint":{"latitude":40.2971532,"longitude":-111.69501,"elevation":1437},"cti4501Conformant":false,"validationMessages":[{"message":"$.metadata.recordGeneratedBy: is missing but it is required","jsonPath":"$.metadata","schemaPath":"#/$defs/OdeMapMetadata/required"},{"message":"$.metadata.receivedMessageDetails.locationData: is missing but it is required","jsonPath":"$.metadata.receivedMessageDetails","schemaPath":"#/$defs/OdeMapMetadata/properties/receivedMessageDetails/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].id.region: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].id","schemaPath":"#/$defs/J2735IntersectionReferenceID/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[6].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[6]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[6].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[6]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[7].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[7]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[7].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[7]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[8].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[8]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[8].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[8]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[9].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[9]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[9].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[9]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[10].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[10]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[10].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[10]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[22].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[22]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[22].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[22]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[23].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[23]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[23].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[23]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[24].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[24]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[24].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[24]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[25].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[25]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[25].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[25]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[26].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[26]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[26].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[26]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[32].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[32]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[32].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[32]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[33].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[33]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[33].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[33]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[34].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[34]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[34].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[34]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[35].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[35]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[35].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[35]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].speedLimits: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0]","schemaPath":"#/$defs/J2735IntersectionGeometry/required"}],"laneWidth":366,"mapSource":"RSU","timeStamp":"@ISO_DATE_TIME@"}} +ProcessedMap;10.164.6.16;6311,1000,{"mapFeatureCollection":{"type":"FeatureCollection","features":[{"type":"Feature","id":10,"geometry":{"coordinates":[[-111.6948409,40.2969746],[-111.6947006,40.2966582],[-111.6945681,40.2963382],[-111.6942976,40.2956952],[-111.6937336,40.2944205]],"type":"LineString"},"properties":{"nodes":[{"delta":[1433,-1984],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1189,-3515],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1123,-3555],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[2292,-7144],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[4780,-14163],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":10,"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":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":31,"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":null}]}},{"type":"Feature","id":11,"geometry":{"coordinates":[[-111.6948823,40.2969752],[-111.6947416,40.2966568],[-111.6946104,40.2963317],[-111.6943345,40.2956892],[-111.6937694,40.2944109]],"type":"LineString"},"properties":{"nodes":[{"delta":[1082,-1978],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1192,-3538],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1112,-3612],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[2338,-7139],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[4789,-14203],"stopLine":null,"dwidth":null,"delevation":null}],"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":3,"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":30,"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":null}]}},{"type":"Feature","id":8,"geometry":{"coordinates":[[-111.6947447,40.296975],[-111.6945987,40.2966224],[-111.6945415,40.296375]],"type":"LineString"},"properties":{"nodes":[{"delta":[2248,-1980],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1237,-3918],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[485,-2749],"stopLine":null,"dwidth":null,"delevation":null}],"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":false,"maneuverUTurnAllowed":false,"maneuverLeftTurnOnRedAllowed":false,"reserved1":false,"maneuverRightAllowed":true,"maneuverLaneChangeAllowed":false,"yieldAllwaysRequired":false,"maneuverRightTurnOnRedAllowed":false,"caution":false},"connectsTo":[{"connectingLane":{"lane":7,"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":2,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":12,"geometry":{"coordinates":[[-111.6949207,40.2969747],[-111.6946355,40.2963144],[-111.6945628,40.2962224]],"type":"LineString"},"properties":{"nodes":[{"delta":[757,-1983],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[2417,-7337],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[616,-1022],"stopLine":null,"dwidth":null,"delevation":null}],"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":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":23,"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":5,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":13,"geometry":{"coordinates":[[-111.6949654,40.2969755],[-111.6946693,40.2963075],[-111.694563,40.2962226]],"type":"LineString"},"properties":{"nodes":[{"delta":[378,-1974],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[2509,-7422],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[901,-943],"stopLine":null,"dwidth":null,"delevation":null}],"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":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":22,"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":5,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":9,"geometry":{"coordinates":[[-111.6947945,40.2969755],[-111.6946603,40.2966635],[-111.6945311,40.2963445],[-111.6942586,40.2957025],[-111.6936955,40.2944313]],"type":"LineString"},"properties":{"nodes":[{"delta":[1826,-1974],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1137,-3467],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1095,-3544],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[2309,-7133],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[4772,-14124],"stopLine":null,"dwidth":null,"delevation":null}],"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":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":32,"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":null}]}},{"type":"Feature","id":16,"geometry":{"coordinates":[[-111.6950993,40.2969606],[-111.6950831,40.2969207]],"type":"LineString"},"properties":{"nodes":[{"delta":[-757,-2140],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[137,-443],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":16,"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":15,"geometry":{"coordinates":[[-111.6950597,40.2969678],[-111.6950435,40.2969279]],"type":"LineString"},"properties":{"nodes":[{"delta":[-421,-2060],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[137,-443],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":15,"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":14,"geometry":{"coordinates":[[-111.6950119,40.2969764],[-111.6949964,40.2969345]],"type":"LineString"},"properties":{"nodes":[{"delta":[-16,-1964],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[131,-466],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":14,"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":6,"geometry":{"coordinates":[[-111.6947034,40.2971076],[-111.6946516,40.2971061]],"type":"LineString"},"properties":{"nodes":[{"delta":[2598,-507],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[439,-17],"stopLine":null,"dwidth":null,"delevation":null}],"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":7,"geometry":{"coordinates":[[-111.6946927,40.2970769],[-111.6946416,40.2970759]],"type":"LineString"},"properties":{"nodes":[{"delta":[2689,-848],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[433,-11],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":7,"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":2,"geometry":{"coordinates":[[-111.6947591,40.2972387],[-111.6935683,40.2972245]],"type":"LineString"},"properties":{"nodes":[{"delta":[2126,950],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[10091,-158],"stopLine":null,"dwidth":null,"delevation":null}],"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":23,"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":8,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":3,"geometry":{"coordinates":[[-111.6947502,40.2972093],[-111.6935675,40.2971992]],"type":"LineString"},"properties":{"nodes":[{"delta":[2202,623],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[10023,-112],"stopLine":null,"dwidth":null,"delevation":null}],"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":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":22,"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":8,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":4,"geometry":{"coordinates":[[-111.694738,40.2971788],[-111.6941318,40.2971713],[-111.6939017,40.2971989]],"type":"LineString"},"properties":{"nodes":[{"delta":[2305,284],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[5137,-83],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1950,307],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":4,"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":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":3,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":5,"geometry":{"coordinates":[[-111.6947267,40.2971466],[-111.6943028,40.2971432],[-111.6941317,40.2971719]],"type":"LineString"},"properties":{"nodes":[{"delta":[2401,-73],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[3592,-38],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1450,319],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":5,"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":14,"maneuver":{"maneuverStraightAllowed":false,"maneuverNoStoppingAllowed":false,"goWithHalt":false,"maneuverLeftAllowed":true,"maneuverUTurnAllowed":true,"maneuverLeftTurnOnRedAllowed":false,"reserved1":false,"maneuverRightAllowed":false,"maneuverLaneChangeAllowed":false,"yieldAllwaysRequired":false,"maneuverRightTurnOnRedAllowed":false,"caution":false}},"remoteIntersection":null,"signalGroup":3,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":1,"geometry":{"coordinates":[[-111.6947696,40.2972705],[-111.693782,40.2972623],[-111.6935771,40.2972531]],"type":"LineString"},"properties":{"nodes":[{"delta":[2037,1303],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[8369,-91],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1736,-102],"stopLine":null,"dwidth":null,"delevation":null}],"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":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":32,"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":8,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":25,"geometry":{"coordinates":[[-111.6952664,40.2973429],[-111.6958094,40.2986271],[-111.6963738,40.2999056]],"type":"LineString"},"properties":{"nodes":[{"delta":[-2173,2108],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-4602,14269],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-4783,14206],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":25,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":7,"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":16,"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":null}]}},{"type":"Feature","id":26,"geometry":{"coordinates":[[-111.6952202,40.2973406],[-111.6957689,40.2986334],[-111.6963331,40.2999146]],"type":"LineString"},"properties":{"nodes":[{"delta":[-1781,2082],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-4650,14364],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-4781,14235],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":26,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":7,"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}},"remoteIntersection":null,"signalGroup":6,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":27,"geometry":{"coordinates":[[-111.6951807,40.29734],[-111.6957307,40.2986348],[-111.6962926,40.2999237]],"type":"LineString"},"properties":{"nodes":[{"delta":[-1447,2076],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-4661,14387],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-4762,14321],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":27,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":7,"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}},"remoteIntersection":null,"signalGroup":6,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":28,"geometry":{"coordinates":[[-111.6951353,40.2973366],[-111.6953943,40.2979223],[-111.6955086,40.2981114]],"type":"LineString"},"properties":{"nodes":[{"delta":[-1062,2038],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-2195,6508],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-969,2101],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":28,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":7,"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":7,"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":1,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":29,"geometry":{"coordinates":[[-111.6950935,40.2973366],[-111.695294,40.2977961],[-111.6953949,40.2979228]],"type":"LineString"},"properties":{"nodes":[{"delta":[-708,2038],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-1699,5105],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-855,1408],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":29,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":7,"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":6,"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":1,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":24,"geometry":{"coordinates":[[-111.6953144,40.2973433],[-111.695503,40.2977839],[-111.6955422,40.2979969]],"type":"LineString"},"properties":{"nodes":[{"delta":[-2580,2112],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-1598,4895],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-332,2367],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":24,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":7,"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":23,"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":6,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":30,"geometry":{"coordinates":[[-111.6950442,40.2973389],[-111.695059,40.2973747]],"type":"LineString"},"properties":{"nodes":[{"delta":[-290,2063],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-125,398],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":30,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":8,"ingressApproach":0,"ingressPath":false,"egressPath":true}},{"type":"Feature","id":31,"geometry":{"coordinates":[[-111.6950017,40.2973394],[-111.6950186,40.2973803]],"type":"LineString"},"properties":{"nodes":[{"delta":[70,2069],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-143,454],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":31,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":8,"ingressApproach":0,"ingressPath":false,"egressPath":true}},{"type":"Feature","id":32,"geometry":{"coordinates":[[-111.6949588,40.2973389],[-111.6949763,40.2973803]],"type":"LineString"},"properties":{"nodes":[{"delta":[434,2063],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-148,460],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":32,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":8,"ingressApproach":0,"ingressPath":false,"egressPath":true}},{"type":"Feature","id":23,"geometry":{"coordinates":[[-111.6953705,40.2972489],[-111.695425,40.2972494]],"type":"LineString"},"properties":{"nodes":[{"delta":[-3055,1063],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-462,6],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":23,"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":22,"geometry":{"coordinates":[[-111.6953725,40.2972147],[-111.695425,40.2972162]],"type":"LineString"},"properties":{"nodes":[{"delta":[-3072,683],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-445,17],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":22,"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":18,"geometry":{"coordinates":[[-111.6952746,40.2970877],[-111.6964743,40.297086]],"type":"LineString"},"properties":{"nodes":[{"delta":[-2242,-728],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-10167,-19],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":18,"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":7,"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":4,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":19,"geometry":{"coordinates":[[-111.6952907,40.2971174],[-111.6964756,40.2971145]],"type":"LineString"},"properties":{"nodes":[{"delta":[-2379,-398],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-10041,-32],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":19,"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":6,"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":4,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":20,"geometry":{"coordinates":[[-111.6953089,40.297147],[-111.6961141,40.2971495],[-111.6962917,40.2971163]],"type":"LineString"},"properties":{"nodes":[{"delta":[-2533,-69],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-6824,28],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-1505,-369],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":20,"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":true,"maneuverUTurnAllowed":false,"maneuverLeftTurnOnRedAllowed":false,"reserved1":false,"maneuverRightAllowed":false,"maneuverLaneChangeAllowed":false,"yieldAllwaysRequired":false,"maneuverRightTurnOnRedAllowed":false,"caution":false},"connectsTo":[{"connectingLane":{"lane":31,"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":7,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":21,"geometry":{"coordinates":[[-111.6953236,40.2971756],[-111.6959863,40.2971761],[-111.6961141,40.29715]],"type":"LineString"},"properties":{"nodes":[{"delta":[-2658,249],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-5616,6],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-1083,-290],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":21,"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":true,"maneuverUTurnAllowed":false,"maneuverLeftTurnOnRedAllowed":false,"reserved1":false,"maneuverRightAllowed":false,"maneuverLaneChangeAllowed":false,"yieldAllwaysRequired":false,"maneuverRightTurnOnRedAllowed":false,"caution":false},"connectsTo":[{"connectingLane":{"lane":30,"maneuver":{"maneuverStraightAllowed":false,"maneuverNoStoppingAllowed":false,"goWithHalt":false,"maneuverLeftAllowed":true,"maneuverUTurnAllowed":true,"maneuverLeftTurnOnRedAllowed":false,"reserved1":false,"maneuverRightAllowed":false,"maneuverLaneChangeAllowed":false,"yieldAllwaysRequired":false,"maneuverRightTurnOnRedAllowed":false,"caution":false}},"remoteIntersection":null,"signalGroup":7,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":17,"geometry":{"coordinates":[[-111.6952574,40.2970542],[-111.6959705,40.2970588],[-111.6961326,40.2970849]],"type":"LineString"},"properties":{"nodes":[{"delta":[-2097,-1100],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-6043,51],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-1374,290],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":17,"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":16,"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":4,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":34,"geometry":{"coordinates":[[-111.694707,40.2970001],[-111.6951879,40.2969977]],"type":"LineString"},"properties":{"nodes":[{"delta":[2568,-1701],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-4075,-27],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":34,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":0,"ingressPath":false,"egressPath":false}},{"type":"Feature","id":35,"geometry":{"coordinates":[[-111.6952023,40.2970198],[-111.6953688,40.2973123]],"type":"LineString"},"properties":{"nodes":[{"delta":[-1630,-1482],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-1411,3250],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":35,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":0,"ingressPath":false,"egressPath":false}},{"type":"Feature","id":36,"geometry":{"coordinates":[[-111.6953605,40.2973241],[-111.6948565,40.2973006]],"type":"LineString"},"properties":{"nodes":[{"delta":[-2970,1899],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[4271,-261],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":36,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":0,"ingressPath":false,"egressPath":false}},{"type":"Feature","id":33,"geometry":{"coordinates":[[-111.694819,40.2972895],[-111.6946964,40.2970125]],"type":"LineString"},"properties":{"nodes":[{"delta":[1619,1514],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1039,-3078],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":33,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":0,"ingressPath":false,"egressPath":false}}]},"connectingLanesFeatureCollection":{"type":"FeatureCollection","features":[{"type":"Feature","id":"10-31","geometry":{"coordinates":[[-111.6948409,40.2969746],[-111.6950017,40.2973394]],"type":"LineString"},"properties":{"signalGroupId":2,"ingressLaneId":10,"egressLaneId":31}},{"type":"Feature","id":"11-30","geometry":{"coordinates":[[-111.6948823,40.2969752],[-111.6950442,40.2973389]],"type":"LineString"},"properties":{"signalGroupId":2,"ingressLaneId":11,"egressLaneId":30}},{"type":"Feature","id":"8-7","geometry":{"coordinates":[[-111.6947447,40.296975],[-111.6946927,40.2970769]],"type":"LineString"},"properties":{"signalGroupId":2,"ingressLaneId":8,"egressLaneId":7}},{"type":"Feature","id":"12-23","geometry":{"coordinates":[[-111.6949207,40.2969747],[-111.6953705,40.2972489]],"type":"LineString"},"properties":{"signalGroupId":5,"ingressLaneId":12,"egressLaneId":23}},{"type":"Feature","id":"13-22","geometry":{"coordinates":[[-111.6949654,40.2969755],[-111.6953725,40.2972147]],"type":"LineString"},"properties":{"signalGroupId":5,"ingressLaneId":13,"egressLaneId":22}},{"type":"Feature","id":"9-32","geometry":{"coordinates":[[-111.6947945,40.2969755],[-111.6949588,40.2973389]],"type":"LineString"},"properties":{"signalGroupId":2,"ingressLaneId":9,"egressLaneId":32}},{"type":"Feature","id":"2-23","geometry":{"coordinates":[[-111.6947591,40.2972387],[-111.6953705,40.2972489]],"type":"LineString"},"properties":{"signalGroupId":8,"ingressLaneId":2,"egressLaneId":23}},{"type":"Feature","id":"3-22","geometry":{"coordinates":[[-111.6947502,40.2972093],[-111.6953725,40.2972147]],"type":"LineString"},"properties":{"signalGroupId":8,"ingressLaneId":3,"egressLaneId":22}},{"type":"Feature","id":"4-15","geometry":{"coordinates":[[-111.694738,40.2971788],[-111.6950597,40.2969678]],"type":"LineString"},"properties":{"signalGroupId":3,"ingressLaneId":4,"egressLaneId":15}},{"type":"Feature","id":"5-14","geometry":{"coordinates":[[-111.6947267,40.2971466],[-111.6950119,40.2969764]],"type":"LineString"},"properties":{"signalGroupId":3,"ingressLaneId":5,"egressLaneId":14}},{"type":"Feature","id":"1-32","geometry":{"coordinates":[[-111.6947696,40.2972705],[-111.6949588,40.2973389]],"type":"LineString"},"properties":{"signalGroupId":8,"ingressLaneId":1,"egressLaneId":32}},{"type":"Feature","id":"25-16","geometry":{"coordinates":[[-111.6952664,40.2973429],[-111.6950993,40.2969606]],"type":"LineString"},"properties":{"signalGroupId":6,"ingressLaneId":25,"egressLaneId":16}},{"type":"Feature","id":"26-15","geometry":{"coordinates":[[-111.6952202,40.2973406],[-111.6950597,40.2969678]],"type":"LineString"},"properties":{"signalGroupId":6,"ingressLaneId":26,"egressLaneId":15}},{"type":"Feature","id":"27-14","geometry":{"coordinates":[[-111.6951807,40.29734],[-111.6950119,40.2969764]],"type":"LineString"},"properties":{"signalGroupId":6,"ingressLaneId":27,"egressLaneId":14}},{"type":"Feature","id":"28-7","geometry":{"coordinates":[[-111.6951353,40.2973366],[-111.6946927,40.2970769]],"type":"LineString"},"properties":{"signalGroupId":1,"ingressLaneId":28,"egressLaneId":7}},{"type":"Feature","id":"29-6","geometry":{"coordinates":[[-111.6950935,40.2973366],[-111.6947034,40.2971076]],"type":"LineString"},"properties":{"signalGroupId":1,"ingressLaneId":29,"egressLaneId":6}},{"type":"Feature","id":"24-23","geometry":{"coordinates":[[-111.6953144,40.2973433],[-111.6953705,40.2972489]],"type":"LineString"},"properties":{"signalGroupId":6,"ingressLaneId":24,"egressLaneId":23}},{"type":"Feature","id":"18-7","geometry":{"coordinates":[[-111.6952746,40.2970877],[-111.6946927,40.2970769]],"type":"LineString"},"properties":{"signalGroupId":4,"ingressLaneId":18,"egressLaneId":7}},{"type":"Feature","id":"19-6","geometry":{"coordinates":[[-111.6952907,40.2971174],[-111.6947034,40.2971076]],"type":"LineString"},"properties":{"signalGroupId":4,"ingressLaneId":19,"egressLaneId":6}},{"type":"Feature","id":"20-31","geometry":{"coordinates":[[-111.6953089,40.297147],[-111.6950017,40.2973394]],"type":"LineString"},"properties":{"signalGroupId":7,"ingressLaneId":20,"egressLaneId":31}},{"type":"Feature","id":"21-30","geometry":{"coordinates":[[-111.6953236,40.2971756],[-111.6950442,40.2973389]],"type":"LineString"},"properties":{"signalGroupId":7,"ingressLaneId":21,"egressLaneId":30}},{"type":"Feature","id":"17-16","geometry":{"coordinates":[[-111.6952574,40.2970542],[-111.6950993,40.2969606]],"type":"LineString"},"properties":{"signalGroupId":4,"ingressLaneId":17,"egressLaneId":16}}]},"properties":{"messageType":"MAP","odeReceivedAt":"@ISO_DATE_TIME@","originIp":"10.164.6.16","intersectionName":"N State St & E Center St","intersectionId":6311,"msgIssueRevision":0,"revision":4,"refPoint":{"latitude":40.2971532,"longitude":-111.69501,"elevation":1437},"cti4501Conformant":false,"validationMessages":[{"message":"$.metadata.recordGeneratedBy: is missing but it is required","jsonPath":"$.metadata","schemaPath":"#/$defs/OdeMapMetadata/required"},{"message":"$.metadata.receivedMessageDetails.locationData: is missing but it is required","jsonPath":"$.metadata.receivedMessageDetails","schemaPath":"#/$defs/OdeMapMetadata/properties/receivedMessageDetails/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].id.region: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].id","schemaPath":"#/$defs/J2735IntersectionReferenceID/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[6].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[6]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[6].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[6]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[7].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[7]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[7].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[7]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[8].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[8]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[8].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[8]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[9].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[9]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[9].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[9]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[10].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[10]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[10].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[10]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[22].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[22]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[22].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[22]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[23].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[23]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[23].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[23]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[24].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[24]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[24].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[24]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[25].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[25]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[25].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[25]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[26].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[26]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[26].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[26]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[32].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[32]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[32].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[32]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[33].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[33]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[33].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[33]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[34].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[34]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[34].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[34]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[35].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[35]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[35].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[35]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].speedLimits: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0]","schemaPath":"#/$defs/J2735IntersectionGeometry/required"}],"laneWidth":366,"mapSource":"RSU","timeStamp":"@ISO_DATE_TIME@"}} + +ProcessedMap;10.164.6.16;6311,2000,{"mapFeatureCollection":{"type":"FeatureCollection","features":[{"type":"Feature","id":10,"geometry":{"coordinates":[[-111.6948409,40.2969746],[-111.6947006,40.2966582],[-111.6945681,40.2963382],[-111.6942976,40.2956952],[-111.6937336,40.2944205]],"type":"LineString"},"properties":{"nodes":[{"delta":[1433,-1984],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1189,-3515],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1123,-3555],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[2292,-7144],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[4780,-14163],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":10,"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":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":31,"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":null}]}},{"type":"Feature","id":11,"geometry":{"coordinates":[[-111.6948823,40.2969752],[-111.6947416,40.2966568],[-111.6946104,40.2963317],[-111.6943345,40.2956892],[-111.6937694,40.2944109]],"type":"LineString"},"properties":{"nodes":[{"delta":[1082,-1978],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1192,-3538],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1112,-3612],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[2338,-7139],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[4789,-14203],"stopLine":null,"dwidth":null,"delevation":null}],"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":3,"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":30,"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":null}]}},{"type":"Feature","id":8,"geometry":{"coordinates":[[-111.6947447,40.296975],[-111.6945987,40.2966224],[-111.6945415,40.296375]],"type":"LineString"},"properties":{"nodes":[{"delta":[2248,-1980],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1237,-3918],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[485,-2749],"stopLine":null,"dwidth":null,"delevation":null}],"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":false,"maneuverUTurnAllowed":false,"maneuverLeftTurnOnRedAllowed":false,"reserved1":false,"maneuverRightAllowed":true,"maneuverLaneChangeAllowed":false,"yieldAllwaysRequired":false,"maneuverRightTurnOnRedAllowed":false,"caution":false},"connectsTo":[{"connectingLane":{"lane":7,"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":2,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":12,"geometry":{"coordinates":[[-111.6949207,40.2969747],[-111.6946355,40.2963144],[-111.6945628,40.2962224]],"type":"LineString"},"properties":{"nodes":[{"delta":[757,-1983],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[2417,-7337],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[616,-1022],"stopLine":null,"dwidth":null,"delevation":null}],"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":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":23,"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":5,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":13,"geometry":{"coordinates":[[-111.6949654,40.2969755],[-111.6946693,40.2963075],[-111.694563,40.2962226]],"type":"LineString"},"properties":{"nodes":[{"delta":[378,-1974],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[2509,-7422],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[901,-943],"stopLine":null,"dwidth":null,"delevation":null}],"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":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":22,"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":5,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":9,"geometry":{"coordinates":[[-111.6947945,40.2969755],[-111.6946603,40.2966635],[-111.6945311,40.2963445],[-111.6942586,40.2957025],[-111.6936955,40.2944313]],"type":"LineString"},"properties":{"nodes":[{"delta":[1826,-1974],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1137,-3467],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1095,-3544],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[2309,-7133],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[4772,-14124],"stopLine":null,"dwidth":null,"delevation":null}],"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":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":32,"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":null}]}},{"type":"Feature","id":16,"geometry":{"coordinates":[[-111.6950993,40.2969606],[-111.6950831,40.2969207]],"type":"LineString"},"properties":{"nodes":[{"delta":[-757,-2140],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[137,-443],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":16,"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":15,"geometry":{"coordinates":[[-111.6950597,40.2969678],[-111.6950435,40.2969279]],"type":"LineString"},"properties":{"nodes":[{"delta":[-421,-2060],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[137,-443],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":15,"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":14,"geometry":{"coordinates":[[-111.6950119,40.2969764],[-111.6949964,40.2969345]],"type":"LineString"},"properties":{"nodes":[{"delta":[-16,-1964],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[131,-466],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":14,"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":6,"geometry":{"coordinates":[[-111.6947034,40.2971076],[-111.6946516,40.2971061]],"type":"LineString"},"properties":{"nodes":[{"delta":[2598,-507],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[439,-17],"stopLine":null,"dwidth":null,"delevation":null}],"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":7,"geometry":{"coordinates":[[-111.6946927,40.2970769],[-111.6946416,40.2970759]],"type":"LineString"},"properties":{"nodes":[{"delta":[2689,-848],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[433,-11],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":7,"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":2,"geometry":{"coordinates":[[-111.6947591,40.2972387],[-111.6935683,40.2972245]],"type":"LineString"},"properties":{"nodes":[{"delta":[2126,950],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[10091,-158],"stopLine":null,"dwidth":null,"delevation":null}],"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":23,"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":8,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":3,"geometry":{"coordinates":[[-111.6947502,40.2972093],[-111.6935675,40.2971992]],"type":"LineString"},"properties":{"nodes":[{"delta":[2202,623],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[10023,-112],"stopLine":null,"dwidth":null,"delevation":null}],"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":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":22,"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":8,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":4,"geometry":{"coordinates":[[-111.694738,40.2971788],[-111.6941318,40.2971713],[-111.6939017,40.2971989]],"type":"LineString"},"properties":{"nodes":[{"delta":[2305,284],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[5137,-83],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1950,307],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":4,"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":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":3,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":5,"geometry":{"coordinates":[[-111.6947267,40.2971466],[-111.6943028,40.2971432],[-111.6941317,40.2971719]],"type":"LineString"},"properties":{"nodes":[{"delta":[2401,-73],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[3592,-38],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1450,319],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":5,"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":14,"maneuver":{"maneuverStraightAllowed":false,"maneuverNoStoppingAllowed":false,"goWithHalt":false,"maneuverLeftAllowed":true,"maneuverUTurnAllowed":true,"maneuverLeftTurnOnRedAllowed":false,"reserved1":false,"maneuverRightAllowed":false,"maneuverLaneChangeAllowed":false,"yieldAllwaysRequired":false,"maneuverRightTurnOnRedAllowed":false,"caution":false}},"remoteIntersection":null,"signalGroup":3,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":1,"geometry":{"coordinates":[[-111.6947696,40.2972705],[-111.693782,40.2972623],[-111.6935771,40.2972531]],"type":"LineString"},"properties":{"nodes":[{"delta":[2037,1303],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[8369,-91],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1736,-102],"stopLine":null,"dwidth":null,"delevation":null}],"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":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":32,"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":8,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":25,"geometry":{"coordinates":[[-111.6952664,40.2973429],[-111.6958094,40.2986271],[-111.6963738,40.2999056]],"type":"LineString"},"properties":{"nodes":[{"delta":[-2173,2108],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-4602,14269],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-4783,14206],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":25,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":7,"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":16,"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":null}]}},{"type":"Feature","id":26,"geometry":{"coordinates":[[-111.6952202,40.2973406],[-111.6957689,40.2986334],[-111.6963331,40.2999146]],"type":"LineString"},"properties":{"nodes":[{"delta":[-1781,2082],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-4650,14364],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-4781,14235],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":26,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":7,"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}},"remoteIntersection":null,"signalGroup":6,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":27,"geometry":{"coordinates":[[-111.6951807,40.29734],[-111.6957307,40.2986348],[-111.6962926,40.2999237]],"type":"LineString"},"properties":{"nodes":[{"delta":[-1447,2076],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-4661,14387],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-4762,14321],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":27,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":7,"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}},"remoteIntersection":null,"signalGroup":6,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":28,"geometry":{"coordinates":[[-111.6951353,40.2973366],[-111.6953943,40.2979223],[-111.6955086,40.2981114]],"type":"LineString"},"properties":{"nodes":[{"delta":[-1062,2038],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-2195,6508],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-969,2101],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":28,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":7,"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":7,"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":1,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":29,"geometry":{"coordinates":[[-111.6950935,40.2973366],[-111.695294,40.2977961],[-111.6953949,40.2979228]],"type":"LineString"},"properties":{"nodes":[{"delta":[-708,2038],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-1699,5105],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-855,1408],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":29,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":7,"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":6,"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":1,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":24,"geometry":{"coordinates":[[-111.6953144,40.2973433],[-111.695503,40.2977839],[-111.6955422,40.2979969]],"type":"LineString"},"properties":{"nodes":[{"delta":[-2580,2112],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-1598,4895],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-332,2367],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":24,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":7,"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":23,"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":6,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":30,"geometry":{"coordinates":[[-111.6950442,40.2973389],[-111.695059,40.2973747]],"type":"LineString"},"properties":{"nodes":[{"delta":[-290,2063],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-125,398],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":30,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":8,"ingressApproach":0,"ingressPath":false,"egressPath":true}},{"type":"Feature","id":31,"geometry":{"coordinates":[[-111.6950017,40.2973394],[-111.6950186,40.2973803]],"type":"LineString"},"properties":{"nodes":[{"delta":[70,2069],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-143,454],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":31,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":8,"ingressApproach":0,"ingressPath":false,"egressPath":true}},{"type":"Feature","id":32,"geometry":{"coordinates":[[-111.6949588,40.2973389],[-111.6949763,40.2973803]],"type":"LineString"},"properties":{"nodes":[{"delta":[434,2063],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-148,460],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":32,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":8,"ingressApproach":0,"ingressPath":false,"egressPath":true}},{"type":"Feature","id":23,"geometry":{"coordinates":[[-111.6953705,40.2972489],[-111.695425,40.2972494]],"type":"LineString"},"properties":{"nodes":[{"delta":[-3055,1063],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-462,6],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":23,"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":22,"geometry":{"coordinates":[[-111.6953725,40.2972147],[-111.695425,40.2972162]],"type":"LineString"},"properties":{"nodes":[{"delta":[-3072,683],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-445,17],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":22,"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":18,"geometry":{"coordinates":[[-111.6952746,40.2970877],[-111.6964743,40.297086]],"type":"LineString"},"properties":{"nodes":[{"delta":[-2242,-728],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-10167,-19],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":18,"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":7,"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":4,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":19,"geometry":{"coordinates":[[-111.6952907,40.2971174],[-111.6964756,40.2971145]],"type":"LineString"},"properties":{"nodes":[{"delta":[-2379,-398],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-10041,-32],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":19,"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":6,"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":4,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":20,"geometry":{"coordinates":[[-111.6953089,40.297147],[-111.6961141,40.2971495],[-111.6962917,40.2971163]],"type":"LineString"},"properties":{"nodes":[{"delta":[-2533,-69],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-6824,28],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-1505,-369],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":20,"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":true,"maneuverUTurnAllowed":false,"maneuverLeftTurnOnRedAllowed":false,"reserved1":false,"maneuverRightAllowed":false,"maneuverLaneChangeAllowed":false,"yieldAllwaysRequired":false,"maneuverRightTurnOnRedAllowed":false,"caution":false},"connectsTo":[{"connectingLane":{"lane":31,"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":7,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":21,"geometry":{"coordinates":[[-111.6953236,40.2971756],[-111.6959863,40.2971761],[-111.6961141,40.29715]],"type":"LineString"},"properties":{"nodes":[{"delta":[-2658,249],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-5616,6],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-1083,-290],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":21,"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":true,"maneuverUTurnAllowed":false,"maneuverLeftTurnOnRedAllowed":false,"reserved1":false,"maneuverRightAllowed":false,"maneuverLaneChangeAllowed":false,"yieldAllwaysRequired":false,"maneuverRightTurnOnRedAllowed":false,"caution":false},"connectsTo":[{"connectingLane":{"lane":30,"maneuver":{"maneuverStraightAllowed":false,"maneuverNoStoppingAllowed":false,"goWithHalt":false,"maneuverLeftAllowed":true,"maneuverUTurnAllowed":true,"maneuverLeftTurnOnRedAllowed":false,"reserved1":false,"maneuverRightAllowed":false,"maneuverLaneChangeAllowed":false,"yieldAllwaysRequired":false,"maneuverRightTurnOnRedAllowed":false,"caution":false}},"remoteIntersection":null,"signalGroup":7,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":17,"geometry":{"coordinates":[[-111.6952574,40.2970542],[-111.6959705,40.2970588],[-111.6961326,40.2970849]],"type":"LineString"},"properties":{"nodes":[{"delta":[-2097,-1100],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-6043,51],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-1374,290],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":17,"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":16,"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":4,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":34,"geometry":{"coordinates":[[-111.694707,40.2970001],[-111.6951879,40.2969977]],"type":"LineString"},"properties":{"nodes":[{"delta":[2568,-1701],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-4075,-27],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":34,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":0,"ingressPath":false,"egressPath":false}},{"type":"Feature","id":35,"geometry":{"coordinates":[[-111.6952023,40.2970198],[-111.6953688,40.2973123]],"type":"LineString"},"properties":{"nodes":[{"delta":[-1630,-1482],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-1411,3250],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":35,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":0,"ingressPath":false,"egressPath":false}},{"type":"Feature","id":36,"geometry":{"coordinates":[[-111.6953605,40.2973241],[-111.6948565,40.2973006]],"type":"LineString"},"properties":{"nodes":[{"delta":[-2970,1899],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[4271,-261],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":36,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":0,"ingressPath":false,"egressPath":false}},{"type":"Feature","id":33,"geometry":{"coordinates":[[-111.694819,40.2972895],[-111.6946964,40.2970125]],"type":"LineString"},"properties":{"nodes":[{"delta":[1619,1514],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1039,-3078],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":33,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":0,"ingressPath":false,"egressPath":false}}]},"connectingLanesFeatureCollection":{"type":"FeatureCollection","features":[{"type":"Feature","id":"10-31","geometry":{"coordinates":[[-111.6948409,40.2969746],[-111.6950017,40.2973394]],"type":"LineString"},"properties":{"signalGroupId":2,"ingressLaneId":10,"egressLaneId":31}},{"type":"Feature","id":"11-30","geometry":{"coordinates":[[-111.6948823,40.2969752],[-111.6950442,40.2973389]],"type":"LineString"},"properties":{"signalGroupId":2,"ingressLaneId":11,"egressLaneId":30}},{"type":"Feature","id":"8-7","geometry":{"coordinates":[[-111.6947447,40.296975],[-111.6946927,40.2970769]],"type":"LineString"},"properties":{"signalGroupId":2,"ingressLaneId":8,"egressLaneId":7}},{"type":"Feature","id":"12-23","geometry":{"coordinates":[[-111.6949207,40.2969747],[-111.6953705,40.2972489]],"type":"LineString"},"properties":{"signalGroupId":5,"ingressLaneId":12,"egressLaneId":23}},{"type":"Feature","id":"13-22","geometry":{"coordinates":[[-111.6949654,40.2969755],[-111.6953725,40.2972147]],"type":"LineString"},"properties":{"signalGroupId":5,"ingressLaneId":13,"egressLaneId":22}},{"type":"Feature","id":"9-32","geometry":{"coordinates":[[-111.6947945,40.2969755],[-111.6949588,40.2973389]],"type":"LineString"},"properties":{"signalGroupId":2,"ingressLaneId":9,"egressLaneId":32}},{"type":"Feature","id":"2-23","geometry":{"coordinates":[[-111.6947591,40.2972387],[-111.6953705,40.2972489]],"type":"LineString"},"properties":{"signalGroupId":8,"ingressLaneId":2,"egressLaneId":23}},{"type":"Feature","id":"3-22","geometry":{"coordinates":[[-111.6947502,40.2972093],[-111.6953725,40.2972147]],"type":"LineString"},"properties":{"signalGroupId":8,"ingressLaneId":3,"egressLaneId":22}},{"type":"Feature","id":"4-15","geometry":{"coordinates":[[-111.694738,40.2971788],[-111.6950597,40.2969678]],"type":"LineString"},"properties":{"signalGroupId":3,"ingressLaneId":4,"egressLaneId":15}},{"type":"Feature","id":"5-14","geometry":{"coordinates":[[-111.6947267,40.2971466],[-111.6950119,40.2969764]],"type":"LineString"},"properties":{"signalGroupId":3,"ingressLaneId":5,"egressLaneId":14}},{"type":"Feature","id":"1-32","geometry":{"coordinates":[[-111.6947696,40.2972705],[-111.6949588,40.2973389]],"type":"LineString"},"properties":{"signalGroupId":8,"ingressLaneId":1,"egressLaneId":32}},{"type":"Feature","id":"25-16","geometry":{"coordinates":[[-111.6952664,40.2973429],[-111.6950993,40.2969606]],"type":"LineString"},"properties":{"signalGroupId":6,"ingressLaneId":25,"egressLaneId":16}},{"type":"Feature","id":"26-15","geometry":{"coordinates":[[-111.6952202,40.2973406],[-111.6950597,40.2969678]],"type":"LineString"},"properties":{"signalGroupId":6,"ingressLaneId":26,"egressLaneId":15}},{"type":"Feature","id":"27-14","geometry":{"coordinates":[[-111.6951807,40.29734],[-111.6950119,40.2969764]],"type":"LineString"},"properties":{"signalGroupId":6,"ingressLaneId":27,"egressLaneId":14}},{"type":"Feature","id":"28-7","geometry":{"coordinates":[[-111.6951353,40.2973366],[-111.6946927,40.2970769]],"type":"LineString"},"properties":{"signalGroupId":1,"ingressLaneId":28,"egressLaneId":7}},{"type":"Feature","id":"29-6","geometry":{"coordinates":[[-111.6950935,40.2973366],[-111.6947034,40.2971076]],"type":"LineString"},"properties":{"signalGroupId":1,"ingressLaneId":29,"egressLaneId":6}},{"type":"Feature","id":"24-23","geometry":{"coordinates":[[-111.6953144,40.2973433],[-111.6953705,40.2972489]],"type":"LineString"},"properties":{"signalGroupId":6,"ingressLaneId":24,"egressLaneId":23}},{"type":"Feature","id":"18-7","geometry":{"coordinates":[[-111.6952746,40.2970877],[-111.6946927,40.2970769]],"type":"LineString"},"properties":{"signalGroupId":4,"ingressLaneId":18,"egressLaneId":7}},{"type":"Feature","id":"19-6","geometry":{"coordinates":[[-111.6952907,40.2971174],[-111.6947034,40.2971076]],"type":"LineString"},"properties":{"signalGroupId":4,"ingressLaneId":19,"egressLaneId":6}},{"type":"Feature","id":"20-31","geometry":{"coordinates":[[-111.6953089,40.297147],[-111.6950017,40.2973394]],"type":"LineString"},"properties":{"signalGroupId":7,"ingressLaneId":20,"egressLaneId":31}},{"type":"Feature","id":"21-30","geometry":{"coordinates":[[-111.6953236,40.2971756],[-111.6950442,40.2973389]],"type":"LineString"},"properties":{"signalGroupId":7,"ingressLaneId":21,"egressLaneId":30}},{"type":"Feature","id":"17-16","geometry":{"coordinates":[[-111.6952574,40.2970542],[-111.6950993,40.2969606]],"type":"LineString"},"properties":{"signalGroupId":4,"ingressLaneId":17,"egressLaneId":16}}]},"properties":{"messageType":"MAP","odeReceivedAt":"@ISO_DATE_TIME@","originIp":"10.164.6.16","intersectionName":"N State St & E Center St","intersectionId":6311,"msgIssueRevision":0,"revision":4,"refPoint":{"latitude":40.2971532,"longitude":-111.69501,"elevation":1437},"cti4501Conformant":false,"validationMessages":[{"message":"$.metadata.recordGeneratedBy: is missing but it is required","jsonPath":"$.metadata","schemaPath":"#/$defs/OdeMapMetadata/required"},{"message":"$.metadata.receivedMessageDetails.locationData: is missing but it is required","jsonPath":"$.metadata.receivedMessageDetails","schemaPath":"#/$defs/OdeMapMetadata/properties/receivedMessageDetails/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].id.region: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].id","schemaPath":"#/$defs/J2735IntersectionReferenceID/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[6].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[6]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[6].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[6]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[7].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[7]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[7].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[7]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[8].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[8]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[8].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[8]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[9].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[9]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[9].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[9]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[10].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[10]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[10].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[10]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[22].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[22]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[22].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[22]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[23].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[23]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[23].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[23]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[24].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[24]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[24].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[24]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[25].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[25]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[25].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[25]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[26].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[26]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[26].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[26]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[32].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[32]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[32].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[32]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[33].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[33]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[33].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[33]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[34].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[34]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[34].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[34]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[35].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[35]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[35].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[35]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].speedLimits: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0]","schemaPath":"#/$defs/J2735IntersectionGeometry/required"}],"laneWidth":366,"mapSource":"RSU","timeStamp":"@ISO_DATE_TIME@"}} +ProcessedMap;10.164.6.16;6311,3000,{"mapFeatureCollection":{"type":"FeatureCollection","features":[{"type":"Feature","id":10,"geometry":{"coordinates":[[-111.6948409,40.2969746],[-111.6947006,40.2966582],[-111.6945681,40.2963382],[-111.6942976,40.2956952],[-111.6937336,40.2944205]],"type":"LineString"},"properties":{"nodes":[{"delta":[1433,-1984],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1189,-3515],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1123,-3555],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[2292,-7144],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[4780,-14163],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":10,"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":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":31,"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":null}]}},{"type":"Feature","id":11,"geometry":{"coordinates":[[-111.6948823,40.2969752],[-111.6947416,40.2966568],[-111.6946104,40.2963317],[-111.6943345,40.2956892],[-111.6937694,40.2944109]],"type":"LineString"},"properties":{"nodes":[{"delta":[1082,-1978],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1192,-3538],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1112,-3612],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[2338,-7139],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[4789,-14203],"stopLine":null,"dwidth":null,"delevation":null}],"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":3,"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":30,"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":null}]}},{"type":"Feature","id":8,"geometry":{"coordinates":[[-111.6947447,40.296975],[-111.6945987,40.2966224],[-111.6945415,40.296375]],"type":"LineString"},"properties":{"nodes":[{"delta":[2248,-1980],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1237,-3918],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[485,-2749],"stopLine":null,"dwidth":null,"delevation":null}],"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":false,"maneuverUTurnAllowed":false,"maneuverLeftTurnOnRedAllowed":false,"reserved1":false,"maneuverRightAllowed":true,"maneuverLaneChangeAllowed":false,"yieldAllwaysRequired":false,"maneuverRightTurnOnRedAllowed":false,"caution":false},"connectsTo":[{"connectingLane":{"lane":7,"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":2,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":12,"geometry":{"coordinates":[[-111.6949207,40.2969747],[-111.6946355,40.2963144],[-111.6945628,40.2962224]],"type":"LineString"},"properties":{"nodes":[{"delta":[757,-1983],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[2417,-7337],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[616,-1022],"stopLine":null,"dwidth":null,"delevation":null}],"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":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":23,"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":5,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":13,"geometry":{"coordinates":[[-111.6949654,40.2969755],[-111.6946693,40.2963075],[-111.694563,40.2962226]],"type":"LineString"},"properties":{"nodes":[{"delta":[378,-1974],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[2509,-7422],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[901,-943],"stopLine":null,"dwidth":null,"delevation":null}],"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":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":22,"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":5,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":9,"geometry":{"coordinates":[[-111.6947945,40.2969755],[-111.6946603,40.2966635],[-111.6945311,40.2963445],[-111.6942586,40.2957025],[-111.6936955,40.2944313]],"type":"LineString"},"properties":{"nodes":[{"delta":[1826,-1974],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1137,-3467],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1095,-3544],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[2309,-7133],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[4772,-14124],"stopLine":null,"dwidth":null,"delevation":null}],"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":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":32,"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":null}]}},{"type":"Feature","id":16,"geometry":{"coordinates":[[-111.6950993,40.2969606],[-111.6950831,40.2969207]],"type":"LineString"},"properties":{"nodes":[{"delta":[-757,-2140],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[137,-443],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":16,"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":15,"geometry":{"coordinates":[[-111.6950597,40.2969678],[-111.6950435,40.2969279]],"type":"LineString"},"properties":{"nodes":[{"delta":[-421,-2060],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[137,-443],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":15,"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":14,"geometry":{"coordinates":[[-111.6950119,40.2969764],[-111.6949964,40.2969345]],"type":"LineString"},"properties":{"nodes":[{"delta":[-16,-1964],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[131,-466],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":14,"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":6,"geometry":{"coordinates":[[-111.6947034,40.2971076],[-111.6946516,40.2971061]],"type":"LineString"},"properties":{"nodes":[{"delta":[2598,-507],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[439,-17],"stopLine":null,"dwidth":null,"delevation":null}],"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":7,"geometry":{"coordinates":[[-111.6946927,40.2970769],[-111.6946416,40.2970759]],"type":"LineString"},"properties":{"nodes":[{"delta":[2689,-848],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[433,-11],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":7,"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":2,"geometry":{"coordinates":[[-111.6947591,40.2972387],[-111.6935683,40.2972245]],"type":"LineString"},"properties":{"nodes":[{"delta":[2126,950],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[10091,-158],"stopLine":null,"dwidth":null,"delevation":null}],"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":23,"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":8,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":3,"geometry":{"coordinates":[[-111.6947502,40.2972093],[-111.6935675,40.2971992]],"type":"LineString"},"properties":{"nodes":[{"delta":[2202,623],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[10023,-112],"stopLine":null,"dwidth":null,"delevation":null}],"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":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":22,"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":8,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":4,"geometry":{"coordinates":[[-111.694738,40.2971788],[-111.6941318,40.2971713],[-111.6939017,40.2971989]],"type":"LineString"},"properties":{"nodes":[{"delta":[2305,284],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[5137,-83],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1950,307],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":4,"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":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":3,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":5,"geometry":{"coordinates":[[-111.6947267,40.2971466],[-111.6943028,40.2971432],[-111.6941317,40.2971719]],"type":"LineString"},"properties":{"nodes":[{"delta":[2401,-73],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[3592,-38],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1450,319],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":5,"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":14,"maneuver":{"maneuverStraightAllowed":false,"maneuverNoStoppingAllowed":false,"goWithHalt":false,"maneuverLeftAllowed":true,"maneuverUTurnAllowed":true,"maneuverLeftTurnOnRedAllowed":false,"reserved1":false,"maneuverRightAllowed":false,"maneuverLaneChangeAllowed":false,"yieldAllwaysRequired":false,"maneuverRightTurnOnRedAllowed":false,"caution":false}},"remoteIntersection":null,"signalGroup":3,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":1,"geometry":{"coordinates":[[-111.6947696,40.2972705],[-111.693782,40.2972623],[-111.6935771,40.2972531]],"type":"LineString"},"properties":{"nodes":[{"delta":[2037,1303],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[8369,-91],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1736,-102],"stopLine":null,"dwidth":null,"delevation":null}],"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":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":32,"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":8,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":25,"geometry":{"coordinates":[[-111.6952664,40.2973429],[-111.6958094,40.2986271],[-111.6963738,40.2999056]],"type":"LineString"},"properties":{"nodes":[{"delta":[-2173,2108],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-4602,14269],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-4783,14206],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":25,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":7,"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":16,"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":null}]}},{"type":"Feature","id":26,"geometry":{"coordinates":[[-111.6952202,40.2973406],[-111.6957689,40.2986334],[-111.6963331,40.2999146]],"type":"LineString"},"properties":{"nodes":[{"delta":[-1781,2082],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-4650,14364],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-4781,14235],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":26,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":7,"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}},"remoteIntersection":null,"signalGroup":6,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":27,"geometry":{"coordinates":[[-111.6951807,40.29734],[-111.6957307,40.2986348],[-111.6962926,40.2999237]],"type":"LineString"},"properties":{"nodes":[{"delta":[-1447,2076],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-4661,14387],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-4762,14321],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":27,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":7,"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}},"remoteIntersection":null,"signalGroup":6,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":28,"geometry":{"coordinates":[[-111.6951353,40.2973366],[-111.6953943,40.2979223],[-111.6955086,40.2981114]],"type":"LineString"},"properties":{"nodes":[{"delta":[-1062,2038],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-2195,6508],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-969,2101],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":28,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":7,"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":7,"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":1,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":29,"geometry":{"coordinates":[[-111.6950935,40.2973366],[-111.695294,40.2977961],[-111.6953949,40.2979228]],"type":"LineString"},"properties":{"nodes":[{"delta":[-708,2038],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-1699,5105],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-855,1408],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":29,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":7,"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":6,"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":1,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":24,"geometry":{"coordinates":[[-111.6953144,40.2973433],[-111.695503,40.2977839],[-111.6955422,40.2979969]],"type":"LineString"},"properties":{"nodes":[{"delta":[-2580,2112],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-1598,4895],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-332,2367],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":24,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":7,"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":23,"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":6,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":30,"geometry":{"coordinates":[[-111.6950442,40.2973389],[-111.695059,40.2973747]],"type":"LineString"},"properties":{"nodes":[{"delta":[-290,2063],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-125,398],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":30,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":8,"ingressApproach":0,"ingressPath":false,"egressPath":true}},{"type":"Feature","id":31,"geometry":{"coordinates":[[-111.6950017,40.2973394],[-111.6950186,40.2973803]],"type":"LineString"},"properties":{"nodes":[{"delta":[70,2069],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-143,454],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":31,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":8,"ingressApproach":0,"ingressPath":false,"egressPath":true}},{"type":"Feature","id":32,"geometry":{"coordinates":[[-111.6949588,40.2973389],[-111.6949763,40.2973803]],"type":"LineString"},"properties":{"nodes":[{"delta":[434,2063],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-148,460],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":32,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":8,"ingressApproach":0,"ingressPath":false,"egressPath":true}},{"type":"Feature","id":23,"geometry":{"coordinates":[[-111.6953705,40.2972489],[-111.695425,40.2972494]],"type":"LineString"},"properties":{"nodes":[{"delta":[-3055,1063],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-462,6],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":23,"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":22,"geometry":{"coordinates":[[-111.6953725,40.2972147],[-111.695425,40.2972162]],"type":"LineString"},"properties":{"nodes":[{"delta":[-3072,683],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-445,17],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":22,"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":18,"geometry":{"coordinates":[[-111.6952746,40.2970877],[-111.6964743,40.297086]],"type":"LineString"},"properties":{"nodes":[{"delta":[-2242,-728],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-10167,-19],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":18,"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":7,"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":4,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":19,"geometry":{"coordinates":[[-111.6952907,40.2971174],[-111.6964756,40.2971145]],"type":"LineString"},"properties":{"nodes":[{"delta":[-2379,-398],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-10041,-32],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":19,"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":6,"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":4,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":20,"geometry":{"coordinates":[[-111.6953089,40.297147],[-111.6961141,40.2971495],[-111.6962917,40.2971163]],"type":"LineString"},"properties":{"nodes":[{"delta":[-2533,-69],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-6824,28],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-1505,-369],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":20,"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":true,"maneuverUTurnAllowed":false,"maneuverLeftTurnOnRedAllowed":false,"reserved1":false,"maneuverRightAllowed":false,"maneuverLaneChangeAllowed":false,"yieldAllwaysRequired":false,"maneuverRightTurnOnRedAllowed":false,"caution":false},"connectsTo":[{"connectingLane":{"lane":31,"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":7,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":21,"geometry":{"coordinates":[[-111.6953236,40.2971756],[-111.6959863,40.2971761],[-111.6961141,40.29715]],"type":"LineString"},"properties":{"nodes":[{"delta":[-2658,249],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-5616,6],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-1083,-290],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":21,"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":true,"maneuverUTurnAllowed":false,"maneuverLeftTurnOnRedAllowed":false,"reserved1":false,"maneuverRightAllowed":false,"maneuverLaneChangeAllowed":false,"yieldAllwaysRequired":false,"maneuverRightTurnOnRedAllowed":false,"caution":false},"connectsTo":[{"connectingLane":{"lane":30,"maneuver":{"maneuverStraightAllowed":false,"maneuverNoStoppingAllowed":false,"goWithHalt":false,"maneuverLeftAllowed":true,"maneuverUTurnAllowed":true,"maneuverLeftTurnOnRedAllowed":false,"reserved1":false,"maneuverRightAllowed":false,"maneuverLaneChangeAllowed":false,"yieldAllwaysRequired":false,"maneuverRightTurnOnRedAllowed":false,"caution":false}},"remoteIntersection":null,"signalGroup":7,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":17,"geometry":{"coordinates":[[-111.6952574,40.2970542],[-111.6959705,40.2970588],[-111.6961326,40.2970849]],"type":"LineString"},"properties":{"nodes":[{"delta":[-2097,-1100],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-6043,51],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-1374,290],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":17,"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":16,"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":4,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":34,"geometry":{"coordinates":[[-111.694707,40.2970001],[-111.6951879,40.2969977]],"type":"LineString"},"properties":{"nodes":[{"delta":[2568,-1701],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-4075,-27],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":34,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":0,"ingressPath":false,"egressPath":false}},{"type":"Feature","id":35,"geometry":{"coordinates":[[-111.6952023,40.2970198],[-111.6953688,40.2973123]],"type":"LineString"},"properties":{"nodes":[{"delta":[-1630,-1482],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-1411,3250],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":35,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":0,"ingressPath":false,"egressPath":false}},{"type":"Feature","id":36,"geometry":{"coordinates":[[-111.6953605,40.2973241],[-111.6948565,40.2973006]],"type":"LineString"},"properties":{"nodes":[{"delta":[-2970,1899],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[4271,-261],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":36,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":0,"ingressPath":false,"egressPath":false}},{"type":"Feature","id":33,"geometry":{"coordinates":[[-111.694819,40.2972895],[-111.6946964,40.2970125]],"type":"LineString"},"properties":{"nodes":[{"delta":[1619,1514],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1039,-3078],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":33,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":0,"ingressPath":false,"egressPath":false}}]},"connectingLanesFeatureCollection":{"type":"FeatureCollection","features":[{"type":"Feature","id":"10-31","geometry":{"coordinates":[[-111.6948409,40.2969746],[-111.6950017,40.2973394]],"type":"LineString"},"properties":{"signalGroupId":2,"ingressLaneId":10,"egressLaneId":31}},{"type":"Feature","id":"11-30","geometry":{"coordinates":[[-111.6948823,40.2969752],[-111.6950442,40.2973389]],"type":"LineString"},"properties":{"signalGroupId":2,"ingressLaneId":11,"egressLaneId":30}},{"type":"Feature","id":"8-7","geometry":{"coordinates":[[-111.6947447,40.296975],[-111.6946927,40.2970769]],"type":"LineString"},"properties":{"signalGroupId":2,"ingressLaneId":8,"egressLaneId":7}},{"type":"Feature","id":"12-23","geometry":{"coordinates":[[-111.6949207,40.2969747],[-111.6953705,40.2972489]],"type":"LineString"},"properties":{"signalGroupId":5,"ingressLaneId":12,"egressLaneId":23}},{"type":"Feature","id":"13-22","geometry":{"coordinates":[[-111.6949654,40.2969755],[-111.6953725,40.2972147]],"type":"LineString"},"properties":{"signalGroupId":5,"ingressLaneId":13,"egressLaneId":22}},{"type":"Feature","id":"9-32","geometry":{"coordinates":[[-111.6947945,40.2969755],[-111.6949588,40.2973389]],"type":"LineString"},"properties":{"signalGroupId":2,"ingressLaneId":9,"egressLaneId":32}},{"type":"Feature","id":"2-23","geometry":{"coordinates":[[-111.6947591,40.2972387],[-111.6953705,40.2972489]],"type":"LineString"},"properties":{"signalGroupId":8,"ingressLaneId":2,"egressLaneId":23}},{"type":"Feature","id":"3-22","geometry":{"coordinates":[[-111.6947502,40.2972093],[-111.6953725,40.2972147]],"type":"LineString"},"properties":{"signalGroupId":8,"ingressLaneId":3,"egressLaneId":22}},{"type":"Feature","id":"4-15","geometry":{"coordinates":[[-111.694738,40.2971788],[-111.6950597,40.2969678]],"type":"LineString"},"properties":{"signalGroupId":3,"ingressLaneId":4,"egressLaneId":15}},{"type":"Feature","id":"5-14","geometry":{"coordinates":[[-111.6947267,40.2971466],[-111.6950119,40.2969764]],"type":"LineString"},"properties":{"signalGroupId":3,"ingressLaneId":5,"egressLaneId":14}},{"type":"Feature","id":"1-32","geometry":{"coordinates":[[-111.6947696,40.2972705],[-111.6949588,40.2973389]],"type":"LineString"},"properties":{"signalGroupId":8,"ingressLaneId":1,"egressLaneId":32}},{"type":"Feature","id":"25-16","geometry":{"coordinates":[[-111.6952664,40.2973429],[-111.6950993,40.2969606]],"type":"LineString"},"properties":{"signalGroupId":6,"ingressLaneId":25,"egressLaneId":16}},{"type":"Feature","id":"26-15","geometry":{"coordinates":[[-111.6952202,40.2973406],[-111.6950597,40.2969678]],"type":"LineString"},"properties":{"signalGroupId":6,"ingressLaneId":26,"egressLaneId":15}},{"type":"Feature","id":"27-14","geometry":{"coordinates":[[-111.6951807,40.29734],[-111.6950119,40.2969764]],"type":"LineString"},"properties":{"signalGroupId":6,"ingressLaneId":27,"egressLaneId":14}},{"type":"Feature","id":"28-7","geometry":{"coordinates":[[-111.6951353,40.2973366],[-111.6946927,40.2970769]],"type":"LineString"},"properties":{"signalGroupId":1,"ingressLaneId":28,"egressLaneId":7}},{"type":"Feature","id":"29-6","geometry":{"coordinates":[[-111.6950935,40.2973366],[-111.6947034,40.2971076]],"type":"LineString"},"properties":{"signalGroupId":1,"ingressLaneId":29,"egressLaneId":6}},{"type":"Feature","id":"24-23","geometry":{"coordinates":[[-111.6953144,40.2973433],[-111.6953705,40.2972489]],"type":"LineString"},"properties":{"signalGroupId":6,"ingressLaneId":24,"egressLaneId":23}},{"type":"Feature","id":"18-7","geometry":{"coordinates":[[-111.6952746,40.2970877],[-111.6946927,40.2970769]],"type":"LineString"},"properties":{"signalGroupId":4,"ingressLaneId":18,"egressLaneId":7}},{"type":"Feature","id":"19-6","geometry":{"coordinates":[[-111.6952907,40.2971174],[-111.6947034,40.2971076]],"type":"LineString"},"properties":{"signalGroupId":4,"ingressLaneId":19,"egressLaneId":6}},{"type":"Feature","id":"20-31","geometry":{"coordinates":[[-111.6953089,40.297147],[-111.6950017,40.2973394]],"type":"LineString"},"properties":{"signalGroupId":7,"ingressLaneId":20,"egressLaneId":31}},{"type":"Feature","id":"21-30","geometry":{"coordinates":[[-111.6953236,40.2971756],[-111.6950442,40.2973389]],"type":"LineString"},"properties":{"signalGroupId":7,"ingressLaneId":21,"egressLaneId":30}},{"type":"Feature","id":"17-16","geometry":{"coordinates":[[-111.6952574,40.2970542],[-111.6950993,40.2969606]],"type":"LineString"},"properties":{"signalGroupId":4,"ingressLaneId":17,"egressLaneId":16}}]},"properties":{"messageType":"MAP","odeReceivedAt":"@ISO_DATE_TIME@","originIp":"10.164.6.16","intersectionName":"N State St & E Center St","intersectionId":6311,"msgIssueRevision":0,"revision":5,"refPoint":{"latitude":40.2971532,"longitude":-111.69501,"elevation":1437},"cti4501Conformant":false,"validationMessages":[{"message":"$.metadata.recordGeneratedBy: is missing but it is required","jsonPath":"$.metadata","schemaPath":"#/$defs/OdeMapMetadata/required"},{"message":"$.metadata.receivedMessageDetails.locationData: is missing but it is required","jsonPath":"$.metadata.receivedMessageDetails","schemaPath":"#/$defs/OdeMapMetadata/properties/receivedMessageDetails/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].id.region: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].id","schemaPath":"#/$defs/J2735IntersectionReferenceID/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[6].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[6]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[6].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[6]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[7].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[7]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[7].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[7]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[8].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[8]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[8].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[8]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[9].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[9]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[9].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[9]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[10].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[10]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[10].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[10]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[22].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[22]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[22].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[22]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[23].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[23]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[23].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[23]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[24].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[24]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[24].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[24]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[25].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[25]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[25].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[25]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[26].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[26]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[26].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[26]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[32].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[32]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[32].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[32]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[33].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[33]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[33].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[33]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[34].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[34]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[34].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[34]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[35].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[35]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[35].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[35]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].speedLimits: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0]","schemaPath":"#/$defs/J2735IntersectionGeometry/required"}],"laneWidth":366,"mapSource":"RSU","timeStamp":"@ISO_DATE_TIME@"}} +ProcessedMap;10.164.6.16;6311,4000,{"mapFeatureCollection":{"type":"FeatureCollection","features":[{"type":"Feature","id":10,"geometry":{"coordinates":[[-111.6948409,40.2969746],[-111.6947006,40.2966582],[-111.6945681,40.2963382],[-111.6942976,40.2956952],[-111.6937336,40.2944205]],"type":"LineString"},"properties":{"nodes":[{"delta":[1433,-1984],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1189,-3515],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1123,-3555],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[2292,-7144],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[4780,-14163],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":10,"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":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":31,"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":null}]}},{"type":"Feature","id":11,"geometry":{"coordinates":[[-111.6948823,40.2969752],[-111.6947416,40.2966568],[-111.6946104,40.2963317],[-111.6943345,40.2956892],[-111.6937694,40.2944109]],"type":"LineString"},"properties":{"nodes":[{"delta":[1082,-1978],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1192,-3538],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1112,-3612],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[2338,-7139],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[4789,-14203],"stopLine":null,"dwidth":null,"delevation":null}],"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":3,"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":30,"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":null}]}},{"type":"Feature","id":8,"geometry":{"coordinates":[[-111.6947447,40.296975],[-111.6945987,40.2966224],[-111.6945415,40.296375]],"type":"LineString"},"properties":{"nodes":[{"delta":[2248,-1980],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1237,-3918],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[485,-2749],"stopLine":null,"dwidth":null,"delevation":null}],"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":false,"maneuverUTurnAllowed":false,"maneuverLeftTurnOnRedAllowed":false,"reserved1":false,"maneuverRightAllowed":true,"maneuverLaneChangeAllowed":false,"yieldAllwaysRequired":false,"maneuverRightTurnOnRedAllowed":false,"caution":false},"connectsTo":[{"connectingLane":{"lane":7,"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":2,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":12,"geometry":{"coordinates":[[-111.6949207,40.2969747],[-111.6946355,40.2963144],[-111.6945628,40.2962224]],"type":"LineString"},"properties":{"nodes":[{"delta":[757,-1983],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[2417,-7337],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[616,-1022],"stopLine":null,"dwidth":null,"delevation":null}],"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":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":23,"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":5,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":13,"geometry":{"coordinates":[[-111.6949654,40.2969755],[-111.6946693,40.2963075],[-111.694563,40.2962226]],"type":"LineString"},"properties":{"nodes":[{"delta":[378,-1974],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[2509,-7422],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[901,-943],"stopLine":null,"dwidth":null,"delevation":null}],"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":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":22,"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":5,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":9,"geometry":{"coordinates":[[-111.6947945,40.2969755],[-111.6946603,40.2966635],[-111.6945311,40.2963445],[-111.6942586,40.2957025],[-111.6936955,40.2944313]],"type":"LineString"},"properties":{"nodes":[{"delta":[1826,-1974],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1137,-3467],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1095,-3544],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[2309,-7133],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[4772,-14124],"stopLine":null,"dwidth":null,"delevation":null}],"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":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":32,"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":null}]}},{"type":"Feature","id":16,"geometry":{"coordinates":[[-111.6950993,40.2969606],[-111.6950831,40.2969207]],"type":"LineString"},"properties":{"nodes":[{"delta":[-757,-2140],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[137,-443],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":16,"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":15,"geometry":{"coordinates":[[-111.6950597,40.2969678],[-111.6950435,40.2969279]],"type":"LineString"},"properties":{"nodes":[{"delta":[-421,-2060],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[137,-443],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":15,"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":14,"geometry":{"coordinates":[[-111.6950119,40.2969764],[-111.6949964,40.2969345]],"type":"LineString"},"properties":{"nodes":[{"delta":[-16,-1964],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[131,-466],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":14,"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":6,"geometry":{"coordinates":[[-111.6947034,40.2971076],[-111.6946516,40.2971061]],"type":"LineString"},"properties":{"nodes":[{"delta":[2598,-507],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[439,-17],"stopLine":null,"dwidth":null,"delevation":null}],"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":7,"geometry":{"coordinates":[[-111.6946927,40.2970769],[-111.6946416,40.2970759]],"type":"LineString"},"properties":{"nodes":[{"delta":[2689,-848],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[433,-11],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":7,"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":2,"geometry":{"coordinates":[[-111.6947591,40.2972387],[-111.6935683,40.2972245]],"type":"LineString"},"properties":{"nodes":[{"delta":[2126,950],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[10091,-158],"stopLine":null,"dwidth":null,"delevation":null}],"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":23,"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":8,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":3,"geometry":{"coordinates":[[-111.6947502,40.2972093],[-111.6935675,40.2971992]],"type":"LineString"},"properties":{"nodes":[{"delta":[2202,623],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[10023,-112],"stopLine":null,"dwidth":null,"delevation":null}],"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":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":22,"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":8,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":4,"geometry":{"coordinates":[[-111.694738,40.2971788],[-111.6941318,40.2971713],[-111.6939017,40.2971989]],"type":"LineString"},"properties":{"nodes":[{"delta":[2305,284],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[5137,-83],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1950,307],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":4,"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":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":3,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":5,"geometry":{"coordinates":[[-111.6947267,40.2971466],[-111.6943028,40.2971432],[-111.6941317,40.2971719]],"type":"LineString"},"properties":{"nodes":[{"delta":[2401,-73],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[3592,-38],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1450,319],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":5,"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":14,"maneuver":{"maneuverStraightAllowed":false,"maneuverNoStoppingAllowed":false,"goWithHalt":false,"maneuverLeftAllowed":true,"maneuverUTurnAllowed":true,"maneuverLeftTurnOnRedAllowed":false,"reserved1":false,"maneuverRightAllowed":false,"maneuverLaneChangeAllowed":false,"yieldAllwaysRequired":false,"maneuverRightTurnOnRedAllowed":false,"caution":false}},"remoteIntersection":null,"signalGroup":3,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":1,"geometry":{"coordinates":[[-111.6947696,40.2972705],[-111.693782,40.2972623],[-111.6935771,40.2972531]],"type":"LineString"},"properties":{"nodes":[{"delta":[2037,1303],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[8369,-91],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1736,-102],"stopLine":null,"dwidth":null,"delevation":null}],"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":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":32,"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":8,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":25,"geometry":{"coordinates":[[-111.6952664,40.2973429],[-111.6958094,40.2986271],[-111.6963738,40.2999056]],"type":"LineString"},"properties":{"nodes":[{"delta":[-2173,2108],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-4602,14269],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-4783,14206],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":25,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":7,"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":16,"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":null}]}},{"type":"Feature","id":26,"geometry":{"coordinates":[[-111.6952202,40.2973406],[-111.6957689,40.2986334],[-111.6963331,40.2999146]],"type":"LineString"},"properties":{"nodes":[{"delta":[-1781,2082],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-4650,14364],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-4781,14235],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":26,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":7,"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}},"remoteIntersection":null,"signalGroup":6,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":27,"geometry":{"coordinates":[[-111.6951807,40.29734],[-111.6957307,40.2986348],[-111.6962926,40.2999237]],"type":"LineString"},"properties":{"nodes":[{"delta":[-1447,2076],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-4661,14387],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-4762,14321],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":27,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":7,"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}},"remoteIntersection":null,"signalGroup":6,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":28,"geometry":{"coordinates":[[-111.6951353,40.2973366],[-111.6953943,40.2979223],[-111.6955086,40.2981114]],"type":"LineString"},"properties":{"nodes":[{"delta":[-1062,2038],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-2195,6508],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-969,2101],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":28,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":7,"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":7,"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":1,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":29,"geometry":{"coordinates":[[-111.6950935,40.2973366],[-111.695294,40.2977961],[-111.6953949,40.2979228]],"type":"LineString"},"properties":{"nodes":[{"delta":[-708,2038],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-1699,5105],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-855,1408],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":29,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":7,"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":6,"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":1,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":24,"geometry":{"coordinates":[[-111.6953144,40.2973433],[-111.695503,40.2977839],[-111.6955422,40.2979969]],"type":"LineString"},"properties":{"nodes":[{"delta":[-2580,2112],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-1598,4895],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-332,2367],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":24,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":7,"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":23,"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":6,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":30,"geometry":{"coordinates":[[-111.6950442,40.2973389],[-111.695059,40.2973747]],"type":"LineString"},"properties":{"nodes":[{"delta":[-290,2063],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-125,398],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":30,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":8,"ingressApproach":0,"ingressPath":false,"egressPath":true}},{"type":"Feature","id":31,"geometry":{"coordinates":[[-111.6950017,40.2973394],[-111.6950186,40.2973803]],"type":"LineString"},"properties":{"nodes":[{"delta":[70,2069],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-143,454],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":31,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":8,"ingressApproach":0,"ingressPath":false,"egressPath":true}},{"type":"Feature","id":32,"geometry":{"coordinates":[[-111.6949588,40.2973389],[-111.6949763,40.2973803]],"type":"LineString"},"properties":{"nodes":[{"delta":[434,2063],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-148,460],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":32,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":8,"ingressApproach":0,"ingressPath":false,"egressPath":true}},{"type":"Feature","id":23,"geometry":{"coordinates":[[-111.6953705,40.2972489],[-111.695425,40.2972494]],"type":"LineString"},"properties":{"nodes":[{"delta":[-3055,1063],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-462,6],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":23,"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":22,"geometry":{"coordinates":[[-111.6953725,40.2972147],[-111.695425,40.2972162]],"type":"LineString"},"properties":{"nodes":[{"delta":[-3072,683],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-445,17],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":22,"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":18,"geometry":{"coordinates":[[-111.6952746,40.2970877],[-111.6964743,40.297086]],"type":"LineString"},"properties":{"nodes":[{"delta":[-2242,-728],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-10167,-19],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":18,"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":7,"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":4,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":19,"geometry":{"coordinates":[[-111.6952907,40.2971174],[-111.6964756,40.2971145]],"type":"LineString"},"properties":{"nodes":[{"delta":[-2379,-398],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-10041,-32],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":19,"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":6,"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":4,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":20,"geometry":{"coordinates":[[-111.6953089,40.297147],[-111.6961141,40.2971495],[-111.6962917,40.2971163]],"type":"LineString"},"properties":{"nodes":[{"delta":[-2533,-69],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-6824,28],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-1505,-369],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":20,"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":true,"maneuverUTurnAllowed":false,"maneuverLeftTurnOnRedAllowed":false,"reserved1":false,"maneuverRightAllowed":false,"maneuverLaneChangeAllowed":true,"yieldAllwaysRequired":false,"maneuverRightTurnOnRedAllowed":false,"caution":false},"connectsTo":[{"connectingLane":{"lane":31,"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":7,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":21,"geometry":{"coordinates":[[-111.6953236,40.2971756],[-111.6959863,40.2971761],[-111.6961141,40.29715]],"type":"LineString"},"properties":{"nodes":[{"delta":[-2658,249],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-5616,6],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-1083,-290],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":21,"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":true,"maneuverUTurnAllowed":false,"maneuverLeftTurnOnRedAllowed":false,"reserved1":false,"maneuverRightAllowed":false,"maneuverLaneChangeAllowed":false,"yieldAllwaysRequired":false,"maneuverRightTurnOnRedAllowed":false,"caution":false},"connectsTo":[{"connectingLane":{"lane":30,"maneuver":{"maneuverStraightAllowed":false,"maneuverNoStoppingAllowed":false,"goWithHalt":false,"maneuverLeftAllowed":true,"maneuverUTurnAllowed":true,"maneuverLeftTurnOnRedAllowed":false,"reserved1":false,"maneuverRightAllowed":false,"maneuverLaneChangeAllowed":false,"yieldAllwaysRequired":false,"maneuverRightTurnOnRedAllowed":false,"caution":false}},"remoteIntersection":null,"signalGroup":7,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":17,"geometry":{"coordinates":[[-111.6952574,40.2970542],[-111.6959705,40.2970588],[-111.6961326,40.2970849]],"type":"LineString"},"properties":{"nodes":[{"delta":[-2097,-1100],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-6043,51],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-1374,290],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":17,"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":16,"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":4,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":34,"geometry":{"coordinates":[[-111.694707,40.2970001],[-111.6951879,40.2969977]],"type":"LineString"},"properties":{"nodes":[{"delta":[2568,-1701],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-4075,-27],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":34,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":0,"ingressPath":false,"egressPath":false}},{"type":"Feature","id":35,"geometry":{"coordinates":[[-111.6952023,40.2970198],[-111.6953688,40.2973123]],"type":"LineString"},"properties":{"nodes":[{"delta":[-1630,-1482],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-1411,3250],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":35,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":0,"ingressPath":false,"egressPath":false}},{"type":"Feature","id":36,"geometry":{"coordinates":[[-111.6953605,40.2973241],[-111.6948565,40.2973006]],"type":"LineString"},"properties":{"nodes":[{"delta":[-2970,1899],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[4271,-261],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":36,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":0,"ingressPath":false,"egressPath":false}},{"type":"Feature","id":33,"geometry":{"coordinates":[[-111.694819,40.2972895],[-111.6946964,40.2970125]],"type":"LineString"},"properties":{"nodes":[{"delta":[1619,1514],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1039,-3078],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":33,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":0,"ingressPath":false,"egressPath":false}}]},"connectingLanesFeatureCollection":{"type":"FeatureCollection","features":[{"type":"Feature","id":"10-31","geometry":{"coordinates":[[-111.6948409,40.2969746],[-111.6950017,40.2973394]],"type":"LineString"},"properties":{"signalGroupId":2,"ingressLaneId":10,"egressLaneId":31}},{"type":"Feature","id":"11-30","geometry":{"coordinates":[[-111.6948823,40.2969752],[-111.6950442,40.2973389]],"type":"LineString"},"properties":{"signalGroupId":2,"ingressLaneId":11,"egressLaneId":30}},{"type":"Feature","id":"8-7","geometry":{"coordinates":[[-111.6947447,40.296975],[-111.6946927,40.2970769]],"type":"LineString"},"properties":{"signalGroupId":2,"ingressLaneId":8,"egressLaneId":7}},{"type":"Feature","id":"12-23","geometry":{"coordinates":[[-111.6949207,40.2969747],[-111.6953705,40.2972489]],"type":"LineString"},"properties":{"signalGroupId":5,"ingressLaneId":12,"egressLaneId":23}},{"type":"Feature","id":"13-22","geometry":{"coordinates":[[-111.6949654,40.2969755],[-111.6953725,40.2972147]],"type":"LineString"},"properties":{"signalGroupId":5,"ingressLaneId":13,"egressLaneId":22}},{"type":"Feature","id":"9-32","geometry":{"coordinates":[[-111.6947945,40.2969755],[-111.6949588,40.2973389]],"type":"LineString"},"properties":{"signalGroupId":2,"ingressLaneId":9,"egressLaneId":32}},{"type":"Feature","id":"2-23","geometry":{"coordinates":[[-111.6947591,40.2972387],[-111.6953705,40.2972489]],"type":"LineString"},"properties":{"signalGroupId":8,"ingressLaneId":2,"egressLaneId":23}},{"type":"Feature","id":"3-22","geometry":{"coordinates":[[-111.6947502,40.2972093],[-111.6953725,40.2972147]],"type":"LineString"},"properties":{"signalGroupId":8,"ingressLaneId":3,"egressLaneId":22}},{"type":"Feature","id":"4-15","geometry":{"coordinates":[[-111.694738,40.2971788],[-111.6950597,40.2969678]],"type":"LineString"},"properties":{"signalGroupId":3,"ingressLaneId":4,"egressLaneId":15}},{"type":"Feature","id":"5-14","geometry":{"coordinates":[[-111.6947267,40.2971466],[-111.6950119,40.2969764]],"type":"LineString"},"properties":{"signalGroupId":3,"ingressLaneId":5,"egressLaneId":14}},{"type":"Feature","id":"1-32","geometry":{"coordinates":[[-111.6947696,40.2972705],[-111.6949588,40.2973389]],"type":"LineString"},"properties":{"signalGroupId":8,"ingressLaneId":1,"egressLaneId":32}},{"type":"Feature","id":"25-16","geometry":{"coordinates":[[-111.6952664,40.2973429],[-111.6950993,40.2969606]],"type":"LineString"},"properties":{"signalGroupId":6,"ingressLaneId":25,"egressLaneId":16}},{"type":"Feature","id":"26-15","geometry":{"coordinates":[[-111.6952202,40.2973406],[-111.6950597,40.2969678]],"type":"LineString"},"properties":{"signalGroupId":6,"ingressLaneId":26,"egressLaneId":15}},{"type":"Feature","id":"27-14","geometry":{"coordinates":[[-111.6951807,40.29734],[-111.6950119,40.2969764]],"type":"LineString"},"properties":{"signalGroupId":6,"ingressLaneId":27,"egressLaneId":14}},{"type":"Feature","id":"28-7","geometry":{"coordinates":[[-111.6951353,40.2973366],[-111.6946927,40.2970769]],"type":"LineString"},"properties":{"signalGroupId":1,"ingressLaneId":28,"egressLaneId":7}},{"type":"Feature","id":"29-6","geometry":{"coordinates":[[-111.6950935,40.2973366],[-111.6947034,40.2971076]],"type":"LineString"},"properties":{"signalGroupId":1,"ingressLaneId":29,"egressLaneId":6}},{"type":"Feature","id":"24-23","geometry":{"coordinates":[[-111.6953144,40.2973433],[-111.6953705,40.2972489]],"type":"LineString"},"properties":{"signalGroupId":6,"ingressLaneId":24,"egressLaneId":23}},{"type":"Feature","id":"18-7","geometry":{"coordinates":[[-111.6952746,40.2970877],[-111.6946927,40.2970769]],"type":"LineString"},"properties":{"signalGroupId":4,"ingressLaneId":18,"egressLaneId":7}},{"type":"Feature","id":"19-6","geometry":{"coordinates":[[-111.6952907,40.2971174],[-111.6947034,40.2971076]],"type":"LineString"},"properties":{"signalGroupId":4,"ingressLaneId":19,"egressLaneId":6}},{"type":"Feature","id":"20-31","geometry":{"coordinates":[[-111.6953089,40.297147],[-111.6950017,40.2973394]],"type":"LineString"},"properties":{"signalGroupId":7,"ingressLaneId":20,"egressLaneId":31}},{"type":"Feature","id":"21-30","geometry":{"coordinates":[[-111.6953236,40.2971756],[-111.6950442,40.2973389]],"type":"LineString"},"properties":{"signalGroupId":7,"ingressLaneId":21,"egressLaneId":30}},{"type":"Feature","id":"17-16","geometry":{"coordinates":[[-111.6952574,40.2970542],[-111.6950993,40.2969606]],"type":"LineString"},"properties":{"signalGroupId":4,"ingressLaneId":17,"egressLaneId":16}}]},"properties":{"messageType":"MAP","odeReceivedAt":"@ISO_DATE_TIME@","originIp":"10.164.6.16","intersectionName":"N State St & E Center St","intersectionId":6311,"msgIssueRevision":0,"revision":6,"refPoint":{"latitude":40.2971532,"longitude":-111.69501,"elevation":1437},"cti4501Conformant":false,"validationMessages":[{"message":"$.metadata.recordGeneratedBy: is missing but it is required","jsonPath":"$.metadata","schemaPath":"#/$defs/OdeMapMetadata/required"},{"message":"$.metadata.receivedMessageDetails.locationData: is missing but it is required","jsonPath":"$.metadata.receivedMessageDetails","schemaPath":"#/$defs/OdeMapMetadata/properties/receivedMessageDetails/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].id.region: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].id","schemaPath":"#/$defs/J2735IntersectionReferenceID/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[6].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[6]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[6].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[6]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[7].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[7]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[7].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[7]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[8].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[8]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[8].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[8]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[9].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[9]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[9].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[9]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[10].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[10]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[10].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[10]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[22].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[22]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[22].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[22]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[23].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[23]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[23].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[23]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[24].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[24]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[24].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[24]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[25].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[25]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[25].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[25]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[26].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[26]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[26].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[26]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[32].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[32]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[32].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[32]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[33].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[33]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[33].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[33]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[34].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[34]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[34].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[34]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[35].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[35]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[35].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[35]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].speedLimits: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0]","schemaPath":"#/$defs/J2735IntersectionGeometry/required"}],"laneWidth":366,"mapSource":"RSU","timeStamp":"@ISO_DATE_TIME@"}} +ProcessedMap;10.164.6.16;6311,5000,{"mapFeatureCollection":{"type":"FeatureCollection","features":[{"type":"Feature","id":10,"geometry":{"coordinates":[[-111.6948409,40.2969746],[-111.6947006,40.2966582],[-111.6945681,40.2963382],[-111.6942976,40.2956952],[-111.6937336,40.2944205]],"type":"LineString"},"properties":{"nodes":[{"delta":[1433,-1984],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1189,-3515],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1123,-3555],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[2292,-7144],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[4780,-14163],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":10,"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":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":31,"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":null}]}},{"type":"Feature","id":11,"geometry":{"coordinates":[[-111.6948823,40.2969752],[-111.6947416,40.2966568],[-111.6946104,40.2963317],[-111.6943345,40.2956892],[-111.6937694,40.2944109]],"type":"LineString"},"properties":{"nodes":[{"delta":[1082,-1978],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1192,-3538],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1112,-3612],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[2338,-7139],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[4789,-14203],"stopLine":null,"dwidth":null,"delevation":null}],"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":3,"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":30,"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":null}]}},{"type":"Feature","id":8,"geometry":{"coordinates":[[-111.6947447,40.296975],[-111.6945987,40.2966224],[-111.6945415,40.296375]],"type":"LineString"},"properties":{"nodes":[{"delta":[2248,-1980],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1237,-3918],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[485,-2749],"stopLine":null,"dwidth":null,"delevation":null}],"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":false,"maneuverUTurnAllowed":false,"maneuverLeftTurnOnRedAllowed":false,"reserved1":false,"maneuverRightAllowed":true,"maneuverLaneChangeAllowed":false,"yieldAllwaysRequired":false,"maneuverRightTurnOnRedAllowed":false,"caution":false},"connectsTo":[{"connectingLane":{"lane":7,"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":2,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":12,"geometry":{"coordinates":[[-111.6949207,40.2969747],[-111.6946355,40.2963144],[-111.6945628,40.2962224]],"type":"LineString"},"properties":{"nodes":[{"delta":[757,-1983],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[2417,-7337],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[616,-1022],"stopLine":null,"dwidth":null,"delevation":null}],"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":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":23,"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":5,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":13,"geometry":{"coordinates":[[-111.6949654,40.2969755],[-111.6946693,40.2963075],[-111.694563,40.2962226]],"type":"LineString"},"properties":{"nodes":[{"delta":[378,-1974],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[2509,-7422],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[901,-943],"stopLine":null,"dwidth":null,"delevation":null}],"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":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":22,"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":5,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":9,"geometry":{"coordinates":[[-111.6947945,40.2969755],[-111.6946603,40.2966635],[-111.6945311,40.2963445],[-111.6942586,40.2957025],[-111.6936955,40.2944313]],"type":"LineString"},"properties":{"nodes":[{"delta":[1826,-1974],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1137,-3467],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1095,-3544],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[2309,-7133],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[4772,-14124],"stopLine":null,"dwidth":null,"delevation":null}],"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":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":32,"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":null}]}},{"type":"Feature","id":16,"geometry":{"coordinates":[[-111.6950993,40.2969606],[-111.6950831,40.2969207]],"type":"LineString"},"properties":{"nodes":[{"delta":[-757,-2140],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[137,-443],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":16,"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":15,"geometry":{"coordinates":[[-111.6950597,40.2969678],[-111.6950435,40.2969279]],"type":"LineString"},"properties":{"nodes":[{"delta":[-421,-2060],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[137,-443],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":15,"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":14,"geometry":{"coordinates":[[-111.6950119,40.2969764],[-111.6949964,40.2969345]],"type":"LineString"},"properties":{"nodes":[{"delta":[-16,-1964],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[131,-466],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":14,"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":6,"geometry":{"coordinates":[[-111.6947034,40.2971076],[-111.6946516,40.2971061]],"type":"LineString"},"properties":{"nodes":[{"delta":[2598,-507],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[439,-17],"stopLine":null,"dwidth":null,"delevation":null}],"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":7,"geometry":{"coordinates":[[-111.6946927,40.2970769],[-111.6946416,40.2970759]],"type":"LineString"},"properties":{"nodes":[{"delta":[2689,-848],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[433,-11],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":7,"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":2,"geometry":{"coordinates":[[-111.6947591,40.2972387],[-111.6935683,40.2972245]],"type":"LineString"},"properties":{"nodes":[{"delta":[2126,950],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[10091,-158],"stopLine":null,"dwidth":null,"delevation":null}],"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":23,"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":8,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":3,"geometry":{"coordinates":[[-111.6947502,40.2972093],[-111.6935675,40.2971992]],"type":"LineString"},"properties":{"nodes":[{"delta":[2202,623],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[10023,-112],"stopLine":null,"dwidth":null,"delevation":null}],"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":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":22,"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":8,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":4,"geometry":{"coordinates":[[-111.694738,40.2971788],[-111.6941318,40.2971713],[-111.6939017,40.2971989]],"type":"LineString"},"properties":{"nodes":[{"delta":[2305,284],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[5137,-83],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1950,307],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":4,"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":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":3,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":5,"geometry":{"coordinates":[[-111.6947267,40.2971466],[-111.6943028,40.2971432],[-111.6941317,40.2971719]],"type":"LineString"},"properties":{"nodes":[{"delta":[2401,-73],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[3592,-38],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1450,319],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":5,"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":14,"maneuver":{"maneuverStraightAllowed":false,"maneuverNoStoppingAllowed":false,"goWithHalt":false,"maneuverLeftAllowed":true,"maneuverUTurnAllowed":true,"maneuverLeftTurnOnRedAllowed":false,"reserved1":false,"maneuverRightAllowed":false,"maneuverLaneChangeAllowed":false,"yieldAllwaysRequired":false,"maneuverRightTurnOnRedAllowed":false,"caution":false}},"remoteIntersection":null,"signalGroup":3,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":1,"geometry":{"coordinates":[[-111.6947696,40.2972705],[-111.693782,40.2972623],[-111.6935771,40.2972531]],"type":"LineString"},"properties":{"nodes":[{"delta":[2037,1303],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[8369,-91],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1736,-102],"stopLine":null,"dwidth":null,"delevation":null}],"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":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":32,"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":8,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":25,"geometry":{"coordinates":[[-111.6952664,40.2973429],[-111.6958094,40.2986271],[-111.6963738,40.2999056]],"type":"LineString"},"properties":{"nodes":[{"delta":[-2173,2108],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-4602,14269],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-4783,14206],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":25,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":7,"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":16,"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":null}]}},{"type":"Feature","id":26,"geometry":{"coordinates":[[-111.6952202,40.2973406],[-111.6957689,40.2986334],[-111.6963331,40.2999146]],"type":"LineString"},"properties":{"nodes":[{"delta":[-1781,2082],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-4650,14364],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-4781,14235],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":26,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":7,"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}},"remoteIntersection":null,"signalGroup":6,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":27,"geometry":{"coordinates":[[-111.6951807,40.29734],[-111.6957307,40.2986348],[-111.6962926,40.2999237]],"type":"LineString"},"properties":{"nodes":[{"delta":[-1447,2076],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-4661,14387],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-4762,14321],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":27,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":7,"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}},"remoteIntersection":null,"signalGroup":6,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":28,"geometry":{"coordinates":[[-111.6951353,40.2973366],[-111.6953943,40.2979223],[-111.6955086,40.2981114]],"type":"LineString"},"properties":{"nodes":[{"delta":[-1062,2038],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-2195,6508],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-969,2101],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":28,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":7,"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":7,"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":1,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":29,"geometry":{"coordinates":[[-111.6950935,40.2973366],[-111.695294,40.2977961],[-111.6953949,40.2979228]],"type":"LineString"},"properties":{"nodes":[{"delta":[-708,2038],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-1699,5105],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-855,1408],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":29,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":7,"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":6,"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":1,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":24,"geometry":{"coordinates":[[-111.6953144,40.2973433],[-111.695503,40.2977839],[-111.6955422,40.2979969]],"type":"LineString"},"properties":{"nodes":[{"delta":[-2580,2112],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-1598,4895],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-332,2367],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":24,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":7,"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":23,"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":6,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":30,"geometry":{"coordinates":[[-111.6950442,40.2973389],[-111.695059,40.2973747]],"type":"LineString"},"properties":{"nodes":[{"delta":[-290,2063],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-125,398],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":30,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":8,"ingressApproach":0,"ingressPath":false,"egressPath":true}},{"type":"Feature","id":31,"geometry":{"coordinates":[[-111.6950017,40.2973394],[-111.6950186,40.2973803]],"type":"LineString"},"properties":{"nodes":[{"delta":[70,2069],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-143,454],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":31,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":8,"ingressApproach":0,"ingressPath":false,"egressPath":true}},{"type":"Feature","id":32,"geometry":{"coordinates":[[-111.6949588,40.2973389],[-111.6949763,40.2973803]],"type":"LineString"},"properties":{"nodes":[{"delta":[434,2063],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-148,460],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":32,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":8,"ingressApproach":0,"ingressPath":false,"egressPath":true}},{"type":"Feature","id":23,"geometry":{"coordinates":[[-111.6953705,40.2972489],[-111.695425,40.2972494]],"type":"LineString"},"properties":{"nodes":[{"delta":[-3055,1063],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-462,6],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":23,"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":22,"geometry":{"coordinates":[[-111.6953725,40.2972147],[-111.695425,40.2972162]],"type":"LineString"},"properties":{"nodes":[{"delta":[-3072,683],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-445,17],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":22,"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":18,"geometry":{"coordinates":[[-111.6952746,40.2970877],[-111.6964743,40.297086]],"type":"LineString"},"properties":{"nodes":[{"delta":[-2242,-728],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-10167,-19],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":18,"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":7,"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":4,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":19,"geometry":{"coordinates":[[-111.6952907,40.2971174],[-111.6964756,40.2971145]],"type":"LineString"},"properties":{"nodes":[{"delta":[-2379,-398],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-10041,-32],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":19,"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":6,"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":4,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":20,"geometry":{"coordinates":[[-111.6953089,40.297147],[-111.6961141,40.2971495],[-111.6962917,40.2971163]],"type":"LineString"},"properties":{"nodes":[{"delta":[-2533,-69],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-6824,28],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-1505,-369],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":20,"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":true,"maneuverUTurnAllowed":false,"maneuverLeftTurnOnRedAllowed":false,"reserved1":false,"maneuverRightAllowed":false,"maneuverLaneChangeAllowed":true,"yieldAllwaysRequired":true,"maneuverRightTurnOnRedAllowed":false,"caution":false},"connectsTo":[{"connectingLane":{"lane":31,"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":7,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":21,"geometry":{"coordinates":[[-111.6953236,40.2971756],[-111.6959863,40.2971761],[-111.6961141,40.29715]],"type":"LineString"},"properties":{"nodes":[{"delta":[-2658,249],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-5616,6],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-1083,-290],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":21,"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":true,"maneuverUTurnAllowed":false,"maneuverLeftTurnOnRedAllowed":false,"reserved1":false,"maneuverRightAllowed":false,"maneuverLaneChangeAllowed":false,"yieldAllwaysRequired":false,"maneuverRightTurnOnRedAllowed":false,"caution":false},"connectsTo":[{"connectingLane":{"lane":30,"maneuver":{"maneuverStraightAllowed":false,"maneuverNoStoppingAllowed":false,"goWithHalt":false,"maneuverLeftAllowed":true,"maneuverUTurnAllowed":true,"maneuverLeftTurnOnRedAllowed":false,"reserved1":false,"maneuverRightAllowed":false,"maneuverLaneChangeAllowed":false,"yieldAllwaysRequired":false,"maneuverRightTurnOnRedAllowed":false,"caution":false}},"remoteIntersection":null,"signalGroup":7,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":17,"geometry":{"coordinates":[[-111.6952574,40.2970542],[-111.6959705,40.2970588],[-111.6961326,40.2970849]],"type":"LineString"},"properties":{"nodes":[{"delta":[-2097,-1100],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-6043,51],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-1374,290],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":17,"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":16,"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":4,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":34,"geometry":{"coordinates":[[-111.694707,40.2970001],[-111.6951879,40.2969977]],"type":"LineString"},"properties":{"nodes":[{"delta":[2568,-1701],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-4075,-27],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":34,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":0,"ingressPath":false,"egressPath":false}},{"type":"Feature","id":35,"geometry":{"coordinates":[[-111.6952023,40.2970198],[-111.6953688,40.2973123]],"type":"LineString"},"properties":{"nodes":[{"delta":[-1630,-1482],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-1411,3250],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":35,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":0,"ingressPath":false,"egressPath":false}},{"type":"Feature","id":36,"geometry":{"coordinates":[[-111.6953605,40.2973241],[-111.6948565,40.2973006]],"type":"LineString"},"properties":{"nodes":[{"delta":[-2970,1899],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[4271,-261],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":36,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":0,"ingressPath":false,"egressPath":false}},{"type":"Feature","id":33,"geometry":{"coordinates":[[-111.694819,40.2972895],[-111.6946964,40.2970125]],"type":"LineString"},"properties":{"nodes":[{"delta":[1619,1514],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1039,-3078],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":33,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":0,"ingressPath":false,"egressPath":false}}]},"connectingLanesFeatureCollection":{"type":"FeatureCollection","features":[{"type":"Feature","id":"10-31","geometry":{"coordinates":[[-111.6948409,40.2969746],[-111.6950017,40.2973394]],"type":"LineString"},"properties":{"signalGroupId":2,"ingressLaneId":10,"egressLaneId":31}},{"type":"Feature","id":"11-30","geometry":{"coordinates":[[-111.6948823,40.2969752],[-111.6950442,40.2973389]],"type":"LineString"},"properties":{"signalGroupId":2,"ingressLaneId":11,"egressLaneId":30}},{"type":"Feature","id":"8-7","geometry":{"coordinates":[[-111.6947447,40.296975],[-111.6946927,40.2970769]],"type":"LineString"},"properties":{"signalGroupId":2,"ingressLaneId":8,"egressLaneId":7}},{"type":"Feature","id":"12-23","geometry":{"coordinates":[[-111.6949207,40.2969747],[-111.6953705,40.2972489]],"type":"LineString"},"properties":{"signalGroupId":5,"ingressLaneId":12,"egressLaneId":23}},{"type":"Feature","id":"13-22","geometry":{"coordinates":[[-111.6949654,40.2969755],[-111.6953725,40.2972147]],"type":"LineString"},"properties":{"signalGroupId":5,"ingressLaneId":13,"egressLaneId":22}},{"type":"Feature","id":"9-32","geometry":{"coordinates":[[-111.6947945,40.2969755],[-111.6949588,40.2973389]],"type":"LineString"},"properties":{"signalGroupId":2,"ingressLaneId":9,"egressLaneId":32}},{"type":"Feature","id":"2-23","geometry":{"coordinates":[[-111.6947591,40.2972387],[-111.6953705,40.2972489]],"type":"LineString"},"properties":{"signalGroupId":8,"ingressLaneId":2,"egressLaneId":23}},{"type":"Feature","id":"3-22","geometry":{"coordinates":[[-111.6947502,40.2972093],[-111.6953725,40.2972147]],"type":"LineString"},"properties":{"signalGroupId":8,"ingressLaneId":3,"egressLaneId":22}},{"type":"Feature","id":"4-15","geometry":{"coordinates":[[-111.694738,40.2971788],[-111.6950597,40.2969678]],"type":"LineString"},"properties":{"signalGroupId":3,"ingressLaneId":4,"egressLaneId":15}},{"type":"Feature","id":"5-14","geometry":{"coordinates":[[-111.6947267,40.2971466],[-111.6950119,40.2969764]],"type":"LineString"},"properties":{"signalGroupId":3,"ingressLaneId":5,"egressLaneId":14}},{"type":"Feature","id":"1-32","geometry":{"coordinates":[[-111.6947696,40.2972705],[-111.6949588,40.2973389]],"type":"LineString"},"properties":{"signalGroupId":8,"ingressLaneId":1,"egressLaneId":32}},{"type":"Feature","id":"25-16","geometry":{"coordinates":[[-111.6952664,40.2973429],[-111.6950993,40.2969606]],"type":"LineString"},"properties":{"signalGroupId":6,"ingressLaneId":25,"egressLaneId":16}},{"type":"Feature","id":"26-15","geometry":{"coordinates":[[-111.6952202,40.2973406],[-111.6950597,40.2969678]],"type":"LineString"},"properties":{"signalGroupId":6,"ingressLaneId":26,"egressLaneId":15}},{"type":"Feature","id":"27-14","geometry":{"coordinates":[[-111.6951807,40.29734],[-111.6950119,40.2969764]],"type":"LineString"},"properties":{"signalGroupId":6,"ingressLaneId":27,"egressLaneId":14}},{"type":"Feature","id":"28-7","geometry":{"coordinates":[[-111.6951353,40.2973366],[-111.6946927,40.2970769]],"type":"LineString"},"properties":{"signalGroupId":1,"ingressLaneId":28,"egressLaneId":7}},{"type":"Feature","id":"29-6","geometry":{"coordinates":[[-111.6950935,40.2973366],[-111.6947034,40.2971076]],"type":"LineString"},"properties":{"signalGroupId":1,"ingressLaneId":29,"egressLaneId":6}},{"type":"Feature","id":"24-23","geometry":{"coordinates":[[-111.6953144,40.2973433],[-111.6953705,40.2972489]],"type":"LineString"},"properties":{"signalGroupId":6,"ingressLaneId":24,"egressLaneId":23}},{"type":"Feature","id":"18-7","geometry":{"coordinates":[[-111.6952746,40.2970877],[-111.6946927,40.2970769]],"type":"LineString"},"properties":{"signalGroupId":4,"ingressLaneId":18,"egressLaneId":7}},{"type":"Feature","id":"19-6","geometry":{"coordinates":[[-111.6952907,40.2971174],[-111.6947034,40.2971076]],"type":"LineString"},"properties":{"signalGroupId":4,"ingressLaneId":19,"egressLaneId":6}},{"type":"Feature","id":"20-31","geometry":{"coordinates":[[-111.6953089,40.297147],[-111.6950017,40.2973394]],"type":"LineString"},"properties":{"signalGroupId":7,"ingressLaneId":20,"egressLaneId":31}},{"type":"Feature","id":"21-30","geometry":{"coordinates":[[-111.6953236,40.2971756],[-111.6950442,40.2973389]],"type":"LineString"},"properties":{"signalGroupId":7,"ingressLaneId":21,"egressLaneId":30}},{"type":"Feature","id":"17-16","geometry":{"coordinates":[[-111.6952574,40.2970542],[-111.6950993,40.2969606]],"type":"LineString"},"properties":{"signalGroupId":4,"ingressLaneId":17,"egressLaneId":16}}]},"properties":{"messageType":"MAP","odeReceivedAt":"@ISO_DATE_TIME@","originIp":"10.164.6.16","intersectionName":"N State St & E Center St","intersectionId":6311,"msgIssueRevision":0,"revision":7,"refPoint":{"latitude":40.2971532,"longitude":-111.69501,"elevation":1437},"cti4501Conformant":false,"validationMessages":[{"message":"$.metadata.recordGeneratedBy: is missing but it is required","jsonPath":"$.metadata","schemaPath":"#/$defs/OdeMapMetadata/required"},{"message":"$.metadata.receivedMessageDetails.locationData: is missing but it is required","jsonPath":"$.metadata.receivedMessageDetails","schemaPath":"#/$defs/OdeMapMetadata/properties/receivedMessageDetails/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].id.region: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].id","schemaPath":"#/$defs/J2735IntersectionReferenceID/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[6].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[6]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[6].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[6]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[7].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[7]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[7].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[7]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[8].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[8]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[8].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[8]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[9].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[9]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[9].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[9]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[10].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[10]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[10].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[10]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[22].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[22]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[22].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[22]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[23].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[23]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[23].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[23]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[24].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[24]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[24].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[24]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[25].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[25]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[25].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[25]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[26].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[26]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[26].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[26]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[32].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[32]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[32].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[32]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[33].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[33]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[33].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[33]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[34].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[34]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[34].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[34]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[35].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[35]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[35].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[35]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].speedLimits: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0]","schemaPath":"#/$defs/J2735IntersectionGeometry/required"}],"laneWidth":366,"mapSource":"RSU","timeStamp":"@ISO_DATE_TIME@"}} +ProcessedMap;10.164.6.16;6311,6000,{"mapFeatureCollection":{"type":"FeatureCollection","features":[{"type":"Feature","id":10,"geometry":{"coordinates":[[-111.6948409,40.2969746],[-111.6947006,40.2966582],[-111.6945681,40.2963382],[-111.6942976,40.2956952],[-111.6937336,40.2944205]],"type":"LineString"},"properties":{"nodes":[{"delta":[1433,-1984],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1189,-3515],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1123,-3555],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[2292,-7144],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[4780,-14163],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":10,"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":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":31,"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":null}]}},{"type":"Feature","id":11,"geometry":{"coordinates":[[-111.6948823,40.2969752],[-111.6947416,40.2966568],[-111.6946104,40.2963317],[-111.6943345,40.2956892],[-111.6937694,40.2944108]],"type":"LineString"},"properties":{"nodes":[{"delta":[1082,-1978],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1192,-3538],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1112,-3612],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[2338,-7139],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[4789,-14203],"stopLine":null,"dwidth":null,"delevation":null}],"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":3,"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":30,"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":null}]}},{"type":"Feature","id":8,"geometry":{"coordinates":[[-111.6947447,40.296975],[-111.6945987,40.2966224],[-111.6945415,40.296375]],"type":"LineString"},"properties":{"nodes":[{"delta":[2248,-1980],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1237,-3918],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[485,-2749],"stopLine":null,"dwidth":null,"delevation":null}],"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":false,"maneuverUTurnAllowed":false,"maneuverLeftTurnOnRedAllowed":false,"reserved1":false,"maneuverRightAllowed":true,"maneuverLaneChangeAllowed":false,"yieldAllwaysRequired":false,"maneuverRightTurnOnRedAllowed":false,"caution":false},"connectsTo":[{"connectingLane":{"lane":7,"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":2,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":12,"geometry":{"coordinates":[[-111.6949207,40.2969747],[-111.6946355,40.2963144],[-111.6945628,40.2962224]],"type":"LineString"},"properties":{"nodes":[{"delta":[757,-1983],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[2417,-7337],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[616,-1022],"stopLine":null,"dwidth":null,"delevation":null}],"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":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":23,"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":5,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":13,"geometry":{"coordinates":[[-111.6949654,40.2969755],[-111.6946693,40.2963075],[-111.694563,40.2962226]],"type":"LineString"},"properties":{"nodes":[{"delta":[378,-1974],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[2509,-7422],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[901,-943],"stopLine":null,"dwidth":null,"delevation":null}],"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":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":22,"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":5,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":9,"geometry":{"coordinates":[[-111.6947945,40.2969755],[-111.6946603,40.2966635],[-111.6945311,40.2963445],[-111.6942586,40.2957025],[-111.6936955,40.2944313]],"type":"LineString"},"properties":{"nodes":[{"delta":[1826,-1974],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1137,-3467],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1095,-3544],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[2309,-7133],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[4772,-14124],"stopLine":null,"dwidth":null,"delevation":null}],"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":false,"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":32,"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":null}]}},{"type":"Feature","id":16,"geometry":{"coordinates":[[-111.6950993,40.2969606],[-111.6950831,40.2969207]],"type":"LineString"},"properties":{"nodes":[{"delta":[-757,-2140],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[137,-443],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":16,"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":15,"geometry":{"coordinates":[[-111.6950597,40.2969678],[-111.6950435,40.2969279]],"type":"LineString"},"properties":{"nodes":[{"delta":[-421,-2060],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[137,-443],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":15,"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":14,"geometry":{"coordinates":[[-111.6950119,40.2969764],[-111.6949964,40.2969345]],"type":"LineString"},"properties":{"nodes":[{"delta":[-16,-1964],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[131,-466],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":14,"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":6,"geometry":{"coordinates":[[-111.6947034,40.2971076],[-111.6946516,40.2971061]],"type":"LineString"},"properties":{"nodes":[{"delta":[2598,-507],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[439,-17],"stopLine":null,"dwidth":null,"delevation":null}],"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":7,"geometry":{"coordinates":[[-111.6946927,40.2970769],[-111.6946416,40.2970759]],"type":"LineString"},"properties":{"nodes":[{"delta":[2689,-848],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[433,-11],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":7,"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":2,"geometry":{"coordinates":[[-111.6947591,40.2972387],[-111.6935683,40.2972245]],"type":"LineString"},"properties":{"nodes":[{"delta":[2126,950],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[10091,-158],"stopLine":null,"dwidth":null,"delevation":null}],"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":23,"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":8,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":3,"geometry":{"coordinates":[[-111.6947502,40.2972093],[-111.6935675,40.2971992]],"type":"LineString"},"properties":{"nodes":[{"delta":[2202,623],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[10023,-112],"stopLine":null,"dwidth":null,"delevation":null}],"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":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":22,"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":8,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":4,"geometry":{"coordinates":[[-111.694738,40.2971788],[-111.6941318,40.2971713],[-111.6939017,40.2971989]],"type":"LineString"},"properties":{"nodes":[{"delta":[2305,284],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[5137,-83],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1950,307],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":4,"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":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":3,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":5,"geometry":{"coordinates":[[-111.6947267,40.2971466],[-111.6943028,40.2971432],[-111.6941317,40.2971719]],"type":"LineString"},"properties":{"nodes":[{"delta":[2401,-73],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[3592,-38],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1450,319],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":5,"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":14,"maneuver":{"maneuverStraightAllowed":false,"maneuverNoStoppingAllowed":false,"goWithHalt":false,"maneuverLeftAllowed":true,"maneuverUTurnAllowed":true,"maneuverLeftTurnOnRedAllowed":false,"reserved1":false,"maneuverRightAllowed":false,"maneuverLaneChangeAllowed":false,"yieldAllwaysRequired":false,"maneuverRightTurnOnRedAllowed":false,"caution":false}},"remoteIntersection":null,"signalGroup":3,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":1,"geometry":{"coordinates":[[-111.6947696,40.2972705],[-111.693782,40.2972623],[-111.6935771,40.2972531]],"type":"LineString"},"properties":{"nodes":[{"delta":[2037,1303],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[8369,-91],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1736,-102],"stopLine":null,"dwidth":null,"delevation":null}],"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":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":32,"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":8,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":25,"geometry":{"coordinates":[[-111.6952664,40.2973429],[-111.6958094,40.2986271],[-111.6963738,40.2999056]],"type":"LineString"},"properties":{"nodes":[{"delta":[-2173,2108],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-4602,14269],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-4783,14206],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":25,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":7,"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":16,"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":null}]}},{"type":"Feature","id":26,"geometry":{"coordinates":[[-111.6952202,40.2973406],[-111.6957689,40.2986334],[-111.6963331,40.2999146]],"type":"LineString"},"properties":{"nodes":[{"delta":[-1781,2082],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-4650,14364],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-4781,14235],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":26,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":7,"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}},"remoteIntersection":null,"signalGroup":6,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":27,"geometry":{"coordinates":[[-111.6951807,40.29734],[-111.6957307,40.2986348],[-111.6962926,40.2999237]],"type":"LineString"},"properties":{"nodes":[{"delta":[-1447,2076],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-4661,14387],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-4762,14321],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":27,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":7,"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}},"remoteIntersection":null,"signalGroup":6,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":28,"geometry":{"coordinates":[[-111.6951353,40.2973366],[-111.6953943,40.2979223],[-111.6955086,40.2981114]],"type":"LineString"},"properties":{"nodes":[{"delta":[-1062,2038],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-2195,6508],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-969,2101],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":28,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":7,"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":7,"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":1,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":29,"geometry":{"coordinates":[[-111.6950935,40.2973366],[-111.695294,40.2977961],[-111.6953949,40.2979228]],"type":"LineString"},"properties":{"nodes":[{"delta":[-708,2038],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-1699,5105],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-855,1408],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":29,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":7,"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":6,"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":1,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":24,"geometry":{"coordinates":[[-111.6953144,40.2973433],[-111.695503,40.2977839],[-111.6955422,40.2979969]],"type":"LineString"},"properties":{"nodes":[{"delta":[-2580,2112],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-1598,4895],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-332,2367],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":24,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":7,"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":23,"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":6,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":30,"geometry":{"coordinates":[[-111.6950442,40.2973389],[-111.695059,40.2973747]],"type":"LineString"},"properties":{"nodes":[{"delta":[-290,2063],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-125,398],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":30,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":8,"ingressApproach":0,"ingressPath":false,"egressPath":true}},{"type":"Feature","id":31,"geometry":{"coordinates":[[-111.6950017,40.2973394],[-111.6950186,40.2973803]],"type":"LineString"},"properties":{"nodes":[{"delta":[70,2069],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-143,454],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":31,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":8,"ingressApproach":0,"ingressPath":false,"egressPath":true}},{"type":"Feature","id":32,"geometry":{"coordinates":[[-111.6949588,40.2973389],[-111.6949763,40.2973803]],"type":"LineString"},"properties":{"nodes":[{"delta":[434,2063],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-148,460],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":32,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":8,"ingressApproach":0,"ingressPath":false,"egressPath":true}},{"type":"Feature","id":23,"geometry":{"coordinates":[[-111.6953705,40.2972489],[-111.695425,40.2972494]],"type":"LineString"},"properties":{"nodes":[{"delta":[-3055,1063],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-462,6],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":23,"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":22,"geometry":{"coordinates":[[-111.6953725,40.2972147],[-111.695425,40.2972162]],"type":"LineString"},"properties":{"nodes":[{"delta":[-3072,683],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-445,17],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":22,"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":18,"geometry":{"coordinates":[[-111.6952746,40.2970877],[-111.6964743,40.297086]],"type":"LineString"},"properties":{"nodes":[{"delta":[-2242,-728],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-10167,-19],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":18,"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":7,"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":4,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":19,"geometry":{"coordinates":[[-111.6952907,40.2971174],[-111.6964756,40.2971145]],"type":"LineString"},"properties":{"nodes":[{"delta":[-2379,-398],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-10041,-32],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":19,"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":6,"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":4,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":20,"geometry":{"coordinates":[[-111.6953089,40.297147],[-111.6961141,40.2971495],[-111.6962917,40.2971163]],"type":"LineString"},"properties":{"nodes":[{"delta":[-2533,-69],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-6824,28],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-1505,-369],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":20,"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":true,"maneuverUTurnAllowed":false,"maneuverLeftTurnOnRedAllowed":false,"reserved1":false,"maneuverRightAllowed":false,"maneuverLaneChangeAllowed":true,"yieldAllwaysRequired":true,"maneuverRightTurnOnRedAllowed":false,"caution":false},"connectsTo":[{"connectingLane":{"lane":31,"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":7,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":21,"geometry":{"coordinates":[[-111.6953236,40.2971756],[-111.6959863,40.2971761],[-111.6961141,40.29715]],"type":"LineString"},"properties":{"nodes":[{"delta":[-2658,249],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-5616,6],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-1083,-290],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":21,"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":true,"maneuverUTurnAllowed":false,"maneuverLeftTurnOnRedAllowed":false,"reserved1":false,"maneuverRightAllowed":false,"maneuverLaneChangeAllowed":false,"yieldAllwaysRequired":false,"maneuverRightTurnOnRedAllowed":false,"caution":false},"connectsTo":[{"connectingLane":{"lane":30,"maneuver":{"maneuverStraightAllowed":false,"maneuverNoStoppingAllowed":false,"goWithHalt":false,"maneuverLeftAllowed":true,"maneuverUTurnAllowed":true,"maneuverLeftTurnOnRedAllowed":false,"reserved1":false,"maneuverRightAllowed":false,"maneuverLaneChangeAllowed":false,"yieldAllwaysRequired":false,"maneuverRightTurnOnRedAllowed":false,"caution":false}},"remoteIntersection":null,"signalGroup":7,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":17,"geometry":{"coordinates":[[-111.6952574,40.2970542],[-111.6959705,40.2970588],[-111.6961326,40.2970849]],"type":"LineString"},"properties":{"nodes":[{"delta":[-2097,-1100],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-6043,51],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-1374,290],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":17,"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":16,"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":4,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":34,"geometry":{"coordinates":[[-111.694707,40.2970001],[-111.6951879,40.2969977]],"type":"LineString"},"properties":{"nodes":[{"delta":[2568,-1701],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-4075,-27],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":34,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":0,"ingressPath":false,"egressPath":false}},{"type":"Feature","id":35,"geometry":{"coordinates":[[-111.6952023,40.2970198],[-111.6953688,40.2973123]],"type":"LineString"},"properties":{"nodes":[{"delta":[-1630,-1482],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-1411,3250],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":35,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":0,"ingressPath":false,"egressPath":false}},{"type":"Feature","id":36,"geometry":{"coordinates":[[-111.6953605,40.2973241],[-111.6948565,40.2973006]],"type":"LineString"},"properties":{"nodes":[{"delta":[-2970,1899],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[4271,-261],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":36,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":0,"ingressPath":false,"egressPath":false}},{"type":"Feature","id":33,"geometry":{"coordinates":[[-111.694819,40.2972895],[-111.6946964,40.2970125]],"type":"LineString"},"properties":{"nodes":[{"delta":[1619,1514],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1039,-3078],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":33,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":0,"ingressPath":false,"egressPath":false}}]},"connectingLanesFeatureCollection":{"type":"FeatureCollection","features":[{"type":"Feature","id":"10-31","geometry":{"coordinates":[[-111.6948409,40.2969746],[-111.6950017,40.2973394]],"type":"LineString"},"properties":{"signalGroupId":2,"ingressLaneId":10,"egressLaneId":31}},{"type":"Feature","id":"11-30","geometry":{"coordinates":[[-111.6948823,40.2969752],[-111.6950442,40.2973389]],"type":"LineString"},"properties":{"signalGroupId":2,"ingressLaneId":11,"egressLaneId":30}},{"type":"Feature","id":"8-7","geometry":{"coordinates":[[-111.6947447,40.296975],[-111.6946927,40.2970769]],"type":"LineString"},"properties":{"signalGroupId":2,"ingressLaneId":8,"egressLaneId":7}},{"type":"Feature","id":"12-23","geometry":{"coordinates":[[-111.6949207,40.2969747],[-111.6953705,40.2972489]],"type":"LineString"},"properties":{"signalGroupId":5,"ingressLaneId":12,"egressLaneId":23}},{"type":"Feature","id":"13-22","geometry":{"coordinates":[[-111.6949654,40.2969755],[-111.6953725,40.2972147]],"type":"LineString"},"properties":{"signalGroupId":5,"ingressLaneId":13,"egressLaneId":22}},{"type":"Feature","id":"9-32","geometry":{"coordinates":[[-111.6947945,40.2969755],[-111.6949588,40.2973389]],"type":"LineString"},"properties":{"signalGroupId":2,"ingressLaneId":9,"egressLaneId":32}},{"type":"Feature","id":"2-23","geometry":{"coordinates":[[-111.6947591,40.2972387],[-111.6953705,40.2972489]],"type":"LineString"},"properties":{"signalGroupId":8,"ingressLaneId":2,"egressLaneId":23}},{"type":"Feature","id":"3-22","geometry":{"coordinates":[[-111.6947502,40.2972093],[-111.6953725,40.2972147]],"type":"LineString"},"properties":{"signalGroupId":8,"ingressLaneId":3,"egressLaneId":22}},{"type":"Feature","id":"4-15","geometry":{"coordinates":[[-111.694738,40.2971788],[-111.6950597,40.2969678]],"type":"LineString"},"properties":{"signalGroupId":3,"ingressLaneId":4,"egressLaneId":15}},{"type":"Feature","id":"5-14","geometry":{"coordinates":[[-111.6947267,40.2971466],[-111.6950119,40.2969764]],"type":"LineString"},"properties":{"signalGroupId":3,"ingressLaneId":5,"egressLaneId":14}},{"type":"Feature","id":"1-32","geometry":{"coordinates":[[-111.6947696,40.2972705],[-111.6949588,40.2973389]],"type":"LineString"},"properties":{"signalGroupId":8,"ingressLaneId":1,"egressLaneId":32}},{"type":"Feature","id":"25-16","geometry":{"coordinates":[[-111.6952664,40.2973429],[-111.6950993,40.2969606]],"type":"LineString"},"properties":{"signalGroupId":6,"ingressLaneId":25,"egressLaneId":16}},{"type":"Feature","id":"26-15","geometry":{"coordinates":[[-111.6952202,40.2973406],[-111.6950597,40.2969678]],"type":"LineString"},"properties":{"signalGroupId":6,"ingressLaneId":26,"egressLaneId":15}},{"type":"Feature","id":"27-14","geometry":{"coordinates":[[-111.6951807,40.29734],[-111.6950119,40.2969764]],"type":"LineString"},"properties":{"signalGroupId":6,"ingressLaneId":27,"egressLaneId":14}},{"type":"Feature","id":"28-7","geometry":{"coordinates":[[-111.6951353,40.2973366],[-111.6946927,40.2970769]],"type":"LineString"},"properties":{"signalGroupId":1,"ingressLaneId":28,"egressLaneId":7}},{"type":"Feature","id":"29-6","geometry":{"coordinates":[[-111.6950935,40.2973366],[-111.6947034,40.2971076]],"type":"LineString"},"properties":{"signalGroupId":1,"ingressLaneId":29,"egressLaneId":6}},{"type":"Feature","id":"24-23","geometry":{"coordinates":[[-111.6953144,40.2973433],[-111.6953705,40.2972489]],"type":"LineString"},"properties":{"signalGroupId":6,"ingressLaneId":24,"egressLaneId":23}},{"type":"Feature","id":"18-7","geometry":{"coordinates":[[-111.6952746,40.2970877],[-111.6946927,40.2970769]],"type":"LineString"},"properties":{"signalGroupId":4,"ingressLaneId":18,"egressLaneId":7}},{"type":"Feature","id":"19-6","geometry":{"coordinates":[[-111.6952907,40.2971174],[-111.6947034,40.2971076]],"type":"LineString"},"properties":{"signalGroupId":4,"ingressLaneId":19,"egressLaneId":6}},{"type":"Feature","id":"20-31","geometry":{"coordinates":[[-111.6953089,40.297147],[-111.6950017,40.2973394]],"type":"LineString"},"properties":{"signalGroupId":7,"ingressLaneId":20,"egressLaneId":31}},{"type":"Feature","id":"21-30","geometry":{"coordinates":[[-111.6953236,40.2971756],[-111.6950442,40.2973389]],"type":"LineString"},"properties":{"signalGroupId":7,"ingressLaneId":21,"egressLaneId":30}},{"type":"Feature","id":"17-16","geometry":{"coordinates":[[-111.6952574,40.2970542],[-111.6950993,40.2969606]],"type":"LineString"},"properties":{"signalGroupId":4,"ingressLaneId":17,"egressLaneId":16}}]},"properties":{"messageType":"MAP","odeReceivedAt":"@ISO_DATE_TIME@","originIp":"10.164.6.16","intersectionName":"N State St & E Center St","intersectionId":6311,"msgIssueRevision":0,"revision":7,"refPoint":{"latitude":40.2971532,"longitude":-111.69501,"elevation":1437},"cti4501Conformant":false,"validationMessages":[{"message":"$.metadata.recordGeneratedBy: is missing but it is required","jsonPath":"$.metadata","schemaPath":"#/$defs/OdeMapMetadata/required"},{"message":"$.metadata.receivedMessageDetails.locationData: is missing but it is required","jsonPath":"$.metadata.receivedMessageDetails","schemaPath":"#/$defs/OdeMapMetadata/properties/receivedMessageDetails/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].id.region: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].id","schemaPath":"#/$defs/J2735IntersectionReferenceID/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[6].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[6]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[6].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[6]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[7].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[7]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[7].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[7]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[8].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[8]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[8].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[8]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[9].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[9]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[9].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[9]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[10].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[10]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[10].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[10]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[22].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[22]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[22].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[22]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[23].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[23]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[23].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[23]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[24].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[24]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[24].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[24]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[25].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[25]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[25].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[25]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[26].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[26]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[26].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[26]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[32].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[32]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[32].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[32]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[33].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[33]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[33].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[33]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[34].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[34]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[34].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[34]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[35].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[35]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[35].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[35]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].speedLimits: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0]","schemaPath":"#/$defs/J2735IntersectionGeometry/required"}],"laneWidth":366,"mapSource":"RSU","timeStamp":"@ISO_DATE_TIME@"}} diff --git a/jpo-conflictmonitor/scripts/IntegrationTestScripts/ProcessedSpat_Revisions.csv b/jpo-conflictmonitor/scripts/IntegrationTestScripts/ProcessedSpat_Revisions.csv new file mode 100644 index 00000000..1732cd43 --- /dev/null +++ b/jpo-conflictmonitor/scripts/IntegrationTestScripts/ProcessedSpat_Revisions.csv @@ -0,0 +1,7 @@ +ProcessedSpat;10.164.6.18;6311,1000,{"messageType":"SPAT","odeReceivedAt":"@ISO_DATE_TIME@","originIp":"10.164.6.18","name":"N State St & E Center St","intersectionId":6311,"cti4501Conformant":false,"validationMessages":[{"message":"$.metadata.receivedMessageDetails.locationData: is missing but it is required","jsonPath":"$.metadata.receivedMessageDetails","schemaPath":"#/$defs/OdeSpatMetadata/properties/receivedMessageDetails/required"},{"message":"$.metadata.encodings: is missing but it is required","jsonPath":"$.metadata","schemaPath":"#/$defs/OdeSpatMetadata/required"},{"message":"$.metadata.recordGeneratedBy: is missing but it is required","jsonPath":"$.metadata","schemaPath":"#/$defs/OdeSpatMetadata/required"},{"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.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.maxEndTime: 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":45,"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":"@ISO_DATE_TIME@","enabledLanes":[],"states":[{"signalGroup":1,"stateTimeSpeed":[{"eventState":"STOP_AND_REMAIN","timing":{"startTime":null,"minEndTime":"@OFFSET_SECONDS_78.61899995803833@","maxEndTime":"@OFFSET_SECONDS_78.61899995803833@","likelyTime":null,"confidence":null,"nextTime":null}}]},{"signalGroup":2,"stateTimeSpeed":[{"eventState":"STOP_AND_REMAIN","timing":{"startTime":null,"minEndTime":"@OFFSET_SECONDS_28.61899995803833@","maxEndTime":"@OFFSET_SECONDS_28.61899995803833@","likelyTime":null,"confidence":null,"nextTime":null}}]},{"signalGroup":3,"stateTimeSpeed":[{"eventState":"STOP_AND_REMAIN","timing":{"startTime":null,"minEndTime":"@OFFSET_SECONDS_98.61899995803833@","maxEndTime":"@OFFSET_SECONDS_98.61899995803833@","likelyTime":null,"confidence":null,"nextTime":null}}]},{"signalGroup":4,"stateTimeSpeed":[{"eventState":"PROTECTED_MOVEMENT_ALLOWED","timing":{"startTime":null,"minEndTime":"@OFFSET_SECONDS_14.418999910354614@","maxEndTime":"@OFFSET_SECONDS_22.418999910354614@","likelyTime":null,"confidence":null,"nextTime":null}}]},{"signalGroup":5,"stateTimeSpeed":[{"eventState":"STOP_AND_REMAIN","timing":{"startTime":null,"minEndTime":"@OFFSET_SECONDS_28.61899995803833@","maxEndTime":"@OFFSET_SECONDS_28.61899995803833@","likelyTime":null,"confidence":null,"nextTime":null}}]},{"signalGroup":6,"stateTimeSpeed":[{"eventState":"STOP_AND_REMAIN","timing":{"startTime":null,"minEndTime":"@OFFSET_SECONDS_58.61899995803833@","maxEndTime":"@OFFSET_SECONDS_58.61899995803833@","likelyTime":null,"confidence":null,"nextTime":null}}]},{"signalGroup":7,"stateTimeSpeed":[{"eventState":"PROTECTED_MOVEMENT_ALLOWED","timing":{"startTime":null,"minEndTime":"@OFFSET_SECONDS_3.319000005722046@","maxEndTime":"@OFFSET_SECONDS_22.7189998626709@","likelyTime":null,"confidence":null,"nextTime":null}}]},{"signalGroup":8,"stateTimeSpeed":[{"eventState":"STOP_AND_REMAIN","timing":{"startTime":null,"minEndTime":"@OFFSET_SECONDS_-0.08100008964538574@","maxEndTime":null,"likelyTime":null,"confidence":null,"nextTime":null}}]}]} +ProcessedSpat;10.164.6.18;6311,1000,{"messageType":"SPAT","odeReceivedAt":"@ISO_DATE_TIME@","originIp":"10.164.6.18","name":"N State St & E Center St","intersectionId":6311,"cti4501Conformant":false,"validationMessages":[{"message":"$.metadata.receivedMessageDetails.locationData: is missing but it is required","jsonPath":"$.metadata.receivedMessageDetails","schemaPath":"#/$defs/OdeSpatMetadata/properties/receivedMessageDetails/required"},{"message":"$.metadata.encodings: is missing but it is required","jsonPath":"$.metadata","schemaPath":"#/$defs/OdeSpatMetadata/required"},{"message":"$.metadata.recordGeneratedBy: is missing but it is required","jsonPath":"$.metadata","schemaPath":"#/$defs/OdeSpatMetadata/required"},{"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.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.maxEndTime: 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":45,"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":"@ISO_DATE_TIME@","enabledLanes":[],"states":[{"signalGroup":1,"stateTimeSpeed":[{"eventState":"STOP_AND_REMAIN","timing":{"startTime":null,"minEndTime":"@OFFSET_SECONDS_78.61899995803833@","maxEndTime":"@OFFSET_SECONDS_78.61899995803833@","likelyTime":null,"confidence":null,"nextTime":null}}]},{"signalGroup":2,"stateTimeSpeed":[{"eventState":"STOP_AND_REMAIN","timing":{"startTime":null,"minEndTime":"@OFFSET_SECONDS_28.61899995803833@","maxEndTime":"@OFFSET_SECONDS_28.61899995803833@","likelyTime":null,"confidence":null,"nextTime":null}}]},{"signalGroup":3,"stateTimeSpeed":[{"eventState":"STOP_AND_REMAIN","timing":{"startTime":null,"minEndTime":"@OFFSET_SECONDS_98.61899995803833@","maxEndTime":"@OFFSET_SECONDS_98.61899995803833@","likelyTime":null,"confidence":null,"nextTime":null}}]},{"signalGroup":4,"stateTimeSpeed":[{"eventState":"PROTECTED_MOVEMENT_ALLOWED","timing":{"startTime":null,"minEndTime":"@OFFSET_SECONDS_14.418999910354614@","maxEndTime":"@OFFSET_SECONDS_22.418999910354614@","likelyTime":null,"confidence":null,"nextTime":null}}]},{"signalGroup":5,"stateTimeSpeed":[{"eventState":"STOP_AND_REMAIN","timing":{"startTime":null,"minEndTime":"@OFFSET_SECONDS_28.61899995803833@","maxEndTime":"@OFFSET_SECONDS_28.61899995803833@","likelyTime":null,"confidence":null,"nextTime":null}}]},{"signalGroup":6,"stateTimeSpeed":[{"eventState":"STOP_AND_REMAIN","timing":{"startTime":null,"minEndTime":"@OFFSET_SECONDS_58.61899995803833@","maxEndTime":"@OFFSET_SECONDS_58.61899995803833@","likelyTime":null,"confidence":null,"nextTime":null}}]},{"signalGroup":7,"stateTimeSpeed":[{"eventState":"PROTECTED_MOVEMENT_ALLOWED","timing":{"startTime":null,"minEndTime":"@OFFSET_SECONDS_3.319000005722046@","maxEndTime":"@OFFSET_SECONDS_22.7189998626709@","likelyTime":null,"confidence":null,"nextTime":null}}]},{"signalGroup":8,"stateTimeSpeed":[{"eventState":"STOP_AND_REMAIN","timing":{"startTime":null,"minEndTime":"@OFFSET_SECONDS_-0.08100008964538574@","maxEndTime":null,"likelyTime":null,"confidence":null,"nextTime":null}}]}]} +ProcessedSpat;10.164.6.18;6311,2000,{"messageType":"SPAT","odeReceivedAt":"@ISO_DATE_TIME@","originIp":"10.164.6.18","name":"N State St & E Center St","intersectionId":6311,"cti4501Conformant":false,"validationMessages":[{"message":"$.metadata.receivedMessageDetails.locationData: is missing but it is required","jsonPath":"$.metadata.receivedMessageDetails","schemaPath":"#/$defs/OdeSpatMetadata/properties/receivedMessageDetails/required"},{"message":"$.metadata.encodings: is missing but it is required","jsonPath":"$.metadata","schemaPath":"#/$defs/OdeSpatMetadata/required"},{"message":"$.metadata.recordGeneratedBy: is missing but it is required","jsonPath":"$.metadata","schemaPath":"#/$defs/OdeSpatMetadata/required"},{"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.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.maxEndTime: 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":45,"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":"@ISO_DATE_TIME@","enabledLanes":[],"states":[{"signalGroup":1,"stateTimeSpeed":[{"eventState":"STOP_AND_REMAIN","timing":{"startTime":null,"minEndTime":"@OFFSET_SECONDS_78.61899995803833@","maxEndTime":"@OFFSET_SECONDS_78.61899995803833@","likelyTime":null,"confidence":null,"nextTime":null}}]},{"signalGroup":2,"stateTimeSpeed":[{"eventState":"STOP_AND_REMAIN","timing":{"startTime":null,"minEndTime":"@OFFSET_SECONDS_28.61899995803833@","maxEndTime":"@OFFSET_SECONDS_28.61899995803833@","likelyTime":null,"confidence":null,"nextTime":null}}]},{"signalGroup":3,"stateTimeSpeed":[{"eventState":"STOP_AND_REMAIN","timing":{"startTime":null,"minEndTime":"@OFFSET_SECONDS_98.61899995803833@","maxEndTime":"@OFFSET_SECONDS_98.61899995803833@","likelyTime":null,"confidence":null,"nextTime":null}}]},{"signalGroup":4,"stateTimeSpeed":[{"eventState":"PROTECTED_MOVEMENT_ALLOWED","timing":{"startTime":null,"minEndTime":"@OFFSET_SECONDS_14.418999910354614@","maxEndTime":"@OFFSET_SECONDS_22.418999910354614@","likelyTime":null,"confidence":null,"nextTime":null}}]},{"signalGroup":5,"stateTimeSpeed":[{"eventState":"STOP_AND_REMAIN","timing":{"startTime":null,"minEndTime":"@OFFSET_SECONDS_28.61899995803833@","maxEndTime":"@OFFSET_SECONDS_28.61899995803833@","likelyTime":null,"confidence":null,"nextTime":null}}]},{"signalGroup":6,"stateTimeSpeed":[{"eventState":"STOP_AND_REMAIN","timing":{"startTime":null,"minEndTime":"@OFFSET_SECONDS_58.61899995803833@","maxEndTime":"@OFFSET_SECONDS_58.61899995803833@","likelyTime":null,"confidence":null,"nextTime":null}}]},{"signalGroup":7,"stateTimeSpeed":[{"eventState":"PROTECTED_MOVEMENT_ALLOWED","timing":{"startTime":null,"minEndTime":"@OFFSET_SECONDS_3.319000005722046@","maxEndTime":"@OFFSET_SECONDS_22.7189998626709@","likelyTime":null,"confidence":null,"nextTime":null}}]},{"signalGroup":8,"stateTimeSpeed":[{"eventState":"STOP_AND_REMAIN","timing":{"startTime":null,"minEndTime":"@OFFSET_SECONDS_-0.08100008964538574@","maxEndTime":null,"likelyTime":null,"confidence":null,"nextTime":null}}]}]} +ProcessedSpat;10.164.6.18;6311,3000,{"messageType":"SPAT","odeReceivedAt":"@ISO_DATE_TIME@","originIp":"10.164.6.18","name":"N State St & E Center St","intersectionId":6311,"cti4501Conformant":false,"validationMessages":[{"message":"$.metadata.receivedMessageDetails.locationData: is missing but it is required","jsonPath":"$.metadata.receivedMessageDetails","schemaPath":"#/$defs/OdeSpatMetadata/properties/receivedMessageDetails/required"},{"message":"$.metadata.encodings: is missing but it is required","jsonPath":"$.metadata","schemaPath":"#/$defs/OdeSpatMetadata/required"},{"message":"$.metadata.recordGeneratedBy: is missing but it is required","jsonPath":"$.metadata","schemaPath":"#/$defs/OdeSpatMetadata/required"},{"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.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.maxEndTime: 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":46,"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":"@ISO_DATE_TIME@","enabledLanes":[],"states":[{"signalGroup":1,"stateTimeSpeed":[{"eventState":"STOP_AND_REMAIN","timing":{"startTime":null,"minEndTime":"@OFFSET_SECONDS_78.61899995803833@","maxEndTime":"@OFFSET_SECONDS_78.61899995803833@","likelyTime":null,"confidence":null,"nextTime":null}}]},{"signalGroup":2,"stateTimeSpeed":[{"eventState":"STOP_AND_REMAIN","timing":{"startTime":null,"minEndTime":"@OFFSET_SECONDS_28.61899995803833@","maxEndTime":"@OFFSET_SECONDS_28.61899995803833@","likelyTime":null,"confidence":null,"nextTime":null}}]},{"signalGroup":3,"stateTimeSpeed":[{"eventState":"STOP_AND_REMAIN","timing":{"startTime":null,"minEndTime":"@OFFSET_SECONDS_98.61899995803833@","maxEndTime":"@OFFSET_SECONDS_98.61899995803833@","likelyTime":null,"confidence":null,"nextTime":null}}]},{"signalGroup":4,"stateTimeSpeed":[{"eventState":"PROTECTED_MOVEMENT_ALLOWED","timing":{"startTime":null,"minEndTime":"@OFFSET_SECONDS_14.418999910354614@","maxEndTime":"@OFFSET_SECONDS_22.418999910354614@","likelyTime":null,"confidence":null,"nextTime":null}}]},{"signalGroup":5,"stateTimeSpeed":[{"eventState":"STOP_AND_REMAIN","timing":{"startTime":null,"minEndTime":"@OFFSET_SECONDS_28.61899995803833@","maxEndTime":"@OFFSET_SECONDS_28.61899995803833@","likelyTime":null,"confidence":null,"nextTime":null}}]},{"signalGroup":6,"stateTimeSpeed":[{"eventState":"STOP_AND_REMAIN","timing":{"startTime":null,"minEndTime":"@OFFSET_SECONDS_58.61899995803833@","maxEndTime":"@OFFSET_SECONDS_58.61899995803833@","likelyTime":null,"confidence":null,"nextTime":null}}]},{"signalGroup":7,"stateTimeSpeed":[{"eventState":"PROTECTED_MOVEMENT_ALLOWED","timing":{"startTime":null,"minEndTime":"@OFFSET_SECONDS_3.319000005722046@","maxEndTime":"@OFFSET_SECONDS_22.7189998626709@","likelyTime":null,"confidence":null,"nextTime":null}}]},{"signalGroup":8,"stateTimeSpeed":[{"eventState":"STOP_AND_REMAIN","timing":{"startTime":null,"minEndTime":"@OFFSET_SECONDS_-0.08100008964538574@","maxEndTime":null,"likelyTime":null,"confidence":null,"nextTime":null}}]}]} +ProcessedSpat;10.164.6.18;6311,4000,{"messageType":"SPAT","odeReceivedAt":"@ISO_DATE_TIME@","originIp":"10.164.6.18","name":"N State St & E Center St","intersectionId":6311,"cti4501Conformant":false,"validationMessages":[{"message":"$.metadata.receivedMessageDetails.locationData: is missing but it is required","jsonPath":"$.metadata.receivedMessageDetails","schemaPath":"#/$defs/OdeSpatMetadata/properties/receivedMessageDetails/required"},{"message":"$.metadata.encodings: is missing but it is required","jsonPath":"$.metadata","schemaPath":"#/$defs/OdeSpatMetadata/required"},{"message":"$.metadata.recordGeneratedBy: is missing but it is required","jsonPath":"$.metadata","schemaPath":"#/$defs/OdeSpatMetadata/required"},{"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.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.maxEndTime: 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":47,"status":{"manualControlIsEnabled":false,"stopTimeIsActivated":false,"failureFlash":false,"preemptIsActive":true,"signalPriorityIsActive":false,"fixedTimeOperation":false,"trafficDependentOperation":false,"standbyOperation":false,"failureMode":false,"off":false,"recentMAPmessageUpdate":true,"recentChangeInMAPassignedLanesIDsUsed":true,"noValidMAPisAvailableAtThisTime":false,"noValidSPATisAvailableAtThisTime":false},"utcTimeStamp":"@ISO_DATE_TIME@","enabledLanes":[],"states":[{"signalGroup":1,"stateTimeSpeed":[{"eventState":"STOP_AND_REMAIN","timing":{"startTime":null,"minEndTime":"@OFFSET_SECONDS_78.61899995803833@","maxEndTime":"@OFFSET_SECONDS_78.61899995803833@","likelyTime":null,"confidence":null,"nextTime":null}}]},{"signalGroup":2,"stateTimeSpeed":[{"eventState":"STOP_AND_REMAIN","timing":{"startTime":null,"minEndTime":"@OFFSET_SECONDS_28.61899995803833@","maxEndTime":"@OFFSET_SECONDS_28.61899995803833@","likelyTime":null,"confidence":null,"nextTime":null}}]},{"signalGroup":3,"stateTimeSpeed":[{"eventState":"STOP_AND_REMAIN","timing":{"startTime":null,"minEndTime":"@OFFSET_SECONDS_98.61899995803833@","maxEndTime":"@OFFSET_SECONDS_98.61899995803833@","likelyTime":null,"confidence":null,"nextTime":null}}]},{"signalGroup":4,"stateTimeSpeed":[{"eventState":"PROTECTED_MOVEMENT_ALLOWED","timing":{"startTime":null,"minEndTime":"@OFFSET_SECONDS_14.418999910354614@","maxEndTime":"@OFFSET_SECONDS_22.418999910354614@","likelyTime":null,"confidence":null,"nextTime":null}}]},{"signalGroup":5,"stateTimeSpeed":[{"eventState":"STOP_AND_REMAIN","timing":{"startTime":null,"minEndTime":"@OFFSET_SECONDS_28.61899995803833@","maxEndTime":"@OFFSET_SECONDS_28.61899995803833@","likelyTime":null,"confidence":null,"nextTime":null}}]},{"signalGroup":6,"stateTimeSpeed":[{"eventState":"STOP_AND_REMAIN","timing":{"startTime":null,"minEndTime":"@OFFSET_SECONDS_58.61899995803833@","maxEndTime":"@OFFSET_SECONDS_58.61899995803833@","likelyTime":null,"confidence":null,"nextTime":null}}]},{"signalGroup":7,"stateTimeSpeed":[{"eventState":"PROTECTED_MOVEMENT_ALLOWED","timing":{"startTime":null,"minEndTime":"@OFFSET_SECONDS_3.319000005722046@","maxEndTime":"@OFFSET_SECONDS_22.7189998626709@","likelyTime":null,"confidence":null,"nextTime":null}}]},{"signalGroup":8,"stateTimeSpeed":[{"eventState":"STOP_AND_REMAIN","timing":{"startTime":null,"minEndTime":"@OFFSET_SECONDS_-0.08100008964538574@","maxEndTime":null,"likelyTime":null,"confidence":null,"nextTime":null}}]}]} +ProcessedSpat;10.164.6.18;6311,5000,{"messageType":"SPAT","odeReceivedAt":"@ISO_DATE_TIME@","originIp":"10.164.6.18","name":"N State St & E Center St","intersectionId":6311,"cti4501Conformant":false,"validationMessages":[{"message":"$.metadata.receivedMessageDetails.locationData: is missing but it is required","jsonPath":"$.metadata.receivedMessageDetails","schemaPath":"#/$defs/OdeSpatMetadata/properties/receivedMessageDetails/required"},{"message":"$.metadata.encodings: is missing but it is required","jsonPath":"$.metadata","schemaPath":"#/$defs/OdeSpatMetadata/required"},{"message":"$.metadata.recordGeneratedBy: is missing but it is required","jsonPath":"$.metadata","schemaPath":"#/$defs/OdeSpatMetadata/required"},{"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.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.maxEndTime: 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":48,"status":{"manualControlIsEnabled":false,"stopTimeIsActivated":false,"failureFlash":false,"preemptIsActive":true,"signalPriorityIsActive":false,"fixedTimeOperation":false,"trafficDependentOperation":false,"standbyOperation":false,"failureMode":false,"off":false,"recentMAPmessageUpdate":true,"recentChangeInMAPassignedLanesIDsUsed":true,"noValidMAPisAvailableAtThisTime":true,"noValidSPATisAvailableAtThisTime":false},"utcTimeStamp":"@ISO_DATE_TIME@","enabledLanes":[],"states":[{"signalGroup":1,"stateTimeSpeed":[{"eventState":"STOP_AND_REMAIN","timing":{"startTime":null,"minEndTime":"@OFFSET_SECONDS_78.61899995803833@","maxEndTime":"@OFFSET_SECONDS_78.61899995803833@","likelyTime":null,"confidence":null,"nextTime":null}}]},{"signalGroup":2,"stateTimeSpeed":[{"eventState":"STOP_AND_REMAIN","timing":{"startTime":null,"minEndTime":"@OFFSET_SECONDS_28.61899995803833@","maxEndTime":"@OFFSET_SECONDS_28.61899995803833@","likelyTime":null,"confidence":null,"nextTime":null}}]},{"signalGroup":3,"stateTimeSpeed":[{"eventState":"STOP_AND_REMAIN","timing":{"startTime":null,"minEndTime":"@OFFSET_SECONDS_98.61899995803833@","maxEndTime":"@OFFSET_SECONDS_98.61899995803833@","likelyTime":null,"confidence":null,"nextTime":null}}]},{"signalGroup":4,"stateTimeSpeed":[{"eventState":"PROTECTED_MOVEMENT_ALLOWED","timing":{"startTime":null,"minEndTime":"@OFFSET_SECONDS_14.418999910354614@","maxEndTime":"@OFFSET_SECONDS_22.418999910354614@","likelyTime":null,"confidence":null,"nextTime":null}}]},{"signalGroup":5,"stateTimeSpeed":[{"eventState":"STOP_AND_REMAIN","timing":{"startTime":null,"minEndTime":"@OFFSET_SECONDS_28.61899995803833@","maxEndTime":"@OFFSET_SECONDS_28.61899995803833@","likelyTime":null,"confidence":null,"nextTime":null}}]},{"signalGroup":6,"stateTimeSpeed":[{"eventState":"STOP_AND_REMAIN","timing":{"startTime":null,"minEndTime":"@OFFSET_SECONDS_58.61899995803833@","maxEndTime":"@OFFSET_SECONDS_58.61899995803833@","likelyTime":null,"confidence":null,"nextTime":null}}]},{"signalGroup":7,"stateTimeSpeed":[{"eventState":"PROTECTED_MOVEMENT_ALLOWED","timing":{"startTime":null,"minEndTime":"@OFFSET_SECONDS_3.319000005722046@","maxEndTime":"@OFFSET_SECONDS_22.7189998626709@","likelyTime":null,"confidence":null,"nextTime":null}}]},{"signalGroup":8,"stateTimeSpeed":[{"eventState":"STOP_AND_REMAIN","timing":{"startTime":null,"minEndTime":"@OFFSET_SECONDS_-0.08100008964538574@","maxEndTime":null,"likelyTime":null,"confidence":null,"nextTime":null}}]}]} +ProcessedSpat;10.164.6.18;6311,6000,{"messageType":"SPAT","odeReceivedAt":"@ISO_DATE_TIME@","originIp":"10.164.6.18","name":"N State St & E Centre St","intersectionId":6311,"cti4501Conformant":false,"validationMessages":[{"message":"$.metadata.receivedMessageDetails.locationData: is missing but it is required","jsonPath":"$.metadata.receivedMessageDetails","schemaPath":"#/$defs/OdeSpatMetadata/properties/receivedMessageDetails/required"},{"message":"$.metadata.encodings: is missing but it is required","jsonPath":"$.metadata","schemaPath":"#/$defs/OdeSpatMetadata/required"},{"message":"$.metadata.recordGeneratedBy: is missing but it is required","jsonPath":"$.metadata","schemaPath":"#/$defs/OdeSpatMetadata/required"},{"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.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.maxEndTime: 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":48,"status":{"manualControlIsEnabled":false,"stopTimeIsActivated":false,"failureFlash":false,"preemptIsActive":true,"signalPriorityIsActive":false,"fixedTimeOperation":false,"trafficDependentOperation":false,"standbyOperation":false,"failureMode":false,"off":false,"recentMAPmessageUpdate":true,"recentChangeInMAPassignedLanesIDsUsed":true,"noValidMAPisAvailableAtThisTime":true,"noValidSPATisAvailableAtThisTime":false},"utcTimeStamp":"@ISO_DATE_TIME@","enabledLanes":[],"states":[{"signalGroup":1,"stateTimeSpeed":[{"eventState":"STOP_AND_REMAIN","timing":{"startTime":null,"minEndTime":"@OFFSET_SECONDS_78.61899995803833@","maxEndTime":"@OFFSET_SECONDS_78.61899995803833@","likelyTime":null,"confidence":null,"nextTime":null}}]},{"signalGroup":2,"stateTimeSpeed":[{"eventState":"STOP_AND_REMAIN","timing":{"startTime":null,"minEndTime":"@OFFSET_SECONDS_28.61899995803833@","maxEndTime":"@OFFSET_SECONDS_28.61899995803833@","likelyTime":null,"confidence":null,"nextTime":null}}]},{"signalGroup":3,"stateTimeSpeed":[{"eventState":"STOP_AND_REMAIN","timing":{"startTime":null,"minEndTime":"@OFFSET_SECONDS_98.61899995803833@","maxEndTime":"@OFFSET_SECONDS_98.61899995803833@","likelyTime":null,"confidence":null,"nextTime":null}}]},{"signalGroup":4,"stateTimeSpeed":[{"eventState":"PROTECTED_MOVEMENT_ALLOWED","timing":{"startTime":null,"minEndTime":"@OFFSET_SECONDS_14.418999910354614@","maxEndTime":"@OFFSET_SECONDS_22.418999910354614@","likelyTime":null,"confidence":null,"nextTime":null}}]},{"signalGroup":5,"stateTimeSpeed":[{"eventState":"STOP_AND_REMAIN","timing":{"startTime":null,"minEndTime":"@OFFSET_SECONDS_28.61899995803833@","maxEndTime":"@OFFSET_SECONDS_28.61899995803833@","likelyTime":null,"confidence":null,"nextTime":null}}]},{"signalGroup":6,"stateTimeSpeed":[{"eventState":"STOP_AND_REMAIN","timing":{"startTime":null,"minEndTime":"@OFFSET_SECONDS_58.61899995803833@","maxEndTime":"@OFFSET_SECONDS_58.61899995803833@","likelyTime":null,"confidence":null,"nextTime":null}}]},{"signalGroup":7,"stateTimeSpeed":[{"eventState":"PROTECTED_MOVEMENT_ALLOWED","timing":{"startTime":null,"minEndTime":"@OFFSET_SECONDS_3.319000005722046@","maxEndTime":"@OFFSET_SECONDS_22.7189998626709@","likelyTime":null,"confidence":null,"nextTime":null}}]},{"signalGroup":8,"stateTimeSpeed":[{"eventState":"STOP_AND_REMAIN","timing":{"startTime":null,"minEndTime":"@OFFSET_SECONDS_-0.08100008964538574@","maxEndTime":null,"likelyTime":null,"confidence":null,"nextTime":null}}]}]} diff --git a/jpo-conflictmonitor/scripts/IntegrationTestScripts/TimestampDelta-ProcessedMap.csv b/jpo-conflictmonitor/scripts/IntegrationTestScripts/TimestampDelta-ProcessedMap.csv new file mode 100644 index 00000000..8bc22683 --- /dev/null +++ b/jpo-conflictmonitor/scripts/IntegrationTestScripts/TimestampDelta-ProcessedMap.csv @@ -0,0 +1,4 @@ +ProcessedMap;10.164.6.16;6311,1000,{"mapFeatureCollection":{"type":"FeatureCollection","features":[{"type":"Feature","id":10,"geometry":{"coordinates":[[-111.6948409,40.2969746],[-111.6947006,40.2966582],[-111.6945681,40.2963382],[-111.6942976,40.2956952],[-111.6937336,40.2944205]],"type":"LineString"},"properties":{"nodes":[{"delta":[1433,-1984],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1189,-3515],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1123,-3555],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[2292,-7144],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[4780,-14163],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":10,"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":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":31,"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":null}]}},{"type":"Feature","id":11,"geometry":{"coordinates":[[-111.6948823,40.2969752],[-111.6947416,40.2966568],[-111.6946104,40.2963317],[-111.6943345,40.2956892],[-111.6937694,40.2944109]],"type":"LineString"},"properties":{"nodes":[{"delta":[1082,-1978],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1192,-3538],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1112,-3612],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[2338,-7139],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[4789,-14203],"stopLine":null,"dwidth":null,"delevation":null}],"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":3,"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":30,"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":null}]}},{"type":"Feature","id":8,"geometry":{"coordinates":[[-111.6947447,40.296975],[-111.6945987,40.2966224],[-111.6945415,40.296375]],"type":"LineString"},"properties":{"nodes":[{"delta":[2248,-1980],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1237,-3918],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[485,-2749],"stopLine":null,"dwidth":null,"delevation":null}],"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":false,"maneuverUTurnAllowed":false,"maneuverLeftTurnOnRedAllowed":false,"reserved1":false,"maneuverRightAllowed":true,"maneuverLaneChangeAllowed":false,"yieldAllwaysRequired":false,"maneuverRightTurnOnRedAllowed":false,"caution":false},"connectsTo":[{"connectingLane":{"lane":7,"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":2,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":12,"geometry":{"coordinates":[[-111.6949207,40.2969747],[-111.6946355,40.2963144],[-111.6945628,40.2962224]],"type":"LineString"},"properties":{"nodes":[{"delta":[757,-1983],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[2417,-7337],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[616,-1022],"stopLine":null,"dwidth":null,"delevation":null}],"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":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":23,"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":5,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":13,"geometry":{"coordinates":[[-111.6949654,40.2969755],[-111.6946693,40.2963075],[-111.694563,40.2962226]],"type":"LineString"},"properties":{"nodes":[{"delta":[378,-1974],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[2509,-7422],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[901,-943],"stopLine":null,"dwidth":null,"delevation":null}],"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":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":22,"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":5,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":9,"geometry":{"coordinates":[[-111.6947945,40.2969755],[-111.6946603,40.2966635],[-111.6945311,40.2963445],[-111.6942586,40.2957025],[-111.6936955,40.2944313]],"type":"LineString"},"properties":{"nodes":[{"delta":[1826,-1974],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1137,-3467],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1095,-3544],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[2309,-7133],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[4772,-14124],"stopLine":null,"dwidth":null,"delevation":null}],"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":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":32,"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":null}]}},{"type":"Feature","id":16,"geometry":{"coordinates":[[-111.6950993,40.2969606],[-111.6950831,40.2969207]],"type":"LineString"},"properties":{"nodes":[{"delta":[-757,-2140],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[137,-443],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":16,"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":15,"geometry":{"coordinates":[[-111.6950597,40.2969678],[-111.6950435,40.2969279]],"type":"LineString"},"properties":{"nodes":[{"delta":[-421,-2060],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[137,-443],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":15,"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":14,"geometry":{"coordinates":[[-111.6950119,40.2969764],[-111.6949964,40.2969345]],"type":"LineString"},"properties":{"nodes":[{"delta":[-16,-1964],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[131,-466],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":14,"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":6,"geometry":{"coordinates":[[-111.6947034,40.2971076],[-111.6946516,40.2971061]],"type":"LineString"},"properties":{"nodes":[{"delta":[2598,-507],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[439,-17],"stopLine":null,"dwidth":null,"delevation":null}],"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":7,"geometry":{"coordinates":[[-111.6946927,40.2970769],[-111.6946416,40.2970759]],"type":"LineString"},"properties":{"nodes":[{"delta":[2689,-848],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[433,-11],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":7,"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":2,"geometry":{"coordinates":[[-111.6947591,40.2972387],[-111.6935683,40.2972245]],"type":"LineString"},"properties":{"nodes":[{"delta":[2126,950],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[10091,-158],"stopLine":null,"dwidth":null,"delevation":null}],"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":23,"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":8,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":3,"geometry":{"coordinates":[[-111.6947502,40.2972093],[-111.6935675,40.2971992]],"type":"LineString"},"properties":{"nodes":[{"delta":[2202,623],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[10023,-112],"stopLine":null,"dwidth":null,"delevation":null}],"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":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":22,"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":8,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":4,"geometry":{"coordinates":[[-111.694738,40.2971788],[-111.6941318,40.2971713],[-111.6939017,40.2971989]],"type":"LineString"},"properties":{"nodes":[{"delta":[2305,284],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[5137,-83],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1950,307],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":4,"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":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":3,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":5,"geometry":{"coordinates":[[-111.6947267,40.2971466],[-111.6943028,40.2971432],[-111.6941317,40.2971719]],"type":"LineString"},"properties":{"nodes":[{"delta":[2401,-73],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[3592,-38],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1450,319],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":5,"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":14,"maneuver":{"maneuverStraightAllowed":false,"maneuverNoStoppingAllowed":false,"goWithHalt":false,"maneuverLeftAllowed":true,"maneuverUTurnAllowed":true,"maneuverLeftTurnOnRedAllowed":false,"reserved1":false,"maneuverRightAllowed":false,"maneuverLaneChangeAllowed":false,"yieldAllwaysRequired":false,"maneuverRightTurnOnRedAllowed":false,"caution":false}},"remoteIntersection":null,"signalGroup":3,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":1,"geometry":{"coordinates":[[-111.6947696,40.2972705],[-111.693782,40.2972623],[-111.6935771,40.2972531]],"type":"LineString"},"properties":{"nodes":[{"delta":[2037,1303],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[8369,-91],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1736,-102],"stopLine":null,"dwidth":null,"delevation":null}],"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":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":32,"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":8,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":25,"geometry":{"coordinates":[[-111.6952664,40.2973429],[-111.6958094,40.2986271],[-111.6963738,40.2999056]],"type":"LineString"},"properties":{"nodes":[{"delta":[-2173,2108],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-4602,14269],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-4783,14206],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":25,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":7,"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":16,"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":null}]}},{"type":"Feature","id":26,"geometry":{"coordinates":[[-111.6952202,40.2973406],[-111.6957689,40.2986334],[-111.6963331,40.2999146]],"type":"LineString"},"properties":{"nodes":[{"delta":[-1781,2082],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-4650,14364],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-4781,14235],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":26,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":7,"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}},"remoteIntersection":null,"signalGroup":6,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":27,"geometry":{"coordinates":[[-111.6951807,40.29734],[-111.6957307,40.2986348],[-111.6962926,40.2999237]],"type":"LineString"},"properties":{"nodes":[{"delta":[-1447,2076],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-4661,14387],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-4762,14321],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":27,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":7,"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}},"remoteIntersection":null,"signalGroup":6,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":28,"geometry":{"coordinates":[[-111.6951353,40.2973366],[-111.6953943,40.2979223],[-111.6955086,40.2981114]],"type":"LineString"},"properties":{"nodes":[{"delta":[-1062,2038],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-2195,6508],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-969,2101],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":28,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":7,"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":7,"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":1,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":29,"geometry":{"coordinates":[[-111.6950935,40.2973366],[-111.695294,40.2977961],[-111.6953949,40.2979228]],"type":"LineString"},"properties":{"nodes":[{"delta":[-708,2038],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-1699,5105],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-855,1408],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":29,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":7,"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":6,"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":1,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":24,"geometry":{"coordinates":[[-111.6953144,40.2973433],[-111.695503,40.2977839],[-111.6955422,40.2979969]],"type":"LineString"},"properties":{"nodes":[{"delta":[-2580,2112],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-1598,4895],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-332,2367],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":24,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":7,"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":23,"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":6,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":30,"geometry":{"coordinates":[[-111.6950442,40.2973389],[-111.695059,40.2973747]],"type":"LineString"},"properties":{"nodes":[{"delta":[-290,2063],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-125,398],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":30,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":8,"ingressApproach":0,"ingressPath":false,"egressPath":true}},{"type":"Feature","id":31,"geometry":{"coordinates":[[-111.6950017,40.2973394],[-111.6950186,40.2973803]],"type":"LineString"},"properties":{"nodes":[{"delta":[70,2069],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-143,454],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":31,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":8,"ingressApproach":0,"ingressPath":false,"egressPath":true}},{"type":"Feature","id":32,"geometry":{"coordinates":[[-111.6949588,40.2973389],[-111.6949763,40.2973803]],"type":"LineString"},"properties":{"nodes":[{"delta":[434,2063],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-148,460],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":32,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":8,"ingressApproach":0,"ingressPath":false,"egressPath":true}},{"type":"Feature","id":23,"geometry":{"coordinates":[[-111.6953705,40.2972489],[-111.695425,40.2972494]],"type":"LineString"},"properties":{"nodes":[{"delta":[-3055,1063],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-462,6],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":23,"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":22,"geometry":{"coordinates":[[-111.6953725,40.2972147],[-111.695425,40.2972162]],"type":"LineString"},"properties":{"nodes":[{"delta":[-3072,683],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-445,17],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":22,"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":18,"geometry":{"coordinates":[[-111.6952746,40.2970877],[-111.6964743,40.297086]],"type":"LineString"},"properties":{"nodes":[{"delta":[-2242,-728],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-10167,-19],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":18,"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":7,"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":4,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":19,"geometry":{"coordinates":[[-111.6952907,40.2971174],[-111.6964756,40.2971145]],"type":"LineString"},"properties":{"nodes":[{"delta":[-2379,-398],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-10041,-32],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":19,"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":6,"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":4,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":20,"geometry":{"coordinates":[[-111.6953089,40.297147],[-111.6961141,40.2971495],[-111.6962917,40.2971163]],"type":"LineString"},"properties":{"nodes":[{"delta":[-2533,-69],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-6824,28],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-1505,-369],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":20,"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":true,"maneuverUTurnAllowed":false,"maneuverLeftTurnOnRedAllowed":false,"reserved1":false,"maneuverRightAllowed":false,"maneuverLaneChangeAllowed":false,"yieldAllwaysRequired":false,"maneuverRightTurnOnRedAllowed":false,"caution":false},"connectsTo":[{"connectingLane":{"lane":31,"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":7,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":21,"geometry":{"coordinates":[[-111.6953236,40.2971756],[-111.6959863,40.2971761],[-111.6961141,40.29715]],"type":"LineString"},"properties":{"nodes":[{"delta":[-2658,249],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-5616,6],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-1083,-290],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":21,"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":true,"maneuverUTurnAllowed":false,"maneuverLeftTurnOnRedAllowed":false,"reserved1":false,"maneuverRightAllowed":false,"maneuverLaneChangeAllowed":false,"yieldAllwaysRequired":false,"maneuverRightTurnOnRedAllowed":false,"caution":false},"connectsTo":[{"connectingLane":{"lane":30,"maneuver":{"maneuverStraightAllowed":false,"maneuverNoStoppingAllowed":false,"goWithHalt":false,"maneuverLeftAllowed":true,"maneuverUTurnAllowed":true,"maneuverLeftTurnOnRedAllowed":false,"reserved1":false,"maneuverRightAllowed":false,"maneuverLaneChangeAllowed":false,"yieldAllwaysRequired":false,"maneuverRightTurnOnRedAllowed":false,"caution":false}},"remoteIntersection":null,"signalGroup":7,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":17,"geometry":{"coordinates":[[-111.6952574,40.2970542],[-111.6959705,40.2970588],[-111.6961326,40.2970849]],"type":"LineString"},"properties":{"nodes":[{"delta":[-2097,-1100],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-6043,51],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-1374,290],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":17,"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":16,"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":4,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":34,"geometry":{"coordinates":[[-111.694707,40.2970001],[-111.6951879,40.2969977]],"type":"LineString"},"properties":{"nodes":[{"delta":[2568,-1701],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-4075,-27],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":34,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":0,"ingressPath":false,"egressPath":false}},{"type":"Feature","id":35,"geometry":{"coordinates":[[-111.6952023,40.2970198],[-111.6953688,40.2973123]],"type":"LineString"},"properties":{"nodes":[{"delta":[-1630,-1482],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-1411,3250],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":35,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":0,"ingressPath":false,"egressPath":false}},{"type":"Feature","id":36,"geometry":{"coordinates":[[-111.6953605,40.2973241],[-111.6948565,40.2973006]],"type":"LineString"},"properties":{"nodes":[{"delta":[-2970,1899],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[4271,-261],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":36,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":0,"ingressPath":false,"egressPath":false}},{"type":"Feature","id":33,"geometry":{"coordinates":[[-111.694819,40.2972895],[-111.6946964,40.2970125]],"type":"LineString"},"properties":{"nodes":[{"delta":[1619,1514],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1039,-3078],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":33,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":0,"ingressPath":false,"egressPath":false}}]},"connectingLanesFeatureCollection":{"type":"FeatureCollection","features":[{"type":"Feature","id":"10-31","geometry":{"coordinates":[[-111.6948409,40.2969746],[-111.6950017,40.2973394]],"type":"LineString"},"properties":{"signalGroupId":2,"ingressLaneId":10,"egressLaneId":31}},{"type":"Feature","id":"11-30","geometry":{"coordinates":[[-111.6948823,40.2969752],[-111.6950442,40.2973389]],"type":"LineString"},"properties":{"signalGroupId":2,"ingressLaneId":11,"egressLaneId":30}},{"type":"Feature","id":"8-7","geometry":{"coordinates":[[-111.6947447,40.296975],[-111.6946927,40.2970769]],"type":"LineString"},"properties":{"signalGroupId":2,"ingressLaneId":8,"egressLaneId":7}},{"type":"Feature","id":"12-23","geometry":{"coordinates":[[-111.6949207,40.2969747],[-111.6953705,40.2972489]],"type":"LineString"},"properties":{"signalGroupId":5,"ingressLaneId":12,"egressLaneId":23}},{"type":"Feature","id":"13-22","geometry":{"coordinates":[[-111.6949654,40.2969755],[-111.6953725,40.2972147]],"type":"LineString"},"properties":{"signalGroupId":5,"ingressLaneId":13,"egressLaneId":22}},{"type":"Feature","id":"9-32","geometry":{"coordinates":[[-111.6947945,40.2969755],[-111.6949588,40.2973389]],"type":"LineString"},"properties":{"signalGroupId":2,"ingressLaneId":9,"egressLaneId":32}},{"type":"Feature","id":"2-23","geometry":{"coordinates":[[-111.6947591,40.2972387],[-111.6953705,40.2972489]],"type":"LineString"},"properties":{"signalGroupId":8,"ingressLaneId":2,"egressLaneId":23}},{"type":"Feature","id":"3-22","geometry":{"coordinates":[[-111.6947502,40.2972093],[-111.6953725,40.2972147]],"type":"LineString"},"properties":{"signalGroupId":8,"ingressLaneId":3,"egressLaneId":22}},{"type":"Feature","id":"4-15","geometry":{"coordinates":[[-111.694738,40.2971788],[-111.6950597,40.2969678]],"type":"LineString"},"properties":{"signalGroupId":3,"ingressLaneId":4,"egressLaneId":15}},{"type":"Feature","id":"5-14","geometry":{"coordinates":[[-111.6947267,40.2971466],[-111.6950119,40.2969764]],"type":"LineString"},"properties":{"signalGroupId":3,"ingressLaneId":5,"egressLaneId":14}},{"type":"Feature","id":"1-32","geometry":{"coordinates":[[-111.6947696,40.2972705],[-111.6949588,40.2973389]],"type":"LineString"},"properties":{"signalGroupId":8,"ingressLaneId":1,"egressLaneId":32}},{"type":"Feature","id":"25-16","geometry":{"coordinates":[[-111.6952664,40.2973429],[-111.6950993,40.2969606]],"type":"LineString"},"properties":{"signalGroupId":6,"ingressLaneId":25,"egressLaneId":16}},{"type":"Feature","id":"26-15","geometry":{"coordinates":[[-111.6952202,40.2973406],[-111.6950597,40.2969678]],"type":"LineString"},"properties":{"signalGroupId":6,"ingressLaneId":26,"egressLaneId":15}},{"type":"Feature","id":"27-14","geometry":{"coordinates":[[-111.6951807,40.29734],[-111.6950119,40.2969764]],"type":"LineString"},"properties":{"signalGroupId":6,"ingressLaneId":27,"egressLaneId":14}},{"type":"Feature","id":"28-7","geometry":{"coordinates":[[-111.6951353,40.2973366],[-111.6946927,40.2970769]],"type":"LineString"},"properties":{"signalGroupId":1,"ingressLaneId":28,"egressLaneId":7}},{"type":"Feature","id":"29-6","geometry":{"coordinates":[[-111.6950935,40.2973366],[-111.6947034,40.2971076]],"type":"LineString"},"properties":{"signalGroupId":1,"ingressLaneId":29,"egressLaneId":6}},{"type":"Feature","id":"24-23","geometry":{"coordinates":[[-111.6953144,40.2973433],[-111.6953705,40.2972489]],"type":"LineString"},"properties":{"signalGroupId":6,"ingressLaneId":24,"egressLaneId":23}},{"type":"Feature","id":"18-7","geometry":{"coordinates":[[-111.6952746,40.2970877],[-111.6946927,40.2970769]],"type":"LineString"},"properties":{"signalGroupId":4,"ingressLaneId":18,"egressLaneId":7}},{"type":"Feature","id":"19-6","geometry":{"coordinates":[[-111.6952907,40.2971174],[-111.6947034,40.2971076]],"type":"LineString"},"properties":{"signalGroupId":4,"ingressLaneId":19,"egressLaneId":6}},{"type":"Feature","id":"20-31","geometry":{"coordinates":[[-111.6953089,40.297147],[-111.6950017,40.2973394]],"type":"LineString"},"properties":{"signalGroupId":7,"ingressLaneId":20,"egressLaneId":31}},{"type":"Feature","id":"21-30","geometry":{"coordinates":[[-111.6953236,40.2971756],[-111.6950442,40.2973389]],"type":"LineString"},"properties":{"signalGroupId":7,"ingressLaneId":21,"egressLaneId":30}},{"type":"Feature","id":"17-16","geometry":{"coordinates":[[-111.6952574,40.2970542],[-111.6950993,40.2969606]],"type":"LineString"},"properties":{"signalGroupId":4,"ingressLaneId":17,"egressLaneId":16}}]},"properties":{"messageType":"MAP","odeReceivedAt":"@ISO_DATE_TIME@","originIp":"10.164.6.16","intersectionName":"N State St & E Center St","intersectionId":6311,"msgIssueRevision":0,"revision":4,"refPoint":{"latitude":40.2971532,"longitude":-111.69501,"elevation":1437},"cti4501Conformant":false,"validationMessages":[{"message":"$.metadata.recordGeneratedBy: is missing but it is required","jsonPath":"$.metadata","schemaPath":"#/$defs/OdeMapMetadata/required"},{"message":"$.metadata.receivedMessageDetails.locationData: is missing but it is required","jsonPath":"$.metadata.receivedMessageDetails","schemaPath":"#/$defs/OdeMapMetadata/properties/receivedMessageDetails/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].id.region: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].id","schemaPath":"#/$defs/J2735IntersectionReferenceID/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[6].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[6]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[6].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[6]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[7].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[7]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[7].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[7]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[8].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[8]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[8].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[8]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[9].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[9]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[9].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[9]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[10].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[10]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[10].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[10]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[22].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[22]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[22].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[22]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[23].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[23]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[23].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[23]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[24].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[24]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[24].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[24]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[25].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[25]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[25].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[25]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[26].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[26]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[26].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[26]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[32].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[32]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[32].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[32]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[33].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[33]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[33].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[33]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[34].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[34]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[34].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[34]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[35].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[35]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[35].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[35]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].speedLimits: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0]","schemaPath":"#/$defs/J2735IntersectionGeometry/required"}],"laneWidth":366,"mapSource":"RSU","timeStamp":"@ISO_DATE_TIME_OFFSET_MILLIS_-10@"}} +ProcessedMap;10.164.6.16;6311,3000,{"mapFeatureCollection":{"type":"FeatureCollection","features":[{"type":"Feature","id":10,"geometry":{"coordinates":[[-111.6948409,40.2969746],[-111.6947006,40.2966582],[-111.6945681,40.2963382],[-111.6942976,40.2956952],[-111.6937336,40.2944205]],"type":"LineString"},"properties":{"nodes":[{"delta":[1433,-1984],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1189,-3515],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1123,-3555],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[2292,-7144],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[4780,-14163],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":10,"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":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":31,"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":null}]}},{"type":"Feature","id":11,"geometry":{"coordinates":[[-111.6948823,40.2969752],[-111.6947416,40.2966568],[-111.6946104,40.2963317],[-111.6943345,40.2956892],[-111.6937694,40.2944109]],"type":"LineString"},"properties":{"nodes":[{"delta":[1082,-1978],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1192,-3538],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1112,-3612],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[2338,-7139],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[4789,-14203],"stopLine":null,"dwidth":null,"delevation":null}],"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":3,"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":30,"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":null}]}},{"type":"Feature","id":8,"geometry":{"coordinates":[[-111.6947447,40.296975],[-111.6945987,40.2966224],[-111.6945415,40.296375]],"type":"LineString"},"properties":{"nodes":[{"delta":[2248,-1980],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1237,-3918],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[485,-2749],"stopLine":null,"dwidth":null,"delevation":null}],"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":false,"maneuverUTurnAllowed":false,"maneuverLeftTurnOnRedAllowed":false,"reserved1":false,"maneuverRightAllowed":true,"maneuverLaneChangeAllowed":false,"yieldAllwaysRequired":false,"maneuverRightTurnOnRedAllowed":false,"caution":false},"connectsTo":[{"connectingLane":{"lane":7,"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":2,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":12,"geometry":{"coordinates":[[-111.6949207,40.2969747],[-111.6946355,40.2963144],[-111.6945628,40.2962224]],"type":"LineString"},"properties":{"nodes":[{"delta":[757,-1983],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[2417,-7337],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[616,-1022],"stopLine":null,"dwidth":null,"delevation":null}],"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":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":23,"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":5,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":13,"geometry":{"coordinates":[[-111.6949654,40.2969755],[-111.6946693,40.2963075],[-111.694563,40.2962226]],"type":"LineString"},"properties":{"nodes":[{"delta":[378,-1974],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[2509,-7422],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[901,-943],"stopLine":null,"dwidth":null,"delevation":null}],"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":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":22,"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":5,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":9,"geometry":{"coordinates":[[-111.6947945,40.2969755],[-111.6946603,40.2966635],[-111.6945311,40.2963445],[-111.6942586,40.2957025],[-111.6936955,40.2944313]],"type":"LineString"},"properties":{"nodes":[{"delta":[1826,-1974],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1137,-3467],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1095,-3544],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[2309,-7133],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[4772,-14124],"stopLine":null,"dwidth":null,"delevation":null}],"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":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":32,"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":null}]}},{"type":"Feature","id":16,"geometry":{"coordinates":[[-111.6950993,40.2969606],[-111.6950831,40.2969207]],"type":"LineString"},"properties":{"nodes":[{"delta":[-757,-2140],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[137,-443],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":16,"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":15,"geometry":{"coordinates":[[-111.6950597,40.2969678],[-111.6950435,40.2969279]],"type":"LineString"},"properties":{"nodes":[{"delta":[-421,-2060],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[137,-443],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":15,"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":14,"geometry":{"coordinates":[[-111.6950119,40.2969764],[-111.6949964,40.2969345]],"type":"LineString"},"properties":{"nodes":[{"delta":[-16,-1964],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[131,-466],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":14,"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":6,"geometry":{"coordinates":[[-111.6947034,40.2971076],[-111.6946516,40.2971061]],"type":"LineString"},"properties":{"nodes":[{"delta":[2598,-507],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[439,-17],"stopLine":null,"dwidth":null,"delevation":null}],"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":7,"geometry":{"coordinates":[[-111.6946927,40.2970769],[-111.6946416,40.2970759]],"type":"LineString"},"properties":{"nodes":[{"delta":[2689,-848],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[433,-11],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":7,"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":2,"geometry":{"coordinates":[[-111.6947591,40.2972387],[-111.6935683,40.2972245]],"type":"LineString"},"properties":{"nodes":[{"delta":[2126,950],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[10091,-158],"stopLine":null,"dwidth":null,"delevation":null}],"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":23,"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":8,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":3,"geometry":{"coordinates":[[-111.6947502,40.2972093],[-111.6935675,40.2971992]],"type":"LineString"},"properties":{"nodes":[{"delta":[2202,623],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[10023,-112],"stopLine":null,"dwidth":null,"delevation":null}],"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":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":22,"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":8,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":4,"geometry":{"coordinates":[[-111.694738,40.2971788],[-111.6941318,40.2971713],[-111.6939017,40.2971989]],"type":"LineString"},"properties":{"nodes":[{"delta":[2305,284],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[5137,-83],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1950,307],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":4,"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":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":3,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":5,"geometry":{"coordinates":[[-111.6947267,40.2971466],[-111.6943028,40.2971432],[-111.6941317,40.2971719]],"type":"LineString"},"properties":{"nodes":[{"delta":[2401,-73],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[3592,-38],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1450,319],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":5,"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":14,"maneuver":{"maneuverStraightAllowed":false,"maneuverNoStoppingAllowed":false,"goWithHalt":false,"maneuverLeftAllowed":true,"maneuverUTurnAllowed":true,"maneuverLeftTurnOnRedAllowed":false,"reserved1":false,"maneuverRightAllowed":false,"maneuverLaneChangeAllowed":false,"yieldAllwaysRequired":false,"maneuverRightTurnOnRedAllowed":false,"caution":false}},"remoteIntersection":null,"signalGroup":3,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":1,"geometry":{"coordinates":[[-111.6947696,40.2972705],[-111.693782,40.2972623],[-111.6935771,40.2972531]],"type":"LineString"},"properties":{"nodes":[{"delta":[2037,1303],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[8369,-91],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1736,-102],"stopLine":null,"dwidth":null,"delevation":null}],"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":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":32,"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":8,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":25,"geometry":{"coordinates":[[-111.6952664,40.2973429],[-111.6958094,40.2986271],[-111.6963738,40.2999056]],"type":"LineString"},"properties":{"nodes":[{"delta":[-2173,2108],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-4602,14269],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-4783,14206],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":25,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":7,"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":16,"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":null}]}},{"type":"Feature","id":26,"geometry":{"coordinates":[[-111.6952202,40.2973406],[-111.6957689,40.2986334],[-111.6963331,40.2999146]],"type":"LineString"},"properties":{"nodes":[{"delta":[-1781,2082],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-4650,14364],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-4781,14235],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":26,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":7,"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}},"remoteIntersection":null,"signalGroup":6,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":27,"geometry":{"coordinates":[[-111.6951807,40.29734],[-111.6957307,40.2986348],[-111.6962926,40.2999237]],"type":"LineString"},"properties":{"nodes":[{"delta":[-1447,2076],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-4661,14387],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-4762,14321],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":27,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":7,"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}},"remoteIntersection":null,"signalGroup":6,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":28,"geometry":{"coordinates":[[-111.6951353,40.2973366],[-111.6953943,40.2979223],[-111.6955086,40.2981114]],"type":"LineString"},"properties":{"nodes":[{"delta":[-1062,2038],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-2195,6508],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-969,2101],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":28,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":7,"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":7,"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":1,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":29,"geometry":{"coordinates":[[-111.6950935,40.2973366],[-111.695294,40.2977961],[-111.6953949,40.2979228]],"type":"LineString"},"properties":{"nodes":[{"delta":[-708,2038],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-1699,5105],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-855,1408],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":29,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":7,"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":6,"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":1,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":24,"geometry":{"coordinates":[[-111.6953144,40.2973433],[-111.695503,40.2977839],[-111.6955422,40.2979969]],"type":"LineString"},"properties":{"nodes":[{"delta":[-2580,2112],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-1598,4895],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-332,2367],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":24,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":7,"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":23,"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":6,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":30,"geometry":{"coordinates":[[-111.6950442,40.2973389],[-111.695059,40.2973747]],"type":"LineString"},"properties":{"nodes":[{"delta":[-290,2063],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-125,398],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":30,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":8,"ingressApproach":0,"ingressPath":false,"egressPath":true}},{"type":"Feature","id":31,"geometry":{"coordinates":[[-111.6950017,40.2973394],[-111.6950186,40.2973803]],"type":"LineString"},"properties":{"nodes":[{"delta":[70,2069],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-143,454],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":31,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":8,"ingressApproach":0,"ingressPath":false,"egressPath":true}},{"type":"Feature","id":32,"geometry":{"coordinates":[[-111.6949588,40.2973389],[-111.6949763,40.2973803]],"type":"LineString"},"properties":{"nodes":[{"delta":[434,2063],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-148,460],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":32,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":8,"ingressApproach":0,"ingressPath":false,"egressPath":true}},{"type":"Feature","id":23,"geometry":{"coordinates":[[-111.6953705,40.2972489],[-111.695425,40.2972494]],"type":"LineString"},"properties":{"nodes":[{"delta":[-3055,1063],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-462,6],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":23,"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":22,"geometry":{"coordinates":[[-111.6953725,40.2972147],[-111.695425,40.2972162]],"type":"LineString"},"properties":{"nodes":[{"delta":[-3072,683],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-445,17],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":22,"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":18,"geometry":{"coordinates":[[-111.6952746,40.2970877],[-111.6964743,40.297086]],"type":"LineString"},"properties":{"nodes":[{"delta":[-2242,-728],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-10167,-19],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":18,"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":7,"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":4,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":19,"geometry":{"coordinates":[[-111.6952907,40.2971174],[-111.6964756,40.2971145]],"type":"LineString"},"properties":{"nodes":[{"delta":[-2379,-398],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-10041,-32],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":19,"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":6,"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":4,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":20,"geometry":{"coordinates":[[-111.6953089,40.297147],[-111.6961141,40.2971495],[-111.6962917,40.2971163]],"type":"LineString"},"properties":{"nodes":[{"delta":[-2533,-69],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-6824,28],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-1505,-369],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":20,"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":true,"maneuverUTurnAllowed":false,"maneuverLeftTurnOnRedAllowed":false,"reserved1":false,"maneuverRightAllowed":false,"maneuverLaneChangeAllowed":false,"yieldAllwaysRequired":false,"maneuverRightTurnOnRedAllowed":false,"caution":false},"connectsTo":[{"connectingLane":{"lane":31,"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":7,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":21,"geometry":{"coordinates":[[-111.6953236,40.2971756],[-111.6959863,40.2971761],[-111.6961141,40.29715]],"type":"LineString"},"properties":{"nodes":[{"delta":[-2658,249],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-5616,6],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-1083,-290],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":21,"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":true,"maneuverUTurnAllowed":false,"maneuverLeftTurnOnRedAllowed":false,"reserved1":false,"maneuverRightAllowed":false,"maneuverLaneChangeAllowed":false,"yieldAllwaysRequired":false,"maneuverRightTurnOnRedAllowed":false,"caution":false},"connectsTo":[{"connectingLane":{"lane":30,"maneuver":{"maneuverStraightAllowed":false,"maneuverNoStoppingAllowed":false,"goWithHalt":false,"maneuverLeftAllowed":true,"maneuverUTurnAllowed":true,"maneuverLeftTurnOnRedAllowed":false,"reserved1":false,"maneuverRightAllowed":false,"maneuverLaneChangeAllowed":false,"yieldAllwaysRequired":false,"maneuverRightTurnOnRedAllowed":false,"caution":false}},"remoteIntersection":null,"signalGroup":7,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":17,"geometry":{"coordinates":[[-111.6952574,40.2970542],[-111.6959705,40.2970588],[-111.6961326,40.2970849]],"type":"LineString"},"properties":{"nodes":[{"delta":[-2097,-1100],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-6043,51],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-1374,290],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":17,"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":16,"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":4,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":34,"geometry":{"coordinates":[[-111.694707,40.2970001],[-111.6951879,40.2969977]],"type":"LineString"},"properties":{"nodes":[{"delta":[2568,-1701],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-4075,-27],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":34,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":0,"ingressPath":false,"egressPath":false}},{"type":"Feature","id":35,"geometry":{"coordinates":[[-111.6952023,40.2970198],[-111.6953688,40.2973123]],"type":"LineString"},"properties":{"nodes":[{"delta":[-1630,-1482],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-1411,3250],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":35,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":0,"ingressPath":false,"egressPath":false}},{"type":"Feature","id":36,"geometry":{"coordinates":[[-111.6953605,40.2973241],[-111.6948565,40.2973006]],"type":"LineString"},"properties":{"nodes":[{"delta":[-2970,1899],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[4271,-261],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":36,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":0,"ingressPath":false,"egressPath":false}},{"type":"Feature","id":33,"geometry":{"coordinates":[[-111.694819,40.2972895],[-111.6946964,40.2970125]],"type":"LineString"},"properties":{"nodes":[{"delta":[1619,1514],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1039,-3078],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":33,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":0,"ingressPath":false,"egressPath":false}}]},"connectingLanesFeatureCollection":{"type":"FeatureCollection","features":[{"type":"Feature","id":"10-31","geometry":{"coordinates":[[-111.6948409,40.2969746],[-111.6950017,40.2973394]],"type":"LineString"},"properties":{"signalGroupId":2,"ingressLaneId":10,"egressLaneId":31}},{"type":"Feature","id":"11-30","geometry":{"coordinates":[[-111.6948823,40.2969752],[-111.6950442,40.2973389]],"type":"LineString"},"properties":{"signalGroupId":2,"ingressLaneId":11,"egressLaneId":30}},{"type":"Feature","id":"8-7","geometry":{"coordinates":[[-111.6947447,40.296975],[-111.6946927,40.2970769]],"type":"LineString"},"properties":{"signalGroupId":2,"ingressLaneId":8,"egressLaneId":7}},{"type":"Feature","id":"12-23","geometry":{"coordinates":[[-111.6949207,40.2969747],[-111.6953705,40.2972489]],"type":"LineString"},"properties":{"signalGroupId":5,"ingressLaneId":12,"egressLaneId":23}},{"type":"Feature","id":"13-22","geometry":{"coordinates":[[-111.6949654,40.2969755],[-111.6953725,40.2972147]],"type":"LineString"},"properties":{"signalGroupId":5,"ingressLaneId":13,"egressLaneId":22}},{"type":"Feature","id":"9-32","geometry":{"coordinates":[[-111.6947945,40.2969755],[-111.6949588,40.2973389]],"type":"LineString"},"properties":{"signalGroupId":2,"ingressLaneId":9,"egressLaneId":32}},{"type":"Feature","id":"2-23","geometry":{"coordinates":[[-111.6947591,40.2972387],[-111.6953705,40.2972489]],"type":"LineString"},"properties":{"signalGroupId":8,"ingressLaneId":2,"egressLaneId":23}},{"type":"Feature","id":"3-22","geometry":{"coordinates":[[-111.6947502,40.2972093],[-111.6953725,40.2972147]],"type":"LineString"},"properties":{"signalGroupId":8,"ingressLaneId":3,"egressLaneId":22}},{"type":"Feature","id":"4-15","geometry":{"coordinates":[[-111.694738,40.2971788],[-111.6950597,40.2969678]],"type":"LineString"},"properties":{"signalGroupId":3,"ingressLaneId":4,"egressLaneId":15}},{"type":"Feature","id":"5-14","geometry":{"coordinates":[[-111.6947267,40.2971466],[-111.6950119,40.2969764]],"type":"LineString"},"properties":{"signalGroupId":3,"ingressLaneId":5,"egressLaneId":14}},{"type":"Feature","id":"1-32","geometry":{"coordinates":[[-111.6947696,40.2972705],[-111.6949588,40.2973389]],"type":"LineString"},"properties":{"signalGroupId":8,"ingressLaneId":1,"egressLaneId":32}},{"type":"Feature","id":"25-16","geometry":{"coordinates":[[-111.6952664,40.2973429],[-111.6950993,40.2969606]],"type":"LineString"},"properties":{"signalGroupId":6,"ingressLaneId":25,"egressLaneId":16}},{"type":"Feature","id":"26-15","geometry":{"coordinates":[[-111.6952202,40.2973406],[-111.6950597,40.2969678]],"type":"LineString"},"properties":{"signalGroupId":6,"ingressLaneId":26,"egressLaneId":15}},{"type":"Feature","id":"27-14","geometry":{"coordinates":[[-111.6951807,40.29734],[-111.6950119,40.2969764]],"type":"LineString"},"properties":{"signalGroupId":6,"ingressLaneId":27,"egressLaneId":14}},{"type":"Feature","id":"28-7","geometry":{"coordinates":[[-111.6951353,40.2973366],[-111.6946927,40.2970769]],"type":"LineString"},"properties":{"signalGroupId":1,"ingressLaneId":28,"egressLaneId":7}},{"type":"Feature","id":"29-6","geometry":{"coordinates":[[-111.6950935,40.2973366],[-111.6947034,40.2971076]],"type":"LineString"},"properties":{"signalGroupId":1,"ingressLaneId":29,"egressLaneId":6}},{"type":"Feature","id":"24-23","geometry":{"coordinates":[[-111.6953144,40.2973433],[-111.6953705,40.2972489]],"type":"LineString"},"properties":{"signalGroupId":6,"ingressLaneId":24,"egressLaneId":23}},{"type":"Feature","id":"18-7","geometry":{"coordinates":[[-111.6952746,40.2970877],[-111.6946927,40.2970769]],"type":"LineString"},"properties":{"signalGroupId":4,"ingressLaneId":18,"egressLaneId":7}},{"type":"Feature","id":"19-6","geometry":{"coordinates":[[-111.6952907,40.2971174],[-111.6947034,40.2971076]],"type":"LineString"},"properties":{"signalGroupId":4,"ingressLaneId":19,"egressLaneId":6}},{"type":"Feature","id":"20-31","geometry":{"coordinates":[[-111.6953089,40.297147],[-111.6950017,40.2973394]],"type":"LineString"},"properties":{"signalGroupId":7,"ingressLaneId":20,"egressLaneId":31}},{"type":"Feature","id":"21-30","geometry":{"coordinates":[[-111.6953236,40.2971756],[-111.6950442,40.2973389]],"type":"LineString"},"properties":{"signalGroupId":7,"ingressLaneId":21,"egressLaneId":30}},{"type":"Feature","id":"17-16","geometry":{"coordinates":[[-111.6952574,40.2970542],[-111.6950993,40.2969606]],"type":"LineString"},"properties":{"signalGroupId":4,"ingressLaneId":17,"egressLaneId":16}}]},"properties":{"messageType":"MAP","odeReceivedAt":"@ISO_DATE_TIME@","originIp":"10.164.6.16","intersectionName":"N State St & E Center St","intersectionId":6311,"msgIssueRevision":0,"revision":4,"refPoint":{"latitude":40.2971532,"longitude":-111.69501,"elevation":1437},"cti4501Conformant":false,"validationMessages":[{"message":"$.metadata.recordGeneratedBy: is missing but it is required","jsonPath":"$.metadata","schemaPath":"#/$defs/OdeMapMetadata/required"},{"message":"$.metadata.receivedMessageDetails.locationData: is missing but it is required","jsonPath":"$.metadata.receivedMessageDetails","schemaPath":"#/$defs/OdeMapMetadata/properties/receivedMessageDetails/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].id.region: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].id","schemaPath":"#/$defs/J2735IntersectionReferenceID/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[6].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[6]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[6].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[6]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[7].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[7]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[7].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[7]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[8].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[8]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[8].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[8]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[9].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[9]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[9].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[9]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[10].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[10]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[10].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[10]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[22].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[22]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[22].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[22]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[23].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[23]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[23].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[23]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[24].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[24]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[24].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[24]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[25].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[25]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[25].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[25]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[26].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[26]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[26].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[26]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[32].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[32]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[32].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[32]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[33].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[33]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[33].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[33]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[34].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[34]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[34].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[34]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[35].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[35]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[35].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[35]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].speedLimits: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0]","schemaPath":"#/$defs/J2735IntersectionGeometry/required"}],"laneWidth":366,"mapSource":"RSU","timeStamp":"@ISO_DATE_TIME_OFFSET_MILLIS_-600@"}} +ProcessedMap;10.164.6.16;6311,5000,{"mapFeatureCollection":{"type":"FeatureCollection","features":[{"type":"Feature","id":10,"geometry":{"coordinates":[[-111.6948409,40.2969746],[-111.6947006,40.2966582],[-111.6945681,40.2963382],[-111.6942976,40.2956952],[-111.6937336,40.2944205]],"type":"LineString"},"properties":{"nodes":[{"delta":[1433,-1984],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1189,-3515],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1123,-3555],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[2292,-7144],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[4780,-14163],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":10,"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":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":31,"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":null}]}},{"type":"Feature","id":11,"geometry":{"coordinates":[[-111.6948823,40.2969752],[-111.6947416,40.2966568],[-111.6946104,40.2963317],[-111.6943345,40.2956892],[-111.6937694,40.2944109]],"type":"LineString"},"properties":{"nodes":[{"delta":[1082,-1978],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1192,-3538],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1112,-3612],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[2338,-7139],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[4789,-14203],"stopLine":null,"dwidth":null,"delevation":null}],"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":3,"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":30,"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":null}]}},{"type":"Feature","id":8,"geometry":{"coordinates":[[-111.6947447,40.296975],[-111.6945987,40.2966224],[-111.6945415,40.296375]],"type":"LineString"},"properties":{"nodes":[{"delta":[2248,-1980],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1237,-3918],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[485,-2749],"stopLine":null,"dwidth":null,"delevation":null}],"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":false,"maneuverUTurnAllowed":false,"maneuverLeftTurnOnRedAllowed":false,"reserved1":false,"maneuverRightAllowed":true,"maneuverLaneChangeAllowed":false,"yieldAllwaysRequired":false,"maneuverRightTurnOnRedAllowed":false,"caution":false},"connectsTo":[{"connectingLane":{"lane":7,"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":2,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":12,"geometry":{"coordinates":[[-111.6949207,40.2969747],[-111.6946355,40.2963144],[-111.6945628,40.2962224]],"type":"LineString"},"properties":{"nodes":[{"delta":[757,-1983],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[2417,-7337],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[616,-1022],"stopLine":null,"dwidth":null,"delevation":null}],"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":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":23,"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":5,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":13,"geometry":{"coordinates":[[-111.6949654,40.2969755],[-111.6946693,40.2963075],[-111.694563,40.2962226]],"type":"LineString"},"properties":{"nodes":[{"delta":[378,-1974],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[2509,-7422],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[901,-943],"stopLine":null,"dwidth":null,"delevation":null}],"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":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":22,"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":5,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":9,"geometry":{"coordinates":[[-111.6947945,40.2969755],[-111.6946603,40.2966635],[-111.6945311,40.2963445],[-111.6942586,40.2957025],[-111.6936955,40.2944313]],"type":"LineString"},"properties":{"nodes":[{"delta":[1826,-1974],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1137,-3467],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1095,-3544],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[2309,-7133],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[4772,-14124],"stopLine":null,"dwidth":null,"delevation":null}],"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":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":32,"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":null}]}},{"type":"Feature","id":16,"geometry":{"coordinates":[[-111.6950993,40.2969606],[-111.6950831,40.2969207]],"type":"LineString"},"properties":{"nodes":[{"delta":[-757,-2140],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[137,-443],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":16,"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":15,"geometry":{"coordinates":[[-111.6950597,40.2969678],[-111.6950435,40.2969279]],"type":"LineString"},"properties":{"nodes":[{"delta":[-421,-2060],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[137,-443],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":15,"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":14,"geometry":{"coordinates":[[-111.6950119,40.2969764],[-111.6949964,40.2969345]],"type":"LineString"},"properties":{"nodes":[{"delta":[-16,-1964],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[131,-466],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":14,"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":6,"geometry":{"coordinates":[[-111.6947034,40.2971076],[-111.6946516,40.2971061]],"type":"LineString"},"properties":{"nodes":[{"delta":[2598,-507],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[439,-17],"stopLine":null,"dwidth":null,"delevation":null}],"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":7,"geometry":{"coordinates":[[-111.6946927,40.2970769],[-111.6946416,40.2970759]],"type":"LineString"},"properties":{"nodes":[{"delta":[2689,-848],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[433,-11],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":7,"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":2,"geometry":{"coordinates":[[-111.6947591,40.2972387],[-111.6935683,40.2972245]],"type":"LineString"},"properties":{"nodes":[{"delta":[2126,950],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[10091,-158],"stopLine":null,"dwidth":null,"delevation":null}],"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":23,"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":8,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":3,"geometry":{"coordinates":[[-111.6947502,40.2972093],[-111.6935675,40.2971992]],"type":"LineString"},"properties":{"nodes":[{"delta":[2202,623],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[10023,-112],"stopLine":null,"dwidth":null,"delevation":null}],"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":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":22,"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":8,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":4,"geometry":{"coordinates":[[-111.694738,40.2971788],[-111.6941318,40.2971713],[-111.6939017,40.2971989]],"type":"LineString"},"properties":{"nodes":[{"delta":[2305,284],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[5137,-83],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1950,307],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":4,"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":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":3,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":5,"geometry":{"coordinates":[[-111.6947267,40.2971466],[-111.6943028,40.2971432],[-111.6941317,40.2971719]],"type":"LineString"},"properties":{"nodes":[{"delta":[2401,-73],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[3592,-38],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1450,319],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":5,"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":14,"maneuver":{"maneuverStraightAllowed":false,"maneuverNoStoppingAllowed":false,"goWithHalt":false,"maneuverLeftAllowed":true,"maneuverUTurnAllowed":true,"maneuverLeftTurnOnRedAllowed":false,"reserved1":false,"maneuverRightAllowed":false,"maneuverLaneChangeAllowed":false,"yieldAllwaysRequired":false,"maneuverRightTurnOnRedAllowed":false,"caution":false}},"remoteIntersection":null,"signalGroup":3,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":1,"geometry":{"coordinates":[[-111.6947696,40.2972705],[-111.693782,40.2972623],[-111.6935771,40.2972531]],"type":"LineString"},"properties":{"nodes":[{"delta":[2037,1303],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[8369,-91],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1736,-102],"stopLine":null,"dwidth":null,"delevation":null}],"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":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":32,"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":8,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":25,"geometry":{"coordinates":[[-111.6952664,40.2973429],[-111.6958094,40.2986271],[-111.6963738,40.2999056]],"type":"LineString"},"properties":{"nodes":[{"delta":[-2173,2108],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-4602,14269],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-4783,14206],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":25,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":7,"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":16,"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":null}]}},{"type":"Feature","id":26,"geometry":{"coordinates":[[-111.6952202,40.2973406],[-111.6957689,40.2986334],[-111.6963331,40.2999146]],"type":"LineString"},"properties":{"nodes":[{"delta":[-1781,2082],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-4650,14364],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-4781,14235],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":26,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":7,"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}},"remoteIntersection":null,"signalGroup":6,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":27,"geometry":{"coordinates":[[-111.6951807,40.29734],[-111.6957307,40.2986348],[-111.6962926,40.2999237]],"type":"LineString"},"properties":{"nodes":[{"delta":[-1447,2076],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-4661,14387],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-4762,14321],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":27,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":7,"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}},"remoteIntersection":null,"signalGroup":6,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":28,"geometry":{"coordinates":[[-111.6951353,40.2973366],[-111.6953943,40.2979223],[-111.6955086,40.2981114]],"type":"LineString"},"properties":{"nodes":[{"delta":[-1062,2038],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-2195,6508],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-969,2101],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":28,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":7,"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":7,"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":1,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":29,"geometry":{"coordinates":[[-111.6950935,40.2973366],[-111.695294,40.2977961],[-111.6953949,40.2979228]],"type":"LineString"},"properties":{"nodes":[{"delta":[-708,2038],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-1699,5105],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-855,1408],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":29,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":7,"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":6,"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":1,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":24,"geometry":{"coordinates":[[-111.6953144,40.2973433],[-111.695503,40.2977839],[-111.6955422,40.2979969]],"type":"LineString"},"properties":{"nodes":[{"delta":[-2580,2112],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-1598,4895],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-332,2367],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":24,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":7,"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":23,"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":6,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":30,"geometry":{"coordinates":[[-111.6950442,40.2973389],[-111.695059,40.2973747]],"type":"LineString"},"properties":{"nodes":[{"delta":[-290,2063],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-125,398],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":30,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":8,"ingressApproach":0,"ingressPath":false,"egressPath":true}},{"type":"Feature","id":31,"geometry":{"coordinates":[[-111.6950017,40.2973394],[-111.6950186,40.2973803]],"type":"LineString"},"properties":{"nodes":[{"delta":[70,2069],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-143,454],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":31,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":8,"ingressApproach":0,"ingressPath":false,"egressPath":true}},{"type":"Feature","id":32,"geometry":{"coordinates":[[-111.6949588,40.2973389],[-111.6949763,40.2973803]],"type":"LineString"},"properties":{"nodes":[{"delta":[434,2063],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-148,460],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":32,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":8,"ingressApproach":0,"ingressPath":false,"egressPath":true}},{"type":"Feature","id":23,"geometry":{"coordinates":[[-111.6953705,40.2972489],[-111.695425,40.2972494]],"type":"LineString"},"properties":{"nodes":[{"delta":[-3055,1063],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-462,6],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":23,"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":22,"geometry":{"coordinates":[[-111.6953725,40.2972147],[-111.695425,40.2972162]],"type":"LineString"},"properties":{"nodes":[{"delta":[-3072,683],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-445,17],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":22,"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":18,"geometry":{"coordinates":[[-111.6952746,40.2970877],[-111.6964743,40.297086]],"type":"LineString"},"properties":{"nodes":[{"delta":[-2242,-728],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-10167,-19],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":18,"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":7,"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":4,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":19,"geometry":{"coordinates":[[-111.6952907,40.2971174],[-111.6964756,40.2971145]],"type":"LineString"},"properties":{"nodes":[{"delta":[-2379,-398],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-10041,-32],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":19,"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":6,"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":4,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":20,"geometry":{"coordinates":[[-111.6953089,40.297147],[-111.6961141,40.2971495],[-111.6962917,40.2971163]],"type":"LineString"},"properties":{"nodes":[{"delta":[-2533,-69],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-6824,28],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-1505,-369],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":20,"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":true,"maneuverUTurnAllowed":false,"maneuverLeftTurnOnRedAllowed":false,"reserved1":false,"maneuverRightAllowed":false,"maneuverLaneChangeAllowed":false,"yieldAllwaysRequired":false,"maneuverRightTurnOnRedAllowed":false,"caution":false},"connectsTo":[{"connectingLane":{"lane":31,"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":7,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":21,"geometry":{"coordinates":[[-111.6953236,40.2971756],[-111.6959863,40.2971761],[-111.6961141,40.29715]],"type":"LineString"},"properties":{"nodes":[{"delta":[-2658,249],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-5616,6],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-1083,-290],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":21,"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":true,"maneuverUTurnAllowed":false,"maneuverLeftTurnOnRedAllowed":false,"reserved1":false,"maneuverRightAllowed":false,"maneuverLaneChangeAllowed":false,"yieldAllwaysRequired":false,"maneuverRightTurnOnRedAllowed":false,"caution":false},"connectsTo":[{"connectingLane":{"lane":30,"maneuver":{"maneuverStraightAllowed":false,"maneuverNoStoppingAllowed":false,"goWithHalt":false,"maneuverLeftAllowed":true,"maneuverUTurnAllowed":true,"maneuverLeftTurnOnRedAllowed":false,"reserved1":false,"maneuverRightAllowed":false,"maneuverLaneChangeAllowed":false,"yieldAllwaysRequired":false,"maneuverRightTurnOnRedAllowed":false,"caution":false}},"remoteIntersection":null,"signalGroup":7,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":17,"geometry":{"coordinates":[[-111.6952574,40.2970542],[-111.6959705,40.2970588],[-111.6961326,40.2970849]],"type":"LineString"},"properties":{"nodes":[{"delta":[-2097,-1100],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-6043,51],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-1374,290],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":17,"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":16,"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":4,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":34,"geometry":{"coordinates":[[-111.694707,40.2970001],[-111.6951879,40.2969977]],"type":"LineString"},"properties":{"nodes":[{"delta":[2568,-1701],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-4075,-27],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":34,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":0,"ingressPath":false,"egressPath":false}},{"type":"Feature","id":35,"geometry":{"coordinates":[[-111.6952023,40.2970198],[-111.6953688,40.2973123]],"type":"LineString"},"properties":{"nodes":[{"delta":[-1630,-1482],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-1411,3250],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":35,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":0,"ingressPath":false,"egressPath":false}},{"type":"Feature","id":36,"geometry":{"coordinates":[[-111.6953605,40.2973241],[-111.6948565,40.2973006]],"type":"LineString"},"properties":{"nodes":[{"delta":[-2970,1899],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[4271,-261],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":36,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":0,"ingressPath":false,"egressPath":false}},{"type":"Feature","id":33,"geometry":{"coordinates":[[-111.694819,40.2972895],[-111.6946964,40.2970125]],"type":"LineString"},"properties":{"nodes":[{"delta":[1619,1514],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1039,-3078],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":33,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":0,"ingressPath":false,"egressPath":false}}]},"connectingLanesFeatureCollection":{"type":"FeatureCollection","features":[{"type":"Feature","id":"10-31","geometry":{"coordinates":[[-111.6948409,40.2969746],[-111.6950017,40.2973394]],"type":"LineString"},"properties":{"signalGroupId":2,"ingressLaneId":10,"egressLaneId":31}},{"type":"Feature","id":"11-30","geometry":{"coordinates":[[-111.6948823,40.2969752],[-111.6950442,40.2973389]],"type":"LineString"},"properties":{"signalGroupId":2,"ingressLaneId":11,"egressLaneId":30}},{"type":"Feature","id":"8-7","geometry":{"coordinates":[[-111.6947447,40.296975],[-111.6946927,40.2970769]],"type":"LineString"},"properties":{"signalGroupId":2,"ingressLaneId":8,"egressLaneId":7}},{"type":"Feature","id":"12-23","geometry":{"coordinates":[[-111.6949207,40.2969747],[-111.6953705,40.2972489]],"type":"LineString"},"properties":{"signalGroupId":5,"ingressLaneId":12,"egressLaneId":23}},{"type":"Feature","id":"13-22","geometry":{"coordinates":[[-111.6949654,40.2969755],[-111.6953725,40.2972147]],"type":"LineString"},"properties":{"signalGroupId":5,"ingressLaneId":13,"egressLaneId":22}},{"type":"Feature","id":"9-32","geometry":{"coordinates":[[-111.6947945,40.2969755],[-111.6949588,40.2973389]],"type":"LineString"},"properties":{"signalGroupId":2,"ingressLaneId":9,"egressLaneId":32}},{"type":"Feature","id":"2-23","geometry":{"coordinates":[[-111.6947591,40.2972387],[-111.6953705,40.2972489]],"type":"LineString"},"properties":{"signalGroupId":8,"ingressLaneId":2,"egressLaneId":23}},{"type":"Feature","id":"3-22","geometry":{"coordinates":[[-111.6947502,40.2972093],[-111.6953725,40.2972147]],"type":"LineString"},"properties":{"signalGroupId":8,"ingressLaneId":3,"egressLaneId":22}},{"type":"Feature","id":"4-15","geometry":{"coordinates":[[-111.694738,40.2971788],[-111.6950597,40.2969678]],"type":"LineString"},"properties":{"signalGroupId":3,"ingressLaneId":4,"egressLaneId":15}},{"type":"Feature","id":"5-14","geometry":{"coordinates":[[-111.6947267,40.2971466],[-111.6950119,40.2969764]],"type":"LineString"},"properties":{"signalGroupId":3,"ingressLaneId":5,"egressLaneId":14}},{"type":"Feature","id":"1-32","geometry":{"coordinates":[[-111.6947696,40.2972705],[-111.6949588,40.2973389]],"type":"LineString"},"properties":{"signalGroupId":8,"ingressLaneId":1,"egressLaneId":32}},{"type":"Feature","id":"25-16","geometry":{"coordinates":[[-111.6952664,40.2973429],[-111.6950993,40.2969606]],"type":"LineString"},"properties":{"signalGroupId":6,"ingressLaneId":25,"egressLaneId":16}},{"type":"Feature","id":"26-15","geometry":{"coordinates":[[-111.6952202,40.2973406],[-111.6950597,40.2969678]],"type":"LineString"},"properties":{"signalGroupId":6,"ingressLaneId":26,"egressLaneId":15}},{"type":"Feature","id":"27-14","geometry":{"coordinates":[[-111.6951807,40.29734],[-111.6950119,40.2969764]],"type":"LineString"},"properties":{"signalGroupId":6,"ingressLaneId":27,"egressLaneId":14}},{"type":"Feature","id":"28-7","geometry":{"coordinates":[[-111.6951353,40.2973366],[-111.6946927,40.2970769]],"type":"LineString"},"properties":{"signalGroupId":1,"ingressLaneId":28,"egressLaneId":7}},{"type":"Feature","id":"29-6","geometry":{"coordinates":[[-111.6950935,40.2973366],[-111.6947034,40.2971076]],"type":"LineString"},"properties":{"signalGroupId":1,"ingressLaneId":29,"egressLaneId":6}},{"type":"Feature","id":"24-23","geometry":{"coordinates":[[-111.6953144,40.2973433],[-111.6953705,40.2972489]],"type":"LineString"},"properties":{"signalGroupId":6,"ingressLaneId":24,"egressLaneId":23}},{"type":"Feature","id":"18-7","geometry":{"coordinates":[[-111.6952746,40.2970877],[-111.6946927,40.2970769]],"type":"LineString"},"properties":{"signalGroupId":4,"ingressLaneId":18,"egressLaneId":7}},{"type":"Feature","id":"19-6","geometry":{"coordinates":[[-111.6952907,40.2971174],[-111.6947034,40.2971076]],"type":"LineString"},"properties":{"signalGroupId":4,"ingressLaneId":19,"egressLaneId":6}},{"type":"Feature","id":"20-31","geometry":{"coordinates":[[-111.6953089,40.297147],[-111.6950017,40.2973394]],"type":"LineString"},"properties":{"signalGroupId":7,"ingressLaneId":20,"egressLaneId":31}},{"type":"Feature","id":"21-30","geometry":{"coordinates":[[-111.6953236,40.2971756],[-111.6950442,40.2973389]],"type":"LineString"},"properties":{"signalGroupId":7,"ingressLaneId":21,"egressLaneId":30}},{"type":"Feature","id":"17-16","geometry":{"coordinates":[[-111.6952574,40.2970542],[-111.6950993,40.2969606]],"type":"LineString"},"properties":{"signalGroupId":4,"ingressLaneId":17,"egressLaneId":16}}]},"properties":{"messageType":"MAP","odeReceivedAt":"@ISO_DATE_TIME@","originIp":"10.164.6.16","intersectionName":"N State St & E Center St","intersectionId":6311,"msgIssueRevision":0,"revision":4,"refPoint":{"latitude":40.2971532,"longitude":-111.69501,"elevation":1437},"cti4501Conformant":false,"validationMessages":[{"message":"$.metadata.recordGeneratedBy: is missing but it is required","jsonPath":"$.metadata","schemaPath":"#/$defs/OdeMapMetadata/required"},{"message":"$.metadata.receivedMessageDetails.locationData: is missing but it is required","jsonPath":"$.metadata.receivedMessageDetails","schemaPath":"#/$defs/OdeMapMetadata/properties/receivedMessageDetails/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].id.region: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].id","schemaPath":"#/$defs/J2735IntersectionReferenceID/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[6].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[6]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[6].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[6]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[7].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[7]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[7].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[7]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[8].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[8]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[8].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[8]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[9].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[9]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[9].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[9]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[10].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[10]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[10].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[10]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[22].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[22]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[22].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[22]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[23].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[23]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[23].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[23]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[24].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[24]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[24].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[24]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[25].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[25]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[25].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[25]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[26].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[26]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[26].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[26]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[32].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[32]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[32].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[32]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[33].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[33]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[33].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[33]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[34].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[34]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[34].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[34]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[35].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[35]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[35].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[35]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].speedLimits: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0]","schemaPath":"#/$defs/J2735IntersectionGeometry/required"}],"laneWidth":366,"mapSource":"RSU","timeStamp":"@ISO_DATE_TIME_OFFSET_MILLIS_-1000@"}} +ProcessedMap;10.164.6.16;6311,7000,{"mapFeatureCollection":{"type":"FeatureCollection","features":[{"type":"Feature","id":10,"geometry":{"coordinates":[[-111.6948409,40.2969746],[-111.6947006,40.2966582],[-111.6945681,40.2963382],[-111.6942976,40.2956952],[-111.6937336,40.2944205]],"type":"LineString"},"properties":{"nodes":[{"delta":[1433,-1984],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1189,-3515],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1123,-3555],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[2292,-7144],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[4780,-14163],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":10,"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":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":31,"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":null}]}},{"type":"Feature","id":11,"geometry":{"coordinates":[[-111.6948823,40.2969752],[-111.6947416,40.2966568],[-111.6946104,40.2963317],[-111.6943345,40.2956892],[-111.6937694,40.2944109]],"type":"LineString"},"properties":{"nodes":[{"delta":[1082,-1978],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1192,-3538],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1112,-3612],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[2338,-7139],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[4789,-14203],"stopLine":null,"dwidth":null,"delevation":null}],"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":3,"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":30,"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":null}]}},{"type":"Feature","id":8,"geometry":{"coordinates":[[-111.6947447,40.296975],[-111.6945987,40.2966224],[-111.6945415,40.296375]],"type":"LineString"},"properties":{"nodes":[{"delta":[2248,-1980],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1237,-3918],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[485,-2749],"stopLine":null,"dwidth":null,"delevation":null}],"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":false,"maneuverUTurnAllowed":false,"maneuverLeftTurnOnRedAllowed":false,"reserved1":false,"maneuverRightAllowed":true,"maneuverLaneChangeAllowed":false,"yieldAllwaysRequired":false,"maneuverRightTurnOnRedAllowed":false,"caution":false},"connectsTo":[{"connectingLane":{"lane":7,"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":2,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":12,"geometry":{"coordinates":[[-111.6949207,40.2969747],[-111.6946355,40.2963144],[-111.6945628,40.2962224]],"type":"LineString"},"properties":{"nodes":[{"delta":[757,-1983],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[2417,-7337],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[616,-1022],"stopLine":null,"dwidth":null,"delevation":null}],"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":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":23,"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":5,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":13,"geometry":{"coordinates":[[-111.6949654,40.2969755],[-111.6946693,40.2963075],[-111.694563,40.2962226]],"type":"LineString"},"properties":{"nodes":[{"delta":[378,-1974],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[2509,-7422],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[901,-943],"stopLine":null,"dwidth":null,"delevation":null}],"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":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":22,"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":5,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":9,"geometry":{"coordinates":[[-111.6947945,40.2969755],[-111.6946603,40.2966635],[-111.6945311,40.2963445],[-111.6942586,40.2957025],[-111.6936955,40.2944313]],"type":"LineString"},"properties":{"nodes":[{"delta":[1826,-1974],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1137,-3467],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1095,-3544],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[2309,-7133],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[4772,-14124],"stopLine":null,"dwidth":null,"delevation":null}],"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":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":32,"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":null}]}},{"type":"Feature","id":16,"geometry":{"coordinates":[[-111.6950993,40.2969606],[-111.6950831,40.2969207]],"type":"LineString"},"properties":{"nodes":[{"delta":[-757,-2140],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[137,-443],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":16,"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":15,"geometry":{"coordinates":[[-111.6950597,40.2969678],[-111.6950435,40.2969279]],"type":"LineString"},"properties":{"nodes":[{"delta":[-421,-2060],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[137,-443],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":15,"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":14,"geometry":{"coordinates":[[-111.6950119,40.2969764],[-111.6949964,40.2969345]],"type":"LineString"},"properties":{"nodes":[{"delta":[-16,-1964],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[131,-466],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":14,"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":6,"geometry":{"coordinates":[[-111.6947034,40.2971076],[-111.6946516,40.2971061]],"type":"LineString"},"properties":{"nodes":[{"delta":[2598,-507],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[439,-17],"stopLine":null,"dwidth":null,"delevation":null}],"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":7,"geometry":{"coordinates":[[-111.6946927,40.2970769],[-111.6946416,40.2970759]],"type":"LineString"},"properties":{"nodes":[{"delta":[2689,-848],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[433,-11],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":7,"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":2,"geometry":{"coordinates":[[-111.6947591,40.2972387],[-111.6935683,40.2972245]],"type":"LineString"},"properties":{"nodes":[{"delta":[2126,950],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[10091,-158],"stopLine":null,"dwidth":null,"delevation":null}],"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":23,"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":8,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":3,"geometry":{"coordinates":[[-111.6947502,40.2972093],[-111.6935675,40.2971992]],"type":"LineString"},"properties":{"nodes":[{"delta":[2202,623],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[10023,-112],"stopLine":null,"dwidth":null,"delevation":null}],"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":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":22,"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":8,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":4,"geometry":{"coordinates":[[-111.694738,40.2971788],[-111.6941318,40.2971713],[-111.6939017,40.2971989]],"type":"LineString"},"properties":{"nodes":[{"delta":[2305,284],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[5137,-83],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1950,307],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":4,"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":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":3,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":5,"geometry":{"coordinates":[[-111.6947267,40.2971466],[-111.6943028,40.2971432],[-111.6941317,40.2971719]],"type":"LineString"},"properties":{"nodes":[{"delta":[2401,-73],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[3592,-38],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1450,319],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":5,"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":14,"maneuver":{"maneuverStraightAllowed":false,"maneuverNoStoppingAllowed":false,"goWithHalt":false,"maneuverLeftAllowed":true,"maneuverUTurnAllowed":true,"maneuverLeftTurnOnRedAllowed":false,"reserved1":false,"maneuverRightAllowed":false,"maneuverLaneChangeAllowed":false,"yieldAllwaysRequired":false,"maneuverRightTurnOnRedAllowed":false,"caution":false}},"remoteIntersection":null,"signalGroup":3,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":1,"geometry":{"coordinates":[[-111.6947696,40.2972705],[-111.693782,40.2972623],[-111.6935771,40.2972531]],"type":"LineString"},"properties":{"nodes":[{"delta":[2037,1303],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[8369,-91],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1736,-102],"stopLine":null,"dwidth":null,"delevation":null}],"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":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":32,"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":8,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":25,"geometry":{"coordinates":[[-111.6952664,40.2973429],[-111.6958094,40.2986271],[-111.6963738,40.2999056]],"type":"LineString"},"properties":{"nodes":[{"delta":[-2173,2108],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-4602,14269],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-4783,14206],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":25,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":7,"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":16,"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":null}]}},{"type":"Feature","id":26,"geometry":{"coordinates":[[-111.6952202,40.2973406],[-111.6957689,40.2986334],[-111.6963331,40.2999146]],"type":"LineString"},"properties":{"nodes":[{"delta":[-1781,2082],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-4650,14364],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-4781,14235],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":26,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":7,"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}},"remoteIntersection":null,"signalGroup":6,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":27,"geometry":{"coordinates":[[-111.6951807,40.29734],[-111.6957307,40.2986348],[-111.6962926,40.2999237]],"type":"LineString"},"properties":{"nodes":[{"delta":[-1447,2076],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-4661,14387],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-4762,14321],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":27,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":7,"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}},"remoteIntersection":null,"signalGroup":6,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":28,"geometry":{"coordinates":[[-111.6951353,40.2973366],[-111.6953943,40.2979223],[-111.6955086,40.2981114]],"type":"LineString"},"properties":{"nodes":[{"delta":[-1062,2038],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-2195,6508],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-969,2101],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":28,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":7,"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":7,"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":1,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":29,"geometry":{"coordinates":[[-111.6950935,40.2973366],[-111.695294,40.2977961],[-111.6953949,40.2979228]],"type":"LineString"},"properties":{"nodes":[{"delta":[-708,2038],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-1699,5105],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-855,1408],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":29,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":7,"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":6,"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":1,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":24,"geometry":{"coordinates":[[-111.6953144,40.2973433],[-111.695503,40.2977839],[-111.6955422,40.2979969]],"type":"LineString"},"properties":{"nodes":[{"delta":[-2580,2112],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-1598,4895],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-332,2367],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":24,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":7,"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":23,"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":6,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":30,"geometry":{"coordinates":[[-111.6950442,40.2973389],[-111.695059,40.2973747]],"type":"LineString"},"properties":{"nodes":[{"delta":[-290,2063],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-125,398],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":30,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":8,"ingressApproach":0,"ingressPath":false,"egressPath":true}},{"type":"Feature","id":31,"geometry":{"coordinates":[[-111.6950017,40.2973394],[-111.6950186,40.2973803]],"type":"LineString"},"properties":{"nodes":[{"delta":[70,2069],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-143,454],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":31,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":8,"ingressApproach":0,"ingressPath":false,"egressPath":true}},{"type":"Feature","id":32,"geometry":{"coordinates":[[-111.6949588,40.2973389],[-111.6949763,40.2973803]],"type":"LineString"},"properties":{"nodes":[{"delta":[434,2063],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-148,460],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":32,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":8,"ingressApproach":0,"ingressPath":false,"egressPath":true}},{"type":"Feature","id":23,"geometry":{"coordinates":[[-111.6953705,40.2972489],[-111.695425,40.2972494]],"type":"LineString"},"properties":{"nodes":[{"delta":[-3055,1063],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-462,6],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":23,"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":22,"geometry":{"coordinates":[[-111.6953725,40.2972147],[-111.695425,40.2972162]],"type":"LineString"},"properties":{"nodes":[{"delta":[-3072,683],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-445,17],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":22,"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":18,"geometry":{"coordinates":[[-111.6952746,40.2970877],[-111.6964743,40.297086]],"type":"LineString"},"properties":{"nodes":[{"delta":[-2242,-728],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-10167,-19],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":18,"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":7,"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":4,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":19,"geometry":{"coordinates":[[-111.6952907,40.2971174],[-111.6964756,40.2971145]],"type":"LineString"},"properties":{"nodes":[{"delta":[-2379,-398],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-10041,-32],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":19,"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":6,"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":4,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":20,"geometry":{"coordinates":[[-111.6953089,40.297147],[-111.6961141,40.2971495],[-111.6962917,40.2971163]],"type":"LineString"},"properties":{"nodes":[{"delta":[-2533,-69],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-6824,28],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-1505,-369],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":20,"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":true,"maneuverUTurnAllowed":false,"maneuverLeftTurnOnRedAllowed":false,"reserved1":false,"maneuverRightAllowed":false,"maneuverLaneChangeAllowed":false,"yieldAllwaysRequired":false,"maneuverRightTurnOnRedAllowed":false,"caution":false},"connectsTo":[{"connectingLane":{"lane":31,"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":7,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":21,"geometry":{"coordinates":[[-111.6953236,40.2971756],[-111.6959863,40.2971761],[-111.6961141,40.29715]],"type":"LineString"},"properties":{"nodes":[{"delta":[-2658,249],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-5616,6],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-1083,-290],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":21,"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":true,"maneuverUTurnAllowed":false,"maneuverLeftTurnOnRedAllowed":false,"reserved1":false,"maneuverRightAllowed":false,"maneuverLaneChangeAllowed":false,"yieldAllwaysRequired":false,"maneuverRightTurnOnRedAllowed":false,"caution":false},"connectsTo":[{"connectingLane":{"lane":30,"maneuver":{"maneuverStraightAllowed":false,"maneuverNoStoppingAllowed":false,"goWithHalt":false,"maneuverLeftAllowed":true,"maneuverUTurnAllowed":true,"maneuverLeftTurnOnRedAllowed":false,"reserved1":false,"maneuverRightAllowed":false,"maneuverLaneChangeAllowed":false,"yieldAllwaysRequired":false,"maneuverRightTurnOnRedAllowed":false,"caution":false}},"remoteIntersection":null,"signalGroup":7,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":17,"geometry":{"coordinates":[[-111.6952574,40.2970542],[-111.6959705,40.2970588],[-111.6961326,40.2970849]],"type":"LineString"},"properties":{"nodes":[{"delta":[-2097,-1100],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-6043,51],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-1374,290],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":17,"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":16,"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":4,"userClass":null,"connectionID":null}]}},{"type":"Feature","id":34,"geometry":{"coordinates":[[-111.694707,40.2970001],[-111.6951879,40.2969977]],"type":"LineString"},"properties":{"nodes":[{"delta":[2568,-1701],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-4075,-27],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":34,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":0,"ingressPath":false,"egressPath":false}},{"type":"Feature","id":35,"geometry":{"coordinates":[[-111.6952023,40.2970198],[-111.6953688,40.2973123]],"type":"LineString"},"properties":{"nodes":[{"delta":[-1630,-1482],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[-1411,3250],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":35,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":0,"ingressPath":false,"egressPath":false}},{"type":"Feature","id":36,"geometry":{"coordinates":[[-111.6953605,40.2973241],[-111.6948565,40.2973006]],"type":"LineString"},"properties":{"nodes":[{"delta":[-2970,1899],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[4271,-261],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":36,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":0,"ingressPath":false,"egressPath":false}},{"type":"Feature","id":33,"geometry":{"coordinates":[[-111.694819,40.2972895],[-111.6946964,40.2970125]],"type":"LineString"},"properties":{"nodes":[{"delta":[1619,1514],"stopLine":null,"dwidth":null,"delevation":null},{"delta":[1039,-3078],"stopLine":null,"dwidth":null,"delevation":null}],"laneId":33,"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":0,"ingressPath":false,"egressPath":false}}]},"connectingLanesFeatureCollection":{"type":"FeatureCollection","features":[{"type":"Feature","id":"10-31","geometry":{"coordinates":[[-111.6948409,40.2969746],[-111.6950017,40.2973394]],"type":"LineString"},"properties":{"signalGroupId":2,"ingressLaneId":10,"egressLaneId":31}},{"type":"Feature","id":"11-30","geometry":{"coordinates":[[-111.6948823,40.2969752],[-111.6950442,40.2973389]],"type":"LineString"},"properties":{"signalGroupId":2,"ingressLaneId":11,"egressLaneId":30}},{"type":"Feature","id":"8-7","geometry":{"coordinates":[[-111.6947447,40.296975],[-111.6946927,40.2970769]],"type":"LineString"},"properties":{"signalGroupId":2,"ingressLaneId":8,"egressLaneId":7}},{"type":"Feature","id":"12-23","geometry":{"coordinates":[[-111.6949207,40.2969747],[-111.6953705,40.2972489]],"type":"LineString"},"properties":{"signalGroupId":5,"ingressLaneId":12,"egressLaneId":23}},{"type":"Feature","id":"13-22","geometry":{"coordinates":[[-111.6949654,40.2969755],[-111.6953725,40.2972147]],"type":"LineString"},"properties":{"signalGroupId":5,"ingressLaneId":13,"egressLaneId":22}},{"type":"Feature","id":"9-32","geometry":{"coordinates":[[-111.6947945,40.2969755],[-111.6949588,40.2973389]],"type":"LineString"},"properties":{"signalGroupId":2,"ingressLaneId":9,"egressLaneId":32}},{"type":"Feature","id":"2-23","geometry":{"coordinates":[[-111.6947591,40.2972387],[-111.6953705,40.2972489]],"type":"LineString"},"properties":{"signalGroupId":8,"ingressLaneId":2,"egressLaneId":23}},{"type":"Feature","id":"3-22","geometry":{"coordinates":[[-111.6947502,40.2972093],[-111.6953725,40.2972147]],"type":"LineString"},"properties":{"signalGroupId":8,"ingressLaneId":3,"egressLaneId":22}},{"type":"Feature","id":"4-15","geometry":{"coordinates":[[-111.694738,40.2971788],[-111.6950597,40.2969678]],"type":"LineString"},"properties":{"signalGroupId":3,"ingressLaneId":4,"egressLaneId":15}},{"type":"Feature","id":"5-14","geometry":{"coordinates":[[-111.6947267,40.2971466],[-111.6950119,40.2969764]],"type":"LineString"},"properties":{"signalGroupId":3,"ingressLaneId":5,"egressLaneId":14}},{"type":"Feature","id":"1-32","geometry":{"coordinates":[[-111.6947696,40.2972705],[-111.6949588,40.2973389]],"type":"LineString"},"properties":{"signalGroupId":8,"ingressLaneId":1,"egressLaneId":32}},{"type":"Feature","id":"25-16","geometry":{"coordinates":[[-111.6952664,40.2973429],[-111.6950993,40.2969606]],"type":"LineString"},"properties":{"signalGroupId":6,"ingressLaneId":25,"egressLaneId":16}},{"type":"Feature","id":"26-15","geometry":{"coordinates":[[-111.6952202,40.2973406],[-111.6950597,40.2969678]],"type":"LineString"},"properties":{"signalGroupId":6,"ingressLaneId":26,"egressLaneId":15}},{"type":"Feature","id":"27-14","geometry":{"coordinates":[[-111.6951807,40.29734],[-111.6950119,40.2969764]],"type":"LineString"},"properties":{"signalGroupId":6,"ingressLaneId":27,"egressLaneId":14}},{"type":"Feature","id":"28-7","geometry":{"coordinates":[[-111.6951353,40.2973366],[-111.6946927,40.2970769]],"type":"LineString"},"properties":{"signalGroupId":1,"ingressLaneId":28,"egressLaneId":7}},{"type":"Feature","id":"29-6","geometry":{"coordinates":[[-111.6950935,40.2973366],[-111.6947034,40.2971076]],"type":"LineString"},"properties":{"signalGroupId":1,"ingressLaneId":29,"egressLaneId":6}},{"type":"Feature","id":"24-23","geometry":{"coordinates":[[-111.6953144,40.2973433],[-111.6953705,40.2972489]],"type":"LineString"},"properties":{"signalGroupId":6,"ingressLaneId":24,"egressLaneId":23}},{"type":"Feature","id":"18-7","geometry":{"coordinates":[[-111.6952746,40.2970877],[-111.6946927,40.2970769]],"type":"LineString"},"properties":{"signalGroupId":4,"ingressLaneId":18,"egressLaneId":7}},{"type":"Feature","id":"19-6","geometry":{"coordinates":[[-111.6952907,40.2971174],[-111.6947034,40.2971076]],"type":"LineString"},"properties":{"signalGroupId":4,"ingressLaneId":19,"egressLaneId":6}},{"type":"Feature","id":"20-31","geometry":{"coordinates":[[-111.6953089,40.297147],[-111.6950017,40.2973394]],"type":"LineString"},"properties":{"signalGroupId":7,"ingressLaneId":20,"egressLaneId":31}},{"type":"Feature","id":"21-30","geometry":{"coordinates":[[-111.6953236,40.2971756],[-111.6950442,40.2973389]],"type":"LineString"},"properties":{"signalGroupId":7,"ingressLaneId":21,"egressLaneId":30}},{"type":"Feature","id":"17-16","geometry":{"coordinates":[[-111.6952574,40.2970542],[-111.6950993,40.2969606]],"type":"LineString"},"properties":{"signalGroupId":4,"ingressLaneId":17,"egressLaneId":16}}]},"properties":{"messageType":"MAP","odeReceivedAt":"@ISO_DATE_TIME@","originIp":"10.164.6.16","intersectionName":"N State St & E Center St","intersectionId":6311,"msgIssueRevision":0,"revision":4,"refPoint":{"latitude":40.2971532,"longitude":-111.69501,"elevation":1437},"cti4501Conformant":false,"validationMessages":[{"message":"$.metadata.recordGeneratedBy: is missing but it is required","jsonPath":"$.metadata","schemaPath":"#/$defs/OdeMapMetadata/required"},{"message":"$.metadata.receivedMessageDetails.locationData: is missing but it is required","jsonPath":"$.metadata.receivedMessageDetails","schemaPath":"#/$defs/OdeMapMetadata/properties/receivedMessageDetails/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].id.region: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].id","schemaPath":"#/$defs/J2735IntersectionReferenceID/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[6].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[6]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[6].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[6]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[7].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[7]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[7].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[7]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[8].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[8]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[8].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[8]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[9].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[9]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[9].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[9]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[10].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[10]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[10].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[10]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[22].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[22]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[22].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[22]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[23].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[23]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[23].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[23]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[24].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[24]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[24].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[24]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[25].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[25]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[25].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[25]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[26].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[26]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[26].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[26]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[32].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[32]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[32].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[32]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[33].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[33]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[33].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[33]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[34].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[34]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[34].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[34]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[35].maneuvers: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[35]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[35].connectsTo: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[35]","schemaPath":"#/$defs/J2735GenericLane/required"},{"message":"$.payload.data.intersections.intersectionGeometry[0].speedLimits: is missing but it is required","jsonPath":"$.payload.data.intersections.intersectionGeometry[0]","schemaPath":"#/$defs/J2735IntersectionGeometry/required"}],"laneWidth":366,"mapSource":"RSU","timeStamp":"@ISO_DATE_TIME_OFFSET_MILLIS_600@"}} \ No newline at end of file diff --git a/jpo-conflictmonitor/scripts/IntegrationTestScripts/TimestampDelta-ProcessedSpats.csv b/jpo-conflictmonitor/scripts/IntegrationTestScripts/TimestampDelta-ProcessedSpats.csv new file mode 100644 index 00000000..0c72b3b3 --- /dev/null +++ b/jpo-conflictmonitor/scripts/IntegrationTestScripts/TimestampDelta-ProcessedSpats.csv @@ -0,0 +1,4 @@ +ProcessedSpat;10.164.6.18;6311,1000,{"messageType":"SPAT","odeReceivedAt":"@ISO_DATE_TIME@","originIp":"10.164.6.18","name":"N State St & E Center St","intersectionId":6311,"cti4501Conformant":false,"validationMessages":[{"message":"$.metadata.receivedMessageDetails.locationData: is missing but it is required","jsonPath":"$.metadata.receivedMessageDetails","schemaPath":"#/$defs/OdeSpatMetadata/properties/receivedMessageDetails/required"},{"message":"$.metadata.encodings: is missing but it is required","jsonPath":"$.metadata","schemaPath":"#/$defs/OdeSpatMetadata/required"},{"message":"$.metadata.recordGeneratedBy: is missing but it is required","jsonPath":"$.metadata","schemaPath":"#/$defs/OdeSpatMetadata/required"},{"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.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.maxEndTime: 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":45,"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":"@ISO_DATE_TIME_OFFSET_MILLIS_20@","enabledLanes":[],"states":[{"signalGroup":1,"stateTimeSpeed":[{"eventState":"STOP_AND_REMAIN","timing":{"startTime":null,"minEndTime":"@OFFSET_SECONDS_78.61899995803833@","maxEndTime":"@OFFSET_SECONDS_78.61899995803833@","likelyTime":null,"confidence":null,"nextTime":null}}]},{"signalGroup":2,"stateTimeSpeed":[{"eventState":"STOP_AND_REMAIN","timing":{"startTime":null,"minEndTime":"@OFFSET_SECONDS_28.61899995803833@","maxEndTime":"@OFFSET_SECONDS_28.61899995803833@","likelyTime":null,"confidence":null,"nextTime":null}}]},{"signalGroup":3,"stateTimeSpeed":[{"eventState":"STOP_AND_REMAIN","timing":{"startTime":null,"minEndTime":"@OFFSET_SECONDS_98.61899995803833@","maxEndTime":"@OFFSET_SECONDS_98.61899995803833@","likelyTime":null,"confidence":null,"nextTime":null}}]},{"signalGroup":4,"stateTimeSpeed":[{"eventState":"PROTECTED_MOVEMENT_ALLOWED","timing":{"startTime":null,"minEndTime":"@OFFSET_SECONDS_14.418999910354614@","maxEndTime":"@OFFSET_SECONDS_22.418999910354614@","likelyTime":null,"confidence":null,"nextTime":null}}]},{"signalGroup":5,"stateTimeSpeed":[{"eventState":"STOP_AND_REMAIN","timing":{"startTime":null,"minEndTime":"@OFFSET_SECONDS_28.61899995803833@","maxEndTime":"@OFFSET_SECONDS_28.61899995803833@","likelyTime":null,"confidence":null,"nextTime":null}}]},{"signalGroup":6,"stateTimeSpeed":[{"eventState":"STOP_AND_REMAIN","timing":{"startTime":null,"minEndTime":"@OFFSET_SECONDS_58.61899995803833@","maxEndTime":"@OFFSET_SECONDS_58.61899995803833@","likelyTime":null,"confidence":null,"nextTime":null}}]},{"signalGroup":7,"stateTimeSpeed":[{"eventState":"PROTECTED_MOVEMENT_ALLOWED","timing":{"startTime":null,"minEndTime":"@OFFSET_SECONDS_3.319000005722046@","maxEndTime":"@OFFSET_SECONDS_22.7189998626709@","likelyTime":null,"confidence":null,"nextTime":null}}]},{"signalGroup":8,"stateTimeSpeed":[{"eventState":"STOP_AND_REMAIN","timing":{"startTime":null,"minEndTime":"@OFFSET_SECONDS_-0.08100008964538574@","maxEndTime":null,"likelyTime":null,"confidence":null,"nextTime":null}}]}]} +ProcessedSpat;10.164.6.18;6311,3000,{"messageType":"SPAT","odeReceivedAt":"@ISO_DATE_TIME@","originIp":"10.164.6.18","name":"N State St & E Center St","intersectionId":6311,"cti4501Conformant":false,"validationMessages":[{"message":"$.metadata.receivedMessageDetails.locationData: is missing but it is required","jsonPath":"$.metadata.receivedMessageDetails","schemaPath":"#/$defs/OdeSpatMetadata/properties/receivedMessageDetails/required"},{"message":"$.metadata.encodings: is missing but it is required","jsonPath":"$.metadata","schemaPath":"#/$defs/OdeSpatMetadata/required"},{"message":"$.metadata.recordGeneratedBy: is missing but it is required","jsonPath":"$.metadata","schemaPath":"#/$defs/OdeSpatMetadata/required"},{"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.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.maxEndTime: 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":45,"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":"@ISO_DATE_TIME_OFFSET_MILLIS_-600@","enabledLanes":[],"states":[{"signalGroup":1,"stateTimeSpeed":[{"eventState":"STOP_AND_REMAIN","timing":{"startTime":null,"minEndTime":"@OFFSET_SECONDS_78.61899995803833@","maxEndTime":"@OFFSET_SECONDS_78.61899995803833@","likelyTime":null,"confidence":null,"nextTime":null}}]},{"signalGroup":2,"stateTimeSpeed":[{"eventState":"STOP_AND_REMAIN","timing":{"startTime":null,"minEndTime":"@OFFSET_SECONDS_28.61899995803833@","maxEndTime":"@OFFSET_SECONDS_28.61899995803833@","likelyTime":null,"confidence":null,"nextTime":null}}]},{"signalGroup":3,"stateTimeSpeed":[{"eventState":"STOP_AND_REMAIN","timing":{"startTime":null,"minEndTime":"@OFFSET_SECONDS_98.61899995803833@","maxEndTime":"@OFFSET_SECONDS_98.61899995803833@","likelyTime":null,"confidence":null,"nextTime":null}}]},{"signalGroup":4,"stateTimeSpeed":[{"eventState":"PROTECTED_MOVEMENT_ALLOWED","timing":{"startTime":null,"minEndTime":"@OFFSET_SECONDS_14.418999910354614@","maxEndTime":"@OFFSET_SECONDS_22.418999910354614@","likelyTime":null,"confidence":null,"nextTime":null}}]},{"signalGroup":5,"stateTimeSpeed":[{"eventState":"STOP_AND_REMAIN","timing":{"startTime":null,"minEndTime":"@OFFSET_SECONDS_28.61899995803833@","maxEndTime":"@OFFSET_SECONDS_28.61899995803833@","likelyTime":null,"confidence":null,"nextTime":null}}]},{"signalGroup":6,"stateTimeSpeed":[{"eventState":"STOP_AND_REMAIN","timing":{"startTime":null,"minEndTime":"@OFFSET_SECONDS_58.61899995803833@","maxEndTime":"@OFFSET_SECONDS_58.61899995803833@","likelyTime":null,"confidence":null,"nextTime":null}}]},{"signalGroup":7,"stateTimeSpeed":[{"eventState":"PROTECTED_MOVEMENT_ALLOWED","timing":{"startTime":null,"minEndTime":"@OFFSET_SECONDS_3.319000005722046@","maxEndTime":"@OFFSET_SECONDS_22.7189998626709@","likelyTime":null,"confidence":null,"nextTime":null}}]},{"signalGroup":8,"stateTimeSpeed":[{"eventState":"STOP_AND_REMAIN","timing":{"startTime":null,"minEndTime":"@OFFSET_SECONDS_-0.08100008964538574@","maxEndTime":null,"likelyTime":null,"confidence":null,"nextTime":null}}]}]} +ProcessedSpat;10.164.6.18;6311,5000,{"messageType":"SPAT","odeReceivedAt":"@ISO_DATE_TIME@","originIp":"10.164.6.18","name":"N State St & E Center St","intersectionId":6311,"cti4501Conformant":false,"validationMessages":[{"message":"$.metadata.receivedMessageDetails.locationData: is missing but it is required","jsonPath":"$.metadata.receivedMessageDetails","schemaPath":"#/$defs/OdeSpatMetadata/properties/receivedMessageDetails/required"},{"message":"$.metadata.encodings: is missing but it is required","jsonPath":"$.metadata","schemaPath":"#/$defs/OdeSpatMetadata/required"},{"message":"$.metadata.recordGeneratedBy: is missing but it is required","jsonPath":"$.metadata","schemaPath":"#/$defs/OdeSpatMetadata/required"},{"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.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.maxEndTime: 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":46,"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":"@ISO_DATE_TIME_OFFSET_MILLIS_-1200@","enabledLanes":[],"states":[{"signalGroup":1,"stateTimeSpeed":[{"eventState":"STOP_AND_REMAIN","timing":{"startTime":null,"minEndTime":"@OFFSET_SECONDS_78.51900005340576@","maxEndTime":"@OFFSET_SECONDS_78.51900005340576@","likelyTime":null,"confidence":null,"nextTime":null}}]},{"signalGroup":2,"stateTimeSpeed":[{"eventState":"STOP_AND_REMAIN","timing":{"startTime":null,"minEndTime":"@OFFSET_SECONDS_28.51900005340576@","maxEndTime":"@OFFSET_SECONDS_28.51900005340576@","likelyTime":null,"confidence":null,"nextTime":null}}]},{"signalGroup":3,"stateTimeSpeed":[{"eventState":"STOP_AND_REMAIN","timing":{"startTime":null,"minEndTime":"@OFFSET_SECONDS_98.51900005340576@","maxEndTime":"@OFFSET_SECONDS_98.51900005340576@","likelyTime":null,"confidence":null,"nextTime":null}}]},{"signalGroup":4,"stateTimeSpeed":[{"eventState":"PROTECTED_MOVEMENT_ALLOWED","timing":{"startTime":null,"minEndTime":"@OFFSET_SECONDS_14.319000005722046@","maxEndTime":"@OFFSET_SECONDS_22.319000005722046@","likelyTime":null,"confidence":null,"nextTime":null}}]},{"signalGroup":5,"stateTimeSpeed":[{"eventState":"STOP_AND_REMAIN","timing":{"startTime":null,"minEndTime":"@OFFSET_SECONDS_28.51900005340576@","maxEndTime":"@OFFSET_SECONDS_28.51900005340576@","likelyTime":null,"confidence":null,"nextTime":null}}]},{"signalGroup":6,"stateTimeSpeed":[{"eventState":"STOP_AND_REMAIN","timing":{"startTime":null,"minEndTime":"@OFFSET_SECONDS_58.51900005340576@","maxEndTime":"@OFFSET_SECONDS_58.51900005340576@","likelyTime":null,"confidence":null,"nextTime":null}}]},{"signalGroup":7,"stateTimeSpeed":[{"eventState":"PROTECTED_MOVEMENT_ALLOWED","timing":{"startTime":null,"minEndTime":"@OFFSET_SECONDS_3.2190001010894775@","maxEndTime":"@OFFSET_SECONDS_22.61899995803833@","likelyTime":null,"confidence":null,"nextTime":null}}]},{"signalGroup":8,"stateTimeSpeed":[{"eventState":"STOP_AND_REMAIN","timing":{"startTime":null,"minEndTime":"@OFFSET_SECONDS_-0.08100008964538574@","maxEndTime":null,"likelyTime":null,"confidence":null,"nextTime":null}}]}]} +ProcessedSpat;10.164.6.18;6311,7000,{"messageType":"SPAT","odeReceivedAt":"@ISO_DATE_TIME@","originIp":"10.164.6.18","name":"N State St & E Center St","intersectionId":6311,"cti4501Conformant":false,"validationMessages":[{"message":"$.metadata.receivedMessageDetails.locationData: is missing but it is required","jsonPath":"$.metadata.receivedMessageDetails","schemaPath":"#/$defs/OdeSpatMetadata/properties/receivedMessageDetails/required"},{"message":"$.metadata.encodings: is missing but it is required","jsonPath":"$.metadata","schemaPath":"#/$defs/OdeSpatMetadata/required"},{"message":"$.metadata.recordGeneratedBy: is missing but it is required","jsonPath":"$.metadata","schemaPath":"#/$defs/OdeSpatMetadata/required"},{"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.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.maxEndTime: 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":47,"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":"@ISO_DATE_TIME_OFFSET_MILLIS_700@","enabledLanes":[],"states":[{"signalGroup":1,"stateTimeSpeed":[{"eventState":"STOP_AND_REMAIN","timing":{"startTime":null,"minEndTime":"@OFFSET_SECONDS_78.41799998283386@","maxEndTime":"@OFFSET_SECONDS_78.41799998283386@","likelyTime":null,"confidence":null,"nextTime":null}}]},{"signalGroup":2,"stateTimeSpeed":[{"eventState":"STOP_AND_REMAIN","timing":{"startTime":null,"minEndTime":"@OFFSET_SECONDS_28.417999982833862@","maxEndTime":"@OFFSET_SECONDS_28.417999982833862@","likelyTime":null,"confidence":null,"nextTime":null}}]},{"signalGroup":3,"stateTimeSpeed":[{"eventState":"STOP_AND_REMAIN","timing":{"startTime":null,"minEndTime":"@OFFSET_SECONDS_98.41799998283386@","maxEndTime":"@OFFSET_SECONDS_98.41799998283386@","likelyTime":null,"confidence":null,"nextTime":null}}]},{"signalGroup":4,"stateTimeSpeed":[{"eventState":"PROTECTED_MOVEMENT_ALLOWED","timing":{"startTime":null,"minEndTime":"@OFFSET_SECONDS_14.217999935150146@","maxEndTime":"@OFFSET_SECONDS_22.217999935150146@","likelyTime":null,"confidence":null,"nextTime":null}}]},{"signalGroup":5,"stateTimeSpeed":[{"eventState":"STOP_AND_REMAIN","timing":{"startTime":null,"minEndTime":"@OFFSET_SECONDS_28.417999982833862@","maxEndTime":"@OFFSET_SECONDS_28.417999982833862@","likelyTime":null,"confidence":null,"nextTime":null}}]},{"signalGroup":6,"stateTimeSpeed":[{"eventState":"STOP_AND_REMAIN","timing":{"startTime":null,"minEndTime":"@OFFSET_SECONDS_58.41799998283386@","maxEndTime":"@OFFSET_SECONDS_58.41799998283386@","likelyTime":null,"confidence":null,"nextTime":null}}]},{"signalGroup":7,"stateTimeSpeed":[{"eventState":"PROTECTED_MOVEMENT_ALLOWED","timing":{"startTime":null,"minEndTime":"@OFFSET_SECONDS_3.118000030517578@","maxEndTime":"@OFFSET_SECONDS_22.51799988746643@","likelyTime":null,"confidence":null,"nextTime":null}}]},{"signalGroup":8,"stateTimeSpeed":[{"eventState":"STOP_AND_REMAIN","timing":{"startTime":null,"minEndTime":"@OFFSET_SECONDS_-0.0820000171661377@","maxEndTime":null,"likelyTime":null,"confidence":null,"nextTime":null}}]}]} diff --git a/jpo-conflictmonitor/scripts/IntegrationTestScripts/script-runner-cli.jar b/jpo-conflictmonitor/scripts/IntegrationTestScripts/script-runner-cli.jar index 2498779e..17c12eaf 100644 Binary files a/jpo-conflictmonitor/scripts/IntegrationTestScripts/script-runner-cli.jar and b/jpo-conflictmonitor/scripts/IntegrationTestScripts/script-runner-cli.jar differ diff --git a/jpo-conflictmonitor/scripts/monitor-topic.py b/jpo-conflictmonitor/scripts/monitor-topic.py new file mode 100644 index 00000000..b153aae6 --- /dev/null +++ b/jpo-conflictmonitor/scripts/monitor-topic.py @@ -0,0 +1,35 @@ +from kafka import KafkaConsumer + +bootstrap_servers = '172.250.250.130:9092' +#topic = "topic.OdeSpatJson" +#topic = "topic.OdeRawEncodedBSMJson" +#topic = "topic.OdeMapJson" +#topic = "topic.ProcessedMap" +#topic = "topic.DeduplicatedProcessedMap" +#topic = "topic.DeduplicatedOdeMapJson" +#topic = "topic.OdeTimJson" +#topic = "topic.OdeRawEncodedTIMJson" +#topic = "topic.OdeRawEncodedTIMJson" +#topic = "topic.DeduplicatedOdeTimJson" +#topic = "topic.ProcessedSpat" +#topic = "CmBsmEvents" +#topic = "topic.CmBsmEvents" +#topic = "topic.ProcessedMapWKT" +#topic = "topic.DeduplicatedProcessedMapWKT" +#topic = "topic.Asn1DecoderInput" +#topic = "topic.Asn1DecoderOutput" +#topic = "topic.OdeTimJson" +topic = "topic.DeduplicatedOdeBsmJson" +#topic = "topic.OdeTimJson" +#topic = "topic.OdeBsmJson" +#topic = "topic.OdePsmJson" +#topic = "topic.OdeSsmJson" +#topic = "topic.OdeSrmJson" + +consumer = KafkaConsumer(bootstrap_servers=bootstrap_servers) +consumer.subscribe(topic) +count = 0 +for message in consumer: + count +=1 + print(count,message) + print() 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 3a972ff1..39f129ec 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 @@ -46,6 +46,8 @@ import us.dot.its.jpo.conflictmonitor.monitor.algorithms.connection_of_travel.ConnectionOfTravelParameters; import us.dot.its.jpo.conflictmonitor.monitor.algorithms.connection_of_travel_assessment.ConnectionOfTravelAssessmentAlgorithmFactory; import us.dot.its.jpo.conflictmonitor.monitor.algorithms.connection_of_travel_assessment.ConnectionOfTravelAssessmentParameters; +import us.dot.its.jpo.conflictmonitor.monitor.algorithms.event.EventAlgorithmFactory; +import us.dot.its.jpo.conflictmonitor.monitor.algorithms.event.EventParameters; import us.dot.its.jpo.conflictmonitor.monitor.algorithms.intersection_event.IntersectionEventAlgorithmFactory; import us.dot.its.jpo.conflictmonitor.monitor.algorithms.lane_direction_of_travel.LaneDirectionOfTravelAlgorithmFactory; import us.dot.its.jpo.conflictmonitor.monitor.algorithms.lane_direction_of_travel.LaneDirectionOfTravelParameters; @@ -59,6 +61,12 @@ 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_revision_counter.MapRevisionCounterAlgorithmFactory; +import us.dot.its.jpo.conflictmonitor.monitor.algorithms.map_revision_counter.MapRevisionCounterParameters; +import us.dot.its.jpo.conflictmonitor.monitor.algorithms.spat_revision_counter.SpatRevisionCounterAlgorithmFactory; +import us.dot.its.jpo.conflictmonitor.monitor.algorithms.spat_revision_counter.SpatRevisionCounterParameters; +import us.dot.its.jpo.conflictmonitor.monitor.algorithms.bsm_revision_counter.BsmRevisionCounterAlgorithmFactory; +import us.dot.its.jpo.conflictmonitor.monitor.algorithms.bsm_revision_counter.BsmRevisionCounterParameters; import us.dot.its.jpo.conflictmonitor.monitor.algorithms.stop_line_passage.StopLinePassageAlgorithmFactory; import us.dot.its.jpo.conflictmonitor.monitor.algorithms.stop_line_passage.StopLinePassageParameters; import us.dot.its.jpo.conflictmonitor.monitor.algorithms.stop_line_passage_assessment.StopLinePassageAssessmentAlgorithmFactory; @@ -71,6 +79,11 @@ import us.dot.its.jpo.conflictmonitor.monitor.algorithms.time_change_details.map.MapTimeChangeDetailsParameters; import us.dot.its.jpo.conflictmonitor.monitor.algorithms.time_change_details.spat.SpatTimeChangeDetailsAlgorithmFactory; import us.dot.its.jpo.conflictmonitor.monitor.algorithms.time_change_details.spat.SpatTimeChangeDetailsParameters; +import us.dot.its.jpo.conflictmonitor.monitor.algorithms.timestamp_delta.map.MapTimestampDeltaAlgorithm; +import us.dot.its.jpo.conflictmonitor.monitor.algorithms.timestamp_delta.map.MapTimestampDeltaAlgorithmFactory; +import us.dot.its.jpo.conflictmonitor.monitor.algorithms.timestamp_delta.map.MapTimestampDeltaParameters; +import us.dot.its.jpo.conflictmonitor.monitor.algorithms.timestamp_delta.spat.SpatTimestampDeltaAlgorithmFactory; +import us.dot.its.jpo.conflictmonitor.monitor.algorithms.timestamp_delta.spat.SpatTimestampDeltaParameters; import us.dot.its.jpo.conflictmonitor.monitor.algorithms.validation.map.MapValidationAlgorithmFactory; import us.dot.its.jpo.conflictmonitor.monitor.algorithms.validation.map.MapValidationParameters; import us.dot.its.jpo.conflictmonitor.monitor.algorithms.validation.spat.SpatValidationParameters; @@ -96,6 +109,13 @@ public class ConflictMonitorProperties implements EnvironmentAware { private SpatValidationParameters spatValidationParameters; private MapValidationParameters mapValidationParameters; + private String mapTimestampDeltaAlgorithm; + private MapTimestampDeltaParameters mapTimestampDeltaParameters; + private MapTimestampDeltaAlgorithmFactory mapTimestampDeltaAlgorithmFactory; + + private String spatTimestampDeltaAlgorithm; + private SpatTimestampDeltaParameters spatTimestampDeltaParameters; + private SpatTimestampDeltaAlgorithmFactory spatTimestampDeltaAlgorithmFactory; private LaneDirectionOfTravelAlgorithmFactory laneDirectionOfTravelAlgorithmFactory; private String laneDirectionOfTravelAlgorithm; @@ -147,10 +167,26 @@ public class ConflictMonitorProperties implements EnvironmentAware { private String repartitionAlgorithm; private RepartitionParameters repartitionAlgorithmParameters; + private MapRevisionCounterAlgorithmFactory mapRevisionCounterAlgorithmFactory; + private String mapRevisionCounterAlgorithm; + private MapRevisionCounterParameters mapRevisionCounterAlgorithmParameters; + + private SpatRevisionCounterAlgorithmFactory spatRevisionCounterAlgorithmFactory; + private String spatRevisionCounterAlgorithm; + private SpatRevisionCounterParameters spatRevisionCounterAlgorithmParameters; + + private BsmRevisionCounterAlgorithmFactory bsmRevisionCounterAlgorithmFactory; + private String bsmRevisionCounterAlgorithm; + private BsmRevisionCounterParameters bsmRevisionCounterAlgorithmParameters; + private NotificationAlgorithmFactory notificationAlgorithmFactory; private String notificationAlgorithm; private NotificationParameters notificationAlgorithmParameters; + private EventAlgorithmFactory eventAlgorithmFactory; + private String eventAlgorithm; + private EventParameters eventParameters; + // Confluent Properties private boolean confluentCloudEnabled = false; private String confluentKey = null; @@ -217,6 +253,31 @@ public void setSpatValidationAlgorithm(String spatBroadcastRateAlgorithm) { } + @Autowired + public void setMapTimestampDeltaParameters(MapTimestampDeltaParameters mapTimestampDeltaParameters) { + this.mapTimestampDeltaParameters = mapTimestampDeltaParameters; + this.mapTimestampDeltaAlgorithm = mapTimestampDeltaParameters.getAlgorithm(); + } + + + @Autowired + public void setMapTimestampDeltaAlgorithmFactory(MapTimestampDeltaAlgorithmFactory factory) { + this.mapTimestampDeltaAlgorithmFactory = factory; + } + + + @Autowired + public void setSpatTimestampDeltaParameters(SpatTimestampDeltaParameters spatTimestampDeltaParameters) { + this.spatTimestampDeltaParameters = spatTimestampDeltaParameters; + this.spatTimestampDeltaAlgorithm = spatTimestampDeltaParameters.getAlgorithm(); + } + + @Autowired + public void setSpatTimestampDeltaAlgorithmFactory(SpatTimestampDeltaAlgorithmFactory factory) { + this.spatTimestampDeltaAlgorithmFactory = factory; + } + + @Autowired @@ -492,6 +553,56 @@ public void setRepartitionAlgorithmParameters(RepartitionParameters repartitionA this.repartitionAlgorithmParameters = repartitionAlgorithmParameters; } + + @Autowired + public void setMapRevisionCounterAlgorithmFactory(MapRevisionCounterAlgorithmFactory mapRevisionCounterAlgorithmFactory) { + this.mapRevisionCounterAlgorithmFactory = mapRevisionCounterAlgorithmFactory; + } + + @Value("${map.revision.counter.algorithm}") + public void setMapRevisionCorrectionAlgorithm(String mapRevisionCounterAlgorithm) { + this.mapRevisionCounterAlgorithm = mapRevisionCounterAlgorithm; + } + + @Autowired + public void setMapRevisionCounterAlgorithmParameters(MapRevisionCounterParameters mapRevisionCounterAlgorithmParameters) { + this.mapRevisionCounterAlgorithmParameters = mapRevisionCounterAlgorithmParameters; + } + + + + @Autowired + public void setSpatRevisionCounterAlgorithmFactory(SpatRevisionCounterAlgorithmFactory spatRevisionCounterAlgorithmFactory) { + this.spatRevisionCounterAlgorithmFactory = spatRevisionCounterAlgorithmFactory; + } + + @Value("${spat.revision.counter.algorithm}") + public void setSpatRevisionCorrectionAlgorithm(String spatRevisionCounterAlgorithm) { + this.spatRevisionCounterAlgorithm = spatRevisionCounterAlgorithm; + } + + @Autowired + public void setSpatRevisionCounterAlgorithmParameters(SpatRevisionCounterParameters spatRevisionCounterAlgorithmParameters) { + this.spatRevisionCounterAlgorithmParameters = spatRevisionCounterAlgorithmParameters; + } + + + @Autowired + public void setBsmRevisionCounterAlgorithmFactory(BsmRevisionCounterAlgorithmFactory bsmRevisionCounterAlgorithmFactory) { + this.bsmRevisionCounterAlgorithmFactory = bsmRevisionCounterAlgorithmFactory; + } + + @Value("${bsm.revision.counter.algorithm}") + public void setBsmRevisionCorrectionAlgorithm(String bsmRevisionCounterAlgorithm) { + this.bsmRevisionCounterAlgorithm = bsmRevisionCounterAlgorithm; + } + + @Autowired + public void setBsmRevisionCounterAlgorithmParameters(BsmRevisionCounterParameters bsmRevisionCounterAlgorithmParameters) { + this.bsmRevisionCounterAlgorithmParameters = bsmRevisionCounterAlgorithmParameters; + } + + public NotificationAlgorithmFactory getNotificationAlgorithmFactory() { return notificationAlgorithmFactory; } @@ -522,6 +633,17 @@ public void setNotificationAlgorithmParameters(NotificationParameters notificati this.notificationAlgorithmParameters = notificationAlgorithmParameters; } + @Autowired + public void setEventParameters(EventParameters eventParameters) { + this.eventParameters = eventParameters; + this.eventAlgorithm = eventParameters.getAlgorithm(); + } + + @Autowired + public void setEventAlgorithmFactory(EventAlgorithmFactory factory) { + this.eventAlgorithmFactory = factory; + } + public Boolean getConfluentCloudStatus() { return confluentCloudEnabled; } 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 0592454c..4d942985 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 @@ -3,15 +3,15 @@ import java.time.Instant; import java.time.ZoneOffset; import java.time.format.DateTimeFormatter; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.TreeMap; +import java.util.*; import java.util.stream.Collectors; +import jakarta.servlet.http.HttpServletRequest; import org.apache.kafka.common.MetricName; import org.apache.kafka.streams.KafkaStreams; import org.apache.kafka.streams.KafkaStreams.State; +import org.apache.kafka.streams.Topology; +import org.apache.kafka.streams.TopologyDescription; import org.apache.kafka.streams.kstream.Windowed; import org.locationtech.jts.index.quadtree.Quadtree; import org.slf4j.Logger; @@ -23,11 +23,7 @@ import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.kafka.core.KafkaAdmin; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.ResponseBody; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; import org.springframework.web.client.RestTemplate; import org.springframework.web.servlet.support.ServletUriComponentsBuilder; @@ -43,8 +39,10 @@ import us.dot.its.jpo.conflictmonitor.monitor.algorithms.AlgorithmParameters; import us.dot.its.jpo.conflictmonitor.monitor.algorithms.StreamsTopology; import us.dot.its.jpo.conflictmonitor.monitor.algorithms.config.ConfigParameters; +import us.dot.its.jpo.conflictmonitor.monitor.health.TopologyGraph; 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.DefaultConfigMap; +import us.dot.its.jpo.conflictmonitor.monitor.models.config.IntersectionConfigMap; import us.dot.its.jpo.conflictmonitor.monitor.models.map.MapIndex; import us.dot.its.jpo.conflictmonitor.monitor.topologies.config.ConfigTopology; import us.dot.its.jpo.conflictmonitor.monitor.topologies.IntersectionEventTopology; @@ -55,6 +53,9 @@ import us.dot.its.jpo.geojsonconverter.pojos.spat.ProcessedSpat; import us.dot.its.jpo.ode.model.OdeBsmData; +import javax.ws.rs.Produces; + + @Getter @Setter @RestController @@ -96,25 +97,24 @@ public List parameterObjects() { } @GetMapping - public @ResponseBody ResponseEntity summary() { - try { - var linkMap = new TreeMap(); - addLinks(linkMap, - "config/default" - ,"config/intersection", - "topics", - "properties", - "streams", - "connectors", - "spatial-indexes", - "spat-window-store", - "bsm-window-store", - "map-store" - ); - return getJsonResponse(linkMap); - } catch (Exception ex) { - return getErrorJson(ex); - } + public @ResponseBody ResponseEntity summary() { + + var linkMap = new TreeMap(); + addLinks(linkMap, + "config/default" + ,"config/intersection", + "topics", + "properties", + "streams", + "connectors", + "spatial-indexes", + "spat-window-store", + "bsm-window-store", + "map-store", + "topologies" + ); + return getResponse(linkMap); + } private void addLinks(Map map, String... paths) { @@ -125,21 +125,15 @@ private void addLinks(Map map, String... paths) { } @GetMapping(value = "/config/default") - public @ResponseBody ResponseEntity listDefaultConfig() { - try { - return getJsonResponse(configTopology.mapDefaultConfigs()); - } catch (Exception ex) { - return getErrorJson(ex); - } + public @ResponseBody ResponseEntity listDefaultConfig() { + + return getResponse(configTopology.mapDefaultConfigs()); + } @GetMapping(value = "/config/intersection") - public @ResponseBody ResponseEntity listIntersectionConfig() { - try { - return getJsonResponse(configTopology.mapIntersectionConfigs()); - } catch (Exception ex) { - return getErrorJson(ex); - } + public @ResponseBody ResponseEntity listIntersectionConfig() { + return getResponse(configTopology.mapIntersectionConfigs()); } @@ -147,47 +141,40 @@ private void addLinks(Map map, String... paths) { * @return JSON map of kafka topics created by this app that currently exist */ @GetMapping(value = "/topics") - public @ResponseBody ResponseEntity listTopics() { - try { - var existingTopics = new TreeMap(); - - var topicNames = kafkaConfiguration.getCreateTopics().stream() - .filter(topic -> topic.keySet().contains("name")) - .map(topic -> (String)topic.get("name")) - .collect(Collectors.toUnmodifiableList()); + public @ResponseBody ResponseEntity> listTopics() { - var topicDescMap = kafkaAdmin.describeTopics(topicNames.toArray(new String[0])); + var existingTopics = new TreeMap(); - for (var entry : topicDescMap.entrySet()) { - existingTopics.put(entry.getKey(), entry.getValue().toString()); - } + var topicNames = kafkaConfiguration.getCreateTopics().stream() + .filter(topic -> topic.keySet().contains("name")) + .map(topic -> (String)topic.get("name")) + .collect(Collectors.toUnmodifiableList()); + + var topicDescMap = kafkaAdmin.describeTopics(topicNames.toArray(new String[0])); - return getJsonResponse(existingTopics); - } catch (Exception ex) { - return getErrorJson(ex); + for (var entry : topicDescMap.entrySet()) { + existingTopics.put(entry.getKey(), entry.getValue().toString()); } + + return getResponse(existingTopics); + } @GetMapping(value = "/properties") - public @ResponseBody ResponseEntity listProperties() { - try { - var propMap = new TreeMap(); - - for (var params : parameterObjects()) { - propMap.put(params.getClass().getSimpleName(), params); - } - - return getJsonResponse(propMap); - } catch (Exception ex) { - logger.error("Error listing properties", ex); - return getErrorJson(ex); + public @ResponseBody ResponseEntity> listProperties() { + var propMap = new TreeMap(); + + for (var params : parameterObjects()) { + propMap.put(params.getClass().getSimpleName(), params); } + + return getResponse(propMap); } @GetMapping(value = "/streams") - public @ResponseBody ResponseEntity listStreams() { + public @ResponseBody ResponseEntity listStreams() { var streamsMap = getKafkaStreamsMap(); String baseUrl = baseUrl(); var result = new StreamsInfoMap(); @@ -205,20 +192,70 @@ private void addLinks(Map map, String... paths) { streamsInfo.setState(state != null ? state : null); } - return getJsonResponse(result); + return getResponse(result); } + @GetMapping(value = "/topologies") + public @ResponseBody ResponseEntity> listTopologies() { + var topoMap = getTopologies(); + String baseUrl = baseUrl(); + var result = new TreeMap(); + for (Map.Entry entry : topoMap.entrySet()) { + String name = entry.getKey(); + String detailUrl = String.format("%s/health/topologies/detail/%s", baseUrl, name); + String simpleGraphUrl = String.format("%s/health/topologies/simple/%s", baseUrl, name); + result.put(name, new TopologyInfoLinks(detailUrl, simpleGraphUrl)); + } + String allUrl = String.format("%s/health/topologies/simple/all", baseUrl); + result.put("all", new TopologyInfoLinks("n/a", allUrl)); + return getResponse(result); + } + + @GetMapping(value = "/topologies/detail/{name}") + @Produces(MediaType.TEXT_PLAIN_VALUE) + public @ResponseBody ResponseEntity topologyDetails(@PathVariable String name) { + var topoMap = getTopologies(); + if (!topoMap.containsKey(name)) { + throw new RuntimeException("The topology map doesn't contain an object named " + name); + } + Topology topology = topoMap.get(name); + TopologyDescription description = topology.describe(); + return ResponseEntity.ok().contentType(MediaType.TEXT_PLAIN).body(description.toString()); + } + + @GetMapping(value = "/topologies/simple/{name}") + @Produces(MediaType.TEXT_PLAIN_VALUE) + public @ResponseBody ResponseEntity topologySimpleGraph(@PathVariable String name) { + TopologyGraph graph; + var topoMap = getTopologies(); + if ("all".equals(name)) { + graph = new TopologyGraph(topoMap); + } else { + if (!topoMap.containsKey(name)) { + throw new RuntimeException("The topology map doesn't contain an object named " + name); + } + Topology topology = topoMap.get(name); + graph = new TopologyGraph(name, topology); + } + return ResponseEntity.ok() + .contentType(MediaType.TEXT_PLAIN) + .header("Content-Disposition", String.format("inline; filename=\"%s.dot\"", name)) + .body(graph.exportDOT()); + } + + + @GetMapping(value = "/streams/{name}") - public @ResponseBody ResponseEntity namedStreams(@PathVariable String name) { + public @ResponseBody ResponseEntity namedStreams(@PathVariable String name) { Map streamsMap = getKafkaStreamsMap(); if (streamsMap == null) - return getOKResponse("The streams map is null."); + throw new RuntimeException("The streams map is null."); if (!streamsMap.containsKey(name)) - return getOKResponse("The streams map doesn't contain an object named " + name); + throw new RuntimeException("The streams map doesn't contain an object named " + name); KafkaStreams streams = streamsMap.get(name); if (streams == null) - return getOKResponse("The KafkaStreams object is null"); + throw new RuntimeException("The KafkaStreams object is null"); var metrics = streams.metrics(); @@ -237,7 +274,7 @@ private void addLinks(Map map, String... paths) { var metricValue = metric.metricValue(); group.put(metricName.name(), metricValue); } - return getJsonResponse(result); + return getResponse(result); } @@ -251,18 +288,18 @@ private void addLinks(Map map, String... paths) { } @GetMapping(value = "/spatial-indexes") - public @ResponseBody ResponseEntity spatial() { + public @ResponseBody ResponseEntity spatial() { if (mapIndex == null) { - return getOKResponse("The map index is null"); + throw new RuntimeException("The map index is null"); } Quadtree quadtree = mapIndex.getQuadtree(); var allItems = quadtree.queryAll(); - return getJsonResponse(allItems); + return getResponse(allItems); } @GetMapping(value = "/map-store") - public @ResponseBody ResponseEntity mapStore() { + public @ResponseBody ResponseEntity>> mapStore() { var mapStore = intersectionEventTopology.getMapStore(); var mapMap = new TreeMap>(); try (var mapIterator = mapStore.all()) { @@ -273,11 +310,11 @@ private void addLinks(Map map, String... paths) { mapMap.put(key.toString(), map); } } - return getJsonResponse(mapMap); + return getResponse(mapMap); } @GetMapping(value = "/spat-window-store") - public @ResponseBody ResponseEntity spatWindowStore() { + public @ResponseBody ResponseEntity spatWindowStore() { var spatWindowStore = intersectionEventTopology.getSpatWindowStore(); var intersectionMap = new IntersectionSpatMap(); var formatter = DateTimeFormatter.ISO_DATE_TIME; @@ -308,11 +345,11 @@ private void addLinks(Map map, String... paths) { spatList.put(theKey.toString(), value); } } - return getJsonResponse(intersectionMap); + return getResponse(intersectionMap); } @GetMapping(value = "/bsm-window-store") - public @ResponseBody ResponseEntity bsmWindowStore() { + public @ResponseBody ResponseEntity bsmWindowStore() { var bsmWindowStore = intersectionEventTopology.getBsmWindowStore(); var intersectionMap = new IntersectionBsm(); var formatter = DateTimeFormatter.ISO_DATE_TIME; @@ -344,7 +381,7 @@ private void addLinks(Map map, String... paths) { bsmList.put(theKey.toString(), value); } } - return getJsonResponse(intersectionMap); + return getResponse(intersectionMap); } private Map getKafkaStreamsMap() { @@ -352,9 +389,6 @@ private Map getKafkaStreamsMap() { var streamsMap = new TreeMap(); - // Streams not part of an algorithm - streamsMap.putAll(monitorServiceController.getStreamsMap()); - // Algorithm streams for (String key : monitorServiceController.getAlgoMap().keySet()) { var algorithm = monitorServiceController.getAlgoMap().get(key); @@ -366,29 +400,38 @@ private Map getKafkaStreamsMap() { return streamsMap; } - private ResponseEntity getOKResponse(String message) { - return ResponseEntity.status(HttpStatus.OK).contentType(MediaType.TEXT_PLAIN).body(message); + private Map getTopologies() { + var topoMap = new TreeMap(); + for (Map.Entry algoEntry : monitorServiceController.getAlgoMap().entrySet()) { + String key = algoEntry.getKey(); + StreamsTopology streamsTopology = algoEntry.getValue(); + Topology topology = streamsTopology.getTopology(); + if (topology != null) { + topoMap.put(key, topology); + logger.error("Topology is not created in {}", streamsTopology); + } + } + return topoMap; } - private ResponseEntity getJsonResponse(Object message) { - String json; - try { - json = mapper.writeValueAsString(message); - } catch (JsonProcessingException jpe) { - logger.error("Error converting to JSON", jpe); - return getErrorJson(jpe); - } - return ResponseEntity.status(HttpStatus.OK).contentType(MediaType.APPLICATION_JSON).body(json); + + + + + + private ResponseEntity getResponse(T message) { + return ResponseEntity.status(HttpStatus.OK).contentType(MediaType.APPLICATION_JSON).body(message); } - private ResponseEntity getErrorJson(Exception ex) { - var errMap = Map.of("error", ex.getMessage()); + @ExceptionHandler(Exception.class) + private ResponseEntity getErrorJson(HttpServletRequest request, Exception ex) { try { + var errMap = Map.of("error", ex.getMessage()); String errJson = mapper.writeValueAsString(errMap); return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).contentType(MediaType.APPLICATION_JSON).body(errJson); - } catch (JsonProcessingException e) { - logger.error("Error converting to JSON", e); - return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).contentType(MediaType.APPLICATION_JSON).body("{ \"error\": \"error\" }"); + } catch (Exception e) { + logger.error("Exception in exception handler", e); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).contentType(MediaType.APPLICATION_JSON).body("{ \"error\": \"unknown error\" }"); } } @@ -417,5 +460,6 @@ public class IntersectionSpatMap extends TreeMap>> {} + public record TopologyInfoLinks(String detailsUrl, String simpleGraphUrl) {} } diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/ConfigController.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/ConfigController.java index cba1d9aa..b021d115 100644 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/ConfigController.java +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/ConfigController.java @@ -13,10 +13,19 @@ import org.springframework.context.annotation.Profile; import us.dot.its.jpo.conflictmonitor.monitor.algorithms.config.ConfigAlgorithm; import us.dot.its.jpo.conflictmonitor.monitor.algorithms.config.ConfigUpdateResult; -import us.dot.its.jpo.conflictmonitor.monitor.models.config.*; +import us.dot.its.jpo.conflictmonitor.monitor.models.concurrent_permissive.ConnectedLanesPair; +import us.dot.its.jpo.conflictmonitor.monitor.models.concurrent_permissive.ConnectedLanesPairList; +import us.dot.its.jpo.conflictmonitor.monitor.models.config.ConfigException; +import us.dot.its.jpo.conflictmonitor.monitor.models.config.DefaultConfig; +import us.dot.its.jpo.conflictmonitor.monitor.models.config.DefaultConfigMap; +import us.dot.its.jpo.conflictmonitor.monitor.models.config.IntersectionConfig; +import us.dot.its.jpo.conflictmonitor.monitor.models.config.IntersectionConfigKey; +import us.dot.its.jpo.conflictmonitor.monitor.models.config.IntersectionConfigMap; import us.dot.its.jpo.conflictmonitor.monitor.topologies.config.ConfigTopology; +import java.util.ArrayList; import java.util.Formatter; +import java.util.Map; import java.util.Optional; import java.util.stream.Collectors; @@ -47,7 +56,7 @@ public ConfigController(ConfigTopology configAlgorithm) { var prefix = optionalPrefix.get(); var filteredMap = configMap.entrySet().stream() .filter(entry -> entry.getKey().startsWith(prefix)) - .collect(Collectors.toMap(entry -> entry.getKey(), entry -> entry.getValue())); + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); return ResponseEntity.ok(new DefaultConfigMap(filteredMap)); } else { return ResponseEntity.ok(new DefaultConfigMap(configMap)); @@ -121,10 +130,11 @@ public ConfigController(ConfigTopology configAlgorithm) { } @PostMapping(value = "default/{key}") + @SuppressWarnings("unchecked") public @ResponseBody ResponseEntity> saveDefaultConfig( @PathVariable(name = "key") String key, @RequestBody DefaultConfig config) { - ConfigUpdateResult updateResult = new ConfigUpdateResult(); + ConfigUpdateResult updateResult = new ConfigUpdateResult<>(); try { @@ -172,21 +182,22 @@ public ConfigController(ConfigTopology configAlgorithm) { @PathVariable(name = "region") int region, @PathVariable(name = "intersectionId") int intersectionId, @PathVariable(name = "key") String key) { - return deleteIntersectionConfigHelper(region, intersectionId, key, true); + return deleteIntersectionConfigHelper(region, intersectionId, key); } @DeleteMapping(value = "intersection/{intersectionId}/{key}") public @ResponseBody ResponseEntity> deleteIntersectionConfig( @PathVariable(name = "intersectionId") int intersectionId, @PathVariable(name = "key") String key) { - return deleteIntersectionConfigHelper(-1, intersectionId, key, false); + return deleteIntersectionConfigHelper(-1, intersectionId, key); } + @SuppressWarnings("unchecked") private ResponseEntity> saveIntersectionConfigHelper( int region, int intersectionId, String key, IntersectionConfig config, boolean useRegion) { - ConfigUpdateResult updateResult = new ConfigUpdateResult(); - try (var errMsg = new Formatter();) { + ConfigUpdateResult updateResult = new ConfigUpdateResult<>(); + try (var errMsg = new Formatter()) { // Validate path keys if (!key.equals(config.getKey())) { @@ -204,7 +215,17 @@ private ResponseEntity> saveIntersectionConfigHelper( if (intersectionId != config.getIntersectionID()) { errMsg.format("IntersectionID in path does not match body property %s != %s%n", intersectionId, config.getIntersectionID()); } - if (errMsg.toString().length() > 0) { + + // Validate Concurrent Permissive + logger.info("Type = {}", config.getType()); + if (ConnectedLanesPairList.class.getName().equals(config.getType())) { + ConnectedLanesPairList connectedLanesPairs = new ConnectedLanesPairList((ArrayList)config.getValue()); + validateConcurrentPermissive(connectedLanesPairs, intersectionId, region, useRegion, errMsg); + config.setValue((T)connectedLanesPairs); + logger.info("Updated config: {}", config); + } + + if (!errMsg.toString().isEmpty()) { var msg = errMsg.toString(); logger.error(msg); updateResult.setResult(ConfigUpdateResult.Result.ERROR); @@ -213,6 +234,7 @@ private ResponseEntity> saveIntersectionConfigHelper( } updateResult = configAlgorithm.updateIntersectionConfig(config); + logger.info("Update Result ==> {}", updateResult); return ResponseEntity.ok(updateResult); } catch (ConfigException ce) { @@ -227,8 +249,37 @@ private ResponseEntity> saveIntersectionConfigHelper( } + + private void validateConcurrentPermissive(ConnectedLanesPairList connectedLanesPairs, int intersectionId, int region, boolean useRegion, Formatter errMsg) { + // Check that each ConnectedLanesPair in the list has matching intersection ID and region, or + // set them from the path if missing. + for (ConnectedLanesPair connectedLanesPair : connectedLanesPairs) { + Integer lanesIntersectionID = connectedLanesPair.getIntersectionID(); + Integer lanesRegion = connectedLanesPair.getRoadRegulatorID(); + + if (lanesIntersectionID == null) { + connectedLanesPair.setIntersectionID(intersectionId); + } else if (lanesIntersectionID != intersectionId) { + errMsg.format("IntersectionID in path, %s, does not match one of the items: %s%n", intersectionId, connectedLanesPair); + } + + if (useRegion) { + if (lanesRegion == null) { + connectedLanesPair.setRoadRegulatorID(region); + } else if (lanesRegion != region) { + errMsg.format("Region in path, %s, does not match road regulator ID in one of the items: %s%n", region, connectedLanesPair); + } + } else { + if (lanesRegion != null && lanesRegion != -1) { + errMsg.format("Region is not specified in URL path, but RoadRegulatorID is set to a value other than null or -1 in an item: %s%n", connectedLanesPair); + } + } + } + } + + @SuppressWarnings("unchecked") private ResponseEntity> deleteIntersectionConfigHelper( - int region, int intersectionId, String key, boolean useRegion) { + int region, int intersectionId, String key) { var updateResult = new ConfigUpdateResult(); try { 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 1acab6b9..9795af32 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 @@ -2,6 +2,7 @@ import lombok.Getter; import org.apache.kafka.streams.KafkaStreams; +import org.apache.kafka.streams.Topology; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -12,6 +13,7 @@ import us.dot.its.jpo.conflictmonitor.ConflictMonitorProperties; import us.dot.its.jpo.conflictmonitor.StateChangeHandler; import us.dot.its.jpo.conflictmonitor.StreamsExceptionHandler; +import us.dot.its.jpo.conflictmonitor.monitor.algorithms.Algorithm; import us.dot.its.jpo.conflictmonitor.monitor.algorithms.StreamsTopology; import us.dot.its.jpo.conflictmonitor.monitor.algorithms.bsm_event.BsmEventAlgorithm; import us.dot.its.jpo.conflictmonitor.monitor.algorithms.bsm_event.BsmEventAlgorithmFactory; @@ -23,6 +25,9 @@ import us.dot.its.jpo.conflictmonitor.monitor.algorithms.connection_of_travel_assessment.ConnectionOfTravelAssessmentAlgorithm; import us.dot.its.jpo.conflictmonitor.monitor.algorithms.connection_of_travel_assessment.ConnectionOfTravelAssessmentAlgorithmFactory; import us.dot.its.jpo.conflictmonitor.monitor.algorithms.connection_of_travel_assessment.ConnectionOfTravelAssessmentParameters; +import us.dot.its.jpo.conflictmonitor.monitor.algorithms.event.EventAlgorithm; +import us.dot.its.jpo.conflictmonitor.monitor.algorithms.event.EventAlgorithmFactory; +import us.dot.its.jpo.conflictmonitor.monitor.algorithms.event.EventParameters; import us.dot.its.jpo.conflictmonitor.monitor.algorithms.intersection_event.IntersectionEventAlgorithm; import us.dot.its.jpo.conflictmonitor.monitor.algorithms.intersection_event.IntersectionEventAlgorithmFactory; import us.dot.its.jpo.conflictmonitor.monitor.algorithms.intersection_event.IntersectionEventStreamsAlgorithm; @@ -59,6 +64,20 @@ import us.dot.its.jpo.conflictmonitor.monitor.algorithms.time_change_details.spat.SpatTimeChangeDetailsAlgorithm; import us.dot.its.jpo.conflictmonitor.monitor.algorithms.time_change_details.spat.SpatTimeChangeDetailsAlgorithmFactory; import us.dot.its.jpo.conflictmonitor.monitor.algorithms.time_change_details.spat.SpatTimeChangeDetailsParameters; +import us.dot.its.jpo.conflictmonitor.monitor.algorithms.map_revision_counter.MapRevisionCounterAlgorithm; +import us.dot.its.jpo.conflictmonitor.monitor.algorithms.map_revision_counter.MapRevisionCounterAlgorithmFactory; +import us.dot.its.jpo.conflictmonitor.monitor.algorithms.map_revision_counter.MapRevisionCounterParameters; +import us.dot.its.jpo.conflictmonitor.monitor.algorithms.spat_revision_counter.SpatRevisionCounterAlgorithm; +import us.dot.its.jpo.conflictmonitor.monitor.algorithms.spat_revision_counter.SpatRevisionCounterAlgorithmFactory; +import us.dot.its.jpo.conflictmonitor.monitor.algorithms.spat_revision_counter.SpatRevisionCounterParameters; +import us.dot.its.jpo.conflictmonitor.monitor.algorithms.bsm_revision_counter.BsmRevisionCounterAlgorithm; +import us.dot.its.jpo.conflictmonitor.monitor.algorithms.bsm_revision_counter.BsmRevisionCounterAlgorithmFactory; +import us.dot.its.jpo.conflictmonitor.monitor.algorithms.bsm_revision_counter.BsmRevisionCounterParameters; +import us.dot.its.jpo.conflictmonitor.monitor.algorithms.timestamp_delta.map.MapTimestampDeltaAlgorithm; +import us.dot.its.jpo.conflictmonitor.monitor.algorithms.timestamp_delta.map.MapTimestampDeltaAlgorithmFactory; +import us.dot.its.jpo.conflictmonitor.monitor.algorithms.timestamp_delta.map.MapTimestampDeltaParameters; +import us.dot.its.jpo.conflictmonitor.monitor.algorithms.timestamp_delta.spat.SpatTimestampDeltaAlgorithm; +import us.dot.its.jpo.conflictmonitor.monitor.algorithms.timestamp_delta.spat.SpatTimestampDeltaAlgorithmFactory; import us.dot.its.jpo.conflictmonitor.monitor.algorithms.validation.map.MapValidationAlgorithm; import us.dot.its.jpo.conflictmonitor.monitor.algorithms.validation.map.MapValidationAlgorithmFactory; import us.dot.its.jpo.conflictmonitor.monitor.algorithms.validation.map.MapValidationParameters; @@ -69,6 +88,7 @@ import us.dot.its.jpo.conflictmonitor.monitor.topologies.config.ConfigInitializer; import us.dot.its.jpo.conflictmonitor.monitor.topologies.config.ConfigTopology; +import java.util.Map; import java.util.concurrent.ConcurrentHashMap; /** @@ -82,14 +102,13 @@ public class MonitorServiceController { private static final Logger logger = LoggerFactory.getLogger(MonitorServiceController.class); org.apache.kafka.common.serialization.Serdes bas; - // Temporary for KafkaStreams that don't implement the Algorithm interface - @Getter - final ConcurrentHashMap streamsMap = new ConcurrentHashMap(); +// // Temporary for KafkaStreams that don't implement the Algorithm interface +// @Getter +// final ConcurrentHashMap streamsMap = new ConcurrentHashMap(); @Getter final ConcurrentHashMap algoMap = new ConcurrentHashMap(); - @Autowired public MonitorServiceController(final ConflictMonitorProperties conflictMonitorProps, @@ -118,8 +137,6 @@ public MonitorServiceController(final ConflictMonitorProperties conflictMonitorP Runtime.getRuntime().addShutdownHook(new Thread(configTopology::stop)); configTopology.setKafkaTemplate(kafkaTemplate); configTopology.start(); - - final String repartition = "repartition"; @@ -158,46 +175,48 @@ public MonitorServiceController(final ConflictMonitorProperties conflictMonitorP notificationAlgo.start(); - // Map Broadcast Rate Topology - // Sends "MAP Broadcast Rate" events when the number of MAPs per rolling period is too low or too high - final String mapBroadcastRate = "mapBroadcastRate"; + // Map Validation Topology + final String mapValidation = "mapValidation"; final MapValidationAlgorithmFactory mapAlgoFactory = conflictMonitorProps.getMapValidationAlgorithmFactory(); final String mapAlgo = conflictMonitorProps.getMapValidationAlgorithm(); - final MapValidationAlgorithm mapCountAlgo = mapAlgoFactory.getAlgorithm(mapAlgo); - final MapValidationParameters mapCountParams = conflictMonitorProps.getMapValidationParameters(); - configTopology.registerConfigListeners(mapCountParams); - logger.info("Map params {}", mapCountParams); - if (mapCountAlgo instanceof StreamsTopology) { - final var streamsAlgo = (StreamsTopology)mapCountAlgo; - streamsAlgo.setStreamsProperties(conflictMonitorProps.createStreamProperties(mapBroadcastRate)); - streamsAlgo.registerStateListener(new StateChangeHandler(kafkaTemplate, mapBroadcastRate, stateChangeTopic, healthTopic)); - streamsAlgo.registerUncaughtExceptionHandler(new StreamsExceptionHandler(kafkaTemplate, mapBroadcastRate, healthTopic)); - algoMap.put(mapBroadcastRate, streamsAlgo); + final MapValidationAlgorithm mapValidationAlgo = mapAlgoFactory.getAlgorithm(mapAlgo); + final MapValidationParameters mapValidationParams = conflictMonitorProps.getMapValidationParameters(); + configTopology.registerConfigListeners(mapValidationParams); + logger.info("Map params {}", mapValidationParams); + if (mapValidationAlgo instanceof StreamsTopology streamsAlgo) { + streamsAlgo.setStreamsProperties(conflictMonitorProps.createStreamProperties(mapValidation)); + streamsAlgo.registerStateListener(new StateChangeHandler(kafkaTemplate, mapValidation, stateChangeTopic, healthTopic)); + streamsAlgo.registerUncaughtExceptionHandler(new StreamsExceptionHandler(kafkaTemplate, mapValidation, healthTopic)); + algoMap.put(mapValidation, streamsAlgo); } - mapCountAlgo.setParameters(mapCountParams); - Runtime.getRuntime().addShutdownHook(new Thread(mapCountAlgo::stop)); - mapCountAlgo.start(); + mapValidationAlgo.setParameters(mapValidationParams); + // Plugin timestamp delta algorithm + final MapTimestampDeltaAlgorithm mapTimestampAlgo = getMapTimestampDeltaAlgorithm(conflictMonitorProps); + mapValidationAlgo.setTimestampDeltaAlgorithm(mapTimestampAlgo); + Runtime.getRuntime().addShutdownHook(new Thread(mapValidationAlgo::stop)); + mapValidationAlgo.start(); - // Spat Broadcast Rate Topology - // Sends "SPAT Broadcast Rate" events when the number of SPATs per rolling period is too low or too high - final String spatBroadcastRate = "spatBroadcastRate"; + // Spat Validation Topology + final String spatValidation = "spatValidation"; final SpatValidationStreamsAlgorithmFactory spatAlgoFactory = conflictMonitorProps.getSpatValidationAlgorithmFactory(); final String spatAlgo = conflictMonitorProps.getSpatValidationAlgorithm(); - final SpatValidationAlgorithm spatCountAlgo = spatAlgoFactory.getAlgorithm(spatAlgo); - final SpatValidationParameters spatCountParams = conflictMonitorProps.getSpatValidationParameters(); - configTopology.registerConfigListeners(spatCountParams); - if (spatCountAlgo instanceof StreamsTopology) { - final var streamsAlgo = (StreamsTopology)spatCountAlgo; - streamsAlgo.setStreamsProperties(conflictMonitorProps.createStreamProperties(spatBroadcastRate)); - streamsAlgo.registerStateListener(new StateChangeHandler(kafkaTemplate, spatBroadcastRate, stateChangeTopic, healthTopic)); - streamsAlgo.registerUncaughtExceptionHandler(new StreamsExceptionHandler(kafkaTemplate, spatBroadcastRate, healthTopic)); - algoMap.put(spatBroadcastRate, streamsAlgo); + final SpatValidationAlgorithm spatValidationAlgo = spatAlgoFactory.getAlgorithm(spatAlgo); + final SpatValidationParameters spatValidationParams = conflictMonitorProps.getSpatValidationParameters(); + configTopology.registerConfigListeners(spatValidationParams); + if (spatValidationAlgo instanceof StreamsTopology streamsAlgo) { + streamsAlgo.setStreamsProperties(conflictMonitorProps.createStreamProperties(spatValidation)); + streamsAlgo.registerStateListener(new StateChangeHandler(kafkaTemplate, spatValidation, stateChangeTopic, healthTopic)); + streamsAlgo.registerUncaughtExceptionHandler(new StreamsExceptionHandler(kafkaTemplate, spatValidation, healthTopic)); + algoMap.put(spatValidation, streamsAlgo); } - spatCountAlgo.setParameters(spatCountParams); - Runtime.getRuntime().addShutdownHook(new Thread(spatCountAlgo::stop)); - spatCountAlgo.start(); + spatValidationAlgo.setParameters(spatValidationParams); + // Plugin timestamp delta algorithm + final SpatTimestampDeltaAlgorithm spatTimestampAlgo = getSpatTimestampDeltaAlgorithm(conflictMonitorProps); + spatValidationAlgo.setTimestampDeltaAlgorithm(spatTimestampAlgo); + Runtime.getRuntime().addShutdownHook(new Thread(spatValidationAlgo::stop)); + spatValidationAlgo.start(); @@ -410,6 +429,76 @@ public MonitorServiceController(final ConflictMonitorProperties conflictMonitorP connectionofTravelAssessmentAlgo.start(); + //Map Revision Counter Topology + final String mapRevisionCounter = "mapRevisionCounter"; + final MapRevisionCounterAlgorithmFactory mapRevisionCounterAlgoFactory = conflictMonitorProps.getMapRevisionCounterAlgorithmFactory(); + final String mapRevisionCounterAlgorithm = conflictMonitorProps.getMapRevisionCounterAlgorithm(); + final MapRevisionCounterAlgorithm mapRevisionCounterAlgo = mapRevisionCounterAlgoFactory.getAlgorithm(mapRevisionCounterAlgorithm); + final MapRevisionCounterParameters mapRevisionCounterParams = conflictMonitorProps.getMapRevisionCounterAlgorithmParameters(); + configTopology.registerConfigListeners(mapRevisionCounterParams); + if (mapRevisionCounterAlgo instanceof StreamsTopology) { + final var streamsAlgo = (StreamsTopology)mapRevisionCounterAlgo; + streamsAlgo.setStreamsProperties(conflictMonitorProps.createStreamProperties(mapRevisionCounter)); + streamsAlgo.registerStateListener(new StateChangeHandler(kafkaTemplate, mapRevisionCounter, stateChangeTopic, healthTopic)); + streamsAlgo.registerUncaughtExceptionHandler(new StreamsExceptionHandler(kafkaTemplate, mapRevisionCounter, healthTopic)); + algoMap.put(mapRevisionCounter, streamsAlgo); + } + mapRevisionCounterAlgo.setParameters(mapRevisionCounterParams); + Runtime.getRuntime().addShutdownHook(new Thread(mapRevisionCounterAlgo::stop)); + mapRevisionCounterAlgo.start(); + + //Spat Revision Counter Topology + final String spatRevisionCounter = "spatRevisionCounter"; + final SpatRevisionCounterAlgorithmFactory spatRevisionCounterAlgoFactory = conflictMonitorProps.getSpatRevisionCounterAlgorithmFactory(); + final String spatRevisionCounterAlgorithm = conflictMonitorProps.getSpatRevisionCounterAlgorithm(); + final SpatRevisionCounterAlgorithm spatRevisionCounterAlgo = spatRevisionCounterAlgoFactory.getAlgorithm(spatRevisionCounterAlgorithm); + final SpatRevisionCounterParameters spatRevisionCounterParams = conflictMonitorProps.getSpatRevisionCounterAlgorithmParameters(); + configTopology.registerConfigListeners(spatRevisionCounterParams); + if (spatRevisionCounterAlgo instanceof StreamsTopology) { + final var streamsAlgo = (StreamsTopology)spatRevisionCounterAlgo; + streamsAlgo.setStreamsProperties(conflictMonitorProps.createStreamProperties(spatRevisionCounter)); + streamsAlgo.registerStateListener(new StateChangeHandler(kafkaTemplate, spatRevisionCounter, stateChangeTopic, healthTopic)); + streamsAlgo.registerUncaughtExceptionHandler(new StreamsExceptionHandler(kafkaTemplate, spatRevisionCounter, healthTopic)); + algoMap.put(spatRevisionCounter, streamsAlgo); + } + spatRevisionCounterAlgo.setParameters(spatRevisionCounterParams); + Runtime.getRuntime().addShutdownHook(new Thread(spatRevisionCounterAlgo::stop)); + spatRevisionCounterAlgo.start(); + + //Bsm Revision Counter Topology + final String bsmRevisionCounter = "bsmRevisionCounter"; + final BsmRevisionCounterAlgorithmFactory bsmRevisionCounterAlgoFactory = conflictMonitorProps.getBsmRevisionCounterAlgorithmFactory(); + final String bsmRevisionCounterAlgorithm = conflictMonitorProps.getBsmRevisionCounterAlgorithm(); + final BsmRevisionCounterAlgorithm bsmRevisionCounterAlgo = bsmRevisionCounterAlgoFactory.getAlgorithm(bsmRevisionCounterAlgorithm); + final BsmRevisionCounterParameters bsmRevisionCounterParams = conflictMonitorProps.getBsmRevisionCounterAlgorithmParameters(); + configTopology.registerConfigListeners(bsmRevisionCounterParams); + if (bsmRevisionCounterAlgo instanceof StreamsTopology) { + final var streamsAlgo = (StreamsTopology)bsmRevisionCounterAlgo; + streamsAlgo.setStreamsProperties(conflictMonitorProps.createStreamProperties(bsmRevisionCounter)); + streamsAlgo.registerStateListener(new StateChangeHandler(kafkaTemplate, bsmRevisionCounter, stateChangeTopic, healthTopic)); + streamsAlgo.registerUncaughtExceptionHandler(new StreamsExceptionHandler(kafkaTemplate, bsmRevisionCounter, healthTopic)); + algoMap.put(bsmRevisionCounter, streamsAlgo); + } + bsmRevisionCounterAlgo.setParameters(bsmRevisionCounterParams); + Runtime.getRuntime().addShutdownHook(new Thread(bsmRevisionCounterAlgo::stop)); + bsmRevisionCounterAlgo.start(); + + // Combined Event Topology + final String event = "event"; + final EventAlgorithmFactory eventAlgorithmFactory = conflictMonitorProps.getEventAlgorithmFactory(); + final String eventAlgorithmName = conflictMonitorProps.getEventAlgorithm(); + final EventAlgorithm eventAlgorithm = eventAlgorithmFactory.getAlgorithm(eventAlgorithmName); + final EventParameters eventParams = conflictMonitorProps.getEventParameters(); + configTopology.registerConfigListeners(eventParams); + if (eventAlgorithm instanceof StreamsTopology streamsAlgo) { + streamsAlgo.setStreamsProperties(conflictMonitorProps.createStreamProperties(event)); + streamsAlgo.registerStateListener(new StateChangeHandler(kafkaTemplate, event, stateChangeTopic, healthTopic)); + streamsAlgo.registerUncaughtExceptionHandler(new StreamsExceptionHandler(kafkaTemplate, event, healthTopic)); + algoMap.put(event, streamsAlgo); + } + eventAlgorithm.setParameters(eventParams); + Runtime.getRuntime().addShutdownHook(new Thread(eventAlgorithm::stop)); + eventAlgorithm.start(); // Restore properties configInitializer.initializeDefaultConfigs(); @@ -423,5 +512,25 @@ public MonitorServiceController(final ConflictMonitorProperties conflictMonitorP } } - + + + private static MapTimestampDeltaAlgorithm getMapTimestampDeltaAlgorithm(ConflictMonitorProperties props) { + final var factory = props.getMapTimestampDeltaAlgorithmFactory(); + final String algorithmName = props.getMapTimestampDeltaAlgorithm(); + final var algorithm = factory.getAlgorithm(algorithmName); + final var parameters = props.getMapTimestampDeltaParameters(); + algorithm.setParameters(parameters); + return algorithm; + } + + private static SpatTimestampDeltaAlgorithm getSpatTimestampDeltaAlgorithm(ConflictMonitorProperties props) { + final var factory = props.getSpatTimestampDeltaAlgorithmFactory(); + final String algorithmName = props.getSpatTimestampDeltaAlgorithm(); + final var algorithm = factory.getAlgorithm(algorithmName); + final var parameters = props.getSpatTimestampDeltaParameters(); + algorithm.setParameters(parameters); + return algorithm; + } + + } \ No newline at end of file diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/WebConfig.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/WebConfig.java new file mode 100644 index 00000000..246e36cf --- /dev/null +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/WebConfig.java @@ -0,0 +1,34 @@ +package us.dot.its.jpo.conflictmonitor.monitor; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.converter.HttpMessageConverter; +import org.springframework.http.converter.StringHttpMessageConverter; +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import us.dot.its.jpo.conflictmonitor.monitor.models.config.IntersectionConfig; +import us.dot.its.jpo.conflictmonitor.monitor.serialization.deserialization.GenericJsonStringDeserializer; + +import java.util.List; + +@Configuration +@EnableWebMvc +public class WebConfig implements WebMvcConfigurer { + + @Override + public void configureMessageConverters(List> converters) { + JavaTimeModule module = new JavaTimeModule(); + module.addDeserializer(IntersectionConfig.class, new GenericJsonStringDeserializer>(IntersectionConfig.class)); + ObjectMapper mapper = new ObjectMapper(); + mapper.registerModule(module); + mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false); + mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false); + mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); + converters.addFirst(new MappingJackson2HttpMessageConverter(mapper)); + converters.addFirst(new StringHttpMessageConverter()); // Allow text/plain responses + } +} diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/Algorithm.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/Algorithm.java index a29ad5fc..ad01156a 100644 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/Algorithm.java +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/Algorithm.java @@ -4,6 +4,6 @@ /** * General interface for an algorithm that can be configured with parameters, and started and stopped. * - * @param TParameters Type of configuration parameters the algorithm requires. + * @param Type of configuration parameters the algorithm requires. */ public interface Algorithm extends ExecutableAlgorithm, ConfigurableAlgorithm { } diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/BaseStreamsBuilder.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/BaseStreamsBuilder.java index a6d40e06..195779be 100644 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/BaseStreamsBuilder.java +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/BaseStreamsBuilder.java @@ -1,30 +1,21 @@ package us.dot.its.jpo.conflictmonitor.monitor.algorithms; +import lombok.Getter; +import lombok.Setter; import org.apache.kafka.streams.StreamsBuilder; -import org.apache.kafka.streams.Topology; import org.slf4j.Logger; /** - * Base class for an algorithm implemented as a chained topology builder to build part of - * a larger topology. + * Base class for an algorithm implemented as a chained topology builder to build part of a larger topology. * * @param */ +@Getter +@Setter public abstract class BaseStreamsBuilder { protected abstract Logger getLogger(); protected TParams parameters; - public void setParameters(TParams parameters) { - this.parameters = parameters; - } - - public TParams getParameters() { - return parameters; - } - - - public abstract StreamsBuilder buildTopology(StreamsBuilder builder); - } diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/BaseStreamsTopology.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/BaseStreamsTopology.java index b0cf3bcf..3187bf85 100644 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/BaseStreamsTopology.java +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/BaseStreamsTopology.java @@ -1,5 +1,7 @@ package us.dot.its.jpo.conflictmonitor.monitor.algorithms; +import lombok.Getter; +import lombok.Setter; import org.apache.kafka.streams.KafkaStreams; import org.apache.kafka.streams.Topology; import org.apache.kafka.streams.errors.StreamsUncaughtExceptionHandler; @@ -8,29 +10,37 @@ import java.util.Properties; +/** + * Base class for a standalone streams topology + * @param Type of parameters + */ public abstract class BaseStreamsTopology { protected abstract Logger getLogger(); + @Getter + @Setter protected TParams parameters; + + @Getter + @Setter protected Properties streamsProperties; + + @Getter protected Topology topology; + + /** + * -- SETTER -- + * Method for testing + */ + @Setter + @Getter protected KafkaStreams streams; + protected KafkaStreams.StateListener stateListener; protected StreamsUncaughtExceptionHandler exceptionHandler; - - public void setParameters(TParams parameters) { - this.parameters = parameters; - } - - - public TParams getParameters() { - return parameters; - } - - public void start() { validate(); getLogger().info("Starting {}.", this.getClass().getSimpleName()); @@ -77,35 +87,6 @@ public void stop() { } - public void setStreamsProperties(Properties streamsProperties) { - this.streamsProperties = streamsProperties; - } - - - public Properties getStreamsProperties() { - return streamsProperties; - } - - - public KafkaStreams getStreams() { - return streams; - } - - /** - * Method for testing - * @param streams {@link KafkaStreams} - */ - public void setStreams(KafkaStreams streams) { - this.streams = streams; - } - - - public Topology getTopology() { - return topology; - } - - - public void registerStateListener(KafkaStreams.StateListener stateListener) { this.stateListener = stateListener; } diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/ConfigurableAlgorithm.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/ConfigurableAlgorithm.java index d33900eb..e804d3e7 100644 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/ConfigurableAlgorithm.java +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/ConfigurableAlgorithm.java @@ -3,7 +3,7 @@ /** * General interface for an algorithm that can be configured with parameters. * - * @param TParameters Type of configuration parameters the algorithm requires. + * @param Type of configuration parameters the algorithm requires. */ public interface ConfigurableAlgorithm { diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/ExecutableAlgorithm.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/ExecutableAlgorithm.java index 289b6278..a673947b 100644 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/ExecutableAlgorithm.java +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/ExecutableAlgorithm.java @@ -1,11 +1,7 @@ package us.dot.its.jpo.conflictmonitor.monitor.algorithms; -import org.slf4j.Logger; - /** * General interface for an algorithm that can be started and stopped. - * - * @param TParameters Type of configuration parameters the algorithm requires. */ public interface ExecutableAlgorithm { diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/PartialStreamsAlgorithm.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/PartialStreamsAlgorithm.java new file mode 100644 index 00000000..b3b03bb5 --- /dev/null +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/PartialStreamsAlgorithm.java @@ -0,0 +1,16 @@ +//package us.dot.its.jpo.conflictmonitor.monitor.algorithms; +// +//import org.apache.kafka.streams.kstream.KStream; +// +///** +// * General interface for an algorithm implemented as a part of a subtopology +// * to plug into a larger topology. +// * @param +// * @param +// * @param +// * @param +// */ +//public interface PartialStreamsAlgorithm +//{ +// KStream buildPartialTopology(KStream inputStream); +//} diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/StreamsBuilderAlgorithm.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/StreamsBuilderAlgorithm.java new file mode 100644 index 00000000..9c06b4bc --- /dev/null +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/StreamsBuilderAlgorithm.java @@ -0,0 +1,18 @@ +//package us.dot.its.jpo.conflictmonitor.monitor.algorithms; +// +//import org.apache.kafka.streams.StreamsBuilder; +//import org.apache.kafka.streams.kstream.KStream; +// +///** +// * General interface for an algorithm implemented as a StreamsBuilder that +// * builds a subtopology of a streams topology and plugs into a larger algorithm. +// * +// * @param - Input type, may be either a StreamsBuilder to create an unconnected +// * subtopology, or KStream<>, etc. to construct part of a subtopology. +// * @param - Output type (KStream<> etc) +// */ +//public interface StreamsBuilderAlgorithm { +// TOut buildTopology(TIn builder); +//} +// +// diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/bsm_revision_counter/BsmRevisionCounterAlgorithm.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/bsm_revision_counter/BsmRevisionCounterAlgorithm.java new file mode 100644 index 00000000..a7cbcfb2 --- /dev/null +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/bsm_revision_counter/BsmRevisionCounterAlgorithm.java @@ -0,0 +1,13 @@ +package us.dot.its.jpo.conflictmonitor.monitor.algorithms.bsm_revision_counter; + +import us.dot.its.jpo.conflictmonitor.monitor.algorithms.Algorithm; + +public interface BsmRevisionCounterAlgorithm extends Algorithm{ + +} + + + + + + diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/bsm_revision_counter/BsmRevisionCounterAlgorithmFactory.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/bsm_revision_counter/BsmRevisionCounterAlgorithmFactory.java new file mode 100644 index 00000000..a1b90b8a --- /dev/null +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/bsm_revision_counter/BsmRevisionCounterAlgorithmFactory.java @@ -0,0 +1,5 @@ +package us.dot.its.jpo.conflictmonitor.monitor.algorithms.bsm_revision_counter; + +public interface BsmRevisionCounterAlgorithmFactory { + BsmRevisionCounterAlgorithm getAlgorithm(String algorithmName); +} diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/bsm_revision_counter/BsmRevisionCounterAlgorithms.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/bsm_revision_counter/BsmRevisionCounterAlgorithms.java new file mode 100644 index 00000000..72d0f72f --- /dev/null +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/bsm_revision_counter/BsmRevisionCounterAlgorithms.java @@ -0,0 +1,16 @@ +package us.dot.its.jpo.conflictmonitor.monitor.algorithms.bsm_revision_counter; + +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 BsmRevisionCounterAlgorithms { + @Bean + public FactoryBean bsmRevisionCounterServiceLocatorFactoryBean() { + var factoryBean = new ServiceLocatorFactoryBean(); + factoryBean.setServiceLocatorInterface(BsmRevisionCounterAlgorithmFactory.class); + return factoryBean; + } +} \ No newline at end of file diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/bsm_revision_counter/BsmRevisionCounterConstants.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/bsm_revision_counter/BsmRevisionCounterConstants.java new file mode 100644 index 00000000..a5a55dd3 --- /dev/null +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/bsm_revision_counter/BsmRevisionCounterConstants.java @@ -0,0 +1,8 @@ +package us.dot.its.jpo.conflictmonitor.monitor.algorithms.bsm_revision_counter; + +public final class BsmRevisionCounterConstants { + public static final String DEFAULT_BSM_REVISION_COUNTER_ALGORITHM = "defaultBsmRevisionCounterAlgorithm"; + public static final String DEBUG_BSM_REVISION_COUNTER_ALGORITHM = "debugBsmRevisionCounterAlgorithm"; +} + + diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/bsm_revision_counter/BsmRevisionCounterParameters.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/bsm_revision_counter/BsmRevisionCounterParameters.java new file mode 100644 index 00000000..4b14c146 --- /dev/null +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/bsm_revision_counter/BsmRevisionCounterParameters.java @@ -0,0 +1,33 @@ +package us.dot.its.jpo.conflictmonitor.monitor.algorithms.bsm_revision_counter; + +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 = "bsm.revision.counter") +@ConfigDataClass +public class BsmRevisionCounterParameters { + + @ConfigData(key = "bsm.revision.counter.debug", + description = "Whether to log diagnostic information for debugging", + updateType = DEFAULT) + boolean debug; + + @ConfigData(key = "bsm.revision.counter.bsmInputTopicName", + description = "The name of the topic to read BSMs from", + updateType = READ_ONLY) + String bsmInputTopicName; + + @ConfigData(key = "bsm.revision.counter.bsmRevisionEventOutputTopicName", + description = "The name of the topic to write BSM revision counter events to", + updateType = READ_ONLY) + String bsmRevisionEventOutputTopicName; +} diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/bsm_revision_counter/BsmRevisionCounterStreamsAlgorithm.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/bsm_revision_counter/BsmRevisionCounterStreamsAlgorithm.java new file mode 100644 index 00000000..220da03a --- /dev/null +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/bsm_revision_counter/BsmRevisionCounterStreamsAlgorithm.java @@ -0,0 +1,7 @@ +package us.dot.its.jpo.conflictmonitor.monitor.algorithms.bsm_revision_counter; + + +import us.dot.its.jpo.conflictmonitor.monitor.algorithms.StreamsTopology; + +public interface BsmRevisionCounterStreamsAlgorithm + extends BsmRevisionCounterAlgorithm, StreamsTopology {} diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/event/EventParameters.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/event/EventParameters.java index cd96202c..02779548 100644 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/event/EventParameters.java +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/event/EventParameters.java @@ -15,6 +15,11 @@ @ConfigurationProperties(prefix = "event") @ConfigDataClass public class EventParameters { + + @ConfigData(key = "event.algorithm", + description = "The algorithm to use", + updateType = READ_ONLY) + String algorithm; // Whether to log diagnostic information for debugging @ConfigData(key = "event.debug", @@ -22,6 +27,11 @@ public class EventParameters { updateType = DEFAULT) boolean debug; + @ConfigData(key = "event.enabled", + description = "Whether to run this topology to produce events to the combined topic.", + updateType = READ_ONLY) + boolean enabled; + @ConfigData(key = "event.eventOutputTopicName", description = "The name of the topic to output events to", updateType = READ_ONLY) @@ -83,5 +93,25 @@ public class EventParameters { updateType = READ_ONLY) String connectionOfTravelEventTopicName; + @ConfigData(key = "event.spatRevisionCounterEventTopicName", + description = "The name of the topic to read spat revision counter events from", + updateType = READ_ONLY) + String spatRevisionCounterEventTopicName; + + @ConfigData(key = "event.mapRevisionCounterEventTopicName", + description = "The name of the topic to read map revision counter events from", + updateType = READ_ONLY) + String mapRevisionCounterEventTopicName; + @ConfigData(key = "event.bsmRevisionCounterEventTopicName", + description = "The name of the topic to read bsm revision counter events from", + updateType = READ_ONLY) + String bsmRevisionCounterEventTopicName; + + @ConfigData(key = "event.timestampDeltaEventTopicName", + description = "The name of the topic to read MAP and SPaT Timestamp Delta events from", + updateType = READ_ONLY) + String timestampDeltaEventTopicName; + + } diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/map_revision_counter/MapRevisionCounterAlgorithm.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/map_revision_counter/MapRevisionCounterAlgorithm.java new file mode 100644 index 00000000..555ade99 --- /dev/null +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/map_revision_counter/MapRevisionCounterAlgorithm.java @@ -0,0 +1,13 @@ +package us.dot.its.jpo.conflictmonitor.monitor.algorithms.map_revision_counter; + +import us.dot.its.jpo.conflictmonitor.monitor.algorithms.Algorithm; + +public interface MapRevisionCounterAlgorithm extends Algorithm{ + +} + + + + + + diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/map_revision_counter/MapRevisionCounterAlgorithmFactory.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/map_revision_counter/MapRevisionCounterAlgorithmFactory.java new file mode 100644 index 00000000..cdcd9bfc --- /dev/null +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/map_revision_counter/MapRevisionCounterAlgorithmFactory.java @@ -0,0 +1,5 @@ +package us.dot.its.jpo.conflictmonitor.monitor.algorithms.map_revision_counter; + +public interface MapRevisionCounterAlgorithmFactory { + MapRevisionCounterAlgorithm getAlgorithm(String algorithmName); +} diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/map_revision_counter/MapRevisionCounterAlgorithms.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/map_revision_counter/MapRevisionCounterAlgorithms.java new file mode 100644 index 00000000..cde18b2f --- /dev/null +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/map_revision_counter/MapRevisionCounterAlgorithms.java @@ -0,0 +1,16 @@ +package us.dot.its.jpo.conflictmonitor.monitor.algorithms.map_revision_counter; + +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 MapRevisionCounterAlgorithms { + @Bean + public FactoryBean mapRevisionCounterServiceLocatorFactoryBean() { + var factoryBean = new ServiceLocatorFactoryBean(); + factoryBean.setServiceLocatorInterface(MapRevisionCounterAlgorithmFactory.class); + return factoryBean; + } +} \ No newline at end of file diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/map_revision_counter/MapRevisionCounterConstants.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/map_revision_counter/MapRevisionCounterConstants.java new file mode 100644 index 00000000..b190dcbb --- /dev/null +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/map_revision_counter/MapRevisionCounterConstants.java @@ -0,0 +1,8 @@ +package us.dot.its.jpo.conflictmonitor.monitor.algorithms.map_revision_counter; + +public final class MapRevisionCounterConstants { + public static final String DEFAULT_MAP_REVISION_COUNTER_ALGORITHM = "defaultMapRevisionCounterAlgorithm"; + public static final String DEBUG_MAP_REVISION_COUNTER_ALGORITHM = "debugMapRevisionCounterAlgorithm"; +} + + diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/map_revision_counter/MapRevisionCounterParameters.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/map_revision_counter/MapRevisionCounterParameters.java new file mode 100644 index 00000000..bbc5e210 --- /dev/null +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/map_revision_counter/MapRevisionCounterParameters.java @@ -0,0 +1,33 @@ +package us.dot.its.jpo.conflictmonitor.monitor.algorithms.map_revision_counter; + +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 = "map.revision.counter") +@ConfigDataClass +public class MapRevisionCounterParameters { + + @ConfigData(key = "map.revision.counter.debug", + description = "Whether to log diagnostic information for debugging", + updateType = DEFAULT) + boolean debug; + + @ConfigData(key = "map.revision.counter.mapInputTopicName", + description = "The name of the topic to read MAPs from", + updateType = READ_ONLY) + String mapInputTopicName; + + @ConfigData(key = "map.revision.counter.mapRevisionEventOutputTopicName", + description = "The name of the topic to write map revision counter events to", + updateType = READ_ONLY) + String mapRevisionEventOutputTopicName; +} diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/map_revision_counter/MapRevisionCounterStreamsAlgorithm.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/map_revision_counter/MapRevisionCounterStreamsAlgorithm.java new file mode 100644 index 00000000..df878685 --- /dev/null +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/map_revision_counter/MapRevisionCounterStreamsAlgorithm.java @@ -0,0 +1,7 @@ +package us.dot.its.jpo.conflictmonitor.monitor.algorithms.map_revision_counter; + + +import us.dot.its.jpo.conflictmonitor.monitor.algorithms.StreamsTopology; + +public interface MapRevisionCounterStreamsAlgorithm + extends MapRevisionCounterAlgorithm, StreamsTopology {} diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/map_spat_message_assessment/MapSpatMessageAssessmentParameters.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/map_spat_message_assessment/MapSpatMessageAssessmentParameters.java index e80d8072..c2aed9d7 100644 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/map_spat_message_assessment/MapSpatMessageAssessmentParameters.java +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/map_spat_message_assessment/MapSpatMessageAssessmentParameters.java @@ -5,9 +5,17 @@ import lombok.Data; import lombok.Generated; -import us.dot.its.jpo.conflictmonitor.monitor.models.AllowConcurrentPermissiveList; +import us.dot.its.jpo.conflictmonitor.monitor.models.IntersectionRegion; +import us.dot.its.jpo.conflictmonitor.monitor.models.concurrent_permissive.ConnectedLanes; +import us.dot.its.jpo.conflictmonitor.monitor.models.concurrent_permissive.ConnectedLanesPair; +import us.dot.its.jpo.conflictmonitor.monitor.models.concurrent_permissive.ConnectedLanesPairList; import us.dot.its.jpo.conflictmonitor.monitor.models.config.ConfigData; import us.dot.its.jpo.conflictmonitor.monitor.models.config.ConfigDataClass; +import us.dot.its.jpo.conflictmonitor.monitor.models.config.ConfigMap; + +import java.util.List; + +import static us.dot.its.jpo.conflictmonitor.monitor.algorithms.config.ConfigUtil.getIntersectionValue; import static us.dot.its.jpo.conflictmonitor.monitor.models.config.UpdateType.*; @Data @@ -64,12 +72,21 @@ public class MapSpatMessageAssessmentParameters { String signalStateConflictNotificationTopicName; - @ConfigData(key = "map.spat.message.assessment.allowConcurrentPermissive", - description = "Allowed Concurrent Permissive Intersections", - updateType = DEFAULT) - String concurrentPermissiveList; + @ConfigData(key = "map.spat.message.assessment.concurrentPermissiveList", + description = "List of pairs of lane connections that are allowed concurrently permissive for an intersection.", + updateType = INTERSECTION) + volatile ConnectedLanesPairList concurrentPermissiveList; + // + // Maps for parameters that can be customized at the intersection level + // + final ConfigMap concurrentPermissiveListMap = new ConfigMap<>(); - - + // + // Intersection-specific properties + // + public ConnectedLanesPairList getConcurrentPermissiveList(IntersectionRegion intersectionKey) { + var defaultList = concurrentPermissiveList != null ? concurrentPermissiveList : new ConnectedLanesPairList(); + return getIntersectionValue(intersectionKey, concurrentPermissiveListMap, defaultList); + } } diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/message_ingest/MessageIngestAlgorithm.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/message_ingest/MessageIngestAlgorithm.java index ad0425de..81c03157 100644 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/message_ingest/MessageIngestAlgorithm.java +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/message_ingest/MessageIngestAlgorithm.java @@ -1,6 +1,5 @@ package us.dot.its.jpo.conflictmonitor.monitor.algorithms.message_ingest; -import us.dot.its.jpo.conflictmonitor.monitor.algorithms.Algorithm; import us.dot.its.jpo.conflictmonitor.monitor.algorithms.ConfigurableAlgorithm; import us.dot.its.jpo.conflictmonitor.monitor.models.map.MapIndex; 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 5441f779..3fac74dd 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 @@ -6,7 +6,6 @@ import org.apache.kafka.streams.state.ReadOnlyWindowStore; 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.map.ProcessedMap; @@ -20,5 +19,5 @@ public interface MessageIngestStreamsAlgorithm ReadOnlyWindowStore getSpatWindowStore(KafkaStreams streams); ReadOnlyKeyValueStore> getMapStore(KafkaStreams streams); - StreamsBuilder buildTopology(StreamsBuilder builder); + void buildTopology(StreamsBuilder builder); } diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/notification/NotificationParameters.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/notification/NotificationParameters.java index 37657190..ba80e954 100644 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/notification/NotificationParameters.java +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/notification/NotificationParameters.java @@ -56,5 +56,9 @@ public class NotificationParameters { description = "The name of the topic to read Spat Time Change Details from", updateType = READ_ONLY) String spatTimeChangeDetailsNotificationTopicName; + + @ConfigData(key = "notification.timestampDeltaNotificationTopicName", + description = "The name of the topic to read MAP and SPAT Timestamp Delta Notifications from") + String timestampDeltaNotificationTopicName; } diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/spat_revision_counter/SpatRevisionCounterAlgorithm.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/spat_revision_counter/SpatRevisionCounterAlgorithm.java new file mode 100644 index 00000000..21b673e2 --- /dev/null +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/spat_revision_counter/SpatRevisionCounterAlgorithm.java @@ -0,0 +1,13 @@ +package us.dot.its.jpo.conflictmonitor.monitor.algorithms.spat_revision_counter; + +import us.dot.its.jpo.conflictmonitor.monitor.algorithms.Algorithm; + +public interface SpatRevisionCounterAlgorithm extends Algorithm{ + +} + + + + + + diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/spat_revision_counter/SpatRevisionCounterAlgorithmFactory.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/spat_revision_counter/SpatRevisionCounterAlgorithmFactory.java new file mode 100644 index 00000000..424387db --- /dev/null +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/spat_revision_counter/SpatRevisionCounterAlgorithmFactory.java @@ -0,0 +1,5 @@ +package us.dot.its.jpo.conflictmonitor.monitor.algorithms.spat_revision_counter; + +public interface SpatRevisionCounterAlgorithmFactory { + SpatRevisionCounterAlgorithm getAlgorithm(String algorithmName); +} diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/spat_revision_counter/SpatRevisionCounterAlgorithms.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/spat_revision_counter/SpatRevisionCounterAlgorithms.java new file mode 100644 index 00000000..8440d5f2 --- /dev/null +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/spat_revision_counter/SpatRevisionCounterAlgorithms.java @@ -0,0 +1,16 @@ +package us.dot.its.jpo.conflictmonitor.monitor.algorithms.spat_revision_counter; + +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 SpatRevisionCounterAlgorithms { + @Bean + public FactoryBean spatRevisionCounterServiceLocatorFactoryBean() { + var factoryBean = new ServiceLocatorFactoryBean(); + factoryBean.setServiceLocatorInterface(SpatRevisionCounterAlgorithmFactory.class); + return factoryBean; + } +} \ No newline at end of file diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/spat_revision_counter/SpatRevisionCounterConstants.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/spat_revision_counter/SpatRevisionCounterConstants.java new file mode 100644 index 00000000..3bf71900 --- /dev/null +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/spat_revision_counter/SpatRevisionCounterConstants.java @@ -0,0 +1,8 @@ +package us.dot.its.jpo.conflictmonitor.monitor.algorithms.spat_revision_counter; + +public final class SpatRevisionCounterConstants { + public static final String DEFAULT_SPAT_REVISION_COUNTER_ALGORITHM = "defaultSpatRevisionCounterAlgorithm"; + public static final String DEBUG_SPAT_REVISION_COUNTER_ALGORITHM = "debugSpatRevisionCounterAlgorithm"; +} + + diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/spat_revision_counter/SpatRevisionCounterParameters.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/spat_revision_counter/SpatRevisionCounterParameters.java new file mode 100644 index 00000000..211d8144 --- /dev/null +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/spat_revision_counter/SpatRevisionCounterParameters.java @@ -0,0 +1,33 @@ +package us.dot.its.jpo.conflictmonitor.monitor.algorithms.spat_revision_counter; + +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 = "spat.revision.counter") +@ConfigDataClass +public class SpatRevisionCounterParameters { + + @ConfigData(key = "spat.revision.counter.debug", + description = "Whether to log diagnostic information for debugging", + updateType = DEFAULT) + boolean debug; + + @ConfigData(key = "spat.revision.counter.spatInputTopicName", + description = "The name of the topic to read SPATs from", + updateType = READ_ONLY) + String spatInputTopicName; + + @ConfigData(key = "spat.revision.counter.spatRevisionEventOutputTopicName", + description = "The name of the topic to write SPAT revision counter events to", + updateType = READ_ONLY) + String spatRevisionEventOutputTopicName; +} diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/spat_revision_counter/SpatRevisionCounterStreamsAlgorithm.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/spat_revision_counter/SpatRevisionCounterStreamsAlgorithm.java new file mode 100644 index 00000000..25fe1ec8 --- /dev/null +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/spat_revision_counter/SpatRevisionCounterStreamsAlgorithm.java @@ -0,0 +1,7 @@ +package us.dot.its.jpo.conflictmonitor.monitor.algorithms.spat_revision_counter; + + +import us.dot.its.jpo.conflictmonitor.monitor.algorithms.StreamsTopology; + +public interface SpatRevisionCounterStreamsAlgorithm + extends SpatRevisionCounterAlgorithm, StreamsTopology {} diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/timestamp_delta/BaseTimestampDeltaAlgorithm.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/timestamp_delta/BaseTimestampDeltaAlgorithm.java new file mode 100644 index 00000000..a73c7b33 --- /dev/null +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/timestamp_delta/BaseTimestampDeltaAlgorithm.java @@ -0,0 +1,7 @@ +package us.dot.its.jpo.conflictmonitor.monitor.algorithms.timestamp_delta; + +import us.dot.its.jpo.conflictmonitor.monitor.algorithms.ConfigurableAlgorithm; + +public interface BaseTimestampDeltaAlgorithm + extends ConfigurableAlgorithm { +} diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/timestamp_delta/BaseTimestampDeltaStreamsAlgorithm.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/timestamp_delta/BaseTimestampDeltaStreamsAlgorithm.java new file mode 100644 index 00000000..d74cd21c --- /dev/null +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/timestamp_delta/BaseTimestampDeltaStreamsAlgorithm.java @@ -0,0 +1,11 @@ +package us.dot.its.jpo.conflictmonitor.monitor.algorithms.timestamp_delta; + +import org.apache.kafka.streams.StreamsBuilder; +import org.apache.kafka.streams.kstream.KStream; +import us.dot.its.jpo.geojsonconverter.partitioner.RsuIntersectionKey; + +public interface BaseTimestampDeltaStreamsAlgorithm { + + void buildTopology(StreamsBuilder builder, KStream inputStream); + +} diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/timestamp_delta/ITimestampDeltaParameters.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/timestamp_delta/ITimestampDeltaParameters.java new file mode 100644 index 00000000..ba23e63a --- /dev/null +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/timestamp_delta/ITimestampDeltaParameters.java @@ -0,0 +1,19 @@ +package us.dot.its.jpo.conflictmonitor.monitor.algorithms.timestamp_delta; + +import us.dot.its.jpo.conflictmonitor.monitor.models.config.ConfigData; + +import static us.dot.its.jpo.conflictmonitor.monitor.models.config.UpdateType.DEFAULT; +import static us.dot.its.jpo.conflictmonitor.monitor.models.config.UpdateType.READ_ONLY; + +public interface ITimestampDeltaParameters { + + + String getAlgorithm(); + String getOutputTopicName(); + int getMaxDeltaMilliseconds(); + boolean isDebug(); + String getKeyStoreName(); + String getEventStoreName(); + int getRetentionTimeMinutes(); + String getNotificationTopicName(); +} diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/timestamp_delta/TimestampDeltaAlgorithms.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/timestamp_delta/TimestampDeltaAlgorithms.java new file mode 100644 index 00000000..19551c2b --- /dev/null +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/timestamp_delta/TimestampDeltaAlgorithms.java @@ -0,0 +1,27 @@ +package us.dot.its.jpo.conflictmonitor.monitor.algorithms.timestamp_delta; + +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; +import us.dot.its.jpo.conflictmonitor.monitor.algorithms.timestamp_delta.map.MapTimestampDeltaAlgorithmFactory; +import us.dot.its.jpo.conflictmonitor.monitor.algorithms.timestamp_delta.spat.SpatTimestampDeltaAlgorithmFactory; + +/** + * Configuration defining {@link FactoryBean}s for locating Timestamp Delta algorithms. + */ +@Configuration +public class TimestampDeltaAlgorithms { + + @Bean FactoryBean spatTimestampDeltaServiceLocatorFactoryBean() { + var factoryBean = new ServiceLocatorFactoryBean(); + factoryBean.setServiceLocatorInterface(SpatTimestampDeltaAlgorithmFactory.class); + return factoryBean; + } + + @Bean FactoryBean mapTimestampDeltaServiceLocatorFactoryBean() { + var factoryBean = new ServiceLocatorFactoryBean(); + factoryBean.setServiceLocatorInterface(MapTimestampDeltaAlgorithmFactory.class); + return factoryBean; + } +} diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/timestamp_delta/TimestampDeltaConstants.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/timestamp_delta/TimestampDeltaConstants.java new file mode 100644 index 00000000..8f73e778 --- /dev/null +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/timestamp_delta/TimestampDeltaConstants.java @@ -0,0 +1,8 @@ +package us.dot.its.jpo.conflictmonitor.monitor.algorithms.timestamp_delta; + +public class TimestampDeltaConstants { + public static final String DEFAULT_SPAT_TIMESTAMP_DELTA_ALGORITHM = "defaultSpatTimestampDeltaAlgorithm"; + public static final String DEFAULT_MAP_TIMESTAMP_DELTA_ALGORITHM = "defaultMapTimestampDeltaAlgorithm"; + public static final String ALTERNATE_SPAT_TIMESTAMP_DELTA_ALGORITHM = "alternateSpatTimestampDeltaAlgorithm"; + public static final String ALTERNATE_MAP_TIMESTAMP_DELTA_ALGORITHM = "alternateMapTimestampDeltaAlgorithm"; +} diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/timestamp_delta/map/MapTimestampDeltaAlgorithm.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/timestamp_delta/map/MapTimestampDeltaAlgorithm.java new file mode 100644 index 00000000..87dc8e07 --- /dev/null +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/timestamp_delta/map/MapTimestampDeltaAlgorithm.java @@ -0,0 +1,7 @@ +package us.dot.its.jpo.conflictmonitor.monitor.algorithms.timestamp_delta.map; + +import us.dot.its.jpo.conflictmonitor.monitor.algorithms.timestamp_delta.BaseTimestampDeltaAlgorithm; + +public interface MapTimestampDeltaAlgorithm + extends BaseTimestampDeltaAlgorithm { +} diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/timestamp_delta/map/MapTimestampDeltaAlgorithmFactory.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/timestamp_delta/map/MapTimestampDeltaAlgorithmFactory.java new file mode 100644 index 00000000..8615c949 --- /dev/null +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/timestamp_delta/map/MapTimestampDeltaAlgorithmFactory.java @@ -0,0 +1,5 @@ +package us.dot.its.jpo.conflictmonitor.monitor.algorithms.timestamp_delta.map; + +public interface MapTimestampDeltaAlgorithmFactory { + MapTimestampDeltaAlgorithm getAlgorithm(String algorithmName); +} diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/timestamp_delta/map/MapTimestampDeltaParameters.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/timestamp_delta/map/MapTimestampDeltaParameters.java new file mode 100644 index 00000000..6011bba5 --- /dev/null +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/timestamp_delta/map/MapTimestampDeltaParameters.java @@ -0,0 +1,60 @@ +package us.dot.its.jpo.conflictmonitor.monitor.algorithms.timestamp_delta.map; + +import lombok.Data; +import lombok.Generated; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; +import us.dot.its.jpo.conflictmonitor.monitor.algorithms.timestamp_delta.ITimestampDeltaParameters; +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.DEFAULT; +import static us.dot.its.jpo.conflictmonitor.monitor.models.config.UpdateType.READ_ONLY; + +@Data +@Generated +@Component +@ConfigurationProperties(prefix = "map.timestamp.delta") +@ConfigDataClass +public class MapTimestampDeltaParameters implements ITimestampDeltaParameters { + + @ConfigData(key = "map.timestamp.delta.algorithm", + description = "The algorithm to use", + updateType = READ_ONLY) + volatile String algorithm; + + @ConfigData(key = "map.timestamp.delta.outputTopicName", + description = "Output Kafka topic", + updateType = READ_ONLY) + volatile String outputTopicName; + + @ConfigData(key = "map.timestamp.delta.maxDeltaMilliseconds", + description = "Timestamp delta above which an event is triggered", + updateType = DEFAULT) + volatile int maxDeltaMilliseconds; + + @ConfigData(key = "map.timestamp.delta.debug", + description = "Whether to log diagnostic info", + updateType = DEFAULT) + volatile boolean debug; + + @ConfigData(key = "map.timestamp.delta.keyStoreName", + description = "Name of sate store for intersection keys with events", + updateType = READ_ONLY) + volatile String keyStoreName; + + @ConfigData(key = "map.timestamp.delta.eventStoreName", + description = "Name of versioned state store to aggregate events", + updateType = READ_ONLY) + volatile String eventStoreName; + + @ConfigData(key = "map.timestamp.delta.retentionTimeMinutes", + description = "Retention time of the event state store", + updateType = DEFAULT) + volatile int retentionTimeMinutes; + + @ConfigData(key = "map.timestamp.delta.notificationTopicName", + description = "Name of topic to send notifications to", + updateType = READ_ONLY) + volatile String notificationTopicName; +} diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/timestamp_delta/map/MapTimestampDeltaStreamsAlgorithm.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/timestamp_delta/map/MapTimestampDeltaStreamsAlgorithm.java new file mode 100644 index 00000000..f5a61969 --- /dev/null +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/timestamp_delta/map/MapTimestampDeltaStreamsAlgorithm.java @@ -0,0 +1,9 @@ +package us.dot.its.jpo.conflictmonitor.monitor.algorithms.timestamp_delta.map; + +import us.dot.its.jpo.conflictmonitor.monitor.algorithms.timestamp_delta.BaseTimestampDeltaStreamsAlgorithm; +import us.dot.its.jpo.geojsonconverter.pojos.geojson.LineString; +import us.dot.its.jpo.geojsonconverter.pojos.geojson.map.ProcessedMap; + +public interface MapTimestampDeltaStreamsAlgorithm + extends MapTimestampDeltaAlgorithm, BaseTimestampDeltaStreamsAlgorithm> { +} diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/timestamp_delta/spat/SpatTimestampDeltaAlgorithm.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/timestamp_delta/spat/SpatTimestampDeltaAlgorithm.java new file mode 100644 index 00000000..9b24e7c8 --- /dev/null +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/timestamp_delta/spat/SpatTimestampDeltaAlgorithm.java @@ -0,0 +1,7 @@ +package us.dot.its.jpo.conflictmonitor.monitor.algorithms.timestamp_delta.spat; + +import us.dot.its.jpo.conflictmonitor.monitor.algorithms.timestamp_delta.BaseTimestampDeltaAlgorithm; + +public interface SpatTimestampDeltaAlgorithm + extends BaseTimestampDeltaAlgorithm { +} diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/timestamp_delta/spat/SpatTimestampDeltaAlgorithmFactory.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/timestamp_delta/spat/SpatTimestampDeltaAlgorithmFactory.java new file mode 100644 index 00000000..8ef5bba9 --- /dev/null +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/timestamp_delta/spat/SpatTimestampDeltaAlgorithmFactory.java @@ -0,0 +1,5 @@ +package us.dot.its.jpo.conflictmonitor.monitor.algorithms.timestamp_delta.spat; + +public interface SpatTimestampDeltaAlgorithmFactory { + SpatTimestampDeltaAlgorithm getAlgorithm(String algorithmName); +} diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/timestamp_delta/spat/SpatTimestampDeltaParameters.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/timestamp_delta/spat/SpatTimestampDeltaParameters.java new file mode 100644 index 00000000..17afd254 --- /dev/null +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/timestamp_delta/spat/SpatTimestampDeltaParameters.java @@ -0,0 +1,60 @@ +package us.dot.its.jpo.conflictmonitor.monitor.algorithms.timestamp_delta.spat; + +import lombok.Data; +import lombok.Generated; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; +import us.dot.its.jpo.conflictmonitor.monitor.algorithms.timestamp_delta.ITimestampDeltaParameters; +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.DEFAULT; +import static us.dot.its.jpo.conflictmonitor.monitor.models.config.UpdateType.READ_ONLY; + +@Data +@Generated +@Component +@ConfigurationProperties(prefix = "spat.timestamp.delta") +@ConfigDataClass +public class SpatTimestampDeltaParameters implements ITimestampDeltaParameters { + + @ConfigData(key = "spat.timestamp.delta.algorithm", + description = "The algorithm to use", + updateType = READ_ONLY) + volatile String algorithm; + + @ConfigData(key = "spat.timestamp.delta.outputTopicName", + description = "Output Kafka topic", + updateType = READ_ONLY) + volatile String outputTopicName; + + @ConfigData(key = "spat.timestamp.delta.maxDeltaMilliseconds", + description = "Timestamp delta above which an event is triggered", + updateType = DEFAULT) + volatile int maxDeltaMilliseconds; + + @ConfigData(key = "spat.timestamp.delta.debug", + description = "Whether to log diagnostic info", + updateType = DEFAULT) + volatile boolean debug; + + @ConfigData(key = "spat.timestamp.delta.keyStoreName", + description = "Name of sate store for intersection keys with events", + updateType = READ_ONLY) + volatile String keyStoreName; + + @ConfigData(key = "spat.timestamp.delta.eventStoreName", + description = "Name of versioned state store to aggregate events", + updateType = READ_ONLY) + volatile String eventStoreName; + + @ConfigData(key = "spat.timestamp.delta.retentionTimeMinutes", + description = "Retention time of the event state store", + updateType = DEFAULT) + volatile int retentionTimeMinutes; + + @ConfigData(key = "spat.timestamp.delta.notificationTopicName", + description = "Name of topic to send notifications to", + updateType = READ_ONLY) + volatile String notificationTopicName; +} diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/timestamp_delta/spat/SpatTimestampDeltaStreamsAlgorithm.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/timestamp_delta/spat/SpatTimestampDeltaStreamsAlgorithm.java new file mode 100644 index 00000000..c8584052 --- /dev/null +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/timestamp_delta/spat/SpatTimestampDeltaStreamsAlgorithm.java @@ -0,0 +1,8 @@ +package us.dot.its.jpo.conflictmonitor.monitor.algorithms.timestamp_delta.spat; + +import us.dot.its.jpo.conflictmonitor.monitor.algorithms.timestamp_delta.BaseTimestampDeltaStreamsAlgorithm; +import us.dot.its.jpo.geojsonconverter.pojos.spat.ProcessedSpat; + +public interface SpatTimestampDeltaStreamsAlgorithm + extends SpatTimestampDeltaAlgorithm, BaseTimestampDeltaStreamsAlgorithm { +} diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/validation/ValidationAlgorithms.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/validation/ValidationAlgorithms.java index b699e856..9fb06b3c 100644 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/validation/ValidationAlgorithms.java +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/validation/ValidationAlgorithms.java @@ -9,7 +9,7 @@ import us.dot.its.jpo.conflictmonitor.monitor.algorithms.validation.spat.SpatValidationStreamsAlgorithmFactory; /** - * Configuration defining {@link FactoryBeans}s for locating Broadcast Rate algorithms. + * Configuration defining {@link FactoryBean}s for locating Broadcast Rate algorithms. */ @Configuration public class ValidationAlgorithms { diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/validation/ValidationConstants.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/validation/ValidationConstants.java index b5ccc2bf..bb39ffac 100644 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/validation/ValidationConstants.java +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/validation/ValidationConstants.java @@ -8,11 +8,11 @@ public final class ValidationConstants { public static final String ALTERNATE_MAP_VALIDATION_ALGORITHM = "alternateMapValidationAlgorithm"; public static final String ALTERNATE_SPAT_VALIDATION_ALGORITHM = "alternateSpatValidationAlgorithm"; - public static final String DEFAULT_MAP_VALIDATION_PARAMETERS = "defaultMapValidationParameters"; - public static final String DEFAULT_SPAT_VALIDATION_PARAMETERS = "defaultSpatValidationParameters"; - - public static final String DEBUG_MAP_VALIDATION_PARAMETERS = "debugMapValidationParameters"; - public static final String DEBUG_SPAT_VALIDATION_PARAMETERS = "debugSpatValidationParameters"; +// public static final String DEFAULT_MAP_VALIDATION_PARAMETERS = "defaultMapValidationParameters"; +// public static final String DEFAULT_SPAT_VALIDATION_PARAMETERS = "defaultSpatValidationParameters"; +// +// public static final String DEBUG_MAP_VALIDATION_PARAMETERS = "debugMapValidationParameters"; +// public static final String DEBUG_SPAT_VALIDATION_PARAMETERS = "debugSpatValidationParameters"; } diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/validation/map/MapValidationAlgorithm.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/validation/map/MapValidationAlgorithm.java index 3670c744..fb393418 100644 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/validation/map/MapValidationAlgorithm.java +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/validation/map/MapValidationAlgorithm.java @@ -1,6 +1,11 @@ package us.dot.its.jpo.conflictmonitor.monitor.algorithms.validation.map; import us.dot.its.jpo.conflictmonitor.monitor.algorithms.Algorithm; +import us.dot.its.jpo.conflictmonitor.monitor.algorithms.timestamp_delta.map.MapTimestampDeltaAlgorithm; public interface MapValidationAlgorithm - extends Algorithm {} + extends Algorithm { + + MapTimestampDeltaAlgorithm getTimestampDeltaAlgorithm(); + void setTimestampDeltaAlgorithm(MapTimestampDeltaAlgorithm timestampDeltaAlgorithm); +} diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/validation/map/MapValidationStreamsAlgorithm.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/validation/map/MapValidationStreamsAlgorithm.java index eadff3f7..64efde08 100644 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/validation/map/MapValidationStreamsAlgorithm.java +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/validation/map/MapValidationStreamsAlgorithm.java @@ -2,5 +2,7 @@ import us.dot.its.jpo.conflictmonitor.monitor.algorithms.StreamsTopology; + public interface MapValidationStreamsAlgorithm - extends MapValidationAlgorithm, StreamsTopology {} + extends MapValidationAlgorithm, StreamsTopology { +} diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/validation/spat/SpatValidationAlgorithm.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/validation/spat/SpatValidationAlgorithm.java index 6efc4707..98fd6dd8 100644 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/validation/spat/SpatValidationAlgorithm.java +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/algorithms/validation/spat/SpatValidationAlgorithm.java @@ -1,7 +1,12 @@ package us.dot.its.jpo.conflictmonitor.monitor.algorithms.validation.spat; import us.dot.its.jpo.conflictmonitor.monitor.algorithms.Algorithm; +import us.dot.its.jpo.conflictmonitor.monitor.algorithms.timestamp_delta.spat.SpatTimestampDeltaAlgorithm; public interface SpatValidationAlgorithm - extends Algorithm {} + extends Algorithm { + + SpatTimestampDeltaAlgorithm getTimestampDeltaAlgorithm(); + void setTimestampDeltaAlgorithm(SpatTimestampDeltaAlgorithm timestampDeltaAlgorithm); +} 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 e348c03c..ff8fa3e9 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 @@ -151,10 +151,12 @@ public StopLineStopEvent getStopLineStopEvent(StopLineStopParameters parameters, event.setTimeStoppedDuringRed(spatStatistics.getTimeStoppedDuringRed()); event.setTimeStoppedDuringYellow(spatStatistics.getTimeStoppedDuringYellow()); event.setTimeStoppedDuringGreen(spatStatistics.getTimeStoppedDuringGreen()); + event.setTimeStoppedDuringDark(spatStatistics.getTimeStoppedDuringDark()); }else{ event.setTimeStoppedDuringRed(-1); event.setTimeStoppedDuringYellow(-1); event.setTimeStoppedDuringGreen(-1); + event.setTimeStoppedDuringDark(-1); event.setSignalGroup(-1); event.setInitialEventState(null); event.setFinalEventState(null); diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/health/TopologyGraph.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/health/TopologyGraph.java new file mode 100644 index 00000000..10188ed6 --- /dev/null +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/health/TopologyGraph.java @@ -0,0 +1,242 @@ +package us.dot.its.jpo.conflictmonitor.monitor.health; + + + +import com.google.common.collect.ImmutableSet; +import lombok.extern.slf4j.Slf4j; +import org.apache.kafka.streams.Topology; +import org.apache.kafka.streams.TopologyDescription; +import org.jgrapht.Graph; +import org.jgrapht.graph.DefaultDirectedGraph; +import org.jgrapht.graph.DefaultEdge; +import org.jgrapht.nio.DefaultAttribute; +import org.jgrapht.nio.dot.DOTExporter; + +import java.io.StringWriter; +import java.io.Writer; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +@Slf4j +public class TopologyGraph { + + final Graph g; + + + + final LinkList links; + + public TopologyGraph(final String name, final Topology topology) { + g = new DefaultDirectedGraph<>(DefaultEdge.class); + links = new LinkList(); + graphTopology(name, topology); + removeUnlinkedGlobalSubtopologies(); + for (Link link : links) { + g.addEdge(link.from, link.to); + } + } + + public TopologyGraph(Map topologyMap) { + try { + g = new DefaultDirectedGraph<>(DefaultEdge.class); + links = new LinkList(); + + // Add nodes to the graph + for (var entry : topologyMap.entrySet()) { + final String name = entry.getKey(); + final Topology topology = entry.getValue(); + graphTopology(name, topology); + } + + removeUnlinkedGlobalSubtopologies(); + + // Add edges to the graph + for (Link link : links) { + g.addEdge(link.from, link.to); + } + }catch (Exception ex) { + log.error("Exception creating graph", ex); + throw new RuntimeException(ex); + } + } + + private void removeUnlinkedGlobalSubtopologies() { + // Remove global subtopology nodes that aren't linked to anything (no global stores or processors) + ImmutableSet vertices = ImmutableSet.copyOf(g.vertexSet()); + for (final Vertex v : vertices) { + if (v.isGlobal) { + boolean hasAnyLinks = links.stream().anyMatch(link -> link.from.equals(v) || link.to.equals(v)); + if (!hasAnyLinks) { + g.removeVertex(v); + } + } + } + } + + + void graphTopology(final String name, final Topology topology) { + final Vertex topologyVertex = vertexTopology(name); + g.addVertex(topologyVertex); + TopologyDescription description = topology.describe(); + description.globalStores().forEach(globalStore -> graphGlobalStore(name, topologyVertex, globalStore)); + description.subtopologies().forEach(subtopology -> graphSubtopology(name, subtopology)); + } + + public String exportDOT() { + DOTExporter exporter = getVertexDefaultEdgeDOTExporter(); + Writer writer = new StringWriter(); + exporter.exportGraph(g, writer); + + // Hack for things DOTExporter doesn't support + String dot = writer.toString(); + var lines = new ArrayList<>(dot.lines().toList()); + lines.add(1, " node [fontsize=10.0 fontname=Arial];"); + dot = lines.stream().collect(Collectors.joining(System.lineSeparator())); + return dot; + } + + private static DOTExporter getVertexDefaultEdgeDOTExporter() { + DOTExporter exporter = new DOTExporter<>(vertex -> vertex.id); + exporter.setVertexAttributeProvider(vertex -> + Map.of("label", DefaultAttribute.createAttribute(vertex.label), + "shape", DefaultAttribute.createAttribute( + switch(vertex.type) { + case "store" -> "cylinder"; + case "subtopology" -> "octagon"; + default -> "box"; + })) + ); + return exporter; + } + + + void graphGlobalStore(final String topologyName, final Vertex topologyVertex, final TopologyDescription.GlobalStore globalStore) { + //g.addVertex(label(globalStore)); + graphTopics(topologyVertex, globalStore.source()); + graphProcessor(topologyName, topologyVertex, globalStore.processor()); + } + + void graphSubtopology(final String topologyName, final TopologyDescription.Subtopology subtopology) { + g.addVertex(vertexSubtopology(topologyName, subtopology)); + subtopology.nodes().forEach(node -> { + graphNode(topologyName, vertexSubtopology(topologyName, subtopology), node); + }); + } + + void graphNode(final String topologyName, final Vertex topologyVertex, final TopologyDescription.Node node) { + if (node instanceof TopologyDescription.Source source) { + graphTopics(topologyVertex, source); + } else if (node instanceof TopologyDescription.Sink sink) { + graphTopics(topologyVertex, sink); + } else if (node instanceof TopologyDescription.Processor processor) { + graphProcessor(topologyName, topologyVertex, processor); + } + } + + + void graphProcessor(final String topologyName, final Vertex topologyVertex, final TopologyDescription.Processor processor) { + processor.stores().forEach(store -> { + Vertex storeVertex = vertexStore(topologyName, store); + g.addVertex(storeVertex); + // Add links in both directions since processors can read and write stores + links.add(topologyVertex, storeVertex); + links.add(storeVertex, topologyVertex); + }); + } + + void graphTopics(final Vertex topologyVertex, final TopologyDescription.Source source) { + Pattern pattern = source.topicPattern(); + String topicPattern = pattern != null ? pattern.pattern() : null; + if (topicPattern != null) { + Vertex topicVertex = vertexTopic(topicPattern); + g.addVertex(topicVertex); + links.add(topicVertex, topologyVertex); + } + + Set topicSet = source.topicSet(); + if (topicSet != null) { + topicSet.forEach(topic -> { + Vertex topicVertex = vertexTopic(topic); + g.addVertex(topicVertex); + links.add(topicVertex, topologyVertex); + }); + } + } + + void graphTopics(final Vertex topologyVertex, final TopologyDescription.Sink sink) { + final String extractorClass = sink.topicNameExtractor() != null ? sink.topicNameExtractor().getClass().getName() : null; + if (extractorClass != null) { + Vertex topicVertex = vertexTopic(extractorClass); + g.addVertex(topicVertex); + links.add(topologyVertex, topicVertex); + } + + final String topic = sink.topic(); + if (topic != null) { + Vertex topicVertex = vertexTopic(topic); + g.addVertex(topicVertex); + links.add(topologyVertex, topicVertex); + } + } + + + final String SUBTOPOLOGY = "subtopology"; + final String STORE = "store"; + final String TOPIC = "topic"; + final String GLOBAL = "global"; + + Vertex vertexTopology(String name) { + return new Vertex( + name + "_" + SUBTOPOLOGY + "_" + GLOBAL, + SUBTOPOLOGY, + name + " " + SUBTOPOLOGY + " " + GLOBAL, + true); + } + + Vertex vertexSubtopology(final String topologyName, final TopologyDescription.Subtopology subtopology) { + return new Vertex( + topologyName + "_" + SUBTOPOLOGY + "_" + subtopology.id(), + SUBTOPOLOGY, + topologyName + " " + SUBTOPOLOGY + " " + subtopology.id(), + true); + } + + Vertex vertexStore(final String topologyName, final String store) { + // Prefix topology name to store id to make sure it is unique for multiple topologies + String uniqueStoreId = topologyName + "-" + store; + return new Vertex(normalizeId(uniqueStoreId), STORE, store); + } + + Vertex vertexTopic(final String topic) { + return new Vertex(normalizeId(topic), TOPIC, topic); + } + + String normalizeId(String id) { + return id.replace(".", "_").replace("-", "_"); + } + + static class LinkList extends ArrayList { + public void add(Vertex from, Vertex to) { + this.add(new Link(from, to)); + } + } + + record Link( + Vertex from, + Vertex to) {} + + record Vertex( + String id, + String type, + String label, + boolean isGlobal) { + public Vertex(final String id, final String type, final String label) { + this(id, type, label, false); + } + } + +} diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/AllowConcurrentPermissiveList.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/AllowConcurrentPermissiveList.java deleted file mode 100644 index 739e286d..00000000 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/AllowConcurrentPermissiveList.java +++ /dev/null @@ -1,16 +0,0 @@ -package us.dot.its.jpo.conflictmonitor.monitor.models; - -import java.util.List; - -import lombok.AllArgsConstructor; -import lombok.Generated; -import lombok.Getter; -import lombok.Setter; - -@Getter -@Setter -@AllArgsConstructor -@Generated -public class AllowConcurrentPermissiveList { - private List allowedConcurrentList; -} diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/AllowedConcurrentPermissive.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/AllowedConcurrentPermissive.java deleted file mode 100644 index 0e9d944d..00000000 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/AllowedConcurrentPermissive.java +++ /dev/null @@ -1,24 +0,0 @@ -package us.dot.its.jpo.conflictmonitor.monitor.models; - - -import lombok.AllArgsConstructor; -import lombok.Generated; -import lombok.Getter; -import lombok.Setter; - -@Getter -@Setter -@AllArgsConstructor -@Generated -public class AllowedConcurrentPermissive { - private Integer intersectionID; - private Integer roadRegulatorID; - - private int firstIngressLane; - private int secondIngressLane; - - private int firstEgressLane; - private int secondEgressLane; - - private boolean allowConcurrent = true; -} \ No newline at end of file diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/LaneConnection.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/LaneConnection.java index 34eef598..69913d90 100644 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/LaneConnection.java +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/LaneConnection.java @@ -191,14 +191,6 @@ public boolean detectConflict(LaneConnection otherConnection) { if (connectingPath.intersects(otherConnection.connectingPath)) { if (this.signalGroup == otherConnection.signalGroup) { - // System.out.println("Conflict Detected between " + this.ingress.getLaneID() + "," - // + this.egress.getLaneID() + " and " + otherConnection.ingress.getLaneID() + "," - // + otherConnection.egress.getLaneID()); - // System.out.println("First Path"); - // printConnectingPath(); - // System.out.println("Second Path"); - // otherConnection.printConnectingPath(); - return true; } } diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/assessments/StopLineStopAssessmentGroup.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/assessments/StopLineStopAssessmentGroup.java index 5588f0aa..8db46789 100644 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/assessments/StopLineStopAssessmentGroup.java +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/assessments/StopLineStopAssessmentGroup.java @@ -4,7 +4,6 @@ import lombok.Getter; import lombok.Setter; -import us.dot.its.jpo.conflictmonitor.monitor.models.events.StopLinePassageEvent; import us.dot.its.jpo.conflictmonitor.monitor.models.events.StopLineStopEvent; @Getter @@ -24,6 +23,7 @@ public void addStopLineStopEvent(StopLineStopEvent event){ timeStoppedOnRed += event.getTimeStoppedDuringRed(); timeStoppedOnYellow += event.getTimeStoppedDuringYellow(); timeStoppedOnGreen += event.getTimeStoppedDuringGreen(); + timeStoppedOnDark += event.getTimeStoppedDuringDark(); } } diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/concurrent_permissive/ConnectedLanes.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/concurrent_permissive/ConnectedLanes.java new file mode 100644 index 00000000..6ed80c78 --- /dev/null +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/concurrent_permissive/ConnectedLanes.java @@ -0,0 +1,16 @@ +package us.dot.its.jpo.conflictmonitor.monitor.models.concurrent_permissive; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * A pair of connected lane IDs + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class ConnectedLanes { + int ingressLaneID; + int egressLaneID; +} diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/concurrent_permissive/ConnectedLanesPair.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/concurrent_permissive/ConnectedLanesPair.java new file mode 100644 index 00000000..71b6c4fd --- /dev/null +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/concurrent_permissive/ConnectedLanesPair.java @@ -0,0 +1,73 @@ +package us.dot.its.jpo.conflictmonitor.monitor.models.concurrent_permissive; + +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Sets; +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; +import us.dot.its.jpo.conflictmonitor.monitor.models.IntersectionRegion; + +import java.util.Objects; +import java.util.Set; + +/** + * An unordered pair of connected lanes in the same intersection. + * Equals and HashCode are defined so the order of the 'first' and 'second' set of connected lanes doesn't matter. + */ +@Getter +@Setter +@ToString +public class ConnectedLanesPair { + + Integer intersectionID; + Integer roadRegulatorID; + + ConnectedLanes first; + ConnectedLanes second; + + public ConnectedLanesPair() {} + + public ConnectedLanesPair(Integer intersectionID, Integer roadRegulatorID, int firstIngressLaneId, int firstEgressLaneId, + int secondIngressLaneId, int secondEgressLaneId) { + this.intersectionID = intersectionID; + this.roadRegulatorID = roadRegulatorID; + this.first = new ConnectedLanes(firstIngressLaneId, firstEgressLaneId); + this.second = new ConnectedLanes(secondIngressLaneId, secondEgressLaneId); + } + + public Set connectedLanesSet() { + var setBuilder = ImmutableSet.builder(); + if (first != null) setBuilder.add(first); + if (second != null) setBuilder.add(second); + return setBuilder.build(); + } + + public IntersectionRegion intersectionRegion() { + return new IntersectionRegion(intersectionID, roadRegulatorID); + } + + @Override + public int hashCode() { + return Objects.hash(intersectionRegion(), connectedLanesSet()); + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof ConnectedLanesPair other)) return false; + + // Compare intersection/region + IntersectionRegion thisIntersection = intersectionRegion(); + IntersectionRegion otherIntersection = other.intersectionRegion(); + if (!Objects.equals(thisIntersection, otherIntersection)) { + return false; + } + + // If intersection/region are the same, compare ConnectedLanes + Set thisSet = connectedLanesSet(); + Set otherSet = other.connectedLanesSet(); + Set diff = Sets.symmetricDifference(thisSet, otherSet); + return diff.isEmpty(); + } + + +} diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/concurrent_permissive/ConnectedLanesPairList.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/concurrent_permissive/ConnectedLanesPairList.java new file mode 100644 index 00000000..332acff8 --- /dev/null +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/concurrent_permissive/ConnectedLanesPairList.java @@ -0,0 +1,12 @@ +package us.dot.its.jpo.conflictmonitor.monitor.models.concurrent_permissive; + +import java.util.ArrayList; +import java.util.Collection; + +public class ConnectedLanesPairList + extends ArrayList { + + public ConnectedLanesPairList() { super(); } + + public ConnectedLanesPairList(Collection coll) { super(coll); } +} diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/config/BaseConfigMap.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/config/BaseConfigMap.java deleted file mode 100644 index 7bf76484..00000000 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/config/BaseConfigMap.java +++ /dev/null @@ -1,19 +0,0 @@ -package us.dot.its.jpo.conflictmonitor.monitor.models.config; - -import java.util.Map; -import java.util.TreeMap; - -/** - * Base class for a map of key to configuration settings. Sorted by key. - * - * @param - Type of configuration settings - */ -@Deprecated -public abstract class BaseConfigMap> extends TreeMap { - - public BaseConfigMap() { } - - public BaseConfigMap(Map configMap) { - this.putAll(configMap); - } -} diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/config/DefaultBooleanConfig.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/config/DefaultBooleanConfig.java deleted file mode 100644 index b71dfde1..00000000 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/config/DefaultBooleanConfig.java +++ /dev/null @@ -1,3 +0,0 @@ -package us.dot.its.jpo.conflictmonitor.monitor.models.config; - -public class DefaultBooleanConfig extends DefaultConfig {} diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/config/DefaultConfigCollection.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/config/DefaultConfigCollection.java deleted file mode 100644 index eca3fd8e..00000000 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/config/DefaultConfigCollection.java +++ /dev/null @@ -1,13 +0,0 @@ -package us.dot.its.jpo.conflictmonitor.monitor.models.config; - -import java.util.Collection; - -public class DefaultConfigCollection extends ConfigCollection> { - - public DefaultConfigCollection() { - super(); - } - public DefaultConfigCollection(Collection> configs) { - super(configs); - } -} diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/config/DefaultDoubleConfig.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/config/DefaultDoubleConfig.java deleted file mode 100644 index f6c1cbd8..00000000 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/config/DefaultDoubleConfig.java +++ /dev/null @@ -1,6 +0,0 @@ -package us.dot.its.jpo.conflictmonitor.monitor.models.config; - - - - -public class DefaultDoubleConfig extends DefaultConfig {} diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/config/DefaultIntConfig.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/config/DefaultIntConfig.java deleted file mode 100644 index 37212dac..00000000 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/config/DefaultIntConfig.java +++ /dev/null @@ -1,3 +0,0 @@ -package us.dot.its.jpo.conflictmonitor.monitor.models.config; - -public class DefaultIntConfig extends DefaultConfig {} diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/config/DefaultLongConfig.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/config/DefaultLongConfig.java deleted file mode 100644 index 80f1f2de..00000000 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/config/DefaultLongConfig.java +++ /dev/null @@ -1,3 +0,0 @@ -package us.dot.its.jpo.conflictmonitor.monitor.models.config; - -public class DefaultLongConfig extends DefaultConfig {} diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/config/DefaultStringConfig.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/config/DefaultStringConfig.java deleted file mode 100644 index 89d6654d..00000000 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/config/DefaultStringConfig.java +++ /dev/null @@ -1,5 +0,0 @@ -package us.dot.its.jpo.conflictmonitor.monitor.models.config; - -public class DefaultStringConfig extends DefaultConfig { - -} diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/config/IntersectionConfig.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/config/IntersectionConfig.java index a19be89d..9ddc9f0e 100644 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/config/IntersectionConfig.java +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/config/IntersectionConfig.java @@ -2,19 +2,20 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; -import org.springframework.data.annotation.Id; - - import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.Setter; +import org.springframework.data.annotation.Id; + +@Setter +@Getter @EqualsAndHashCode(callSuper = true) @JsonIgnoreProperties(ignoreUnknown = true) public class IntersectionConfig extends Config{ - @Getter @Setter private int roadRegulatorID; - @Getter @Setter private int intersectionID; + private int roadRegulatorID; + private int intersectionID; public IntersectionConfig(){ super(); diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/config/IntersectionConfigCollection.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/config/IntersectionConfigCollection.java deleted file mode 100644 index 2cff845e..00000000 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/config/IntersectionConfigCollection.java +++ /dev/null @@ -1,14 +0,0 @@ -package us.dot.its.jpo.conflictmonitor.monitor.models.config; - -import java.util.Collection; - -public class IntersectionConfigCollection extends ConfigCollection> { - - public IntersectionConfigCollection() { - super(); - } - - public IntersectionConfigCollection(Collection> configs) { - super(configs); - } -} diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/config/IntersectionKey.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/config/IntersectionKey.java deleted file mode 100644 index 022623eb..00000000 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/config/IntersectionKey.java +++ /dev/null @@ -1,96 +0,0 @@ -//package us.dot.its.jpo.conflictmonitor.monitor.models.config; -// -//import com.fasterxml.jackson.core.JsonProcessingException; -//import lombok.Getter; -//import lombok.Setter; -//import org.apache.commons.lang3.ObjectUtils; -//import org.slf4j.Logger; -//import org.slf4j.LoggerFactory; -//import us.dot.its.jpo.geojsonconverter.DateJsonMapper; -//import us.dot.its.jpo.geojsonconverter.partitioner.RsuIntersectionKey; -// -//import javax.annotation.Nullable; -//import java.util.Objects; -// -//@Getter -//@Setter -//public class IntersectionKey implements Comparable { -// -// private static final Logger logger = LoggerFactory.getLogger(IntersectionKey.class); -// -// /** -// * Optional. Set to 0 if undefined. -// */ -// int roadRegulatorID; -// -// /** -// * Required -// */ -// int intersectionID; -// -// public IntersectionKey() {} -// -// public IntersectionKey(int roadRegulatorID, int intersectionID) { -// this.roadRegulatorID = roadRegulatorID; -// this.intersectionID = intersectionID; -// } -// -// public IntersectionKey(int intersectionID) { -// this.roadRegulatorID = 0; -// this.intersectionID = intersectionID; -// } -// -// @Override -// public boolean equals(Object o) { -// if (this == o) return true; -// if (o == null) return false; -// if (!(o instanceof IntersectionKey)) return false; -// IntersectionKey otherKey = (IntersectionKey) o; -// -// // Compare region only if it is defined for both objects -// if (roadRegulatorID > 0 && otherKey.getRoadRegulatorID() > 0) { -// if (roadRegulatorID != otherKey.getRoadRegulatorID()) { -// return false; -// } -// } -// -// return intersectionID == otherKey.intersectionID; -// } -// -// @Override -// public int hashCode() { -// // hash code doesn't depend on region/ regulator ID -// return Objects.hash(intersectionID); -// } -// -// @Override -// public int compareTo(@Nullable IntersectionKey other) { -// if (other == null) return 1; -// -// // Compare region only if it is defined for both objects -// if (roadRegulatorID > 0 && other.getRoadRegulatorID() > 0) { -// int compareRegion = Integer.compare(roadRegulatorID, other.getRoadRegulatorID()); -// if (compareRegion != 0) { -// return compareRegion; -// } -// } -// -// return Integer.compare(intersectionID, other.getIntersectionID()); -// } -// -// @Override -// public String toString() { -// var mapper = DateJsonMapper.getInstance(); -// try { -// return mapper.writeValueAsString(this); -// } catch (JsonProcessingException e) { -// logger.error("Error converting IntersectionKey to JSON", e); -// return ""; -// } -// } -// -// // TODO Include region/road regulator ID in RsuIntersectionKey -// public static IntersectionKey fromRsuIntersectionKey(RsuIntersectionKey rsuIntersectionKey) { -// return new IntersectionKey(rsuIntersectionKey.getIntersectionId()); -// } -//} diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/config/RsuConfigKey.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/config/RsuConfigKey.java deleted file mode 100644 index f04e826e..00000000 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/config/RsuConfigKey.java +++ /dev/null @@ -1,75 +0,0 @@ -package us.dot.its.jpo.conflictmonitor.monitor.models.config; - -import org.apache.commons.lang3.ObjectUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.fasterxml.jackson.core.JsonProcessingException; - -import lombok.EqualsAndHashCode; -import lombok.Getter; -import lombok.Setter; -import us.dot.its.jpo.geojsonconverter.DateJsonMapper; -import us.dot.its.jpo.geojsonconverter.partitioner.RsuIdKey; - -/** - * Kafka key for {@link IntersectionConfig} settings - * that implements {@link us.dot.its.jpo.geojsonconverter.partitioner.RsuIdKey} - * - * @deprecated use {@link IntersectionConfigKey} instead - */ -@Deprecated -@EqualsAndHashCode -public class RsuConfigKey implements RsuIdKey, Comparable { - - private static final Logger logger = LoggerFactory.getLogger(RsuConfigKey.class); - - @Setter String rsuId; - - @Getter @Setter String key; - - - @Override - public String getRsuId() { - return rsuId; - } - - - public RsuConfigKey() {} - - - public RsuConfigKey(String rsuId, String key) { - this.rsuId = rsuId; - this.key = key; - } - - - @Override - public int compareTo(RsuConfigKey other) { - if (other == null) return 1; - int compareRsu = ObjectUtils.compare(rsuId, other.getRsuId()); - if (compareRsu != 0) { - return compareRsu; - } else { - return ObjectUtils.compare(key, other.getKey()); - } - } - - @Override - public String toString() { - var mapper = DateJsonMapper.getInstance(); - try { - return mapper.writeValueAsString(this); - } catch (JsonProcessingException e) { - logger.error("Error converting RsuConfigKey to JSON", e); - return ""; - } - } - - - - - -} - - diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/events/BsmRevisionCounterEvent.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/events/BsmRevisionCounterEvent.java new file mode 100644 index 00000000..a1ebff8a --- /dev/null +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/events/BsmRevisionCounterEvent.java @@ -0,0 +1,23 @@ +package us.dot.its.jpo.conflictmonitor.monitor.models.events; + +import lombok.EqualsAndHashCode; +import lombok.Generated; +import lombok.Getter; +import lombok.Setter; +import us.dot.its.jpo.ode.model.OdeBsmData; + +@Getter +@Setter +@EqualsAndHashCode(callSuper=true) +@Generated +public class BsmRevisionCounterEvent extends Event{ + + private OdeBsmData previousBsm; + private OdeBsmData newBsm; + private String message; + + public BsmRevisionCounterEvent(){ + super("BsmRevisionCounter"); + } + +} diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/events/Event.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/events/Event.java index 0c0f9598..7b2eead6 100644 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/events/Event.java +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/events/Event.java @@ -12,6 +12,8 @@ import us.dot.its.jpo.conflictmonitor.monitor.models.events.broadcast_rate.SpatBroadcastRateEvent; import us.dot.its.jpo.conflictmonitor.monitor.models.events.minimum_data.MapMinimumDataEvent; import us.dot.its.jpo.conflictmonitor.monitor.models.events.minimum_data.SpatMinimumDataEvent; +import us.dot.its.jpo.conflictmonitor.monitor.models.events.timestamp_delta.MapTimestampDeltaEvent; +import us.dot.its.jpo.conflictmonitor.monitor.models.events.timestamp_delta.SpatTimestampDeltaEvent; import us.dot.its.jpo.geojsonconverter.DateJsonMapper; import lombok.EqualsAndHashCode; @@ -37,6 +39,11 @@ @JsonSubTypes.Type(value = SpatMinimumDataEvent.class, name = "SpatMinimumData"), @JsonSubTypes.Type(value = MapBroadcastRateEvent.class, name = "MapBroadcastRate"), @JsonSubTypes.Type(value = SpatBroadcastRateEvent.class, name = "SpatBroadcastRate"), + @JsonSubTypes.Type(value = MapRevisionCounterEvent.class, name = "MapRevisionCounter"), + @JsonSubTypes.Type(value = SpatRevisionCounterEvent.class, name = "SpatRevisionCounter"), + @JsonSubTypes.Type(value = BsmRevisionCounterEvent.class, name = "BsmRevisionCounter"), + @JsonSubTypes.Type(value = MapTimestampDeltaEvent.class, name = "MapTimestampDelta"), + @JsonSubTypes.Type(value = SpatTimestampDeltaEvent.class, name = "SpatTimestampDelta") }) @Getter @Setter diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/events/MapRevisionCounterEvent.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/events/MapRevisionCounterEvent.java new file mode 100644 index 00000000..679e798a --- /dev/null +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/events/MapRevisionCounterEvent.java @@ -0,0 +1,23 @@ +package us.dot.its.jpo.conflictmonitor.monitor.models.events; + +import lombok.EqualsAndHashCode; +import lombok.Generated; +import lombok.Getter; +import lombok.Setter; +import us.dot.its.jpo.geojsonconverter.pojos.geojson.map.ProcessedMap; +import us.dot.its.jpo.geojsonconverter.pojos.geojson.LineString; +@Getter +@Setter +@EqualsAndHashCode(callSuper=true) +@Generated +public class MapRevisionCounterEvent extends Event{ + + private ProcessedMap previousMap; + private ProcessedMap newMap; + private String message; + + public MapRevisionCounterEvent(){ + super("MapRevisionCounter"); + } + +} diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/events/SpatRevisionCounterEvent.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/events/SpatRevisionCounterEvent.java new file mode 100644 index 00000000..044cd4e2 --- /dev/null +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/events/SpatRevisionCounterEvent.java @@ -0,0 +1,23 @@ +package us.dot.its.jpo.conflictmonitor.monitor.models.events; + +import lombok.EqualsAndHashCode; +import lombok.Generated; +import lombok.Getter; +import lombok.Setter; +import us.dot.its.jpo.geojsonconverter.pojos.spat.ProcessedSpat; + +@Getter +@Setter +@EqualsAndHashCode(callSuper=true) +@Generated +public class SpatRevisionCounterEvent extends Event{ + + private ProcessedSpat previousSpat; + private ProcessedSpat newSpat; + private String message; + + public SpatRevisionCounterEvent(){ + super("SpatRevisionCounter"); + } + +} diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/events/StopLineStopEvent.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/events/StopLineStopEvent.java index 06401bef..732e5222 100644 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/events/StopLineStopEvent.java +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/events/StopLineStopEvent.java @@ -30,6 +30,7 @@ public class StopLineStopEvent extends Event{ private double timeStoppedDuringRed; private double timeStoppedDuringYellow; private double timeStoppedDuringGreen; + private double timeStoppedDuringDark; public StopLineStopEvent(){ super("StopLineStop"); diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/events/timestamp_delta/BaseTimestampDeltaEvent.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/events/timestamp_delta/BaseTimestampDeltaEvent.java new file mode 100644 index 00000000..30231e74 --- /dev/null +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/events/timestamp_delta/BaseTimestampDeltaEvent.java @@ -0,0 +1,36 @@ +package us.dot.its.jpo.conflictmonitor.monitor.models.events.timestamp_delta; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import lombok.EqualsAndHashCode; +import lombok.Generated; +import lombok.Getter; +import lombok.Setter; +import us.dot.its.jpo.conflictmonitor.monitor.models.events.Event; + +@Getter +@Setter +@EqualsAndHashCode(callSuper = true) +@Generated +@JsonIgnoreProperties(ignoreUnknown = true) +public abstract class BaseTimestampDeltaEvent extends Event { + + public BaseTimestampDeltaEvent(String eventType, String inputType) { + super(eventType); + this.inputType = inputType; + } + + final String inputType; + + /** + * The source RSU device ID + */ + String source; + + /** + * The timestamp difference + */ + TimestampDelta delta; + + + +} diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/events/timestamp_delta/MapTimestampDeltaEvent.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/events/timestamp_delta/MapTimestampDeltaEvent.java new file mode 100644 index 00000000..5076645c --- /dev/null +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/events/timestamp_delta/MapTimestampDeltaEvent.java @@ -0,0 +1,12 @@ +package us.dot.its.jpo.conflictmonitor.monitor.models.events.timestamp_delta; + +import us.dot.its.jpo.geojsonconverter.pojos.geojson.map.ProcessedMap; + +public class MapTimestampDeltaEvent + extends BaseTimestampDeltaEvent { + + public MapTimestampDeltaEvent() { + super("MapTimestampDelta", ProcessedMap.class.getTypeName()); + } + +} diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/events/timestamp_delta/SpatTimestampDeltaEvent.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/events/timestamp_delta/SpatTimestampDeltaEvent.java new file mode 100644 index 00000000..5dcad789 --- /dev/null +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/events/timestamp_delta/SpatTimestampDeltaEvent.java @@ -0,0 +1,10 @@ +package us.dot.its.jpo.conflictmonitor.monitor.models.events.timestamp_delta; + +import us.dot.its.jpo.geojsonconverter.pojos.spat.ProcessedSpat; + +public class SpatTimestampDeltaEvent + extends BaseTimestampDeltaEvent { + public SpatTimestampDeltaEvent() { + super("SpatTimestampDelta", ProcessedSpat.class.getName()); + } +} diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/events/timestamp_delta/TimestampDelta.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/events/timestamp_delta/TimestampDelta.java new file mode 100644 index 00000000..45f565b8 --- /dev/null +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/events/timestamp_delta/TimestampDelta.java @@ -0,0 +1,73 @@ +package us.dot.its.jpo.conflictmonitor.monitor.models.events.timestamp_delta; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.core.JsonProcessingException; +import lombok.*; +import lombok.extern.slf4j.Slf4j; +import us.dot.its.jpo.geojsonconverter.DateJsonMapper; + +@Getter +@Setter +@EqualsAndHashCode +@Generated +@Slf4j +@JsonIgnoreProperties(ignoreUnknown = true) +public class TimestampDelta { + + /** + * The configured max delta (absolute value) + */ + int maxDeltaMillis; + + public void setMaxDeltaMillis(int maxDeltaMillis) { + this.maxDeltaMillis = Math.abs(maxDeltaMillis); + } + + /** + * The ODE ingest timestamp + */ + long odeIngestTimestampMillis; + + /** + * The timestamp extracted from the message + */ + long messageTimestampMillis; + + /** + * @return The actual timestamp delta, signed + */ + public long getDeltaMillis() { + return odeIngestTimestampMillis - messageTimestampMillis; + } + + /** + * @return The magnitude of the delta, always positive. + */ + public long getAbsDeltaMillis() { + return Math.abs(getDeltaMillis()); + } + + public boolean emitEvent() { + // If OdeReceivedAt is earlier than message timestamp, always emit an event + // otherwise emit one if the lag delta exceeds the max + return isOdeIngestBeforeMessageTimestamp() || isDeltaGreaterThanMax(); + } + + public boolean isOdeIngestBeforeMessageTimestamp() { + return getDeltaMillis() < 0; + } + + public boolean isDeltaGreaterThanMax() { + return getAbsDeltaMillis() > maxDeltaMillis; + } + + @Override + public String toString() { + try { + return DateJsonMapper.getInstance().writeValueAsString(this); + } catch (JsonProcessingException e) { + log.error("Exception serializing TimestampDelta Event to JSON", e); + } + return ""; + } +} diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/notifications/Notification.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/notifications/Notification.java index e505c328..cc699646 100644 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/notifications/Notification.java +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/notifications/Notification.java @@ -17,6 +17,8 @@ import lombok.Getter; import lombok.Setter; import us.dot.its.jpo.conflictmonitor.monitor.models.notifications.app_health.KafkaStreamsAnomalyNotification; +import us.dot.its.jpo.conflictmonitor.monitor.models.notifications.timestamp_delta.MapTimestampDeltaNotification; +import us.dot.its.jpo.conflictmonitor.monitor.models.notifications.timestamp_delta.SpatTimestampDeltaNotification; import us.dot.its.jpo.geojsonconverter.DateJsonMapper; /** @@ -38,6 +40,8 @@ @JsonSubTypes.Type(value = SignalStateConflictNotification.class, name = "SignalStateConflictNotification"), @JsonSubTypes.Type(value = TimeChangeDetailsNotification.class, name = "TimeChangeDetailsNotification"), @JsonSubTypes.Type(value = KafkaStreamsAnomalyNotification.class, name = "AppHealthNotification"), + @JsonSubTypes.Type(value = MapTimestampDeltaNotification.class, name = "MapTimestampDeltaNotification"), + @JsonSubTypes.Type(value = SpatTimestampDeltaNotification.class, name = "SpatTimestampDeltaNotification") }) @Getter @Setter diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/notifications/timestamp_delta/BaseTimestampDeltaNotification.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/notifications/timestamp_delta/BaseTimestampDeltaNotification.java new file mode 100644 index 00000000..a99d00f0 --- /dev/null +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/notifications/timestamp_delta/BaseTimestampDeltaNotification.java @@ -0,0 +1,49 @@ +package us.dot.its.jpo.conflictmonitor.monitor.models.notifications.timestamp_delta; + +import lombok.Getter; +import lombok.Setter; +import us.dot.its.jpo.conflictmonitor.monitor.models.events.ProcessingTimePeriod; +import us.dot.its.jpo.conflictmonitor.monitor.models.notifications.Notification; + +/** + * Base class for a timestamp delta notification + */ +@Getter +@Setter +public abstract class BaseTimestampDeltaNotification extends Notification { + + public BaseTimestampDeltaNotification(String notificationType) { + super(notificationType); + } + + ProcessingTimePeriod timePeriod; + long numberOfEvents; + + /** + * Minimum delta in milliseconds, signed. + *

If this is less than 0, indicates there were events with OdeReceivedAt earlier + * than the message timestamp. + */ + long minDeltaMillis; + + /** + * Maximum delta in milliseconds, signed. + */ + long maxDeltaMillis; + + /** + * The median magnitude of the delta in milliseconds. + */ + double absMedianDeltaMillis; + + + @Override + public String getUniqueId() { + return String.format("%s_%d_%d_%d_%d", + this.getNotificationType(), + this.getRoadRegulatorID(), + this.getIntersectionID(), + getTimePeriod() != null ? getTimePeriod().getBeginTimestamp() : 0, + getTimePeriod() != null ? getTimePeriod().getEndTimestamp() : 0); + } +} diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/notifications/timestamp_delta/MapTimestampDeltaNotification.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/notifications/timestamp_delta/MapTimestampDeltaNotification.java new file mode 100644 index 00000000..5fc65ae0 --- /dev/null +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/notifications/timestamp_delta/MapTimestampDeltaNotification.java @@ -0,0 +1,11 @@ +package us.dot.its.jpo.conflictmonitor.monitor.models.notifications.timestamp_delta; + +import us.dot.its.jpo.conflictmonitor.monitor.models.events.timestamp_delta.MapTimestampDeltaEvent; + +public class MapTimestampDeltaNotification + extends BaseTimestampDeltaNotification { + + public MapTimestampDeltaNotification() { + super("MapTimestampDeltaNotification"); + } +} diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/notifications/timestamp_delta/SpatTimestampDeltaNotification.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/notifications/timestamp_delta/SpatTimestampDeltaNotification.java new file mode 100644 index 00000000..1e4e8085 --- /dev/null +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/models/notifications/timestamp_delta/SpatTimestampDeltaNotification.java @@ -0,0 +1,9 @@ +package us.dot.its.jpo.conflictmonitor.monitor.models.notifications.timestamp_delta; + +public class SpatTimestampDeltaNotification + extends BaseTimestampDeltaNotification { + + public SpatTimestampDeltaNotification() { + super("SpatTimestampDeltaNotification"); + } +} diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/processors/timestamp_deltas/BaseTimestampDeltaNotificationProcessor.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/processors/timestamp_deltas/BaseTimestampDeltaNotificationProcessor.java new file mode 100644 index 00000000..787e3f1f --- /dev/null +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/processors/timestamp_deltas/BaseTimestampDeltaNotificationProcessor.java @@ -0,0 +1,164 @@ +package us.dot.its.jpo.conflictmonitor.monitor.processors.timestamp_deltas; + +import com.google.common.primitives.Doubles; +import org.apache.commons.math3.stat.descriptive.DescriptiveStatistics; +import org.apache.commons.math3.stat.descriptive.SummaryStatistics; +import org.apache.kafka.streams.KeyValue; +import org.apache.kafka.streams.processor.Cancellable; +import org.apache.kafka.streams.processor.PunctuationType; +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.query.MultiVersionedKeyQuery; +import org.apache.kafka.streams.query.PositionBound; +import org.apache.kafka.streams.query.QueryConfig; +import org.apache.kafka.streams.query.QueryResult; +import org.apache.kafka.streams.state.KeyValueStore; +import org.apache.kafka.streams.state.VersionedKeyValueStore; +import org.apache.kafka.streams.state.VersionedRecord; +import org.apache.kafka.streams.state.VersionedRecordIterator; +import org.slf4j.Logger; +import us.dot.its.jpo.conflictmonitor.monitor.models.events.ProcessingTimePeriod; +import us.dot.its.jpo.conflictmonitor.monitor.models.events.timestamp_delta.BaseTimestampDeltaEvent; +import us.dot.its.jpo.conflictmonitor.monitor.models.events.timestamp_delta.TimestampDelta; +import us.dot.its.jpo.conflictmonitor.monitor.models.notifications.timestamp_delta.BaseTimestampDeltaNotification; +import us.dot.its.jpo.geojsonconverter.partitioner.RsuIntersectionKey; + +import java.time.Duration; +import java.time.Instant; +import java.util.ArrayList; +import java.util.List; + + +public abstract class BaseTimestampDeltaNotificationProcessor + extends ContextualProcessor { + + abstract protected Logger getLogger(); + abstract protected TNotification constructNotification(); + abstract protected String getNotificationHeading(); + abstract protected String getNotificationText(); + + final Duration retentionTime; + final String eventStoreName; + final String keyStoreName; + + VersionedKeyValueStore eventStore; + + // Store to keep track of all the keys. Needed because Versioned state stores don't support range queries yet. + KeyValueStore keyStore; + + Cancellable punctuatorCancellationToken; + + public BaseTimestampDeltaNotificationProcessor(final Duration retentionTime, final String eventStoreName, + final String keyStoreName) { + this.retentionTime = retentionTime; + this.eventStoreName = eventStoreName; + this.keyStoreName = keyStoreName; + } + + @Override + public void init(ProcessorContext context) { + try { + super.init(context); + eventStore = context.getStateStore(eventStoreName); + keyStore = context.getStateStore(keyStoreName); + punctuatorCancellationToken = context.schedule(retentionTime, PunctuationType.WALL_CLOCK_TIME, this::punctuate); + } catch (Exception e) { + getLogger().error("Error initializing MapTimestampDeltaNotificationProcessor"); + } + } + + @Override + public void process(Record record) { + var key = record.key(); + var value = record.value(); + var timestamp = record.timestamp(); + // Ignore tombstones + if (value == null) return; + keyStore.put(key, true); + eventStore.put(key, value, timestamp); + } + + private void punctuate(final long timestamp) { + final Instant toTime = Instant.now(); + final Instant fromTime = toTime.minus(retentionTime); + + // Check every intersection for notifications + List keysToClean = new ArrayList<>(); + try (var iterator = keyStore.all()) { + while (iterator.hasNext()) { + KeyValue keyValue = iterator.next(); + RsuIntersectionKey key = keyValue.key; + assessmentForIntersection(key, fromTime, toTime, timestamp); + keysToClean.add(key); + } + } catch (Exception ex) { + getLogger().error("Error in punctuate method", ex); + } + + // Clean up the store + for (RsuIntersectionKey key : keysToClean) { + keyStore.delete(key); + } + } + + // Read stored events for one intersection, calculate statistics, and emit notifications + private void assessmentForIntersection(RsuIntersectionKey key, Instant fromTime, Instant toTime, long timestamp) { + var versionedQuery = + MultiVersionedKeyQuery.withKey(key) + .fromTime(fromTime) + .withAscendingTimestamps(); + QueryResult> result = + eventStore.query(versionedQuery, PositionBound.unbounded(), new QueryConfig(false)); + VersionedRecordIterator resultIterator = result.getResult(); + + SummaryStatistics stats = new SummaryStatistics(); + DescriptiveStatistics absStats = new DescriptiveStatistics(); + while (resultIterator.hasNext()) { + VersionedRecord record = resultIterator.next(); + long recordTimestamp = record.timestamp(); + Instant recordInstant = Instant.ofEpochMilli(recordTimestamp); + // Shouldn't happen but check timestamps, in case of stream-time vs clock time issue + if (recordInstant.isBefore(fromTime) || recordInstant.isAfter(toTime)) { + getLogger().warn("Record instant {} is not between {} and {}, skipping it.", recordInstant, fromTime, toTime); + continue; + } + TEvent event = record.value(); + TimestampDelta delta = event.getDelta(); + stats.addValue((double)delta.getDeltaMillis()); + absStats.addValue((double)delta.getAbsDeltaMillis()); + } + + long numberOfEvents = stats.getN(); + long minDeltaMillis = (long)stats.getMin(); + long maxDeltaMillis = (long)stats.getMax(); + double absMedianDelta = absStats.getPercentile(50.0); + + if (numberOfEvents > 0) { + TNotification notification = + createNotification(key, fromTime, toTime, numberOfEvents, minDeltaMillis, maxDeltaMillis, absMedianDelta); + context().forward(new Record<>(key, notification, timestamp)); + } + } + + private TNotification createNotification(final RsuIntersectionKey key, final Instant fromTime, final Instant toTime, + final long numberOfEvents, final long minDeltaMillis, final long maxDeltaMillis, + final double absMedianDelta) { + final var notification = constructNotification(); + final var timePeriod = new ProcessingTimePeriod(); + timePeriod.setBeginTimestamp(fromTime.toEpochMilli()); + timePeriod.setEndTimestamp(toTime.toEpochMilli()); + notification.setTimePeriod(timePeriod); + notification.setIntersectionID(key.getIntersectionId()); + notification.setRoadRegulatorID(key.getRegion()); + notification.setNumberOfEvents(numberOfEvents); + notification.setMinDeltaMillis(minDeltaMillis); + notification.setMaxDeltaMillis(maxDeltaMillis); + notification.setAbsMedianDeltaMillis(absMedianDelta); + notification.setNotificationHeading(getNotificationHeading()); + notification.setNotificationText(getNotificationText()); + notification.setKey(notification.getUniqueId()); + return notification; + } +} diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/processors/timestamp_deltas/MapTimestampDeltaNotificationProcessor.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/processors/timestamp_deltas/MapTimestampDeltaNotificationProcessor.java new file mode 100644 index 00000000..84fa9fb6 --- /dev/null +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/processors/timestamp_deltas/MapTimestampDeltaNotificationProcessor.java @@ -0,0 +1,37 @@ +package us.dot.its.jpo.conflictmonitor.monitor.processors.timestamp_deltas; + +import lombok.extern.slf4j.Slf4j; +import org.slf4j.Logger; +import us.dot.its.jpo.conflictmonitor.monitor.models.events.timestamp_delta.MapTimestampDeltaEvent; +import us.dot.its.jpo.conflictmonitor.monitor.models.notifications.timestamp_delta.MapTimestampDeltaNotification; + +import java.time.Duration; + +@Slf4j +public class MapTimestampDeltaNotificationProcessor + extends BaseTimestampDeltaNotificationProcessor { + + public MapTimestampDeltaNotificationProcessor(Duration retentionTime, String eventStoreName, String keyStoreName) { + super(retentionTime, eventStoreName, keyStoreName); + } + + @Override + protected Logger getLogger() { + return log; + } + + @Override + protected MapTimestampDeltaNotification constructNotification() { + return new MapTimestampDeltaNotification(); + } + + @Override + protected String getNotificationHeading() { + return "MAP Timestamp Delta Notification"; + } + + @Override + protected String getNotificationText() { + return "There were differences between the ODE ingest time and message timestamp."; + } +} diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/processors/timestamp_deltas/SpatTimestampDeltaNotificationProcessor.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/processors/timestamp_deltas/SpatTimestampDeltaNotificationProcessor.java new file mode 100644 index 00000000..48679f3a --- /dev/null +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/processors/timestamp_deltas/SpatTimestampDeltaNotificationProcessor.java @@ -0,0 +1,37 @@ +package us.dot.its.jpo.conflictmonitor.monitor.processors.timestamp_deltas; + +import lombok.extern.slf4j.Slf4j; +import org.slf4j.Logger; +import us.dot.its.jpo.conflictmonitor.monitor.models.events.timestamp_delta.SpatTimestampDeltaEvent; +import us.dot.its.jpo.conflictmonitor.monitor.models.notifications.timestamp_delta.SpatTimestampDeltaNotification; + +import java.time.Duration; + +@Slf4j +public class SpatTimestampDeltaNotificationProcessor + extends BaseTimestampDeltaNotificationProcessor { + + public SpatTimestampDeltaNotificationProcessor(Duration retentionTime, String eventStoreName, String keyStoreName) { + super(retentionTime, eventStoreName, keyStoreName); + } + + @Override + protected Logger getLogger() { + return log; + } + + @Override + protected SpatTimestampDeltaNotification constructNotification() { + return new SpatTimestampDeltaNotification(); + } + + @Override + protected String getNotificationHeading() { + return "SPaT Timestamp Delta Notification"; + } + + @Override + protected String getNotificationText() { + return "There were differences between the ODE ingest time and message timestamp."; + } +} 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 e9c7b839..25261404 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 @@ -21,7 +21,6 @@ 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; -import us.dot.its.jpo.conflictmonitor.monitor.models.config.RsuConfigKey; import us.dot.its.jpo.conflictmonitor.monitor.models.events.ConnectionOfTravelEvent; import us.dot.its.jpo.conflictmonitor.monitor.models.events.IntersectionReferenceAlignmentEvent; import us.dot.its.jpo.conflictmonitor.monitor.models.events.LaneDirectionOfTravelEvent; @@ -34,7 +33,15 @@ import us.dot.its.jpo.conflictmonitor.monitor.models.events.broadcast_rate.SpatBroadcastRateEvent; import us.dot.its.jpo.conflictmonitor.monitor.models.events.minimum_data.MapMinimumDataEvent; import us.dot.its.jpo.conflictmonitor.monitor.models.events.minimum_data.SpatMinimumDataEvent; +import us.dot.its.jpo.conflictmonitor.monitor.models.events.MapRevisionCounterEvent; +import us.dot.its.jpo.conflictmonitor.monitor.models.events.SpatRevisionCounterEvent; +import us.dot.its.jpo.conflictmonitor.monitor.models.events.BsmRevisionCounterEvent; +import us.dot.its.jpo.conflictmonitor.monitor.models.events.timestamp_delta.BaseTimestampDeltaEvent; +import us.dot.its.jpo.conflictmonitor.monitor.models.events.timestamp_delta.MapTimestampDeltaEvent; +import us.dot.its.jpo.conflictmonitor.monitor.models.events.timestamp_delta.SpatTimestampDeltaEvent; import us.dot.its.jpo.conflictmonitor.monitor.models.map.MapBoundingBox; +import us.dot.its.jpo.conflictmonitor.monitor.models.notifications.timestamp_delta.MapTimestampDeltaNotification; +import us.dot.its.jpo.conflictmonitor.monitor.models.notifications.timestamp_delta.SpatTimestampDeltaNotification; import us.dot.its.jpo.conflictmonitor.monitor.models.spat.SpatTimeChangeDetailAggregator; import us.dot.its.jpo.conflictmonitor.monitor.serialization.deserialization.GenericJsonDeserializer; import us.dot.its.jpo.geojsonconverter.serialization.deserializers.JsonDeserializer; @@ -140,6 +147,25 @@ public static Serde TimeChangeDetailsEvent() { new JsonDeserializer<>(TimeChangeDetailsEvent.class)); } + public static Serde MapRevisionCounterEvent() { + return Serdes.serdeFrom( + new JsonSerializer(), + new JsonDeserializer<>(MapRevisionCounterEvent.class)); + } + + public static Serde SpatRevisionCounterEvent() { + return Serdes.serdeFrom( + new JsonSerializer(), + new JsonDeserializer<>(SpatRevisionCounterEvent.class)); + } + + public static Serde BsmRevisionCounterEvent() { + return Serdes.serdeFrom( + new JsonSerializer(), + new JsonDeserializer<>(BsmRevisionCounterEvent.class)); + } + + public static Serde SpatTimeChangeDetailAggregator() { return Serdes.serdeFrom( new JsonSerializer(), @@ -336,12 +362,6 @@ public static Serde MapBroadcastRateNotification() ); } - public static Serde RsuConfigKey() { - return Serdes.serdeFrom( - new JsonSerializer(), - new JsonDeserializer<>(RsuConfigKey.class) - ); - } public static Serde IntersectionConfigKey() { return Serdes.serdeFrom( @@ -356,4 +376,33 @@ public static Serde MapBoundingBox() { new JsonDeserializer<>(MapBoundingBox.class) ); } + + public static Serde MapTimestampDeltaEvent() { + return Serdes.serdeFrom( + new JsonSerializer(), + new JsonDeserializer<>(MapTimestampDeltaEvent.class) + ); + } + + public static Serde SpatTimestampDeltaEvent() { + return Serdes.serdeFrom( + new JsonSerializer(), + new JsonDeserializer<>(SpatTimestampDeltaEvent.class) + ); + } + + public static Serde MapTimestampDeltaNotification() { + return Serdes.serdeFrom( + new JsonSerializer(), + new JsonDeserializer<>(MapTimestampDeltaNotification.class) + ); + } + + public static Serde SpatTimestampDeltaNotification() { + return Serdes.serdeFrom( + new JsonSerializer(), + new JsonDeserializer<>(SpatTimestampDeltaNotification.class) + ); + } + } diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/serialization/deserialization/GenericJsonDeserializer.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/serialization/deserialization/GenericJsonDeserializer.java index 8ca9cc12..226ef8eb 100644 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/serialization/deserialization/GenericJsonDeserializer.java +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/serialization/deserialization/GenericJsonDeserializer.java @@ -12,13 +12,16 @@ import us.dot.its.jpo.geojsonconverter.DateJsonMapper; +/** + * Generic JSON deserializer for Kafka, deserializes from byte[] data. + */ public class GenericJsonDeserializer implements Deserializer { private static Logger logger = LoggerFactory.getLogger(GenericJsonDeserializer.class); protected final ObjectMapper mapper = DateJsonMapper.getInstance(); - private Class genericClass; + final Class genericClass; public GenericJsonDeserializer(Class genericClass) { this.genericClass = genericClass; diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/serialization/deserialization/GenericJsonStringDeserializer.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/serialization/deserialization/GenericJsonStringDeserializer.java new file mode 100644 index 00000000..69ff13e4 --- /dev/null +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/serialization/deserialization/GenericJsonStringDeserializer.java @@ -0,0 +1,45 @@ +package us.dot.its.jpo.conflictmonitor.monitor.serialization.deserialization; + +import com.fasterxml.jackson.core.JacksonException; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.*; +import lombok.extern.slf4j.Slf4j; +import us.dot.its.jpo.geojsonconverter.DateJsonMapper; + +import java.io.IOException; + +/** + * Generic JSON deserializer for REST controllers, deserializes from string. + */ +@Slf4j +public class GenericJsonStringDeserializer extends JsonDeserializer { + + protected final ObjectMapper mapper = DateJsonMapper.getInstance(); + + final Class genericClass; + + public GenericJsonStringDeserializer(Class genericClass) { + this.genericClass = genericClass; + } + + @Override + @SuppressWarnings("unchecked") + public T deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JacksonException { + + + JsonNode node = mapper.readTree(jsonParser); + if (node.has("type")) { + String type = node.get("type").asText(); + Class nestedClass = null; + try { + nestedClass = Class.forName(type); + } catch (ClassNotFoundException e) { + throw new IOException(e); + } + JavaType javaType = mapper.getTypeFactory().constructParametricType(genericClass, nestedClass); + return (T)mapper.treeToValue(node, javaType); + } + return null; + + } +} diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/BsmRevisionCounterTopology.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/BsmRevisionCounterTopology.java new file mode 100644 index 00000000..a3ccb84b --- /dev/null +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/BsmRevisionCounterTopology.java @@ -0,0 +1,131 @@ +package us.dot.its.jpo.conflictmonitor.monitor.topologies; + +import org.apache.kafka.common.serialization.Serdes; +import org.apache.kafka.streams.KafkaStreams.StateListener; +import org.apache.kafka.streams.KeyValue; +import org.apache.kafka.streams.errors.StreamsUncaughtExceptionHandler; + +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.Grouped; +import org.apache.kafka.streams.kstream.KStream; +import org.apache.kafka.streams.kstream.Materialized; +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.bsm_revision_counter.BsmRevisionCounterParameters; +import us.dot.its.jpo.conflictmonitor.monitor.algorithms.bsm_revision_counter.BsmRevisionCounterStreamsAlgorithm; +import us.dot.its.jpo.conflictmonitor.monitor.models.events.BsmRevisionCounterEvent; +import us.dot.its.jpo.conflictmonitor.monitor.serialization.JsonSerdes; +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.bsm_revision_counter.BsmRevisionCounterConstants.DEFAULT_BSM_REVISION_COUNTER_ALGORITHM; + +import java.util.ArrayList; +import java.util.Objects; + +@Component(DEFAULT_BSM_REVISION_COUNTER_ALGORITHM) +public class BsmRevisionCounterTopology + extends BaseStreamsTopology + implements BsmRevisionCounterStreamsAlgorithm { + + private static final Logger logger = LoggerFactory.getLogger(BsmRevisionCounterTopology.class); + + + + @Override + protected Logger getLogger() { + return logger; + } + + @Override + public Topology buildTopology() { + StreamsBuilder builder = new StreamsBuilder(); + + KStream inputStream = builder.stream(parameters.getBsmInputTopicName(), Consumed.with(Serdes.String(), JsonSerdes.OdeBsm())); + + KStream eventStream = inputStream + .groupByKey(Grouped.with(Serdes.String(), JsonSerdes.OdeBsm())) + .aggregate(() -> new BsmRevisionCounterEvent(), + (key, newValue, aggregate) -> { + aggregate.setMessage(null); + if (aggregate.getNewBsm() == null){ + aggregate.setNewBsm(newValue); + return aggregate; + } + + //update the aggregate + aggregate.setPreviousBsm(aggregate.getNewBsm()); + aggregate.setNewBsm(newValue); + + J2735Bsm previousBsmPayload = (J2735Bsm) aggregate.getPreviousBsm().getPayload().getData(); + J2735Bsm newBsmPayload = (J2735Bsm) aggregate.getNewBsm().getPayload().getData(); + + int newSecMark = newBsmPayload.getCoreData().getSecMark(); + + newBsmPayload.getCoreData().setSecMark(previousBsmPayload.getCoreData().getSecMark()); + aggregate.getNewBsm().getMetadata().setOdeReceivedAt(aggregate.getPreviousBsm().getMetadata().getOdeReceivedAt()); + + int oldMetadataHash = Objects.hash(aggregate.getPreviousBsm().getMetadata().toJson()); + int newMetadataHash = Objects.hash(aggregate.getNewBsm().getMetadata().toJson()); + int oldPayloadHash = Objects.hash(previousBsmPayload.toJson()); + int newPayloadHash = Objects.hash(newBsmPayload.toJson()); + + if (oldPayloadHash != newPayloadHash || oldMetadataHash != newMetadataHash){ //Contents of bsm message have changed + newBsmPayload.getCoreData().setSecMark(newSecMark); + aggregate.getNewBsm().getMetadata().setOdeReceivedAt(newValue.getMetadata().getOdeReceivedAt()); + if (previousBsmPayload.getCoreData().getMsgCnt() == newBsmPayload.getCoreData().getMsgCnt()) { //Revision has not changed + aggregate.setMessage("Bsm message changed without msgCount increment."); + aggregate.setRoadRegulatorID(-1); + return aggregate; + } + else { //Revision has changed + return aggregate; + } + } + else { //Bsm messages are the same + return aggregate; + + } + + }, Materialized.with(Serdes.String(), us.dot.its.jpo.conflictmonitor.monitor.serialization.JsonSerdes.BsmRevisionCounterEvent())) + .toStream() + .flatMap((key, value) ->{ + ArrayList> outputList = new ArrayList<>(); + if (value.getMessage() != null){ + outputList.add(new KeyValue<>(key, value)); + } + return outputList; + }); + eventStream.to(parameters.getBsmRevisionEventOutputTopicName(), Produced.with(Serdes.String(), us.dot.its.jpo.conflictmonitor.monitor.serialization.JsonSerdes.BsmRevisionCounterEvent())); + + return builder.build(); + } + + public void stop() { + logger.info("Stopping Bsm Revision Counter Socket Broadcast Topology."); + if (streams != null) { + streams.close(); + streams.cleanUp(); + streams = null; + } + logger.info("Stopped Bsm Revision Counter 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-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/EventTopology.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/EventTopology.java index 50e0abb3..e6247f6f 100644 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/EventTopology.java +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/EventTopology.java @@ -28,6 +28,15 @@ public class EventTopology private static final Logger logger = LoggerFactory.getLogger(EventTopology.class); + @Override + public void start() { + // Don't start the topology if it is disabled by configuration setting + if (parameters.isEnabled()) { + super.start(); + } else { + logger.warn("Not starting the EventTopology because EventParameters.enabled = false"); + } + } @Override @@ -51,9 +60,14 @@ public Topology buildTopology() { .merge(builder.stream(parameters.getMapMinimumDataTopicName(), Consumed.with(Serdes.String(), JsonSerdes.Event()))) .merge(builder.stream(parameters.getSpatMinimumDataTopicName(), Consumed.with(Serdes.String(), JsonSerdes.Event()))) .merge(builder.stream(parameters.getMapBroadcastRateTopicName(), Consumed.with(Serdes.String(), JsonSerdes.Event()))) - .merge(builder.stream(parameters.getSpatBroadcastRateTopicName(), Consumed.with(Serdes.String(), JsonSerdes.Event()))); + .merge(builder.stream(parameters.getSpatBroadcastRateTopicName(), Consumed.with(Serdes.String(), JsonSerdes.Event()))) + .merge(builder.stream(parameters.getSpatRevisionCounterEventTopicName(), Consumed.with(Serdes.String(), JsonSerdes.Event()))) + .merge(builder.stream(parameters.getBsmRevisionCounterEventTopicName(), Consumed.with(Serdes.String(), JsonSerdes.Event()))) + .merge(builder.stream(parameters.getMapRevisionCounterEventTopicName(), Consumed.with(Serdes.String(), JsonSerdes.Event()))) + .merge(builder.stream(parameters.getTimestampDeltaEventTopicName(), Consumed.with(Serdes.String(), JsonSerdes.Event()))); allEvents.to(parameters.getEventOutputTopicName(), Produced.with(Serdes.String(), JsonSerdes.Event())); + if(parameters.isDebug()){ allEvents.print(Printed.toSysOut()); } 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 a4ed1ef3..16c7ceec 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 @@ -349,9 +349,8 @@ public Topology buildTopology() { StreamsBuilder builder = new StreamsBuilder(); - if (messageIngestAlgorithm instanceof MessageIngestStreamsAlgorithm) { - var messageIngestStreamsAlgorithm = (MessageIngestStreamsAlgorithm)messageIngestAlgorithm; - builder = messageIngestStreamsAlgorithm.buildTopology(builder); + if (messageIngestAlgorithm instanceof MessageIngestStreamsAlgorithm messageIngestStreamsAlgorithm) { + messageIngestStreamsAlgorithm.buildTopology(builder); } diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/MapRevisionCounterTopology.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/MapRevisionCounterTopology.java new file mode 100644 index 00000000..86244bac --- /dev/null +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/MapRevisionCounterTopology.java @@ -0,0 +1,107 @@ +package us.dot.its.jpo.conflictmonitor.monitor.topologies; + +import org.apache.kafka.common.serialization.Serdes; +import org.apache.kafka.streams.KeyValue; +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.Grouped; +import org.apache.kafka.streams.kstream.KStream; +import org.apache.kafka.streams.kstream.Materialized; +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.map_revision_counter.MapRevisionCounterParameters; +import us.dot.its.jpo.conflictmonitor.monitor.algorithms.map_revision_counter.MapRevisionCounterStreamsAlgorithm; +import us.dot.its.jpo.conflictmonitor.monitor.models.events.MapRevisionCounterEvent; +import us.dot.its.jpo.geojsonconverter.pojos.geojson.map.ProcessedMap; + +import us.dot.its.jpo.geojsonconverter.pojos.geojson.LineString; +import us.dot.its.jpo.geojsonconverter.serialization.JsonSerdes; + +import static us.dot.its.jpo.conflictmonitor.monitor.algorithms.map_revision_counter.MapRevisionCounterConstants.DEFAULT_MAP_REVISION_COUNTER_ALGORITHM; + +import java.util.ArrayList; +import java.util.Objects; + +@Component(DEFAULT_MAP_REVISION_COUNTER_ALGORITHM) +public class MapRevisionCounterTopology + extends BaseStreamsTopology + implements MapRevisionCounterStreamsAlgorithm { + + private static final Logger logger = LoggerFactory.getLogger(MapRevisionCounterTopology.class); + + + + @Override + protected Logger getLogger() { + return logger; + } + + @Override + public Topology buildTopology() { + StreamsBuilder builder = new StreamsBuilder(); + + KStream> inputStream = builder.stream(parameters.getMapInputTopicName(), Consumed.with(Serdes.String(), JsonSerdes.ProcessedMapGeoJson())); + + KStream eventStream = inputStream + .groupByKey(Grouped.with(Serdes.String(), JsonSerdes.ProcessedMapGeoJson())) + .aggregate(() -> new MapRevisionCounterEvent(), + (key, newValue, aggregate) -> { + + aggregate.setMessage(null); + if (aggregate.getNewMap() == null){ + aggregate.setNewMap(newValue); + return aggregate; + } + + //update the aggregate + aggregate.setPreviousMap(aggregate.getNewMap()); + aggregate.setNewMap(newValue); + + aggregate.getNewMap().getProperties().setTimeStamp(aggregate.getPreviousMap().getProperties().getTimeStamp()); + aggregate.getNewMap().getProperties().setOdeReceivedAt(aggregate.getPreviousMap().getProperties().getOdeReceivedAt()); + + int oldHash = Objects.hash(aggregate.getPreviousMap().toString()); + int newHash = Objects.hash(aggregate.getNewMap().toString()); + + if (oldHash != newHash){ //Contents of map message have changed + aggregate.getNewMap().getProperties().setTimeStamp(newValue.getProperties().getTimeStamp()); + aggregate.getNewMap().getProperties().setOdeReceivedAt(newValue.getProperties().getOdeReceivedAt()); + if (aggregate.getNewMap().getProperties().getRevision() == aggregate.getPreviousMap().getProperties().getRevision()) { //Revision has not changed + aggregate.setIntersectionID(aggregate.getNewMap().getProperties().getIntersectionId()); + aggregate.setRoadRegulatorID(-1); + aggregate.setMessage("Map message changed without revision increment."); + return aggregate; + } + else { //Revision has changed + return aggregate; + } + } + else { //Map messages are the same + return aggregate; + + } + + }, Materialized.with(Serdes.String(), us.dot.its.jpo.conflictmonitor.monitor.serialization.JsonSerdes.MapRevisionCounterEvent())) + .toStream() + .flatMap((key, value) ->{ + ArrayList> outputList = new ArrayList<>(); + if (value.getMessage() != null){ + outputList.add(new KeyValue<>(key, value)); + } + return outputList; + }); + eventStream.to(parameters.getMapRevisionEventOutputTopicName(), Produced.with(Serdes.String(), us.dot.its.jpo.conflictmonitor.monitor.serialization.JsonSerdes.MapRevisionCounterEvent())); + + return builder.build(); + + + } + + + +} diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/MapSpatMessageAssessmentTopology.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/MapSpatMessageAssessmentTopology.java index 91b188c1..6a16b018 100644 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/MapSpatMessageAssessmentTopology.java +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/MapSpatMessageAssessmentTopology.java @@ -5,7 +5,14 @@ import org.apache.kafka.streams.KeyValue; import org.apache.kafka.streams.StreamsBuilder; import org.apache.kafka.streams.Topology; -import org.apache.kafka.streams.kstream.*; +import org.apache.kafka.streams.kstream.Consumed; +import org.apache.kafka.streams.kstream.Grouped; +import org.apache.kafka.streams.kstream.Joined; +import org.apache.kafka.streams.kstream.KStream; +import org.apache.kafka.streams.kstream.KTable; +import org.apache.kafka.streams.kstream.Materialized; +import org.apache.kafka.streams.kstream.Printed; +import org.apache.kafka.streams.kstream.Produced; import org.apache.kafka.streams.state.KeyValueStore; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -13,11 +20,13 @@ import us.dot.its.jpo.conflictmonitor.monitor.algorithms.BaseStreamsTopology; import us.dot.its.jpo.conflictmonitor.monitor.algorithms.map_spat_message_assessment.MapSpatMessageAssessmentParameters; import us.dot.its.jpo.conflictmonitor.monitor.algorithms.map_spat_message_assessment.MapSpatMessageAssessmentStreamsAlgorithm; -import us.dot.its.jpo.conflictmonitor.monitor.models.AllowedConcurrentPermissive; import us.dot.its.jpo.conflictmonitor.monitor.models.Intersection.Intersection; import us.dot.its.jpo.conflictmonitor.monitor.models.Intersection.LaneConnection; import us.dot.its.jpo.conflictmonitor.monitor.models.RegulatorIntersectionId; import us.dot.its.jpo.conflictmonitor.monitor.models.SpatMap; +import us.dot.its.jpo.conflictmonitor.monitor.models.concurrent_permissive.ConnectedLanesPair; +import us.dot.its.jpo.conflictmonitor.monitor.models.concurrent_permissive.ConnectedLanesPairList; +import us.dot.its.jpo.conflictmonitor.monitor.models.config.ConfigMap; import us.dot.its.jpo.conflictmonitor.monitor.models.events.IntersectionReferenceAlignmentEvent; import us.dot.its.jpo.conflictmonitor.monitor.models.events.SignalGroupAlignmentEvent; import us.dot.its.jpo.conflictmonitor.monitor.models.events.SignalStateConflictEvent; @@ -65,9 +74,9 @@ private J2735MovementPhaseState getSpatEventStateBySignalGroup(ProcessedSpat spa return null; } - private String hashLaneConnection(Integer intersectionID, int ingressOne, int ingressTwo, int egressOne, int egressTwo){ - return intersectionID + "_" + ingressOne + "_" + ingressTwo + "_" + egressOne + "_" + egressTwo; - } +// private String hashLaneConnection(Integer intersectionID, int ingressOne, int ingressTwo, int egressOne, int egressTwo){ +// return intersectionID + "_" + ingressOne + "_" + ingressTwo + "_" + egressOne + "_" + egressTwo; +// } private boolean doStatesConflict(J2735MovementPhaseState a, J2735MovementPhaseState b) { return a.equals(J2735MovementPhaseState.PROTECTED_CLEARANCE) @@ -85,15 +94,13 @@ private boolean doStatesConflict(J2735MovementPhaseState a, J2735MovementPhaseSt public Topology buildTopology() { - // TODO: Populate concurrent permissive allowed from intersection-level config - Map allowMap = new HashMap<>(); - List list = new ArrayList<>(); - for(AllowedConcurrentPermissive elem : list){ - String hash = hashLaneConnection(elem.getIntersectionID(), elem.getFirstIngressLane(), elem.getSecondIngressLane(), elem.getFirstEgressLane(), elem.getSecondEgressLane()); - allowMap.put(hash, elem); + // Populate concurrent permissive allowed from intersection-level config + ConfigMap concurrentPermissiveConfigMap = parameters.getConcurrentPermissiveListMap(); + final Set allowConcurrentPermissiveSet = new HashSet<>(); + for (ConnectedLanesPairList list : concurrentPermissiveConfigMap.values()) { + allowConcurrentPermissiveSet.addAll(list); } - StreamsBuilder builder = new StreamsBuilder(); // SPaT Input Stream @@ -343,11 +350,14 @@ public Topology buildTopology() { for (int j = i + 1; j < connections.size(); j++) { LaneConnection secondConnection = connections.get(j); - String compareHash = hashLaneConnection(intersection.getIntersectionId(), firstConnection.getIngressLane().getId(), secondConnection.getIngressLane().getId(), firstConnection.getEgressLane().getId(), secondConnection.getEgressLane().getId()); + ConnectedLanesPair theseConnectedLanes = new ConnectedLanesPair( + intersection.getIntersectionId(), intersection.getRoadRegulatorId(), + firstConnection.getIngressLane().getId(), firstConnection.getEgressLane().getId(), + secondConnection.getIngressLane().getId(), secondConnection.getEgressLane().getId()); // Skip if this connection is defined in the allowable map. - if(allowMap.containsKey(compareHash)){ + if(allowConcurrentPermissiveSet.contains(theseConnectedLanes)){ continue; } 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 046ac884..e3e023b8 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 @@ -4,8 +4,18 @@ import org.apache.kafka.streams.KafkaStreams; import org.apache.kafka.streams.StoreQueryParameters; import org.apache.kafka.streams.StreamsBuilder; -import org.apache.kafka.streams.kstream.*; -import org.apache.kafka.streams.state.*; +import org.apache.kafka.streams.kstream.Consumed; +import org.apache.kafka.streams.kstream.Grouped; +import org.apache.kafka.streams.kstream.KGroupedStream; +import org.apache.kafka.streams.kstream.KStream; +import org.apache.kafka.streams.kstream.Materialized; +import org.apache.kafka.streams.kstream.Produced; +import org.apache.kafka.streams.kstream.TimeWindows; +import org.apache.kafka.streams.state.KeyValueStore; +import org.apache.kafka.streams.state.QueryableStoreTypes; +import org.apache.kafka.streams.state.ReadOnlyKeyValueStore; +import org.apache.kafka.streams.state.ReadOnlyWindowStore; +import org.apache.kafka.streams.state.WindowStore; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; @@ -13,7 +23,6 @@ import us.dot.its.jpo.conflictmonitor.monitor.algorithms.message_ingest.MessageIngestParameters; import us.dot.its.jpo.conflictmonitor.monitor.algorithms.message_ingest.MessageIngestStreamsAlgorithm; 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.MapBoundingBox; import us.dot.its.jpo.conflictmonitor.monitor.models.map.MapIndex; @@ -38,9 +47,10 @@ public class MessageIngestTopology implements MessageIngestStreamsAlgorithm { private static final Logger logger = LoggerFactory.getLogger(MessageIngestTopology.class); - //private int count = 0; - - public StreamsBuilder buildTopology(StreamsBuilder builder) { + + + @Override + public void buildTopology(StreamsBuilder builder) { @@ -190,10 +200,6 @@ public StreamsBuilder buildTopology(StreamsBuilder builder) { ); - - - - return builder; } @@ -226,7 +232,6 @@ public ReadOnlyKeyValueStore> getMa - private MapIndex mapIndex; diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/NotificationTopology.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/NotificationTopology.java index 78d48f73..b2bc7105 100644 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/NotificationTopology.java +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/NotificationTopology.java @@ -45,7 +45,8 @@ public Topology buildTopology() { .merge(builder.stream(parameters.getIntersectionReferenceAlignmentNotificationTopicName(), Consumed.with(Serdes.String(), JsonSerdes.Notification()))) .merge(builder.stream(parameters.getSignalGroupAlignmentNotificationTopicName(), Consumed.with(Serdes.String(), JsonSerdes.Notification()))) .merge(builder.stream(parameters.getSignalStateConflictNotificationTopicName(), Consumed.with(Serdes.String(), JsonSerdes.Notification()))) - .merge(builder.stream(parameters.getSpatTimeChangeDetailsNotificationTopicName(), Consumed.with(Serdes.String(), JsonSerdes.Notification()))); + .merge(builder.stream(parameters.getSpatTimeChangeDetailsNotificationTopicName(), Consumed.with(Serdes.String(), JsonSerdes.Notification()))) + .merge(builder.stream(parameters.getTimestampDeltaNotificationTopicName(), Consumed.with(Serdes.String(), JsonSerdes.Notification()))); allNotifications.to(parameters.getNotificationOutputTopicName(), Produced.with(Serdes.String(), JsonSerdes.Notification())); if(parameters.isDebug()){ 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 dd84625f..11cb7fd7 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 @@ -54,21 +54,11 @@ public Topology buildTopology() { KStream bsmRekeyedStream = bsmRepartitionStream.selectKey((key, value)->{ String ip = BsmUtils.getRsuIp(value); -// if (value.getMetadata() != null && value.getMetadata() instanceof OdeBsmMetadata) { -// var metadata = (OdeBsmMetadata) value.getMetadata(); -// ip = metadata.getOriginIp(); -// } String bsmId = BsmUtils.getVehicleId(value); -// if (value.getPayload() != null -// && value.getPayload().getData() instanceof J2735Bsm -// && ((J2735Bsm) value.getPayload().getData()).getCoreData() != null) { -// var coreData = ((J2735Bsm) value.getPayload().getData()).getCoreData(); -// bsmId = coreData.getId(); -// } - return new BsmRsuIdKey(ip, bsmId); }); + bsmRekeyedStream.to( parameters.getBsmRepartitionOutputTopicName(), Produced.with( diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/SpatRevisionCounterTopology.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/SpatRevisionCounterTopology.java new file mode 100644 index 00000000..6670b606 --- /dev/null +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/SpatRevisionCounterTopology.java @@ -0,0 +1,126 @@ +package us.dot.its.jpo.conflictmonitor.monitor.topologies; + +import org.apache.kafka.common.serialization.Serdes; +import org.apache.kafka.streams.KafkaStreams.StateListener; +import org.apache.kafka.streams.KeyValue; +import org.apache.kafka.streams.errors.StreamsUncaughtExceptionHandler; + +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.Grouped; +import org.apache.kafka.streams.kstream.KStream; +import org.apache.kafka.streams.kstream.Materialized; +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.spat_revision_counter.SpatRevisionCounterParameters; +import us.dot.its.jpo.conflictmonitor.monitor.algorithms.spat_revision_counter.SpatRevisionCounterStreamsAlgorithm; +import us.dot.its.jpo.conflictmonitor.monitor.models.events.SpatRevisionCounterEvent; +import us.dot.its.jpo.geojsonconverter.pojos.spat.ProcessedSpat; + +import us.dot.its.jpo.geojsonconverter.serialization.JsonSerdes; + +import static us.dot.its.jpo.conflictmonitor.monitor.algorithms.spat_revision_counter.SpatRevisionCounterConstants.DEFAULT_SPAT_REVISION_COUNTER_ALGORITHM; + +import java.util.ArrayList; + +@Component(DEFAULT_SPAT_REVISION_COUNTER_ALGORITHM) +public class SpatRevisionCounterTopology + extends BaseStreamsTopology + implements SpatRevisionCounterStreamsAlgorithm { + + private static final Logger logger = LoggerFactory.getLogger(SpatRevisionCounterTopology.class); + + + + @Override + protected Logger getLogger() { + return logger; + } + + @Override + public Topology buildTopology() { + StreamsBuilder builder = new StreamsBuilder(); + + KStream inputStream = builder.stream(parameters.getSpatInputTopicName(), Consumed.with(Serdes.String(), JsonSerdes.ProcessedSpat())); + + KStream eventStream = inputStream + .groupByKey(Grouped.with(Serdes.String(), JsonSerdes.ProcessedSpat())) + .aggregate(() -> new SpatRevisionCounterEvent(), + (key, newValue, aggregate) -> { + + aggregate.setMessage(null); + if (aggregate.getNewSpat() == null){ + aggregate.setNewSpat(newValue); + return aggregate; + } + + //update the aggregate + aggregate.setPreviousSpat(aggregate.getNewSpat()); + aggregate.setNewSpat(newValue); + + aggregate.getNewSpat().setUtcTimeStamp(aggregate.getPreviousSpat().getUtcTimeStamp()); + aggregate.getNewSpat().setOdeReceivedAt(aggregate.getPreviousSpat().getOdeReceivedAt()); + + int oldHash = aggregate.getPreviousSpat().hashCode(); + int newHash = aggregate.getNewSpat().hashCode(); + + if (oldHash != newHash){ //Contents of spat message have changed + aggregate.getNewSpat().setUtcTimeStamp(newValue.getUtcTimeStamp()); + aggregate.getNewSpat().setOdeReceivedAt(newValue.getOdeReceivedAt()); + if (aggregate.getNewSpat().getRevision() == aggregate.getPreviousSpat().getRevision()) { //Revision has not changed + aggregate.setIntersectionID(aggregate.getNewSpat().getIntersectionId()); + aggregate.setRoadRegulatorID(-1); + aggregate.setMessage("Spat message changed without revision increment."); + + return aggregate; + } + else { //Revision has changed + return aggregate; + } + } + else { //Spat messages are the same + return aggregate; + + } + + }, Materialized.with(Serdes.String(), us.dot.its.jpo.conflictmonitor.monitor.serialization.JsonSerdes.SpatRevisionCounterEvent())) + .toStream() + .flatMap((key, value) ->{ + ArrayList> outputList = new ArrayList<>(); + if (value.getMessage() != null){ + outputList.add(new KeyValue<>(key, value)); + } + return outputList; + }); + eventStream.to(parameters.getSpatRevisionEventOutputTopicName(), Produced.with(Serdes.String(), us.dot.its.jpo.conflictmonitor.monitor.serialization.JsonSerdes.SpatRevisionCounterEvent())); + + return builder.build(); + } + + public void stop() { + logger.info("Stopping Spat Revision Counter Socket Broadcast Topology."); + if (streams != null) { + streams.close(); + streams.cleanUp(); + streams = null; + } + logger.info("Stopped Spat Revision Counter 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-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/assessments/StopLineStopAssessmentTopology.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/assessments/StopLineStopAssessmentTopology.java index 7c4a5587..d312b067 100644 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/assessments/StopLineStopAssessmentTopology.java +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/assessments/StopLineStopAssessmentTopology.java @@ -125,7 +125,7 @@ public Topology buildTopology() { for(StopLineStopAssessmentGroup group: assessment.getStopLineStopAssessmentGroup()){ // Only Send Assessments that match the generating signal group. if(group.getSignalGroup() == event.getSignalGroup() && group.getNumberOfEvents() >= parameters.getMinimumEventsToNotify()){ - double totalTime = group.getTimeStoppedOnDark() + group.getTimeStoppedOnGreen() + group.getTimeStoppedOnRed() + group.getTimeStoppedOnYellow(); + double totalTime = group.getTimeStoppedOnDark() + group.getTimeStoppedOnGreen() + group.getTimeStoppedOnRed() + group.getTimeStoppedOnYellow() + group.getTimeStoppedOnDark(); if(group.getTimeStoppedOnGreen() > parameters.getGreenLightPercentToNotify() * totalTime){ StopLineStopNotification notification = new StopLineStopNotification(); notification.setSignalGroup(group.getSignalGroup()); diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/config/ConfigInitializer.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/config/ConfigInitializer.java index 521e5a0f..84d6e5c3 100644 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/config/ConfigInitializer.java +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/config/ConfigInitializer.java @@ -1,20 +1,18 @@ package us.dot.its.jpo.conflictmonitor.monitor.topologies.config; -import com.fasterxml.jackson.core.JsonProcessingException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.PropertyAccessor; import org.springframework.beans.PropertyAccessorFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Profile; -import org.springframework.kafka.core.KafkaTemplate; import org.springframework.stereotype.Component; import us.dot.its.jpo.conflictmonitor.monitor.algorithms.AlgorithmParameters; import us.dot.its.jpo.conflictmonitor.monitor.algorithms.config.ConfigParameters; +import us.dot.its.jpo.conflictmonitor.monitor.models.concurrent_permissive.ConnectedLanesPairList; import us.dot.its.jpo.conflictmonitor.monitor.models.config.*; -import us.dot.its.jpo.geojsonconverter.DateJsonMapper; -import static us.dot.its.jpo.conflictmonitor.monitor.serialization.JsonSerdes.*; + import java.lang.reflect.Field; @@ -77,34 +75,42 @@ private void writeDefaultConfigObject(Object paramObj) { } private DefaultConfig createConfig(Class type, Object propValue, ConfigData updatable) { - if (Integer.class.equals(type) || "int".equals(type.getName())) { - var config = new DefaultIntConfig(); - config.setValue((Integer)propValue); + var config = new DefaultConfig(); + config.setValue((Integer) propValue); setConfigProps(config, updatable, Integer.class); return config; } else if (String.class.equals(type)) { - var config = new DefaultStringConfig(); - config.setValue((String)propValue); + var config = new DefaultConfig(); + config.setValue((String) propValue); setConfigProps(config, updatable, String.class); return config; } else if (Boolean.class.equals(type) || "boolean".equals(type.getName())) { - var config = new DefaultBooleanConfig(); - config.setValue((Boolean)propValue); + var config = new DefaultConfig(); + config.setValue((Boolean) propValue); setConfigProps(config, updatable, Boolean.class); return config; } else if (Double.class.equals(type) || "double".equals(type.getName())) { - var config = new DefaultDoubleConfig(); - config.setValue((Double)propValue); + var config = new DefaultConfig(); + config.setValue((Double) propValue); setConfigProps(config, updatable, Double.class); return config; } else if (Long.class.equals(type) || "long".equals(type.getName())) { - var config = new DefaultLongConfig(); - config.setValue((Long)propValue); + var config = new DefaultConfig(); + config.setValue((Long) propValue); setConfigProps(config, updatable, Long.class); return config; + } else if (ConnectedLanesPairList.class.equals(type)) { + var config = new DefaultConfig(); + if (propValue != null) { + config.setValue((ConnectedLanesPairList) propValue); + } else { + config.setValue(new ConnectedLanesPairList()); + } + setConfigProps(config, updatable, ConnectedLanesPairList.class); + return config; } else { - var config = new DefaultIntConfig(); + var config = new DefaultConfig(); config.setValue((Integer)propValue); setConfigProps(config, updatable, Integer.class); return config; diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/config/ConfigTopology.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/config/ConfigTopology.java index 04a542d6..bf61ebd7 100644 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/config/ConfigTopology.java +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/config/ConfigTopology.java @@ -7,7 +7,11 @@ import org.apache.commons.lang3.StringUtils; import org.apache.kafka.common.utils.Bytes; -import org.apache.kafka.streams.*; +import org.apache.kafka.streams.KafkaStreams; +import org.apache.kafka.streams.KeyValue; +import org.apache.kafka.streams.StoreQueryParameters; +import org.apache.kafka.streams.StreamsBuilder; +import org.apache.kafka.streams.Topology; import org.apache.kafka.streams.kstream.*; import org.apache.kafka.streams.state.KeyValueStore; import org.apache.kafka.streams.state.QueryableStoreTypes; @@ -18,13 +22,27 @@ import org.springframework.kafka.core.KafkaTemplate; import org.springframework.stereotype.Component; import us.dot.its.jpo.conflictmonitor.monitor.algorithms.BaseStreamsTopology; -import us.dot.its.jpo.conflictmonitor.monitor.algorithms.config.*; +import us.dot.its.jpo.conflictmonitor.monitor.algorithms.config.ConfigParameters; +import us.dot.its.jpo.conflictmonitor.monitor.algorithms.config.ConfigStreamsAlgorithm; +import us.dot.its.jpo.conflictmonitor.monitor.algorithms.config.ConfigUpdateResult; +import us.dot.its.jpo.conflictmonitor.monitor.algorithms.config.DefaultConfigListener; +import us.dot.its.jpo.conflictmonitor.monitor.algorithms.config.IntersectionConfigListener; +import us.dot.its.jpo.conflictmonitor.monitor.models.config.Config; +import us.dot.its.jpo.conflictmonitor.monitor.models.config.ConfigException; import us.dot.its.jpo.conflictmonitor.monitor.models.config.DefaultConfig; +import us.dot.its.jpo.conflictmonitor.monitor.models.config.DefaultConfigMap; import us.dot.its.jpo.conflictmonitor.monitor.models.config.IntersectionConfig; -import us.dot.its.jpo.conflictmonitor.monitor.models.config.*; +import us.dot.its.jpo.conflictmonitor.monitor.models.config.IntersectionConfigKey; +import us.dot.its.jpo.conflictmonitor.monitor.models.config.IntersectionConfigMap; +import us.dot.its.jpo.conflictmonitor.monitor.models.config.UpdateType; import us.dot.its.jpo.geojsonconverter.DateJsonMapper; -import java.util.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.TreeMap; import static org.apache.kafka.common.serialization.Serdes.String; import static us.dot.its.jpo.conflictmonitor.monitor.serialization.JsonSerdes.*; diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/timestamp_delta/AlternateMapTimestampDeltaAlgorithm.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/timestamp_delta/AlternateMapTimestampDeltaAlgorithm.java new file mode 100644 index 00000000..61a601d1 --- /dev/null +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/timestamp_delta/AlternateMapTimestampDeltaAlgorithm.java @@ -0,0 +1,30 @@ +package us.dot.its.jpo.conflictmonitor.monitor.topologies.timestamp_delta; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; +import us.dot.its.jpo.conflictmonitor.monitor.algorithms.timestamp_delta.map.MapTimestampDeltaAlgorithm; +import us.dot.its.jpo.conflictmonitor.monitor.algorithms.timestamp_delta.map.MapTimestampDeltaParameters; + +import static us.dot.its.jpo.conflictmonitor.monitor.algorithms.timestamp_delta.TimestampDeltaConstants.ALTERNATE_MAP_TIMESTAMP_DELTA_ALGORITHM; + +// Alternate algorithm that does nothing, for demonstrating the modular architecture +@Component(ALTERNATE_MAP_TIMESTAMP_DELTA_ALGORITHM) +@Slf4j +public class AlternateMapTimestampDeltaAlgorithm implements MapTimestampDeltaAlgorithm { + + MapTimestampDeltaParameters parameters; + + @Override + public void setParameters(MapTimestampDeltaParameters mapTimestampDeltaParameters) { + this.parameters = mapTimestampDeltaParameters; + } + + @Override + public MapTimestampDeltaParameters getParameters() { + return parameters; + } + + public void doNothing() { + log.info("Doing nothing"); + } +} diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/timestamp_delta/AlternateSpatTimestampDeltaAlgorithm.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/timestamp_delta/AlternateSpatTimestampDeltaAlgorithm.java new file mode 100644 index 00000000..14db64f5 --- /dev/null +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/timestamp_delta/AlternateSpatTimestampDeltaAlgorithm.java @@ -0,0 +1,30 @@ +package us.dot.its.jpo.conflictmonitor.monitor.topologies.timestamp_delta; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; +import us.dot.its.jpo.conflictmonitor.monitor.algorithms.timestamp_delta.spat.SpatTimestampDeltaAlgorithm; +import us.dot.its.jpo.conflictmonitor.monitor.algorithms.timestamp_delta.spat.SpatTimestampDeltaParameters; + +import static us.dot.its.jpo.conflictmonitor.monitor.algorithms.timestamp_delta.TimestampDeltaConstants.ALTERNATE_SPAT_TIMESTAMP_DELTA_ALGORITHM; + +// Alternate algorithm that does nothing, for demonstrating the modular architecture +@Component(ALTERNATE_SPAT_TIMESTAMP_DELTA_ALGORITHM) +@Slf4j +public class AlternateSpatTimestampDeltaAlgorithm implements SpatTimestampDeltaAlgorithm { + + SpatTimestampDeltaParameters parameters; + + @Override + public void setParameters(SpatTimestampDeltaParameters spatTimestampDeltaParameters) { + this.parameters = spatTimestampDeltaParameters; + } + + @Override + public SpatTimestampDeltaParameters getParameters() { + return parameters; + } + + public void doNothing() { + log.info("Doing nothing"); + } +} diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/timestamp_delta/BaseTimestampDeltaTopology.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/timestamp_delta/BaseTimestampDeltaTopology.java new file mode 100644 index 00000000..21f8b827 --- /dev/null +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/timestamp_delta/BaseTimestampDeltaTopology.java @@ -0,0 +1,114 @@ +package us.dot.its.jpo.conflictmonitor.monitor.topologies.timestamp_delta; + +import org.apache.kafka.common.serialization.Serde; +import org.apache.kafka.common.serialization.Serdes; +import org.apache.kafka.streams.StreamsBuilder; +import org.apache.kafka.streams.kstream.KStream; +import org.apache.kafka.streams.kstream.Produced; +import org.apache.kafka.streams.state.Stores; +import org.slf4j.Logger; +import us.dot.its.jpo.conflictmonitor.monitor.algorithms.BaseStreamsBuilder; +import us.dot.its.jpo.conflictmonitor.monitor.algorithms.timestamp_delta.BaseTimestampDeltaStreamsAlgorithm; +import us.dot.its.jpo.conflictmonitor.monitor.algorithms.timestamp_delta.ITimestampDeltaParameters; +import us.dot.its.jpo.conflictmonitor.monitor.models.events.timestamp_delta.BaseTimestampDeltaEvent; +import us.dot.its.jpo.conflictmonitor.monitor.models.events.timestamp_delta.TimestampDelta; +import us.dot.its.jpo.conflictmonitor.monitor.models.notifications.timestamp_delta.BaseTimestampDeltaNotification; +import us.dot.its.jpo.conflictmonitor.monitor.processors.timestamp_deltas.BaseTimestampDeltaNotificationProcessor; +import us.dot.its.jpo.geojsonconverter.partitioner.IntersectionIdPartitioner; +import us.dot.its.jpo.geojsonconverter.partitioner.RsuIntersectionKey; +import java.time.Duration; + +public abstract class BaseTimestampDeltaTopology + extends BaseStreamsBuilder + implements BaseTimestampDeltaStreamsAlgorithm { + + abstract protected Logger getLogger(); + abstract protected long extractMessageTimestamp(TMessage message); + abstract protected long extractOdeReceivedAt(TMessage message); + abstract protected TEvent constructEvent(); + abstract protected Serde eventSerde(); + abstract protected Serde notificationSerde(); + + // Construct an instance of the notification processor + abstract protected BaseTimestampDeltaNotificationProcessor + constructProcessor(Duration retentionTime, String eventStoreName, String keyStoreName); + + @Override + public void buildTopology(StreamsBuilder builder, KStream inputStream) { + + final String keyStoreName = parameters.getKeyStoreName(); + final String eventStoreName = parameters.getEventStoreName(); + final Duration retentionTime = Duration.ofMinutes(parameters.getRetentionTimeMinutes()); + final String outputTopicName = parameters.getOutputTopicName(); + final String notificationTopicName = parameters.getNotificationTopicName(); + final int maxDeltaMilliseconds = parameters.getMaxDeltaMilliseconds(); + final boolean isDebug = parameters.isDebug(); + + final var eventStoreBuilder = + Stores.versionedKeyValueStoreBuilder( + Stores.persistentVersionedKeyValueStore(eventStoreName, retentionTime), + us.dot.its.jpo.geojsonconverter.serialization.JsonSerdes.RsuIntersectionKey(), + eventSerde() + ); + final var keyStoreBuilder = + Stores.keyValueStoreBuilder( + Stores.persistentKeyValueStore(keyStoreName), + us.dot.its.jpo.geojsonconverter.serialization.JsonSerdes.RsuIntersectionKey(), + Serdes.Boolean() + ); + builder.addStateStore(eventStoreBuilder); + builder.addStateStore(keyStoreBuilder); + + KStream eventStream = + inputStream + // Ignore tombstones + .filter((rsuIntersectionKey, processedMap) -> processedMap != null) + + // Calculate timestamp delta + .mapValues((rsuIntersectionKey, processedMap) -> { + TimestampDelta delta = new TimestampDelta(); + delta.setMaxDeltaMillis(maxDeltaMilliseconds); + delta.setMessageTimestampMillis(extractMessageTimestamp(processedMap)); + delta.setOdeIngestTimestampMillis(extractOdeReceivedAt(processedMap)); + if (isDebug) { + getLogger().debug("RSU: {}, TimestampDelta: {}", rsuIntersectionKey.getRsuId(), delta); + } + return delta; + }) + + // Filter out deltas that shouldn't emit events + .filter((rsuIntersectionKey, timestampDelta) -> timestampDelta.emitEvent()) + + // Create Events + .mapValues((rsuIntersectionKey, timestampDelta) -> { + TEvent event = constructEvent(); + event.setDelta(timestampDelta); + event.setSource(rsuIntersectionKey.getRsuId()); + event.setIntersectionID(rsuIntersectionKey.getIntersectionId()); + event.setRoadRegulatorID(rsuIntersectionKey.getRegion()); + if (isDebug) { + getLogger().info("Producing TimestampDeltaEvent: {}", event); + } + return event; + }); + + // Output events + eventStream.to(outputTopicName, Produced.with( + us.dot.its.jpo.geojsonconverter.serialization.JsonSerdes.RsuIntersectionKey(), + eventSerde(), + new IntersectionIdPartitioner<>())); // Don't change partitioning of output + + + + // Collect events to issue hourly summary notifications + eventStream + .process(() -> constructProcessor(retentionTime, eventStoreName, keyStoreName), + eventStoreName, keyStoreName) + .to(notificationTopicName, + Produced.with( + us.dot.its.jpo.geojsonconverter.serialization.JsonSerdes.RsuIntersectionKey(), + notificationSerde(), + new IntersectionIdPartitioner<>())); + } +} diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/timestamp_delta/MapTimestampDeltaTopology.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/timestamp_delta/MapTimestampDeltaTopology.java new file mode 100644 index 00000000..bda0d3e3 --- /dev/null +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/timestamp_delta/MapTimestampDeltaTopology.java @@ -0,0 +1,64 @@ +package us.dot.its.jpo.conflictmonitor.monitor.topologies.timestamp_delta; + +import lombok.extern.slf4j.Slf4j; +import org.apache.kafka.common.serialization.Serde; +import org.slf4j.Logger; +import org.springframework.stereotype.Component; +import us.dot.its.jpo.conflictmonitor.monitor.algorithms.timestamp_delta.map.MapTimestampDeltaParameters; +import us.dot.its.jpo.conflictmonitor.monitor.algorithms.timestamp_delta.map.MapTimestampDeltaStreamsAlgorithm; +import us.dot.its.jpo.conflictmonitor.monitor.models.events.timestamp_delta.MapTimestampDeltaEvent; +import us.dot.its.jpo.conflictmonitor.monitor.models.notifications.timestamp_delta.MapTimestampDeltaNotification; +import us.dot.its.jpo.conflictmonitor.monitor.processors.timestamp_deltas.BaseTimestampDeltaNotificationProcessor; +import us.dot.its.jpo.conflictmonitor.monitor.processors.timestamp_deltas.MapTimestampDeltaNotificationProcessor; +import us.dot.its.jpo.conflictmonitor.monitor.serialization.JsonSerdes; +import us.dot.its.jpo.conflictmonitor.monitor.utils.ProcessedMapUtils; +import us.dot.its.jpo.geojsonconverter.pojos.geojson.LineString; +import us.dot.its.jpo.geojsonconverter.pojos.geojson.map.ProcessedMap; + +import java.time.Duration; + +import static us.dot.its.jpo.conflictmonitor.monitor.algorithms.timestamp_delta.TimestampDeltaConstants.DEFAULT_MAP_TIMESTAMP_DELTA_ALGORITHM; + +@Component(DEFAULT_MAP_TIMESTAMP_DELTA_ALGORITHM) +@Slf4j +public class MapTimestampDeltaTopology + extends BaseTimestampDeltaTopology, MapTimestampDeltaParameters, MapTimestampDeltaEvent, + MapTimestampDeltaNotification> + implements MapTimestampDeltaStreamsAlgorithm { + + @Override + protected Logger getLogger() { + return log; + } + + @Override + protected long extractMessageTimestamp(ProcessedMap message) { + return ProcessedMapUtils.getTimestamp(message); + } + + @Override + protected long extractOdeReceivedAt(ProcessedMap message) { + return ProcessedMapUtils.getOdeReceivedAt(message); + } + + @Override + protected MapTimestampDeltaEvent constructEvent() { + return new MapTimestampDeltaEvent(); + } + + @Override + protected Serde eventSerde() { + return JsonSerdes.MapTimestampDeltaEvent(); + } + + @Override + protected Serde notificationSerde() { + return JsonSerdes.MapTimestampDeltaNotification(); + } + + @Override + protected BaseTimestampDeltaNotificationProcessor constructProcessor(Duration retentionTime, String eventStoreName, String keyStoreName) { + return new MapTimestampDeltaNotificationProcessor(retentionTime, eventStoreName, keyStoreName); + } + +} diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/timestamp_delta/SpatTimestampDeltaTopology.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/timestamp_delta/SpatTimestampDeltaTopology.java new file mode 100644 index 00000000..1064759a --- /dev/null +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/timestamp_delta/SpatTimestampDeltaTopology.java @@ -0,0 +1,63 @@ +package us.dot.its.jpo.conflictmonitor.monitor.topologies.timestamp_delta; + +import lombok.extern.slf4j.Slf4j; +import org.apache.kafka.common.serialization.Serde; +import org.slf4j.Logger; +import org.springframework.stereotype.Component; +import us.dot.its.jpo.conflictmonitor.monitor.algorithms.timestamp_delta.spat.SpatTimestampDeltaParameters; +import us.dot.its.jpo.conflictmonitor.monitor.algorithms.timestamp_delta.spat.SpatTimestampDeltaStreamsAlgorithm; +import us.dot.its.jpo.conflictmonitor.monitor.models.events.timestamp_delta.SpatTimestampDeltaEvent; +import us.dot.its.jpo.conflictmonitor.monitor.models.notifications.timestamp_delta.SpatTimestampDeltaNotification; +import us.dot.its.jpo.conflictmonitor.monitor.processors.timestamp_deltas.BaseTimestampDeltaNotificationProcessor; +import us.dot.its.jpo.conflictmonitor.monitor.processors.timestamp_deltas.SpatTimestampDeltaNotificationProcessor; +import us.dot.its.jpo.conflictmonitor.monitor.serialization.JsonSerdes; +import us.dot.its.jpo.conflictmonitor.monitor.utils.SpatUtils; +import us.dot.its.jpo.geojsonconverter.pojos.spat.ProcessedSpat; + +import java.time.Duration; + +import static us.dot.its.jpo.conflictmonitor.monitor.algorithms.timestamp_delta.TimestampDeltaConstants.DEFAULT_SPAT_TIMESTAMP_DELTA_ALGORITHM; + +@Component(DEFAULT_SPAT_TIMESTAMP_DELTA_ALGORITHM) +@Slf4j +public class SpatTimestampDeltaTopology + extends BaseTimestampDeltaTopology + implements SpatTimestampDeltaStreamsAlgorithm { + + @Override + protected Logger getLogger() { + return log; + } + + @Override + protected long extractMessageTimestamp(ProcessedSpat processedSpat) { + return SpatUtils.getTimestamp(processedSpat); + } + + @Override + protected long extractOdeReceivedAt(ProcessedSpat processedSpat) { + return SpatUtils.getOdeReceivedAt(processedSpat); + } + + @Override + protected SpatTimestampDeltaEvent constructEvent() { + return new SpatTimestampDeltaEvent(); + } + + @Override + protected Serde eventSerde() { + return JsonSerdes.SpatTimestampDeltaEvent(); + } + + @Override + protected Serde notificationSerde() { + return JsonSerdes.SpatTimestampDeltaNotification(); + } + + @Override + protected BaseTimestampDeltaNotificationProcessor constructProcessor(Duration retentionTime, String eventStoreName, String keyStoreName) { + return new SpatTimestampDeltaNotificationProcessor(retentionTime, eventStoreName, keyStoreName); + } + +} diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/validation/AlternateMapValidationAlgorithm.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/validation/AlternateMapValidationAlgorithm.java index 64d92776..3e92a905 100644 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/validation/AlternateMapValidationAlgorithm.java +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/validation/AlternateMapValidationAlgorithm.java @@ -9,8 +9,10 @@ import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; +import us.dot.its.jpo.conflictmonitor.monitor.algorithms.timestamp_delta.map.MapTimestampDeltaAlgorithm; import us.dot.its.jpo.conflictmonitor.monitor.algorithms.validation.map.MapValidationAlgorithm; import us.dot.its.jpo.conflictmonitor.monitor.algorithms.validation.map.MapValidationParameters; +import us.dot.its.jpo.conflictmonitor.monitor.topologies.timestamp_delta.AlternateMapTimestampDeltaAlgorithm; /** * Test algorithm just writes random numbers to the log @@ -38,6 +40,9 @@ public void start() { // Don't run if not debugging if (!parameters.isDebug()) return; + // Plugin algorithm + timestampDeltaAlgorithm.doNothing(); + timer = new Timer(); timer.scheduleAtFixedRate(new TimerTask() { @@ -63,5 +68,23 @@ public void stop() { } } - + + + AlternateMapTimestampDeltaAlgorithm timestampDeltaAlgorithm; + + + @Override + public MapTimestampDeltaAlgorithm getTimestampDeltaAlgorithm() { + return timestampDeltaAlgorithm; + } + + @Override + public void setTimestampDeltaAlgorithm(MapTimestampDeltaAlgorithm timestampDeltaAlgorithm) { + // Enforce a specific algorithm implementation + if (timestampDeltaAlgorithm instanceof AlternateMapTimestampDeltaAlgorithm altAlgorithm) { + this.timestampDeltaAlgorithm = altAlgorithm; + } else { + throw new IllegalArgumentException("Algorithm is not an instance of AlternateMapTimestampDeltaAlgorithm"); + } + } } diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/validation/AlternateSpatValidationAlgorithm.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/validation/AlternateSpatValidationAlgorithm.java index 3002c0f4..454f6d3c 100644 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/validation/AlternateSpatValidationAlgorithm.java +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/validation/AlternateSpatValidationAlgorithm.java @@ -9,8 +9,10 @@ import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; +import us.dot.its.jpo.conflictmonitor.monitor.algorithms.timestamp_delta.spat.SpatTimestampDeltaAlgorithm; import us.dot.its.jpo.conflictmonitor.monitor.algorithms.validation.spat.SpatValidationAlgorithm; import us.dot.its.jpo.conflictmonitor.monitor.algorithms.validation.spat.SpatValidationParameters; +import us.dot.its.jpo.conflictmonitor.monitor.topologies.timestamp_delta.AlternateSpatTimestampDeltaAlgorithm; /** * Test SPAT algorithm, writes random numbers to the log in debug mode. @@ -64,4 +66,22 @@ public void stop() { } } + + AlternateSpatTimestampDeltaAlgorithm timestampDeltaAlgorithm; + + + @Override + public SpatTimestampDeltaAlgorithm getTimestampDeltaAlgorithm() { + return timestampDeltaAlgorithm; + } + + @Override + public void setTimestampDeltaAlgorithm(SpatTimestampDeltaAlgorithm timestampDeltaAlgorithm) { + // Enforce a specific algorithm implementation + if (timestampDeltaAlgorithm instanceof AlternateSpatTimestampDeltaAlgorithm altAlgorithm) { + this.timestampDeltaAlgorithm = altAlgorithm; + } else { + throw new IllegalArgumentException("Algorithm is not an instance of AlternateSpatTimestampDeltaAlgorithm"); + } + } } diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/validation/MapValidationTopology.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/validation/MapValidationTopology.java index efdf7fc4..6142cd0f 100644 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/validation/MapValidationTopology.java +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/validation/MapValidationTopology.java @@ -7,13 +7,13 @@ import org.apache.kafka.streams.Topology; import org.apache.kafka.streams.kstream.*; import org.apache.kafka.streams.kstream.Suppressed.BufferConfig; -import org.apache.kafka.streams.processor.api.FixedKeyProcessor; -import org.apache.kafka.streams.processor.api.FixedKeyProcessorSupplier; import org.apache.kafka.streams.state.Stores; import org.apache.kafka.streams.state.WindowStore; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; +import us.dot.its.jpo.conflictmonitor.monitor.algorithms.timestamp_delta.map.MapTimestampDeltaAlgorithm; +import us.dot.its.jpo.conflictmonitor.monitor.algorithms.timestamp_delta.map.MapTimestampDeltaStreamsAlgorithm; import us.dot.its.jpo.conflictmonitor.monitor.algorithms.validation.map.MapValidationParameters; import us.dot.its.jpo.conflictmonitor.monitor.algorithms.validation.map.MapValidationStreamsAlgorithm; import us.dot.its.jpo.conflictmonitor.monitor.models.IntersectionRegion; @@ -49,8 +49,34 @@ protected Logger getLogger() { private static final String LATEST_TIMESTAMP_STORE = "latest-timestamp-store"; + MapTimestampDeltaStreamsAlgorithm timestampDeltaAlgorithm; + + @Override + public MapTimestampDeltaAlgorithm getTimestampDeltaAlgorithm() { + return timestampDeltaAlgorithm; + } + + @Override + public void setTimestampDeltaAlgorithm(MapTimestampDeltaAlgorithm timestampDeltaAlgorithm) { + // Enforce the algorithm being a Streams algorithm + if (timestampDeltaAlgorithm instanceof MapTimestampDeltaStreamsAlgorithm timestampDeltaStreamsAlgorithm) { + this.timestampDeltaAlgorithm = timestampDeltaStreamsAlgorithm; + } else { + throw new IllegalArgumentException("algorithm is not an instance of MapTimestampDeltaStreamsAlgorithm"); + } + } + + @Override + protected void validate() { + super.validate(); + + if (timestampDeltaAlgorithm == null) { + throw new IllegalStateException("MapTimestampDeltaAlgorithm is not set."); + } + } public Topology buildTopology() { + var builder = new StreamsBuilder(); // Create state store for zero count @@ -69,6 +95,9 @@ public Topology buildTopology() { .withTimestampExtractor(new TimestampExtractorForBroadcastRate()) ); + // timestamp delta plugin after reading processed MAPs + timestampDeltaAlgorithm.buildTopology(builder, processedMapStream); + // Extract validation info for Minimum Data events KStream minDataStream = processedMapStream // Filter out messages that are valid @@ -200,5 +229,5 @@ public Topology buildTopology() { } - + } diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/validation/SpatValidationTopology.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/validation/SpatValidationTopology.java index 48414010..4f1cb467 100644 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/validation/SpatValidationTopology.java +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/validation/SpatValidationTopology.java @@ -12,6 +12,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; +import us.dot.its.jpo.conflictmonitor.monitor.algorithms.timestamp_delta.spat.SpatTimestampDeltaAlgorithm; +import us.dot.its.jpo.conflictmonitor.monitor.algorithms.timestamp_delta.spat.SpatTimestampDeltaStreamsAlgorithm; import us.dot.its.jpo.conflictmonitor.monitor.algorithms.validation.spat.SpatValidationParameters; import us.dot.its.jpo.conflictmonitor.monitor.algorithms.validation.spat.SpatValidationStreamsAlgorithm; import us.dot.its.jpo.conflictmonitor.monitor.models.events.ProcessingTimePeriod; @@ -44,6 +46,31 @@ protected Logger getLogger() { private static final String LATEST_TIMESTAMP_STORE = "latest-timestamp-store"; + SpatTimestampDeltaStreamsAlgorithm timestampDeltaAlgorithm; + + @Override + public SpatTimestampDeltaAlgorithm getTimestampDeltaAlgorithm() { + return timestampDeltaAlgorithm; + } + + @Override + public void setTimestampDeltaAlgorithm(SpatTimestampDeltaAlgorithm timestampDeltaAlgorithm) { + // Enforce the algorithm being a Streams algorithm + if (timestampDeltaAlgorithm instanceof SpatTimestampDeltaStreamsAlgorithm timestampDeltaStreamsAlgorithm) { + this.timestampDeltaAlgorithm = timestampDeltaStreamsAlgorithm; + } else { + throw new IllegalArgumentException("Algorithm is not an instance of SpatTimestampDeltaStreamsAlgorithm"); + } + } + + @Override + protected void validate() { + super.validate(); + + if (timestampDeltaAlgorithm == null) { + throw new IllegalStateException("SpatTimestampDeltaAlgorithm is not set"); + } + } @Override public Topology buildTopology() { @@ -65,6 +92,9 @@ public Topology buildTopology() { .withTimestampExtractor(new TimestampExtractorForBroadcastRate()) ); + // timestamp delta plugin after reading processed SPATs + timestampDeltaAlgorithm.buildTopology(builder, processedSpatStream); + // Extract validation info for Minimum Data events processedSpatStream .filter((key, value) -> value != null && !value.getCti4501Conformant()) @@ -180,5 +210,4 @@ public Topology buildTopology() { - } 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 f809fd12..78a579d8 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 @@ -1,5 +1,6 @@ package us.dot.its.jpo.conflictmonitor.monitor.utils; +import lombok.extern.slf4j.Slf4j; import org.locationtech.jts.geom.CoordinateXY; import us.dot.its.jpo.ode.model.OdeBsmData; import us.dot.its.jpo.ode.model.OdeBsmMetadata; @@ -8,8 +9,11 @@ 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 public class BsmUtils { public static CoordinateXY getPosition(OdeBsmData bsm) { CoordinateXY position = new CoordinateXY(); @@ -74,4 +78,18 @@ public static String getRsuIp(OdeBsmData bsm) { } 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/main/java/us/dot/its/jpo/conflictmonitor/monitor/utils/ProcessedMapUtils.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/utils/ProcessedMapUtils.java new file mode 100644 index 00000000..bdbca8b2 --- /dev/null +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/utils/ProcessedMapUtils.java @@ -0,0 +1,52 @@ +package us.dot.its.jpo.conflictmonitor.monitor.utils; + +import lombok.extern.slf4j.Slf4j; +import us.dot.its.jpo.geojsonconverter.pojos.geojson.map.MapSharedProperties; +import us.dot.its.jpo.geojsonconverter.pojos.geojson.map.ProcessedMap; + +import java.time.ZonedDateTime; + +/** + * Methods to get properties from ProcessedMaps with null checks + */ +@Slf4j +public class ProcessedMapUtils { + + public static long getTimestamp(ProcessedMap processedMap) { + if (processedMap == null) { + log.error("ProcessedMap is null"); + return 0L; + } + MapSharedProperties properties = processedMap.getProperties(); + if (properties == null) { + log.error("ProcessedMap.properties are null"); + return 0L; + } + ZonedDateTime zdt = properties.getTimeStamp(); + if (zdt == null) { + log.error("ProcessedMap Timestamp is null"); + return 0L; + } + return zdt.toInstant().toEpochMilli(); + } + + public static long getOdeReceivedAt(ProcessedMap processedMap) { + if (processedMap == null) { + log.error("ProcessedMap is null"); + return 0L; + } + MapSharedProperties properties = processedMap.getProperties(); + if (properties == null) { + log.error("ProcessedMap.properties are null"); + return 0L; + } + ZonedDateTime zdt = properties.getOdeReceivedAt(); + if (zdt == null) { + log.error("ProcessedMap.OdeReceivedAt is null"); + return 0L; + } + return zdt.toInstant().toEpochMilli(); + } + + +} diff --git a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/utils/SpatUtils.java b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/utils/SpatUtils.java index d876245a..c281c4f9 100644 --- a/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/utils/SpatUtils.java +++ b/jpo-conflictmonitor/src/main/java/us/dot/its/jpo/conflictmonitor/monitor/utils/SpatUtils.java @@ -4,14 +4,20 @@ import lombok.Getter; import lombok.Setter; import lombok.ToString; +import lombok.extern.slf4j.Slf4j; import us.dot.its.jpo.conflictmonitor.monitor.models.spat.SpatTimestampExtractor; -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; import us.dot.its.jpo.ode.plugin.j2735.J2735MovementPhaseState; -import java.util.*; +import java.time.Instant; +import java.time.ZonedDateTime; +import java.time.format.DateTimeParseException; +import java.util.ArrayList; +import java.util.List; +import java.util.ListIterator; +@Slf4j public class SpatUtils { public static J2735MovementPhaseState getSignalGroupState(ProcessedSpat spat, int signalGroup){ @@ -99,6 +105,8 @@ public static SpatStatistics getSpatStatistics(List spats, int si long redMillis = 0; long yellowMillis = 0; long greenMillis = 0; + long darkMillis = 0; + List spatTimingList = getSpatTiming(spats, signalGroupId); for (SpatTiming spatTiming : spatTimingList) { switch (spatTiming.getState()) { @@ -113,11 +121,13 @@ public static SpatStatistics getSpatStatistics(List spats, int si case PROTECTED_MOVEMENT_ALLOWED: greenMillis += spatTiming.getDuration(); break; + case DARK: + darkMillis += spatTiming.getDuration(); default: break; } } - return new SpatStatistics(redMillis/1000.0, yellowMillis/1000.0, greenMillis/1000.0); + return new SpatStatistics(redMillis/1000.0, yellowMillis/1000.0, greenMillis/1000.0, darkMillis/1000.0); } @Getter @@ -156,5 +166,46 @@ public static class SpatStatistics { * vehicle was stopped. */ private double timeStoppedDuringGreen; + + + /** + * The amount of time (seconds) the event state was ‘dark’ while the + * vehicle was stopped. + */ + private double timeStoppedDuringDark; + + + + } + + public static long getTimestamp(ProcessedSpat processedSpat) { + if (processedSpat == null) { + log.error("ProcessedSpat is null"); + return 0L; + } + ZonedDateTime zdt = processedSpat.getUtcTimeStamp(); + if (zdt == null) { + log.error("ProcessedSpat.UtcTimeStamp is null"); + return 0L; + } + return zdt.toInstant().toEpochMilli(); + } + + public static long getOdeReceivedAt(ProcessedSpat processedSpat) { + if (processedSpat == null) { + log.error("ProcessedSpat is null"); + return 0L; + } + String odeReceivedAtStr = processedSpat.getOdeReceivedAt(); + if (odeReceivedAtStr == null) { + log.error("ProcessedSpat.OdeReceivedAt is null"); + return 0L; + } + try { + return Instant.parse(odeReceivedAtStr).toEpochMilli(); + } catch (Exception ex) { + log.error("Exception parsing ProcessedSpat.OdeReceivedAt", ex); + return 0L; + } } } diff --git a/jpo-conflictmonitor/src/main/resources/application.yaml b/jpo-conflictmonitor/src/main/resources/application.yaml index 3f4ae7b2..d2a26282 100644 --- a/jpo-conflictmonitor/src/main/resources/application.yaml +++ b/jpo-conflictmonitor/src/main/resources/application.yaml @@ -162,6 +162,20 @@ kafka.topics: - name: topic.CmStopLinePassageNotification cleanupPolicy: compact retentionMs: 300000 + - name: topic.CmMapRevisionCounterEvents + cleanupPolicy: compact + retentionMs: 300000 + - name: topic.CmSpatRevisionCounterEvents + cleanupPolicy: compact + retentionMs: 300000 + - name: topic.CmBsmRevisionCounterEvents + cleanupPolicy: compact + retentionMs: 300000 + - name: topic.CmTimestampDeltaEvent + cleanupPolicy: delete + retentionMs: 300000 + - name: topic.CmTimestampDeltaNotification + cleanupPolicy: compact # - name: topic.CmSpatBroadcastRateNotification # cleanupPolicy: compact # - name: topic.CmMapBroadcastRateNotification @@ -225,6 +239,7 @@ map.spat.message.assessment: signalGroupAlignmentNotificationTopicName: topic.CmSignalGroupAlignmentNotification signalStateConflictNotificationTopicName: topic.CmSignalStateConflictNotification + # MAP Time Change Details map.time.change.details: algorithm: defaultMapTimeChangeDetailsAlgorithm @@ -265,6 +280,7 @@ notification: signalGroupAlignmentNotificationTopicName: topic.CmSignalGroupAlignmentNotification signalStateConflictNotificationTopicName: topic.CmSignalStateConflictNotification spatTimeChangeDetailsNotificationTopicName: topic.CmSpatTimeChangeDetailsNotification + timestampDeltaNotificationTopicName: topic.CmTimestampDeltaNotification assessment: algorithm: defaultAssessmentAlgorithm @@ -276,6 +292,8 @@ assessment: event: algorithm: defaultEventAlgorithm + enabled: false +# enabled: true debug: false eventOutputTopicName: topic.CmEvent signalStateEventTopicName: topic.CmStopLinePassageEvent @@ -289,8 +307,10 @@ event: signalStateConflictEventTopicName: topic.CmSignalStateConflictEvents laneDirectionOfTravelEventTopicName: topic.CmLaneDirectionOfTravelEvent connectionOfTravelEventTopicName: topic.CmConnectionOfTravelEvent - - + spatRevisionCounterEventTopicName: topic.CmSpatRevisionCounterEvents + mapRevisionCounterEventTopicName: topic.CmMapRevisionCounterEvents + bsmRevisionCounterEventTopicName: topic.CmBsmRevisionCounterEvents + timestampDeltaEventTopicName: topic.CmTimestampDeltaEvent # Signal State Event Assessment stop.line.passage.assessment: @@ -388,6 +408,27 @@ message.ingest: mapStoreName: ProcessedMapWindowStore mapSpatialIndexStoreName: MapSpatialIndexStore +# MAP Revision Counter +map.revision.counter: + algorithm: defaultMapRevisionCounterAlgorithm + debug: false + mapInputTopicName: topic.ProcessedMap + mapRevisionEventOutputTopicName: topic.CmMapRevisionCounterEvents + +# SPAT Revision Counter +spat.revision.counter: + algorithm: defaultSpatRevisionCounterAlgorithm + debug: false + spatInputTopicName: topic.ProcessedSpat + spatRevisionEventOutputTopicName: topic.CmSpatRevisionCounterEvents + +# BSM Revision Counter +bsm.revision.counter: + algorithm: defaultBsmRevisionCounterAlgorithm + debug: false + bsmInputTopicName: topic.CmBsmJsonRepartition + bsmRevisionEventOutputTopicName: topic.CmBsmRevisionCounterEvents + # Config parameters config: defaultStateStore: default-config @@ -397,5 +438,28 @@ config: mergedTopicName: topic.CmMergedConfigTable intersectionTableName: topic.CmIntersectionConfigTable +# MAP Timestamp Delta parameters +map.timestamp.delta: + algorithm: defaultMapTimestampDeltaAlgorithm + outputTopicName: topic.CmTimestampDeltaEvent + maxDeltaMilliseconds: 50 + debug: false + keyStoreName: mapTimestampDeltaKeyStore + eventStoreName: mapTimestampDeltaEventStore + retentionTimeMinutes: 60 +# retentionTimeMinutes: 5 + notificationTopicName: topic.CmTimestampDeltaNotification + +# SPaT Timestamp Delta parameters +spat.timestamp.delta: + algorithm: defaultSpatTimestampDeltaAlgorithm + outputTopicName: topic.CmTimestampDeltaEvent + maxDeltaMilliseconds: 50 + debug: false + keyStoreName: spatTimestampDeltaKeyStore + eventStoreName: spatTimestampDeltaEventStore + retentionTimeMinutes: 60 +# retentionTimeMinutes: 5 + notificationTopicName: topic.CmTimestampDeltaNotification 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 b4e8664a..8e4db08a 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 @@ -68,6 +68,8 @@ public void testSpatBroadcastRateParameters() { assertThat(props.getMinimumDataTopicName(), equalTo("topic.CmSpatMinimumDataEvents")); } + + @Test public void testKafkaAdminInjected() { assertThat(kafkaAdmin, notNullValue()); @@ -173,6 +175,7 @@ public void testGetProperty_DefaultInt() { public void testGetProperty_DefaultString() { assertThat(properties.getProperty("artifactId", "default"), allOf(notNullValue(), not(equalTo("default")))); } - + + } diff --git a/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/monitor/ConfigControllerTest.java b/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/monitor/ConfigControllerTest.java index 6ae0dd7b..87bde86f 100644 --- a/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/monitor/ConfigControllerTest.java +++ b/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/monitor/ConfigControllerTest.java @@ -16,15 +16,20 @@ import org.springframework.test.web.servlet.MockMvc; import us.dot.its.jpo.conflictmonitor.ConflictMonitorProperties; import us.dot.its.jpo.conflictmonitor.monitor.algorithms.config.ConfigUpdateResult; -import us.dot.its.jpo.conflictmonitor.monitor.models.config.DefaultConfig; +import us.dot.its.jpo.conflictmonitor.monitor.models.concurrent_permissive.ConnectedLanes; +import us.dot.its.jpo.conflictmonitor.monitor.models.concurrent_permissive.ConnectedLanesPair; +import us.dot.its.jpo.conflictmonitor.monitor.models.concurrent_permissive.ConnectedLanesPairList; +import us.dot.its.jpo.conflictmonitor.monitor.models.config.Config; import us.dot.its.jpo.conflictmonitor.monitor.models.config.IntersectionConfig; import us.dot.its.jpo.conflictmonitor.monitor.models.config.IntersectionConfigKey; +import us.dot.its.jpo.conflictmonitor.monitor.models.config.UnitsEnum; import us.dot.its.jpo.conflictmonitor.monitor.topologies.config.ConfigTopology; import us.dot.its.jpo.conflictmonitor.testutils.ConfigTestUtils; import java.util.Optional; import static org.hamcrest.Matchers.containsString; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.when; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; @@ -185,4 +190,47 @@ public void testSaveIntersectionConfig_NoRegion() throws Exception { .andExpect(content().string(containsString(ConfigUpdateResult.Result.UPDATED.toString()))); } + + @Test + public void testSaveIntersectionConfig_ConcurrentPermissive() throws Exception { + final String key = "map.spat.message.assessment.concurrentPermissiveList"; + final int intersectionId = ConfigTestUtils.intersectionId; + final int region = ConfigTestUtils.regionId; + final String description = "Concurrent permissive lanes"; + final ConnectedLanesPairList pairList = new ConnectedLanesPairList(); + ConnectedLanesPair pair1 = new ConnectedLanesPair(); + pair1.setFirst(new ConnectedLanes(1, 2)); + pair1.setSecond(new ConnectedLanes(3, 4)); + ConnectedLanesPair pair2 = new ConnectedLanesPair(); + pair2.setFirst(new ConnectedLanes(5, 6)); + pair2.setSecond(new ConnectedLanes(7, 8)); + pairList.add(pair1); + pairList.add(pair2); + + final var config = new IntersectionConfig(); + config.setKey(key); + config.setValue(pairList); + config.setCategory("test"); + config.setUnits(UnitsEnum.NONE); + config.setDescription(description); + config.setIntersectionID(intersectionId); + config.setRoadRegulatorID(region); + config.setType(ConnectedLanesPairList.class.getName()); + + final ConfigUpdateResult expectUpdateResult = ConfigTestUtils.getUpdateResult(config); + logger.info("Expect update result: {}", expectUpdateResult); + + when(configTopology.updateIntersectionConfig(any())).thenReturn((ConfigUpdateResult)expectUpdateResult); + + mockMvc.perform( + post("/config/intersection/{region}/{intersectionId}/{key}", region, intersectionId, key) + .content(config.toString()) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.ALL) + ).andDo(mvcResult -> logger.info("POST /config/intersection/{}/{}/{}: {}", region, intersectionId, key, mvcResult.getResponse().getContentAsString())) + .andExpect(status().isOk()) + .andExpect(content().string(containsString(config.getIntersectionKey()))) + .andExpect(content().string(containsString(ConfigUpdateResult.Result.UPDATED.toString()))); + + } } 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 7c86f8e6..f5162677 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 @@ -56,12 +56,27 @@ import us.dot.its.jpo.conflictmonitor.monitor.algorithms.time_change_details.spat.SpatTimeChangeDetailsAlgorithmFactory; import us.dot.its.jpo.conflictmonitor.monitor.algorithms.time_change_details.spat.SpatTimeChangeDetailsParameters; import us.dot.its.jpo.conflictmonitor.monitor.algorithms.time_change_details.spat.SpatTimeChangeDetailsStreamsAlgorithm; +import us.dot.its.jpo.conflictmonitor.monitor.algorithms.timestamp_delta.map.MapTimestampDeltaAlgorithmFactory; +import us.dot.its.jpo.conflictmonitor.monitor.algorithms.timestamp_delta.map.MapTimestampDeltaParameters; +import us.dot.its.jpo.conflictmonitor.monitor.algorithms.timestamp_delta.map.MapTimestampDeltaStreamsAlgorithm; +import us.dot.its.jpo.conflictmonitor.monitor.algorithms.timestamp_delta.spat.SpatTimestampDeltaAlgorithmFactory; +import us.dot.its.jpo.conflictmonitor.monitor.algorithms.timestamp_delta.spat.SpatTimestampDeltaParameters; +import us.dot.its.jpo.conflictmonitor.monitor.algorithms.timestamp_delta.spat.SpatTimestampDeltaStreamsAlgorithm; import us.dot.its.jpo.conflictmonitor.monitor.algorithms.validation.map.MapValidationAlgorithmFactory; import us.dot.its.jpo.conflictmonitor.monitor.algorithms.validation.map.MapValidationParameters; import us.dot.its.jpo.conflictmonitor.monitor.algorithms.validation.map.MapValidationStreamsAlgorithm; import us.dot.its.jpo.conflictmonitor.monitor.algorithms.validation.spat.SpatValidationParameters; import us.dot.its.jpo.conflictmonitor.monitor.algorithms.validation.spat.SpatValidationStreamsAlgorithm; import us.dot.its.jpo.conflictmonitor.monitor.algorithms.validation.spat.SpatValidationStreamsAlgorithmFactory; +import us.dot.its.jpo.conflictmonitor.monitor.algorithms.map_revision_counter.MapRevisionCounterAlgorithm; +import us.dot.its.jpo.conflictmonitor.monitor.algorithms.map_revision_counter.MapRevisionCounterAlgorithmFactory; +import us.dot.its.jpo.conflictmonitor.monitor.algorithms.map_revision_counter.MapRevisionCounterParameters; +import us.dot.its.jpo.conflictmonitor.monitor.algorithms.spat_revision_counter.SpatRevisionCounterAlgorithm; +import us.dot.its.jpo.conflictmonitor.monitor.algorithms.spat_revision_counter.SpatRevisionCounterAlgorithmFactory; +import us.dot.its.jpo.conflictmonitor.monitor.algorithms.spat_revision_counter.SpatRevisionCounterParameters; +import us.dot.its.jpo.conflictmonitor.monitor.algorithms.bsm_revision_counter.BsmRevisionCounterAlgorithm; +import us.dot.its.jpo.conflictmonitor.monitor.algorithms.bsm_revision_counter.BsmRevisionCounterAlgorithmFactory; +import us.dot.its.jpo.conflictmonitor.monitor.algorithms.bsm_revision_counter.BsmRevisionCounterParameters; import us.dot.its.jpo.conflictmonitor.monitor.models.map.MapIndex; import us.dot.its.jpo.conflictmonitor.monitor.topologies.config.ConfigInitializer; import us.dot.its.jpo.conflictmonitor.monitor.topologies.config.ConfigTopology; @@ -95,10 +110,18 @@ public class MonitorServiceControllerTest { @Mock MapValidationStreamsAlgorithm mapValidationAlgorithm; MapValidationParameters mapValidationParameters = new MapValidationParameters(); + @Mock MapTimestampDeltaAlgorithmFactory mapTimestampDeltaAlgorithmFactory; + @Mock MapTimestampDeltaStreamsAlgorithm mapTimestampDeltaStreamsAlgorithm; + MapTimestampDeltaParameters mapTimestampDeltaParameters = new MapTimestampDeltaParameters(); + @Mock SpatValidationStreamsAlgorithmFactory spatValidationStreamsAlgorithmFactory; @Mock SpatValidationStreamsAlgorithm spatValidationAlgorithm; SpatValidationParameters spatValidationParameters = new SpatValidationParameters(); + @Mock SpatTimestampDeltaAlgorithmFactory spatTimestampDeltaAlgorithmFactory; + @Mock SpatTimestampDeltaStreamsAlgorithm spatTimestampDeltaStreamsAlgorithm; + SpatTimestampDeltaParameters spatTimestampDeltaParameters = new SpatTimestampDeltaParameters(); + @Mock SpatTimeChangeDetailsAlgorithmFactory spatTimeChangeDetailsAlgorithmFactory; @Mock SpatTimeChangeDetailsStreamsAlgorithm spatTimeChangeDetailsAlgorithm; SpatTimeChangeDetailsParameters spatTimeChangeDetailsParameters = new SpatTimeChangeDetailsParameters(); @@ -154,6 +177,18 @@ public class MonitorServiceControllerTest { @Mock StopLineStopAssessmentStreamsAlgorithm stopLineStopAssessmentAlgorithm; StopLineStopAssessmentParameters stopLineStopAssessmentParameters = new StopLineStopAssessmentParameters(); + @Mock SpatRevisionCounterAlgorithmFactory spatRevisionCounterAlgorithmFactory; + @Mock SpatRevisionCounterAlgorithm spatRevisionCounterAlgorithm; + SpatRevisionCounterParameters spatRevisionCounterParameters = new SpatRevisionCounterParameters(); + + @Mock MapRevisionCounterAlgorithmFactory mapRevisionCounterAlgorithmFactory; + @Mock MapRevisionCounterAlgorithm mapRevisionCounterAlgorithm; + MapRevisionCounterParameters mapRevisionCounterParameters = new MapRevisionCounterParameters(); + + @Mock BsmRevisionCounterAlgorithmFactory bsmRevisionCounterAlgorithmFactory; + @Mock BsmRevisionCounterAlgorithm bsmRevisionCounterAlgorithm; + BsmRevisionCounterParameters bsmRevisionCounterParameters = new BsmRevisionCounterParameters(); + MapIndex mapIndex = new MapIndex(); @Test @@ -176,11 +211,21 @@ public void testConstructor() { when(mapValidationAlgorithmFactory.getAlgorithm(defaultAlgo)).thenReturn(mapValidationAlgorithm); when(conflictMonitorProperties.getMapValidationParameters()).thenReturn(mapValidationParameters); + when(conflictMonitorProperties.getMapTimestampDeltaAlgorithmFactory()).thenReturn(mapTimestampDeltaAlgorithmFactory); + when(conflictMonitorProperties.getMapTimestampDeltaAlgorithm()).thenReturn(defaultAlgo); + when(mapTimestampDeltaAlgorithmFactory.getAlgorithm(defaultAlgo)).thenReturn(mapTimestampDeltaStreamsAlgorithm); + when(conflictMonitorProperties.getMapTimestampDeltaParameters()).thenReturn(mapTimestampDeltaParameters); + when(conflictMonitorProperties.getSpatValidationAlgorithmFactory()).thenReturn(spatValidationStreamsAlgorithmFactory); when(conflictMonitorProperties.getSpatValidationAlgorithm()).thenReturn(defaultAlgo); when(spatValidationStreamsAlgorithmFactory.getAlgorithm(defaultAlgo)).thenReturn(spatValidationAlgorithm); when(conflictMonitorProperties.getSpatValidationParameters()).thenReturn(spatValidationParameters); + when(conflictMonitorProperties.getSpatTimestampDeltaAlgorithmFactory()).thenReturn(spatTimestampDeltaAlgorithmFactory); + when(conflictMonitorProperties.getSpatTimestampDeltaAlgorithm()).thenReturn(defaultAlgo); + when(spatTimestampDeltaAlgorithmFactory.getAlgorithm(defaultAlgo)).thenReturn(spatTimestampDeltaStreamsAlgorithm); + when(conflictMonitorProperties.getSpatTimestampDeltaParameters()).thenReturn(spatTimestampDeltaParameters); + when(conflictMonitorProperties.getSpatTimeChangeDetailsAlgorithmFactory()).thenReturn(spatTimeChangeDetailsAlgorithmFactory); when(conflictMonitorProperties.getSpatTimeChangeDetailsAlgorithm()).thenReturn(defaultAlgo); when(spatTimeChangeDetailsAlgorithmFactory.getAlgorithm(defaultAlgo)).thenReturn(spatTimeChangeDetailsAlgorithm); @@ -245,7 +290,15 @@ public void testConstructor() { when(stopLineStopAssessmentAlgorithmFactory.getAlgorithm(defaultAlgo)).thenReturn(stopLineStopAssessmentAlgorithm); when(conflictMonitorProperties.getStopLineStopAssessmentAlgorithmParameters()).thenReturn(stopLineStopAssessmentParameters); - + when(conflictMonitorProperties.getMapRevisionCounterAlgorithmFactory()).thenReturn(mapRevisionCounterAlgorithmFactory); + when(conflictMonitorProperties.getMapRevisionCounterAlgorithm()).thenReturn(defaultAlgo); + when(mapRevisionCounterAlgorithmFactory.getAlgorithm(defaultAlgo)).thenReturn(mapRevisionCounterAlgorithm); + when(conflictMonitorProperties.getMapRevisionCounterAlgorithmParameters()).thenReturn(mapRevisionCounterParameters); + + when(conflictMonitorProperties.getSpatRevisionCounterAlgorithmFactory()).thenReturn(spatRevisionCounterAlgorithmFactory); + when(conflictMonitorProperties.getSpatRevisionCounterAlgorithm()).thenReturn(defaultAlgo); + when(spatRevisionCounterAlgorithmFactory.getAlgorithm(defaultAlgo)).thenReturn(spatRevisionCounterAlgorithm); + when(conflictMonitorProperties.getSpatRevisionCounterAlgorithmParameters()).thenReturn(spatRevisionCounterParameters); var monitorServiceController = new MonitorServiceController( conflictMonitorProperties, @@ -270,6 +323,8 @@ public void testConstructor() { verify(laneDirectionOfTravelAssessmentAlgorithm, times(1)).start(); verify(connectionOfTravelAssessmentAlgorithm, times(1)).start(); verify(stopLineStopAssessmentAlgorithm, times(1)).start(); + verify(mapRevisionCounterAlgorithm, times(1)).start(); + verify(spatRevisionCounterAlgorithm, times(1)).start(); } } diff --git a/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/monitor/assessments/StopLineStopAssessmentTopologyTest.java b/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/monitor/assessments/StopLineStopAssessmentTopologyTest.java index aa605ca9..c169435a 100644 --- a/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/monitor/assessments/StopLineStopAssessmentTopologyTest.java +++ b/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/monitor/assessments/StopLineStopAssessmentTopologyTest.java @@ -8,16 +8,11 @@ import org.apache.kafka.streams.TopologyTestDriver; import org.junit.Test; -import us.dot.its.jpo.conflictmonitor.monitor.algorithms.stop_line_passage_assessment.StopLinePassageAssessmentParameters; import us.dot.its.jpo.conflictmonitor.monitor.algorithms.stop_line_stop_assessment.StopLineStopAssessmentParameters; -import us.dot.its.jpo.conflictmonitor.monitor.models.assessments.StopLinePassageAssessment; -import us.dot.its.jpo.conflictmonitor.monitor.models.assessments.StopLinePassageAssessmentGroup; import us.dot.its.jpo.conflictmonitor.monitor.models.assessments.StopLineStopAssessment; import us.dot.its.jpo.conflictmonitor.monitor.models.assessments.StopLineStopAssessmentGroup; -import us.dot.its.jpo.conflictmonitor.monitor.models.notifications.StopLinePassageNotification; import us.dot.its.jpo.conflictmonitor.monitor.models.notifications.StopLineStopNotification; import us.dot.its.jpo.conflictmonitor.monitor.serialization.JsonSerdes; -import us.dot.its.jpo.conflictmonitor.monitor.topologies.assessments.StopLinePassageAssessmentTopology; import us.dot.its.jpo.conflictmonitor.monitor.topologies.assessments.StopLineStopAssessmentTopology; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -30,9 +25,8 @@ public class StopLineStopAssessmentTopologyTest { String kafkaTopicStopLineStopAssessment = "topic.CmStopLineStopAssessment"; String kafkaTopicStopLineStopNotification = "topic.CmStopLineStopNotification"; String stopLineStopEventKey = "12109"; - String stopLineStopEvent = "{\"eventGeneratedAt\":1701281898834,\"eventType\":\"StopLineStop\",\"intersectionID\":12101,\"roadRegulatorID\":-1,\"source\":\"{ rsuId='10.11.81.28', intersectionId='12101', region='0'}\",\"ingressLane\":12,\"egressLane\":29,\"connectionID\":4,\"initialEventState\":\"STOP_AND_REMAIN\",\"initialTimestamp\":1701281879858,\"finalEventState\":\"STOP_AND_REMAIN\",\"finalTimestamp\":1701281882642,\"vehicleID\":\"61899505\",\"latitude\":39.63870516395606,\"longitude\":-105.08191242814065,\"heading\":90.0,\"signalGroup\":4,\"timeStoppedDuringRed\":2.77,\"timeStoppedDuringYellow\":0.0,\"timeStoppedDuringGreen\":3.00,\"key\":\"-1_12101_61899505\"}"; - - @Test + String stopLineStopEvent = "{\"eventGeneratedAt\":1701281898834,\"eventType\":\"StopLineStop\",\"intersectionID\":12101,\"roadRegulatorID\":-1,\"source\":\"{ rsuId='10.11.81.28', intersectionId='12101', region='0'}\",\"ingressLane\":12,\"egressLane\":29,\"connectionID\":4,\"initialEventState\":\"STOP_AND_REMAIN\",\"initialTimestamp\":1701281879858,\"finalEventState\":\"STOP_AND_REMAIN\",\"finalTimestamp\":1701281882642,\"vehicleID\":\"61899505\",\"latitude\":39.63870516395606,\"longitude\":-105.08191242814065,\"heading\":90.0,\"signalGroup\":4,\"timeStoppedDuringRed\":2.77,\"timeStoppedDuringYellow\":0.0,\"timeStoppedDuringGreen\":3.00,\"timeStoppedDuringDark\":0.3,\"key\":\"-1_12101_61899505\"}"; + public void testTopology() { StopLineStopAssessmentTopology assessment = new StopLineStopAssessmentTopology(); StopLineStopAssessmentParameters parameters = new StopLineStopAssessmentParameters(); @@ -81,7 +75,7 @@ public void testTopology() { assertEquals(group.getTimeStoppedOnGreen(), 6.00); assertEquals(group.getTimeStoppedOnRed(), 2.77 * 2); assertEquals(group.getTimeStoppedOnYellow(), 0); - assertEquals(group.getTimeStoppedOnDark(), 0); + assertEquals(group.getTimeStoppedOnDark(), 0.3); assertEquals(group.getSignalGroup(), 4); } } @@ -136,12 +130,12 @@ public void testNotification() { assertEquals(group.getTimeStoppedOnGreen(), 6.00); assertEquals(group.getTimeStoppedOnRed(), 2.77 * 2); assertEquals(group.getTimeStoppedOnYellow(), 0); - assertEquals(group.getTimeStoppedOnDark(), 0); + assertEquals(group.getTimeStoppedOnDark(), 0.3 * 2); assertEquals(group.getSignalGroup(), 4); assertEquals(output.getNotificationHeading(), "Stop Line Stop Notification"); - assertEquals(output.getNotificationText(), "Stop Line Stop Notification, percent time stopped on green: 52% for signal group: 4 exceeds maximum allowable percent."); + assertEquals(output.getNotificationText(), "Stop Line Stop Notification, percent time stopped on green: 47% for signal group: 4 exceeds maximum allowable percent."); assertEquals(output.getNotificationType(), "StopLineStopNotification"); } } diff --git a/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/monitor/events/BsmRevisionCounterTopologyTest.java b/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/monitor/events/BsmRevisionCounterTopologyTest.java new file mode 100644 index 00000000..12471ef7 --- /dev/null +++ b/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/monitor/events/BsmRevisionCounterTopologyTest.java @@ -0,0 +1,102 @@ +package us.dot.its.jpo.conflictmonitor.monitor.events; + +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 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.conflictmonitor.monitor.topologies.BsmRevisionCounterTopology; +import us.dot.its.jpo.ode.model.OdeBsmData; +import us.dot.its.jpo.ode.plugin.j2735.J2735Bsm; +import us.dot.its.jpo.conflictmonitor.monitor.algorithms.bsm_revision_counter.BsmRevisionCounterParameters; +import us.dot.its.jpo.conflictmonitor.monitor.models.events.BsmRevisionCounterEvent; + +import static org.junit.Assert.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.List; + +public class BsmRevisionCounterTopologyTest { + + String inputTopic = "topic.CmBsmJsonRepartition"; + String outputTopic = "topic.CmBsmRevisionCounterEvents"; + + + TypeReference typeReference = new TypeReference<>(){}; + ObjectMapper objectMapper = new ObjectMapper(); + + String inputBsm1 = "{\"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\"}}"; + String inputBsm2 = "{\"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\":13,\"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\"}}"; + String inputBsm3 = "{\"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\":14,\"id\":\"48C45782\",\"secMark\":5987,\"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\"}}"; + String inputBsm4 = "{\"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\":7,\"maxDurationTime\":0,\"recordGeneratedAt\":\"\",\"sanitized\":false,\"odePacketID\":\"\",\"odeTimStartDateTime\":\"\",\"originIp\":\"10.11.81.12\"},\"payload\":{\"data\":{\"coreData\":{\"msgCnt\":14,\"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\"}}"; + + String key = "{\"rsuId\":\"10.11.81.12\",\"intersectionId\":12109,\"region\":-1}"; + + @Test + public void testTopology() { + + BsmRevisionCounterTopology bsmRevisionCounterTopology = new BsmRevisionCounterTopology(); + BsmRevisionCounterParameters parameters = new BsmRevisionCounterParameters(); + parameters.setBsmInputTopicName(inputTopic); + parameters.setBsmRevisionEventOutputTopicName(outputTopic); + + bsmRevisionCounterTopology.setParameters(parameters); + + Topology topology = bsmRevisionCounterTopology.buildTopology(); + objectMapper.registerModule(new JavaTimeModule()); + + try (TopologyTestDriver driver = new TopologyTestDriver(topology)) { + + + TestInputTopic inputBsmData = driver.createInputTopic( + inputTopic, + Serdes.String().serializer(), + Serdes.String().serializer()); + + TestOutputTopic outputRevisionCounterEvents = driver.createOutputTopic( + outputTopic, + Serdes.String().deserializer(), + us.dot.its.jpo.conflictmonitor.monitor.serialization.JsonSerdes.BsmRevisionCounterEvent().deserializer()); + + inputBsmData.pipeInput(key, inputBsm1); // a bsm + inputBsmData.pipeInput(key, inputBsm2); // the same bsm, with msgCount incremented + inputBsmData.pipeInput(key, inputBsm3); // a changed bsm, with msgCount incremented + inputBsmData.pipeInput(key, inputBsm4); // a changed bsm, without msgCount incremented + inputBsmData.pipeInput(key, inputBsm4); // bsm 4 again + + List> bsmRevisionCounterEvents = outputRevisionCounterEvents.readKeyValuesToList(); + + // validate that just 1 event is returned, for the 3-4 bsm change without a revision change + assertEquals(1, bsmRevisionCounterEvents.size()); + + OdeBsmData bsm3 = objectMapper.readValue(inputBsm3, typeReference); + OdeBsmData bsm4 = objectMapper.readValue(inputBsm4, typeReference); + J2735Bsm eventPreviousBsmPayload = (J2735Bsm) bsmRevisionCounterEvents.get(0).value.getPreviousBsm().getPayload().getData(); + J2735Bsm eventNewBsmPayload = (J2735Bsm) bsmRevisionCounterEvents.get(0).value.getNewBsm().getPayload().getData(); + +// assertEquals(bsm3.getOdeReceivedAt(), bsmRevisionCounterEvents.get(0).value.getPreviousBsm().getOdeReceivedAt()); +// assertEquals(bsm4.getOdeReceivedAt(), bsmRevisionCounterEvents.get(0).value.getNewBsm().getOdeReceivedAt()); + assertEquals(eventPreviousBsmPayload.getCoreData().getMsgCnt(), eventNewBsmPayload.getCoreData().getMsgCnt()); + + int hashBsm3 = bsm3.hashCode(); + int hashBsm4 = bsm4.hashCode(); + assertNotEquals(hashBsm3, hashBsm4); + + + + } catch (JsonMappingException e) { + e.printStackTrace(); + } catch (JsonProcessingException e) { + e.printStackTrace(); + } + } +} diff --git a/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/monitor/events/EventTopologyTest.java b/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/monitor/events/EventTopologyTest.java index 5c2a2c56..43cfdbf4 100644 --- a/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/monitor/events/EventTopologyTest.java +++ b/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/monitor/events/EventTopologyTest.java @@ -14,6 +14,8 @@ import us.dot.its.jpo.conflictmonitor.monitor.models.events.broadcast_rate.SpatBroadcastRateEvent; import us.dot.its.jpo.conflictmonitor.monitor.models.events.minimum_data.MapMinimumDataEvent; import us.dot.its.jpo.conflictmonitor.monitor.models.events.minimum_data.SpatMinimumDataEvent; +import us.dot.its.jpo.conflictmonitor.monitor.models.events.timestamp_delta.MapTimestampDeltaEvent; +import us.dot.its.jpo.conflictmonitor.monitor.models.events.timestamp_delta.SpatTimestampDeltaEvent; import us.dot.its.jpo.conflictmonitor.monitor.serialization.JsonSerdes; import us.dot.its.jpo.conflictmonitor.monitor.topologies.EventTopology; import us.dot.its.jpo.conflictmonitor.monitor.algorithms.event.EventParameters; @@ -35,7 +37,10 @@ public class EventTopologyTest { String signalStateConflictEventTopicName = "topic.CmSignalStateConflictEvents"; String laneDirectionOfTravelEventTopicName = "topic.CmLaneDirectionOfTravelEvent"; String connectionOfTravelEventTopicName = "topic.CmConnectionOfTravelEvent"; - + String spatRevisionCounterEventTopicName = "topic.CmSpatRevisionCounterEvents"; + String mapRevisionCounterEventTopicName = "topic.CmMapRevisionCounterEvents"; + String bsmRevisionCounterEventTopicName = "topic.CmBsmRevisionCounterEvents"; + String timestampDeltaEventTopicName = "topic.CmTimestampDeltaEvent"; @Test public void testTopology() { @@ -54,7 +59,10 @@ public void testTopology() { parameters.setSignalStateConflictEventTopicName(signalStateConflictEventTopicName); parameters.setLaneDirectionOfTravelEventTopicName(laneDirectionOfTravelEventTopicName); parameters.setConnectionOfTravelEventTopicName(connectionOfTravelEventTopicName); - + parameters.setSpatRevisionCounterEventTopicName(spatRevisionCounterEventTopicName); + parameters.setMapRevisionCounterEventTopicName(mapRevisionCounterEventTopicName); + parameters.setBsmRevisionCounterEventTopicName(bsmRevisionCounterEventTopicName); + parameters.setTimestampDeltaEventTopicName(timestampDeltaEventTopicName); eventTopology.setParameters(parameters); @@ -73,6 +81,11 @@ public void testTopology() { SignalStateConflictEvent sscEvent = new SignalStateConflictEvent(); LaneDirectionOfTravelEvent ldotEvent = new LaneDirectionOfTravelEvent(); ConnectionOfTravelEvent cotEvent = new ConnectionOfTravelEvent(); + SpatRevisionCounterEvent srcEvent = new SpatRevisionCounterEvent(); + MapRevisionCounterEvent mrcEvent = new MapRevisionCounterEvent(); + BsmRevisionCounterEvent brcEvent = new BsmRevisionCounterEvent(); + MapTimestampDeltaEvent mapTimestampDeltaEvent = new MapTimestampDeltaEvent(); + SpatTimestampDeltaEvent spatTimestampDeltaEvent = new SpatTimestampDeltaEvent(); try (TopologyTestDriver driver = new TopologyTestDriver(topology)) { @@ -154,18 +167,45 @@ public void testTopology() { inputConnectionOfTravel.pipeInput("12109", cotEvent); + TestInputTopic inputSpatRevisionCounterEvent = driver.createInputTopic( + spatRevisionCounterEventTopicName, + Serdes.String().serializer(), + JsonSerdes.SpatRevisionCounterEvent().serializer()); + + inputSpatRevisionCounterEvent.pipeInput("12109", srcEvent); + + TestInputTopic inputMapRevisionCounterEvent = driver.createInputTopic( + mapRevisionCounterEventTopicName, + Serdes.String().serializer(), + JsonSerdes.MapRevisionCounterEvent().serializer()); + + inputMapRevisionCounterEvent.pipeInput("12109", mrcEvent); + + TestInputTopic inputBsmRevisionCounterEvent = driver.createInputTopic( + bsmRevisionCounterEventTopicName, + Serdes.String().serializer(), + JsonSerdes.BsmRevisionCounterEvent().serializer()); + + inputBsmRevisionCounterEvent.pipeInput("12109", brcEvent); + + TestInputTopic inputTimestampDeltaEvent = driver.createInputTopic( + timestampDeltaEventTopicName, + Serdes.String().serializer(), + JsonSerdes.Event().serializer()); + inputTimestampDeltaEvent.pipeInput("12109", mapTimestampDeltaEvent); + inputTimestampDeltaEvent.pipeInput("12109", spatTimestampDeltaEvent); TestOutputTopic outputEventTopic = driver.createOutputTopic( eventOutputTopicName, Serdes.String().deserializer(), JsonSerdes.Event().deserializer()); - + List> eventResults = outputEventTopic.readKeyValuesToList(); - assertEquals(11, eventResults.size()); + assertEquals(16, eventResults.size()); for(KeyValue eventKeyValue: eventResults){ assertEquals("12109", eventKeyValue.key); @@ -206,6 +246,21 @@ else if(type.equals("LaneDirectionOfTravel")){ else if(type.equals("ConnectionOfTravel")){ assertEquals((ConnectionOfTravelEvent) event, cotEvent); } + else if(type.equals("SpatRevisionCounter")){ + assertEquals((SpatRevisionCounterEvent) event, srcEvent); + } + else if(type.equals("MapRevisionCounter")){ + assertEquals((MapRevisionCounterEvent) event, mrcEvent); + } + else if(type.equals("BsmRevisionCounter")){ + assertEquals((BsmRevisionCounterEvent) event, brcEvent); + } + else if (type.equals("MapTimestampDelta")) { + assertEquals(event, mapTimestampDeltaEvent); + } + else if (type.equals("SpatTimestampDelta")) { + assertEquals(event, spatTimestampDeltaEvent); + } else{ // Throw an error System.out.println("Unrecognized Type for Decoding: " + type); diff --git a/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/monitor/events/MapRevisionCounterTopologyTest.java b/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/monitor/events/MapRevisionCounterTopologyTest.java new file mode 100644 index 00000000..b339ef33 --- /dev/null +++ b/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/monitor/events/MapRevisionCounterTopologyTest.java @@ -0,0 +1,105 @@ +package us.dot.its.jpo.conflictmonitor.monitor.events; + +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 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.conflictmonitor.monitor.topologies.MapRevisionCounterTopology; +import us.dot.its.jpo.conflictmonitor.monitor.algorithms.map_revision_counter.MapRevisionCounterParameters; +import us.dot.its.jpo.conflictmonitor.monitor.models.events.MapRevisionCounterEvent; +import us.dot.its.jpo.geojsonconverter.pojos.geojson.LineString; +import us.dot.its.jpo.geojsonconverter.pojos.geojson.map.ProcessedMap; + +import static org.junit.Assert.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.List; + +public class MapRevisionCounterTopologyTest { + + String inputTopic = "topic.ProcessedMap"; + String outputTopic = "topic.CmMapRevisionCounterEvents"; + + + 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:21.06Z\",\"originIp\":\"10.11.81.12\",\"intersectionId\":12109,\"msgIssueRevision\":2,\"revision\":3,\"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 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\":true,\"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\":4,\"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 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.5886316],[-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\":4,\"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 key = "{\"rsuId\":\"10.11.81.12\",\"intersectionId\":12109,\"region\":-1}"; + + + + + @Test + public void testTopology() { + + MapRevisionCounterTopology mapRevisionCounterTopology = new MapRevisionCounterTopology(); + MapRevisionCounterParameters parameters = new MapRevisionCounterParameters(); + parameters.setMapInputTopicName(inputTopic); + parameters.setMapRevisionEventOutputTopicName(outputTopic); + + mapRevisionCounterTopology.setParameters(parameters); + + Topology topology = mapRevisionCounterTopology.buildTopology(); + objectMapper.registerModule(new JavaTimeModule()); + + try (TopologyTestDriver driver = new TopologyTestDriver(topology)) { + + + TestInputTopic inputProcessedMapData = driver.createInputTopic( + inputTopic, + Serdes.String().serializer(), + Serdes.String().serializer()); + + TestOutputTopic outputRevisionCounterEvents = driver.createOutputTopic( + outputTopic, + Serdes.String().deserializer(), + us.dot.its.jpo.conflictmonitor.monitor.serialization.JsonSerdes.MapRevisionCounterEvent().deserializer()); + + inputProcessedMapData.pipeInput(key, inputProcessedMap1); // a map + inputProcessedMapData.pipeInput(key, inputProcessedMap2); // the same map, with revision incremented + inputProcessedMapData.pipeInput(key, inputProcessedMap3); // a changed map, with revision incremented + inputProcessedMapData.pipeInput(key, inputProcessedMap4); // a changed map, without revision incremented + inputProcessedMapData.pipeInput(key, inputProcessedMap4); // map 4 again + + List> mapRevisionCounterEvents = outputRevisionCounterEvents.readKeyValuesToList(); + + // validate that just 1 event is returned, for the 3-4 map change without a revision change + assertEquals(1, mapRevisionCounterEvents.size()); + + ProcessedMap map3 = objectMapper.readValue(inputProcessedMap3, typeReference); + ProcessedMap map4 = objectMapper.readValue(inputProcessedMap4, typeReference); + + assertEquals(map3.getProperties().getOdeReceivedAt(), mapRevisionCounterEvents.get(0).value.getPreviousMap().getProperties().getOdeReceivedAt()); + assertEquals(map4.getProperties().getOdeReceivedAt(), mapRevisionCounterEvents.get(0).value.getNewMap().getProperties().getOdeReceivedAt()); + assertEquals(mapRevisionCounterEvents.get(0).value.getPreviousMap().getProperties().getRevision(), + mapRevisionCounterEvents.get(0).value.getNewMap().getProperties().getRevision()); + + int hashMap3 = map3.hashCode(); + int hashMap4 = map4.hashCode(); + assertNotEquals(hashMap3, hashMap4); + + + + } catch (JsonMappingException e) { + e.printStackTrace(); + } catch (JsonProcessingException e) { + e.printStackTrace(); + } + } +} diff --git a/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/monitor/events/SpatRevisionCounterTopologyTest.java b/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/monitor/events/SpatRevisionCounterTopologyTest.java new file mode 100644 index 00000000..c03b7721 --- /dev/null +++ b/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/monitor/events/SpatRevisionCounterTopologyTest.java @@ -0,0 +1,104 @@ +package us.dot.its.jpo.conflictmonitor.monitor.events; + +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 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.conflictmonitor.monitor.topologies.SpatRevisionCounterTopology; +import us.dot.its.jpo.conflictmonitor.monitor.algorithms.spat_revision_counter.SpatRevisionCounterParameters; +import us.dot.its.jpo.conflictmonitor.monitor.models.events.SpatRevisionCounterEvent; +import us.dot.its.jpo.geojsonconverter.pojos.spat.ProcessedSpat; + +import static org.junit.Assert.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.List; + +public class SpatRevisionCounterTopologyTest { + + String inputTopic = "topic.ProcessedSpat"; + String outputTopic = "topic.CmSpatRevisionCounterEvents"; + + + TypeReference typeReference = new TypeReference<>(){}; + ObjectMapper objectMapper = new ObjectMapper(); + + String inputProcessedSpat1 = "{\"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\"}}]}]}"; + String inputProcessedSpat2 = "{\"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\":1,\"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\"}}]}]}"; + String inputProcessedSpat3 = "{\"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\":2,\"status\":{\"manualControlIsEnabled\":false,\"stopTimeIsActivated\":false,\"failureFlash\":false,\"preemptIsActive\":false,\"signalPriorityIsActive\":true,\"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\"}}]}]}"; + String inputProcessedSpat4 = "{\"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\":2,\"status\":{\"manualControlIsEnabled\":false,\"stopTimeIsActivated\":false,\"failureFlash\":true,\"preemptIsActive\":false,\"signalPriorityIsActive\":true,\"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\"}}]}]}"; + + + String key = "{\"rsuId\":\"10.11.81.12\",\"intersectionId\":12109,\"region\":-1}"; + + + + + @Test + public void testTopology() { + + SpatRevisionCounterTopology spatRevisionCounterTopology = new SpatRevisionCounterTopology(); + SpatRevisionCounterParameters parameters = new SpatRevisionCounterParameters(); + parameters.setSpatInputTopicName(inputTopic); + parameters.setSpatRevisionEventOutputTopicName(outputTopic); + + spatRevisionCounterTopology.setParameters(parameters); + + Topology topology = spatRevisionCounterTopology.buildTopology(); + objectMapper.registerModule(new JavaTimeModule()); + + try (TopologyTestDriver driver = new TopologyTestDriver(topology)) { + + + TestInputTopic inputProcessedSpatData = driver.createInputTopic( + inputTopic, + Serdes.String().serializer(), + Serdes.String().serializer()); + + TestOutputTopic outputRevisionCounterEvents = driver.createOutputTopic( + outputTopic, + Serdes.String().deserializer(), + us.dot.its.jpo.conflictmonitor.monitor.serialization.JsonSerdes.SpatRevisionCounterEvent().deserializer()); + + inputProcessedSpatData.pipeInput(key, inputProcessedSpat1); // a spat + inputProcessedSpatData.pipeInput(key, inputProcessedSpat2); // the same spat, with revision incremented + inputProcessedSpatData.pipeInput(key, inputProcessedSpat3); // a changed spat, with revision incremented + inputProcessedSpatData.pipeInput(key, inputProcessedSpat4); // a changed spat, without revision incremented + inputProcessedSpatData.pipeInput(key, inputProcessedSpat4); // spat 4 again + + List> spatRevisionCounterEvents = outputRevisionCounterEvents.readKeyValuesToList(); + + // validate that just 1 event is returned, for the 3-4 spat change without a revision change + assertEquals(1, spatRevisionCounterEvents.size()); + + ProcessedSpat spat3 = objectMapper.readValue(inputProcessedSpat3, typeReference); + ProcessedSpat spat4 = objectMapper.readValue(inputProcessedSpat4, typeReference); + + assertEquals(spat3.getOdeReceivedAt(), spatRevisionCounterEvents.get(0).value.getPreviousSpat().getOdeReceivedAt()); + assertEquals(spat4.getOdeReceivedAt(), spatRevisionCounterEvents.get(0).value.getNewSpat().getOdeReceivedAt()); + assertEquals(spatRevisionCounterEvents.get(0).value.getPreviousSpat().getRevision(), + spatRevisionCounterEvents.get(0).value.getNewSpat().getRevision()); + + int hashSpat3 = spat3.hashCode(); + int hashSpat4 = spat4.hashCode(); + assertNotEquals(hashSpat3, hashSpat4); + + + + } catch (JsonMappingException e) { + e.printStackTrace(); + } catch (JsonProcessingException e) { + e.printStackTrace(); + } + } +} diff --git a/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/monitor/notifications/NotificationTopologyTest.java b/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/monitor/notifications/NotificationTopologyTest.java index 781fcff8..d6b1bf9b 100644 --- a/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/monitor/notifications/NotificationTopologyTest.java +++ b/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/monitor/notifications/NotificationTopologyTest.java @@ -15,6 +15,8 @@ import us.dot.its.jpo.conflictmonitor.monitor.models.notifications.SignalGroupAlignmentNotification; import us.dot.its.jpo.conflictmonitor.monitor.models.notifications.SignalStateConflictNotification; import us.dot.its.jpo.conflictmonitor.monitor.models.notifications.TimeChangeDetailsNotification; +import us.dot.its.jpo.conflictmonitor.monitor.models.notifications.timestamp_delta.MapTimestampDeltaNotification; +import us.dot.its.jpo.conflictmonitor.monitor.models.notifications.timestamp_delta.SpatTimestampDeltaNotification; import us.dot.its.jpo.conflictmonitor.monitor.serialization.JsonSerdes; import us.dot.its.jpo.conflictmonitor.monitor.topologies.NotificationTopology; import us.dot.its.jpo.conflictmonitor.monitor.algorithms.notification.NotificationParameters; @@ -31,6 +33,7 @@ public class NotificationTopologyTest { String signalStateConflictTopicName = "topic.CmSignalStateConflictNotification"; String spatTimeChangeDetailsTopicName = "topic.CmSpatTimeChangeDetailsNotification"; String notificationTopicName = "topic.CmNotification"; + String timestampDeltaNotificationTopicName = "topic.CmTimestampDeltaNotification"; @Test @@ -46,6 +49,7 @@ public void testTopology() { parameters.setSpatTimeChangeDetailsNotificationTopicName(spatTimeChangeDetailsTopicName); parameters.setNotificationOutputTopicName(notificationTopicName); parameters.setDebug(false); + parameters.setTimestampDeltaNotificationTopicName(timestampDeltaNotificationTopicName); @@ -59,6 +63,8 @@ public void testTopology() { SignalGroupAlignmentNotification sgaNotification = new SignalGroupAlignmentNotification(); SignalStateConflictNotification sscNotification = new SignalStateConflictNotification(); TimeChangeDetailsNotification tcdNotification = new TimeChangeDetailsNotification(); + MapTimestampDeltaNotification mapTimestampDeltaNotification = new MapTimestampDeltaNotification(); + SpatTimestampDeltaNotification spatTimestampDeltaNotification = new SpatTimestampDeltaNotification(); try (TopologyTestDriver driver = new TopologyTestDriver(topology)) { @@ -105,6 +111,13 @@ public void testTopology() { inputTimeChangeDetails.pipeInput("12109", tcdNotification); + TestInputTopic inputTimestampDeltaNotification = driver.createInputTopic( + timestampDeltaNotificationTopicName, + Serdes.String().serializer(), + JsonSerdes.Notification().serializer() + ); + inputTimestampDeltaNotification.pipeInput("12109", mapTimestampDeltaNotification); + inputTimestampDeltaNotification.pipeInput("12109", spatTimestampDeltaNotification); TestOutputTopic outputNotificationTopic = driver.createOutputTopic( @@ -117,7 +130,7 @@ public void testTopology() { - assertEquals(6, notificationResults.size()); + assertEquals(8, notificationResults.size()); for(KeyValue notificationKeyValue: notificationResults){ assertEquals("12109", notificationKeyValue.key); @@ -141,6 +154,11 @@ else if(type.equals("SignalStateConflictNotification")){ else if(type.equals("TimeChangeDetailsNotification")){ assertEquals((TimeChangeDetailsNotification) notification, tcdNotification); } + else if (type.equals("MapTimestampDeltaNotification")) { + assertEquals(notification, mapTimestampDeltaNotification); + } else if (type.equals("SpatTimestampDeltaNotification")) { + assertEquals(notification, spatTimestampDeltaNotification); + } else{ assertEquals(1,0); } diff --git a/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/monitor/serialization/deserialization/BaseGenericJsonDeserializerTest.java b/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/monitor/serialization/deserialization/BaseGenericJsonDeserializerTest.java new file mode 100644 index 00000000..d53b7718 --- /dev/null +++ b/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/monitor/serialization/deserialization/BaseGenericJsonDeserializerTest.java @@ -0,0 +1,57 @@ +package us.dot.its.jpo.conflictmonitor.monitor.serialization.deserialization; + +import org.junit.runners.Parameterized; + +import java.util.ArrayList; +import java.util.Collection; + +public abstract class BaseGenericJsonDeserializerTest { + + protected String configString; + protected Object expectedValue; + protected String expectedType; + + public BaseGenericJsonDeserializerTest(String configString, Object expectedValue, String expectedType) { + this.configString = configString; + this.expectedValue = expectedValue; + this.expectedType = expectedType; + } + + @Parameterized.Parameters + public static Collection getParams() { + var params = new ArrayList(); + params.add(new Object[] { getConfig(10, "java.lang.Integer"), 10, "java.lang.Integer" }); + params.add(new Object[] { getConfig(10.5, "java.lang.Double"), 10.5, "java.lang.Double" }); + params.add(new Object[] { getConfig("\"test\"", "java.lang.String"), "test", "java.lang.String" }); + params.add(new Object[] { getConfig(true, "java.lang.Boolean"), true, "java.lang.Boolean" }); + params.add(new Object[] { getConfig(Long.MAX_VALUE, "java.lang.Long"), Long.MAX_VALUE, "java.lang.Long" }); + return params; + } + + // Test for method: public T deserialize(String topic, byte[] data) + public abstract void testDeserialize(); + + + + + + final static String configTemplate = """ + { + "key": "key", + "category": "category", + "value": %s, + "type": "%s", + "units": "SECONDS", + "description": "description", + "updateType": "INTERSECTION" + } + """; + + + static String getConfig(Object value, String type) { + return String.format(configTemplate, value, type); + } + + + +} diff --git a/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/monitor/serialization/deserialization/BaseGenericJsonDeserializer_ConcurrentPermissiveTest.java b/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/monitor/serialization/deserialization/BaseGenericJsonDeserializer_ConcurrentPermissiveTest.java new file mode 100644 index 00000000..b3d09c80 --- /dev/null +++ b/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/monitor/serialization/deserialization/BaseGenericJsonDeserializer_ConcurrentPermissiveTest.java @@ -0,0 +1,83 @@ +package us.dot.its.jpo.conflictmonitor.monitor.serialization.deserialization; + +import us.dot.its.jpo.conflictmonitor.monitor.models.concurrent_permissive.ConnectedLanes; +import us.dot.its.jpo.conflictmonitor.monitor.models.concurrent_permissive.ConnectedLanesPair; +import us.dot.its.jpo.conflictmonitor.monitor.models.concurrent_permissive.ConnectedLanesPairList; +import us.dot.its.jpo.conflictmonitor.monitor.models.config.IntersectionConfig; +import us.dot.its.jpo.conflictmonitor.monitor.models.config.UnitsEnum; +import us.dot.its.jpo.conflictmonitor.monitor.models.config.UpdateType; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.greaterThan; +import static org.hamcrest.Matchers.hasProperty; +import static org.hamcrest.Matchers.hasSize; +import static org.hamcrest.Matchers.instanceOf; +import static org.hamcrest.Matchers.notNullValue; + +public abstract class BaseGenericJsonDeserializer_ConcurrentPermissiveTest { + + public abstract void testDeserialize_ConcurrentPermissive(); + + protected void testConfigResult(IntersectionConfig config) { + assertThat(config, notNullValue()); + assertThat(config, hasProperty("type", equalTo("us.dot.its.jpo.conflictmonitor.monitor.models.concurrent_permissive.ConnectedLanesPairList"))); + assertThat(config, hasProperty("key", equalTo("map.spat.message.assessment.concurrentPermissiveList"))); + assertThat(config, hasProperty("roadRegulatorID", equalTo(10))); + assertThat(config, hasProperty("intersectionID", equalTo(101010))); + assertThat(config, hasProperty("units", equalTo(UnitsEnum.NONE))); + assertThat(config, hasProperty("description", equalTo("List of pairs of lane connections that are allowed concurrently permissive for an intersection."))); + assertThat(config, hasProperty("updateType", equalTo(UpdateType.INTERSECTION))); + assertThat(config, hasProperty("value", instanceOf(ConnectedLanesPairList.class))); + + ConnectedLanesPairList value = (ConnectedLanesPairList)config.getValue(); + assertThat(value, hasSize(2)); + for (ConnectedLanesPair item : value) { + assertThat(item, hasProperty("first", notNullValue())); + ConnectedLanes first = item.getFirst(); + assertThat(first, hasProperty("ingressLaneID", greaterThan(0))); + assertThat(first, hasProperty("egressLaneID", greaterThan(0))); + assertThat(item, hasProperty("second", notNullValue())); + ConnectedLanes second = item.getSecond(); + assertThat(second, hasProperty("ingressLaneID", greaterThan(0))); + assertThat(second, hasProperty("egressLaneID", greaterThan(0))); + + } + } + + final static String configString = """ + { + "key": "map.spat.message.assessment.concurrentPermissiveList", + "category": "category", + "roadRegulatorID": 10, + "intersectionID": 101010, + "value": [ + { + "first": { + "ingressLaneID": 1, + "egressLaneID": 2 + }, + "second": { + "ingressLaneID": 3, + "egressLaneID": 4 + } + }, + { + "first": { + "ingressLaneID": 9, + "egressLaneID": 10 + }, + "second": { + "ingressLaneID": 11, + "egressLaneID": 12 + } + } + ], + "type": "us.dot.its.jpo.conflictmonitor.monitor.models.concurrent_permissive.ConnectedLanesPairList", + "units": "NONE", + "description": "List of pairs of lane connections that are allowed concurrently permissive for an intersection.", + "updateType": "INTERSECTION" + } + """; + +} diff --git a/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/monitor/serialization/deserialization/GenericJsonDeserializerTest.java b/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/monitor/serialization/deserialization/GenericJsonDeserializerTest.java index 7c288be7..9c3420eb 100644 --- a/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/monitor/serialization/deserialization/GenericJsonDeserializerTest.java +++ b/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/monitor/serialization/deserialization/GenericJsonDeserializerTest.java @@ -1,48 +1,33 @@ package us.dot.its.jpo.conflictmonitor.monitor.serialization.deserialization; +import lombok.extern.slf4j.Slf4j; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; -import org.junit.runners.Parameterized.Parameters; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.*; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; - import us.dot.its.jpo.conflictmonitor.monitor.models.config.DefaultConfig; import us.dot.its.jpo.conflictmonitor.monitor.models.config.UnitsEnum; import us.dot.its.jpo.conflictmonitor.monitor.models.config.UpdateType; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.notNullValue; + +@Slf4j @RunWith(Parameterized.class) -public class GenericJsonDeserializerTest { +public class GenericJsonDeserializerTest extends BaseGenericJsonDeserializerTest { + - String configString; - Object expectedValue; - String expectedType; public GenericJsonDeserializerTest(String configString, Object expectedValue, String expectedType) { - this.configString = configString; - this.expectedValue = expectedValue; - this.expectedType = expectedType; + super(configString, expectedValue, expectedType); } - @Parameters - public static Collection getParams() { - var params = new ArrayList(); - params.add(new Object[] { getConfig(10, "java.lang.Integer"), 10, "java.lang.Integer" }); - params.add(new Object[] { getConfig(10.5, "java.lang.Double"), 10.5, "java.lang.Double" }); - params.add(new Object[] { getConfig("\"test\"", "java.lang.String"), "test", "java.lang.String" }); - params.add(new Object[] { getConfig(true, "java.lang.Boolean"), true, "java.lang.Boolean" }); - params.add(new Object[] { getConfig(Long.MAX_VALUE, "java.lang.Long"), Long.MAX_VALUE, "java.lang.Long" }); - return params; - } // Test for method: public T deserialize(String topic, byte[] data) @Test + @Override public void testDeserialize() { + log.info("testDeserialize: {}", configString); try (GenericJsonDeserializer> deserializer = new GenericJsonDeserializer<>(DefaultConfig.class)) { DefaultConfig config = deserializer.deserialize("test", configString.getBytes()); assertThat(config, notNullValue()); @@ -56,23 +41,5 @@ public void testDeserialize() { } } - - - final static String configTemplate = "{ " + // - " \"key\": \"key\", " + // - " \"category\": \"category\", " + // - " \"value\": %s, " + // - " \"type\": \"%s\", " + // - " \"units\": \"SECONDS\", " + // - " \"description\": \"description\", " + // - " \"updateType\": \"INTERSECTION\" " + // - "}"; - - - static String getConfig(Object value, String type) { - return String.format(configTemplate, value, type); - } - - } diff --git a/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/monitor/serialization/deserialization/GenericJsonDeserializer_ConcurrentPermissiveTest.java b/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/monitor/serialization/deserialization/GenericJsonDeserializer_ConcurrentPermissiveTest.java new file mode 100644 index 00000000..855b335c --- /dev/null +++ b/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/monitor/serialization/deserialization/GenericJsonDeserializer_ConcurrentPermissiveTest.java @@ -0,0 +1,22 @@ +package us.dot.its.jpo.conflictmonitor.monitor.serialization.deserialization; + +import lombok.extern.slf4j.Slf4j; +import org.junit.Test; +import us.dot.its.jpo.conflictmonitor.monitor.models.config.IntersectionConfig; + +@Slf4j +public class GenericJsonDeserializer_ConcurrentPermissiveTest + extends BaseGenericJsonDeserializer_ConcurrentPermissiveTest { + + @Test + @Override + public void testDeserialize_ConcurrentPermissive() { + log.info("testDeserialize: {}", configString); + try (var deserializer = new GenericJsonDeserializer>(IntersectionConfig.class)) { + IntersectionConfig config = deserializer.deserialize("test", configString.getBytes()); + testConfigResult(config); + } + } + + +} diff --git a/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/monitor/serialization/deserialization/GenericJsonStringDeserializerTest.java b/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/monitor/serialization/deserialization/GenericJsonStringDeserializerTest.java new file mode 100644 index 00000000..8e7a57fc --- /dev/null +++ b/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/monitor/serialization/deserialization/GenericJsonStringDeserializerTest.java @@ -0,0 +1,51 @@ +package us.dot.its.jpo.conflictmonitor.monitor.serialization.deserialization; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.module.SimpleModule; +import lombok.extern.slf4j.Slf4j; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import us.dot.its.jpo.conflictmonitor.monitor.models.config.DefaultConfig; +import us.dot.its.jpo.conflictmonitor.monitor.models.config.UnitsEnum; +import us.dot.its.jpo.conflictmonitor.monitor.models.config.UpdateType; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.notNullValue; + +@Slf4j +@RunWith(Parameterized.class) +public class GenericJsonStringDeserializerTest + extends BaseGenericJsonDeserializerTest { + public GenericJsonStringDeserializerTest(String configString, Object expectedValue, String expectedType) { + super(configString, expectedValue, expectedType); + } + + @Test + @Override + public void testDeserialize() { + log.info("testDeserialize: {}", configString); + GenericJsonStringDeserializer> deserializer + = new GenericJsonStringDeserializer<>(DefaultConfig.class); + var mapper = new ObjectMapper(); + var module = new SimpleModule(); + module.addDeserializer(DefaultConfig.class, deserializer); + mapper.registerModule(module); + DefaultConfig config = null; + try { + config = mapper.readValue(configString, DefaultConfig.class); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + assertThat(config, notNullValue()); + assertThat("type", config.getType(), equalTo(expectedType)); + assertThat("value", config.getValue(), equalTo(expectedValue)); + assertThat("units", config.getUnits(), equalTo(UnitsEnum.SECONDS)); + assertThat("description", config.getDescription(), equalTo("description")); + assertThat("category", config.getCategory(), equalTo("category")); + assertThat("updateType", config.getUpdateType(), equalTo(UpdateType.INTERSECTION)); + assertThat("key", config.getKey(), equalTo("key")); + } +} diff --git a/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/monitor/serialization/deserialization/GenericJsonStringDeserializer_ConcurrentPermissiveTest.java b/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/monitor/serialization/deserialization/GenericJsonStringDeserializer_ConcurrentPermissiveTest.java new file mode 100644 index 00000000..ddff825a --- /dev/null +++ b/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/monitor/serialization/deserialization/GenericJsonStringDeserializer_ConcurrentPermissiveTest.java @@ -0,0 +1,32 @@ +package us.dot.its.jpo.conflictmonitor.monitor.serialization.deserialization; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.module.SimpleModule; +import lombok.extern.slf4j.Slf4j; +import org.junit.Test; +import us.dot.its.jpo.conflictmonitor.monitor.models.config.IntersectionConfig; + +@Slf4j +public class GenericJsonStringDeserializer_ConcurrentPermissiveTest + extends BaseGenericJsonDeserializer_ConcurrentPermissiveTest { + + @Test + @Override + public void testDeserialize_ConcurrentPermissive() { + log.info("testDeserialize: {}", configString); + var deserializer = new GenericJsonStringDeserializer>(IntersectionConfig.class); + var mapper = new ObjectMapper(); + var module = new SimpleModule(); + module.addDeserializer(IntersectionConfig.class, deserializer); + mapper.registerModule(module); + IntersectionConfig config = null; + try { + config = mapper.readValue(configString, IntersectionConfig.class); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + + testConfigResult(config); + } +} 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 4288d0d6..7a3bd12f 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 @@ -84,7 +84,7 @@ public class IntersectionEventTopologyTest { public void testIntersectionEventTopology() { // Return builder inputs unchanged for embedded topologies - when(messageIngestAlgorithm.buildTopology(any())).thenAnswer(i -> i.getArguments()[0]); + //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()); 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 3cbec377..1474af7e 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 @@ -48,7 +48,8 @@ public void testMessageIngestTopology() throws JsonProcessingException { var messageIngestTopology = new MessageIngestTopology(); messageIngestTopology.setParameters(parameters); messageIngestTopology.setMapIndex(mapIndex); - StreamsBuilder builder = messageIngestTopology.buildTopology(new StreamsBuilder()); + StreamsBuilder builder = new StreamsBuilder(); + messageIngestTopology.buildTopology(builder); Topology topology = builder.build(); try (TopologyTestDriver driver = new TopologyTestDriver(topology, streamsConfig)) { diff --git a/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/validation/MapValidationTopologyTest.java b/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/validation/MapValidationTopologyTest.java index 9754fe79..77557806 100644 --- a/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/validation/MapValidationTopologyTest.java +++ b/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/validation/MapValidationTopologyTest.java @@ -5,14 +5,23 @@ import java.util.ArrayList; import java.util.List; import java.util.Properties; +import java.util.Set; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Sets; +import org.apache.kafka.common.serialization.Serde; import org.apache.kafka.streams.StreamsConfig; import org.apache.kafka.streams.Topology; import org.apache.kafka.streams.TopologyTestDriver; +import us.dot.its.jpo.conflictmonitor.monitor.algorithms.timestamp_delta.map.MapTimestampDeltaParameters; import us.dot.its.jpo.conflictmonitor.monitor.algorithms.validation.map.MapValidationParameters; +import us.dot.its.jpo.conflictmonitor.monitor.models.events.broadcast_rate.MapBroadcastRateEvent; +import us.dot.its.jpo.conflictmonitor.monitor.models.events.minimum_data.MapMinimumDataEvent; +import us.dot.its.jpo.conflictmonitor.monitor.models.events.timestamp_delta.MapTimestampDeltaEvent; import us.dot.its.jpo.conflictmonitor.monitor.serialization.JsonSerdes; +import us.dot.its.jpo.conflictmonitor.monitor.topologies.timestamp_delta.MapTimestampDeltaTopology; import us.dot.its.jpo.conflictmonitor.testutils.TopologyTestUtils; import us.dot.its.jpo.geojsonconverter.partitioner.RsuIntersectionKey; import us.dot.its.jpo.geojsonconverter.pojos.ProcessedValidationMessage; @@ -23,8 +32,13 @@ import org.junit.Test; +import static java.util.stream.Collectors.toSet; import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.*; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.greaterThan; +import static org.hamcrest.Matchers.hasSize; +import static org.hamcrest.Matchers.notNullValue; +import static org.hamcrest.Matchers.startsWith; public class MapValidationTopologyTest { @@ -33,6 +47,12 @@ public class MapValidationTopologyTest { final String inputTopicName = "topic.ProcessedMap"; final String broadcastRateTopicName = "topic.CmMapBroadcastRateEvents"; final String minimumDataTopicName = "topic.CmMapMinimumDataEvents"; + final int maxDeltaMilliseconds = 50; + final String timestampOutputTopicName = "topic.CmTimestampDeltaEvent"; + final String keyStoreName = "mapTimestampDeltaKeyStore"; + final String eventStoreName = "mapTimestampDeltaEventStore"; + final int retentionTimeMinutes = 60; + final String notificationTopicName = "topic.CmTimestampDeltaNotification"; // Use a tumbling window for test (rolling period = output interval) // just to make it easier to design the test. @@ -59,36 +79,26 @@ public class MapValidationTopologyTest { @Test public void testMapValidationTopology() { - var parameters = getParameters(); - var streamsConfig = new Properties(); - streamsConfig.setProperty( - StreamsConfig.DEFAULT_TIMESTAMP_EXTRACTOR_CLASS_CONFIG, - TimestampExtractorForBroadcastRate.class.getName()); - var mapValidationTopology = new MapValidationTopology(); - mapValidationTopology.setParameters(parameters); - Topology topology = mapValidationTopology.buildTopology(); + Properties streamsConfig = createStreamsConfig(); + Topology topology = createTopology(); - - - try (TopologyTestDriver driver = new TopologyTestDriver(topology, streamsConfig)) { - - + try (TopologyTestDriver driver = new TopologyTestDriver(topology, streamsConfig); + Serde rsuIntersectionKeySerde + = us.dot.its.jpo.geojsonconverter.serialization.JsonSerdes.RsuIntersectionKey(); + Serde> processedMapSerde + = us.dot.its.jpo.geojsonconverter.serialization.JsonSerdes.ProcessedMapGeoJson(); + Serde mapBroadcastRateEventSerde = JsonSerdes.MapBroadcastRateEvent(); + Serde mapMinumumDataEventSerde = JsonSerdes.MapMinimumDataEvent()) { var inputTopic = driver.createInputTopic(inputTopicName, - us.dot.its.jpo.geojsonconverter.serialization.JsonSerdes.RsuIntersectionKey().serializer(), - us.dot.its.jpo.geojsonconverter.serialization.JsonSerdes.ProcessedMapGeoJson().serializer() - ); + rsuIntersectionKeySerde.serializer(), processedMapSerde.serializer()); var broadcastRateTopic = driver.createOutputTopic(broadcastRateTopicName, - us.dot.its.jpo.geojsonconverter.serialization.JsonSerdes.RsuIntersectionKey().deserializer(), - JsonSerdes.MapBroadcastRateEvent().deserializer() - ); + rsuIntersectionKeySerde.deserializer(), mapBroadcastRateEventSerde.deserializer()); var minimumDataTopic = driver.createOutputTopic(minimumDataTopicName, - us.dot.its.jpo.geojsonconverter.serialization.JsonSerdes.RsuIntersectionKey().deserializer(), - JsonSerdes.MapMinimumDataEvent().deserializer() - ); + rsuIntersectionKeySerde.deserializer(), mapMinumumDataEventSerde.deserializer()); final RsuIntersectionKey key = new RsuIntersectionKey(rsuId, intersectionId, region); @@ -133,6 +143,86 @@ public void testMapValidationTopology() { } + @Test + public void testMapTimestampDeltaSubtopology() { + Properties streamsConfig = createStreamsConfig(); + Topology topology = createTopology(); + + try (TopologyTestDriver driver = new TopologyTestDriver(topology, streamsConfig); + Serde rsuIntersectionKeySerde + = us.dot.its.jpo.geojsonconverter.serialization.JsonSerdes.RsuIntersectionKey(); + Serde> processedMapSerde + = us.dot.its.jpo.geojsonconverter.serialization.JsonSerdes.ProcessedMapGeoJson(); + Serde mapTimestampDeltaEventSerde = JsonSerdes.MapTimestampDeltaEvent()) { + + var inputTopic = driver.createInputTopic(inputTopicName, + rsuIntersectionKeySerde.serializer(), processedMapSerde.serializer()); + + var timestampDeltaEventTopic = driver.createOutputTopic(timestampOutputTopicName, + rsuIntersectionKeySerde.deserializer(), mapTimestampDeltaEventSerde.deserializer()); + + final RsuIntersectionKey key = new RsuIntersectionKey(rsuId, intersectionId, region); + + final Instant start1 = startTime; + final Instant start1_plus10 = start1.plusMillis(10L); + final Instant start2 = start1.plusSeconds(2L); + final Instant start2_plus500 = start2.plusMillis(500L); + final Instant start3 = start2.plusSeconds(2L); + final Instant start3_minus20 = start3.minusMillis(20L); + final Instant start4 = start3.plusSeconds(2L); + final Instant start4_minus600 = start4.minusMillis(600L); + + inputTopic.pipeInput(key, createMapWithTimestampOffset(start1, start1_plus10), start1); + inputTopic.pipeInput(key, createMapWithTimestampOffset(start2, start2_plus500), start2); + inputTopic.pipeInput(key, createMapWithTimestampOffset(start3, start3_minus20), start3); + inputTopic.pipeInput(key, createMapWithTimestampOffset(start4, start4_minus600), start4); + + final Set expectDeltas = ImmutableSet.of(500L, -20L, -600L); + final int numberOfEventsExpected = expectDeltas.size(); + + var timestampEventList = timestampDeltaEventTopic.readKeyValuesToList(); + assertThat(String.format("%s of 4 inputs should have produced timestamp delta events", numberOfEventsExpected), + timestampEventList, hasSize(numberOfEventsExpected)); + + + Set actualDeltas = timestampEventList.stream().map(entry -> entry.value.getDelta().getDeltaMillis()).collect(toSet()); + assertThat(String.format("Expect deltas %s. Actual deltas: %s", expectDeltas, actualDeltas), + Sets.symmetricDifference(expectDeltas, actualDeltas), hasSize(0)); + } + } + + + private Topology createTopology() { + var parameters = getParameters(); + var mapValidationTopology = new MapValidationTopology(); + mapValidationTopology.setParameters(parameters); + var timestampTopology = new MapTimestampDeltaTopology(); + var timestampParameters = getTimestampParameters(); + timestampTopology.setParameters(timestampParameters); + mapValidationTopology.setTimestampDeltaAlgorithm(timestampTopology); + return mapValidationTopology.buildTopology(); + } + + private Properties createStreamsConfig() { + var streamsConfig = new Properties(); + streamsConfig.setProperty( + StreamsConfig.DEFAULT_TIMESTAMP_EXTRACTOR_CLASS_CONFIG, + TimestampExtractorForBroadcastRate.class.getName()); + return streamsConfig; + } + + private MapTimestampDeltaParameters getTimestampParameters() { + var parameters = new MapTimestampDeltaParameters(); + parameters.setDebug(debug); + parameters.setMaxDeltaMilliseconds(maxDeltaMilliseconds); + parameters.setOutputTopicName(timestampOutputTopicName); + parameters.setKeyStoreName(keyStoreName); + parameters.setEventStoreName(eventStoreName); + parameters.setRetentionTimeMinutes(retentionTimeMinutes); + parameters.setNotificationTopicName(notificationTopicName); + return parameters; + } + private MapValidationParameters getParameters() { var parameters = new MapValidationParameters(); parameters.setInputTopicName(inputTopicName); @@ -163,6 +253,17 @@ private ProcessedMap createMap(Instant timestamp) { return map; } + // odeReceivedAt and timestamp separately + private ProcessedMap createMapWithTimestampOffset(Instant timestamp, Instant odeReceivedAt) { + var map = new ProcessedMap(); + var props = new MapSharedProperties(); + map.setProperties(props); + props.setOdeReceivedAt(odeReceivedAt.atZone(ZoneOffset.UTC)); + props.setTimeStamp(timestamp.atZone(ZoneOffset.UTC)); + props.setCti4501Conformant(true); + return map; + } + diff --git a/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/validation/SpatValidationTopologyTest.java b/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/validation/SpatValidationTopologyTest.java index 3a0bc149..bd6439ad 100644 --- a/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/validation/SpatValidationTopologyTest.java +++ b/jpo-conflictmonitor/src/test/java/us/dot/its/jpo/conflictmonitor/monitor/topologies/validation/SpatValidationTopologyTest.java @@ -6,12 +6,20 @@ import java.util.ArrayList; import java.util.List; import java.util.Properties; +import java.util.Set; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Sets; +import lombok.extern.slf4j.Slf4j; +import org.apache.kafka.common.serialization.Serde; +import us.dot.its.jpo.conflictmonitor.monitor.algorithms.timestamp_delta.spat.SpatTimestampDeltaParameters; import us.dot.its.jpo.conflictmonitor.monitor.algorithms.validation.spat.SpatValidationParameters; +import us.dot.its.jpo.conflictmonitor.monitor.models.events.broadcast_rate.SpatBroadcastRateEvent; +import us.dot.its.jpo.conflictmonitor.monitor.models.events.minimum_data.SpatMinimumDataEvent; +import us.dot.its.jpo.conflictmonitor.monitor.models.events.timestamp_delta.SpatTimestampDeltaEvent; import us.dot.its.jpo.conflictmonitor.monitor.serialization.JsonSerdes; +import us.dot.its.jpo.conflictmonitor.monitor.topologies.timestamp_delta.SpatTimestampDeltaTopology; import us.dot.its.jpo.conflictmonitor.testutils.TopologyTestUtils; import us.dot.its.jpo.geojsonconverter.partitioner.RsuIntersectionKey; import us.dot.its.jpo.geojsonconverter.pojos.ProcessedValidationMessage; @@ -21,16 +29,27 @@ import org.apache.kafka.streams.Topology; import org.apache.kafka.streams.TopologyTestDriver; import org.junit.Test; + +import static java.util.stream.Collectors.toSet; import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.*; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.greaterThan; +import static org.hamcrest.Matchers.hasSize; +import static org.hamcrest.Matchers.notNullValue; +import static org.hamcrest.Matchers.startsWith; +@Slf4j public class SpatValidationTopologyTest { - private final static Logger logger = LoggerFactory.getLogger(SpatValidationTopologyTest.class); - final String inputTopicName = "topic.ProcessedSpat"; final String broadcastRateTopicName = "topic.CmSpatBroadcastRateEvents"; final String minimumDataTopicName = "topic.CmSpatMinimumDataEvents"; + final int maxDeltaMilliseconds = 50; + final String timestampOutputTopicName = "topic.CmTimestampDeltaEvent"; + final String keyStoreName = "spatTimestampDeltaKeyStore"; + final String eventStoreName = "spatTimestampDeltaEventStore"; + final int retentionTimeMinutes = 60; + final String notificationTopicName = "topic.CmTimestampDeltaNotification"; // Use a tumbling window for test (rolling period = output interval) // just to make it easier to design the test. @@ -55,36 +74,26 @@ public class SpatValidationTopologyTest { @Test public void testMapValidationTopology() { - var parameters = getParameters(); - var streamsConfig = new Properties(); - streamsConfig.setProperty( - StreamsConfig.DEFAULT_TIMESTAMP_EXTRACTOR_CLASS_CONFIG, - TimestampExtractorForBroadcastRate.class.getName()); - - var spatValidationTopology = new SpatValidationTopology(); - spatValidationTopology.setParameters(parameters); - Topology topology = spatValidationTopology.buildTopology(); - - - try (TopologyTestDriver driver = new TopologyTestDriver(topology, streamsConfig)) { + var streamsConfig = createStreamsConfig(); + Topology topology = createTopology(); - + try (TopologyTestDriver driver = new TopologyTestDriver(topology, streamsConfig); + Serde rsuIntersectionKeySerde + = us.dot.its.jpo.geojsonconverter.serialization.JsonSerdes.RsuIntersectionKey(); + Serde processedSpatSerde + = us.dot.its.jpo.geojsonconverter.serialization.JsonSerdes.ProcessedSpat(); + Serde spatBroadcastRateEventSerde = JsonSerdes.SpatBroadcastRateEvent(); + Serde spatMinimumDataEventSerde = JsonSerdes.SpatMinimumDataEvent()) { var inputTopic = driver.createInputTopic(inputTopicName, - us.dot.its.jpo.geojsonconverter.serialization.JsonSerdes.RsuIntersectionKey().serializer(), - us.dot.its.jpo.geojsonconverter.serialization.JsonSerdes.ProcessedSpat().serializer() - ); + rsuIntersectionKeySerde.serializer(), processedSpatSerde.serializer()); var broadcastRateTopic = driver.createOutputTopic(broadcastRateTopicName, - us.dot.its.jpo.geojsonconverter.serialization.JsonSerdes.RsuIntersectionKey().deserializer(), - JsonSerdes.SpatBroadcastRateEvent().deserializer() - ); + rsuIntersectionKeySerde.deserializer(), spatBroadcastRateEventSerde.deserializer()); var minimumDataTopic = driver.createOutputTopic(minimumDataTopicName, - us.dot.its.jpo.geojsonconverter.serialization.JsonSerdes.RsuIntersectionKey().deserializer(), - JsonSerdes.SpatMinimumDataEvent().deserializer() - ); + rsuIntersectionKeySerde.deserializer(), spatMinimumDataEventSerde.deserializer()); final RsuIntersectionKey key = new RsuIntersectionKey(rsuId, intersectionId, region); @@ -107,13 +116,13 @@ public void testMapValidationTopology() { assertThat("min data event rsuId", result.getSource(), equalTo(source)); assertThat("min data event intersectionId", result.getIntersectionID(), equalTo(intersectionId)); assertThat("min data missingDataElements size", result.getMissingDataElements(), hasSize(1)); - var msg = result.getMissingDataElements().get(0); + var msg = result.getMissingDataElements().getFirst(); assertThat("min data validation message match", msg, startsWith(validationMsg)); } var broadcastRateList = broadcastRateTopic.readKeyValuesToList(); assertThat("Should be 1 broadcast rate event", broadcastRateList, hasSize(1)); - var broadcastRate = broadcastRateList.get(0); + var broadcastRate = broadcastRateList.getFirst(); var bcKey = broadcastRate.key; assertThat("broadcast rate key rsuId", bcKey.getRsuId(), equalTo(rsuId)); assertThat("broadcast rate key intersectionId", bcKey.getIntersectionId(), equalTo(intersectionId)); @@ -129,6 +138,83 @@ public void testMapValidationTopology() { } + @Test + public void testSpatTimestampDeltaSubtopology() { + Properties streamsConfig = createStreamsConfig(); + Topology topology = createTopology(); + + try (TopologyTestDriver driver = new TopologyTestDriver(topology, streamsConfig); + Serde rsuIntersectionKeySerde = us.dot.its.jpo.geojsonconverter.serialization.JsonSerdes.RsuIntersectionKey(); + Serde processedSpatSerde = us.dot.its.jpo.geojsonconverter.serialization.JsonSerdes.ProcessedSpat(); + Serde spatTimestampDeltaEventSerde = JsonSerdes.SpatTimestampDeltaEvent()) { + + var inputTopic = driver.createInputTopic(inputTopicName, + rsuIntersectionKeySerde.serializer(), processedSpatSerde.serializer()); + + var timestampDeltaEventTopic = driver.createOutputTopic(timestampOutputTopicName, + rsuIntersectionKeySerde.deserializer(), spatTimestampDeltaEventSerde.deserializer()); + + final RsuIntersectionKey key = new RsuIntersectionKey(rsuId, intersectionId, region); + + final Instant start1 = startTime; + final Instant start1_plus10 = start1.plusMillis(10L); + final Instant start2 = start1.plusSeconds(2L); + final Instant start2_plus500 = start2.plusMillis(500L); + final Instant start3 = start2.plusSeconds(2L); + final Instant start3_minus20 = start3.minusMillis(20L); + final Instant start4 = start3.plusSeconds(2L); + final Instant start4_minus600 = start4.minusMillis(600L); + + inputTopic.pipeInput(key, createSpatWithTimestampOffset(start1, start1_plus10), start1); + inputTopic.pipeInput(key, createSpatWithTimestampOffset(start2, start2_plus500), start2); + inputTopic.pipeInput(key, createSpatWithTimestampOffset(start3, start3_minus20), start3); + inputTopic.pipeInput(key, createSpatWithTimestampOffset(start4, start4_minus600), start4); + + var timestampEventList = timestampDeltaEventTopic.readKeyValuesToList(); + + final Set expectDeltas = ImmutableSet.of(500L, -20L, -600L); + final int numberOfEventsExpected = expectDeltas.size(); + + assertThat(String.format("%s of 4 inputs should have produced timestamp delta events", numberOfEventsExpected), + timestampEventList, hasSize(numberOfEventsExpected)); + + + Set actualDeltas = timestampEventList.stream().map(entry -> entry.value.getDelta().getDeltaMillis()).collect(toSet()); + assertThat(String.format("Expect deltas: %s. Actual deltas: %s", expectDeltas, actualDeltas), Sets.symmetricDifference(expectDeltas, actualDeltas), hasSize(0)); + } + } + + private Topology createTopology() { + var parameters = getParameters(); + var spatValidationTopology = new SpatValidationTopology(); + spatValidationTopology.setParameters(parameters); + var timestampTopology = new SpatTimestampDeltaTopology(); + var timestampParameters = getTimestampParameters(); + timestampTopology.setParameters(timestampParameters); + spatValidationTopology.setTimestampDeltaAlgorithm(timestampTopology); + return spatValidationTopology.buildTopology(); + } + + private Properties createStreamsConfig() { + var streamsConfig = new Properties(); + streamsConfig.setProperty( + StreamsConfig.DEFAULT_TIMESTAMP_EXTRACTOR_CLASS_CONFIG, + TimestampExtractorForBroadcastRate.class.getName()); + return streamsConfig; + } + + private SpatTimestampDeltaParameters getTimestampParameters() { + var parameters = new SpatTimestampDeltaParameters(); + parameters.setDebug(debug); + parameters.setMaxDeltaMilliseconds(maxDeltaMilliseconds); + parameters.setOutputTopicName(timestampOutputTopicName); + parameters.setKeyStoreName(keyStoreName); + parameters.setEventStoreName(eventStoreName); + parameters.setRetentionTimeMinutes(retentionTimeMinutes); + parameters.setNotificationTopicName(notificationTopicName); + return parameters; + } + private SpatValidationParameters getParameters() { var parameters = new SpatValidationParameters(); parameters.setInputTopicName(inputTopicName); @@ -140,6 +226,7 @@ private SpatValidationParameters getParameters() { parameters.setLowerBound(lowerBound); parameters.setUpperBound(upperBound); parameters.setDebug(debug); + return parameters; } @@ -157,6 +244,14 @@ private ProcessedSpat createSpat(Instant timestamp) { return spat; } + private ProcessedSpat createSpatWithTimestampOffset(Instant timestamp, Instant odeReceivedAt) { + var spat = new ProcessedSpat(); + spat.setOdeReceivedAt(odeReceivedAt.atZone(ZoneOffset.UTC).format(DateTimeFormatter.ISO_DATE_TIME)); + spat.setUtcTimeStamp(timestamp.atZone(ZoneOffset.UTC)); + spat.setCti4501Conformant(true); + return spat; + } + } diff --git a/jpo-conflictmonitor/src/test/resources/logback-test.xml b/jpo-conflictmonitor/src/test/resources/logback-test.xml index 5d2cbbc6..14754d01 100644 --- a/jpo-conflictmonitor/src/test/resources/logback-test.xml +++ b/jpo-conflictmonitor/src/test/resources/logback-test.xml @@ -4,7 +4,7 @@ %msg%n - + 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 index 32887969..9b574d62 100644 --- 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 @@ -53,12 +53,52 @@ 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; + + @Autowired @Setter(AccessLevel.NONE) private Environment env; @@ -255,6 +295,111 @@ public Boolean getConfluentCloudStatus() { } + @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; 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 index 2f9d1bdc..e03a9ade 100644 --- 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 @@ -15,10 +15,12 @@ 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.TimDeduplicatorTopology; @Controller @DependsOn("createKafkaTopics") @@ -43,33 +45,51 @@ public DeduplicatorServiceController(final DeduplicatorProperties props, try { - ProcessedMapDeduplicatorTopology processedMapDeduplicatorTopology = new ProcessedMapDeduplicatorTopology( - "topic.ProcessedMap", - "topic.DeduplicatedProcessedMap", - props.createStreamProperties("ProcessedMapDeduplicator") - ); - processedMapDeduplicatorTopology.start(); - - ProcessedMapWktDeduplicatorTopology processedMapWktDeduplicatorTopology = new ProcessedMapWktDeduplicatorTopology( - "topic.ProcessedMapWKT", - "topic.DeduplicatedProcessedMapWKT", - props.createStreamProperties("ProcessedMapWKTdeduplicator") - ); - processedMapWktDeduplicatorTopology.start(); + 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(); + } - MapDeduplicatorTopology mapDeduplicatorTopology = new MapDeduplicatorTopology( - "topic.OdeMapJson", - "topic.DeduplicatedOdeMapJson", - props.createStreamProperties("MapDeduplicator") - ); - mapDeduplicatorTopology.start(); + if(props.isEnableOdeRawEncodedTimDeduplication()){ + OdeRawEncodedTimDeduplicatorTopology odeRawEncodedTimDeduplicatorTopology = new OdeRawEncodedTimDeduplicatorTopology( + props, + props.createStreamProperties("OdeRawEncodedTimDeduplicator") + ); + odeRawEncodedTimDeduplicatorTopology.start(); + } - TimDeduplicatorTopology timDeduplicatorTopology = new TimDeduplicatorTopology( - "topic.OdeTimJson", - "topic.DeduplicatedOdeTimJson", - props.createStreamProperties("TimDeduplicator") - ); - timDeduplicatorTopology.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/TimPair.java b/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/models/OdeBsmPair.java similarity index 63% rename from jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/models/TimPair.java rename to jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/models/OdeBsmPair.java index a0474020..208622b7 100644 --- a/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/models/TimPair.java +++ b/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/models/OdeBsmPair.java @@ -3,17 +3,17 @@ import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; -import us.dot.its.jpo.ode.model.OdeTimData; +import us.dot.its.jpo.ode.model.OdeBsmData; @NoArgsConstructor @Setter @Getter -public class TimPair { +public class OdeBsmPair { - public OdeTimData message; + public OdeBsmData message; public boolean shouldSend; - public TimPair(OdeTimData message, 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/processors/DeduplicationProcessor.java b/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/processors/DeduplicationProcessor.java new file mode 100644 index 00000000..55b669c4 --- /dev/null +++ b/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/processors/DeduplicationProcessor.java @@ -0,0 +1,69 @@ +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 new file mode 100644 index 00000000..2197b23d --- /dev/null +++ b/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/processors/OdeBsmJsonProcessor.java @@ -0,0 +1,80 @@ +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 new file mode 100644 index 00000000..adaf6db2 --- /dev/null +++ b/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/processors/OdeMapJsonProcessor.java @@ -0,0 +1,70 @@ +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 new file mode 100644 index 00000000..cca49a7b --- /dev/null +++ b/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/processors/OdeRawEncodedTimJsonProcessor.java @@ -0,0 +1,43 @@ +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 new file mode 100644 index 00000000..751ce8cd --- /dev/null +++ b/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/processors/OdeTimJsonProcessor.java @@ -0,0 +1,42 @@ +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 new file mode 100644 index 00000000..35e2c2f6 --- /dev/null +++ b/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/processors/ProcessedMapProcessor.java @@ -0,0 +1,57 @@ +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 new file mode 100644 index 00000000..75560602 --- /dev/null +++ b/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/processors/ProcessedMapWktProcessor.java @@ -0,0 +1,55 @@ +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/suppliers/OdeBsmJsonProcessorSupplier.java b/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/processors/suppliers/OdeBsmJsonProcessorSupplier.java new file mode 100644 index 00000000..6b08b9f6 --- /dev/null +++ b/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/processors/suppliers/OdeBsmJsonProcessorSupplier.java @@ -0,0 +1,26 @@ +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 new file mode 100644 index 00000000..829af131 --- /dev/null +++ b/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/processors/suppliers/OdeMapJsonProcessorSupplier.java @@ -0,0 +1,22 @@ +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 new file mode 100644 index 00000000..ef0ebb7f --- /dev/null +++ b/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/processors/suppliers/OdeRawEncodedTimProcessorSupplier.java @@ -0,0 +1,22 @@ +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 new file mode 100644 index 00000000..7a27588d --- /dev/null +++ b/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/processors/suppliers/OdeTimJsonProcessorSupplier.java @@ -0,0 +1,22 @@ +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 new file mode 100644 index 00000000..9e45cd03 --- /dev/null +++ b/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/processors/suppliers/ProcessedMapProcessorSupplier.java @@ -0,0 +1,23 @@ +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 new file mode 100644 index 00000000..3dbaa8c1 --- /dev/null +++ b/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/processors/suppliers/ProcessedMapWktProcessorSupplier.java @@ -0,0 +1,22 @@ +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/serialization/PairSerdes.java b/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/serialization/PairSerdes.java index 751d1e96..e509fa00 100644 --- 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 @@ -6,6 +6,7 @@ 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; @@ -31,6 +32,12 @@ public static Serde OdeMapPair() { 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(), 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 new file mode 100644 index 00000000..6b26d676 --- /dev/null +++ b/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/topologies/BsmDeduplicatorTopology.java @@ -0,0 +1,125 @@ +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 index 6cfa5f63..a80fea74 100644 --- 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 @@ -2,30 +2,34 @@ import org.apache.kafka.common.serialization.Serdes; import org.apache.kafka.streams.KafkaStreams; -import org.apache.kafka.streams.KeyValue; 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.models.OdeMapPair; -import us.dot.its.jpo.deduplicator.deduplicator.serialization.PairSerdes; +import us.dot.its.jpo.conflictmonitor.monitor.models.bsm.BsmRsuIdKey; +import us.dot.its.jpo.conflictmonitor.monitor.utils.BsmUtils; +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.RsuIdPartitioner; import us.dot.its.jpo.geojsonconverter.partitioner.RsuIntersectionKey; import us.dot.its.jpo.geojsonconverter.serialization.JsonSerdes; +import us.dot.its.jpo.ode.model.OdeBsmData; 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.Duration; import java.time.Instant; import java.time.format.DateTimeFormatter; -import java.util.ArrayList; import java.util.Objects; import java.util.Properties; @@ -40,13 +44,13 @@ public class MapDeduplicatorTopology { Properties streamsProperties; ObjectMapper objectMapper; DateTimeFormatter formatter = DateTimeFormatter.ISO_INSTANT; + DeduplicatorProperties props; - public MapDeduplicatorTopology(String inputTopic, String outputTopic, Properties streamsProperties){ - this.inputTopic = inputTopic; - this.outputTopic = outputTopic; + public MapDeduplicatorTopology(DeduplicatorProperties props, Properties streamsProperties){ + this.props = props; this.streamsProperties = streamsProperties; - this.objectMapper = new ObjectMapper(); + this.objectMapper = DateJsonMapper.getInstance(); } @@ -78,8 +82,10 @@ public int hashMapMessage(OdeMapData map){ public Topology buildTopology() { StreamsBuilder builder = new StreamsBuilder(); - KStream inputStream = builder.stream(inputTopic, Consumed.with(Serdes.Void(), JsonSerdes.OdeMap())); + 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(); @@ -87,55 +93,13 @@ public Topology buildTopology() { newKey.setRsuId(((OdeMapMetadata)value.getMetadata()).getOriginIp()); newKey.setIntersectionReferenceID(intersectionId); return newKey.toString(); - }); - - KStream deduplicatedStream = mapRekeyedStream - .groupByKey(Grouped.with(Serdes.String(), JsonSerdes.OdeMap())) - .aggregate(() -> new OdeMapPair(new OdeMapData(), true), - (key, newValue, aggregate)->{ - - if(aggregate.getMessage().getMetadata() == null){ - return new OdeMapPair(newValue, true); - } - - Instant newValueTime = getInstantFromMap(newValue); - Instant oldValueTime = getInstantFromMap(aggregate.getMessage()); - - if(newValueTime.minus(Duration.ofHours(1)).isAfter(oldValueTime)){ - return new OdeMapPair(newValue, true ); - - }else{ - - OdeMapPayload oldPayload = (OdeMapPayload)aggregate.getMessage().getPayload(); - OdeMapPayload newPayload = (OdeMapPayload)newValue.getPayload(); - - Integer oldTimestamp = oldPayload.getMap().getTimeStamp(); - Integer newTimestamp = newPayload.getMap().getTimeStamp(); - - - newPayload.getMap().setTimeStamp(oldTimestamp); - - int oldHash = hashMapMessage(aggregate.getMessage()); - int newhash = hashMapMessage(newValue); - - if(oldHash != newhash){ - newPayload.getMap().setTimeStamp(newTimestamp); - return new OdeMapPair(newValue, true); - }else{ - return new OdeMapPair(aggregate.getMessage(), false); - } - } - }, Materialized.with(Serdes.String(), PairSerdes.OdeMapPair())) - .toStream() - .flatMap((key, value) ->{ - ArrayList> outputList = new ArrayList<>(); - if(value != null && value.isShouldSend()){ - outputList.add(new KeyValue<>(key, value.getMessage())); - } - return outputList; - }); + }).repartition(Repartitioned.with(Serdes.String(), JsonSerdes.OdeMap())); + + // KStream repartitionedStream = mapRekeyedStream.repartition(); + + KStream deduplicatedStream = mapRekeyedStream.process(new OdeMapJsonProcessorSupplier(props), props.getKafkaStateStoreOdeMapJsonName()); - deduplicatedStream.to(outputTopic, Produced.with(Serdes.String(), JsonSerdes.OdeMap())); + deduplicatedStream.to(props.getKafkaTopicDeduplicatedOdeMapJson(), Produced.with(Serdes.String(), JsonSerdes.OdeMap())); return builder.build(); 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 new file mode 100644 index 00000000..9431d6b4 --- /dev/null +++ b/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/topologies/OdeRawEncodedTimDeduplicatorTopology.java @@ -0,0 +1,131 @@ +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 index 0899b1d4..5f9da3dd 100644 --- 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 @@ -5,27 +5,22 @@ import org.apache.kafka.streams.StreamsBuilder; import org.apache.kafka.streams.Topology; import org.apache.kafka.streams.KafkaStreams.StateListener; -import org.apache.kafka.streams.KeyValue; import org.apache.kafka.streams.errors.StreamsUncaughtExceptionHandler; -import us.dot.its.jpo.deduplicator.deduplicator.models.ProcessedMapPair; -import us.dot.its.jpo.deduplicator.deduplicator.serialization.PairSerdes; +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.time.Duration; -import java.time.Instant; -import java.time.ZonedDateTime; -import java.util.ArrayList; import java.util.Properties; -import java.util.Objects; public class ProcessedMapDeduplicatorTopology { @@ -33,16 +28,14 @@ public class ProcessedMapDeduplicatorTopology { Topology topology; KafkaStreams streams; - String inputTopic; - String outputTopic; Properties streamsProperties; ObjectMapper objectMapper; + DeduplicatorProperties props; - public ProcessedMapDeduplicatorTopology(String inputTopic, String outputTopic, Properties streamsProperties){ - this.inputTopic = inputTopic; - this.outputTopic = outputTopic; + public ProcessedMapDeduplicatorTopology(DeduplicatorProperties props, Properties streamsProperties){ + this.props = props; this.streamsProperties = streamsProperties; - this.objectMapper = new ObjectMapper(); + this.objectMapper = DateJsonMapper.getInstance(); } @@ -54,61 +47,21 @@ public void start() { 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(inputTopic, Consumed.with(Serdes.String(), JsonSerdes.ProcessedMapGeoJson())); - - KStream> deduplicatedStream = inputStream - .groupByKey(Grouped.with(Serdes.String(), JsonSerdes.ProcessedMapGeoJson())) - .aggregate(() -> new ProcessedMapPair(new ProcessedMap(), true), - (key, newValue, aggregate)->{ - - // Handle the first message where the aggregate map isn't good. - if(aggregate.getMessage().getProperties() == null){ - return new ProcessedMapPair(newValue, true ); - } - - Instant newValueTime = newValue.getProperties().getOdeReceivedAt().toInstant(); - Instant oldValueTime = aggregate.getMessage().getProperties().getOdeReceivedAt().toInstant(); - - if(newValueTime.minus(Duration.ofHours(1)).isAfter(oldValueTime)){ - return new ProcessedMapPair(newValue, true ); - }else{ - ZonedDateTime newValueTimestamp = newValue.getProperties().getTimeStamp(); - ZonedDateTime newValueOdeReceivedAt = newValue.getProperties().getOdeReceivedAt(); - - newValue.getProperties().setTimeStamp(aggregate.getMessage().getProperties().getTimeStamp()); - newValue.getProperties().setOdeReceivedAt(aggregate.getMessage().getProperties().getOdeReceivedAt()); - - // int oldHash = aggregate.getMessage().getProperties().hashCode(); - // int newhash = newValue.getProperties().hashCode(); - int oldHash = Objects.hash(aggregate.getMessage().toString()); - int newHash = Objects.hash(newValue.toString()); - - if(oldHash != newHash){ - newValue.getProperties().setTimeStamp(newValueTimestamp); - newValue.getProperties().setOdeReceivedAt(newValueOdeReceivedAt); - return new ProcessedMapPair(newValue, true); - }else{ - return new ProcessedMapPair(aggregate.getMessage(), false); - } - } - }, Materialized.with(Serdes.String(), PairSerdes.ProcessedMapPair())) - .toStream() - .flatMap((key, value) ->{ - ArrayList>> outputList = new ArrayList<>(); - if(value != null && value.isShouldSend()){ - outputList.add(new KeyValue<>(key, value.getMessage())); - } - return outputList; - }); + 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(outputTopic, Produced.with(Serdes.String(), JsonSerdes.ProcessedMapGeoJson())); + deduplicatedStream.to(props.getKafkaTopicDeduplicatedProcessedMap(), Produced.with(Serdes.String(), JsonSerdes.ProcessedMapGeoJson())); return builder.build(); 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 index 9e6c8941..872e66fa 100644 --- 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 @@ -5,23 +5,20 @@ import org.apache.kafka.streams.StreamsBuilder; import org.apache.kafka.streams.Topology; import org.apache.kafka.streams.KafkaStreams.StateListener; -import org.apache.kafka.streams.KeyValue; import org.apache.kafka.streams.errors.StreamsUncaughtExceptionHandler; -import us.dot.its.jpo.deduplicator.deduplicator.models.ProcessedMapWktPair; -import us.dot.its.jpo.deduplicator.deduplicator.serialization.PairSerdes; +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.time.Duration; -import java.time.Instant; -import java.time.ZonedDateTime; -import java.util.ArrayList; import java.util.Properties; public class ProcessedMapWktDeduplicatorTopology { @@ -34,12 +31,12 @@ public class ProcessedMapWktDeduplicatorTopology { String outputTopic; Properties streamsProperties; ObjectMapper objectMapper; + DeduplicatorProperties props; - public ProcessedMapWktDeduplicatorTopology(String inputTopic, String outputTopic, Properties streamsProperties){ - this.inputTopic = inputTopic; - this.outputTopic = outputTopic; + public ProcessedMapWktDeduplicatorTopology(DeduplicatorProperties props, Properties streamsProperties){ + this.props = props; this.streamsProperties = streamsProperties; - this.objectMapper = new ObjectMapper(); + this.objectMapper = DateJsonMapper.getInstance(); } @@ -51,59 +48,21 @@ public void start() { 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(inputTopic, Consumed.with(Serdes.String(), JsonSerdes.ProcessedMapWKT())); - - KStream> deduplicatedStream = inputStream - .groupByKey(Grouped.with(Serdes.String(), JsonSerdes.ProcessedMapWKT())) - .aggregate(() -> new ProcessedMapWktPair(new ProcessedMap(), true), - (key, newValue, aggregate)->{ - - // Handle the first message where the aggregate map isn't good. - if(aggregate.getMessage().getProperties() == null){ - return new ProcessedMapWktPair(newValue, true ); - } - - Instant newValueTime = newValue.getProperties().getTimeStamp().toInstant(); - Instant oldValueTime = aggregate.getMessage().getProperties().getTimeStamp().toInstant(); - - if(newValueTime.minus(Duration.ofHours(1)).isAfter(oldValueTime)){ - return new ProcessedMapWktPair(newValue, true ); - }else{ - ZonedDateTime newValueTimestamp = newValue.getProperties().getTimeStamp(); - ZonedDateTime newValueOdeReceivedAt = newValue.getProperties().getOdeReceivedAt(); - - newValue.getProperties().setTimeStamp(aggregate.getMessage().getProperties().getTimeStamp()); - newValue.getProperties().setOdeReceivedAt(aggregate.getMessage().getProperties().getOdeReceivedAt()); - - int oldHash = aggregate.getMessage().getProperties().hashCode(); - int newhash = newValue.getProperties().hashCode(); - - if(oldHash != newhash){ - newValue.getProperties().setTimeStamp(newValueTimestamp); - newValue.getProperties().setOdeReceivedAt(newValueOdeReceivedAt); - return new ProcessedMapWktPair(newValue, true); - }else{ - return new ProcessedMapWktPair(aggregate.getMessage(), false); - } - } - }, Materialized.with(Serdes.String(), PairSerdes.ProcessedMapWktPair())) - .toStream() - .flatMap((key, value) ->{ - ArrayList>> outputList = new ArrayList<>(); - if(value != null && value.isShouldSend()){ - outputList.add(new KeyValue<>(key, value.getMessage())); - } - return outputList; - }); + KStream> inputStream = builder.stream(props.getKafkaTopicProcessedMapWKT(), Consumed.with(Serdes.String(), JsonSerdes.ProcessedMapWKT())); + builder.addStateStore(Stores.keyValueStoreBuilder(Stores.persistentKeyValueStore(props.getKafkaStateStoreProcessedMapWKTName()), + Serdes.String(), JsonSerdes.ProcessedMapWKT())); - deduplicatedStream.to(outputTopic, Produced.with(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(); 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 index fcb06b0f..d8cf5708 100644 --- 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 @@ -1,4 +1,3 @@ - package us.dot.its.jpo.deduplicator.deduplicator.topologies; import org.apache.kafka.common.serialization.Serdes; @@ -6,150 +5,122 @@ import org.apache.kafka.streams.StreamsBuilder; import org.apache.kafka.streams.Topology; import org.apache.kafka.streams.KafkaStreams.StateListener; -import org.apache.kafka.streams.KeyValue; import org.apache.kafka.streams.errors.StreamsUncaughtExceptionHandler; -import us.dot.its.jpo.deduplicator.deduplicator.models.JsonPair; -import us.dot.its.jpo.deduplicator.deduplicator.serialization.PairSerdes; 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.Duration; -import java.time.Instant; import java.time.format.DateTimeFormatter; -import java.util.ArrayList; 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(MapDeduplicatorTopology.class); + private static final Logger logger = LoggerFactory.getLogger(TimDeduplicatorTopology.class); Topology topology; KafkaStreams streams; - String inputTopic; - String outputTopic; Properties streamsProperties; ObjectMapper objectMapper; DateTimeFormatter formatter = DateTimeFormatter.ISO_INSTANT; + DeduplicatorProperties props; - public TimDeduplicatorTopology(String inputTopic, String outputTopic, Properties streamsProperties){ - this.inputTopic = inputTopic; - this.outputTopic = outputTopic; + public TimDeduplicatorTopology(DeduplicatorProperties props, Properties streamsProperties) { + this.props = props; this.streamsProperties = streamsProperties; - this.objectMapper = new ObjectMapper(); + 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"); + if (exceptionHandler != null) + streams.setUncaughtExceptionHandler(exceptionHandler); + if (stateListener != null) + streams.setStateListener(stateListener); + logger.info("Starting Tim Deduplicator Topology"); + streams.start(); } - public JsonNode genJsonNode(){ + 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(inputTopic, Consumed.with(Serdes.Void(), JsonSerdes.JSON())); - - KStream timRekeyedStream = inputStream.selectKey((key, value)->{ - try{ - String packetID = value.get("payload") - .get("data") - .get("AdvisorySituationData") - .get("asdmDetails") - .get("advisoryMessage") - .get("Ieee1609Dot2Data") - .get("content") - .get("unsecuredData") - .get("MessageFrame") - .get("value") - .get("TravelerInformation") - .get("packetID") - .asText(); - return packetID; - }catch(Exception e){ + 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 ""; } - }); - - KStream deduplicatedStream = timRekeyedStream - .groupByKey(Grouped.with(Serdes.String(), JsonSerdes.JSON())) - .aggregate( - ()-> new JsonPair(genJsonNode(), true), - (aggKey, newValue, aggregate) ->{ - if(aggregate.getMessage().get("metadata") == null){ - return new JsonPair(newValue, true); - } - - Instant oldValueTime = getInstantFromJsonTim(aggregate.getMessage()); - Instant newValueTime = getInstantFromJsonTim(newValue); - - if(newValueTime.minus(Duration.ofHours(1)).isAfter(oldValueTime)){ - return new JsonPair(newValue, true ); - }else{ - return new JsonPair(aggregate.getMessage(), false); - } - }, - Materialized.with(Serdes.String(), PairSerdes.JsonPair()) - ) - .toStream() - .flatMap((key, value) ->{ - ArrayList> outputList = new ArrayList<>(); - if(value != null && value.isShouldSend()){ - outputList.add(new KeyValue<>(key, value.getMessage())); - } - return outputList; - }); - - deduplicatedStream.to(outputTopic, Produced.with(Serdes.String(), JsonSerdes.JSON())); + }).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 Map deduplicator Socket Broadcast Topology."); + logger.info("Stopping Tim deduplicator Socket Broadcast Topology."); if (streams != null) { streams.close(); streams.cleanUp(); streams = null; } - logger.info("Stopped Map deduplicator Socket Broadcast Topology."); + 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 index d2bb5dfa..6104c141 100644 --- a/jpo-deduplicator/src/main/resources/application.yaml +++ b/jpo-deduplicator/src/main/resources/application.yaml @@ -6,7 +6,7 @@ version: ^project.version^ server.port: 8085 # Kafka properties -spring.kafka.bootstrap-servers: 172.250.250.181:9092 +spring.kafka.bootstrap-servers: ${KAFKA_BROKER_IP:localhost}:9092 logging.level.org.apache.kafka: INFO logging.level: INFO log4j.logger.kafka: OFF @@ -14,34 +14,70 @@ 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 + + + + # Custom kafka properties kafka.topics: autoCreateTopics: true # Override auto-create in test properties numPartitions: 1 numReplicas: 1 createTopics: - - name: topic.ProcessedMap + - name: ${kafkaTopicProcessedMap} cleanupPolicy: delete retentionMs: 300000 - - name: topic.DeduplicatedProcessedMap + - name: ${kafkaTopicDeduplicatedProcessedMap} cleanupPolicy: delete retentionMs: 300000 - - name: topic.ProcessedMapWKT + - name: ${kafkaTopicProcessedMapWKT} cleanupPolicy: delete retentionMs: 300000 - - name: topic.DeduplicatedProcessedMapWKT + - name: ${kafkaTopicDeduplicatedProcessedMapWKT} cleanupPolicy: delete retentionMs: 300000 - - name: topic.OdeMapJson + - name: ${kafkaTopicOdeMapJson} cleanupPolicy: delete retentionMs: 300000 - - name: topic.DeduplicatedOdeMapJson + - name: ${kafkaTopicDeduplicatedOdeMapJson} cleanupPolicy: delete retentionMs: 300000 - - name: topic.OdeTimJson + - name: ${kafkaTopicOdeTimJson} cleanupPolicy: delete retentionMs: 300000 - - name: topic.DeduplicatedOdeTimJson + - name: ${kafkaTopicDeduplicatedOdeTimJson} cleanupPolicy: delete retentionMs: 300000 diff --git a/jpo-deduplicator/src/test/java/deduplicator/BsmDeduplicatorTopologyTest.java b/jpo-deduplicator/src/test/java/deduplicator/BsmDeduplicatorTopologyTest.java new file mode 100644 index 00000000..98d62047 --- /dev/null +++ b/jpo-deduplicator/src/test/java/deduplicator/BsmDeduplicatorTopologyTest.java @@ -0,0 +1,116 @@ +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 index a6ae671d..a3396772 100644 --- a/jpo-deduplicator/src/test/java/deduplicator/MapDeduplicatorTopologyTest.java +++ b/jpo-deduplicator/src/test/java/deduplicator/MapDeduplicatorTopologyTest.java @@ -43,7 +43,11 @@ public class MapDeduplicatorTopologyTest { @Test public void testTopology() { - MapDeduplicatorTopology mapDeduplicatorTopology = new MapDeduplicatorTopology(inputTopic, outputTopic, null); + props = new DeduplicatorProperties(); + props.setKafkaTopicOdeMapJson(inputTopic); + props.setKafkaTopicDeduplicatedOdeMapJson(outputTopic); + + MapDeduplicatorTopology mapDeduplicatorTopology = new MapDeduplicatorTopology(props, null); Topology topology = mapDeduplicatorTopology.buildTopology(); diff --git a/jpo-deduplicator/src/test/java/deduplicator/OdeRawEncodedTimDeduplicatorTopologyTest.java b/jpo-deduplicator/src/test/java/deduplicator/OdeRawEncodedTimDeduplicatorTopologyTest.java new file mode 100644 index 00000000..4b618d9f --- /dev/null +++ b/jpo-deduplicator/src/test/java/deduplicator/OdeRawEncodedTimDeduplicatorTopologyTest.java @@ -0,0 +1,89 @@ +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 index 771abd74..331bfdcd 100644 --- a/jpo-deduplicator/src/test/java/deduplicator/ProcessedMapDeduplicatorTopologyTest.java +++ b/jpo-deduplicator/src/test/java/deduplicator/ProcessedMapDeduplicatorTopologyTest.java @@ -7,6 +7,7 @@ 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; @@ -14,6 +15,7 @@ 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; @@ -40,13 +42,18 @@ public class ProcessedMapDeduplicatorTopologyTest { String key = "{\"rsuId\":\"10.11.81.12\",\"intersectionId\":12109,\"region\":-1}"; - + @Autowired + DeduplicatorProperties props; @Test public void testTopology() { - ProcessedMapDeduplicatorTopology processedMapDeduplicatorTopology = new ProcessedMapDeduplicatorTopology(inputTopic, outputTopic, null); + props = new DeduplicatorProperties(); + props.setKafkaTopicProcessedMap(inputTopic); + props.setKafkaTopicDeduplicatedProcessedMap(outputTopic); + + ProcessedMapDeduplicatorTopology processedMapDeduplicatorTopology = new ProcessedMapDeduplicatorTopology(props, null); Topology topology = processedMapDeduplicatorTopology.buildTopology(); objectMapper.registerModule(new JavaTimeModule()); diff --git a/jpo-deduplicator/src/test/java/deduplicator/ProcessedMapWktDeduplicatorTopologyTest.java b/jpo-deduplicator/src/test/java/deduplicator/ProcessedMapWktDeduplicatorTopologyTest.java index cb8b43e5..7b1d2fb0 100644 --- a/jpo-deduplicator/src/test/java/deduplicator/ProcessedMapWktDeduplicatorTopologyTest.java +++ b/jpo-deduplicator/src/test/java/deduplicator/ProcessedMapWktDeduplicatorTopologyTest.java @@ -7,6 +7,7 @@ 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; @@ -14,6 +15,7 @@ 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; @@ -40,13 +42,18 @@ public class ProcessedMapWktDeduplicatorTopologyTest { String key = "{\"rsuId\":\"10.11.81.12\",\"intersectionId\":12109,\"region\":-1}"; - + @Autowired + DeduplicatorProperties props; @Test public void testTopology() { - ProcessedMapWktDeduplicatorTopology processedMapDeduplicatorTopology = new ProcessedMapWktDeduplicatorTopology(inputTopic, outputTopic, null); + props = new DeduplicatorProperties(); + props.setKafkaTopicProcessedMapWKT(inputTopic); + props.setKafkaTopicDeduplicatedProcessedMapWKT(outputTopic); + + ProcessedMapWktDeduplicatorTopology processedMapDeduplicatorTopology = new ProcessedMapWktDeduplicatorTopology(props, null); Topology topology = processedMapDeduplicatorTopology.buildTopology(); objectMapper.registerModule(new JavaTimeModule()); diff --git a/jpo-deduplicator/src/test/java/deduplicator/TimDeduplicatorTopologyTest.java b/jpo-deduplicator/src/test/java/deduplicator/TimDeduplicatorTopologyTest.java index 0cb1cf26..164dd220 100644 --- a/jpo-deduplicator/src/test/java/deduplicator/TimDeduplicatorTopologyTest.java +++ b/jpo-deduplicator/src/test/java/deduplicator/TimDeduplicatorTopologyTest.java @@ -7,10 +7,12 @@ 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; @@ -24,17 +26,29 @@ public class TimDeduplicatorTopologyTest { ObjectMapper objectMapper = new ObjectMapper(); - String inputTim1 = "{\"metadata\": {\"request\": {\"ode\": {\"verb\": \"POST\", \"version\": \"3\"}, \"sdw\": {\"recordId\": \"8F1EC79A\", \"serviceRegion\": {\"nwCorner\": {\"latitude\": \"38.260071253000035\", \"longitude\": \"-104.61205821899995\"}, \"seCorner\": {\"latitude\": \"38.24662288300004\", \"longitude\": \"-104.60519522999999\"}}, \"ttl\": \"oneday\"}}, \"recordGeneratedBy\": \"TMC\", \"schemaVersion\": \"6\", \"payloadType\": \"us.dot.its.jpo.ode.model.OdeTimPayload\", \"odePacketID\": \"2BDF1FF7CC704D162F\", \"serialId\": {\"recordId\": \"0\", \"serialNumber\": \"5368\", \"streamId\": \"b0b6d9d1-b141-4c36-8e6c-399b0d3752cb\", \"bundleSize\": \"1\", \"bundleId\": \"5368\"}, \"sanitized\": \"false\", \"recordGeneratedAt\": \"2024-02-06T16:05:07Z\", \"maxDurationTime\": \"30\", \"odeTimStartDateTime\": \"2024-02-07T03:30:35.594Z\", \"odeReceivedAt\": \"2024-02-07T03:30:36.655175608Z\"}, \"payload\": {\"data\": {\"AdvisorySituationData\": {\"recordID\": \"8F1EC79A\", \"timeToLive\": \"2\", \"serviceRegion\": {\"nwCorner\": {\"lat\": \"382600713\", \"long\": \"-1046120582\"}, \"seCorner\": {\"lat\": \"382466229\", \"long\": \"-1046051952\"}}, \"asdmDetails\": {\"advisoryMessage\": {\"Ieee1609Dot2Data\": {\"protocolVersion\": \"3\", \"content\": {\"unsecuredData\": {\"MessageFrame\": {\"messageId\": \"31\", \"value\": {\"TravelerInformation\": {\"timeStamp\": \"52805\", \"packetID\": \"2BDF1FF7CC704D162F\", \"urlB\": \"null\", \"dataFrames\": {\"TravelerDataFrame\": {\"durationTime\": \"30\", \"regions\": {\"GeographicalPath\": {\"closedPath\": {\"false\": \"\"}, \"anchor\": {\"lat\": \"382464880\", \"long\": \"-1046120566\"}, \"name\": \"I_I-25_SAT_8F1EC79A\", \"laneWidth\": \"5000\", \"directionality\": {\"both\": \"\"}, \"description\": {\"path\": {\"offset\": {\"ll\": {\"nodes\": {\"NodeLL\": [{\"delta\": {\"node-LL1\": {\"lon\": \"-10\", \"lat\": \"1349\"}}}, {\"delta\": {\"node-LL1\": {\"lon\": \"-6\", \"lat\": \"867\"}}}, {\"delta\": {\"node-LL2\": {\"lon\": \"508\", \"lat\": \"7000\"}}}, {\"delta\": {\"node-LL2\": {\"lon\": \"1661\", \"lat\": \"4937\"}}}, {\"delta\": {\"node-LL2\": {\"lon\": \"4782\", \"lat\": \"7303\"}}}, {\"delta\": {\"node-LL3\": {\"lon\": \"10822\", \"lat\": \"13477\"}}}, {\"delta\": {\"node-LL2\": {\"lon\": \"2959\", \"lat\": \"5342\"}}}, {\"delta\": {\"node-LL2\": {\"lon\": \"1727\", \"lat\": \"5691\"}}}, {\"delta\": {\"node-LL2\": {\"lon\": \"478\", \"lat\": \"5229\"}}}, {\"delta\": {\"node-LL3\": {\"lon\": \"813\", \"lat\": \"9717\"}}}, {\"delta\": {\"node-LL2\": {\"lon\": \"1340\", \"lat\": \"4096\"}}}, {\"delta\": {\"node-LL2\": {\"lon\": \"2129\", \"lat\": \"4303\"}}}, {\"delta\": {\"node-LL2\": {\"lon\": \"4414\", \"lat\": \"5808\"}}}, {\"delta\": {\"node-LL3\": {\"lon\": \"9105\", \"lat\": \"10079\"}}}, {\"delta\": {\"node-LL3\": {\"lon\": \"11527\", \"lat\": \"13142\"}}}, {\"delta\": {\"node-LL3\": {\"lon\": \"7811\", \"lat\": \"8931\"}}}, {\"delta\": {\"node-LL2\": {\"lon\": \"3534\", \"lat\": \"5332\"}}}, {\"delta\": {\"node-LL2\": {\"lon\": \"1496\", \"lat\": \"3910\"}}}, {\"delta\": {\"node-LL2\": {\"lon\": \"1336\", \"lat\": \"3608\"}}}, {\"delta\": {\"node-LL2\": {\"lon\": \"1151\", \"lat\": \"4104\"}}}, {\"delta\": {\"node-LL2\": {\"lon\": \"870\", \"lat\": \"7091\"}}}, {\"delta\": {\"node-LL2\": {\"lon\": \"166\", \"lat\": \"4518\"}}}]}}}, \"scale\": \"0\"}}, \"id\": {\"id\": \"0\", \"region\": \"0\"}, \"direction\": \"1100000000000001\"}}, \"startYear\": \"2024\", \"notUsed2\": \"0\", \"msgId\": {\"roadSignID\": {\"viewAngle\": \"1111111111111111\", \"mutcdCode\": {\"warning\": \"\"}, \"position\": {\"lat\": \"382464880\", \"long\": \"-1046120566\"}}}, \"notUsed3\": \"0\", \"notUsed1\": \"0\", \"priority\": \"5\", \"content\": {\"workZone\": {\"SEQUENCE\": {\"item\": {\"itis\": \"1025\"}}}}, \"url\": \"null\", \"notUsed\": \"0\", \"frameType\": {\"advisory\": \"\"}, \"startTime\": \"53490\"}}, \"msgCnt\": \"1\"}}}}}}}, \"startTime\": {\"month\": \"0\", \"hour\": \"31\", \"year\": \"0\", \"day\": \"0\", \"minute\": \"60\"}, \"stopTime\": {\"month\": \"0\", \"hour\": \"31\", \"year\": \"0\", \"day\": \"0\", \"minute\": \"60\"}, \"distType\": \"02\", \"asdmType\": \"2\", \"asdmID\": \"17B500B3\"}, \"requestID\": \"17B500B3\", \"groupID\": \"00000000\", \"dialogID\": \"156\", \"seqID\": \"5\"}}, \"dataType\": \"TravelerInformation\"}, \"recordGeneratedAt\": {\"$date\": \"2024-02-07T03:30:36.655Z\"}}"; - String inputTim2 = "{\"metadata\": {\"request\": {\"ode\": {\"verb\": \"POST\", \"version\": \"3\"}, \"sdw\": {\"recordId\": \"8F1EC79A\", \"serviceRegion\": {\"nwCorner\": {\"latitude\": \"38.260071253000035\", \"longitude\": \"-104.61205821899995\"}, \"seCorner\": {\"latitude\": \"38.24662288300004\", \"longitude\": \"-104.60519522999999\"}}, \"ttl\": \"oneday\"}}, \"recordGeneratedBy\": \"TMC\", \"schemaVersion\": \"6\", \"payloadType\": \"us.dot.its.jpo.ode.model.OdeTimPayload\", \"odePacketID\": \"2BDF1FF7CC704D162F\", \"serialId\": {\"recordId\": \"0\", \"serialNumber\": \"5368\", \"streamId\": \"b0b6d9d1-b141-4c36-8e6c-399b0d3752cb\", \"bundleSize\": \"1\", \"bundleId\": \"5368\"}, \"sanitized\": \"false\", \"recordGeneratedAt\": \"2024-02-06T16:05:07Z\", \"maxDurationTime\": \"30\", \"odeTimStartDateTime\": \"2024-02-07T03:30:35.594Z\", \"odeReceivedAt\": \"2024-02-07T03:30:37.655175608Z\"}, \"payload\": {\"data\": {\"AdvisorySituationData\": {\"recordID\": \"8F1EC79A\", \"timeToLive\": \"2\", \"serviceRegion\": {\"nwCorner\": {\"lat\": \"382600713\", \"long\": \"-1046120582\"}, \"seCorner\": {\"lat\": \"382466229\", \"long\": \"-1046051952\"}}, \"asdmDetails\": {\"advisoryMessage\": {\"Ieee1609Dot2Data\": {\"protocolVersion\": \"3\", \"content\": {\"unsecuredData\": {\"MessageFrame\": {\"messageId\": \"31\", \"value\": {\"TravelerInformation\": {\"timeStamp\": \"52805\", \"packetID\": \"2BDF1FF7CC704D162F\", \"urlB\": \"null\", \"dataFrames\": {\"TravelerDataFrame\": {\"durationTime\": \"30\", \"regions\": {\"GeographicalPath\": {\"closedPath\": {\"false\": \"\"}, \"anchor\": {\"lat\": \"382464880\", \"long\": \"-1046120566\"}, \"name\": \"I_I-25_SAT_8F1EC79A\", \"laneWidth\": \"5000\", \"directionality\": {\"both\": \"\"}, \"description\": {\"path\": {\"offset\": {\"ll\": {\"nodes\": {\"NodeLL\": [{\"delta\": {\"node-LL1\": {\"lon\": \"-10\", \"lat\": \"1349\"}}}, {\"delta\": {\"node-LL1\": {\"lon\": \"-6\", \"lat\": \"867\"}}}, {\"delta\": {\"node-LL2\": {\"lon\": \"508\", \"lat\": \"7000\"}}}, {\"delta\": {\"node-LL2\": {\"lon\": \"1661\", \"lat\": \"4937\"}}}, {\"delta\": {\"node-LL2\": {\"lon\": \"4782\", \"lat\": \"7303\"}}}, {\"delta\": {\"node-LL3\": {\"lon\": \"10822\", \"lat\": \"13477\"}}}, {\"delta\": {\"node-LL2\": {\"lon\": \"2959\", \"lat\": \"5342\"}}}, {\"delta\": {\"node-LL2\": {\"lon\": \"1727\", \"lat\": \"5691\"}}}, {\"delta\": {\"node-LL2\": {\"lon\": \"478\", \"lat\": \"5229\"}}}, {\"delta\": {\"node-LL3\": {\"lon\": \"813\", \"lat\": \"9717\"}}}, {\"delta\": {\"node-LL2\": {\"lon\": \"1340\", \"lat\": \"4096\"}}}, {\"delta\": {\"node-LL2\": {\"lon\": \"2129\", \"lat\": \"4303\"}}}, {\"delta\": {\"node-LL2\": {\"lon\": \"4414\", \"lat\": \"5808\"}}}, {\"delta\": {\"node-LL3\": {\"lon\": \"9105\", \"lat\": \"10079\"}}}, {\"delta\": {\"node-LL3\": {\"lon\": \"11527\", \"lat\": \"13142\"}}}, {\"delta\": {\"node-LL3\": {\"lon\": \"7811\", \"lat\": \"8931\"}}}, {\"delta\": {\"node-LL2\": {\"lon\": \"3534\", \"lat\": \"5332\"}}}, {\"delta\": {\"node-LL2\": {\"lon\": \"1496\", \"lat\": \"3910\"}}}, {\"delta\": {\"node-LL2\": {\"lon\": \"1336\", \"lat\": \"3608\"}}}, {\"delta\": {\"node-LL2\": {\"lon\": \"1151\", \"lat\": \"4104\"}}}, {\"delta\": {\"node-LL2\": {\"lon\": \"870\", \"lat\": \"7091\"}}}, {\"delta\": {\"node-LL2\": {\"lon\": \"166\", \"lat\": \"4518\"}}}]}}}, \"scale\": \"0\"}}, \"id\": {\"id\": \"0\", \"region\": \"0\"}, \"direction\": \"1100000000000001\"}}, \"startYear\": \"2024\", \"notUsed2\": \"0\", \"msgId\": {\"roadSignID\": {\"viewAngle\": \"1111111111111111\", \"mutcdCode\": {\"warning\": \"\"}, \"position\": {\"lat\": \"382464880\", \"long\": \"-1046120566\"}}}, \"notUsed3\": \"0\", \"notUsed1\": \"0\", \"priority\": \"5\", \"content\": {\"workZone\": {\"SEQUENCE\": {\"item\": {\"itis\": \"1025\"}}}}, \"url\": \"null\", \"notUsed\": \"0\", \"frameType\": {\"advisory\": \"\"}, \"startTime\": \"53490\"}}, \"msgCnt\": \"1\"}}}}}}}, \"startTime\": {\"month\": \"0\", \"hour\": \"31\", \"year\": \"0\", \"day\": \"0\", \"minute\": \"60\"}, \"stopTime\": {\"month\": \"0\", \"hour\": \"31\", \"year\": \"0\", \"day\": \"0\", \"minute\": \"60\"}, \"distType\": \"02\", \"asdmType\": \"2\", \"asdmID\": \"17B500B3\"}, \"requestID\": \"17B500B3\", \"groupID\": \"00000000\", \"dialogID\": \"156\", \"seqID\": \"5\"}}, \"dataType\": \"TravelerInformation\"}, \"recordGeneratedAt\": {\"$date\": \"2024-02-07T03:30:36.655Z\"}}"; - String inputTim3 = "{\"metadata\": {\"request\": {\"ode\": {\"verb\": \"POST\", \"version\": \"3\"}, \"sdw\": {\"recordId\": \"8F1EC79A\", \"serviceRegion\": {\"nwCorner\": {\"latitude\": \"38.260071253000035\", \"longitude\": \"-104.61205821899995\"}, \"seCorner\": {\"latitude\": \"38.24662288300004\", \"longitude\": \"-104.60519522999999\"}}, \"ttl\": \"oneday\"}}, \"recordGeneratedBy\": \"TMC\", \"schemaVersion\": \"6\", \"payloadType\": \"us.dot.its.jpo.ode.model.OdeTimPayload\", \"odePacketID\": \"2BDF1FF7CC704D162F\", \"serialId\": {\"recordId\": \"0\", \"serialNumber\": \"5368\", \"streamId\": \"b0b6d9d1-b141-4c36-8e6c-399b0d3752cb\", \"bundleSize\": \"1\", \"bundleId\": \"5368\"}, \"sanitized\": \"false\", \"recordGeneratedAt\": \"2024-02-06T16:05:07Z\", \"maxDurationTime\": \"30\", \"odeTimStartDateTime\": \"2024-02-07T03:30:35.594Z\", \"odeReceivedAt\": \"2024-02-07T03:30:38.655175608Z\"}, \"payload\": {\"data\": {\"AdvisorySituationData\": {\"recordID\": \"8F1EC79A\", \"timeToLive\": \"2\", \"serviceRegion\": {\"nwCorner\": {\"lat\": \"382600713\", \"long\": \"-1046120582\"}, \"seCorner\": {\"lat\": \"382466229\", \"long\": \"-1046051952\"}}, \"asdmDetails\": {\"advisoryMessage\": {\"Ieee1609Dot2Data\": {\"protocolVersion\": \"3\", \"content\": {\"unsecuredData\": {\"MessageFrame\": {\"messageId\": \"31\", \"value\": {\"TravelerInformation\": {\"timeStamp\": \"52805\", \"packetID\": \"2BDF1FF7CC704D162A\", \"urlB\": \"null\", \"dataFrames\": {\"TravelerDataFrame\": {\"durationTime\": \"30\", \"regions\": {\"GeographicalPath\": {\"closedPath\": {\"false\": \"\"}, \"anchor\": {\"lat\": \"382464880\", \"long\": \"-1046120566\"}, \"name\": \"I_I-25_SAT_8F1EC79A\", \"laneWidth\": \"5000\", \"directionality\": {\"both\": \"\"}, \"description\": {\"path\": {\"offset\": {\"ll\": {\"nodes\": {\"NodeLL\": [{\"delta\": {\"node-LL1\": {\"lon\": \"-10\", \"lat\": \"1349\"}}}, {\"delta\": {\"node-LL1\": {\"lon\": \"-6\", \"lat\": \"867\"}}}, {\"delta\": {\"node-LL2\": {\"lon\": \"508\", \"lat\": \"7000\"}}}, {\"delta\": {\"node-LL2\": {\"lon\": \"1661\", \"lat\": \"4937\"}}}, {\"delta\": {\"node-LL2\": {\"lon\": \"4782\", \"lat\": \"7303\"}}}, {\"delta\": {\"node-LL3\": {\"lon\": \"10822\", \"lat\": \"13477\"}}}, {\"delta\": {\"node-LL2\": {\"lon\": \"2959\", \"lat\": \"5342\"}}}, {\"delta\": {\"node-LL2\": {\"lon\": \"1727\", \"lat\": \"5691\"}}}, {\"delta\": {\"node-LL2\": {\"lon\": \"478\", \"lat\": \"5229\"}}}, {\"delta\": {\"node-LL3\": {\"lon\": \"813\", \"lat\": \"9717\"}}}, {\"delta\": {\"node-LL2\": {\"lon\": \"1340\", \"lat\": \"4096\"}}}, {\"delta\": {\"node-LL2\": {\"lon\": \"2129\", \"lat\": \"4303\"}}}, {\"delta\": {\"node-LL2\": {\"lon\": \"4414\", \"lat\": \"5808\"}}}, {\"delta\": {\"node-LL3\": {\"lon\": \"9105\", \"lat\": \"10079\"}}}, {\"delta\": {\"node-LL3\": {\"lon\": \"11527\", \"lat\": \"13142\"}}}, {\"delta\": {\"node-LL3\": {\"lon\": \"7811\", \"lat\": \"8931\"}}}, {\"delta\": {\"node-LL2\": {\"lon\": \"3534\", \"lat\": \"5332\"}}}, {\"delta\": {\"node-LL2\": {\"lon\": \"1496\", \"lat\": \"3910\"}}}, {\"delta\": {\"node-LL2\": {\"lon\": \"1336\", \"lat\": \"3608\"}}}, {\"delta\": {\"node-LL2\": {\"lon\": \"1151\", \"lat\": \"4104\"}}}, {\"delta\": {\"node-LL2\": {\"lon\": \"870\", \"lat\": \"7091\"}}}, {\"delta\": {\"node-LL2\": {\"lon\": \"166\", \"lat\": \"4518\"}}}]}}}, \"scale\": \"0\"}}, \"id\": {\"id\": \"0\", \"region\": \"0\"}, \"direction\": \"1100000000000001\"}}, \"startYear\": \"2024\", \"notUsed2\": \"0\", \"msgId\": {\"roadSignID\": {\"viewAngle\": \"1111111111111111\", \"mutcdCode\": {\"warning\": \"\"}, \"position\": {\"lat\": \"382464880\", \"long\": \"-1046120566\"}}}, \"notUsed3\": \"0\", \"notUsed1\": \"0\", \"priority\": \"5\", \"content\": {\"workZone\": {\"SEQUENCE\": {\"item\": {\"itis\": \"1025\"}}}}, \"url\": \"null\", \"notUsed\": \"0\", \"frameType\": {\"advisory\": \"\"}, \"startTime\": \"53490\"}}, \"msgCnt\": \"1\"}}}}}}}, \"startTime\": {\"month\": \"0\", \"hour\": \"31\", \"year\": \"0\", \"day\": \"0\", \"minute\": \"60\"}, \"stopTime\": {\"month\": \"0\", \"hour\": \"31\", \"year\": \"0\", \"day\": \"0\", \"minute\": \"60\"}, \"distType\": \"02\", \"asdmType\": \"2\", \"asdmID\": \"17B500B3\"}, \"requestID\": \"17B500B3\", \"groupID\": \"00000000\", \"dialogID\": \"156\", \"seqID\": \"5\"}}, \"dataType\": \"TravelerInformation\"}, \"recordGeneratedAt\": {\"$date\": \"2024-02-07T03:30:36.655Z\"}}"; - String inputTim4 = "{\"metadata\": {\"request\": {\"ode\": {\"verb\": \"POST\", \"version\": \"3\"}, \"sdw\": {\"recordId\": \"8F1EC79A\", \"serviceRegion\": {\"nwCorner\": {\"latitude\": \"38.260071253000035\", \"longitude\": \"-104.61205821899995\"}, \"seCorner\": {\"latitude\": \"38.24662288300004\", \"longitude\": \"-104.60519522999999\"}}, \"ttl\": \"oneday\"}}, \"recordGeneratedBy\": \"TMC\", \"schemaVersion\": \"6\", \"payloadType\": \"us.dot.its.jpo.ode.model.OdeTimPayload\", \"odePacketID\": \"2BDF1FF7CC704D162F\", \"serialId\": {\"recordId\": \"0\", \"serialNumber\": \"5368\", \"streamId\": \"b0b6d9d1-b141-4c36-8e6c-399b0d3752cb\", \"bundleSize\": \"1\", \"bundleId\": \"5368\"}, \"sanitized\": \"false\", \"recordGeneratedAt\": \"2024-02-06T16:05:07Z\", \"maxDurationTime\": \"30\", \"odeTimStartDateTime\": \"2024-02-07T03:30:35.594Z\", \"odeReceivedAt\": \"2024-02-07T04:35:36.655175608Z\"}, \"payload\": {\"data\": {\"AdvisorySituationData\": {\"recordID\": \"8F1EC79A\", \"timeToLive\": \"2\", \"serviceRegion\": {\"nwCorner\": {\"lat\": \"382600713\", \"long\": \"-1046120582\"}, \"seCorner\": {\"lat\": \"382466229\", \"long\": \"-1046051952\"}}, \"asdmDetails\": {\"advisoryMessage\": {\"Ieee1609Dot2Data\": {\"protocolVersion\": \"3\", \"content\": {\"unsecuredData\": {\"MessageFrame\": {\"messageId\": \"31\", \"value\": {\"TravelerInformation\": {\"timeStamp\": \"52805\", \"packetID\": \"2BDF1FF7CC704D162F\", \"urlB\": \"null\", \"dataFrames\": {\"TravelerDataFrame\": {\"durationTime\": \"30\", \"regions\": {\"GeographicalPath\": {\"closedPath\": {\"false\": \"\"}, \"anchor\": {\"lat\": \"382464880\", \"long\": \"-1046120566\"}, \"name\": \"I_I-25_SAT_8F1EC79A\", \"laneWidth\": \"5000\", \"directionality\": {\"both\": \"\"}, \"description\": {\"path\": {\"offset\": {\"ll\": {\"nodes\": {\"NodeLL\": [{\"delta\": {\"node-LL1\": {\"lon\": \"-10\", \"lat\": \"1349\"}}}, {\"delta\": {\"node-LL1\": {\"lon\": \"-6\", \"lat\": \"867\"}}}, {\"delta\": {\"node-LL2\": {\"lon\": \"508\", \"lat\": \"7000\"}}}, {\"delta\": {\"node-LL2\": {\"lon\": \"1661\", \"lat\": \"4937\"}}}, {\"delta\": {\"node-LL2\": {\"lon\": \"4782\", \"lat\": \"7303\"}}}, {\"delta\": {\"node-LL3\": {\"lon\": \"10822\", \"lat\": \"13477\"}}}, {\"delta\": {\"node-LL2\": {\"lon\": \"2959\", \"lat\": \"5342\"}}}, {\"delta\": {\"node-LL2\": {\"lon\": \"1727\", \"lat\": \"5691\"}}}, {\"delta\": {\"node-LL2\": {\"lon\": \"478\", \"lat\": \"5229\"}}}, {\"delta\": {\"node-LL3\": {\"lon\": \"813\", \"lat\": \"9717\"}}}, {\"delta\": {\"node-LL2\": {\"lon\": \"1340\", \"lat\": \"4096\"}}}, {\"delta\": {\"node-LL2\": {\"lon\": \"2129\", \"lat\": \"4303\"}}}, {\"delta\": {\"node-LL2\": {\"lon\": \"4414\", \"lat\": \"5808\"}}}, {\"delta\": {\"node-LL3\": {\"lon\": \"9105\", \"lat\": \"10079\"}}}, {\"delta\": {\"node-LL3\": {\"lon\": \"11527\", \"lat\": \"13142\"}}}, {\"delta\": {\"node-LL3\": {\"lon\": \"7811\", \"lat\": \"8931\"}}}, {\"delta\": {\"node-LL2\": {\"lon\": \"3534\", \"lat\": \"5332\"}}}, {\"delta\": {\"node-LL2\": {\"lon\": \"1496\", \"lat\": \"3910\"}}}, {\"delta\": {\"node-LL2\": {\"lon\": \"1336\", \"lat\": \"3608\"}}}, {\"delta\": {\"node-LL2\": {\"lon\": \"1151\", \"lat\": \"4104\"}}}, {\"delta\": {\"node-LL2\": {\"lon\": \"870\", \"lat\": \"7091\"}}}, {\"delta\": {\"node-LL2\": {\"lon\": \"166\", \"lat\": \"4518\"}}}]}}}, \"scale\": \"0\"}}, \"id\": {\"id\": \"0\", \"region\": \"0\"}, \"direction\": \"1100000000000001\"}}, \"startYear\": \"2024\", \"notUsed2\": \"0\", \"msgId\": {\"roadSignID\": {\"viewAngle\": \"1111111111111111\", \"mutcdCode\": {\"warning\": \"\"}, \"position\": {\"lat\": \"382464880\", \"long\": \"-1046120566\"}}}, \"notUsed3\": \"0\", \"notUsed1\": \"0\", \"priority\": \"5\", \"content\": {\"workZone\": {\"SEQUENCE\": {\"item\": {\"itis\": \"1025\"}}}}, \"url\": \"null\", \"notUsed\": \"0\", \"frameType\": {\"advisory\": \"\"}, \"startTime\": \"53490\"}}, \"msgCnt\": \"1\"}}}}}}}, \"startTime\": {\"month\": \"0\", \"hour\": \"31\", \"year\": \"0\", \"day\": \"0\", \"minute\": \"60\"}, \"stopTime\": {\"month\": \"0\", \"hour\": \"31\", \"year\": \"0\", \"day\": \"0\", \"minute\": \"60\"}, \"distType\": \"02\", \"asdmType\": \"2\", \"asdmID\": \"17B500B3\"}, \"requestID\": \"17B500B3\", \"groupID\": \"00000000\", \"dialogID\": \"156\", \"seqID\": \"5\"}}, \"dataType\": \"TravelerInformation\"}, \"recordGeneratedAt\": {\"$date\": \"2024-02-07T03:30:36.655Z\"}}"; - + //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() { - TimDeduplicatorTopology TimDeduplicatorTopology = new TimDeduplicatorTopology(inputTopic, outputTopic, null); + props = new DeduplicatorProperties(); + props.setKafkaTopicOdeTimJson(inputTopic); + props.setKafkaTopicDeduplicatedOdeTimJson(outputTopic); + + TimDeduplicatorTopology TimDeduplicatorTopology = new TimDeduplicatorTopology(props, null); Topology topology = TimDeduplicatorTopology.buildTopology(); objectMapper.registerModule(new JavaTimeModule()); diff --git a/jpo-geojsonconverter b/jpo-geojsonconverter index 4fa5b8eb..1800d426 160000 --- a/jpo-geojsonconverter +++ b/jpo-geojsonconverter @@ -1 +1 @@ -Subproject commit 4fa5b8eb1204c48db4774eed6449d3bcb0bb9150 +Subproject commit 1800d426c4957d1bbf072013ffbb1fed49c08089 diff --git a/test-message-sender/README.md b/test-message-sender/README.md index eb430fbe..884f2bde 100644 --- a/test-message-sender/README.md +++ b/test-message-sender/README.md @@ -98,12 +98,13 @@ message-type,relative-timestamp,json-template `relative-timestamp` is the number of milliseconds relative to the start time. -`json-template` is a OdeSpatJson, OdeMapJson, or OdeBsmJson object on a single line, with the following placeholders: +`json-template` is a OdeSpatJson, OdeMapJson, or OdeBsmJson, ProcessedMap or ProcessedSpat object on a single line, with the following placeholders: * `@ISO_DATE_TIME@` - Date/Time string. * `@TEMP_ID@` - Temporary ID for BSMs, a string of 8 hex digits. * `"@MINUTE_OF_YEAR@"` - Numeric minute of the year. * `"@MILLI_OF_MINUTE@"` - Numeric millisecond of the minute. +* `@ISO_DATE_TIME_OFFSET_MILLIS_{offset}` - Date/Time string offset by a number of milliseconds The script runner converts the timestamps to times relative to the script start time, inserts them into the JSON templates, and schedules the messages to be sent to the appropriate topics in real time. It generates a random BSM Temporary ID for each script run. diff --git a/test-message-sender/script-runner/pom.xml b/test-message-sender/script-runner/pom.xml index c3e658ea..52dccce9 100644 --- a/test-message-sender/script-runner/pom.xml +++ b/test-message-sender/script-runner/pom.xml @@ -67,6 +67,18 @@ spring-kafka-test test + + junit + junit + 4.13.2 + test + + + org.mockito + mockito-core + 5.10.0 + test + @@ -92,6 +104,36 @@ + + org.apache.maven.plugins + maven-surefire-plugin + 3.2.5 + + + + + + + + + + + + + + org.apache.maven.surefire + surefire-junit47 + 3.2.5 + + + + + + + org.apache.maven.plugins + maven-surefire-report-plugin + 3.2.5 + 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 c1ff4813..272a3e19 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 @@ -20,6 +20,8 @@ import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; import org.springframework.stereotype.Component; +import static us.dot.its.jpo.ode.messagesender.scriptrunner.ScriptTemplate.fillTemplate; + @Component public class ScriptRunner { @@ -100,54 +102,8 @@ private void scheduleMessage(final long startTime, final String messageType, logger.info("Scheduled {} job at {}", messageType, sendTime); } - public static final String ISO_DATE_TIME = "@ISO_DATE_TIME@"; - public static final String MINUTE_OF_YEAR = "\"@MINUTE_OF_YEAR@\""; - public static final String MILLI_OF_MINUTE = "\"@MILLI_OF_MINUTE@\""; - public static final String EPOCH_SECONDS = "\"@EPOCH_SECONDS@\""; - public static final Pattern OFFSET_SECONDS = Pattern.compile("@OFFSET_SECONDS_(?-?[0-9.]+)@"); - public static final String TEMP_ID = "@TEMP_ID@"; - - - - private static String fillTemplate(Instant sendInstant, String message, String tempId) { - ZonedDateTime zdt = sendInstant.atZone(ZoneOffset.UTC); - String isoDateTime = zdt.format(DateTimeFormatter.ISO_DATE_TIME); - - ZonedDateTime zdtYear = ZonedDateTime.of(zdt.getYear(), 1, 1, 0, 0, 0, 0, ZoneOffset.UTC); - Duration moyDuration = Duration.between(zdtYear, zdt); - long minuteOfYear = moyDuration.toMinutes(); - - ZonedDateTime zdtMinute = ZonedDateTime.of(zdt.getYear(), zdt.getMonthValue(), - zdt.getDayOfMonth(), zdt.getHour(), zdt.getMinute(), 0, 0, ZoneOffset.UTC); - Duration minDuration = Duration.between(zdtMinute, zdt); - long milliOfMinute = minDuration.toMillis(); - - double epochSecond = sendInstant.toEpochMilli() / 1000.0d; - - // Fill in offset seconds in timing - var matcher = OFFSET_SECONDS.matcher(message); - String replaced = matcher.replaceAll((matchResult) -> { - String offsetStr = matcher.group("offset"); - double offsetSeconds = Double.parseDouble(offsetStr); - double timingSeconds = epochSecond + offsetSeconds; - long timingMillis = Math.round(1000 * timingSeconds); - Instant timingInstant = Instant.ofEpochMilli(timingMillis); - ZonedDateTime zdtTiming = timingInstant.atZone(ZoneOffset.UTC); - return zdtTiming.format(DateTimeFormatter.ISO_DATE_TIME); - }); - - return replaced - .replace(ISO_DATE_TIME, isoDateTime) - .replace(MINUTE_OF_YEAR, Long.toString(minuteOfYear)) - .replace(MILLI_OF_MINUTE, Long.toString(milliOfMinute)) - .replace(EPOCH_SECONDS, Double.toString(epochSecond)) - .replace(TEMP_ID, tempId); - +} - } - - -} diff --git a/test-message-sender/script-runner/src/main/java/us/dot/its/jpo/ode/messagesender/scriptrunner/ScriptRunnerConfig.java b/test-message-sender/script-runner/src/main/java/us/dot/its/jpo/ode/messagesender/scriptrunner/ScriptRunnerConfig.java index e7205a42..b3ff1a24 100644 --- a/test-message-sender/script-runner/src/main/java/us/dot/its/jpo/ode/messagesender/scriptrunner/ScriptRunnerConfig.java +++ b/test-message-sender/script-runner/src/main/java/us/dot/its/jpo/ode/messagesender/scriptrunner/ScriptRunnerConfig.java @@ -1,6 +1,7 @@ package us.dot.its.jpo.ode.messagesender.scriptrunner; import org.springframework.boot.task.TaskSchedulerBuilder; +import org.springframework.boot.task.ThreadPoolTaskSchedulerBuilder; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; @@ -12,7 +13,7 @@ public class ScriptRunnerConfig { @Bean(destroyMethod = "shutdown") public ThreadPoolTaskScheduler threadPoolTaskScheduler() { - var builder = new TaskSchedulerBuilder(); + var builder = new ThreadPoolTaskSchedulerBuilder(); return builder .poolSize(3) .threadNamePrefix("ScriptRunner-") diff --git a/test-message-sender/script-runner/src/main/java/us/dot/its/jpo/ode/messagesender/scriptrunner/ScriptTemplate.java b/test-message-sender/script-runner/src/main/java/us/dot/its/jpo/ode/messagesender/scriptrunner/ScriptTemplate.java new file mode 100644 index 00000000..c1753725 --- /dev/null +++ b/test-message-sender/script-runner/src/main/java/us/dot/its/jpo/ode/messagesender/scriptrunner/ScriptTemplate.java @@ -0,0 +1,83 @@ +package us.dot.its.jpo.ode.messagesender.scriptrunner; + +import java.text.DecimalFormat; +import java.time.Duration; +import java.time.Instant; +import java.time.ZoneOffset; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Methods for filling in templated scripts + */ +public class ScriptTemplate { + + public static final String ISO_DATE_TIME = "@ISO_DATE_TIME@"; + public static final Pattern ISO_DATE_TIME_OFFSET_MILLIS = Pattern.compile("@ISO_DATE_TIME_OFFSET_MILLIS_(?-?[0-9]+)@"); + public static final String MINUTE_OF_YEAR = "\"@MINUTE_OF_YEAR@\""; + public static final String MILLI_OF_MINUTE = "\"@MILLI_OF_MINUTE@\""; + public static final String EPOCH_SECONDS = "\"@EPOCH_SECONDS@\""; + public static final Pattern OFFSET_SECONDS = Pattern.compile("@OFFSET_SECONDS_(?-?[0-9.]+)@"); + public static final String TEMP_ID = "@TEMP_ID@"; + + + + public static String fillTemplate(final Instant sendInstant, final String message, final String tempId) { + final ZonedDateTime zdt = sendInstant.atZone(ZoneOffset.UTC); + final String isoDateTime = zdt.format(DateTimeFormatter.ISO_DATE_TIME); + + final ZonedDateTime zdtYear = ZonedDateTime.of(zdt.getYear(), 1, 1, 0, 0, 0, 0, ZoneOffset.UTC); + final Duration moyDuration = Duration.between(zdtYear, zdt); + final long minuteOfYear = moyDuration.toMinutes(); + + final ZonedDateTime zdtMinute = ZonedDateTime.of(zdt.getYear(), zdt.getMonthValue(), + zdt.getDayOfMonth(), zdt.getHour(), zdt.getMinute(), 0, 0, ZoneOffset.UTC); + final Duration minDuration = Duration.between(zdtMinute, zdt); + final long milliOfMinute = minDuration.toMillis(); + + final double epochSecond = sendInstant.toEpochMilli() / 1000.0d; + + // Fill in offset seconds in timing + // Fill in ISO Date/time offset by milliseconds + String offsetsReplaced = + replaceIsoOffsetMillis(sendInstant, + replaceOffsetSeconds(epochSecond, message)); + + return offsetsReplaced + .replace(ISO_DATE_TIME, isoDateTime) + .replace(MINUTE_OF_YEAR, Long.toString(minuteOfYear)) + .replace(MILLI_OF_MINUTE, Long.toString(milliOfMinute)) + .replace(EPOCH_SECONDS, String.format("%.3f", epochSecond)) + .replace(TEMP_ID, tempId); + + + } + + public static String replaceOffsetSeconds(final double epochSecond, final String message) { + final Matcher matcher = OFFSET_SECONDS.matcher(message); + return matcher.replaceAll((matchResult) -> { + String offsetStr = matcher.group("offset"); + double offsetSeconds = Double.parseDouble(offsetStr); + double timingSeconds = epochSecond + offsetSeconds; + long timingMillis = Math.round(1000 * timingSeconds); + Instant timingInstant = Instant.ofEpochMilli(timingMillis); + ZonedDateTime zdtTiming = timingInstant.atZone(ZoneOffset.UTC); + return zdtTiming.format(DateTimeFormatter.ISO_DATE_TIME); + }); + } + + public static String replaceIsoOffsetMillis(final Instant sendInstant, final String message) { + final Matcher matcher = ISO_DATE_TIME_OFFSET_MILLIS.matcher(message); + return matcher.replaceAll((matchResult) -> { + final String offsetStr = matcher.group("offset"); + final long offsetMillis = Long.parseLong(offsetStr); + final long sendInstantMillis = sendInstant.toEpochMilli(); + final long isoOffsetMillis = sendInstantMillis + offsetMillis; + final Instant offsetInstant = Instant.ofEpochMilli(isoOffsetMillis); + final ZonedDateTime zdtOffset = offsetInstant.atZone(ZoneOffset.UTC); + return zdtOffset.format(DateTimeFormatter.ISO_DATE_TIME); + }); + } +} diff --git a/test-message-sender/script-runner/src/test/java/us/dot/its/jpo/ode/messagesender/scriptrunner/ScriptTemplateTest.java b/test-message-sender/script-runner/src/test/java/us/dot/its/jpo/ode/messagesender/scriptrunner/ScriptTemplateTest.java new file mode 100644 index 00000000..cf9ff33c --- /dev/null +++ b/test-message-sender/script-runner/src/test/java/us/dot/its/jpo/ode/messagesender/scriptrunner/ScriptTemplateTest.java @@ -0,0 +1,89 @@ +package us.dot.its.jpo.ode.messagesender.scriptrunner; + +import org.junit.Test; + +import java.time.Instant; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; + + +public class ScriptTemplateTest { + + @Test + public void testFillTemplate() { + final Instant sendInstant = Instant.ofEpochMilli(1721876849123L); + final String tempId = "abababab"; + final String message = """ + "isoDateTime": "@ISO_DATE_TIME@" + "minuteOfYear": "@MINUTE_OF_YEAR@" + "milliOfMinute": "@MILLI_OF_MINUTE@" + "epochSeconds": "@EPOCH_SECONDS@" + "tempId": "@TEMP_ID@" + """; + final String expectStr = """ + "isoDateTime": "2024-07-25T03:07:29.123Z" + "minuteOfYear": 296827 + "milliOfMinute": 29123 + "epochSeconds": 1721876849.123 + "tempId": "abababab" + """; + String actualStr = ScriptTemplate.fillTemplate(sendInstant, message, tempId); + assertThat(actualStr, equalTo(expectStr)); + } + + @Test + public void testReplaceIsoOffsetMillis() { + final Instant sendInstant = Instant.ofEpochMilli(1721876849000L); + final String message = """ + "timeStamp": "@ISO_DATE_TIME_OFFSET_MILLIS_1575@" + """; + final String expectStr = """ + "timeStamp": "2024-07-25T03:07:30.575Z" + """; + + String actualStr = ScriptTemplate.replaceIsoOffsetMillis(sendInstant, message); + assertThat(actualStr, equalTo(expectStr)); + } + + @Test + public void testReplaceIsoOffsetMillis_Negative() { + final Instant sendInstant = Instant.ofEpochMilli(1721876849000L); + final String message = """ + "timeStamp": "@ISO_DATE_TIME_OFFSET_MILLIS_-2575@" + """; + final String expectStr = """ + "timeStamp": "2024-07-25T03:07:26.425Z" + """; + + String actualStr = ScriptTemplate.replaceIsoOffsetMillis(sendInstant, message); + assertThat(actualStr, equalTo(expectStr)); + } + + @Test + public void testReplaceOffsetSeconds() { + final double epochSecond = 1721876849; + final String message = """ + "maxEndTime": "@OFFSET_SECONDS_21.555@" + """; + final String expectStr = """ + "maxEndTime": "2024-07-25T03:07:50.555Z" + """; + String actualStr = ScriptTemplate.replaceOffsetSeconds(epochSecond, message); + assertThat(actualStr, equalTo(expectStr)); + } + + @Test + public void testReplaceOffsetSeconds_Negative() { + final double epochSecond = 1721876849; + final String message = """ + "maxEndTime": "@OFFSET_SECONDS_-21.555@" + """; + final String expectStr = """ + "maxEndTime": "2024-07-25T03:07:07.445Z" + """; + String actualStr = ScriptTemplate.replaceOffsetSeconds(epochSecond, message); + assertThat(actualStr, equalTo(expectStr)); + } + +}