diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile new file mode 100644 index 0000000..bad1a85 --- /dev/null +++ b/.devcontainer/Dockerfile @@ -0,0 +1,69 @@ +#------------------------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information. +#------------------------------------------------------------------------------------------------------------- + +FROM eclipse-temurin:21-jdk + +# This Dockerfile adds a non-root user with sudo access. Use the "remoteUser" +# property in devcontainer.json to use it. On Linux, the container user's GID/UIDs +# will be updated to match your local UID/GID (when using the dockerFile property). +# See https://aka.ms/vscode-remote/containers/non-root-user for details. +ARG USERNAME=vscode +ARG USER_UID=1234 +ARG USER_GID=$USER_UID + +# Configure apt +ENV DEBIAN_FRONTEND=noninteractive +RUN apt-get update +RUN apt-get upgrade -y +RUN apt-get -y install --no-install-recommends apt-utils dialog 2>&1 + +# Create a non-root user to use if preferred - see https://aka.ms/vscode-remote/containers/non-root-user. +RUN groupadd --gid $USER_GID $USERNAME +RUN useradd -s /bin/bash --uid $USER_UID --gid $USER_GID -m $USERNAME +# [Optional] Add sudo support for the non-root user +RUN apt-get install -y sudo +RUN echo $USERNAME ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME +RUN chmod 0440 /etc/sudoers.d/$USERNAME + +# Verify git, needed tools installed +RUN apt-get -y install git openssh-client less iproute2 procps curl lsb-release zip unzip sed kafkacat telnet + +#-------------------Install SDKMan---------------------------------- +RUN curl -s https://get.sdkman.io | bash +RUN chmod a+x "$HOME/.sdkman/bin/sdkman-init.sh" +#------------------------------------------------------------------------------------------------------------- + +#-------------------Install Maven CLI Tools---------------------------------- +ARG MAVEN_VERSION=3.6.3 +RUN /bin/bash -c "source $HOME/.sdkman/bin/sdkman-init.sh && sdk install maven ${MAVEN_VERSION}" +#------------------------------------------------------------------------------------------------------------- + +# Install snmp (rsu-data-controller dependency) +RUN apt-get -y install snmp + +#-------------------Install Kafka---------------------------------- +RUN mkdir ~/Downloads +RUN curl "https://archive.apache.org/dist/kafka/3.6.1/kafka_2.12-3.6.1.tgz" -o ~/Downloads/kafka.tgz +RUN mkdir ~/kafka \ + && cd ~/kafka \ + && tar -xvzf ~/Downloads/kafka.tgz --strip 1 +RUN echo "\nadvertised.listeners=PLAINTEXT://localhost:9092" >> ~/kafka/config/server.properties +#------------------------------------------------------------------------------------------------------------- + +# Clean up +RUN apt-get autoremove -y \ + && apt-get clean -y \ + && rm -rf /var/lib/apt/lists/* +ENV DEBIAN_FRONTEND=dialog + +# Allow for a consistant java home location for settings - image is changing over time +RUN if [ ! -d "/docker-java-home" ]; then ln -s "${JAVA_HOME}" /docker-java-home; fi + +COPY kafka /etc/init.d/kafka +RUN chmod 775 /etc/init.d/kafka && update-rc.d kafka defaults + +COPY ./docker-entrypoint.sh ./docker-entrypoint.sh +RUN chmod +x ./docker-entrypoint.sh +ENTRYPOINT ["./docker-entrypoint.sh"] diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000..d808b0e --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,38 @@ +// For format details, see https://aka.ms/devcontainer.json. For config options, see the README at: +// https://github.com/microsoft/vscode-dev-containers/tree/v0.154.0/containers/java-8 +{ + "name": "JPO Deduplicator Java 21", + "dockerFile": "Dockerfile", + "overrideCommand": false, + "shutdownAction": "stopContainer", + "customizations": { + "vscode": { + "settings": { + "terminal.integrated.shell.linux": "/bin/bash" + }, + "extensions": [ + "vscjava.vscode-java-pack", + "vscjava.vscode-java-debug", + "vscjava.vscode-maven", + "vscjava.vscode-java-dependency", + "vscjava.vscode-java-test", + "hbenl.vscode-test-explorer", + "ms-vscode.test-adapter-converter", + "esbenp.prettier-vscode", + "mhutchie.git-graph", + "tabnine.tabnine-vscode", + "redhat.java", + "redhat.vscode-commons" + ] + } + }, + // Use 'forwardPorts' to make a list of ports inside the container available locally. + // "forwardPorts": [8080, 9090, 46753, 46800, 5555, 6666, 8090, 2181, 9092], + // Use 'postCreateCommand' to run commands after the container is created. + "postCreateCommand": "bash .devcontainer/post-create.sh", + // Comment out connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root. + // "remoteUser": "vscode" + "runArgs": [ + "--network=host" + ] +} \ No newline at end of file diff --git a/.devcontainer/docker-entrypoint.sh b/.devcontainer/docker-entrypoint.sh new file mode 100644 index 0000000..a294d8b --- /dev/null +++ b/.devcontainer/docker-entrypoint.sh @@ -0,0 +1,22 @@ +#!/usr/bin/env bash + +trap stop SIGTERM SIGINT SIGQUIT SIGHUP ERR + +start() { + echo "Container started, starting kafka..." >>/root/startup.txt + sudo service kafka start +} + +stop() { + echo "Container stopped, performing cleanup..." >>/root/shutdown.txt + sudo service kafka stop + sleep 2 + exit 0 +} + +start + +while + sleep 1 & + wait $! +do :; done diff --git a/.devcontainer/jpo-deduplicator.code-workspace b/.devcontainer/jpo-deduplicator.code-workspace new file mode 100644 index 0000000..998bc22 --- /dev/null +++ b/.devcontainer/jpo-deduplicator.code-workspace @@ -0,0 +1,11 @@ +{ + "folders": [ + { + "path": "." + } + ], + "settings": { + "java.configuration.updateBuildConfiguration": "automatic", + "java.server.launchMode": "Standard" + } +} \ No newline at end of file diff --git a/.devcontainer/kafka b/.devcontainer/kafka new file mode 100644 index 0000000..be2be98 --- /dev/null +++ b/.devcontainer/kafka @@ -0,0 +1,36 @@ +DAEMON_PATH=/root/kafka +PATH=$PATH:$DAEMON_PATH/bin +PATH=$PATH:/root/.sdkman/candidates/java/current/bin + +export LOG_DIR=/var/log/kafka + +# See how we were called. +case "$1" in + start) + # Start daemon. + echo "Starting Kafka"; + $DAEMON_PATH/bin/kafka-server-start.sh -daemon $DAEMON_PATH/config/server.properties + ;; + stop) + # Stop daemons. + echo "Shutting down Kafka"; + $DAEMON_PATH/bin/kafka-server-stop.sh + ;; + restart) + $0 stop + sleep 2 + $0 start + ;; + status) + pid=`ps ax | grep -i 'kafka.Kafka' | grep -v grep | awk '{print $1}'` + if [ -n "$pid" ] + then + echo "Kafka is Running as PID: $pid" + else + echo "Kafka is not Running" + fi + ;; + *) + echo "Usage: $0 {start|stop|restart|status}" + exit 1 +esac \ No newline at end of file diff --git a/.devcontainer/post-create.sh b/.devcontainer/post-create.sh new file mode 100644 index 0000000..b54a6a5 --- /dev/null +++ b/.devcontainer/post-create.sh @@ -0,0 +1,30 @@ +cd ~/kafka/ +KAFKA_CLUSTER_ID="$(bin/kafka-storage.sh random-uuid)" + +bin/kafka-storage.sh format -t $KAFKA_CLUSTER_ID -c config/kraft/server.properties + +# start kafka +bin/kafka-server-start.sh -daemon config/kraft/server.properties +# wait 2 seconds for the server to start and be able to add partitions +sleep 2s +# add topics + +# MAP +bin/kafka-topics.sh --create --topic "topic.OdeMapJson" --bootstrap-server localhost:9092 --replication-factor 1 --partitions 1 +bin/kafka-topics.sh --create --topic "topic.DeduplicatedOdeMapJson" --bootstrap-server localhost:9092 --replication-factor 1 --partitions 1 +bin/kafka-topics.sh --create --topic "topic.ProcessedMap" --bootstrap-server localhost:9092 --replication-factor 1 --partitions 1 +bin/kafka-topics.sh --create --topic "topic.DeduplicatedProcessedMap" --bootstrap-server localhost:9092 --replication-factor 1 --partitions 1 + +# SPaT +bin/kafka-topics.sh --create --topic "topic.OdeSpatJson" --bootstrap-server localhost:9092 --replication-factor 1 --partitions 1 +bin/kafka-topics.sh --create --topic "topic.DeduplicatedOdeSpatJson" --bootstrap-server localhost:9092 --replication-factor 1 --partitions 1 +bin/kafka-topics.sh --create --topic "topic.ProcessedSpat" --bootstrap-server localhost:9092 --replication-factor 1 --partitions 1 +bin/kafka-topics.sh --create --topic "topic.DeduplicatedProcessedSpat" --bootstrap-server localhost:9092 --replication-factor 1 --partitions 1 + +# BSM +bin/kafka-topics.sh --create --topic "topic.OdeBsmJson" --bootstrap-server localhost:9092 --replication-factor 1 --partitions 1 +bin/kafka-topics.sh --create --topic "topic.DeduplicatedOdeBsmJson" --bootstrap-server localhost:9092 --replication-factor 1 --partitions 1 + +# TIM +bin/kafka-topics.sh --create --topic "topic.OdeTimJson" --bootstrap-server localhost:9092 --replication-factor 1 --partitions 1 +bin/kafka-topics.sh --create --topic "topic.DeduplicatedOdeTimJson" --bootstrap-server localhost:9092 --replication-factor 1 --partitions 1 diff --git a/.github/workflows/artifact-publish.yml b/.github/workflows/artifact-publish.yml new file mode 100644 index 0000000..8ef378f --- /dev/null +++ b/.github/workflows/artifact-publish.yml @@ -0,0 +1,48 @@ +name: Publish Java Package + +on: + push: + branches: + - "develop" + - "master" + - "release/*" + + +jobs: + deduplicator-publish: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up JDK 21a + uses: actions/setup-java@v4 + with: + java-version: '21' + distribution: 'temurin' + + - name: Remove snapshot from version + run: | + cd jpo-deduplicator + mvn versions:set -DremoveSnapshot + + - name: Build with Maven + env: + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + MAVEN_GITHUB_TOKEN_NAME: ${{ vars.MAVEN_GITHUB_TOKEN_NAME }} + MAVEN_GITHUB_TOKEN: ${{ secrets.MAVEN_GITHUB_TOKEN }} + MAVEN_GITHUB_ORG: ${{ github.repository_owner }} + run: | + cd jpo-deduplicator + mvn -s settings.xml -B package --file pom.xml -DskipTests -Ppackage-jar + + - name: Publish to GitHub Packages + run: | + cd jpo-deduplicator + mvn -s settings.xml --batch-mode -Dgithub_organization=${{ github.repository_owner }} deploy -DskipTests -Ppackage-jar + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + MAVEN_GITHUB_TOKEN_NAME: ${{ vars.MAVEN_GITHUB_TOKEN_NAME }} + MAVEN_GITHUB_TOKEN: ${{ secrets.MAVEN_GITHUB_TOKEN }} + MAVEN_GITHUB_ORG: ${{ github.repository_owner }} \ No newline at end of file diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..51b81c7 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,30 @@ +name: CI + +on: + pull_request: + paths: + - 'jpo-deduplicator/**' + + + +jobs: + deduplicator-test: + runs-on: ubuntu-latest + steps: + - name: Checkout Repository + uses: actions/checkout@v4 + + - name: Set up JDK + uses: actions/setup-java@v4 + with: + java-version: "21" + distribution: "temurin" + cache: 'maven' + + - name: Run tests + env: + MAVEN_GITHUB_TOKEN: ${{ secrets.MAVEN_GITHUB_TOKEN }} + MAVEN_GITHUB_ORG: ${{ github.repository_owner }} + run: | + cd $GITHUB_WORKSPACE/jpo-deduplicator + mvn verify -s ./settings.xml \ No newline at end of file diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml new file mode 100644 index 0000000..d4808d5 --- /dev/null +++ b/.github/workflows/docker.yml @@ -0,0 +1,26 @@ +name: Docker build + +on: + pull_request: + types: [opened, synchronize, reopened] + +jobs: + jpo-deduplicator: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + - name: Build + uses: docker/build-push-action@v3 + with: + context: . + build-args: | + MAVEN_GITHUB_TOKEN_NAME=${{ vars.MAVEN_GITHUB_TOKEN_NAME }} + MAVEN_GITHUB_TOKEN=${{ secrets.MAVEN_GITHUB_TOKEN }} + MAVEN_GITHUB_ORG=${{ github.repository_owner }} + secrets: | + MAVEN_GITHUB_TOKEN: ${{ secrets.MAVEN_GITHUB_TOKEN }} + cache-from: type=gha + cache-to: type=gha,mode=max \ No newline at end of file diff --git a/.github/workflows/dockerhub.yml b/.github/workflows/dockerhub.yml new file mode 100644 index 0000000..ea71cb3 --- /dev/null +++ b/.github/workflows/dockerhub.yml @@ -0,0 +1,41 @@ +name: "DockerHub Build and Push" + +on: + push: + branches: + - "develop" + - "master" + - "release/*" + +jobs: + dockerhub-jpo-deduplicator: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + - name: Login to DockerHub + uses: docker/login-action@v2 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Replcae Docker tag + id: set_tag + run: echo "TAG=$(echo ${GITHUB_REF##*/} | sed 's/\//-/g')" >> $GITHUB_ENV + + - name: Build + uses: docker/build-push-action@v3 + with: + context: . + push: true + tags: usdotjpoode/jpo-deduplicator:${{ env.TAG }} + build-args: | + MAVEN_GITHUB_TOKEN_NAME=${{ vars.MAVEN_GITHUB_TOKEN_NAME }} + MAVEN_GITHUB_TOKEN=${{ secrets.MAVEN_GITHUB_TOKEN }} + MAVEN_GITHUB_ORG=${{ github.repository_owner }} + secrets: | + MAVEN_GITHUB_TOKEN: ${{ secrets.MAVEN_GITHUB_TOKEN }} + cache-from: type=gha + cache-to: type=gha,mode=max \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8d161e5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +**/.env + +**/target \ No newline at end of file diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..532f96c --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "jpo-utils"] + path = jpo-utils + url = https://github.com/usdot-jpo-ode/jpo-utils.git diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..53f13e6 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,8 @@ +{ + "recommendations": [ + "redhat.vscode-xml", + "vscjava.vscode-java-pack", + "redhat.java", + "vmware.vscode-boot-dev-pack" + ] +} \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..49e558c --- /dev/null +++ b/Dockerfile @@ -0,0 +1,56 @@ +FROM maven:3.8-eclipse-temurin-21-alpine AS builder + +WORKDIR /home + +ARG MAVEN_GITHUB_TOKEN +ARG MAVEN_GITHUB_ORG + +ENV MAVEN_GITHUB_TOKEN=$MAVEN_GITHUB_TOKEN +ENV MAVEN_GITHUB_ORG=$MAVEN_GITHUB_ORG + +RUN test -n "$MAVEN_GITHUB_TOKEN" || (echo "Error: MAVEN_GITHUB_TOKEN cannot be empty" && exit 1) +RUN test -n "$MAVEN_GITHUB_ORG" || (echo "Error: MAVEN_GITHUB_ORG cannot be empty" && exit 1) + +# Copy and Build Deduplicator +WORKDIR /home +COPY ./jpo-deduplicator/pom.xml ./jpo-deduplicator/ +COPY ./jpo-deduplicator/settings.xml ./jpo-deduplicator/ + +WORKDIR /home/jpo-deduplicator +RUN mvn -s settings.xml dependency:resolve + +COPY ./jpo-deduplicator/src ./src +RUN mvn -s settings.xml install -DskipTests + +FROM amazoncorretto:21 + +WORKDIR /home + +COPY --from=builder /home/jpo-deduplicator/src/main/resources/application.yaml /home +COPY --from=builder /home/jpo-deduplicator/src/main/resources/logback.xml /home +COPY --from=builder /home/jpo-deduplicator/target/jpo-deduplicator.jar /home + +#COPY cert.crt /home/cert.crt +#RUN keytool -import -trustcacerts -keystore /usr/local/openjdk-11/lib/security/cacerts -storepass changeit -noprompt -alias mycert -file cert.crt + +RUN amazon-linux-extras install -y epel && \ + yum install -y jemalloc-devel +ENV LD_PRELOAD="/usr/lib64/libjemalloc.so" + +ENTRYPOINT ["java", \ + "-Djava.rmi.server.hostname=$DOCKER_HOST_IP", \ + "-Dlogback.configurationFile=/home/logback.xml", \ + "-Xmx1024M", \ + "-Xms128M", \ + "-XX:+UseG1GC", \ + "-XX:MaxGCPauseMillis=20", \ + "-XX:InitiatingHeapOccupancyPercent=35", \ + "-XX:MetaspaceSize=96m", \ + "-XX:MinMetaspaceFreeRatio=50", \ + "-XX:MaxMetaspaceFreeRatio=80", \ + "-XX:+ExplicitGCInvokesConcurrent", \ + "-XX:InitialRAMPercentage=5.0", \ + "-jar", \ + "/home/jpo-deduplicator.jar"] + +# ENTRYPOINT ["tail", "-f", "/dev/null"] diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..d080e5c --- /dev/null +++ b/Makefile @@ -0,0 +1,48 @@ +default: + $(info Make target options:) + $(info `make start` to run the deduplicator) + $(info `make build` to build the deduplicator) + $(info `make stop` to stop the deduplicator) + $(info `make delete` to stop the deduplicator and remove the volumes) + $(info `make restart` to stop and then start the deduplicator) + $(info `make rebuild` to stop, delete, and then rebuild the containers) + $(info `make clean-build` to rebuild the containers without using the cache) + +.PHONY: start +start: +ifeq ("$(wildcard .env)", "") + $(error "ERROR: deduplicator Environment file `.env` not found in ${PWD}") +endif +ifeq ("$(wildcard ./jpo-utils/.env)", "") + $(error "ERROR: jpo-utils Environment file `.env` not found in ${PWD}") +endif + docker compose up -d + +build: +ifeq ("$(wildcard .env)", "") + $(error "ERROR: jpo-ode Environment file `.env` not found in ${PWD}") +endif +ifeq ("$(wildcard ./jpo-utils/.env)", "") + $(error "ERROR: jpo-utils Environment file `.env` not found in ${PWD}") +endif + docker compose build + +.PHONY: stop +stop: + docker compose down + +.PHONY: delete +delete: + docker compose down -v + +.PHONY: restart +restart: + $(MAKE) stop start + +.PHONY: rebuild +rebuild: + $(MAKE) stop delete build start + +.PHONY: clean-build +clean-build: + docker compose build --no-cache \ No newline at end of file diff --git a/README.md b/README.md index a231a3d..983dec0 100644 --- a/README.md +++ b/README.md @@ -1 +1,170 @@ -# jpo-deduplicator \ No newline at end of file + +# jpo-deduplicator + +**US Department of Transportation (USDOT) Intelligent Transportation Systems (ITS) Joint Program Office (JPO) Message Deduplicator** + +The JPO-Deduplicator is a Kafka Java spring-boot application designed to reduce the number of messages stored and processed in the ODE system. This is done by reading in messages from an input topic (such as topic.ProcessedMap) and outputting a subset of those messages on a related output topic (topic.DeduplicatedProcessedMap). Functionally, this is done by removing deduplicate messages from the input topic and only passing on unique messages. In addition, each topic will pass on at least 1 message per hour even if the message is a duplicate. This behavior helps ensure messages are still flowing through the system. + +The following topics currently support deduplication. + +- topic.ProcessedMap -> topic.DeduplicatedProcessedMap +- topic.ProcessedMapWKT -> topic.DeduplicatedProcessedMapWKT +- topic.OdeMapJson -> topic.DeduplicatedOdeMapJson +- topic.OdeTimJson -> topic.DeduplicatedOdeTimJson +- topic.OdeRawEncodedTIMJson -> topic.DeduplicatedOdeRawEncodedTIMJson +- topic.OdeBsmJson -> topic.DeduplicatedOdeBsmJson +- topic.ProcessedSpat -> topic.DeduplicatedProcessedSpat + +## Release Notes + +The current version and release history of the JPO Deduplicator: [Release Notes]() + + + +## Table of Contents + +- [jpo-deduplicator](#jpo-deduplicator) + - [Release Notes](#release-notes) + - [Table of Contents](#table-of-contents) + - [1. System Requirements](#1-system-requirements) + - [2. Usage Example](#2-usage-example) + - [3. Configuration](#3-configuration) + - [Software Prerequisites](#software-prerequisites) + - [Feature Flags](#feature-flags) + - [Generate a Github Token](#generate-a-github-token) + - [4. Development Setup](#4-development-setup) + - [Integrated Development Environment (IDE)](#integrated-development-environment-ide) + - [5. Contact Information](#5-contact-information) + - [License information](#license-information) + - [6. Contributing](#6-contributing) + + + +## 1. System Requirements + +Recommended machine specs running Docker to run the JPO-Deduplicator: + +- Minimum RAM: 16 GB + +- Minimum storage space: 100 GB +- Supported operating systems: + + - Ubuntu 20.04 Linux (Recommended) + - Windows 10/11 Professional (Professional version required for Docker virtualization) + - OSX 10 Mojave + +The JPO-Deduplicator software can run on most standard Window, Mac, or Linux based computers with +Pentium core processors. Performance of the software will be based on the computing power and available RAM in +the system. Larger data flows can require much larger space requirements depending on the amount of data being processed by the software. The JPO-Deduplicator software application was developed using the open source programming language Java. If running the JPO-Deduplicator outside of Docker, the application requires the Java 21 runtime environment. + +[Back to top](#table-of-contents) + + + +## 2. Usage Example + +1. Create a copy of `sample.env` and rename it to `.env`. +2. Create a copy of the `jpo-utils/sample.env` file and rename it to `.env` in the `jpo-utils` directory. +3. Update the variable `MAVEN_GITHUB_TOKEN` in the root `.env` file to a github token used for downloading jar file dependencies. For full instructions on how to generate a token please see [here](https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-apache-maven-registry#authenticating-to-github-packages). +4. Navigate back to the root directory and run the following command: `make build` + 1. Make sure that you have [docker-compose](https://docs.docker.com/compose/install/) and [make](https://www.gnu.org/software/make/manual/make.html) installed. +5. Run the following command: `make start` +6. Produce a sample message to one of the sink topics by using `kafka_ui` by: + 1. Go to `localhost:8001` + 2. Click local -> Topics + 3. Select `topic.OdeMapJson` + 4. Select `Produce Message` + 5. Copy in sample JSON for a Map Message + 6. Click `Produce Message` multiple times +7. View the synced message in `kafka_ui` by: + 1. Go to `localhost:8001` + 2. Click local -> Topics + 3. Select `topic.DeduplicatedOdeMapJson` + 4. You should now see only one copy of the map message sent. + +[Back to top](#table-of-contents) + + + +## 3. Configuration + +### Software Prerequisites + +The JPO-Deduplicator is a micro service that runs as an independent application but serves the sole purpose of deduplicating JSON objects created by the JPO-ODE via Apache Kafka. To support these JSON objects, the JPO-Deduplicator application utilizes some classes from the JPO-ODE, JPO-GeojsonConverter, and the JPO-ConflictMonitor. These classes are referenced in the JPO-Deduplicator by pulling the built `.jar` artifact from GitHub Maven Central. All other required dependencies will automatically be downloaded and installed as part of the Docker build process. + +- Docker: +- Docker-Compose: + +### Feature Flags + +To manually configure deduplication for a topic, the following environment variables can also be used. + +| Environment Variable | Description | +|---|---| +| `ENABLE_PROCESSED_MAP_DEDUPLICATION` | `true` / `false` - Enable ProcessedMap message Deduplication | +| `ENABLE_PROCESSED_MAP_WKT_DEDUPLICATION` | `true` / `false` - Enable ProcessedMap WKT message Deduplication | +| `ENABLE_ODE_MAP_DEDUPLICATION` | `true` / `false` - Enable ODE MAP message Deduplication | +| `ENABLE_ODE_TIM_DEDUPLICATION` | `true` / `false` - Enable ODE TIM message Deduplication | +| `ENABLE_ODE_RAW_ENCODED_TIM_DEDUPLICATION` | `true` / `false` - Enable ODE Raw Encoded TIM Deduplication | +| `ENABLE_PROCESSED_SPAT_DEDUPLICATION` | `true` / `false` - Enable ProcessedSpat Deduplication | +| `ENABLE_ODE_BSM_DEDUPLICATION` | `true` / `false` - Enable ODE BSM Deduplication | + +### Generate a Github Token + +A GitHub token is required to pull artifacts from GitHub repositories. This is required to obtain the jpo-deduplicator jars and must be done before attempting to build this repository. + +1. Log into GitHub. +2. Navigate to Settings -> Developer settings -> Personal access tokens. +3. Click "New personal access token (classic)". + 1. As of now, GitHub does not support `Fine-grained tokens` for obtaining packages. +4. Provide a name and expiration for the token. +5. Select the `read:packages` scope. +6. Click "Generate token" and copy the token. +7. Copy the token name and token value into your `.env` file. + +For local development the following steps are also required +8. Create a copy of [settings.xml](jpo-deduplicator/jpo-deduplicator/settings.xml) and save it to `~/.m2/settings.xml` +9. Update the variables in your `~/.m2/settings.xml` with the token value and target jpo-ode organization. + +[Back to top](#table-of-contents) + + + +## 4. Development Setup + +### Integrated Development Environment (IDE) + +Install the IDE of your choice: + +- Eclipse: [https://eclipse.org/](https://eclipse.org/) +- STS: [https://spring.io/tools/sts/all](https://spring.io/tools/sts/all) +- IntelliJ: [https://www.jetbrains.com/idea/](https://www.jetbrains.com/idea/) +- VS Code: [https://code.visualstudio.com/](https://code.visualstudio.com/) + +[Back to top](#table-of-contents) + + + +## 5. Contact Information + +Contact the developers of the JPO-Deduplicator application by submitting a [Github issue](https://github.com/usdot-jpo-ode/jpo-deduplicator/issues). + +### License information + +Licensed under the Apache License, Version 2.0 (the "License"); you may not use this +file except in compliance with the License. + +You may obtain a copy of the License at +Unless required by applicable law or agreed to in writing, software distributed under +the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either expressed or implied. See the License for the specific language governing +permissions and limitations under the [License](http://www.apache.org/licenses/LICENSE-2.0). + +[Back to top](#table-of-contents) + + + +## 6. Contributing + +Please read the ODE [contributing guide](https://github.com/usdot-jpo-ode/jpo-ode/blob/develop/docs/contributing_guide.md) to learn about our development process, how to propose pull requests and improvements, and how to build and test your changes to this project. + +[Back to top](#table-of-contents) \ No newline at end of file diff --git a/docker-compose-ode.yml b/docker-compose-ode.yml new file mode 100644 index 0000000..bebfbca --- /dev/null +++ b/docker-compose-ode.yml @@ -0,0 +1,147 @@ +include: + - jpo-utils/docker-compose.yml + +services: + geojsonconverter: + profiles: + - all + - deduplicator_full + - geojsonconverter + image: usdotjpoode/geojsonconverter:2025-q1 + restart: ${RESTART_POLICY} + deploy: + resources: + limits: + cpus: '1' + memory: 2G + environment: + DOCKER_HOST_IP: ${DOCKER_HOST_IP:?error} + KAFKA_TYPE: ${KAFKA_TYPE} + CONFLUENT_KEY: ${CONFLUENT_KEY} + CONFLUENT_SECRET: ${CONFLUENT_SECRET} + geometry.output.mode: ${GEOMETRY_OUTPUT_MODE:-GEOJSON_ONLY} + spring.kafka.bootstrap-servers: ${DOCKER_HOST_IP:?error}:9092 + logging: + options: + max-size: "10m" + max-file: "5" + depends_on: + kafka: + condition: service_healthy + required: false + # ODE Services: + ode: + profiles: + - all + - deduplicator_full + - ode + image: usdotjpoode/jpo-ode:2025-q1 + restart: ${RESTART_POLICY} + deploy: + resources: + limits: + cpus: '2' + memory: 4G + ports: + - "8080:8080" + - "9090:9090" + - "46753:46753/udp" + - "46800:46800/udp" + - "47900:47900/udp" + - "44900:44900/udp" + - "44910:44910/udp" + - "44920:44920/udp" + - "44930:44930/udp" + - "44940:44940/udp" + - "44990:44990/udp" + - "5555:5555/udp" + - "6666:6666/udp" + environment: + DOCKER_HOST_IP: ${DOCKER_HOST_IP:?error} + KAFKA_TYPE: ${KAFKA_TYPE} + CONFLUENT_KEY: ${CONFLUENT_KEY} + CONFLUENT_SECRET: ${CONFLUENT_SECRET} + ODE_TIM_INGEST_MONITORING_ENABLED: true + ODE_TIM_INGEST_MONITORING_INTERVAL: 60 + DATA_SIGNING_ENABLED_RSU: false + DATA_SIGNING_ENABLED_SDW: false + ODE_KAFKA_BROKERS: ${DOCKER_HOST_IP}:9092 + KAFKA_LINGER_MS: 1 + KAFKA_BATCH_SIZE: 16384 + KAFKA_RETRIES: 0 + depends_on: + kafka: + condition: service_healthy + required: false + healthcheck: + test: ["CMD", "wget" ,"--spider", "http://localhost:8080"] + interval: 5s + timeout: 30s + retries: 5 + start_period: 10s + logging: + options: + max-size: "10m" + max-file: "5" + + adm: + profiles: + - all + - deduplicator_full + - adm + image: usdotjpoode/asn1_codec:2025-q1 + restart: ${RESTART_POLICY} + deploy: + resources: + limits: + cpus: '1' + memory: 2G + environment: + DOCKER_HOST_IP: ${DOCKER_HOST_IP:?error} + KAFKA_TYPE: ${KAFKA_TYPE} + CONFLUENT_KEY: ${CONFLUENT_KEY} + CONFLUENT_SECRET: ${CONFLUENT_SECRET} + ACM_CONFIG_FILE: adm.properties + ACM_LOG_TO_CONSOLE: ${ADM_LOG_TO_CONSOLE:-false} + ACM_LOG_TO_FILE: ${ADM_LOG_TO_FILE:-true} + ACM_LOG_LEVEL: ${ADM_LOG_LEVEL:-INFO} + depends_on: + kafka: + condition: service_healthy + required: false + logging: + options: + max-size: "10m" + max-file: "5" + + conflictmonitor: + profiles: + - all + - deduplicator_full + - conflictmonitor + image: usdotjpoode/jpo-conflictmonitor:2025-q1 + restart: ${RESTART_POLICY} + ports: + - "8082:8082" + environment: + DOCKER_HOST_IP: ${DOCKER_HOST_IP:?error} + KAFKA_BOOTSTRAP_SERVERS: ${KAFKA_BOOTSTRAP_SERVERS:?error} + kafka.topics.autoCreateTopics: false + spring.kafka.bootstrap-servers: ${KAFKA_BOOTSTRAP_SERVERS:?error} + healthcheck: + test: ["CMD", "java", "-version"] + interval: 10s + timeout: 10s + retries: 20 + logging: + options: + max-size: "10m" + max-file: "5" + deploy: + resources: + limits: + memory: 3G + depends_on: + kafka: + condition: service_healthy + required: false diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..bee6284 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,56 @@ +include: + - docker-compose-ode.yml +services: + deduplicator: + profiles: + - all + - deduplicator_base + - deduplicator_full + build: + context: . + dockerfile: Dockerfile + args: + MAVEN_GITHUB_TOKEN: ${MAVEN_GITHUB_TOKEN} + MAVEN_GITHUB_ORG: ${MAVEN_GITHUB_ORG} + image: jpo-deduplicator:latest + privileged: false # Set true to allow writing to /proc/sys/vm/drop_caches + restart: ${RESTART_POLICY} + ports: + - "10091:10090" # JMX + environment: + DOCKER_HOST_IP: ${DOCKER_HOST_IP} + KAFKA_BOOTSTRAP_SERVERS: ${KAFKA_BOOTSTRAP_SERVERS} + SPRING_KAFKA_BOOTSTRAPSERVERS: ${KAFKA_BOOTSTRAP_SERVERS} + ENABLE_PROCESSED_MAP_DEDUPLICATION: ${ENABLE_PROCESSED_MAP_DEDUPLICATION} + ENABLE_PROCESSED_MAP_WKT_DEDUPLICATION: ${ENABLE_PROCESSED_MAP_WKT_DEDUPLICATION} + ENABLE_ODE_MAP_DEDUPLICATION: ${ENABLE_ODE_MAP_DEDUPLICATION} + ENABLE_ODE_TIM_DEDUPLICATION: ${ENABLE_ODE_TIM_DEDUPLICATION} + ENABLE_ODE_RAW_ENCODED_TIM_DEDUPLICATION: ${ENABLE_ODE_RAW_ENCODED_TIM_DEDUPLICATION} + ENABLE_PROCESSED_SPAT_DEDUPLICATION: ${ENABLE_PROCESSED_SPAT_DEDUPLICATION} + ENABLE_ODE_BSM_DEDUPLICATION: ${ENABLE_ODE_BSM_DEDUPLICATION} + DEDUPLICATOR_ROCKSDB_TOTAL_OFF_HEAP_MEMORY: ${DEDUPLICATOR_ROCKSDB_TOTAL_OFF_HEAP_MEMORY} + DEDUPLICATOR_ROCKSDB_INDEX_FILTER_BLOCK_RATIO: ${DEDUPLICATOR_ROCKSDB_INDEX_FILTER_BLOCK_RATIO} + DEDUPLICATOR_ROCKSDB_TOTAL_MEMTABLE_MEMORY: ${DEDUPLICATOR_ROCKSDB_TOTAL_MEMTABLE_MEMORY} + DEDUPLICATOR_ROCKSDB_BLOCK_SIZE: ${DEDUPLICATOR_ROCKSDB_BLOCK_SIZE} + DEDUPLICATOR_ROCKSDB_N_MEMTABLES: ${DEDUPLICATOR_ROCKSDB_N_MEMTABLES} + DEDUPLICATOR_ROCKSDB_MEMTABLE_SIZE: ${DEDUPLICATOR_ROCKSDB_MEMTABLE_SIZE} + KAFKA_TYPE: ${KAFKA_TYPE} + CONFLUENT_KEY: ${CONFLUENT_KEY} + CONFLUENT_SECRET: ${CONFLUENT_SECRET} + healthcheck: + test: ["CMD", "java", "-version"] + interval: 10s + timeout: 10s + retries: 20 + logging: + options: + max-size: "10m" + max-file: "5" + deploy: + resources: + limits: + memory: 1G + depends_on: + kafka: + condition: service_healthy + required: false \ No newline at end of file diff --git a/docs/Release_notes.md b/docs/Release_notes.md new file mode 100644 index 0000000..34fb1a5 --- /dev/null +++ b/docs/Release_notes.md @@ -0,0 +1,17 @@ +JPO-Deduplicator Release Notes +Version 2.0.0 +Summary +The first release of the jpo-deduplicator package. This package focuses on removing duplicate messages from Kafka topics. This in turns saves deployers costs associated with data transfer and storage within the ODE ecosystem. This initial release included deduplication for the following messages types + - ProcessedMap + - ProcessedMapWKT + - ProcessedSpat + - OdeMapJson + - OdeBSMJson + - OdeTIMJson + - OdeRawEncodedTIm + +This release also makes additional changes to the submodule components as follows + +Refactored docker-compose files to use compose profiles for modular component approach +Updated jpo-deduplicator for compatibility with jpo-ode version 4.0.0 +Updated jpo-deduplicator to use zstd compression for output messages \ No newline at end of file diff --git a/jpo-deduplicator/LICENSE-2.0.html b/jpo-deduplicator/LICENSE-2.0.html new file mode 100644 index 0000000..d1055c8 --- /dev/null +++ b/jpo-deduplicator/LICENSE-2.0.html @@ -0,0 +1,228 @@ + + + + + + Apache License, Version 2.0 + + +
+ +

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

+

TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND + DISTRIBUTION

+

1. + Definitions.

+

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

+

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

+

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

+

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

+

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

+

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

+

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

+

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

+

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

+

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

+

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

+

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

+

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

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

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

+

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

+

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

+

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

+

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

+

END OF TERMS AND CONDITIONS

+

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

+

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

+
+
Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+    
+
+
+ + + diff --git a/jpo-deduplicator/pom.xml b/jpo-deduplicator/pom.xml new file mode 100644 index 0000000..47ff3df --- /dev/null +++ b/jpo-deduplicator/pom.xml @@ -0,0 +1,336 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 3.1.3 + + + usdot.jpo.ode + jpo-deduplicator + 2.0.0 + jar + jpo-deduplicator + http://maven.apache.org + + UTF-8 + 29-SNAPSHOT + usdot-jpo-ode + https://sonarcloud.io + + Deduplicates Messages generated by Subcomponents of the ODE + 21 + + ^ + + + 0.8.11 + jacoco + reuseReports + ${project.basedir}/target/site/jacoco/jacoco.xml + java + + + + + org.springframework.boot + spring-boot-starter + + + org.apache.logging.log4j + log4j-to-slf4j + + + + + org.springframework.boot + spring-boot-starter-test + test + + + com.vaadin.external.google + android-json + + + + + + org.springframework.boot + spring-boot-devtools + runtime + + + org.springframework.boot + spring-boot-starter-data-rest + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.restdocs + spring-restdocs-mockmvc + test + + + org.springframework.boot + spring-boot-configuration-processor + true + + + org.springframework.boot + spring-boot-starter-websocket + + + org.springframework.kafka + spring-kafka + + + org.springframework.kafka + spring-kafka-test + test + + + + + usdot.jpo.ode + jpo-ode-core + 4.0.0 + + + usdot.jpo.ode + jpo-ode-plugins + 4.0.0 + + + usdot.jpo.ode + jpo-geojsonconverter + 2.0.0 + + + usdot.jpo.ode + jpo-conflictmonitor + 1.5.0 + + + junit + junit + 4.13.2 + test + + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + + + org.jacoco + jacoco-maven-plugin + ${jacoco.version} + test + + + org.mockito + mockito-core + 5.10.0 + test + + + + com.google.guava + guava + 33.0.0-jre + + + + + + + + org.projectlombok + lombok + 1.18.30 + + + + + + + + + false + + central + Central Repository + https://repo.maven.apache.org/maven2 + + + + + + ${project.artifactId} + + + org.sonarsource.scanner.maven + sonar-maven-plugin + 3.10.0.2594 + + + org.springframework.boot + spring-boot-maven-plugin + + + + build-info + + build-info + + + + + + org.apache.maven.plugins + maven-surefire-plugin + 3.2.5 + + all + exit + + + + @{argLine} + -XX:+EnableDynamicAgentLoading + + + + + + org.apache.maven.surefire + surefire-junit47 + 3.2.5 + + + + + + org.jacoco + jacoco-maven-plugin + ${jacoco.version} + + + jacoco-initialize + + prepare-agent + + + + jacoco-site + package + + report + + + + + + org.apache.maven.plugins + maven-jar-plugin + 3.3.0 + + + + jar + + package + + + jpo-deduplicator + + + + + + + + org.apache.maven.plugins + maven-surefire-report-plugin + 3.2.5 + + + + + + package-jar + + + + org.apache.maven.plugins + maven-jar-plugin + 3.2.0 + + + + true + lib/ + + us.dot.its.jpo.deduplicator.DeduplicatorApplication + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + repackage + none + + + + + + + + + + + github + GitHub Packages + https://maven.pkg.github.com/${github_organization}/jpo-deduplicator + + + diff --git a/jpo-deduplicator/settings.xml b/jpo-deduplicator/settings.xml new file mode 100644 index 0000000..2a4f90b --- /dev/null +++ b/jpo-deduplicator/settings.xml @@ -0,0 +1,28 @@ + + + + default + + + + github + jpo_deduplicator + ${env.MAVEN_GITHUB_TOKEN} + + + + + default + + + github + GitHub JPO Conflict Monitor + https://maven.pkg.github.com/${env.MAVEN_GITHUB_ORG}/* + + false + + + + + + \ No newline at end of file diff --git a/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/DeduplicatorApplication.java b/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/DeduplicatorApplication.java new file mode 100644 index 0000000..6b483c9 --- /dev/null +++ b/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/DeduplicatorApplication.java @@ -0,0 +1,57 @@ +/******************************************************************************* + * Copyright 2018 572682 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + ******************************************************************************/ +package us.dot.its.jpo.deduplicator; + +import javax.management.InstanceAlreadyExistsException; +import javax.management.MBeanRegistrationException; +import javax.management.MalformedObjectNameException; +import javax.management.NotCompliantMBeanException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.CommandLineRunner; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; + +@SpringBootApplication +@EnableConfigurationProperties(DeduplicatorProperties.class) +public class DeduplicatorApplication { + + private static final Logger logger = LoggerFactory.getLogger(DeduplicatorApplication.class); + + static final int DEFAULT_NO_THREADS = 10; + static final String DEFAULT_SCHEMA = "default"; + + public static void main(String[] args) throws MalformedObjectNameException, InterruptedException, + InstanceAlreadyExistsException, MBeanRegistrationException, NotCompliantMBeanException { + + logger.info("Starting Message Deduplicator"); + SpringApplication.run(DeduplicatorApplication.class, args); + // MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); + // SystemConfig mBean = new SystemConfig(DEFAULT_NO_THREADS, DEFAULT_SCHEMA); + // ObjectName name = new ObjectName("us.dot.its.jpo.geojson:type=SystemConfig"); + // mbs.registerMBean(mBean, name); + logger.info("Message Deduplicator has started"); + + } + + @Bean + CommandLineRunner init(DeduplicatorProperties geojsonProperties) { + return args -> { + }; + } +} diff --git a/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/DeduplicatorProperties.java b/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/DeduplicatorProperties.java new file mode 100644 index 0000000..8f90068 --- /dev/null +++ b/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/DeduplicatorProperties.java @@ -0,0 +1,450 @@ +/******************************************************************************* + * Copyright 2018 572682 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + ******************************************************************************/ +package us.dot.its.jpo.deduplicator; + +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.Properties; +import java.util.UUID; + +import jakarta.annotation.PostConstruct; + +import org.apache.commons.lang3.SystemUtils; +import org.apache.kafka.clients.producer.ProducerConfig; +import org.apache.kafka.common.serialization.Serdes; +import org.apache.kafka.streams.StreamsConfig; +import org.apache.kafka.streams.errors.LogAndContinueExceptionHandler; +import org.apache.kafka.streams.processor.LogAndSkipOnInvalidTimestamp; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.boot.info.BuildProperties; +import org.springframework.context.EnvironmentAware; +import org.springframework.core.env.Environment; + +import lombok.Getter; +import lombok.Setter; +import lombok.AccessLevel; +import us.dot.its.jpo.conflictmonitor.AlwaysContinueProductionExceptionHandler; +import us.dot.its.jpo.deduplicator.deduplicator.BoundedMemoryRocksDBConfig; +import us.dot.its.jpo.ode.eventlog.EventLogger; +import us.dot.its.jpo.ode.util.CommonUtils; + +// import us.dot.its.jpo.conflictmonitor.AlwaysContinueProductionExceptionHandler; + +@Getter +@Setter +@ConfigurationProperties +public class DeduplicatorProperties implements EnvironmentAware { + + private static final Logger logger = LoggerFactory.getLogger(DeduplicatorProperties.class); + + // Processed Map Configuration + private String kafkaTopicProcessedMap; + private String kafkaTopicDeduplicatedProcessedMap; + private boolean enableProcessedMapDeduplication; + private String kafkaStateStoreProcessedMapName = "ProcessedMap-store"; + + // Processed Map WKT Configuration + private String kafkaTopicProcessedMapWKT; + private String kafkaTopicDeduplicatedProcessedMapWKT; + private boolean enableProcessedMapWktDeduplication; + private String kafkaStateStoreProcessedMapWKTName = "ProcessedMapWKT-store"; + + // Ode Map Json Configuration + private String kafkaTopicOdeMapJson; + private String kafkaTopicDeduplicatedOdeMapJson; + private boolean enableOdeMapDeduplication; + private String kafkaStateStoreOdeMapJsonName = "OdeMapJson-store"; + + // Ode Tim Json Configuration + private String kafkaTopicOdeTimJson; + private String kafkaTopicDeduplicatedOdeTimJson; + private boolean enableOdeTimDeduplication; + private String kafkaStateStoreOdeTimJsonName = "OdeTimJson-store"; + + // Ode Raw Encoded Tim Json Configuration + private String kafkaTopicOdeRawEncodedTimJson; + private String kafkaTopicDeduplicatedOdeRawEncodedTimJson; + private boolean enableOdeRawEncodedTimDeduplication; + private String kafkaStateStoreOdeRawEncodedTimJsonName = "OdeRawEncodedTimJson-store"; + + //Ode BsmJson Configuration + private String kafkaTopicOdeBsmJson; + private String kafkaTopicDeduplicatedOdeBsmJson; + private boolean enableOdeBsmDeduplication; + private long odeBsmMaximumTimeDelta; + private double odeBsmMaximumPositionDelta; + private double odeBsmAlwaysIncludeAtSpeed; + private String kafkaStateStoreOdeBsmJsonName = "OdeBsmJson-store"; + + // Confluent Properties + private boolean confluentCloudEnabled = false; + private String confluentKey = null; + private String confluentSecret = null; + + // Processed SPaT Configuration + private String kafkaTopicProcessedSpat; + private String kafkaTopicDeduplicatedProcessedSpat; + private boolean enableProcessedSpatDeduplication; + private String kafkaStateStoreProcessedSpatName = "ProcessedSpat-store"; + + + private int lingerMs = 0; + + + + @Autowired + @Setter(AccessLevel.NONE) + private Environment env; + + /* + * General Properties + */ + private String version; + // public static final int OUTPUT_SCHEMA_VERSION = 6; + + @Setter(AccessLevel.NONE) + private String kafkaBrokers = null; + + private static final String DEFAULT_KAFKA_PORT = "9092"; + private static final String DEFAULT_CONNECT_PORT = "8083"; + + @Setter(AccessLevel.NONE) + private String hostId; + + // @Setter(AccessLevel.NONE) + // private String connectURL = null; + + // @Setter(AccessLevel.NONE) + // private String dockerHostIP = null; + + @Setter(AccessLevel.NONE) + private String kafkaBrokerIP = null; + + + // @Setter(AccessLevel.NONE) + // private String dbHostIP = null; + + + @Setter(AccessLevel.NONE) + @Autowired + BuildProperties buildProperties; + + @PostConstruct + void initialize() { + setVersion(buildProperties.getVersion()); + logger.info("groupId: {}", buildProperties.getGroup()); + logger.info("artifactId: {}", buildProperties.getArtifact()); + logger.info("version: {}", version); + //OdeMsgMetadata.setStaticSchemaVersion(OUTPUT_SCHEMA_VERSION); + + + + String hostname; + try { + hostname = InetAddress.getLocalHost().getHostName(); + } catch (UnknownHostException e) { + // Let's just use a random hostname + hostname = UUID.randomUUID().toString(); + logger.info("Unknown host error: {}, using random", e); + } + hostId = hostname; + logger.info("Host ID: {}", hostId); + EventLogger.logger.info("Initializing services on host {}", hostId); + + // if(dbHostIP == null){ + // String dbHost = CommonUtils.getEnvironmentVariable("MONGO_IP"); + + // if(dbHost == null){ + // logger.warn( + // "DB Host IP not defined, Defaulting to localhost."); + // dbHost = "localhost"; + // } + // dbHostIP = dbHost; + // } + + if (kafkaBrokers == null) { + + String kafkaBrokers = CommonUtils.getEnvironmentVariable("KAFKA_BOOTSTRAP_SERVERS"); + + logger.info("ode.kafkaBrokers property not defined. Will try KAFKA_BOOTSTRAP_SERVERS => {}", kafkaBrokers); + + if (kafkaBrokers == null) { + logger.warn( + "Neither ode.kafkaBrokers ode property nor KAFKA_BOOTSTRAP_SERVERS environment variable are defined. Defaulting to localhost:9092"); + kafkaBrokers = "localhost:9092"; + } + + } + + String kafkaType = CommonUtils.getEnvironmentVariable("KAFKA_TYPE"); + if (kafkaType != null) { + confluentCloudEnabled = kafkaType.equals("CONFLUENT"); + if (confluentCloudEnabled) { + + logger.info("Enabling Confluent Cloud Integration"); + + confluentKey = CommonUtils.getEnvironmentVariable("CONFLUENT_KEY"); + confluentSecret = CommonUtils.getEnvironmentVariable("CONFLUENT_SECRET"); + } + } + + // Initialize the Kafka Connect URL + // if (connectURL == null) { + // String connectURL = CommonUtils.getEnvironmentVariable("CONNECT_URL"); + // if (connectURL == null) { + // connectURL = String.format("http://%s:%s", "localhost", DEFAULT_CONNECT_PORT); + // } + // } + + // List asList = Arrays.asList(this.getKafkaTopicsDisabled()); + // logger.info("Disabled Topics: {}", asList); + // kafkaTopicsDisabledSet.addAll(asList); + } + + public Properties createStreamProperties(String name) { + Properties streamProps = new Properties(); + streamProps.put(StreamsConfig.APPLICATION_ID_CONFIG, name); + + streamProps.put(StreamsConfig.BOOTSTRAP_SERVERS_CONFIG, kafkaBrokers); + + streamProps.put(StreamsConfig.DEFAULT_DESERIALIZATION_EXCEPTION_HANDLER_CLASS_CONFIG, + LogAndContinueExceptionHandler.class.getName()); + + streamProps.put(StreamsConfig.DEFAULT_TIMESTAMP_EXTRACTOR_CLASS_CONFIG, + LogAndSkipOnInvalidTimestamp.class.getName()); + + streamProps.put(StreamsConfig.DEFAULT_PRODUCTION_EXCEPTION_HANDLER_CLASS_CONFIG, + AlwaysContinueProductionExceptionHandler.class.getName()); + + streamProps.put(StreamsConfig.NUM_STREAM_THREADS_CONFIG, 2); + + // streamProps.put(StreamsConfig.producerPrefix("acks"), "all"); + streamProps.put(StreamsConfig.producerPrefix(ProducerConfig.ACKS_CONFIG), "all"); + + // Reduce cache buffering per topology to 1MB + streamProps.put(StreamsConfig.STATESTORE_CACHE_MAX_BYTES_CONFIG, 1 * 1024 * 1024L); + // Optionally, to disable caching: + //streamProps.put(StreamsConfig.STATESTORE_CACHE_MAX_BYTES_CONFIG, 0); + + + // Decrease default commit interval. Default for 'at least once' mode of 30000ms + // is too slow. + streamProps.put(StreamsConfig.COMMIT_INTERVAL_MS_CONFIG, 100); + + // All the keys are Strings in this app + streamProps.put(StreamsConfig.DEFAULT_KEY_SERDE_CLASS_CONFIG, Serdes.String().getClass().getName()); + + // Configure the state store location + if (SystemUtils.IS_OS_LINUX) { + streamProps.put(StreamsConfig.STATE_DIR_CONFIG, "/var/lib/ode/kafka-streams"); + } else if (SystemUtils.IS_OS_WINDOWS) { + streamProps.put(StreamsConfig.STATE_DIR_CONFIG, "C:/temp/ode"); + } + // streamProps.put(StreamsConfig.STATE_DIR_CONFIG, "/var/lib/")\ + + // Increase max.block.ms and delivery.timeout.ms for streams + final int FIVE_MINUTES_MS = 5 * 60 * 1000; + streamProps.put(ProducerConfig.MAX_BLOCK_MS_CONFIG, FIVE_MINUTES_MS); + streamProps.put(ProducerConfig.DELIVERY_TIMEOUT_MS_CONFIG, FIVE_MINUTES_MS); + + // Disable batching + // streamProps.put(ProducerConfig.BATCH_SIZE_CONFIG, 0); + + streamProps.put(ProducerConfig.COMPRESSION_TYPE_CONFIG, "zstd"); + streamProps.put(ProducerConfig.LINGER_MS_CONFIG, getKafkaLingerMs()); + + if (confluentCloudEnabled) { + streamProps.put("ssl.endpoint.identification.algorithm", "https"); + streamProps.put("security.protocol", "SASL_SSL"); + streamProps.put("sasl.mechanism", "PLAIN"); + + if (confluentKey != null && confluentSecret != null) { + String auth = "org.apache.kafka.common.security.plain.PlainLoginModule required " + + "username=\"" + confluentKey + "\" " + + "password=\"" + confluentSecret + "\";"; + streamProps.put("sasl.jaas.config", auth); + } + else { + logger.error("Environment variables CONFLUENT_KEY and CONFLUENT_SECRET are not set. Set these in the .env file to use Confluent Cloud"); + } + } + + // Configure RocksDB memory usage + streamProps.put(StreamsConfig.ROCKSDB_CONFIG_SETTER_CLASS_CONFIG, BoundedMemoryRocksDBConfig.class); + + return streamProps; + } + + public String getProperty(String key) { + return env.getProperty(key); + } + + public String getProperty(String key, String defaultValue) { + return env.getProperty(key, defaultValue); + } + + public Object getProperty(String key, int i) { + return env.getProperty(key, Integer.class, i); + } + + public Boolean getConfluentCloudStatus() { + return confluentCloudEnabled; + } + + + @Value("${kafkaTopicProcessedMap}") + public void setKafkaTopicProcessedMap(String kafkaTopicProcessedMap) { + this.kafkaTopicProcessedMap = kafkaTopicProcessedMap; + } + + @Value("${kafkaTopicDeduplicatedProcessedMap}") + public void setKafkaTopicDeduplicatedProcessedMap(String kafkaTopicDeduplicatedProcessedMap) { + this.kafkaTopicDeduplicatedProcessedMap = kafkaTopicDeduplicatedProcessedMap; + } + + @Value("${enableProcessedMapDeduplication}") + public void setEnableProcessedMapDeduplication(boolean enableProcessedMapDeduplication) { + this.enableProcessedMapDeduplication = enableProcessedMapDeduplication; + } + + @Value("${kafkaTopicProcessedMapWKT}") + public void setKafkaTopicProcessedMapWKT(String kafkaTopicProcessedMapWKT) { + this.kafkaTopicProcessedMapWKT = kafkaTopicProcessedMapWKT; + } + + @Value("${kafkaTopicDeduplicatedProcessedMapWKT}") + public void setKafkaTopicDeduplicatedProcessedMapWKT(String kafkaTopicDeduplicatedProcessedMapWKT) { + this.kafkaTopicDeduplicatedProcessedMapWKT = kafkaTopicDeduplicatedProcessedMapWKT; + } + + @Value("${enableProcessedMapWktDeduplication}") + public void setEnableProcessedMapWktDeduplication(boolean enableProcessedMapWktDeduplication) { + this.enableProcessedMapWktDeduplication = enableProcessedMapWktDeduplication; + } + + @Value("${kafkaTopicOdeMapJson}") + public void setKafkaTopicOdeMapJson(String kafkaTopicOdeMapJson) { + this.kafkaTopicOdeMapJson = kafkaTopicOdeMapJson; + } + + @Value("${kafkaTopicDeduplicatedOdeMapJson}") + public void setKafkaTopicDeduplicatedOdeMapJson(String kafkaTopicDeduplicatedOdeMapJson) { + this.kafkaTopicDeduplicatedOdeMapJson = kafkaTopicDeduplicatedOdeMapJson; + } + + @Value("${enableOdeMapDeduplication}") + public void setEnableOdeMapDeduplication(boolean enableOdeMapDeduplication) { + this.enableOdeMapDeduplication = enableOdeMapDeduplication; + } + + @Value("${kafkaTopicOdeTimJson}") + public void setKafkaTopicOdeTimJson(String kafkaTopicOdeTimJson) { + this.kafkaTopicOdeTimJson = kafkaTopicOdeTimJson; + } + + @Value("${kafkaTopicDeduplicatedOdeTimJson}") + public void setKafkaTopicDeduplicatedOdeTimJson(String kafkaTopicDeduplicatedOdeTimJson) { + this.kafkaTopicDeduplicatedOdeTimJson = kafkaTopicDeduplicatedOdeTimJson; + } + + @Value("${enableOdeTimDeduplication}") + public void setEnableOdeTimDeduplication(boolean enableOdeTimDeduplication) { + this.enableOdeTimDeduplication = enableOdeTimDeduplication; + } + + @Value("${kafkaTopicOdeRawEncodedTimJson}") + public void setKafkaTopicOdeRawEncodedTimJson(String kafkaTopicOdeRawEncodedTimJson) { + this.kafkaTopicOdeRawEncodedTimJson = kafkaTopicOdeRawEncodedTimJson; + } + + @Value("${kafkaTopicDeduplicatedOdeRawEncodedTimJson}") + public void setKafkaTopicDeduplicatedOdeRawEncodedTimJson(String kafkaTopicDeduplicatedOdeRawEncodedTimJson) { + this.kafkaTopicDeduplicatedOdeRawEncodedTimJson = kafkaTopicDeduplicatedOdeRawEncodedTimJson; + } + + @Value("${enableOdeRawEncodedTimDeduplication}") + public void setEnableOdeRawEncodedTimDeduplication(boolean enableOdeRawEncodedTimDeduplication) { + this.enableOdeRawEncodedTimDeduplication = enableOdeRawEncodedTimDeduplication; + } + + @Value("${kafkaTopicOdeBsmJson}") + public void setkafkaTopicOdeBsmJson(String kafkaTopicOdeBsmJson) { + this.kafkaTopicOdeBsmJson = kafkaTopicOdeBsmJson; + } + + @Value("${kafkaTopicDeduplicatedOdeBsmJson}") + public void setkafkaTopicDeduplicatedOdeBsmJson(String kafkaTopicDeduplicatedOdeBsmJson) { + this.kafkaTopicDeduplicatedOdeBsmJson = kafkaTopicDeduplicatedOdeBsmJson; + } + + @Value("${enableOdeBsmDeduplication}") + public void setenableOdeBsmDeduplication(boolean enableOdeBsmDeduplication) { + this.enableOdeBsmDeduplication = enableOdeBsmDeduplication; + } + + @Value("${odeBsmMaximumTimeDelta}") + public void setMaximumTimeDelta(long maximumTimeDelta) { + this.odeBsmMaximumTimeDelta = maximumTimeDelta; + } + + @Value("${odeBsmMaximumPositionDelta}") + public void setMaximumPositionDelta(double maximumPositionDelta) { + this.odeBsmMaximumPositionDelta = maximumPositionDelta; + } + + @Value("${odeBsmAlwaysIncludeAtSpeed}") + public void setAlwaysIncludeAtSpeed(double alwaysIncludeAtSpeed) { + this.odeBsmAlwaysIncludeAtSpeed = alwaysIncludeAtSpeed; + } + + @Value("${spring.kafka.bootstrap-servers}") + public void setKafkaBrokers(String kafkaBrokers) { + this.kafkaBrokers = kafkaBrokers; + } + + @Value("${kafkaTopicProcessedSpat}") + public void setKafkaTopicProcessedSpat(String kafkaTopicProcessedSpat) { + this.kafkaTopicProcessedSpat = kafkaTopicProcessedSpat; + } + + @Value("${kafkaTopicDeduplicatedProcessedSpat}") + public void setKafkaTopicDeduplicatedProcessedSpat(String kafkaTopicDeduplicatedProcessedSpat) { + this.kafkaTopicDeduplicatedProcessedSpat = kafkaTopicDeduplicatedProcessedSpat; + } + + @Value("${enableProcessedSpatDeduplication}") + public void setEnableProcessedSpatDeduplication(boolean enableProcessedSpatDeduplication) { + this.enableProcessedSpatDeduplication = enableProcessedSpatDeduplication; + } + + @Override + public void setEnvironment(Environment environment) { + env = environment; + } + + @Value("${kafka.linger_ms}") + public void setKafkaLingerMs(int lingerMs) { + this.lingerMs = lingerMs; + } + + public int getKafkaLingerMs() { + return lingerMs; + } +} diff --git a/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/KafkaConfiguration.java b/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/KafkaConfiguration.java new file mode 100644 index 0000000..a5cac5f --- /dev/null +++ b/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/KafkaConfiguration.java @@ -0,0 +1,197 @@ +package us.dot.its.jpo.deduplicator; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import org.apache.kafka.clients.admin.NewTopic; +import org.apache.kafka.common.serialization.StringSerializer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.kafka.config.TopicBuilder; +import org.springframework.kafka.core.DefaultKafkaProducerFactory; +import org.springframework.kafka.core.KafkaAdmin; +import org.springframework.kafka.core.KafkaAdmin.NewTopics; +import org.springframework.kafka.core.KafkaTemplate; +import org.springframework.kafka.core.ProducerFactory; +import org.springframework.stereotype.Component; +import org.apache.kafka.clients.producer.ProducerConfig; + +@Component +@ConfigurationProperties(prefix = "kafka.topics") +public class KafkaConfiguration { + + @Autowired + private DeduplicatorProperties properties; + + @Bean(name = "createKafkaTopics") + public KafkaAdmin.NewTopics createKafkaTopics() { + logger.info("createTopic"); + List newTopics = new ArrayList<>(); + + if(!properties.getConfluentCloudStatus()){ + try { + for(var propEntry : admin.getConfigurationProperties().entrySet()) { + logger.info("KafkaAdmin property {} = {}", propEntry.getKey(), propEntry.getValue()); + } + + if (!autoCreateTopics) { + logger.info("Auto create topics is disabled"); + return null; + } + + logger.info("Creating topics: {}", createTopics); + + + + List topicNames = new ArrayList<>(); + for (var topic : createTopics) { + + // Get the name and config settings for the topic + String topicName = (String)topic.getOrDefault("name", null); + if (topicName == null) { + logger.error("CreateTopic {} has no topic name", topic); + break; + } + topicNames.add(topicName); + + Map topicConfigs = new HashMap<>(); + String cleanupPolicy = (String)topic.getOrDefault("cleanupPolicy", null); + if (cleanupPolicy != null) { + topicConfigs.put("cleanup.policy", cleanupPolicy); + } + Integer retentionMs = (Integer)topic.getOrDefault("retentionMs", null); + if (retentionMs != null) { + topicConfigs.put("retention.ms", retentionMs.toString()); + } + + NewTopic newTopic = TopicBuilder + .name(topicName) + .partitions(numPartitions) + .replicas(numReplicas) + .configs(topicConfigs) + .build(); + newTopics.add(newTopic); + logger.info("New Topic: {}", newTopic); + } + + // Explicitly create the topics here to prevent error on first run + admin.initialize(); + admin.createOrModifyTopics(newTopics.toArray(new NewTopic[0])); + + // Check that topics were created + var topicDescMap = admin.describeTopics(topicNames.toArray(new String[0])); + for (var entry : topicDescMap.entrySet()) { + String topicName = entry.getKey(); + var desc = entry.getValue(); + logger.info("Created topic {}: {}", topicName, desc); + } + + + } catch (Exception e) { + logger.error("Exception in createKafkaTopics", e); + throw e; + } + } + + // List out existing topics + // Admin adminClient = Admin.create(properties.createStreamProperties("DeduplicatorAdminClient")); + // ListTopicsOptions listTopicsOptions = new ListTopicsOptions().listInternal(true); + // ListTopicsResult topicsResult = adminClient.listTopics(listTopicsOptions); + // KafkaFuture> topicsFuture = topicsResult.names(); + // try { + // List topicNames = new ArrayList<>(); + // for(String topicName: topicsFuture.get()){ + // logger.info("Found Topic: " + topicName); + // topicNames.add(topicName); + // } + + // } catch (InterruptedException e) { + // logger.error("Interruption Exception in createKafkaTopics. Unable to List existing Topics", e); + // } catch (ExecutionException e) { + // logger.error("Execution Exception in createKafkaTopics. Unable to List existing Topics", e); + // } + + + return new NewTopics(newTopics.toArray(NewTopic[]::new)); + } + + @Bean + public ProducerFactory producerFactory() { + Properties configProps = properties.createStreamProperties("Deduplicator-producer-factory"); + + Map map = new HashMap<>(); + + for (Map.Entry entry : configProps.entrySet()) { + String key = (String) entry.getKey(); + Object value = entry.getValue(); + map.put(key, value); + } + + map.put( + ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, + StringSerializer.class); + map.put( + ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, + StringSerializer.class); + + return new DefaultKafkaProducerFactory(map); + } + + @Bean + public KafkaTemplate kafkaTemplate() { + return new KafkaTemplate<>(producerFactory()); + } + + private static final Logger logger = LoggerFactory.getLogger(KafkaConfiguration.class); + + private boolean autoCreateTopics; + private int numPartitions; + private int numReplicas; + private List> createTopics; + + public boolean getAutoCreateTopics() { + return autoCreateTopics; + } + + public void setAutoCreateTopics(boolean autoCreateTopics) { + this.autoCreateTopics = autoCreateTopics; + } + + public int getNumPartitions() { + return numPartitions; + } + + public int getNumReplicas() { + return numReplicas; + } + + public List> getCreateTopics() { + return createTopics; + } + + public void setNumPartitions(int numPartitions) { + this.numPartitions = numPartitions; + logger.info("kafka.topics.numPartitions = {}", numPartitions); + } + + public void setNumReplicas(int numReplicas) { + this.numReplicas = numReplicas; + } + + public void setCreateTopics(List> createTopics) { + this.createTopics = createTopics; + } + + + + @Autowired + private KafkaAdmin admin; + + + +} diff --git a/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/StreamsExceptionHandler.java b/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/StreamsExceptionHandler.java new file mode 100644 index 0000000..71132f3 --- /dev/null +++ b/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/StreamsExceptionHandler.java @@ -0,0 +1,56 @@ +package us.dot.its.jpo.deduplicator; + +import org.apache.kafka.streams.errors.StreamsUncaughtExceptionHandler; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.kafka.core.KafkaTemplate; + + + +/** + * Handler for unhandled exceptions thrown from Streams topologies that + * logs the exception to a topic, and allows choosing the shutdown behavior. + * + * See {@link https://cwiki.apache.org/confluence/display/KAFKA/KIP-671%3A+Introduce+Kafka+Streams+Specific+Uncaught+Exception+Handler} + * for a description of the options. + */ +public class StreamsExceptionHandler implements StreamsUncaughtExceptionHandler { + + final static Logger logger = LoggerFactory.getLogger(StreamsExceptionHandler.class); + + final KafkaTemplate kafkaTemplate; + final String topology; + final String notificationTopic; + + @Autowired + public StreamsExceptionHandler(KafkaTemplate kafkaTemplate, String topology, String notificationTopic) { + this.kafkaTemplate = kafkaTemplate; + this.topology = topology; + this.notificationTopic = notificationTopic; + } + + @Override + public StreamThreadExceptionResponse handle(Throwable exception) { + try { + logger.error(String.format("Uncaught exception in stream topology %s", topology), exception); + } catch (Exception ex) { + logger.error("Exception sending kafka streams error event", ex); + } + + + // SHUTDOWN_CLIENT option shuts down quickly. + return StreamThreadExceptionResponse.SHUTDOWN_CLIENT; + + // SHUTDOWN_APPLICATION shuts down more slowly, but cleans up more thoroughly + //return StreamThreadExceptionResponse.SHUTDOWN_APPLICATION; + + // "Replace Thread" mode can be used to keep the streams client alive, + // however if the cause of the error was not transient, but due to a code error processing + // a record, it can result in the record being repeatedly processed throwing the + // same error + // + //return StreamThreadExceptionResponse.REPLACE_THREAD; + } + +} diff --git a/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/BoundedMemoryRocksDBConfig.java b/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/BoundedMemoryRocksDBConfig.java new file mode 100644 index 0000000..2c31ce7 --- /dev/null +++ b/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/BoundedMemoryRocksDBConfig.java @@ -0,0 +1,144 @@ +package us.dot.its.jpo.deduplicator.deduplicator; + +import lombok.extern.slf4j.Slf4j; +import org.apache.kafka.streams.state.RocksDBConfigSetter; +import org.rocksdb.BlockBasedTableConfig; +import org.rocksdb.CompressionType; +import org.rocksdb.Options; +import org.rocksdb.RocksDB; +import java.util.Map; + +/** + * Bounded memory configuration for RocksDB for all topologies. + *

References: + *

+ *

Configured using environment variables: + *

+ *
DEDUPLICATOR_ROCKSDB_TOTAL_OFF_HEAP_MEMORY
Total block cache size
+ *
DEDUPLICATOR_ROCKSDB_INDEX_FILTER_BLOCK_RATIO
Fraction of the block cache to use for high priority blocks (index + * and filter blocks).
+ *
DEDUPLICATOR_ROCKSDB_TOTAL_MEMTABLE_MEMORY
Write buffer size, include in block cache
+ *
DEDUPLICATOR_ROCKSDB_BLOCK_SIZE
{@link org.rocksdb.BlockBasedTableConfig#blockSize()}, Default 4KB
+ *
DEDUPLICATOR_ROCKSDB_N_MEMTABLES
{@link org.rocksdb.Options#maxWriteBufferNumber()}, Default 2
+ *
DEDUPLICATOR_ROCKSDB_MEMTABLE_SIZE
{@link org.rocksdb.Options#writeBufferSize()}, Default 64MB
+ *
+ *

+ */ + +@Slf4j +public class BoundedMemoryRocksDBConfig implements RocksDBConfigSetter { + + private final static long TOTAL_OFF_HEAP_MEMORY; + private final static double INDEX_FILTER_BLOCK_RATIO; + private final static long TOTAL_MEMTABLE_MEMORY; + + // Block size: Default 4K + private final static long BLOCK_SIZE; + + // MaxWriteBufferNumber: Default 2 + private final static int N_MEMTABLES; + + // WriteBufferSize: Default 64MB + private final static long MEMTABLE_SIZE; + private final static long KB = 1024L; + private final static long MB = KB * KB; + + static { + RocksDB.loadLibrary(); + // Initialize properties from env variables + TOTAL_OFF_HEAP_MEMORY = getEnvLong("DEDUPLICATOR_ROCKSDB_TOTAL_OFF_HEAP_MEMORY", 128 * MB); + INDEX_FILTER_BLOCK_RATIO = getEnvDouble("DEDUPLICATOR_ROCKSDB_INDEX_FILTER_BLOCK_RATIO", 0.1); + TOTAL_MEMTABLE_MEMORY = getEnvLong("DEDUPLICATOR_ROCKSDB_TOTAL_MEMTABLE_MEMORY", 64 * MB); + BLOCK_SIZE = getEnvLong("DEDUPLICATOR_ROCKSDB_BLOCK_SIZE", 4 * KB); + N_MEMTABLES = getEnvInt("DEDUPLICATOR_ROCKSDB_N_MEMTABLES", 2); + MEMTABLE_SIZE = getEnvLong("DEDUPLICATOR_ROCKSDB_MEMTABLE_SIZE", 16 * MB); + + log.info("Initialized BoundedMemoryRocksDBConfig. TOTAL_OFF_HEAP_MEMORY = {}, INDEX_FILTER_BLOCK_RATIO = {}," + + " TOTAL_MEMTABLE_MEMORY = {}, BLOCK_SIZE = {}, N_MEMTABLES = {}, MEMTABLE_SIZE = {}", + TOTAL_OFF_HEAP_MEMORY, INDEX_FILTER_BLOCK_RATIO, TOTAL_MEMTABLE_MEMORY, BLOCK_SIZE, N_MEMTABLES, + MEMTABLE_SIZE); + } + + // See #1 below + private static final org.rocksdb.Cache cache + = new org.rocksdb.LRUCache(TOTAL_OFF_HEAP_MEMORY, -1, false, INDEX_FILTER_BLOCK_RATIO); + private static final org.rocksdb.WriteBufferManager writeBufferManager + = new org.rocksdb.WriteBufferManager(TOTAL_MEMTABLE_MEMORY, cache); + @Override + public void setConfig(final String storeName, final Options options, final Map configs) { + log.info("Setting RocksDB config for store {}", storeName); + BlockBasedTableConfig tableConfig = (BlockBasedTableConfig) options.tableFormatConfig(); + + // These three options in combination will limit the memory used by RocksDB to the size passed to the block + // cache (TOTAL_OFF_HEAP_MEMORY) + tableConfig.setBlockCache(cache); + tableConfig.setCacheIndexAndFilterBlocks(true); + options.setWriteBufferManager(writeBufferManager); + + // These options are recommended to be set when bounding the total memory + // See #2 below + tableConfig.setCacheIndexAndFilterBlocksWithHighPriority(true); + tableConfig.setPinTopLevelIndexAndFilter(true); + + // See #3 below + tableConfig.setBlockSize(BLOCK_SIZE); + options.setMaxWriteBufferNumber(N_MEMTABLES); + options.setWriteBufferSize(MEMTABLE_SIZE); + + // Enable compression (optional). Compression can decrease the required storage + // and increase the CPU usage of the machine. For CompressionType values, see + // https://javadoc.io/static/org.rocksdb/rocksdbjni/6.4.6/org/rocksdb/CompressionType.html. + options.setCompressionType(CompressionType.LZ4_COMPRESSION); + options.setTableFormatConfig(tableConfig); + log.info("Rocksdb set table config: {}, options: {}", tableConfig, options); + } + @Override + public void close(final String storeName, final Options options) { + // Cache and WriteBufferManager should not be closed here, as the same objects are shared by every store instance. + } + + private static long getEnvLong(String name, long defaultValue) { + String strValue = getEnvString(name); + if (strValue == null) return defaultValue; + + try { + return Long.parseLong(strValue); + } catch (NumberFormatException nfe) { + log.error("Error parsing env variable to long {}, {}", name, strValue, nfe); + return defaultValue; + } + } + + private static int getEnvInt(String name, int defaultValue) { + String strValue = getEnvString(name); + if (strValue == null) return defaultValue; + try { + return Integer.parseInt(strValue); + } catch (NumberFormatException nfe) { + log.error("Error parsing env variable to long {}, {}", name, strValue, nfe); + return defaultValue; + } + } + + private static double getEnvDouble(String name, double defaultValue) { + String strValue = getEnvString(name); + if (strValue == null) return defaultValue; + try { + return Double.parseDouble(strValue); + } catch (NumberFormatException nfe) { + log.error("Error parsing env variable to long {}, {}", name, strValue, nfe); + return defaultValue; + } + } + + private static String getEnvString(String name) { + String strValue = System.getenv(name); + if (strValue == null) { + log.warn("Env variable {} is not set", name); + } + return strValue; + } +} \ No newline at end of file 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 new file mode 100644 index 0000000..bd38ab9 --- /dev/null +++ b/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/DeduplicatorServiceController.java @@ -0,0 +1,114 @@ +package us.dot.its.jpo.deduplicator.deduplicator; + +import java.util.concurrent.ConcurrentHashMap; + +import org.apache.kafka.streams.KafkaStreams; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.DependsOn; +import org.springframework.context.annotation.Profile; +import org.springframework.kafka.core.KafkaTemplate; +import org.springframework.stereotype.Controller; + +import lombok.Getter; +import us.dot.its.jpo.conflictmonitor.monitor.MonitorServiceController; +import us.dot.its.jpo.conflictmonitor.monitor.algorithms.StreamsTopology; +import us.dot.its.jpo.deduplicator.DeduplicatorProperties; +import us.dot.its.jpo.deduplicator.deduplicator.topologies.BsmDeduplicatorTopology; +import us.dot.its.jpo.deduplicator.deduplicator.topologies.MapDeduplicatorTopology; +import us.dot.its.jpo.deduplicator.deduplicator.topologies.TimDeduplicatorTopology; +import us.dot.its.jpo.deduplicator.deduplicator.topologies.OdeRawEncodedTimDeduplicatorTopology; +import us.dot.its.jpo.deduplicator.deduplicator.topologies.ProcessedMapDeduplicatorTopology; +import us.dot.its.jpo.deduplicator.deduplicator.topologies.ProcessedMapWktDeduplicatorTopology; +import us.dot.its.jpo.deduplicator.deduplicator.topologies.ProcessedSpatDeduplicatorTopology; + +@Controller +@DependsOn("createKafkaTopics") +@Profile("!test && !testConfig") +public class DeduplicatorServiceController { + + private static final Logger logger = LoggerFactory.getLogger(MonitorServiceController.class); + + // Temporary for KafkaStreams that don't implement the Algorithm interface + @Getter + final ConcurrentHashMap streamsMap = new ConcurrentHashMap(); + + @Getter + final ConcurrentHashMap algoMap = new ConcurrentHashMap(); + + + + @Autowired + public DeduplicatorServiceController(final DeduplicatorProperties props, + final KafkaTemplate kafkaTemplate) { + + + try { + + if(props.isEnableProcessedMapDeduplication()){ + logger.info("Starting Processed Map Deduplicator"); + ProcessedMapDeduplicatorTopology processedMapDeduplicatorTopology = new ProcessedMapDeduplicatorTopology( + props, + props.createStreamProperties("ProcessedMapDeduplicator") + ); + processedMapDeduplicatorTopology.start(); + } + + if(props.isEnableProcessedMapWktDeduplication()){ + logger.info("Starting Processed Map WKT Deduplicator"); + ProcessedMapWktDeduplicatorTopology processedMapWktDeduplicatorTopology = new ProcessedMapWktDeduplicatorTopology( + props, + props.createStreamProperties("ProcessedMapWKTdeduplicator") + ); + processedMapWktDeduplicatorTopology.start(); + } + + if(props.isEnableProcessedMapDeduplication()){ + logger.info("Starting Map Deduplicator"); + MapDeduplicatorTopology mapDeduplicatorTopology = new MapDeduplicatorTopology( + props, + props.createStreamProperties("MapDeduplicator") + ); + mapDeduplicatorTopology.start(); + } + + if(props.isEnableOdeTimDeduplication()){ + logger.info("Starting Tim Deduplicator"); + TimDeduplicatorTopology timDeduplicatorTopology = new TimDeduplicatorTopology( + props, + props.createStreamProperties("TimDeduplicator") + ); + timDeduplicatorTopology.start(); + } + + if(props.isEnableOdeRawEncodedTimDeduplication()){ + logger.info("Starting Raw Encoded TIM Deduplicator"); + OdeRawEncodedTimDeduplicatorTopology odeRawEncodedTimDeduplicatorTopology = new OdeRawEncodedTimDeduplicatorTopology( + props, + props.createStreamProperties("OdeRawEncodedTimDeduplicator") + ); + odeRawEncodedTimDeduplicatorTopology.start(); + } + + if(props.isEnableProcessedSpatDeduplication()){ + logger.info("Starting Processed Spat Deduplicator"); + ProcessedSpatDeduplicatorTopology processedSpatDeduplicatorTopology = new ProcessedSpatDeduplicatorTopology( + props, + props.createStreamProperties("ProcessedSpatDeduplicator") + ); + processedSpatDeduplicatorTopology.start(); + } + + if(props.isEnableOdeBsmDeduplication()){ + logger.info("Starting BSM Deduplicator"); + BsmDeduplicatorTopology bsmDeduplicatorTopology = new BsmDeduplicatorTopology(props); + bsmDeduplicatorTopology.start(); + } + + + } catch (Exception e) { + logger.error("Encountered issue with creating topologies", e); + } + } +} diff --git a/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/models/JsonPair.java b/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/models/JsonPair.java new file mode 100644 index 0000000..d0f4377 --- /dev/null +++ b/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/models/JsonPair.java @@ -0,0 +1,21 @@ +package us.dot.its.jpo.deduplicator.deduplicator.models; + +import com.fasterxml.jackson.databind.JsonNode; + +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@NoArgsConstructor +@Setter +@Getter +public class JsonPair { + + public JsonNode message; + public boolean shouldSend; + + public JsonPair(JsonNode message, boolean shouldSend){ + this.message = message; + this.shouldSend = shouldSend; + } +} diff --git a/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/models/OdeBsmPair.java b/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/models/OdeBsmPair.java new file mode 100644 index 0000000..208622b --- /dev/null +++ b/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/models/OdeBsmPair.java @@ -0,0 +1,20 @@ +package us.dot.its.jpo.deduplicator.deduplicator.models; + +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import us.dot.its.jpo.ode.model.OdeBsmData; + +@NoArgsConstructor +@Setter +@Getter +public class OdeBsmPair { + + public OdeBsmData message; + public boolean shouldSend; + + public OdeBsmPair(OdeBsmData message, boolean shouldSend){ + this.message = message; + this.shouldSend = shouldSend; + } +} diff --git a/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/models/OdeMapPair.java b/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/models/OdeMapPair.java new file mode 100644 index 0000000..24c265a --- /dev/null +++ b/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/models/OdeMapPair.java @@ -0,0 +1,20 @@ +package us.dot.its.jpo.deduplicator.deduplicator.models; + +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import us.dot.its.jpo.ode.model.OdeMapData; + +@NoArgsConstructor +@Setter +@Getter +public class OdeMapPair { + + public OdeMapData message; + public boolean shouldSend; + + public OdeMapPair(OdeMapData message, boolean shouldSend){ + this.message = message; + this.shouldSend = shouldSend; + } +} diff --git a/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/models/Pair.java b/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/models/Pair.java new file mode 100644 index 0000000..fd0ee44 --- /dev/null +++ b/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/models/Pair.java @@ -0,0 +1,19 @@ +package us.dot.its.jpo.deduplicator.deduplicator.models; + +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@NoArgsConstructor +@Setter +@Getter +public class Pair { + + public T message; + public boolean shouldSend; + + public Pair(T message, boolean shouldSend){ + this.message = message; + this.shouldSend = shouldSend; + } +} diff --git a/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/models/ProcessedMapPair.java b/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/models/ProcessedMapPair.java new file mode 100644 index 0000000..b1400c5 --- /dev/null +++ b/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/models/ProcessedMapPair.java @@ -0,0 +1,21 @@ +package us.dot.its.jpo.deduplicator.deduplicator.models; + +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import us.dot.its.jpo.geojsonconverter.pojos.geojson.LineString; +import us.dot.its.jpo.geojsonconverter.pojos.geojson.map.ProcessedMap; + +@NoArgsConstructor +@Setter +@Getter +public class ProcessedMapPair { + + public ProcessedMap message; + public boolean shouldSend; + + public ProcessedMapPair(ProcessedMap message, boolean shouldSend){ + this.message = message; + this.shouldSend = shouldSend; + } +} diff --git a/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/models/ProcessedMapWktPair.java b/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/models/ProcessedMapWktPair.java new file mode 100644 index 0000000..d6acaca --- /dev/null +++ b/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/models/ProcessedMapWktPair.java @@ -0,0 +1,20 @@ +package us.dot.its.jpo.deduplicator.deduplicator.models; + +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import us.dot.its.jpo.geojsonconverter.pojos.geojson.map.ProcessedMap; + +@NoArgsConstructor +@Setter +@Getter +public class ProcessedMapWktPair { + + public ProcessedMap message; + public boolean shouldSend; + + public ProcessedMapWktPair(ProcessedMap message, boolean shouldSend){ + this.message = message; + this.shouldSend = shouldSend; + } +} diff --git a/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/processors/DeduplicationProcessor.java b/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/processors/DeduplicationProcessor.java new file mode 100644 index 0000000..55b669c --- /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 0000000..16a621c --- /dev/null +++ b/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/processors/OdeBsmJsonProcessor.java @@ -0,0 +1,84 @@ +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 org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +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; + + private static final Logger logger = LoggerFactory.getLogger(OdeBsmJsonProcessor.class); + + public OdeBsmJsonProcessor(String storeName, DeduplicatorProperties props){ + this.storeName = storeName; + this.props = props; + calculator = new GeodeticCalculator(); + } + + + @Override + public Instant getMessageTime(OdeBsmData message) { + String time = ((OdeBsmMetadata)message.getMetadata()).getOdeReceivedAt(); + try { + return Instant.from(formatter.parse(time)); + } catch (Exception e) { + logger.warn("Failed to Parse Time: " + 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 0000000..adaf6db --- /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 0000000..cca49a7 --- /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 0000000..9a117b3 --- /dev/null +++ b/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/processors/OdeTimJsonProcessor.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 us.dot.its.jpo.deduplicator.DeduplicatorProperties; +import us.dot.its.jpo.ode.model.OdeTimData; +import us.dot.its.jpo.ode.model.OdeTimMetadata; + +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(OdeTimData message) { + try { + // String time = message.get("metadata").get("odeReceivedAt").asText(); + String time = ((OdeTimMetadata)message.getMetadata()).getOdeReceivedAt(); + return Instant.from(formatter.parse(time)); + } catch (Exception e) { + return Instant.ofEpochMilli(0); + } + } + + @Override + public boolean isDuplicate(OdeTimData lastMessage, OdeTimData 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 0000000..35e2c2f --- /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 0000000..7556060 --- /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/ProcessedSpatProcessor.java b/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/processors/ProcessedSpatProcessor.java new file mode 100644 index 0000000..2cc58af --- /dev/null +++ b/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/processors/ProcessedSpatProcessor.java @@ -0,0 +1,64 @@ +package us.dot.its.jpo.deduplicator.deduplicator.processors; + + +import java.time.Duration; +import java.time.Instant; +import java.util.HashMap; +import java.util.List; + +import us.dot.its.jpo.deduplicator.DeduplicatorProperties; +import us.dot.its.jpo.geojsonconverter.pojos.spat.MovementEvent; +import us.dot.its.jpo.geojsonconverter.pojos.spat.MovementState; +import us.dot.its.jpo.geojsonconverter.pojos.spat.ProcessedSpat; + +public class ProcessedSpatProcessor extends DeduplicationProcessor{ + + DeduplicatorProperties props; + + public ProcessedSpatProcessor(DeduplicatorProperties props){ + this.props = props; + this.storeName = props.getKafkaStateStoreProcessedSpatName(); + } + + + @Override + public Instant getMessageTime(ProcessedSpat message) { + return message.getUtcTimeStamp().toInstant(); + } + + @Override + public boolean isDuplicate(ProcessedSpat lastMessage, ProcessedSpat newMessage) { + + Instant newValueTime = getMessageTime(newMessage); + Instant oldValueTime = getMessageTime(lastMessage); + + if(newValueTime.minus(Duration.ofMinutes(1)).isAfter(oldValueTime)){ + return false; + }else{ + HashMap> lastMessageStates = new HashMap<>(); + for(MovementState state: lastMessage.getStates()){ + lastMessageStates.put(state.getSignalGroup(), state.getStateTimeSpeed()); + } + + if(lastMessageStates.size() != newMessage.getStates().size()){ + return false; // message cannot be duplicate if the signal groups have a different number of signal groups + } + + for(MovementState state: newMessage.getStates()){ + List lastMessageState = lastMessageStates.get(state.getSignalGroup()); + + if(lastMessageState == null){ + return false; // messages cannot be duplicates if they have different signal groups + } + + + for(int i=0; i< state.getStateTimeSpeed().size(); i++){ + if(state.getStateTimeSpeed().get(i).getEventState() != lastMessageState.get(i).getEventState()){ + return false; // Some signal group light has changed. Therefore the SPaTs are different + } + } + } + } + return true; + } +} diff --git a/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/processors/suppliers/OdeBsmJsonProcessorSupplier.java b/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/processors/suppliers/OdeBsmJsonProcessorSupplier.java new file mode 100644 index 0000000..6b08b9f --- /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 0000000..829af13 --- /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 0000000..ef0ebb7 --- /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 0000000..0c07e30 --- /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 us.dot.its.jpo.deduplicator.DeduplicatorProperties; +import us.dot.its.jpo.deduplicator.deduplicator.processors.OdeTimJsonProcessor; +import us.dot.its.jpo.ode.model.OdeTimData; + +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 0000000..9e45cd0 --- /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 0000000..3dbaa8c --- /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/processors/suppliers/ProcessedSpatProcessorSupplier.java b/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/processors/suppliers/ProcessedSpatProcessorSupplier.java new file mode 100644 index 0000000..e6661ac --- /dev/null +++ b/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/processors/suppliers/ProcessedSpatProcessorSupplier.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.ProcessedSpatProcessor; +import us.dot.its.jpo.geojsonconverter.pojos.spat.ProcessedSpat; + +public class ProcessedSpatProcessorSupplier implements ProcessorSupplier { + + DeduplicatorProperties props; + + public ProcessedSpatProcessorSupplier(DeduplicatorProperties props){ + this.props = props; + } + + @Override + public Processor get() { + return new ProcessedSpatProcessor(props); + } +} \ No newline at end of file diff --git a/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/serialization/JsonSerdes.java b/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/serialization/JsonSerdes.java new file mode 100644 index 0000000..29c9778 --- /dev/null +++ b/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/serialization/JsonSerdes.java @@ -0,0 +1,24 @@ +package us.dot.its.jpo.deduplicator.deduplicator.serialization; + +import org.apache.kafka.common.serialization.Serde; +import org.apache.kafka.common.serialization.Serdes; + +import com.fasterxml.jackson.databind.JsonNode; + +import us.dot.its.jpo.geojsonconverter.serialization.deserializers.JsonDeserializer; +import us.dot.its.jpo.geojsonconverter.serialization.serializers.JsonSerializer; +import us.dot.its.jpo.ode.model.OdeTimData; + +public class JsonSerdes { + public static Serde OdeTim() { + return Serdes.serdeFrom( + new JsonSerializer(), + new JsonDeserializer<>(OdeTimData.class)); + } + + public static Serde JSON(){ + return Serdes.serdeFrom( + new JsonSerializer(), + new JsonDeserializer<>(JsonNode.class)); + } +} diff --git a/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/serialization/PairSerdes.java b/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/serialization/PairSerdes.java new file mode 100644 index 0000000..e509fa0 --- /dev/null +++ b/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/serialization/PairSerdes.java @@ -0,0 +1,52 @@ +package us.dot.its.jpo.deduplicator.deduplicator.serialization; + +import org.apache.kafka.common.serialization.Serde; +import org.apache.kafka.common.serialization.Serdes; + +import us.dot.its.jpo.deduplicator.deduplicator.models.ProcessedMapPair; +import us.dot.its.jpo.deduplicator.deduplicator.models.ProcessedMapWktPair; +import us.dot.its.jpo.deduplicator.deduplicator.models.OdeMapPair; +import us.dot.its.jpo.deduplicator.deduplicator.models.OdeBsmPair; +import us.dot.its.jpo.deduplicator.deduplicator.models.JsonPair; +import us.dot.its.jpo.geojsonconverter.pojos.geojson.map.DeserializedRawMap; +import us.dot.its.jpo.geojsonconverter.serialization.deserializers.JsonDeserializer; +import us.dot.its.jpo.geojsonconverter.serialization.serializers.JsonSerializer; + + +public class PairSerdes { + public static Serde ProcessedMapPair() { + return Serdes.serdeFrom( + new JsonSerializer(), + new JsonDeserializer<>(ProcessedMapPair.class)); + } + + public static Serde ProcessedMapWktPair() { + return Serdes.serdeFrom( + new JsonSerializer(), + new JsonDeserializer<>(ProcessedMapWktPair.class)); + } + + public static Serde OdeMapPair() { + return Serdes.serdeFrom( + new JsonSerializer(), + new JsonDeserializer<>(OdeMapPair.class)); + } + + public static Serde OdeBsmPair() { + return Serdes.serdeFrom( + new JsonSerializer(), + new JsonDeserializer<>(OdeBsmPair.class)); + } + + public static Serde RawMap() { + return Serdes.serdeFrom( + new JsonSerializer(), + new JsonDeserializer<>(DeserializedRawMap.class)); + } + + public static Serde JsonPair() { + return Serdes.serdeFrom( + new JsonSerializer(), + new JsonDeserializer<>(JsonPair.class)); + } +} diff --git a/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/topologies/BsmDeduplicatorTopology.java b/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/topologies/BsmDeduplicatorTopology.java new file mode 100644 index 0000000..6b26d67 --- /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 new file mode 100644 index 0000000..c8ac7f6 --- /dev/null +++ b/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/topologies/MapDeduplicatorTopology.java @@ -0,0 +1,121 @@ +package us.dot.its.jpo.deduplicator.deduplicator.topologies; + +import org.apache.kafka.common.serialization.Serdes; +import org.apache.kafka.streams.KafkaStreams; +import org.apache.kafka.streams.StreamsBuilder; +import org.apache.kafka.streams.Topology; +import org.apache.kafka.streams.KafkaStreams.StateListener; +import org.apache.kafka.streams.errors.StreamsUncaughtExceptionHandler; + +import us.dot.its.jpo.deduplicator.DeduplicatorProperties; +import us.dot.its.jpo.deduplicator.deduplicator.processors.suppliers.OdeMapJsonProcessorSupplier; +import us.dot.its.jpo.geojsonconverter.DateJsonMapper; +import us.dot.its.jpo.geojsonconverter.partitioner.RsuIntersectionKey; +import us.dot.its.jpo.geojsonconverter.serialization.JsonSerdes; +import us.dot.its.jpo.ode.model.OdeMapData; +import us.dot.its.jpo.ode.model.OdeMapMetadata; +import us.dot.its.jpo.ode.model.OdeMapPayload; +import us.dot.its.jpo.ode.plugin.j2735.J2735IntersectionReferenceID; + +import org.apache.kafka.streams.kstream.*; +import org.apache.kafka.streams.state.Stores; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.databind.ObjectMapper; + +import java.time.Instant; +import java.time.format.DateTimeFormatter; +import java.util.Objects; +import java.util.Properties; + +public class MapDeduplicatorTopology { + + private static final Logger logger = LoggerFactory.getLogger(MapDeduplicatorTopology.class); + + Topology topology; + KafkaStreams streams; + String inputTopic; + String outputTopic; + Properties streamsProperties; + ObjectMapper objectMapper; + DateTimeFormatter formatter = DateTimeFormatter.ISO_INSTANT; + DeduplicatorProperties props; + + + public MapDeduplicatorTopology(DeduplicatorProperties props, Properties streamsProperties){ + this.props = props; + this.streamsProperties = streamsProperties; + this.objectMapper = DateJsonMapper.getInstance(); + } + + + + public void start() { + if (streams != null && streams.state().isRunningOrRebalancing()) { + throw new IllegalStateException("Start called while streams is already running."); + } + Topology topology = buildTopology(); + streams = new KafkaStreams(topology, streamsProperties); + if (exceptionHandler != null) streams.setUncaughtExceptionHandler(exceptionHandler); + if (stateListener != null) streams.setStateListener(stateListener); + logger.info("Starting Map Deduplicator Topology"); + streams.start(); + } + + public Instant getInstantFromMap(OdeMapData map){ + String time = ((OdeMapMetadata)map.getMetadata()).getOdeReceivedAt(); + + return Instant.from(formatter.parse(time)); + } + + public int hashMapMessage(OdeMapData map){ + OdeMapPayload payload = (OdeMapPayload)map.getPayload(); + return Objects.hash(payload.toJson()); + + } + + public Topology buildTopology() { + StreamsBuilder builder = new StreamsBuilder(); + + KStream inputStream = builder.stream(props.getKafkaTopicOdeMapJson(), Consumed.with(Serdes.Void(), JsonSerdes.OdeMap())); + + builder.addStateStore(Stores.keyValueStoreBuilder(Stores.persistentKeyValueStore(props.getKafkaStateStoreOdeMapJsonName()), + Serdes.String(), JsonSerdes.OdeMap())); + + KStream mapRekeyedStream = inputStream.selectKey((key, value)->{ + J2735IntersectionReferenceID intersectionId = ((OdeMapPayload)value.getPayload()).getMap().getIntersections().getIntersections().get(0).getId(); + RsuIntersectionKey newKey = new RsuIntersectionKey(); + newKey.setRsuId(((OdeMapMetadata)value.getMetadata()).getOriginIp()); + newKey.setIntersectionReferenceID(intersectionId); + return newKey.toString(); + }).repartition(Repartitioned.with(Serdes.String(), JsonSerdes.OdeMap())); + + KStream deduplicatedStream = mapRekeyedStream.process(new OdeMapJsonProcessorSupplier(props), props.getKafkaStateStoreOdeMapJsonName()); + + deduplicatedStream.to(props.getKafkaTopicDeduplicatedOdeMapJson(), Produced.with(Serdes.String(), JsonSerdes.OdeMap())); + + return builder.build(); + + } + + public void stop() { + logger.info("Stopping Map Deduplicator Socket Broadcast Topology."); + if (streams != null) { + streams.close(); + streams.cleanUp(); + streams = null; + } + logger.info("Stopped Map Deduplicator Socket Broadcast Topology."); + } + + StateListener stateListener; + public void registerStateListener(StateListener stateListener) { + this.stateListener = stateListener; + } + + StreamsUncaughtExceptionHandler exceptionHandler; + public void registerUncaughtExceptionHandler(StreamsUncaughtExceptionHandler exceptionHandler) { + this.exceptionHandler = exceptionHandler; + } +} diff --git a/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/topologies/OdeRawEncodedTimDeduplicatorTopology.java b/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/topologies/OdeRawEncodedTimDeduplicatorTopology.java new file mode 100644 index 0000000..c68d902 --- /dev/null +++ b/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/topologies/OdeRawEncodedTimDeduplicatorTopology.java @@ -0,0 +1,130 @@ +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){ + String time = tim.get("metadata").get("odeReceivedAt").asText(); + try{ + return Instant.from(formatter.parse(time)); + }catch(Exception e){ + logger.warn("Failed to parse time: " + 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 new file mode 100644 index 0000000..5f9da3d --- /dev/null +++ b/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/topologies/ProcessedMapDeduplicatorTopology.java @@ -0,0 +1,92 @@ +package us.dot.its.jpo.deduplicator.deduplicator.topologies; + +import org.apache.kafka.common.serialization.Serdes; +import org.apache.kafka.streams.KafkaStreams; +import org.apache.kafka.streams.StreamsBuilder; +import org.apache.kafka.streams.Topology; +import org.apache.kafka.streams.KafkaStreams.StateListener; +import org.apache.kafka.streams.errors.StreamsUncaughtExceptionHandler; + +import us.dot.its.jpo.deduplicator.DeduplicatorProperties; +import us.dot.its.jpo.deduplicator.deduplicator.processors.suppliers.ProcessedMapProcessorSupplier; +import us.dot.its.jpo.geojsonconverter.DateJsonMapper; +import us.dot.its.jpo.geojsonconverter.pojos.geojson.LineString; +import us.dot.its.jpo.geojsonconverter.pojos.geojson.map.ProcessedMap; +import us.dot.its.jpo.geojsonconverter.serialization.JsonSerdes; +import org.apache.kafka.streams.kstream.*; +import org.apache.kafka.streams.state.Stores; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import com.fasterxml.jackson.databind.ObjectMapper; + + +import java.util.Properties; + +public class ProcessedMapDeduplicatorTopology { + + private static final Logger logger = LoggerFactory.getLogger(MapDeduplicatorTopology.class); + + Topology topology; + KafkaStreams streams; + Properties streamsProperties; + ObjectMapper objectMapper; + DeduplicatorProperties props; + + public ProcessedMapDeduplicatorTopology(DeduplicatorProperties props, Properties streamsProperties){ + this.props = props; + this.streamsProperties = streamsProperties; + this.objectMapper = DateJsonMapper.getInstance(); + } + + + public void start() { + if (streams != null && streams.state().isRunningOrRebalancing()) { + throw new IllegalStateException("Start called while streams is already running."); + } + Topology topology = buildTopology(); + streams = new KafkaStreams(topology, streamsProperties); + if (exceptionHandler != null) streams.setUncaughtExceptionHandler(exceptionHandler); + if (stateListener != null) streams.setStateListener(stateListener); + logger.info("Starting Processed Map Deduplicator Topology"); + streams.start(); + } + + public Topology buildTopology() { + StreamsBuilder builder = new StreamsBuilder(); + + KStream> inputStream = builder.stream(props.getKafkaTopicProcessedMap(), Consumed.with(Serdes.String(), JsonSerdes.ProcessedMapGeoJson())); + + builder.addStateStore(Stores.keyValueStoreBuilder(Stores.persistentKeyValueStore(props.getKafkaStateStoreProcessedMapName()), + Serdes.String(), JsonSerdes.ProcessedMapGeoJson())); + + KStream> deduplicatedStream = inputStream.process(new ProcessedMapProcessorSupplier(props), props.getKafkaStateStoreProcessedMapName()); + + deduplicatedStream.to(props.getKafkaTopicDeduplicatedProcessedMap(), Produced.with(Serdes.String(), JsonSerdes.ProcessedMapGeoJson())); + + return builder.build(); + + } + + public void stop() { + logger.info("Stopping Processed Map deduplicator Socket Broadcast Topology."); + if (streams != null) { + streams.close(); + streams.cleanUp(); + streams = null; + } + logger.info("Stopped Processed Map deduplicator Socket Broadcast Topology."); + } + + StateListener stateListener; + public void registerStateListener(StateListener stateListener) { + this.stateListener = stateListener; + } + + StreamsUncaughtExceptionHandler exceptionHandler; + public void registerUncaughtExceptionHandler(StreamsUncaughtExceptionHandler exceptionHandler) { + this.exceptionHandler = exceptionHandler; + } + + + +} diff --git a/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/topologies/ProcessedMapWktDeduplicatorTopology.java b/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/topologies/ProcessedMapWktDeduplicatorTopology.java new file mode 100644 index 0000000..872e66f --- /dev/null +++ b/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/topologies/ProcessedMapWktDeduplicatorTopology.java @@ -0,0 +1,93 @@ +package us.dot.its.jpo.deduplicator.deduplicator.topologies; + +import org.apache.kafka.common.serialization.Serdes; +import org.apache.kafka.streams.KafkaStreams; +import org.apache.kafka.streams.StreamsBuilder; +import org.apache.kafka.streams.Topology; +import org.apache.kafka.streams.KafkaStreams.StateListener; +import org.apache.kafka.streams.errors.StreamsUncaughtExceptionHandler; + +import us.dot.its.jpo.deduplicator.DeduplicatorProperties; +import us.dot.its.jpo.deduplicator.deduplicator.processors.suppliers.ProcessedMapWktProcessorSupplier; +import us.dot.its.jpo.geojsonconverter.DateJsonMapper; +import us.dot.its.jpo.geojsonconverter.pojos.geojson.map.ProcessedMap; +import us.dot.its.jpo.geojsonconverter.serialization.JsonSerdes; + +import org.apache.kafka.streams.kstream.*; +import org.apache.kafka.streams.state.Stores; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import com.fasterxml.jackson.databind.ObjectMapper; + +import java.util.Properties; + +public class ProcessedMapWktDeduplicatorTopology { + + private static final Logger logger = LoggerFactory.getLogger(MapDeduplicatorTopology.class); + + Topology topology; + KafkaStreams streams; + String inputTopic; + String outputTopic; + Properties streamsProperties; + ObjectMapper objectMapper; + DeduplicatorProperties props; + + public ProcessedMapWktDeduplicatorTopology(DeduplicatorProperties props, Properties streamsProperties){ + this.props = props; + this.streamsProperties = streamsProperties; + this.objectMapper = DateJsonMapper.getInstance(); + } + + + public void start() { + if (streams != null && streams.state().isRunningOrRebalancing()) { + throw new IllegalStateException("Start called while streams is already running."); + } + Topology topology = buildTopology(); + streams = new KafkaStreams(topology, streamsProperties); + if (exceptionHandler != null) streams.setUncaughtExceptionHandler(exceptionHandler); + if (stateListener != null) streams.setStateListener(stateListener); + logger.info("Starting Processed Map WKT Deduplicator Topology"); + streams.start(); + } + + public Topology buildTopology() { + StreamsBuilder builder = new StreamsBuilder(); + + KStream> inputStream = builder.stream(props.getKafkaTopicProcessedMapWKT(), Consumed.with(Serdes.String(), JsonSerdes.ProcessedMapWKT())); + + builder.addStateStore(Stores.keyValueStoreBuilder(Stores.persistentKeyValueStore(props.getKafkaStateStoreProcessedMapWKTName()), + Serdes.String(), JsonSerdes.ProcessedMapWKT())); + + KStream> deduplicatedStream = inputStream.process(new ProcessedMapWktProcessorSupplier(props), props.getKafkaStateStoreProcessedMapWKTName()); + + deduplicatedStream.to(props.getKafkaTopicDeduplicatedProcessedMapWKT(), Produced.with(Serdes.String(), JsonSerdes.ProcessedMapWKT())); + + return builder.build(); + + } + + public void stop() { + logger.info("Stopping Processed Map deduplicator Socket Broadcast Topology."); + if (streams != null) { + streams.close(); + streams.cleanUp(); + streams = null; + } + logger.info("Stopped Processed Map deduplicator Socket Broadcast Topology."); + } + + StateListener stateListener; + public void registerStateListener(StateListener stateListener) { + this.stateListener = stateListener; + } + + StreamsUncaughtExceptionHandler exceptionHandler; + public void registerUncaughtExceptionHandler(StreamsUncaughtExceptionHandler exceptionHandler) { + this.exceptionHandler = exceptionHandler; + } + + + +} diff --git a/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/topologies/ProcessedSpatDeduplicatorTopology.java b/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/topologies/ProcessedSpatDeduplicatorTopology.java new file mode 100644 index 0000000..6f55329 --- /dev/null +++ b/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/topologies/ProcessedSpatDeduplicatorTopology.java @@ -0,0 +1,96 @@ +package us.dot.its.jpo.deduplicator.deduplicator.topologies; + +import org.apache.kafka.common.serialization.Serdes; +import org.apache.kafka.streams.KafkaStreams; +import org.apache.kafka.streams.StreamsBuilder; +import org.apache.kafka.streams.Topology; +import org.apache.kafka.streams.KafkaStreams.StateListener; +import org.apache.kafka.streams.errors.StreamsUncaughtExceptionHandler; + +import us.dot.its.jpo.deduplicator.DeduplicatorProperties; +import us.dot.its.jpo.geojsonconverter.DateJsonMapper; +import us.dot.its.jpo.deduplicator.deduplicator.processors.suppliers.ProcessedSpatProcessorSupplier; +import us.dot.its.jpo.geojsonconverter.pojos.spat.ProcessedSpat; +import us.dot.its.jpo.geojsonconverter.serialization.JsonSerdes; + +import org.apache.kafka.streams.kstream.*; +import org.apache.kafka.streams.state.Stores; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.databind.ObjectMapper; + +import java.time.format.DateTimeFormatter; +import java.util.Properties; + +public class ProcessedSpatDeduplicatorTopology { + + private static final Logger logger = LoggerFactory.getLogger(ProcessedSpatDeduplicatorTopology.class); + + Topology topology; + KafkaStreams streams; + String inputTopic; + String outputTopic; + Properties streamsProperties; + ObjectMapper objectMapper; + DateTimeFormatter formatter = DateTimeFormatter.ISO_INSTANT; + DeduplicatorProperties props; + + + public ProcessedSpatDeduplicatorTopology(DeduplicatorProperties props, Properties streamsProperties){ + this.props = props; + this.streamsProperties = streamsProperties; + this.objectMapper = DateJsonMapper.getInstance(); + } + + + + public void start() { + if (streams != null && streams.state().isRunningOrRebalancing()) { + throw new IllegalStateException("Start called while streams is already running."); + } + Topology topology = buildTopology(); + streams = new KafkaStreams(topology, streamsProperties); + if (exceptionHandler != null) streams.setUncaughtExceptionHandler(exceptionHandler); + if (stateListener != null) streams.setStateListener(stateListener); + logger.info("Starting Map Deduplicator Topology"); + streams.start(); + } + + public Topology buildTopology() { + StreamsBuilder builder = new StreamsBuilder(); + + KStream inputStream = builder.stream(props.getKafkaTopicProcessedSpat(), Consumed.with(Serdes.String(), JsonSerdes.ProcessedSpat())); + + builder.addStateStore(Stores.keyValueStoreBuilder(Stores.persistentKeyValueStore(props.getKafkaStateStoreProcessedSpatName()), + Serdes.String(), JsonSerdes.ProcessedSpat())); + + KStream deduplicatedStream = inputStream.process(new ProcessedSpatProcessorSupplier(props), props.getKafkaStateStoreProcessedSpatName()); + + + deduplicatedStream.to(props.getKafkaTopicDeduplicatedProcessedSpat(), Produced.with(Serdes.String(), JsonSerdes.ProcessedSpat())); + + return builder.build(); + + } + + public void stop() { + logger.info("Stopping Processed SPaT deduplicator Socket Broadcast Topology."); + if (streams != null) { + streams.close(); + streams.cleanUp(); + streams = null; + } + logger.info("Stopped Processed SPaT deduplicator Socket Broadcast Topology."); + } + + StateListener stateListener; + public void registerStateListener(StateListener stateListener) { + this.stateListener = stateListener; + } + + StreamsUncaughtExceptionHandler exceptionHandler; + public void registerUncaughtExceptionHandler(StreamsUncaughtExceptionHandler exceptionHandler) { + this.exceptionHandler = exceptionHandler; + } +} diff --git a/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/topologies/TimDeduplicatorTopology.java b/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/topologies/TimDeduplicatorTopology.java new file mode 100644 index 0000000..f128da9 --- /dev/null +++ b/jpo-deduplicator/src/main/java/us/dot/its/jpo/deduplicator/deduplicator/topologies/TimDeduplicatorTopology.java @@ -0,0 +1,126 @@ +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.geojsonconverter.DateJsonMapper; +import us.dot.its.jpo.ode.model.OdeTimData; +import us.dot.its.jpo.ode.model.OdeTimMetadata; +import us.dot.its.jpo.ode.plugin.j2735.travelerinformation.TravelerInformation; + +import org.apache.kafka.streams.kstream.*; +import org.apache.kafka.streams.state.Stores; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; + +import java.time.format.DateTimeFormatter; +import java.util.Properties; + +import us.dot.its.jpo.deduplicator.DeduplicatorProperties; +import us.dot.its.jpo.deduplicator.deduplicator.processors.suppliers.OdeTimJsonProcessorSupplier; +import us.dot.its.jpo.deduplicator.deduplicator.serialization.JsonSerdes; + + +public class TimDeduplicatorTopology { + + private static final Logger logger = LoggerFactory.getLogger(TimDeduplicatorTopology.class); + + Topology topology; + KafkaStreams streams; + Properties streamsProperties; + ObjectMapper objectMapper; + DateTimeFormatter formatter = DateTimeFormatter.ISO_INSTANT; + DeduplicatorProperties props; + + public TimDeduplicatorTopology(DeduplicatorProperties props, Properties streamsProperties) { + this.props = props; + this.streamsProperties = streamsProperties; + this.objectMapper = DateJsonMapper.getInstance(); + } + + public void start() { + if (streams != null && streams.state().isRunningOrRebalancing()) { + throw new IllegalStateException("Start called while streams is already running."); + } + Topology topology = buildTopology(); + streams = new KafkaStreams(topology, streamsProperties); + if (exceptionHandler != null) + streams.setUncaughtExceptionHandler(exceptionHandler); + if (stateListener != null) + streams.setStateListener(stateListener); + logger.info("Starting Tim Deduplicator Topology"); + streams.start(); + } + + public JsonNode genJsonNode() { + return objectMapper.createObjectNode(); + } + + + + public Topology buildTopology() { + StreamsBuilder builder = new StreamsBuilder(); + + KStream inputStream = builder.stream(props.getKafkaTopicOdeTimJson(), + Consumed.with(Serdes.String(), JsonSerdes.OdeTim())); + + builder.addStateStore(Stores.keyValueStoreBuilder(Stores.persistentKeyValueStore(props.getKafkaStateStoreOdeTimJsonName()), + Serdes.String(), JsonSerdes.OdeTim())); + + KStream timRekeyedStream = inputStream.selectKey((key, value) -> { + try { + + TravelerInformation travellerInformation = (TravelerInformation)value.getPayload().getData(); + + + String rsuIP = ((OdeTimMetadata)value.getMetadata()).getOriginIp(); + // String packetId = ((OdeTimPayload)value.getPayload()).getData();// .get("packetID").asText(); + String packetId = travellerInformation.getPacketID().toString(); + int msgCnt = travellerInformation.getMsgCnt().intValue(); + + String newKey = rsuIP + "_" + packetId + "_" + msgCnt; + return newKey; + } catch (Exception e) { + logger.error(e.toString()); + return ""; + } + }).repartition(Repartitioned.with(Serdes.String(), JsonSerdes.OdeTim())); + + KStream deduplicatedStream = timRekeyedStream.process(new OdeTimJsonProcessorSupplier(props), props.getKafkaStateStoreOdeTimJsonName()); + + deduplicatedStream.to(props.getKafkaTopicDeduplicatedOdeTimJson(), Produced.with(Serdes.String(), JsonSerdes.OdeTim())); + + return builder.build(); + + } + + public void stop() { + logger.info("Stopping Tim deduplicator Socket Broadcast Topology."); + if (streams != null) { + streams.close(); + streams.cleanUp(); + streams = null; + } + logger.info("Stopped Tim deduplicator Socket Broadcast Topology."); + } + + StateListener stateListener; + + public void registerStateListener(StateListener stateListener) { + this.stateListener = stateListener; + } + + StreamsUncaughtExceptionHandler exceptionHandler; + + public void registerUncaughtExceptionHandler(StreamsUncaughtExceptionHandler exceptionHandler) { + this.exceptionHandler = exceptionHandler; + } + +} diff --git a/jpo-deduplicator/src/main/resources/application.yaml b/jpo-deduplicator/src/main/resources/application.yaml new file mode 100644 index 0000000..7e01e98 --- /dev/null +++ b/jpo-deduplicator/src/main/resources/application.yaml @@ -0,0 +1,96 @@ +#General Properties +#================== +groupId: ^project.groupId^ +artifactId: ^project.artifactId^ +version: ^project.version^ +server.port: 8085 + +# Kafka properties +spring.kafka.bootstrap-servers: ${KAFKA_BOOTSTRAP_SERVERS:localhost:9092} +logging.level.org.apache.kafka: INFO +logging.level: INFO +log4j.logger.kafka: OFF +log4j.logger.org.apache.kafka: OFF + + + +# Processed Map Configuration +kafkaTopicProcessedMap: topic.ProcessedMap +kafkaTopicDeduplicatedProcessedMap: topic.DeduplicatedProcessedMap +enableProcessedMapDeduplication: ${ENABLE_PROCESSED_MAP_DEDUPLICATION:true} + +# Processed Map WKT Configuration +kafkaTopicProcessedMapWKT: topic.ProcessedMapWKT +kafkaTopicDeduplicatedProcessedMapWKT: topic.DeduplicatedProcessedMapWKT +enableProcessedMapWktDeduplication: ${ENABLE_PROCESSED_MAP_WKT_DEDUPLICATION:true} + +# Ode Map Json Configuration +kafkaTopicOdeMapJson: topic.OdeMapJson +kafkaTopicDeduplicatedOdeMapJson: topic.DeduplicatedOdeMapJson +enableOdeMapDeduplication: ${ENABLE_ODE_MAP_DEDUPLICATION:true} + +# Ode Tim Json Configuration +kafkaTopicOdeTimJson: topic.OdeTimJson +kafkaTopicDeduplicatedOdeTimJson: topic.DeduplicatedOdeTimJson +enableOdeTimDeduplication: ${ENABLE_ODE_TIM_DEDUPLICATION:true} + +# Ode Raw Encoded Tim Json Configuration +kafkaTopicOdeRawEncodedTimJson: topic.OdeRawEncodedTIMJson +kafkaTopicDeduplicatedOdeRawEncodedTimJson: topic.DeduplicatedOdeRawEncodedTIMJson +enableOdeRawEncodedTimDeduplication: ${ENABLE_ODE_RAW_ENCODED_TIM_DEDUPLICATION:true} + +# Ode Bsm Json Configuration +kafkaTopicOdeBsmJson: topic.OdeBsmJson +kafkaTopicDeduplicatedOdeBsmJson: topic.DeduplicatedOdeBsmJson +enableOdeBsmDeduplication: ${ENABLE_ODE_BSM_DEDUPLICATION:true} +odeBsmMaximumTimeDelta: 10000 # Milliseconds +odeBsmMaximumPositionDelta: 1 # Meter +odeBsmAlwaysIncludeAtSpeed: 1 # Meter / Second + +# Processed Map Configuration +kafkaTopicProcessedSpat: topic.ProcessedSpat +kafkaTopicDeduplicatedProcessedSpat: topic.DeduplicatedProcessedSpat +enableProcessedSpatDeduplication: ${ENABLE_PROCESSED_SPAT_DEDUPLICATION:true} + + +# Amount of time to wait to try and increase batching +kafka.linger_ms: 50 + +# Custom kafka properties +kafka.topics: + autoCreateTopics: true # Override auto-create in test properties + numPartitions: 1 + numReplicas: 1 + createTopics: + - name: ${kafkaTopicProcessedMap} + cleanupPolicy: delete + retentionMs: 300000 + - name: ${kafkaTopicDeduplicatedProcessedMap} + cleanupPolicy: delete + retentionMs: 300000 + - name: ${kafkaTopicProcessedMapWKT} + cleanupPolicy: delete + retentionMs: 300000 + - name: ${kafkaTopicDeduplicatedProcessedMapWKT} + cleanupPolicy: delete + retentionMs: 300000 + - name: ${kafkaTopicOdeMapJson} + cleanupPolicy: delete + retentionMs: 300000 + - name: ${kafkaTopicDeduplicatedOdeMapJson} + cleanupPolicy: delete + retentionMs: 300000 + - name: ${kafkaTopicOdeTimJson} + cleanupPolicy: delete + retentionMs: 300000 + - name: ${kafkaTopicDeduplicatedOdeTimJson} + cleanupPolicy: delete + retentionMs: 300000 + - name: ${kafkaTopicProcessedSpat} + cleanupPolicy: delete + retentionMs: 300000 + - name: ${kafkaTopicDeduplicatedProcessedSpat} + cleanupPolicy: delete + retentionMs: 300000 + + \ No newline at end of file diff --git a/jpo-deduplicator/src/main/resources/logback.xml b/jpo-deduplicator/src/main/resources/logback.xml new file mode 100644 index 0000000..860df15 --- /dev/null +++ b/jpo-deduplicator/src/main/resources/logback.xml @@ -0,0 +1,20 @@ + + + + + + + %date{"yyyy-MM-dd HH:mm:ss", UTC} [%thread] %-5level %logger{0} - %msg %n + + + + + + + + + + + + + diff --git a/jpo-deduplicator/src/test/java/deduplicator/BsmDeduplicatorTopologyTest.java b/jpo-deduplicator/src/test/java/deduplicator/BsmDeduplicatorTopologyTest.java new file mode 100644 index 0000000..adb1e95 --- /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\":\"EV\",\"logFileName\":\"\",\"recordType\":\"bsmTx\",\"securityResultCode\":\"success\",\"receivedMessageDetails\":{\"locationData\":{\"latitude\":\"unavailable\",\"longitude\":\"unavailable\",\"elevation\":\"unavailable\",\"speed\":\"unavailable\",\"heading\":\"unavailable\"},\"rxSource\":\"RSU\"},\"payloadType\":\"us.dot.its.jpo.ode.model.OdeBsmPayload\",\"serialId\":{\"streamId\":\"9bc470d1-babe-415b-8c5a-4cd4a9403350\",\"bundleSize\":1,\"bundleId\":0,\"recordId\":0,\"serialNumber\":0},\"odeReceivedAt\":\"2025-01-31T23:14:24.693Z\",\"schemaVersion\":8,\"maxDurationTime\":0,\"recordGeneratedAt\":\"\",\"recordGeneratedBy\":\"OBU\",\"sanitized\":false,\"odePacketID\":\"\",\"odeTimStartDateTime\":\"\",\"asn1\":\"001480B8494C4C950CD8CDE6E9651116579F22A424DD78FFFFF00761E4FD7EB7D07F7FFF80005F11D1020214C1C0FFC7C016AFF4017A0FF65403B0FD204C20FFCCC04F8FE40C420FFE6404CEFE60E9A10133408FCFDE1438103AB4138F00E1EEC1048EC160103E237410445C171104E26BC103DC4154305C2C84103B1C1C8F0A82F42103F34262D1123198103DAC25FB12034CE10381C259F12038CA103574251B10E3B2210324C23AD0F23D8EFFFE0000209340D10000004264BF00\",\"originIp\":\"172.20.0.1\"},\"payload\":{\"data\":{\"coreData\":{\"msgCnt\":37,\"id\":\"31325433\",\"secMark\":25399,\"position\":{\"latitude\":40.5659938,\"longitude\":-105.0317754,\"elevation\":1440.9},\"accelSet\":{\"accelLat\":0.00,\"accelLong\":0.27,\"accelVert\":0.00,\"accelYaw\":0.00},\"accuracy\":{\"semiMajor\":9.30,\"semiMinor\":12.05},\"transmission\":\"UNAVAILABLE\",\"speed\":0.28,\"heading\":313.2500,\"brakes\":{\"wheelBrakes\":{\"leftFront\":false,\"rightFront\":false,\"unavailable\":true,\"leftRear\":false,\"rightRear\":false},\"traction\":\"unavailable\",\"abs\":\"unavailable\",\"scs\":\"unavailable\",\"brakeBoost\":\"unavailable\",\"auxBrakes\":\"unavailable\"},\"size\":{\"width\":190,\"length\":570}},\"partII\":[{\"id\":\"VehicleSafetyExtensions\",\"value\":{\"pathHistory\":{\"crumbData\":[{\"elevationOffset\":-0.6,\"latOffset\":-0.0000113,\"lonOffset\":0.0000181,\"timeOffset\":1.90},{\"elevationOffset\":-2.3,\"latOffset\":-0.0000310,\"lonOffset\":0.0000472,\"timeOffset\":6.10},{\"elevationOffset\":-1.4,\"latOffset\":-0.0000103,\"lonOffset\":0.0000636,\"timeOffset\":15.70},{\"elevationOffset\":-1.3,\"latOffset\":-0.0000052,\"lonOffset\":0.0000615,\"timeOffset\":18.70},{\"elevationOffset\":-1.7,\"latOffset\":0.0000614,\"lonOffset\":0.0001150,\"timeOffset\":25.89},{\"elevationOffset\":0.7,\"latOffset\":0.0001878,\"lonOffset\":0.0002503,\"timeOffset\":39.59},{\"elevationOffset\":3.1,\"latOffset\":0.0002333,\"lonOffset\":0.0002816,\"timeOffset\":45.39},{\"elevationOffset\":3.9,\"latOffset\":0.0002187,\"lonOffset\":0.0002952,\"timeOffset\":49.59},{\"elevationOffset\":4.6,\"latOffset\":0.0001976,\"lonOffset\":0.0002721,\"timeOffset\":56.99},{\"elevationOffset\":8.4,\"latOffset\":0.0001891,\"lonOffset\":0.0003655,\"timeOffset\":60.50},{\"elevationOffset\":13.7,\"latOffset\":0.0002022,\"lonOffset\":0.0004886,\"timeOffset\":63.49},{\"elevationOffset\":14.4,\"latOffset\":0.0001973,\"lonOffset\":0.0004861,\"timeOffset\":67.60},{\"elevationOffset\":14.4,\"latOffset\":0.0001795,\"lonOffset\":0.0004815,\"timeOffset\":72.70},{\"elevationOffset\":13.5,\"latOffset\":0.0001710,\"lonOffset\":0.0004749,\"timeOffset\":75.70},{\"elevationOffset\":12.1,\"latOffset\":0.0001609,\"lonOffset\":0.0004566,\"timeOffset\":78.80}]},\"pathPrediction\":{\"confidence\":0.0,\"radiusOfCurve\":0.0}}},{\"id\":\"SupplementalVehicleExtensions\",\"value\":{\"classDetails\":{\"fuelType\":\"unknownFuel\",\"hpmsType\":\"none\",\"keyType\":0,\"role\":\"basicVehicle\"},\"vehicleData\":{\"height\":1.90},\"doNotUse2\":{}}}]},\"dataType\":\"us.dot.its.jpo.ode.plugin.j2735.J2735Bsm\"}}"; + + // Same as BSM 1 - No Message should be generated + String inputBsm2 = "{\"metadata\":{\"bsmSource\":\"EV\",\"logFileName\":\"\",\"recordType\":\"bsmTx\",\"securityResultCode\":\"success\",\"receivedMessageDetails\":{\"locationData\":{\"latitude\":\"unavailable\",\"longitude\":\"unavailable\",\"elevation\":\"unavailable\",\"speed\":\"unavailable\",\"heading\":\"unavailable\"},\"rxSource\":\"RSU\"},\"payloadType\":\"us.dot.its.jpo.ode.model.OdeBsmPayload\",\"serialId\":{\"streamId\":\"9bc470d1-babe-415b-8c5a-4cd4a9403350\",\"bundleSize\":1,\"bundleId\":0,\"recordId\":0,\"serialNumber\":0},\"odeReceivedAt\":\"2025-01-31T23:14:24.793Z\",\"schemaVersion\":8,\"maxDurationTime\":0,\"recordGeneratedAt\":\"\",\"recordGeneratedBy\":\"OBU\",\"sanitized\":false,\"odePacketID\":\"\",\"odeTimStartDateTime\":\"\",\"asn1\":\"001480B8494C4C950CD8CDE6E9651116579F22A424DD78FFFFF00761E4FD7EB7D07F7FFF80005F11D1020214C1C0FFC7C016AFF4017A0FF65403B0FD204C20FFCCC04F8FE40C420FFE6404CEFE60E9A10133408FCFDE1438103AB4138F00E1EEC1048EC160103E237410445C171104E26BC103DC4154305C2C84103B1C1C8F0A82F42103F34262D1123198103DAC25FB12034CE10381C259F12038CA103574251B10E3B2210324C23AD0F23D8EFFFE0000209340D10000004264BF00\",\"originIp\":\"172.20.0.1\"},\"payload\":{\"data\":{\"coreData\":{\"msgCnt\":37,\"id\":\"31325433\",\"secMark\":25399,\"position\":{\"latitude\":40.5659938,\"longitude\":-105.0317754,\"elevation\":1440.9},\"accelSet\":{\"accelLat\":0.00,\"accelLong\":0.27,\"accelVert\":0.00,\"accelYaw\":0.00},\"accuracy\":{\"semiMajor\":9.30,\"semiMinor\":12.05},\"transmission\":\"UNAVAILABLE\",\"speed\":0.28,\"heading\":313.2500,\"brakes\":{\"wheelBrakes\":{\"leftFront\":false,\"rightFront\":false,\"unavailable\":true,\"leftRear\":false,\"rightRear\":false},\"traction\":\"unavailable\",\"abs\":\"unavailable\",\"scs\":\"unavailable\",\"brakeBoost\":\"unavailable\",\"auxBrakes\":\"unavailable\"},\"size\":{\"width\":190,\"length\":570}},\"partII\":[{\"id\":\"VehicleSafetyExtensions\",\"value\":{\"pathHistory\":{\"crumbData\":[{\"elevationOffset\":-0.6,\"latOffset\":-0.0000113,\"lonOffset\":0.0000181,\"timeOffset\":1.90},{\"elevationOffset\":-2.3,\"latOffset\":-0.0000310,\"lonOffset\":0.0000472,\"timeOffset\":6.10},{\"elevationOffset\":-1.4,\"latOffset\":-0.0000103,\"lonOffset\":0.0000636,\"timeOffset\":15.70},{\"elevationOffset\":-1.3,\"latOffset\":-0.0000052,\"lonOffset\":0.0000615,\"timeOffset\":18.70},{\"elevationOffset\":-1.7,\"latOffset\":0.0000614,\"lonOffset\":0.0001150,\"timeOffset\":25.89},{\"elevationOffset\":0.7,\"latOffset\":0.0001878,\"lonOffset\":0.0002503,\"timeOffset\":39.59},{\"elevationOffset\":3.1,\"latOffset\":0.0002333,\"lonOffset\":0.0002816,\"timeOffset\":45.39},{\"elevationOffset\":3.9,\"latOffset\":0.0002187,\"lonOffset\":0.0002952,\"timeOffset\":49.59},{\"elevationOffset\":4.6,\"latOffset\":0.0001976,\"lonOffset\":0.0002721,\"timeOffset\":56.99},{\"elevationOffset\":8.4,\"latOffset\":0.0001891,\"lonOffset\":0.0003655,\"timeOffset\":60.50},{\"elevationOffset\":13.7,\"latOffset\":0.0002022,\"lonOffset\":0.0004886,\"timeOffset\":63.49},{\"elevationOffset\":14.4,\"latOffset\":0.0001973,\"lonOffset\":0.0004861,\"timeOffset\":67.60},{\"elevationOffset\":14.4,\"latOffset\":0.0001795,\"lonOffset\":0.0004815,\"timeOffset\":72.70},{\"elevationOffset\":13.5,\"latOffset\":0.0001710,\"lonOffset\":0.0004749,\"timeOffset\":75.70},{\"elevationOffset\":12.1,\"latOffset\":0.0001609,\"lonOffset\":0.0004566,\"timeOffset\":78.80}]},\"pathPrediction\":{\"confidence\":0.0,\"radiusOfCurve\":0.0}}},{\"id\":\"SupplementalVehicleExtensions\",\"value\":{\"classDetails\":{\"fuelType\":\"unknownFuel\",\"hpmsType\":\"none\",\"keyType\":0,\"role\":\"basicVehicle\"},\"vehicleData\":{\"height\":1.90},\"doNotUse2\":{}}}]},\"dataType\":\"us.dot.its.jpo.ode.plugin.j2735.J2735Bsm\"}}"; + + // Increase Time from Bsm 1 + String inputBsm3 = "{\"metadata\":{\"bsmSource\":\"EV\",\"logFileName\":\"\",\"recordType\":\"bsmTx\",\"securityResultCode\":\"success\",\"receivedMessageDetails\":{\"locationData\":{\"latitude\":\"unavailable\",\"longitude\":\"unavailable\",\"elevation\":\"unavailable\",\"speed\":\"unavailable\",\"heading\":\"unavailable\"},\"rxSource\":\"RSU\"},\"payloadType\":\"us.dot.its.jpo.ode.model.OdeBsmPayload\",\"serialId\":{\"streamId\":\"9bc470d1-babe-415b-8c5a-4cd4a9403350\",\"bundleSize\":1,\"bundleId\":0,\"recordId\":0,\"serialNumber\":0},\"odeReceivedAt\":\"2025-01-31T23:14:34.793Z\",\"schemaVersion\":8,\"maxDurationTime\":0,\"recordGeneratedAt\":\"\",\"recordGeneratedBy\":\"OBU\",\"sanitized\":false,\"odePacketID\":\"\",\"odeTimStartDateTime\":\"\",\"asn1\":\"001480B8494C4C950CD8CDE6E9651116579F22A424DD78FFFFF00761E4FD7EB7D07F7FFF80005F11D1020214C1C0FFC7C016AFF4017A0FF65403B0FD204C20FFCCC04F8FE40C420FFE6404CEFE60E9A10133408FCFDE1438103AB4138F00E1EEC1048EC160103E237410445C171104E26BC103DC4154305C2C84103B1C1C8F0A82F42103F34262D1123198103DAC25FB12034CE10381C259F12038CA103574251B10E3B2210324C23AD0F23D8EFFFE0000209340D10000004264BF00\",\"originIp\":\"172.20.0.1\"},\"payload\":{\"data\":{\"coreData\":{\"msgCnt\":37,\"id\":\"31325433\",\"secMark\":25399,\"position\":{\"latitude\":40.5659938,\"longitude\":-105.0317754,\"elevation\":1440.9},\"accelSet\":{\"accelLat\":0.00,\"accelLong\":0.27,\"accelVert\":0.00,\"accelYaw\":0.00},\"accuracy\":{\"semiMajor\":9.30,\"semiMinor\":12.05},\"transmission\":\"UNAVAILABLE\",\"speed\":0.28,\"heading\":313.2500,\"brakes\":{\"wheelBrakes\":{\"leftFront\":false,\"rightFront\":false,\"unavailable\":true,\"leftRear\":false,\"rightRear\":false},\"traction\":\"unavailable\",\"abs\":\"unavailable\",\"scs\":\"unavailable\",\"brakeBoost\":\"unavailable\",\"auxBrakes\":\"unavailable\"},\"size\":{\"width\":190,\"length\":570}},\"partII\":[{\"id\":\"VehicleSafetyExtensions\",\"value\":{\"pathHistory\":{\"crumbData\":[{\"elevationOffset\":-0.6,\"latOffset\":-0.0000113,\"lonOffset\":0.0000181,\"timeOffset\":1.90},{\"elevationOffset\":-2.3,\"latOffset\":-0.0000310,\"lonOffset\":0.0000472,\"timeOffset\":6.10},{\"elevationOffset\":-1.4,\"latOffset\":-0.0000103,\"lonOffset\":0.0000636,\"timeOffset\":15.70},{\"elevationOffset\":-1.3,\"latOffset\":-0.0000052,\"lonOffset\":0.0000615,\"timeOffset\":18.70},{\"elevationOffset\":-1.7,\"latOffset\":0.0000614,\"lonOffset\":0.0001150,\"timeOffset\":25.89},{\"elevationOffset\":0.7,\"latOffset\":0.0001878,\"lonOffset\":0.0002503,\"timeOffset\":39.59},{\"elevationOffset\":3.1,\"latOffset\":0.0002333,\"lonOffset\":0.0002816,\"timeOffset\":45.39},{\"elevationOffset\":3.9,\"latOffset\":0.0002187,\"lonOffset\":0.0002952,\"timeOffset\":49.59},{\"elevationOffset\":4.6,\"latOffset\":0.0001976,\"lonOffset\":0.0002721,\"timeOffset\":56.99},{\"elevationOffset\":8.4,\"latOffset\":0.0001891,\"lonOffset\":0.0003655,\"timeOffset\":60.50},{\"elevationOffset\":13.7,\"latOffset\":0.0002022,\"lonOffset\":0.0004886,\"timeOffset\":63.49},{\"elevationOffset\":14.4,\"latOffset\":0.0001973,\"lonOffset\":0.0004861,\"timeOffset\":67.60},{\"elevationOffset\":14.4,\"latOffset\":0.0001795,\"lonOffset\":0.0004815,\"timeOffset\":72.70},{\"elevationOffset\":13.5,\"latOffset\":0.0001710,\"lonOffset\":0.0004749,\"timeOffset\":75.70},{\"elevationOffset\":12.1,\"latOffset\":0.0001609,\"lonOffset\":0.0004566,\"timeOffset\":78.80}]},\"pathPrediction\":{\"confidence\":0.0,\"radiusOfCurve\":0.0}}},{\"id\":\"SupplementalVehicleExtensions\",\"value\":{\"classDetails\":{\"fuelType\":\"unknownFuel\",\"hpmsType\":\"none\",\"keyType\":0,\"role\":\"basicVehicle\"},\"vehicleData\":{\"height\":1.90},\"doNotUse2\":{}}}]},\"dataType\":\"us.dot.its.jpo.ode.plugin.j2735.J2735Bsm\"}}"; + + // Vehicle Speed not 0 + String inputBsm4 = "{\"metadata\":{\"bsmSource\":\"EV\",\"logFileName\":\"\",\"recordType\":\"bsmTx\",\"securityResultCode\":\"success\",\"receivedMessageDetails\":{\"locationData\":{\"latitude\":\"unavailable\",\"longitude\":\"unavailable\",\"elevation\":\"unavailable\",\"speed\":\"unavailable\",\"heading\":\"unavailable\"},\"rxSource\":\"RSU\"},\"payloadType\":\"us.dot.its.jpo.ode.model.OdeBsmPayload\",\"serialId\":{\"streamId\":\"9bc470d1-babe-415b-8c5a-4cd4a9403350\",\"bundleSize\":1,\"bundleId\":0,\"recordId\":0,\"serialNumber\":0},\"odeReceivedAt\":\"2025-01-31T23:14:34.893Z\",\"schemaVersion\":8,\"maxDurationTime\":0,\"recordGeneratedAt\":\"\",\"recordGeneratedBy\":\"OBU\",\"sanitized\":false,\"odePacketID\":\"\",\"odeTimStartDateTime\":\"\",\"asn1\":\"001480B8494C4C950CD8CDE6E9651116579F22A424DD78FFFFF00761E4FD7EB7D07F7FFF80005F11D1020214C1C0FFC7C016AFF4017A0FF65403B0FD204C20FFCCC04F8FE40C420FFE6404CEFE60E9A10133408FCFDE1438103AB4138F00E1EEC1048EC160103E237410445C171104E26BC103DC4154305C2C84103B1C1C8F0A82F42103F34262D1123198103DAC25FB12034CE10381C259F12038CA103574251B10E3B2210324C23AD0F23D8EFFFE0000209340D10000004264BF00\",\"originIp\":\"172.20.0.1\"},\"payload\":{\"data\":{\"coreData\":{\"msgCnt\":37,\"id\":\"31325433\",\"secMark\":25399,\"position\":{\"latitude\":40.5659938,\"longitude\":-105.0317754,\"elevation\":1440.9},\"accelSet\":{\"accelLat\":0.00,\"accelLong\":0.27,\"accelVert\":0.00,\"accelYaw\":0.00},\"accuracy\":{\"semiMajor\":9.30,\"semiMinor\":12.05},\"transmission\":\"UNAVAILABLE\",\"speed\":5,\"heading\":313.2500,\"brakes\":{\"wheelBrakes\":{\"leftFront\":false,\"rightFront\":false,\"unavailable\":true,\"leftRear\":false,\"rightRear\":false},\"traction\":\"unavailable\",\"abs\":\"unavailable\",\"scs\":\"unavailable\",\"brakeBoost\":\"unavailable\",\"auxBrakes\":\"unavailable\"},\"size\":{\"width\":190,\"length\":570}},\"partII\":[{\"id\":\"VehicleSafetyExtensions\",\"value\":{\"pathHistory\":{\"crumbData\":[{\"elevationOffset\":-0.6,\"latOffset\":-0.0000113,\"lonOffset\":0.0000181,\"timeOffset\":1.90},{\"elevationOffset\":-2.3,\"latOffset\":-0.0000310,\"lonOffset\":0.0000472,\"timeOffset\":6.10},{\"elevationOffset\":-1.4,\"latOffset\":-0.0000103,\"lonOffset\":0.0000636,\"timeOffset\":15.70},{\"elevationOffset\":-1.3,\"latOffset\":-0.0000052,\"lonOffset\":0.0000615,\"timeOffset\":18.70},{\"elevationOffset\":-1.7,\"latOffset\":0.0000614,\"lonOffset\":0.0001150,\"timeOffset\":25.89},{\"elevationOffset\":0.7,\"latOffset\":0.0001878,\"lonOffset\":0.0002503,\"timeOffset\":39.59},{\"elevationOffset\":3.1,\"latOffset\":0.0002333,\"lonOffset\":0.0002816,\"timeOffset\":45.39},{\"elevationOffset\":3.9,\"latOffset\":0.0002187,\"lonOffset\":0.0002952,\"timeOffset\":49.59},{\"elevationOffset\":4.6,\"latOffset\":0.0001976,\"lonOffset\":0.0002721,\"timeOffset\":56.99},{\"elevationOffset\":8.4,\"latOffset\":0.0001891,\"lonOffset\":0.0003655,\"timeOffset\":60.50},{\"elevationOffset\":13.7,\"latOffset\":0.0002022,\"lonOffset\":0.0004886,\"timeOffset\":63.49},{\"elevationOffset\":14.4,\"latOffset\":0.0001973,\"lonOffset\":0.0004861,\"timeOffset\":67.60},{\"elevationOffset\":14.4,\"latOffset\":0.0001795,\"lonOffset\":0.0004815,\"timeOffset\":72.70},{\"elevationOffset\":13.5,\"latOffset\":0.0001710,\"lonOffset\":0.0004749,\"timeOffset\":75.70},{\"elevationOffset\":12.1,\"latOffset\":0.0001609,\"lonOffset\":0.0004566,\"timeOffset\":78.80}]},\"pathPrediction\":{\"confidence\":0.0,\"radiusOfCurve\":0.0}}},{\"id\":\"SupplementalVehicleExtensions\",\"value\":{\"classDetails\":{\"fuelType\":\"unknownFuel\",\"hpmsType\":\"none\",\"keyType\":0,\"role\":\"basicVehicle\"},\"vehicleData\":{\"height\":1.90},\"doNotUse2\":{}}}]},\"dataType\":\"us.dot.its.jpo.ode.plugin.j2735.J2735Bsm\"}}"; + + // Vehicle Position has changed + String inputBsm5 = "{\"metadata\":{\"bsmSource\":\"EV\",\"logFileName\":\"\",\"recordType\":\"bsmTx\",\"securityResultCode\":\"success\",\"receivedMessageDetails\":{\"locationData\":{\"latitude\":\"unavailable\",\"longitude\":\"unavailable\",\"elevation\":\"unavailable\",\"speed\":\"unavailable\",\"heading\":\"unavailable\"},\"rxSource\":\"RSU\"},\"payloadType\":\"us.dot.its.jpo.ode.model.OdeBsmPayload\",\"serialId\":{\"streamId\":\"9bc470d1-babe-415b-8c5a-4cd4a9403350\",\"bundleSize\":1,\"bundleId\":0,\"recordId\":0,\"serialNumber\":0},\"odeReceivedAt\":\"2025-01-31T23:14:34.993Z\",\"schemaVersion\":8,\"maxDurationTime\":0,\"recordGeneratedAt\":\"\",\"recordGeneratedBy\":\"OBU\",\"sanitized\":false,\"odePacketID\":\"\",\"odeTimStartDateTime\":\"\",\"asn1\":\"001480B8494C4C950CD8CDE6E9651116579F22A424DD78FFFFF00761E4FD7EB7D07F7FFF80005F11D1020214C1C0FFC7C016AFF4017A0FF65403B0FD204C20FFCCC04F8FE40C420FFE6404CEFE60E9A10133408FCFDE1438103AB4138F00E1EEC1048EC160103E237410445C171104E26BC103DC4154305C2C84103B1C1C8F0A82F42103F34262D1123198103DAC25FB12034CE10381C259F12038CA103574251B10E3B2210324C23AD0F23D8EFFFE0000209340D10000004264BF00\",\"originIp\":\"172.20.0.1\"},\"payload\":{\"data\":{\"coreData\":{\"msgCnt\":37,\"id\":\"31325433\",\"secMark\":25399,\"position\":{\"latitude\":40.6659938,\"longitude\":-105.0317754,\"elevation\":1440.9},\"accelSet\":{\"accelLat\":0.00,\"accelLong\":0.27,\"accelVert\":0.00,\"accelYaw\":0.00},\"accuracy\":{\"semiMajor\":9.30,\"semiMinor\":12.05},\"transmission\":\"UNAVAILABLE\",\"speed\":0.28,\"heading\":313.2500,\"brakes\":{\"wheelBrakes\":{\"leftFront\":false,\"rightFront\":false,\"unavailable\":true,\"leftRear\":false,\"rightRear\":false},\"traction\":\"unavailable\",\"abs\":\"unavailable\",\"scs\":\"unavailable\",\"brakeBoost\":\"unavailable\",\"auxBrakes\":\"unavailable\"},\"size\":{\"width\":190,\"length\":570}},\"partII\":[{\"id\":\"VehicleSafetyExtensions\",\"value\":{\"pathHistory\":{\"crumbData\":[{\"elevationOffset\":-0.6,\"latOffset\":-0.0000113,\"lonOffset\":0.0000181,\"timeOffset\":1.90},{\"elevationOffset\":-2.3,\"latOffset\":-0.0000310,\"lonOffset\":0.0000472,\"timeOffset\":6.10},{\"elevationOffset\":-1.4,\"latOffset\":-0.0000103,\"lonOffset\":0.0000636,\"timeOffset\":15.70},{\"elevationOffset\":-1.3,\"latOffset\":-0.0000052,\"lonOffset\":0.0000615,\"timeOffset\":18.70},{\"elevationOffset\":-1.7,\"latOffset\":0.0000614,\"lonOffset\":0.0001150,\"timeOffset\":25.89},{\"elevationOffset\":0.7,\"latOffset\":0.0001878,\"lonOffset\":0.0002503,\"timeOffset\":39.59},{\"elevationOffset\":3.1,\"latOffset\":0.0002333,\"lonOffset\":0.0002816,\"timeOffset\":45.39},{\"elevationOffset\":3.9,\"latOffset\":0.0002187,\"lonOffset\":0.0002952,\"timeOffset\":49.59},{\"elevationOffset\":4.6,\"latOffset\":0.0001976,\"lonOffset\":0.0002721,\"timeOffset\":56.99},{\"elevationOffset\":8.4,\"latOffset\":0.0001891,\"lonOffset\":0.0003655,\"timeOffset\":60.50},{\"elevationOffset\":13.7,\"latOffset\":0.0002022,\"lonOffset\":0.0004886,\"timeOffset\":63.49},{\"elevationOffset\":14.4,\"latOffset\":0.0001973,\"lonOffset\":0.0004861,\"timeOffset\":67.60},{\"elevationOffset\":14.4,\"latOffset\":0.0001795,\"lonOffset\":0.0004815,\"timeOffset\":72.70},{\"elevationOffset\":13.5,\"latOffset\":0.0001710,\"lonOffset\":0.0004749,\"timeOffset\":75.70},{\"elevationOffset\":12.1,\"latOffset\":0.0001609,\"lonOffset\":0.0004566,\"timeOffset\":78.80}]},\"pathPrediction\":{\"confidence\":0.0,\"radiusOfCurve\":0.0}}},{\"id\":\"SupplementalVehicleExtensions\",\"value\":{\"classDetails\":{\"fuelType\":\"unknownFuel\",\"hpmsType\":\"none\",\"keyType\":0,\"role\":\"basicVehicle\"},\"vehicleData\":{\"height\":1.90},\"doNotUse2\":{}}}]},\"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 new file mode 100644 index 0000000..54aa14a --- /dev/null +++ b/jpo-deduplicator/src/test/java/deduplicator/MapDeduplicatorTopologyTest.java @@ -0,0 +1,115 @@ +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.Before; +import org.junit.Test; +import org.springframework.beans.factory.annotation.Autowired; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.ObjectMapper; + +import us.dot.its.jpo.deduplicator.DeduplicatorProperties; +import us.dot.its.jpo.deduplicator.deduplicator.topologies.MapDeduplicatorTopology; +import us.dot.its.jpo.geojsonconverter.serialization.JsonSerdes; +import us.dot.its.jpo.ode.model.OdeMapData; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.List; + + +public class MapDeduplicatorTopologyTest { + + String inputTopic = "topic.OdeMapJson"; + String outputTopic = "topic.DeduplicatedOdeMapJson"; + ObjectMapper objectMapper; + + String inputMap1 = ""; + String inputMap2 = ""; + String inputMap3 = ""; + String inputMap4 = ""; + + @Autowired + DeduplicatorProperties props; + + @Before + public void setup() throws IOException { + // Load test files from resources + + // Reference MAP + inputMap1 = new String(Files.readAllBytes(Paths.get("src/test/resources/json/map/sample.map-reference.json"))); + + // Duplicate of Number 1 + inputMap2 = new String(Files.readAllBytes(Paths.get("src/test/resources/json/map/sample.map-reference.json"))); + + // A different Message entirely + inputMap3 = new String(Files.readAllBytes(Paths.get("src/test/resources/json/map/sample.map-different.json"))); + + // Message 1 but 1 hour later + inputMap4 = new String(Files.readAllBytes(Paths.get("src/test/resources/json/map/sample.map-reference-1-hour-later.json"))); + } + + @Test + public void testTopology() { + + props = new DeduplicatorProperties(); + props.setKafkaTopicOdeMapJson(inputTopic); + props.setKafkaTopicDeduplicatedOdeMapJson(outputTopic); + + MapDeduplicatorTopology mapDeduplicatorTopology = new MapDeduplicatorTopology(props, null); + + Topology topology = mapDeduplicatorTopology.buildTopology(); + + try (TopologyTestDriver driver = new TopologyTestDriver(topology)) { + + + TestInputTopic inputOdeMapData = driver.createInputTopic( + inputTopic, + Serdes.Void().serializer(), + Serdes.String().serializer()); + + + TestOutputTopic outputOdeMapData = driver.createOutputTopic( + outputTopic, + Serdes.String().deserializer(), + JsonSerdes.OdeMap().deserializer()); + + inputOdeMapData.pipeInput(null, inputMap1); + inputOdeMapData.pipeInput(null, inputMap2); + inputOdeMapData.pipeInput(null, inputMap3); + inputOdeMapData.pipeInput(null, inputMap4); + + List> mapDeduplicationResults = outputOdeMapData.readKeyValuesToList(); + + // validate that only 3 messages make it through + assertEquals(3, mapDeduplicationResults.size()); + + objectMapper = new ObjectMapper(); + OdeMapData map1 = objectMapper.readValue(inputMap1, OdeMapData.class); + OdeMapData map3 = objectMapper.readValue(inputMap3, OdeMapData.class); + OdeMapData map4 = objectMapper.readValue(inputMap4, OdeMapData.class); + + + assertEquals(map1.getMetadata().getOdeReceivedAt(), mapDeduplicationResults.get(0).value.getMetadata().getOdeReceivedAt()); + assertEquals(map3.getMetadata().getOdeReceivedAt(), mapDeduplicationResults.get(1).value.getMetadata().getOdeReceivedAt()); + assertEquals(map4.getMetadata().getOdeReceivedAt(), mapDeduplicationResults.get(2).value.getMetadata().getOdeReceivedAt()); + + } catch (JsonMappingException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (JsonProcessingException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } +} \ No newline at end of file diff --git a/jpo-deduplicator/src/test/java/deduplicator/OdeRawEncodedTimDeduplicatorTopologyTest.java b/jpo-deduplicator/src/test/java/deduplicator/OdeRawEncodedTimDeduplicatorTopologyTest.java new file mode 100644 index 0000000..4b618d9 --- /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 new file mode 100644 index 0000000..6868cf0 --- /dev/null +++ b/jpo-deduplicator/src/test/java/deduplicator/ProcessedMapDeduplicatorTopologyTest.java @@ -0,0 +1,128 @@ +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.Before; +import org.junit.Test; +import org.springframework.beans.factory.annotation.Autowired; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; + +import us.dot.its.jpo.deduplicator.DeduplicatorProperties; +import us.dot.its.jpo.deduplicator.deduplicator.topologies.ProcessedMapDeduplicatorTopology; +import us.dot.its.jpo.geojsonconverter.pojos.geojson.LineString; +import us.dot.its.jpo.geojsonconverter.pojos.geojson.map.ProcessedMap; +import us.dot.its.jpo.geojsonconverter.serialization.JsonSerdes; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.List; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; + +public class ProcessedMapDeduplicatorTopologyTest { + + String inputTopic = "topic.ProcessedMap"; + String outputTopic = "topic.DeduplicatedProcessedMap"; + + + TypeReference> typeReference = new TypeReference<>(){}; + ObjectMapper objectMapper = new ObjectMapper(); + + // Reference MAP + String inputProcessedMap1 = ""; + + // Duplicate of Number 1 + String inputProcessedMap2 = ""; + + // A different Message entirely + String inputProcessedMap3 = ""; + + // Message 1 but 1 hour later + String inputProcessedMap4 = ""; + + + String key = "{\"rsuId\":\"10.11.81.12\",\"intersectionId\":12109,\"region\":-1}"; + + @Autowired + DeduplicatorProperties props; + + + @Before + public void setup() throws IOException { + // Load test files from resources + + // Reference MAP + inputProcessedMap1 = new String(Files.readAllBytes(Paths.get("src/test/resources/json/processed_map/sample.processed_map-reference.json"))); + + // Duplicate of Number 1 + inputProcessedMap2 = new String(Files.readAllBytes(Paths.get("src/test/resources/json/processed_map/sample.processed_map-reference.json"))); + + // A different Message entirely + inputProcessedMap3 = new String(Files.readAllBytes(Paths.get("src/test/resources/json/processed_map/sample.processed_map-different.json"))); + + // Message 1 but 1 hour later + inputProcessedMap4 = new String(Files.readAllBytes(Paths.get("src/test/resources/json/processed_map/sample.processed_map-reference-1-hour-later.json"))); + } + + + @Test + public void testTopology() { + + props = new DeduplicatorProperties(); + props.setKafkaTopicProcessedMap(inputTopic); + props.setKafkaTopicDeduplicatedProcessedMap(outputTopic); + + ProcessedMapDeduplicatorTopology processedMapDeduplicatorTopology = new ProcessedMapDeduplicatorTopology(props, null); + + Topology topology = processedMapDeduplicatorTopology.buildTopology(); + objectMapper.registerModule(new JavaTimeModule()); + + try (TopologyTestDriver driver = new TopologyTestDriver(topology)) { + + + TestInputTopic inputProcessedMapData = driver.createInputTopic( + inputTopic, + Serdes.String().serializer(), + Serdes.String().serializer()); + + + TestOutputTopic> outputProcessedMapData = driver.createOutputTopic( + outputTopic, + Serdes.String().deserializer(), + JsonSerdes.ProcessedMapGeoJson().deserializer()); + + inputProcessedMapData.pipeInput(key, inputProcessedMap1); + inputProcessedMapData.pipeInput(key, inputProcessedMap2); + inputProcessedMapData.pipeInput(key, inputProcessedMap3); + inputProcessedMapData.pipeInput(key, inputProcessedMap4); + + List>> mapDeduplicatorResults = outputProcessedMapData.readKeyValuesToList(); + + // validate that only 3 messages make it through + assertEquals(3, mapDeduplicatorResults.size()); + + ProcessedMap map1 = objectMapper.readValue(inputProcessedMap1, typeReference); + ProcessedMap map3 = objectMapper.readValue(inputProcessedMap3, typeReference); + ProcessedMap map4 = objectMapper.readValue(inputProcessedMap4, typeReference); + + assertEquals(map1.getProperties().getOdeReceivedAt(), mapDeduplicatorResults.get(0).value.getProperties().getOdeReceivedAt()); + assertEquals(map3.getProperties().getOdeReceivedAt(), mapDeduplicatorResults.get(1).value.getProperties().getOdeReceivedAt()); + assertEquals(map4.getProperties().getOdeReceivedAt(), mapDeduplicatorResults.get(2).value.getProperties().getOdeReceivedAt()); + + } catch (JsonMappingException e) { + e.printStackTrace(); + } catch (JsonProcessingException e) { + e.printStackTrace(); + } + } +} diff --git a/jpo-deduplicator/src/test/java/deduplicator/ProcessedMapWktDeduplicatorTopologyTest.java b/jpo-deduplicator/src/test/java/deduplicator/ProcessedMapWktDeduplicatorTopologyTest.java new file mode 100644 index 0000000..7709120 --- /dev/null +++ b/jpo-deduplicator/src/test/java/deduplicator/ProcessedMapWktDeduplicatorTopologyTest.java @@ -0,0 +1,129 @@ +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.Before; +import org.junit.Test; +import org.springframework.beans.factory.annotation.Autowired; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; + +import us.dot.its.jpo.deduplicator.DeduplicatorProperties; +import us.dot.its.jpo.deduplicator.deduplicator.topologies.ProcessedMapWktDeduplicatorTopology; +import us.dot.its.jpo.geojsonconverter.pojos.geojson.map.ProcessedMap; +import us.dot.its.jpo.geojsonconverter.serialization.JsonSerdes; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; + +import java.util.List; + +public class ProcessedMapWktDeduplicatorTopologyTest { + + String inputTopic = "topic.ProcessedMapWKT"; + String outputTopic = "topic.DeduplicatedProcessedMapWKT"; + + + + TypeReference> typeReference = new TypeReference<>(){}; + ObjectMapper objectMapper = new ObjectMapper(); + + // Reference MAP + String inputProcessedMapWkt1 = ""; + + // Duplicate of Number 1 + String inputProcessedMapWkt2 = ""; + + // A different Message entirely + String inputProcessedMapWkt3 = ""; + + // Message 1 but 1 hour later + String inputProcessedMapWkt4 = ""; + + String key = "{\"rsuId\":\"10.11.81.12\",\"intersectionId\":12109,\"region\":-1}"; + + @Autowired + DeduplicatorProperties props; + + + @Before + public void setup() throws IOException { + // Load test files from resources + + // Reference MAP + inputProcessedMapWkt1 = new String(Files.readAllBytes(Paths.get("src/test/resources/json/processed_map_wkt/sample.processed_map_wkt-reference.json"))); + + // Duplicate of Number 1 + inputProcessedMapWkt2 = new String(Files.readAllBytes(Paths.get("src/test/resources/json/processed_map_wkt/sample.processed_map_wkt-reference.json"))); + + // A different Message entirely + inputProcessedMapWkt3 = new String(Files.readAllBytes(Paths.get("src/test/resources/json/processed_map_wkt/sample.processed_map_wkt-different.json"))); + + // Message 1 but 1 hour later + inputProcessedMapWkt4 = new String(Files.readAllBytes(Paths.get("src/test/resources/json/processed_map_wkt/sample.processed_map_wkt-reference-1-hour-later.json"))); + } + + + @Test + public void testTopology() { + + props = new DeduplicatorProperties(); + props.setKafkaTopicProcessedMapWKT(inputTopic); + props.setKafkaTopicDeduplicatedProcessedMapWKT(outputTopic); + + ProcessedMapWktDeduplicatorTopology processedMapDeduplicatorTopology = new ProcessedMapWktDeduplicatorTopology(props, null); + + Topology topology = processedMapDeduplicatorTopology.buildTopology(); + objectMapper.registerModule(new JavaTimeModule()); + + try (TopologyTestDriver driver = new TopologyTestDriver(topology)) { + + + TestInputTopic inputProcessedMapData = driver.createInputTopic( + inputTopic, + Serdes.String().serializer(), + Serdes.String().serializer()); + + + TestOutputTopic> outputProcessedMapData = driver.createOutputTopic( + outputTopic, + Serdes.String().deserializer(), + JsonSerdes.ProcessedMapWKT().deserializer()); + + inputProcessedMapData.pipeInput(key, inputProcessedMapWkt1); + inputProcessedMapData.pipeInput(key, inputProcessedMapWkt2); + inputProcessedMapData.pipeInput(key, inputProcessedMapWkt3); + inputProcessedMapData.pipeInput(key, inputProcessedMapWkt4); + + List>> mapDeduplicatorResults = outputProcessedMapData.readKeyValuesToList(); + + // validate that only 3 messages make it through + assertEquals(3, mapDeduplicatorResults.size()); + + ProcessedMap map1 = objectMapper.readValue(inputProcessedMapWkt1, typeReference); + ProcessedMap map2 = objectMapper.readValue(inputProcessedMapWkt2, typeReference); + ProcessedMap map4 = objectMapper.readValue(inputProcessedMapWkt4, typeReference); + + assertEquals(map1.getProperties().getOdeReceivedAt(), mapDeduplicatorResults.get(0).value.getProperties().getOdeReceivedAt()); + assertEquals(map2.getProperties().getOdeReceivedAt(), mapDeduplicatorResults.get(1).value.getProperties().getOdeReceivedAt()); + assertEquals(map4.getProperties().getOdeReceivedAt(), mapDeduplicatorResults.get(2).value.getProperties().getOdeReceivedAt()); + + + + } catch (JsonMappingException e) { + e.printStackTrace(); + } catch (JsonProcessingException e) { + e.printStackTrace(); + } + } +} diff --git a/jpo-deduplicator/src/test/java/deduplicator/ProcessedSpatDeduplicatorTopologyTest.java b/jpo-deduplicator/src/test/java/deduplicator/ProcessedSpatDeduplicatorTopologyTest.java new file mode 100644 index 0000000..047c629 --- /dev/null +++ b/jpo-deduplicator/src/test/java/deduplicator/ProcessedSpatDeduplicatorTopologyTest.java @@ -0,0 +1,117 @@ +package deduplicator; + +import org.apache.kafka.common.serialization.Serdes; +import org.apache.kafka.streams.KeyValue; +import org.apache.kafka.streams.TestInputTopic; +import org.apache.kafka.streams.TestOutputTopic; +import org.apache.kafka.streams.Topology; +import org.apache.kafka.streams.TopologyTestDriver; +import org.junit.Test; +import org.springframework.beans.factory.annotation.Autowired; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; + +import us.dot.its.jpo.deduplicator.DeduplicatorProperties; +import us.dot.its.jpo.deduplicator.deduplicator.topologies.ProcessedSpatDeduplicatorTopology; +import us.dot.its.jpo.geojsonconverter.pojos.spat.ProcessedSpat; +import us.dot.its.jpo.geojsonconverter.serialization.JsonSerdes; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.List; + + +public class ProcessedSpatDeduplicatorTopologyTest { + + String inputTopic = "topic.ProcessedSpat"; + String outputTopic = "topic.DeduplicatedProcessedSpat"; + + + TypeReference typeReference = new TypeReference<>(){}; + ObjectMapper objectMapper = new ObjectMapper(); + + // Reference Message + String inputProcessedSpat1 = "{\"schemaVersion\":1,\"messageType\":\"SPAT\",\"odeReceivedAt\":\"2025-02-01T00:04:56.686Z\",\"originIp\":\"172.20.0.1\",\"intersectionId\":12111,\"cti4501Conformant\":false,\"validationMessages\":[{\"message\":\"$.payload.data.timeStamp: is missing but it is required\",\"jsonPath\":\"$.payload.data\",\"schemaPath\":\"#/$defs/J2735SPAT/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\"}],\"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\":\"2025-02-01T00:04:35.176Z\",\"states\":[{\"signalGroup\":2,\"stateTimeSpeed\":[{\"eventState\":\"PROTECTED_MOVEMENT_ALLOWED\",\"timing\":{\"minEndTime\":\"2025-02-01T00:36:52Z\",\"maxEndTime\":\"2025-02-01T00:36:52.1Z\"}}]},{\"signalGroup\":4,\"stateTimeSpeed\":[{\"eventState\":\"STOP_AND_REMAIN\",\"timing\":{\"minEndTime\":\"2025-02-01T00:36:58.1Z\",\"maxEndTime\":\"2025-02-01T00:36:58.1Z\"}}]},{\"signalGroup\":6,\"stateTimeSpeed\":[{\"eventState\":\"PROTECTED_MOVEMENT_ALLOWED\",\"timing\":{\"minEndTime\":\"2025-02-01T00:36:52Z\",\"maxEndTime\":\"2025-02-01T00:36:52.1Z\"}}]},{\"signalGroup\":8,\"stateTimeSpeed\":[{\"eventState\":\"STOP_AND_REMAIN\",\"timing\":{\"minEndTime\":\"2025-02-01T00:36:25.2Z\",\"maxEndTime\":\"2025-02-01T00:36:25.2Z\"}}]},{\"signalGroup\":1,\"stateTimeSpeed\":[{\"eventState\":\"STOP_AND_REMAIN\",\"timing\":{\"minEndTime\":\"2025-02-01T00:36:25.2Z\",\"maxEndTime\":\"2025-02-01T00:36:25.2Z\"}}]},{\"signalGroup\":5,\"stateTimeSpeed\":[{\"eventState\":\"STOP_AND_REMAIN\",\"timing\":{\"minEndTime\":\"2025-02-01T00:36:25.2Z\",\"maxEndTime\":\"2025-02-01T00:36:25.2Z\"}}]}]}"; + + // Deduplicated Message - Same as Reference. + String inputProcessedSpat2 = "{\"schemaVersion\":1,\"messageType\":\"SPAT\",\"odeReceivedAt\":\"2025-02-01T00:05:56.686Z\",\"originIp\":\"172.20.0.1\",\"intersectionId\":12111,\"cti4501Conformant\":false,\"validationMessages\":[{\"message\":\"$.payload.data.timeStamp: is missing but it is required\",\"jsonPath\":\"$.payload.data\",\"schemaPath\":\"#/$defs/J2735SPAT/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\"}],\"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\":\"2025-02-01T00:04:35.276Z\",\"states\":[{\"signalGroup\":2,\"stateTimeSpeed\":[{\"eventState\":\"PROTECTED_MOVEMENT_ALLOWED\",\"timing\":{\"minEndTime\":\"2025-02-01T00:36:52Z\",\"maxEndTime\":\"2025-02-01T00:36:52.1Z\"}}]},{\"signalGroup\":4,\"stateTimeSpeed\":[{\"eventState\":\"STOP_AND_REMAIN\",\"timing\":{\"minEndTime\":\"2025-02-01T00:36:58.1Z\",\"maxEndTime\":\"2025-02-01T00:36:58.1Z\"}}]},{\"signalGroup\":6,\"stateTimeSpeed\":[{\"eventState\":\"PROTECTED_MOVEMENT_ALLOWED\",\"timing\":{\"minEndTime\":\"2025-02-01T00:36:52Z\",\"maxEndTime\":\"2025-02-01T00:36:52.1Z\"}}]},{\"signalGroup\":8,\"stateTimeSpeed\":[{\"eventState\":\"STOP_AND_REMAIN\",\"timing\":{\"minEndTime\":\"2025-02-01T00:36:25.2Z\",\"maxEndTime\":\"2025-02-01T00:36:25.2Z\"}}]},{\"signalGroup\":1,\"stateTimeSpeed\":[{\"eventState\":\"STOP_AND_REMAIN\",\"timing\":{\"minEndTime\":\"2025-02-01T00:36:25.2Z\",\"maxEndTime\":\"2025-02-01T00:36:25.2Z\"}}]},{\"signalGroup\":5,\"stateTimeSpeed\":[{\"eventState\":\"STOP_AND_REMAIN\",\"timing\":{\"minEndTime\":\"2025-02-01T00:36:25.2Z\",\"maxEndTime\":\"2025-02-01T00:36:25.2Z\"}}]}]}"; + + // Fast forward 1 minute + String inputProcessedSpat3 = "{\"schemaVersion\":1,\"messageType\":\"SPAT\",\"odeReceivedAt\":\"2025-02-01T00:05:57.686Z\",\"originIp\":\"172.20.0.1\",\"intersectionId\":12111,\"cti4501Conformant\":false,\"validationMessages\":[{\"message\":\"$.payload.data.timeStamp: is missing but it is required\",\"jsonPath\":\"$.payload.data\",\"schemaPath\":\"#/$defs/J2735SPAT/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\"}],\"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\":\"2025-02-01T00:05:36.376Z\",\"states\":[{\"signalGroup\":2,\"stateTimeSpeed\":[{\"eventState\":\"PROTECTED_MOVEMENT_ALLOWED\",\"timing\":{\"minEndTime\":\"2025-02-01T00:36:52Z\",\"maxEndTime\":\"2025-02-01T00:36:52.1Z\"}}]},{\"signalGroup\":4,\"stateTimeSpeed\":[{\"eventState\":\"STOP_AND_REMAIN\",\"timing\":{\"minEndTime\":\"2025-02-01T00:36:58.1Z\",\"maxEndTime\":\"2025-02-01T00:36:58.1Z\"}}]},{\"signalGroup\":6,\"stateTimeSpeed\":[{\"eventState\":\"PROTECTED_MOVEMENT_ALLOWED\",\"timing\":{\"minEndTime\":\"2025-02-01T00:36:52Z\",\"maxEndTime\":\"2025-02-01T00:36:52.1Z\"}}]},{\"signalGroup\":8,\"stateTimeSpeed\":[{\"eventState\":\"STOP_AND_REMAIN\",\"timing\":{\"minEndTime\":\"2025-02-01T00:36:25.2Z\",\"maxEndTime\":\"2025-02-01T00:36:25.2Z\"}}]},{\"signalGroup\":1,\"stateTimeSpeed\":[{\"eventState\":\"STOP_AND_REMAIN\",\"timing\":{\"minEndTime\":\"2025-02-01T00:36:25.2Z\",\"maxEndTime\":\"2025-02-01T00:36:25.2Z\"}}]},{\"signalGroup\":5,\"stateTimeSpeed\":[{\"eventState\":\"STOP_AND_REMAIN\",\"timing\":{\"minEndTime\":\"2025-02-01T00:36:25.2Z\",\"maxEndTime\":\"2025-02-01T00:36:25.2Z\"}}]}]}"; + + // Remove a Signal Group + String inputProcessedSpat4 = "{\"schemaVersion\":1,\"messageType\":\"SPAT\",\"odeReceivedAt\":\"2025-02-01T00:05:56.686Z\",\"originIp\":\"172.20.0.1\",\"intersectionId\":12111,\"cti4501Conformant\":false,\"validationMessages\":[{\"message\":\"$.payload.data.timeStamp: is missing but it is required\",\"jsonPath\":\"$.payload.data\",\"schemaPath\":\"#/$defs/J2735SPAT/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\"}],\"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\":\"2025-02-01T00:05:36.496Z\",\"states\":[{\"signalGroup\":2,\"stateTimeSpeed\":[{\"eventState\":\"PROTECTED_MOVEMENT_ALLOWED\",\"timing\":{\"minEndTime\":\"2025-02-01T00:36:52Z\",\"maxEndTime\":\"2025-02-01T00:36:52.1Z\"}}]},{\"signalGroup\":4,\"stateTimeSpeed\":[{\"eventState\":\"STOP_AND_REMAIN\",\"timing\":{\"minEndTime\":\"2025-02-01T00:36:58.1Z\",\"maxEndTime\":\"2025-02-01T00:36:58.1Z\"}}]},{\"signalGroup\":6,\"stateTimeSpeed\":[{\"eventState\":\"PROTECTED_MOVEMENT_ALLOWED\",\"timing\":{\"minEndTime\":\"2025-02-01T00:36:52Z\",\"maxEndTime\":\"2025-02-01T00:36:52.1Z\"}}]},{\"signalGroup\":8,\"stateTimeSpeed\":[{\"eventState\":\"STOP_AND_REMAIN\",\"timing\":{\"minEndTime\":\"2025-02-01T00:36:25.2Z\",\"maxEndTime\":\"2025-02-01T00:36:25.2Z\"}}]},{\"signalGroup\":1,\"stateTimeSpeed\":[{\"eventState\":\"STOP_AND_REMAIN\",\"timing\":{\"minEndTime\":\"2025-02-01T00:36:25.2Z\",\"maxEndTime\":\"2025-02-01T00:36:25.2Z\"}}]}]}"; + + // Change the ID of a Signal Group + String inputProcessedSpat5 = "{\"schemaVersion\":1,\"messageType\":\"SPAT\",\"odeReceivedAt\":\"2025-02-01T00:05:56.686Z\",\"originIp\":\"172.20.0.1\",\"intersectionId\":12111,\"cti4501Conformant\":false,\"validationMessages\":[{\"message\":\"$.payload.data.timeStamp: is missing but it is required\",\"jsonPath\":\"$.payload.data\",\"schemaPath\":\"#/$defs/J2735SPAT/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\"}],\"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\":\"2025-02-01T00:05:35.576Z\",\"states\":[{\"signalGroup\":2,\"stateTimeSpeed\":[{\"eventState\":\"PROTECTED_MOVEMENT_ALLOWED\",\"timing\":{\"minEndTime\":\"2025-02-01T00:36:52Z\",\"maxEndTime\":\"2025-02-01T00:36:52.1Z\"}}]},{\"signalGroup\":4,\"stateTimeSpeed\":[{\"eventState\":\"STOP_AND_REMAIN\",\"timing\":{\"minEndTime\":\"2025-02-01T00:36:58.1Z\",\"maxEndTime\":\"2025-02-01T00:36:58.1Z\"}}]},{\"signalGroup\":6,\"stateTimeSpeed\":[{\"eventState\":\"PROTECTED_MOVEMENT_ALLOWED\",\"timing\":{\"minEndTime\":\"2025-02-01T00:36:52Z\",\"maxEndTime\":\"2025-02-01T00:36:52.1Z\"}}]},{\"signalGroup\":8,\"stateTimeSpeed\":[{\"eventState\":\"STOP_AND_REMAIN\",\"timing\":{\"minEndTime\":\"2025-02-01T00:36:25.2Z\",\"maxEndTime\":\"2025-02-01T00:36:25.2Z\"}}]},{\"signalGroup\":1,\"stateTimeSpeed\":[{\"eventState\":\"STOP_AND_REMAIN\",\"timing\":{\"minEndTime\":\"2025-02-01T00:36:25.2Z\",\"maxEndTime\":\"2025-02-01T00:36:25.2Z\"}}]},{\"signalGroup\":7,\"stateTimeSpeed\":[{\"eventState\":\"STOP_AND_REMAIN\",\"timing\":{\"minEndTime\":\"2025-02-01T00:36:25.2Z\",\"maxEndTime\":\"2025-02-01T00:36:25.2Z\"}}]}]}"; + + // Change the Light State of one of the Signal Groups + String inputProcessedSpat6 = "{\"schemaVersion\":1,\"messageType\":\"SPAT\",\"odeReceivedAt\":\"2025-02-01T00:05:56.686Z\",\"originIp\":\"172.20.0.1\",\"intersectionId\":12111,\"cti4501Conformant\":false,\"validationMessages\":[{\"message\":\"$.payload.data.timeStamp: is missing but it is required\",\"jsonPath\":\"$.payload.data\",\"schemaPath\":\"#/$defs/J2735SPAT/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\"}],\"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\":\"2025-02-01T00:05:35.676Z\",\"states\":[{\"signalGroup\":2,\"stateTimeSpeed\":[{\"eventState\":\"PROTECTED_MOVEMENT_ALLOWED\",\"timing\":{\"minEndTime\":\"2025-02-01T00:36:52Z\",\"maxEndTime\":\"2025-02-01T00:36:52.1Z\"}}]},{\"signalGroup\":4,\"stateTimeSpeed\":[{\"eventState\":\"STOP_AND_REMAIN\",\"timing\":{\"minEndTime\":\"2025-02-01T00:36:58.1Z\",\"maxEndTime\":\"2025-02-01T00:36:58.1Z\"}}]},{\"signalGroup\":6,\"stateTimeSpeed\":[{\"eventState\":\"PROTECTED_MOVEMENT_ALLOWED\",\"timing\":{\"minEndTime\":\"2025-02-01T00:36:52Z\",\"maxEndTime\":\"2025-02-01T00:36:52.1Z\"}}]},{\"signalGroup\":8,\"stateTimeSpeed\":[{\"eventState\":\"STOP_AND_REMAIN\",\"timing\":{\"minEndTime\":\"2025-02-01T00:36:25.2Z\",\"maxEndTime\":\"2025-02-01T00:36:25.2Z\"}}]},{\"signalGroup\":1,\"stateTimeSpeed\":[{\"eventState\":\"PROTECTED_MOVEMENT_ALLOWED\",\"timing\":{\"minEndTime\":\"2025-02-01T00:36:25.2Z\",\"maxEndTime\":\"2025-02-01T00:36:25.2Z\"}}]},{\"signalGroup\":5,\"stateTimeSpeed\":[{\"eventState\":\"STOP_AND_REMAIN\",\"timing\":{\"minEndTime\":\"2025-02-01T00:36:25.2Z\",\"maxEndTime\":\"2025-02-01T00:36:25.2Z\"}}]}]}"; + + String key = "{\"rsuId\": \"10.164.6.16\", \"intersectionId\": 6311, \"region\": -1}"; + + @Autowired + DeduplicatorProperties props; + + + @Test + public void testTopology() { + + props = new DeduplicatorProperties(); + props.setKafkaTopicProcessedSpat(inputTopic); + props.setKafkaTopicDeduplicatedProcessedSpat(outputTopic); + + ProcessedSpatDeduplicatorTopology processedSpatDeduplicatorTopology = new ProcessedSpatDeduplicatorTopology(props, null); + + Topology topology = processedSpatDeduplicatorTopology.buildTopology(); + objectMapper.registerModule(new JavaTimeModule()); + + try (TopologyTestDriver driver = new TopologyTestDriver(topology)) { + + + TestInputTopic inputProcessedSpatData = driver.createInputTopic( + inputTopic, + Serdes.String().serializer(), + Serdes.String().serializer()); + + + TestOutputTopic outputProcessedSpatData = driver.createOutputTopic( + outputTopic, + Serdes.String().deserializer(), + JsonSerdes.ProcessedSpat().deserializer()); + + inputProcessedSpatData.pipeInput(key, inputProcessedSpat1); + inputProcessedSpatData.pipeInput(key, inputProcessedSpat2); + inputProcessedSpatData.pipeInput(key, inputProcessedSpat3); + inputProcessedSpatData.pipeInput(key, inputProcessedSpat4); + inputProcessedSpatData.pipeInput(key, inputProcessedSpat5); + inputProcessedSpatData.pipeInput(key, inputProcessedSpat6); + + List> spatDeduplicatorResults = outputProcessedSpatData.readKeyValuesToList(); + + // validate that only 5 messages make it through + assertEquals(5, spatDeduplicatorResults.size()); + + ProcessedSpat spat1 = objectMapper.readValue(inputProcessedSpat1, typeReference); + ProcessedSpat spat3 = objectMapper.readValue(inputProcessedSpat3, typeReference); // forwarded because the time on the message changes by 1 minute + ProcessedSpat spat4 = objectMapper.readValue(inputProcessedSpat4, typeReference); // forwarded because the signal state changes + ProcessedSpat spat5 = objectMapper.readValue(inputProcessedSpat5, typeReference); // forwarded because the number of signal groups changed + ProcessedSpat spat6 = objectMapper.readValue(inputProcessedSpat6, typeReference); // forwarded because a signal group ID changed + + assertEquals(spat1.getUtcTimeStamp(), spatDeduplicatorResults.get(0).value.getUtcTimeStamp()); + assertEquals(spat3.getUtcTimeStamp(), spatDeduplicatorResults.get(1).value.getUtcTimeStamp()); + assertEquals(spat4.getUtcTimeStamp(), spatDeduplicatorResults.get(2).value.getUtcTimeStamp()); + assertEquals(spat5.getUtcTimeStamp(), spatDeduplicatorResults.get(3).value.getUtcTimeStamp()); + assertEquals(spat6.getUtcTimeStamp(), spatDeduplicatorResults.get(4).value.getUtcTimeStamp()); + + + } catch (JsonMappingException e) { + e.printStackTrace(); + } catch (JsonProcessingException e) { + e.printStackTrace(); + } + } +} diff --git a/jpo-deduplicator/src/test/java/deduplicator/TimDeduplicatorTopologyTest.java b/jpo-deduplicator/src/test/java/deduplicator/TimDeduplicatorTopologyTest.java new file mode 100644 index 0000000..fd6d3e9 --- /dev/null +++ b/jpo-deduplicator/src/test/java/deduplicator/TimDeduplicatorTopologyTest.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.TimDeduplicatorTopology; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.List; + + +public class TimDeduplicatorTopologyTest { + + String inputTopic = "topic.OdeTimJson"; + String outputTopic = "topic.DeduplicatedOdeTimJson"; + + ObjectMapper objectMapper = new ObjectMapper(); + + //Original Message + String inputTim1 = "{\"metadata\":{\"logFileName\":\"\",\"recordType\":\"timMsg\",\"securityResultCode\":\"success\",\"receivedMessageDetails\":{\"rxSource\":\"NA\"},\"payloadType\":\"us.dot.its.jpo.ode.model.OdeTimPayload\",\"serialId\":{\"streamId\":\"b2d15f2d-7461-4083-b3df-b4efadab4d17\",\"bundleSize\":1,\"bundleId\":0,\"recordId\":0,\"serialNumber\":0},\"odeReceivedAt\":\"2025-02-01T00:19:45.739Z\",\"schemaVersion\":8,\"maxDurationTime\":0,\"recordGeneratedAt\":\"\",\"recordGeneratedBy\":\"RSU\",\"sanitized\":false,\"odePacketID\":\"\",\"odeTimStartDateTime\":\"\",\"asn1\":\"001F83A175D472274F43544554205354520A4C16B18193D0D1F9CDF54733FB1BFC0C983FCFC48D24FF97A474B8A754A9112A6F690200192EFCB5FF96D90FA32D4E83FC0C9830B5F5FC150A5059C545235AC20227C697080018815F84759CB3BF452C850424643A30E028544E9C511560A9DD8C2629F0D4470DBB3DDB4316096FC100800809BC746A108C8F26FC4C3208DA0E61091B7429182D3BFC0C98359EA8B4B454C16E606F037AE007A1CDE32000152E6C0ECDF612A90558D403FC049BF003734AC1C240EC930B39E850A7990A808008C033EFC47606FDDFA252B4A9942280C1020C9D818700EC4B4A76680C001D9F981240013111914408214602F8173D850A0D48F09F5D75264929260B5A7D27260B5A65260B56744F43999104E394B5204FF09260B5A7D3E32C5F74A0DB09EA975B8C1724DC92D9201005800092D84A89EF67BC1B27429C710979A5FE0E4C16B4F5EE874A08F2404C40AA60E2A09E79F91602003E5DB0AA9B32A2E0A6F36507F829305ACEE93E6B134C1CCC3C2EF3FA5CB5D02ECE000142002950BD8FB7D02D26BB6CAFCB848BE4A9260B5A7D29260B5A7D19D28125C17566972EA98F7172471344010153D0C21C1D69E158731BFC1C982D69E2E4FEDB544A012D60EDDB5D7569995CCC001CB02000CB8B449E02D39DB1072106F80B79BFC14982D666D178E4A198A3579B12B09915D01723B0000A10002A973AEAF40B82284427D9124DFE024F9230F8DD6AD73490518F80A3B259CF3FC40014001266976FBC88CB08E20EE8AD087EC16463A2B7AC5E62CB83FC9C830B7275F28A3128CDB2491AFF05260B580BDABD3249C784B718EFDC1906727B228001160002B10C89FAF5F0E9BA4F0AC74920F4947402561EBFB6201930424BF9E8112A39CA22519425D8E01001A7A1E0222723B864CB17F849305AD3E92E6884164E2CE7F0A6BD84FE4E38949D300081A01A290029F8111120048308876C910829B04B5148014FC9621814460542FAA24A460FBF82D2CF1A8CE66032A7E6A0807028A04283228610217947C12CE3FFF20CA031F809A2007D242408F0B4510F23D2A2646294D48A41F4F8494C87B58CCFE2983829A707069C17A4BBF23992859B3A528C03ACD3506FF07260B5A7BBA7391E53AAABAA44EA1584A857727A910002C0020391DD0DEDC78D916CBD8D839D52DABDB084919305C975AABA210D2D0CDF7A0ABC1000D3D0D9D071298F916D83FC049B2CFCF26A78A5951B5CC28075CAF1EAC780042808048EB0ADE229537A0161356A3A68175E5809621740382083BEDD5810921240\",\"originIp\":\"172.20.0.1\"},\"payload\":{\"data\":{\"msgCnt\":93,\"timeStamp\":291367,\"packetID\":\"4F4354455420535452\",\"urlB\":\"IA5\",\"dataFrames\":[{\"doNotUse1\":0,\"frameType\":\"commercialSignage\",\"msgId\":{\"furtherInfoID\":\"4F43\"},\"startYear\":1150,\"startTime\":473045,\"durationTime\":3687,\"priority\":7,\"doNotUse2\":22,\"regions\":[{\"name\":\"IA\",\"id\":{\"region\":64764,\"id\":18642},\"anchor\":{\"lat\":172032029,\"long\":-1025506517,\"elevation\":13386},\"laneWidth\":19949,\"directionality\":\"unavailable\",\"closedPath\":true,\"direction\":{\"from000-0to022-5degrees\":false,\"from022-5to045-0degrees\":false,\"from045-0to067-5degrees\":false,\"from067-5to090-0degrees\":false,\"from090-0to112-5degrees\":false,\"from112-5to135-0degrees\":false,\"from135-0to157-5degrees\":true,\"from157-5to180-0degrees\":false,\"from180-0to202-5degrees\":false,\"from202-5to225-0degrees\":false,\"from225-0to247-5degrees\":false,\"from247-5to270-0degrees\":false,\"from270-0to292-5degrees\":false,\"from292-5to315-0degrees\":false,\"from315-0to337-5degrees\":false,\"from337-5to360-0degrees\":false},\"description\":{\"path\":{\"scale\":9,\"offset\":{\"xy\":{\"computed\":{\"referenceLaneId\":252,\"offsetXaxis\":{\"large\":-5120},\"offsetYaxis\":{\"small\":-585},\"rotateXY\":8692,\"scaleXaxis\":-422,\"scaleYaxis\":464}}}}}},{\"name\":\"IA\",\"id\":{\"region\":2911,\"id\":24513},\"anchor\":{\"lat\":217001329,\"long\":-436271951,\"elevation\":28809},\"laneWidth\":30930,\"directionality\":\"both\",\"closedPath\":true,\"direction\":{\"from000-0to022-5degrees\":false,\"from022-5to045-0degrees\":false,\"from045-0to067-5degrees\":false,\"from067-5to090-0degrees\":false,\"from090-0to112-5degrees\":true,\"from112-5to135-0degrees\":false,\"from135-0to157-5degrees\":false,\"from157-5to180-0degrees\":false,\"from180-0to202-5degrees\":false,\"from202-5to225-0degrees\":false,\"from225-0to247-5degrees\":false,\"from247-5to270-0degrees\":false,\"from270-0to292-5degrees\":false,\"from292-5to315-0degrees\":false,\"from315-0to337-5degrees\":false,\"from337-5to360-0degrees\":false},\"description\":{\"path\":{\"scale\":8,\"offset\":{\"ll\":{\"nodes\":[{\"delta\":{\"node-LL4\":{\"lon\":115258,\"lat\":80231}},\"attributes\":{\"localNode\":[\"curbPresentAtStepOff\",\"hydrantPresent\",\"mergePoint\",\"divergePoint\",\"reserved\"],\"disabled\":[\"transitStopOnRight\",\"adaptiveTimingPresent\",\"loadingzoneOnLeft\",\"costToPark\"],\"enabled\":[\"curbOnLeft\"],\"data\":[{\"speedLimits\":[{\"type\":\"truckNightMaxSpeed\",\"speed\":6769},{\"type\":\"truckMaxSpeed\",\"speed\":4438},{\"type\":\"maxSpeedInSchoolZone\",\"speed\":2679},{\"type\":\"vehiclesWithTrailersNightMaxSpeed\",\"speed\":3110},{\"type\":\"vehicleMaxSpeed\",\"speed\":1987}]}],\"dWidth\":-188,\"dElevation\":-61}},{\"delta\":{\"node-LL6\":{\"lon\":5893850,\"lat\":-6770613}},\"attributes\":{\"localNode\":[\"closedToTraffic\"],\"disabled\":[\"bikeBoxInFront\"],\"enabled\":[\"mergingLaneRight\"],\"data\":[{\"laneCrownPointLeft\":-17}],\"dWidth\":-396,\"dElevation\":-88}},{\"delta\":{\"node-LL1\":{\"lon\":-924,\"lat\":-109}},\"attributes\":{\"localNode\":[\"downstreamStopLine\",\"roundedCapStyleB\"],\"disabled\":[\"whiteLine\",\"partialCurbIntrusion\"],\"enabled\":[\"loadingzoneOnLeft\",\"audibleSignalingPresent\",\"freeParking\"],\"data\":[{\"laneCrownPointCenter\":55},{\"laneAngle\":-98}],\"dWidth\":-319,\"dElevation\":-89}}]}}}}},{\"name\":\"IA\",\"id\":{\"region\":23018,\"id\":35659},\"anchor\":{\"lat\":-544509288,\"long\":-1334375239,\"elevation\":-3608},\"laneWidth\":14780,\"directionality\":\"forward\",\"closedPath\":true,\"direction\":{\"from000-0to022-5degrees\":false,\"from022-5to045-0degrees\":false,\"from045-0to067-5degrees\":true,\"from067-5to090-0degrees\":false,\"from090-0to112-5degrees\":false,\"from112-5to135-0degrees\":false,\"from135-0to157-5degrees\":false,\"from157-5to180-0degrees\":false,\"from180-0to202-5degrees\":false,\"from202-5to225-0degrees\":false,\"from225-0to247-5degrees\":false,\"from247-5to270-0degrees\":false,\"from270-0to292-5degrees\":false,\"from292-5to315-0degrees\":false,\"from315-0to337-5degrees\":false,\"from337-5to360-0degrees\":false},\"description\":{\"path\":{\"scale\":5,\"offset\":{\"xy\":{\"computed\":{\"referenceLaneId\":108,\"offsetXaxis\":{\"small\":-1574},\"offsetYaxis\":{\"large\":-635},\"rotateXY\":21792,\"scaleXaxis\":689,\"scaleYaxis\":640}}}}}},{\"name\":\"I\",\"id\":{\"region\":32256,\"id\":28265},\"anchor\":{\"lat\":725366646,\"long\":-566506763,\"elevation\":6227},\"laneWidth\":26178,\"directionality\":\"reverse\",\"closedPath\":true,\"direction\":{\"from000-0to022-5degrees\":false,\"from022-5to045-0degrees\":false,\"from045-0to067-5degrees\":false,\"from067-5to090-0degrees\":false,\"from090-0to112-5degrees\":false,\"from112-5to135-0degrees\":false,\"from135-0to157-5degrees\":false,\"from157-5to180-0degrees\":true,\"from180-0to202-5degrees\":false,\"from202-5to225-0degrees\":false,\"from225-0to247-5degrees\":false,\"from247-5to270-0degrees\":false,\"from270-0to292-5degrees\":false,\"from292-5to315-0degrees\":false,\"from315-0to337-5degrees\":false,\"from337-5to360-0degrees\":false},\"description\":{\"path\":{\"scale\":1,\"offset\":{\"ll\":{\"nodes\":[{\"delta\":{\"node-LL5\":{\"lon\":2030663,\"lat\":-517129}},\"attributes\":{\"localNode\":[\"safeIsland\",\"hydrantPresent\",\"curbPresentAtStepOff\"],\"disabled\":[\"sharedWithTrackedVehicle\",\"transitStopOnLeft\",\"headInParking\",\"audibleSignalingPresent\"],\"enabled\":[\"doNotBlock\",\"mergingLaneLeft\"],\"data\":[{\"laneCrownPointRight\":48},{\"laneCrownPointRight\":-114}],\"dWidth\":-505,\"dElevation\":-119}},{\"delta\":{\"node-LL6\":{\"lon\":-5645920,\"lat\":-5242762}},\"attributes\":{\"localNode\":[\"reserved\",\"safeIsland\",\"mergePoint\"],\"disabled\":[\"turnOutPointOnLeft\"],\"enabled\":[\"timeRestrictionsOnParking\",\"adaptiveTimingPresent\",\"turnOutPointOnRight\",\"bikeBoxInFront\"],\"data\":[{\"laneCrownPointCenter\":-58},{\"pathEndPointAngle\":-55},{\"pathEndPointAngle\":-58}],\"dWidth\":472,\"dElevation\":-190}}]}}}}}],\"doNotUse3\":16,\"doNotUse4\":13,\"content\":{\"genericSign\":[{\"item\":{\"itis\":61599}},{\"item\":{\"itis\":47850}},{\"item\":{\"itis\":39204}},{\"item\":{\"text\":\"IA5St\"}},{\"item\":{\"text\":\"IA5S\"}}]},\"url\":\"IA5\"},{\"doNotUse1\":7,\"frameType\":\"roadSignage\",\"msgId\":{\"furtherInfoID\":\"4F43\"},\"startYear\":2457,\"startTime\":66787,\"durationTime\":19034,\"priority\":4,\"doNotUse2\":16,\"regions\":[{\"name\":\"IA5St\",\"id\":{\"region\":61846,\"id\":12218},\"anchor\":{\"lat\":202451669,\"long\":-1016248785,\"elevation\":14777},\"laneWidth\":4825,\"directionality\":\"unavailable\",\"closedPath\":true,\"direction\":{\"from000-0to022-5degrees\":false,\"from022-5to045-0degrees\":false,\"from045-0to067-5degrees\":false,\"from067-5to090-0degrees\":false,\"from090-0to112-5degrees\":false,\"from112-5to135-0degrees\":false,\"from135-0to157-5degrees\":false,\"from157-5to180-0degrees\":false,\"from180-0to202-5degrees\":true,\"from202-5to225-0degrees\":false,\"from225-0to247-5degrees\":false,\"from247-5to270-0degrees\":false,\"from270-0to292-5degrees\":false,\"from292-5to315-0degrees\":false,\"from315-0to337-5degrees\":false,\"from337-5to360-0degrees\":false},\"description\":{\"geometry\":{\"direction\":{\"from000-0to022-5degrees\":false,\"from022-5to045-0degrees\":false,\"from045-0to067-5degrees\":false,\"from067-5to090-0degrees\":false,\"from090-0to112-5degrees\":false,\"from112-5to135-0degrees\":false,\"from135-0to157-5degrees\":false,\"from157-5to180-0degrees\":false,\"from180-0to202-5degrees\":false,\"from202-5to225-0degrees\":false,\"from225-0to247-5degrees\":false,\"from247-5to270-0degrees\":false,\"from270-0to292-5degrees\":false,\"from292-5to315-0degrees\":false,\"from315-0to337-5degrees\":true,\"from337-5to360-0degrees\":false},\"extent\":\"useFor100meters\",\"laneWidth\":23305,\"circle\":{\"center\":{\"lat\":257084126,\"long\":-1572221105,\"elevation\":10372},\"radius\":3021,\"units\":\"cm2-5\"}}}},{\"name\":\"IA5S\",\"id\":{\"region\":44916,\"id\":14928},\"anchor\":{\"lat\":-391962488,\"long\":-1442690475,\"elevation\":975},\"laneWidth\":8081,\"directionality\":\"forward\",\"closedPath\":true,\"direction\":{\"from000-0to022-5degrees\":false,\"from022-5to045-0degrees\":false,\"from045-0to067-5degrees\":false,\"from067-5to090-0degrees\":false,\"from090-0to112-5degrees\":false,\"from112-5to135-0degrees\":false,\"from135-0to157-5degrees\":false,\"from157-5to180-0degrees\":true,\"from180-0to202-5degrees\":false,\"from202-5to225-0degrees\":false,\"from225-0to247-5degrees\":false,\"from247-5to270-0degrees\":false,\"from270-0to292-5degrees\":false,\"from292-5to315-0degrees\":false,\"from315-0to337-5degrees\":false,\"from337-5to360-0degrees\":false},\"description\":{\"path\":{\"scale\":15,\"offset\":{\"xy\":{\"computed\":{\"referenceLaneId\":216,\"offsetXaxis\":{\"small\":682},\"offsetYaxis\":{\"large\":-6571},\"rotateXY\":11786,\"scaleXaxis\":-269,\"scaleYaxis\":-432}}}}}},{\"name\":\"IA5\",\"id\":{\"region\":15268,\"id\":63916},\"anchor\":{\"lat\":-14883901,\"long\":1470459302,\"elevation\":47965},\"laneWidth\":374,\"directionality\":\"forward\",\"closedPath\":true,\"direction\":{\"from000-0to022-5degrees\":true,\"from022-5to045-0degrees\":false,\"from045-0to067-5degrees\":false,\"from067-5to090-0degrees\":false,\"from090-0to112-5degrees\":false,\"from112-5to135-0degrees\":false,\"from135-0to157-5degrees\":false,\"from157-5to180-0degrees\":false,\"from180-0to202-5degrees\":false,\"from202-5to225-0degrees\":false,\"from225-0to247-5degrees\":false,\"from247-5to270-0degrees\":false,\"from270-0to292-5degrees\":false,\"from292-5to315-0degrees\":false,\"from315-0to337-5degrees\":false,\"from337-5to360-0degrees\":false},\"description\":{\"oldRegion\":{\"direction\":{\"from000-0to022-5degrees\":false,\"from022-5to045-0degrees\":false,\"from045-0to067-5degrees\":false,\"from067-5to090-0degrees\":false,\"from090-0to112-5degrees\":true,\"from112-5to135-0degrees\":false,\"from135-0to157-5degrees\":false,\"from157-5to180-0degrees\":false,\"from180-0to202-5degrees\":false,\"from202-5to225-0degrees\":false,\"from225-0to247-5degrees\":false,\"from247-5to270-0degrees\":false,\"from270-0to292-5degrees\":false,\"from292-5to315-0degrees\":false,\"from315-0to337-5degrees\":false,\"from337-5to360-0degrees\":false},\"extent\":\"useFor100000meters\",\"area\":{\"circle\":{\"center\":{\"lat\":223434207,\"long\":-714422034,\"elevation\":41663},\"radius\":737,\"units\":\"cm2-5\"}}}}}],\"doNotUse3\":2,\"doNotUse4\":31,\"content\":{\"workZone\":[{\"item\":{\"text\":\"IA5St\"}},{\"item\":{\"text\":\"IA5St\"}},{\"item\":{\"itis\":52884}}]},\"url\":\"I\"},{\"doNotUse1\":16,\"frameType\":\"roadSignage\",\"msgId\":{\"roadSignID\":{\"position\":{\"lat\":604037802,\"long\":-124613998,\"elevation\":46289},\"viewAngle\":{\"from000-0to022-5degrees\":false,\"from022-5to045-0degrees\":false,\"from045-0to067-5degrees\":false,\"from067-5to090-0degrees\":false,\"from090-0to112-5degrees\":false,\"from112-5to135-0degrees\":false,\"from135-0to157-5degrees\":false,\"from157-5to180-0degrees\":false,\"from180-0to202-5degrees\":false,\"from202-5to225-0degrees\":true,\"from225-0to247-5degrees\":false,\"from247-5to270-0degrees\":false,\"from270-0to292-5degrees\":false,\"from292-5to315-0degrees\":false,\"from315-0to337-5degrees\":false,\"from337-5to360-0degrees\":false},\"mutcdCode\":\"guide\",\"crc\":\"4F43\"}},\"startYear\":135,\"startTime\":30119,\"durationTime\":17072,\"priority\":7,\"doNotUse2\":6,\"regions\":[{\"name\":\"IA5S\",\"id\":{\"region\":35731,\"id\":64365},\"anchor\":{\"lat\":251341270,\"long\":-1550588968,\"elevation\":18073},\"laneWidth\":19174,\"directionality\":\"forward\",\"closedPath\":true,\"direction\":{\"from000-0to022-5degrees\":false,\"from022-5to045-0degrees\":false,\"from045-0to067-5degrees\":false,\"from067-5to090-0degrees\":false,\"from090-0to112-5degrees\":false,\"from112-5to135-0degrees\":false,\"from135-0to157-5degrees\":false,\"from157-5to180-0degrees\":false,\"from180-0to202-5degrees\":false,\"from202-5to225-0degrees\":false,\"from225-0to247-5degrees\":false,\"from247-5to270-0degrees\":false,\"from270-0to292-5degrees\":false,\"from292-5to315-0degrees\":true,\"from315-0to337-5degrees\":true,\"from337-5to360-0degrees\":true},\"description\":{\"geometry\":{\"direction\":{\"from000-0to022-5degrees\":false,\"from022-5to045-0degrees\":false,\"from045-0to067-5degrees\":false,\"from067-5to090-0degrees\":false,\"from090-0to112-5degrees\":false,\"from112-5to135-0degrees\":true,\"from135-0to157-5degrees\":false,\"from157-5to180-0degrees\":false,\"from180-0to202-5degrees\":false,\"from202-5to225-0degrees\":false,\"from225-0to247-5degrees\":false,\"from247-5to270-0degrees\":false,\"from270-0to292-5degrees\":false,\"from292-5to315-0degrees\":false,\"from315-0to337-5degrees\":false,\"from337-5to360-0degrees\":false},\"extent\":\"useFor3meters\",\"laneWidth\":19339,\"circle\":{\"center\":{\"lat\":-590142898,\"long\":192563845,\"elevation\":3040},\"radius\":734,\"units\":\"meter\"}}}},{\"name\":\"IA5\",\"id\":{\"region\":13160,\"id\":48242},\"anchor\":{\"lat\":227302831,\"long\":-891580621,\"elevation\":7072},\"laneWidth\":5923,\"directionality\":\"reverse\",\"closedPath\":true,\"direction\":{\"from000-0to022-5degrees\":true,\"from022-5to045-0degrees\":false,\"from045-0to067-5degrees\":false,\"from067-5to090-0degrees\":false,\"from090-0to112-5degrees\":false,\"from112-5to135-0degrees\":false,\"from135-0to157-5degrees\":false,\"from157-5to180-0degrees\":false,\"from180-0to202-5degrees\":false,\"from202-5to225-0degrees\":false,\"from225-0to247-5degrees\":false,\"from247-5to270-0degrees\":false,\"from270-0to292-5degrees\":false,\"from292-5to315-0degrees\":false,\"from315-0to337-5degrees\":false,\"from337-5to360-0degrees\":false},\"description\":{\"oldRegion\":{\"direction\":{\"from000-0to022-5degrees\":false,\"from022-5to045-0degrees\":false,\"from045-0to067-5degrees\":false,\"from067-5to090-0degrees\":false,\"from090-0to112-5degrees\":true,\"from112-5to135-0degrees\":false,\"from135-0to157-5degrees\":false,\"from157-5to180-0degrees\":false,\"from180-0to202-5degrees\":false,\"from202-5to225-0degrees\":false,\"from225-0to247-5degrees\":false,\"from247-5to270-0degrees\":false,\"from270-0to292-5degrees\":false,\"from292-5to315-0degrees\":false,\"from315-0to337-5degrees\":false,\"from337-5to360-0degrees\":false},\"extent\":\"useFor3meters\",\"area\":{\"circle\":{\"center\":{\"lat\":368610426,\"long\":-1703460317,\"elevation\":1004},\"radius\":2194,\"units\":\"meter\"}}}}},{\"name\":\"I\",\"id\":{\"region\":58508,\"id\":15927},\"anchor\":{\"lat\":892488592,\"long\":-431640924,\"elevation\":41561},\"laneWidth\":26527,\"directionality\":\"both\",\"closedPath\":true,\"direction\":{\"from000-0to022-5degrees\":false,\"from022-5to045-0degrees\":false,\"from045-0to067-5degrees\":false,\"from067-5to090-0degrees\":true,\"from090-0to112-5degrees\":false,\"from112-5to135-0degrees\":false,\"from135-0to157-5degrees\":false,\"from157-5to180-0degrees\":false,\"from180-0to202-5degrees\":false,\"from202-5to225-0degrees\":false,\"from225-0to247-5degrees\":false,\"from247-5to270-0degrees\":false,\"from270-0to292-5degrees\":false,\"from292-5to315-0degrees\":false,\"from315-0to337-5degrees\":false,\"from337-5to360-0degrees\":false},\"description\":{\"oldRegion\":{\"direction\":{\"from000-0to022-5degrees\":false,\"from022-5to045-0degrees\":false,\"from045-0to067-5degrees\":false,\"from067-5to090-0degrees\":false,\"from090-0to112-5degrees\":false,\"from112-5to135-0degrees\":false,\"from135-0to157-5degrees\":false,\"from157-5to180-0degrees\":false,\"from180-0to202-5degrees\":false,\"from202-5to225-0degrees\":false,\"from225-0to247-5degrees\":false,\"from247-5to270-0degrees\":false,\"from270-0to292-5degrees\":false,\"from292-5to315-0degrees\":true,\"from315-0to337-5degrees\":false,\"from337-5to360-0degrees\":false},\"extent\":\"useFor50000meters\",\"area\":{\"regionPointSet\":{\"anchor\":{\"lat\":-113602543,\"long\":717746718,\"elevation\":49498},\"scale\":1,\"nodeList\":[{\"xOffset\":27670,\"yOffset\":-14790,\"zOffset\":-21638},{\"xOffset\":3020,\"yOffset\":-9872,\"zOffset\":-109},{\"xOffset\":-24382,\"yOffset\":23709,\"zOffset\":-862},{\"xOffset\":-26476,\"yOffset\":-6439,\"zOffset\":-23411}]}}}}},{\"name\":\"IA5\",\"id\":{\"region\":379,\"id\":22438},\"anchor\":{\"lat\":-281093797,\"long\":556669965,\"elevation\":29497},\"laneWidth\":7880,\"directionality\":\"reverse\",\"closedPath\":true,\"direction\":{\"from000-0to022-5degrees\":false,\"from022-5to045-0degrees\":false,\"from045-0to067-5degrees\":false,\"from067-5to090-0degrees\":false,\"from090-0to112-5degrees\":false,\"from112-5to135-0degrees\":false,\"from135-0to157-5degrees\":false,\"from157-5to180-0degrees\":false,\"from180-0to202-5degrees\":false,\"from202-5to225-0degrees\":false,\"from225-0to247-5degrees\":false,\"from247-5to270-0degrees\":false,\"from270-0to292-5degrees\":false,\"from292-5to315-0degrees\":false,\"from315-0to337-5degrees\":true,\"from337-5to360-0degrees\":false},\"description\":{\"geometry\":{\"direction\":{\"from000-0to022-5degrees\":false,\"from022-5to045-0degrees\":false,\"from045-0to067-5degrees\":false,\"from067-5to090-0degrees\":false,\"from090-0to112-5degrees\":false,\"from112-5to135-0degrees\":false,\"from135-0to157-5degrees\":false,\"from157-5to180-0degrees\":false,\"from180-0to202-5degrees\":false,\"from202-5to225-0degrees\":false,\"from225-0to247-5degrees\":false,\"from247-5to270-0degrees\":false,\"from270-0to292-5degrees\":false,\"from292-5to315-0degrees\":false,\"from315-0to337-5degrees\":true,\"from337-5to360-0degrees\":false},\"extent\":\"useFor500000meters\",\"laneWidth\":2148,\"circle\":{\"center\":{\"lat\":163173661,\"long\":-872411303,\"elevation\":55588},\"radius\":489,\"units\":\"cm2-5\"}}}}],\"doNotUse3\":8,\"doNotUse4\":29,\"content\":{\"advisory\":[{\"item\":{\"itis\":44093}},{\"item\":{\"itis\":65240}},{\"item\":{\"text\":\"IA\"}}]},\"url\":\"I\"},{\"doNotUse1\":31,\"frameType\":\"advisory\",\"msgId\":{\"roadSignID\":{\"position\":{\"lat\":-864002503,\"long\":-654286715,\"elevation\":43804},\"viewAngle\":{\"from000-0to022-5degrees\":false,\"from022-5to045-0degrees\":false,\"from045-0to067-5degrees\":false,\"from067-5to090-0degrees\":false,\"from090-0to112-5degrees\":false,\"from112-5to135-0degrees\":false,\"from135-0to157-5degrees\":true,\"from157-5to180-0degrees\":false,\"from180-0to202-5degrees\":false,\"from202-5to225-0degrees\":false,\"from225-0to247-5degrees\":false,\"from247-5to270-0degrees\":false,\"from270-0to292-5degrees\":false,\"from292-5to315-0degrees\":false,\"from315-0to337-5degrees\":false,\"from337-5to360-0degrees\":false},\"mutcdCode\":\"maintenance\",\"crc\":\"4F43\"}},\"startYear\":3076,\"startTime\":282183,\"durationTime\":14436,\"priority\":6,\"doNotUse2\":11,\"regions\":[{\"name\":\"IA5St\",\"id\":{\"region\":11880,\"id\":33814},\"anchor\":{\"lat\":51295938,\"long\":799818234,\"elevation\":10466},\"laneWidth\":10554,\"directionality\":\"forward\",\"closedPath\":true,\"direction\":{\"from000-0to022-5degrees\":false,\"from022-5to045-0degrees\":false,\"from045-0to067-5degrees\":false,\"from067-5to090-0degrees\":false,\"from090-0to112-5degrees\":false,\"from112-5to135-0degrees\":false,\"from135-0to157-5degrees\":false,\"from157-5to180-0degrees\":false,\"from180-0to202-5degrees\":false,\"from202-5to225-0degrees\":false,\"from225-0to247-5degrees\":false,\"from247-5to270-0degrees\":false,\"from270-0to292-5degrees\":true,\"from292-5to315-0degrees\":false,\"from315-0to337-5degrees\":false,\"from337-5to360-0degrees\":false},\"description\":{\"path\":{\"scale\":10,\"offset\":{\"xy\":{\"nodes\":[{\"delta\":{\"node-XY1\":{\"x\":144,\"y\":-502}},\"attributes\":{\"localNode\":[\"mergePoint\"],\"disabled\":[\"transitStopOnLeft\",\"bikeBoxInFront\",\"doNotBlock\"],\"enabled\":[\"mergingLaneLeft\",\"mergingLaneRight\"],\"data\":[{\"laneCrownPointCenter\":91},{\"laneCrownPointLeft\":-60},{\"laneCrownPointLeft\":-118}],\"dWidth\":-80,\"dElevation\":-211}},{\"delta\":{\"node-XY1\":{\"x\":144,\"y\":-502}},\"attributes\":{\"localNode\":[\"hydrantPresent\",\"roundedCapStyleA\",\"roundedCapStyleB\"],\"disabled\":[\"turnOutPointOnRight\"],\"enabled\":[\"adjacentParkingOnRight\",\"curbOnLeft\"],\"data\":[{\"laneCrownPointCenter\":-3},{\"laneCrownPointCenter\":-23},{\"speedLimits\":[{\"type\":\"vehicleMinSpeed\",\"speed\":5260},{\"type\":\"maxSpeedInConstructionZone\",\"speed\":7676}]}],\"dWidth\":-98,\"dElevation\":-300}},{\"delta\":{\"node-XY5\":{\"x\":6552,\"y\":-7382}},\"attributes\":{\"localNode\":[\"curbPresentAtStepOff\",\"stopLine\",\"reserved\",\"roundedCapStyleB\"],\"disabled\":[\"curbOnLeft\",\"turnOutPointOnRight\",\"whiteLine\",\"curbOnRight\"],\"enabled\":[\"sharedWithTrackedVehicle\",\"audibleSignalingPresent\",\"headInParking\"],\"data\":[{\"laneCrownPointCenter\":-7},{\"laneAngle\":68},{\"laneCrownPointLeft\":-39}],\"dWidth\":287,\"dElevation\":510}},{\"delta\":{\"node-XY1\":{\"x\":-310,\"y\":-500}},\"attributes\":{\"localNode\":[\"roundedCapStyleA\"],\"disabled\":[\"timeRestrictionsOnParking\",\"reserved\",\"parallelParking\",\"midBlockCurbPresent\"],\"enabled\":[\"transitStopOnRight\",\"whiteLine\",\"taperToCenterLine\",\"adjacentParkingOnLeft\",\"timeRestrictionsOnParking\"],\"data\":[{\"laneAngle\":-59},{\"laneCrownPointCenter\":105},{\"laneCrownPointCenter\":25},{\"speedLimits\":[{\"type\":\"vehicleNightMaxSpeed\",\"speed\":2245},{\"type\":\"vehicleMaxSpeed\",\"speed\":1700}]},{\"speedLimits\":[{\"type\":\"maxSpeedInSchoolZone\",\"speed\":7839},{\"type\":\"maxSpeedInSchoolZone\",\"speed\":1190},{\"type\":\"truckMaxSpeed\",\"speed\":3947}]}],\"dWidth\":497,\"dElevation\":-208}},{\"delta\":{\"node-LatLon\":{\"lon\":-1625296958,\"lat\":501091223}},\"attributes\":{\"localNode\":[\"downstreamStartNode\",\"downstreamStopLine\",\"safeIsland\"],\"disabled\":[\"adjacentParkingOnLeft\",\"partialCurbIntrusion\",\"taperToRight\"],\"enabled\":[\"unEvenPavementPresent\",\"adjacentParkingOnRight\"],\"data\":[{\"laneCrownPointCenter\":86}],\"dWidth\":-90,\"dElevation\":131}}]}}}}},{\"name\":\"IA5S\",\"id\":{\"region\":48039,\"id\":14622},\"anchor\":{\"lat\":419808681,\"long\":-1470200813,\"elevation\":37213},\"laneWidth\":25845,\"directionality\":\"unavailable\",\"closedPath\":true,\"direction\":{\"from000-0to022-5degrees\":false,\"from022-5to045-0degrees\":false,\"from045-0to067-5degrees\":false,\"from067-5to090-0degrees\":true,\"from090-0to112-5degrees\":false,\"from112-5to135-0degrees\":false,\"from135-0to157-5degrees\":false,\"from157-5to180-0degrees\":false,\"from180-0to202-5degrees\":false,\"from202-5to225-0degrees\":false,\"from225-0to247-5degrees\":false,\"from247-5to270-0degrees\":false,\"from270-0to292-5degrees\":false,\"from292-5to315-0degrees\":false,\"from315-0to337-5degrees\":false,\"from337-5to360-0degrees\":false},\"description\":{\"geometry\":{\"direction\":{\"from000-0to022-5degrees\":false,\"from022-5to045-0degrees\":false,\"from045-0to067-5degrees\":false,\"from067-5to090-0degrees\":false,\"from090-0to112-5degrees\":false,\"from112-5to135-0degrees\":false,\"from135-0to157-5degrees\":false,\"from157-5to180-0degrees\":false,\"from180-0to202-5degrees\":false,\"from202-5to225-0degrees\":false,\"from225-0to247-5degrees\":false,\"from247-5to270-0degrees\":true,\"from270-0to292-5degrees\":false,\"from292-5to315-0degrees\":false,\"from315-0to337-5degrees\":false,\"from337-5to360-0degrees\":false},\"extent\":\"useFor3meters\",\"laneWidth\":25719,\"circle\":{\"center\":{\"lat\":-666313075,\"long\":639822734,\"elevation\":29597},\"radius\":1325,\"units\":\"foot\"}}}}],\"doNotUse3\":11,\"doNotUse4\":27,\"content\":{\"speedLimit\":[{\"item\":{\"text\":\"I\"}}]},\"url\":\"IA\"},{\"doNotUse1\":18,\"frameType\":\"roadSignage\",\"msgId\":{\"roadSignID\":{\"position\":{\"lat\":889823043,\"long\":-537303585,\"elevation\":29359},\"viewAngle\":{\"from000-0to022-5degrees\":false,\"from022-5to045-0degrees\":false,\"from045-0to067-5degrees\":false,\"from067-5to090-0degrees\":false,\"from090-0to112-5degrees\":false,\"from112-5to135-0degrees\":true,\"from135-0to157-5degrees\":false,\"from157-5to180-0degrees\":false,\"from180-0to202-5degrees\":false,\"from202-5to225-0degrees\":false,\"from225-0to247-5degrees\":false,\"from247-5to270-0degrees\":false,\"from270-0to292-5degrees\":false,\"from292-5to315-0degrees\":false,\"from315-0to337-5degrees\":false,\"from337-5to360-0degrees\":false},\"mutcdCode\":\"maintenance\",\"crc\":\"4F43\"}},\"startYear\":1652,\"startTime\":115878,\"durationTime\":7970,\"priority\":6,\"doNotUse2\":27,\"regions\":[{\"name\":\"I\",\"id\":{\"region\":26015,\"id\":40525},\"anchor\":{\"lat\":112058765,\"long\":1125609019,\"elevation\":54648},\"laneWidth\":31409,\"directionality\":\"both\",\"closedPath\":true,\"direction\":{\"from000-0to022-5degrees\":false,\"from022-5to045-0degrees\":false,\"from045-0to067-5degrees\":false,\"from067-5to090-0degrees\":false,\"from090-0to112-5degrees\":false,\"from112-5to135-0degrees\":false,\"from135-0to157-5degrees\":false,\"from157-5to180-0degrees\":false,\"from180-0to202-5degrees\":false,\"from202-5to225-0degrees\":false,\"from225-0to247-5degrees\":false,\"from247-5to270-0degrees\":false,\"from270-0to292-5degrees\":true,\"from292-5to315-0degrees\":false,\"from315-0to337-5degrees\":false,\"from337-5to360-0degrees\":false},\"description\":{\"oldRegion\":{\"direction\":{\"from000-0to022-5degrees\":false,\"from022-5to045-0degrees\":false,\"from045-0to067-5degrees\":false,\"from067-5to090-0degrees\":false,\"from090-0to112-5degrees\":false,\"from112-5to135-0degrees\":false,\"from135-0to157-5degrees\":false,\"from157-5to180-0degrees\":true,\"from180-0to202-5degrees\":false,\"from202-5to225-0degrees\":false,\"from225-0to247-5degrees\":false,\"from247-5to270-0degrees\":false,\"from270-0to292-5degrees\":false,\"from292-5to315-0degrees\":false,\"from315-0to337-5degrees\":false,\"from337-5to360-0degrees\":false},\"extent\":\"useFor50000meters\",\"area\":{\"shapePointSet\":{\"anchor\":{\"lat\":733403986,\"long\":1001009347,\"elevation\":23252},\"laneWidth\":14952,\"directionality\":\"unavailable\",\"nodeList\":{\"computed\":{\"referenceLaneId\":188,\"offsetXaxis\":{\"large\":-8154},\"offsetYaxis\":{\"large\":-28485},\"rotateXY\":224,\"scaleXaxis\":32,\"scaleYaxis\":1787}}}}}}}],\"doNotUse3\":14,\"doNotUse4\":21,\"content\":{\"exitService\":[{\"item\":{\"text\":\"I\"}}]},\"url\":\"I\"}]},\"dataType\":\"us.dot.its.jpo.ode.plugin.j2735.travelerinformation.TravelerInformation\"}}"; + + // Shifted Forward .1 seconds - Should be deduplicated + String inputTim2 = "{\"metadata\":{\"logFileName\":\"\",\"recordType\":\"timMsg\",\"securityResultCode\":\"success\",\"receivedMessageDetails\":{\"rxSource\":\"NA\"},\"payloadType\":\"us.dot.its.jpo.ode.model.OdeTimPayload\",\"serialId\":{\"streamId\":\"b2d15f2d-7461-4083-b3df-b4efadab4d17\",\"bundleSize\":1,\"bundleId\":0,\"recordId\":0,\"serialNumber\":0},\"odeReceivedAt\":\"2025-02-01T00:19:45.839Z\",\"schemaVersion\":8,\"maxDurationTime\":0,\"recordGeneratedAt\":\"\",\"recordGeneratedBy\":\"RSU\",\"sanitized\":false,\"odePacketID\":\"\",\"odeTimStartDateTime\":\"\",\"asn1\":\"001F83A175D472274F43544554205354520A4C16B18193D0D1F9CDF54733FB1BFC0C983FCFC48D24FF97A474B8A754A9112A6F690200192EFCB5FF96D90FA32D4E83FC0C9830B5F5FC150A5059C545235AC20227C697080018815F84759CB3BF452C850424643A30E028544E9C511560A9DD8C2629F0D4470DBB3DDB4316096FC100800809BC746A108C8F26FC4C3208DA0E61091B7429182D3BFC0C98359EA8B4B454C16E606F037AE007A1CDE32000152E6C0ECDF612A90558D403FC049BF003734AC1C240EC930B39E850A7990A808008C033EFC47606FDDFA252B4A9942280C1020C9D818700EC4B4A76680C001D9F981240013111914408214602F8173D850A0D48F09F5D75264929260B5A7D27260B5A65260B56744F43999104E394B5204FF09260B5A7D3E32C5F74A0DB09EA975B8C1724DC92D9201005800092D84A89EF67BC1B27429C710979A5FE0E4C16B4F5EE874A08F2404C40AA60E2A09E79F91602003E5DB0AA9B32A2E0A6F36507F829305ACEE93E6B134C1CCC3C2EF3FA5CB5D02ECE000142002950BD8FB7D02D26BB6CAFCB848BE4A9260B5A7D29260B5A7D19D28125C17566972EA98F7172471344010153D0C21C1D69E158731BFC1C982D69E2E4FEDB544A012D60EDDB5D7569995CCC001CB02000CB8B449E02D39DB1072106F80B79BFC14982D666D178E4A198A3579B12B09915D01723B0000A10002A973AEAF40B82284427D9124DFE024F9230F8DD6AD73490518F80A3B259CF3FC40014001266976FBC88CB08E20EE8AD087EC16463A2B7AC5E62CB83FC9C830B7275F28A3128CDB2491AFF05260B580BDABD3249C784B718EFDC1906727B228001160002B10C89FAF5F0E9BA4F0AC74920F4947402561EBFB6201930424BF9E8112A39CA22519425D8E01001A7A1E0222723B864CB17F849305AD3E92E6884164E2CE7F0A6BD84FE4E38949D300081A01A290029F8111120048308876C910829B04B5148014FC9621814460542FAA24A460FBF82D2CF1A8CE66032A7E6A0807028A04283228610217947C12CE3FFF20CA031F809A2007D242408F0B4510F23D2A2646294D48A41F4F8494C87B58CCFE2983829A707069C17A4BBF23992859B3A528C03ACD3506FF07260B5A7BBA7391E53AAABAA44EA1584A857727A910002C0020391DD0DEDC78D916CBD8D839D52DABDB084919305C975AABA210D2D0CDF7A0ABC1000D3D0D9D071298F916D83FC049B2CFCF26A78A5951B5CC28075CAF1EAC780042808048EB0ADE229537A0161356A3A68175E5809621740382083BEDD5810921240\",\"originIp\":\"172.20.0.1\"},\"payload\":{\"data\":{\"msgCnt\":93,\"timeStamp\":291367,\"packetID\":\"4F4354455420535452\",\"urlB\":\"IA5\",\"dataFrames\":[{\"doNotUse1\":0,\"frameType\":\"commercialSignage\",\"msgId\":{\"furtherInfoID\":\"4F43\"},\"startYear\":1150,\"startTime\":473045,\"durationTime\":3687,\"priority\":7,\"doNotUse2\":22,\"regions\":[{\"name\":\"IA\",\"id\":{\"region\":64764,\"id\":18642},\"anchor\":{\"lat\":172032029,\"long\":-1025506517,\"elevation\":13386},\"laneWidth\":19949,\"directionality\":\"unavailable\",\"closedPath\":true,\"direction\":{\"from000-0to022-5degrees\":false,\"from022-5to045-0degrees\":false,\"from045-0to067-5degrees\":false,\"from067-5to090-0degrees\":false,\"from090-0to112-5degrees\":false,\"from112-5to135-0degrees\":false,\"from135-0to157-5degrees\":true,\"from157-5to180-0degrees\":false,\"from180-0to202-5degrees\":false,\"from202-5to225-0degrees\":false,\"from225-0to247-5degrees\":false,\"from247-5to270-0degrees\":false,\"from270-0to292-5degrees\":false,\"from292-5to315-0degrees\":false,\"from315-0to337-5degrees\":false,\"from337-5to360-0degrees\":false},\"description\":{\"path\":{\"scale\":9,\"offset\":{\"xy\":{\"computed\":{\"referenceLaneId\":252,\"offsetXaxis\":{\"large\":-5120},\"offsetYaxis\":{\"small\":-585},\"rotateXY\":8692,\"scaleXaxis\":-422,\"scaleYaxis\":464}}}}}},{\"name\":\"IA\",\"id\":{\"region\":2911,\"id\":24513},\"anchor\":{\"lat\":217001329,\"long\":-436271951,\"elevation\":28809},\"laneWidth\":30930,\"directionality\":\"both\",\"closedPath\":true,\"direction\":{\"from000-0to022-5degrees\":false,\"from022-5to045-0degrees\":false,\"from045-0to067-5degrees\":false,\"from067-5to090-0degrees\":false,\"from090-0to112-5degrees\":true,\"from112-5to135-0degrees\":false,\"from135-0to157-5degrees\":false,\"from157-5to180-0degrees\":false,\"from180-0to202-5degrees\":false,\"from202-5to225-0degrees\":false,\"from225-0to247-5degrees\":false,\"from247-5to270-0degrees\":false,\"from270-0to292-5degrees\":false,\"from292-5to315-0degrees\":false,\"from315-0to337-5degrees\":false,\"from337-5to360-0degrees\":false},\"description\":{\"path\":{\"scale\":8,\"offset\":{\"ll\":{\"nodes\":[{\"delta\":{\"node-LL4\":{\"lon\":115258,\"lat\":80231}},\"attributes\":{\"localNode\":[\"curbPresentAtStepOff\",\"hydrantPresent\",\"mergePoint\",\"divergePoint\",\"reserved\"],\"disabled\":[\"transitStopOnRight\",\"adaptiveTimingPresent\",\"loadingzoneOnLeft\",\"costToPark\"],\"enabled\":[\"curbOnLeft\"],\"data\":[{\"speedLimits\":[{\"type\":\"truckNightMaxSpeed\",\"speed\":6769},{\"type\":\"truckMaxSpeed\",\"speed\":4438},{\"type\":\"maxSpeedInSchoolZone\",\"speed\":2679},{\"type\":\"vehiclesWithTrailersNightMaxSpeed\",\"speed\":3110},{\"type\":\"vehicleMaxSpeed\",\"speed\":1987}]}],\"dWidth\":-188,\"dElevation\":-61}},{\"delta\":{\"node-LL6\":{\"lon\":5893850,\"lat\":-6770613}},\"attributes\":{\"localNode\":[\"closedToTraffic\"],\"disabled\":[\"bikeBoxInFront\"],\"enabled\":[\"mergingLaneRight\"],\"data\":[{\"laneCrownPointLeft\":-17}],\"dWidth\":-396,\"dElevation\":-88}},{\"delta\":{\"node-LL1\":{\"lon\":-924,\"lat\":-109}},\"attributes\":{\"localNode\":[\"downstreamStopLine\",\"roundedCapStyleB\"],\"disabled\":[\"whiteLine\",\"partialCurbIntrusion\"],\"enabled\":[\"loadingzoneOnLeft\",\"audibleSignalingPresent\",\"freeParking\"],\"data\":[{\"laneCrownPointCenter\":55},{\"laneAngle\":-98}],\"dWidth\":-319,\"dElevation\":-89}}]}}}}},{\"name\":\"IA\",\"id\":{\"region\":23018,\"id\":35659},\"anchor\":{\"lat\":-544509288,\"long\":-1334375239,\"elevation\":-3608},\"laneWidth\":14780,\"directionality\":\"forward\",\"closedPath\":true,\"direction\":{\"from000-0to022-5degrees\":false,\"from022-5to045-0degrees\":false,\"from045-0to067-5degrees\":true,\"from067-5to090-0degrees\":false,\"from090-0to112-5degrees\":false,\"from112-5to135-0degrees\":false,\"from135-0to157-5degrees\":false,\"from157-5to180-0degrees\":false,\"from180-0to202-5degrees\":false,\"from202-5to225-0degrees\":false,\"from225-0to247-5degrees\":false,\"from247-5to270-0degrees\":false,\"from270-0to292-5degrees\":false,\"from292-5to315-0degrees\":false,\"from315-0to337-5degrees\":false,\"from337-5to360-0degrees\":false},\"description\":{\"path\":{\"scale\":5,\"offset\":{\"xy\":{\"computed\":{\"referenceLaneId\":108,\"offsetXaxis\":{\"small\":-1574},\"offsetYaxis\":{\"large\":-635},\"rotateXY\":21792,\"scaleXaxis\":689,\"scaleYaxis\":640}}}}}},{\"name\":\"I\",\"id\":{\"region\":32256,\"id\":28265},\"anchor\":{\"lat\":725366646,\"long\":-566506763,\"elevation\":6227},\"laneWidth\":26178,\"directionality\":\"reverse\",\"closedPath\":true,\"direction\":{\"from000-0to022-5degrees\":false,\"from022-5to045-0degrees\":false,\"from045-0to067-5degrees\":false,\"from067-5to090-0degrees\":false,\"from090-0to112-5degrees\":false,\"from112-5to135-0degrees\":false,\"from135-0to157-5degrees\":false,\"from157-5to180-0degrees\":true,\"from180-0to202-5degrees\":false,\"from202-5to225-0degrees\":false,\"from225-0to247-5degrees\":false,\"from247-5to270-0degrees\":false,\"from270-0to292-5degrees\":false,\"from292-5to315-0degrees\":false,\"from315-0to337-5degrees\":false,\"from337-5to360-0degrees\":false},\"description\":{\"path\":{\"scale\":1,\"offset\":{\"ll\":{\"nodes\":[{\"delta\":{\"node-LL5\":{\"lon\":2030663,\"lat\":-517129}},\"attributes\":{\"localNode\":[\"safeIsland\",\"hydrantPresent\",\"curbPresentAtStepOff\"],\"disabled\":[\"sharedWithTrackedVehicle\",\"transitStopOnLeft\",\"headInParking\",\"audibleSignalingPresent\"],\"enabled\":[\"doNotBlock\",\"mergingLaneLeft\"],\"data\":[{\"laneCrownPointRight\":48},{\"laneCrownPointRight\":-114}],\"dWidth\":-505,\"dElevation\":-119}},{\"delta\":{\"node-LL6\":{\"lon\":-5645920,\"lat\":-5242762}},\"attributes\":{\"localNode\":[\"reserved\",\"safeIsland\",\"mergePoint\"],\"disabled\":[\"turnOutPointOnLeft\"],\"enabled\":[\"timeRestrictionsOnParking\",\"adaptiveTimingPresent\",\"turnOutPointOnRight\",\"bikeBoxInFront\"],\"data\":[{\"laneCrownPointCenter\":-58},{\"pathEndPointAngle\":-55},{\"pathEndPointAngle\":-58}],\"dWidth\":472,\"dElevation\":-190}}]}}}}}],\"doNotUse3\":16,\"doNotUse4\":13,\"content\":{\"genericSign\":[{\"item\":{\"itis\":61599}},{\"item\":{\"itis\":47850}},{\"item\":{\"itis\":39204}},{\"item\":{\"text\":\"IA5St\"}},{\"item\":{\"text\":\"IA5S\"}}]},\"url\":\"IA5\"},{\"doNotUse1\":7,\"frameType\":\"roadSignage\",\"msgId\":{\"furtherInfoID\":\"4F43\"},\"startYear\":2457,\"startTime\":66787,\"durationTime\":19034,\"priority\":4,\"doNotUse2\":16,\"regions\":[{\"name\":\"IA5St\",\"id\":{\"region\":61846,\"id\":12218},\"anchor\":{\"lat\":202451669,\"long\":-1016248785,\"elevation\":14777},\"laneWidth\":4825,\"directionality\":\"unavailable\",\"closedPath\":true,\"direction\":{\"from000-0to022-5degrees\":false,\"from022-5to045-0degrees\":false,\"from045-0to067-5degrees\":false,\"from067-5to090-0degrees\":false,\"from090-0to112-5degrees\":false,\"from112-5to135-0degrees\":false,\"from135-0to157-5degrees\":false,\"from157-5to180-0degrees\":false,\"from180-0to202-5degrees\":true,\"from202-5to225-0degrees\":false,\"from225-0to247-5degrees\":false,\"from247-5to270-0degrees\":false,\"from270-0to292-5degrees\":false,\"from292-5to315-0degrees\":false,\"from315-0to337-5degrees\":false,\"from337-5to360-0degrees\":false},\"description\":{\"geometry\":{\"direction\":{\"from000-0to022-5degrees\":false,\"from022-5to045-0degrees\":false,\"from045-0to067-5degrees\":false,\"from067-5to090-0degrees\":false,\"from090-0to112-5degrees\":false,\"from112-5to135-0degrees\":false,\"from135-0to157-5degrees\":false,\"from157-5to180-0degrees\":false,\"from180-0to202-5degrees\":false,\"from202-5to225-0degrees\":false,\"from225-0to247-5degrees\":false,\"from247-5to270-0degrees\":false,\"from270-0to292-5degrees\":false,\"from292-5to315-0degrees\":false,\"from315-0to337-5degrees\":true,\"from337-5to360-0degrees\":false},\"extent\":\"useFor100meters\",\"laneWidth\":23305,\"circle\":{\"center\":{\"lat\":257084126,\"long\":-1572221105,\"elevation\":10372},\"radius\":3021,\"units\":\"cm2-5\"}}}},{\"name\":\"IA5S\",\"id\":{\"region\":44916,\"id\":14928},\"anchor\":{\"lat\":-391962488,\"long\":-1442690475,\"elevation\":975},\"laneWidth\":8081,\"directionality\":\"forward\",\"closedPath\":true,\"direction\":{\"from000-0to022-5degrees\":false,\"from022-5to045-0degrees\":false,\"from045-0to067-5degrees\":false,\"from067-5to090-0degrees\":false,\"from090-0to112-5degrees\":false,\"from112-5to135-0degrees\":false,\"from135-0to157-5degrees\":false,\"from157-5to180-0degrees\":true,\"from180-0to202-5degrees\":false,\"from202-5to225-0degrees\":false,\"from225-0to247-5degrees\":false,\"from247-5to270-0degrees\":false,\"from270-0to292-5degrees\":false,\"from292-5to315-0degrees\":false,\"from315-0to337-5degrees\":false,\"from337-5to360-0degrees\":false},\"description\":{\"path\":{\"scale\":15,\"offset\":{\"xy\":{\"computed\":{\"referenceLaneId\":216,\"offsetXaxis\":{\"small\":682},\"offsetYaxis\":{\"large\":-6571},\"rotateXY\":11786,\"scaleXaxis\":-269,\"scaleYaxis\":-432}}}}}},{\"name\":\"IA5\",\"id\":{\"region\":15268,\"id\":63916},\"anchor\":{\"lat\":-14883901,\"long\":1470459302,\"elevation\":47965},\"laneWidth\":374,\"directionality\":\"forward\",\"closedPath\":true,\"direction\":{\"from000-0to022-5degrees\":true,\"from022-5to045-0degrees\":false,\"from045-0to067-5degrees\":false,\"from067-5to090-0degrees\":false,\"from090-0to112-5degrees\":false,\"from112-5to135-0degrees\":false,\"from135-0to157-5degrees\":false,\"from157-5to180-0degrees\":false,\"from180-0to202-5degrees\":false,\"from202-5to225-0degrees\":false,\"from225-0to247-5degrees\":false,\"from247-5to270-0degrees\":false,\"from270-0to292-5degrees\":false,\"from292-5to315-0degrees\":false,\"from315-0to337-5degrees\":false,\"from337-5to360-0degrees\":false},\"description\":{\"oldRegion\":{\"direction\":{\"from000-0to022-5degrees\":false,\"from022-5to045-0degrees\":false,\"from045-0to067-5degrees\":false,\"from067-5to090-0degrees\":false,\"from090-0to112-5degrees\":true,\"from112-5to135-0degrees\":false,\"from135-0to157-5degrees\":false,\"from157-5to180-0degrees\":false,\"from180-0to202-5degrees\":false,\"from202-5to225-0degrees\":false,\"from225-0to247-5degrees\":false,\"from247-5to270-0degrees\":false,\"from270-0to292-5degrees\":false,\"from292-5to315-0degrees\":false,\"from315-0to337-5degrees\":false,\"from337-5to360-0degrees\":false},\"extent\":\"useFor100000meters\",\"area\":{\"circle\":{\"center\":{\"lat\":223434207,\"long\":-714422034,\"elevation\":41663},\"radius\":737,\"units\":\"cm2-5\"}}}}}],\"doNotUse3\":2,\"doNotUse4\":31,\"content\":{\"workZone\":[{\"item\":{\"text\":\"IA5St\"}},{\"item\":{\"text\":\"IA5St\"}},{\"item\":{\"itis\":52884}}]},\"url\":\"I\"},{\"doNotUse1\":16,\"frameType\":\"roadSignage\",\"msgId\":{\"roadSignID\":{\"position\":{\"lat\":604037802,\"long\":-124613998,\"elevation\":46289},\"viewAngle\":{\"from000-0to022-5degrees\":false,\"from022-5to045-0degrees\":false,\"from045-0to067-5degrees\":false,\"from067-5to090-0degrees\":false,\"from090-0to112-5degrees\":false,\"from112-5to135-0degrees\":false,\"from135-0to157-5degrees\":false,\"from157-5to180-0degrees\":false,\"from180-0to202-5degrees\":false,\"from202-5to225-0degrees\":true,\"from225-0to247-5degrees\":false,\"from247-5to270-0degrees\":false,\"from270-0to292-5degrees\":false,\"from292-5to315-0degrees\":false,\"from315-0to337-5degrees\":false,\"from337-5to360-0degrees\":false},\"mutcdCode\":\"guide\",\"crc\":\"4F43\"}},\"startYear\":135,\"startTime\":30119,\"durationTime\":17072,\"priority\":7,\"doNotUse2\":6,\"regions\":[{\"name\":\"IA5S\",\"id\":{\"region\":35731,\"id\":64365},\"anchor\":{\"lat\":251341270,\"long\":-1550588968,\"elevation\":18073},\"laneWidth\":19174,\"directionality\":\"forward\",\"closedPath\":true,\"direction\":{\"from000-0to022-5degrees\":false,\"from022-5to045-0degrees\":false,\"from045-0to067-5degrees\":false,\"from067-5to090-0degrees\":false,\"from090-0to112-5degrees\":false,\"from112-5to135-0degrees\":false,\"from135-0to157-5degrees\":false,\"from157-5to180-0degrees\":false,\"from180-0to202-5degrees\":false,\"from202-5to225-0degrees\":false,\"from225-0to247-5degrees\":false,\"from247-5to270-0degrees\":false,\"from270-0to292-5degrees\":false,\"from292-5to315-0degrees\":true,\"from315-0to337-5degrees\":true,\"from337-5to360-0degrees\":true},\"description\":{\"geometry\":{\"direction\":{\"from000-0to022-5degrees\":false,\"from022-5to045-0degrees\":false,\"from045-0to067-5degrees\":false,\"from067-5to090-0degrees\":false,\"from090-0to112-5degrees\":false,\"from112-5to135-0degrees\":true,\"from135-0to157-5degrees\":false,\"from157-5to180-0degrees\":false,\"from180-0to202-5degrees\":false,\"from202-5to225-0degrees\":false,\"from225-0to247-5degrees\":false,\"from247-5to270-0degrees\":false,\"from270-0to292-5degrees\":false,\"from292-5to315-0degrees\":false,\"from315-0to337-5degrees\":false,\"from337-5to360-0degrees\":false},\"extent\":\"useFor3meters\",\"laneWidth\":19339,\"circle\":{\"center\":{\"lat\":-590142898,\"long\":192563845,\"elevation\":3040},\"radius\":734,\"units\":\"meter\"}}}},{\"name\":\"IA5\",\"id\":{\"region\":13160,\"id\":48242},\"anchor\":{\"lat\":227302831,\"long\":-891580621,\"elevation\":7072},\"laneWidth\":5923,\"directionality\":\"reverse\",\"closedPath\":true,\"direction\":{\"from000-0to022-5degrees\":true,\"from022-5to045-0degrees\":false,\"from045-0to067-5degrees\":false,\"from067-5to090-0degrees\":false,\"from090-0to112-5degrees\":false,\"from112-5to135-0degrees\":false,\"from135-0to157-5degrees\":false,\"from157-5to180-0degrees\":false,\"from180-0to202-5degrees\":false,\"from202-5to225-0degrees\":false,\"from225-0to247-5degrees\":false,\"from247-5to270-0degrees\":false,\"from270-0to292-5degrees\":false,\"from292-5to315-0degrees\":false,\"from315-0to337-5degrees\":false,\"from337-5to360-0degrees\":false},\"description\":{\"oldRegion\":{\"direction\":{\"from000-0to022-5degrees\":false,\"from022-5to045-0degrees\":false,\"from045-0to067-5degrees\":false,\"from067-5to090-0degrees\":false,\"from090-0to112-5degrees\":true,\"from112-5to135-0degrees\":false,\"from135-0to157-5degrees\":false,\"from157-5to180-0degrees\":false,\"from180-0to202-5degrees\":false,\"from202-5to225-0degrees\":false,\"from225-0to247-5degrees\":false,\"from247-5to270-0degrees\":false,\"from270-0to292-5degrees\":false,\"from292-5to315-0degrees\":false,\"from315-0to337-5degrees\":false,\"from337-5to360-0degrees\":false},\"extent\":\"useFor3meters\",\"area\":{\"circle\":{\"center\":{\"lat\":368610426,\"long\":-1703460317,\"elevation\":1004},\"radius\":2194,\"units\":\"meter\"}}}}},{\"name\":\"I\",\"id\":{\"region\":58508,\"id\":15927},\"anchor\":{\"lat\":892488592,\"long\":-431640924,\"elevation\":41561},\"laneWidth\":26527,\"directionality\":\"both\",\"closedPath\":true,\"direction\":{\"from000-0to022-5degrees\":false,\"from022-5to045-0degrees\":false,\"from045-0to067-5degrees\":false,\"from067-5to090-0degrees\":true,\"from090-0to112-5degrees\":false,\"from112-5to135-0degrees\":false,\"from135-0to157-5degrees\":false,\"from157-5to180-0degrees\":false,\"from180-0to202-5degrees\":false,\"from202-5to225-0degrees\":false,\"from225-0to247-5degrees\":false,\"from247-5to270-0degrees\":false,\"from270-0to292-5degrees\":false,\"from292-5to315-0degrees\":false,\"from315-0to337-5degrees\":false,\"from337-5to360-0degrees\":false},\"description\":{\"oldRegion\":{\"direction\":{\"from000-0to022-5degrees\":false,\"from022-5to045-0degrees\":false,\"from045-0to067-5degrees\":false,\"from067-5to090-0degrees\":false,\"from090-0to112-5degrees\":false,\"from112-5to135-0degrees\":false,\"from135-0to157-5degrees\":false,\"from157-5to180-0degrees\":false,\"from180-0to202-5degrees\":false,\"from202-5to225-0degrees\":false,\"from225-0to247-5degrees\":false,\"from247-5to270-0degrees\":false,\"from270-0to292-5degrees\":false,\"from292-5to315-0degrees\":true,\"from315-0to337-5degrees\":false,\"from337-5to360-0degrees\":false},\"extent\":\"useFor50000meters\",\"area\":{\"regionPointSet\":{\"anchor\":{\"lat\":-113602543,\"long\":717746718,\"elevation\":49498},\"scale\":1,\"nodeList\":[{\"xOffset\":27670,\"yOffset\":-14790,\"zOffset\":-21638},{\"xOffset\":3020,\"yOffset\":-9872,\"zOffset\":-109},{\"xOffset\":-24382,\"yOffset\":23709,\"zOffset\":-862},{\"xOffset\":-26476,\"yOffset\":-6439,\"zOffset\":-23411}]}}}}},{\"name\":\"IA5\",\"id\":{\"region\":379,\"id\":22438},\"anchor\":{\"lat\":-281093797,\"long\":556669965,\"elevation\":29497},\"laneWidth\":7880,\"directionality\":\"reverse\",\"closedPath\":true,\"direction\":{\"from000-0to022-5degrees\":false,\"from022-5to045-0degrees\":false,\"from045-0to067-5degrees\":false,\"from067-5to090-0degrees\":false,\"from090-0to112-5degrees\":false,\"from112-5to135-0degrees\":false,\"from135-0to157-5degrees\":false,\"from157-5to180-0degrees\":false,\"from180-0to202-5degrees\":false,\"from202-5to225-0degrees\":false,\"from225-0to247-5degrees\":false,\"from247-5to270-0degrees\":false,\"from270-0to292-5degrees\":false,\"from292-5to315-0degrees\":false,\"from315-0to337-5degrees\":true,\"from337-5to360-0degrees\":false},\"description\":{\"geometry\":{\"direction\":{\"from000-0to022-5degrees\":false,\"from022-5to045-0degrees\":false,\"from045-0to067-5degrees\":false,\"from067-5to090-0degrees\":false,\"from090-0to112-5degrees\":false,\"from112-5to135-0degrees\":false,\"from135-0to157-5degrees\":false,\"from157-5to180-0degrees\":false,\"from180-0to202-5degrees\":false,\"from202-5to225-0degrees\":false,\"from225-0to247-5degrees\":false,\"from247-5to270-0degrees\":false,\"from270-0to292-5degrees\":false,\"from292-5to315-0degrees\":false,\"from315-0to337-5degrees\":true,\"from337-5to360-0degrees\":false},\"extent\":\"useFor500000meters\",\"laneWidth\":2148,\"circle\":{\"center\":{\"lat\":163173661,\"long\":-872411303,\"elevation\":55588},\"radius\":489,\"units\":\"cm2-5\"}}}}],\"doNotUse3\":8,\"doNotUse4\":29,\"content\":{\"advisory\":[{\"item\":{\"itis\":44093}},{\"item\":{\"itis\":65240}},{\"item\":{\"text\":\"IA\"}}]},\"url\":\"I\"},{\"doNotUse1\":31,\"frameType\":\"advisory\",\"msgId\":{\"roadSignID\":{\"position\":{\"lat\":-864002503,\"long\":-654286715,\"elevation\":43804},\"viewAngle\":{\"from000-0to022-5degrees\":false,\"from022-5to045-0degrees\":false,\"from045-0to067-5degrees\":false,\"from067-5to090-0degrees\":false,\"from090-0to112-5degrees\":false,\"from112-5to135-0degrees\":false,\"from135-0to157-5degrees\":true,\"from157-5to180-0degrees\":false,\"from180-0to202-5degrees\":false,\"from202-5to225-0degrees\":false,\"from225-0to247-5degrees\":false,\"from247-5to270-0degrees\":false,\"from270-0to292-5degrees\":false,\"from292-5to315-0degrees\":false,\"from315-0to337-5degrees\":false,\"from337-5to360-0degrees\":false},\"mutcdCode\":\"maintenance\",\"crc\":\"4F43\"}},\"startYear\":3076,\"startTime\":282183,\"durationTime\":14436,\"priority\":6,\"doNotUse2\":11,\"regions\":[{\"name\":\"IA5St\",\"id\":{\"region\":11880,\"id\":33814},\"anchor\":{\"lat\":51295938,\"long\":799818234,\"elevation\":10466},\"laneWidth\":10554,\"directionality\":\"forward\",\"closedPath\":true,\"direction\":{\"from000-0to022-5degrees\":false,\"from022-5to045-0degrees\":false,\"from045-0to067-5degrees\":false,\"from067-5to090-0degrees\":false,\"from090-0to112-5degrees\":false,\"from112-5to135-0degrees\":false,\"from135-0to157-5degrees\":false,\"from157-5to180-0degrees\":false,\"from180-0to202-5degrees\":false,\"from202-5to225-0degrees\":false,\"from225-0to247-5degrees\":false,\"from247-5to270-0degrees\":false,\"from270-0to292-5degrees\":true,\"from292-5to315-0degrees\":false,\"from315-0to337-5degrees\":false,\"from337-5to360-0degrees\":false},\"description\":{\"path\":{\"scale\":10,\"offset\":{\"xy\":{\"nodes\":[{\"delta\":{\"node-XY1\":{\"x\":144,\"y\":-502}},\"attributes\":{\"localNode\":[\"mergePoint\"],\"disabled\":[\"transitStopOnLeft\",\"bikeBoxInFront\",\"doNotBlock\"],\"enabled\":[\"mergingLaneLeft\",\"mergingLaneRight\"],\"data\":[{\"laneCrownPointCenter\":91},{\"laneCrownPointLeft\":-60},{\"laneCrownPointLeft\":-118}],\"dWidth\":-80,\"dElevation\":-211}},{\"delta\":{\"node-XY1\":{\"x\":144,\"y\":-502}},\"attributes\":{\"localNode\":[\"hydrantPresent\",\"roundedCapStyleA\",\"roundedCapStyleB\"],\"disabled\":[\"turnOutPointOnRight\"],\"enabled\":[\"adjacentParkingOnRight\",\"curbOnLeft\"],\"data\":[{\"laneCrownPointCenter\":-3},{\"laneCrownPointCenter\":-23},{\"speedLimits\":[{\"type\":\"vehicleMinSpeed\",\"speed\":5260},{\"type\":\"maxSpeedInConstructionZone\",\"speed\":7676}]}],\"dWidth\":-98,\"dElevation\":-300}},{\"delta\":{\"node-XY5\":{\"x\":6552,\"y\":-7382}},\"attributes\":{\"localNode\":[\"curbPresentAtStepOff\",\"stopLine\",\"reserved\",\"roundedCapStyleB\"],\"disabled\":[\"curbOnLeft\",\"turnOutPointOnRight\",\"whiteLine\",\"curbOnRight\"],\"enabled\":[\"sharedWithTrackedVehicle\",\"audibleSignalingPresent\",\"headInParking\"],\"data\":[{\"laneCrownPointCenter\":-7},{\"laneAngle\":68},{\"laneCrownPointLeft\":-39}],\"dWidth\":287,\"dElevation\":510}},{\"delta\":{\"node-XY1\":{\"x\":-310,\"y\":-500}},\"attributes\":{\"localNode\":[\"roundedCapStyleA\"],\"disabled\":[\"timeRestrictionsOnParking\",\"reserved\",\"parallelParking\",\"midBlockCurbPresent\"],\"enabled\":[\"transitStopOnRight\",\"whiteLine\",\"taperToCenterLine\",\"adjacentParkingOnLeft\",\"timeRestrictionsOnParking\"],\"data\":[{\"laneAngle\":-59},{\"laneCrownPointCenter\":105},{\"laneCrownPointCenter\":25},{\"speedLimits\":[{\"type\":\"vehicleNightMaxSpeed\",\"speed\":2245},{\"type\":\"vehicleMaxSpeed\",\"speed\":1700}]},{\"speedLimits\":[{\"type\":\"maxSpeedInSchoolZone\",\"speed\":7839},{\"type\":\"maxSpeedInSchoolZone\",\"speed\":1190},{\"type\":\"truckMaxSpeed\",\"speed\":3947}]}],\"dWidth\":497,\"dElevation\":-208}},{\"delta\":{\"node-LatLon\":{\"lon\":-1625296958,\"lat\":501091223}},\"attributes\":{\"localNode\":[\"downstreamStartNode\",\"downstreamStopLine\",\"safeIsland\"],\"disabled\":[\"adjacentParkingOnLeft\",\"partialCurbIntrusion\",\"taperToRight\"],\"enabled\":[\"unEvenPavementPresent\",\"adjacentParkingOnRight\"],\"data\":[{\"laneCrownPointCenter\":86}],\"dWidth\":-90,\"dElevation\":131}}]}}}}},{\"name\":\"IA5S\",\"id\":{\"region\":48039,\"id\":14622},\"anchor\":{\"lat\":419808681,\"long\":-1470200813,\"elevation\":37213},\"laneWidth\":25845,\"directionality\":\"unavailable\",\"closedPath\":true,\"direction\":{\"from000-0to022-5degrees\":false,\"from022-5to045-0degrees\":false,\"from045-0to067-5degrees\":false,\"from067-5to090-0degrees\":true,\"from090-0to112-5degrees\":false,\"from112-5to135-0degrees\":false,\"from135-0to157-5degrees\":false,\"from157-5to180-0degrees\":false,\"from180-0to202-5degrees\":false,\"from202-5to225-0degrees\":false,\"from225-0to247-5degrees\":false,\"from247-5to270-0degrees\":false,\"from270-0to292-5degrees\":false,\"from292-5to315-0degrees\":false,\"from315-0to337-5degrees\":false,\"from337-5to360-0degrees\":false},\"description\":{\"geometry\":{\"direction\":{\"from000-0to022-5degrees\":false,\"from022-5to045-0degrees\":false,\"from045-0to067-5degrees\":false,\"from067-5to090-0degrees\":false,\"from090-0to112-5degrees\":false,\"from112-5to135-0degrees\":false,\"from135-0to157-5degrees\":false,\"from157-5to180-0degrees\":false,\"from180-0to202-5degrees\":false,\"from202-5to225-0degrees\":false,\"from225-0to247-5degrees\":false,\"from247-5to270-0degrees\":true,\"from270-0to292-5degrees\":false,\"from292-5to315-0degrees\":false,\"from315-0to337-5degrees\":false,\"from337-5to360-0degrees\":false},\"extent\":\"useFor3meters\",\"laneWidth\":25719,\"circle\":{\"center\":{\"lat\":-666313075,\"long\":639822734,\"elevation\":29597},\"radius\":1325,\"units\":\"foot\"}}}}],\"doNotUse3\":11,\"doNotUse4\":27,\"content\":{\"speedLimit\":[{\"item\":{\"text\":\"I\"}}]},\"url\":\"IA\"},{\"doNotUse1\":18,\"frameType\":\"roadSignage\",\"msgId\":{\"roadSignID\":{\"position\":{\"lat\":889823043,\"long\":-537303585,\"elevation\":29359},\"viewAngle\":{\"from000-0to022-5degrees\":false,\"from022-5to045-0degrees\":false,\"from045-0to067-5degrees\":false,\"from067-5to090-0degrees\":false,\"from090-0to112-5degrees\":false,\"from112-5to135-0degrees\":true,\"from135-0to157-5degrees\":false,\"from157-5to180-0degrees\":false,\"from180-0to202-5degrees\":false,\"from202-5to225-0degrees\":false,\"from225-0to247-5degrees\":false,\"from247-5to270-0degrees\":false,\"from270-0to292-5degrees\":false,\"from292-5to315-0degrees\":false,\"from315-0to337-5degrees\":false,\"from337-5to360-0degrees\":false},\"mutcdCode\":\"maintenance\",\"crc\":\"4F43\"}},\"startYear\":1652,\"startTime\":115878,\"durationTime\":7970,\"priority\":6,\"doNotUse2\":27,\"regions\":[{\"name\":\"I\",\"id\":{\"region\":26015,\"id\":40525},\"anchor\":{\"lat\":112058765,\"long\":1125609019,\"elevation\":54648},\"laneWidth\":31409,\"directionality\":\"both\",\"closedPath\":true,\"direction\":{\"from000-0to022-5degrees\":false,\"from022-5to045-0degrees\":false,\"from045-0to067-5degrees\":false,\"from067-5to090-0degrees\":false,\"from090-0to112-5degrees\":false,\"from112-5to135-0degrees\":false,\"from135-0to157-5degrees\":false,\"from157-5to180-0degrees\":false,\"from180-0to202-5degrees\":false,\"from202-5to225-0degrees\":false,\"from225-0to247-5degrees\":false,\"from247-5to270-0degrees\":false,\"from270-0to292-5degrees\":true,\"from292-5to315-0degrees\":false,\"from315-0to337-5degrees\":false,\"from337-5to360-0degrees\":false},\"description\":{\"oldRegion\":{\"direction\":{\"from000-0to022-5degrees\":false,\"from022-5to045-0degrees\":false,\"from045-0to067-5degrees\":false,\"from067-5to090-0degrees\":false,\"from090-0to112-5degrees\":false,\"from112-5to135-0degrees\":false,\"from135-0to157-5degrees\":false,\"from157-5to180-0degrees\":true,\"from180-0to202-5degrees\":false,\"from202-5to225-0degrees\":false,\"from225-0to247-5degrees\":false,\"from247-5to270-0degrees\":false,\"from270-0to292-5degrees\":false,\"from292-5to315-0degrees\":false,\"from315-0to337-5degrees\":false,\"from337-5to360-0degrees\":false},\"extent\":\"useFor50000meters\",\"area\":{\"shapePointSet\":{\"anchor\":{\"lat\":733403986,\"long\":1001009347,\"elevation\":23252},\"laneWidth\":14952,\"directionality\":\"unavailable\",\"nodeList\":{\"computed\":{\"referenceLaneId\":188,\"offsetXaxis\":{\"large\":-8154},\"offsetYaxis\":{\"large\":-28485},\"rotateXY\":224,\"scaleXaxis\":32,\"scaleYaxis\":1787}}}}}}}],\"doNotUse3\":14,\"doNotUse4\":21,\"content\":{\"exitService\":[{\"item\":{\"text\":\"I\"}}]},\"url\":\"I\"}]},\"dataType\":\"us.dot.its.jpo.ode.plugin.j2735.travelerinformation.TravelerInformation\"}}"; + + // Shifted Forward 1 hour Should be allowed to pass through + String inputTim3 = "{\"metadata\":{\"logFileName\":\"\",\"recordType\":\"timMsg\",\"securityResultCode\":\"success\",\"receivedMessageDetails\":{\"rxSource\":\"NA\"},\"payloadType\":\"us.dot.its.jpo.ode.model.OdeTimPayload\",\"serialId\":{\"streamId\":\"b2d15f2d-7461-4083-b3df-b4efadab4d17\",\"bundleSize\":1,\"bundleId\":0,\"recordId\":0,\"serialNumber\":0},\"odeReceivedAt\":\"2025-02-01T01:19:46.739Z\",\"schemaVersion\":8,\"maxDurationTime\":0,\"recordGeneratedAt\":\"\",\"recordGeneratedBy\":\"RSU\",\"sanitized\":false,\"odePacketID\":\"\",\"odeTimStartDateTime\":\"\",\"asn1\":\"001F83A175D472274F43544554205354520A4C16B18193D0D1F9CDF54733FB1BFC0C983FCFC48D24FF97A474B8A754A9112A6F690200192EFCB5FF96D90FA32D4E83FC0C9830B5F5FC150A5059C545235AC20227C697080018815F84759CB3BF452C850424643A30E028544E9C511560A9DD8C2629F0D4470DBB3DDB4316096FC100800809BC746A108C8F26FC4C3208DA0E61091B7429182D3BFC0C98359EA8B4B454C16E606F037AE007A1CDE32000152E6C0ECDF612A90558D403FC049BF003734AC1C240EC930B39E850A7990A808008C033EFC47606FDDFA252B4A9942280C1020C9D818700EC4B4A76680C001D9F981240013111914408214602F8173D850A0D48F09F5D75264929260B5A7D27260B5A65260B56744F43999104E394B5204FF09260B5A7D3E32C5F74A0DB09EA975B8C1724DC92D9201005800092D84A89EF67BC1B27429C710979A5FE0E4C16B4F5EE874A08F2404C40AA60E2A09E79F91602003E5DB0AA9B32A2E0A6F36507F829305ACEE93E6B134C1CCC3C2EF3FA5CB5D02ECE000142002950BD8FB7D02D26BB6CAFCB848BE4A9260B5A7D29260B5A7D19D28125C17566972EA98F7172471344010153D0C21C1D69E158731BFC1C982D69E2E4FEDB544A012D60EDDB5D7569995CCC001CB02000CB8B449E02D39DB1072106F80B79BFC14982D666D178E4A198A3579B12B09915D01723B0000A10002A973AEAF40B82284427D9124DFE024F9230F8DD6AD73490518F80A3B259CF3FC40014001266976FBC88CB08E20EE8AD087EC16463A2B7AC5E62CB83FC9C830B7275F28A3128CDB2491AFF05260B580BDABD3249C784B718EFDC1906727B228001160002B10C89FAF5F0E9BA4F0AC74920F4947402561EBFB6201930424BF9E8112A39CA22519425D8E01001A7A1E0222723B864CB17F849305AD3E92E6884164E2CE7F0A6BD84FE4E38949D300081A01A290029F8111120048308876C910829B04B5148014FC9621814460542FAA24A460FBF82D2CF1A8CE66032A7E6A0807028A04283228610217947C12CE3FFF20CA031F809A2007D242408F0B4510F23D2A2646294D48A41F4F8494C87B58CCFE2983829A707069C17A4BBF23992859B3A528C03ACD3506FF07260B5A7BBA7391E53AAABAA44EA1584A857727A910002C0020391DD0DEDC78D916CBD8D839D52DABDB084919305C975AABA210D2D0CDF7A0ABC1000D3D0D9D071298F916D83FC049B2CFCF26A78A5951B5CC28075CAF1EAC780042808048EB0ADE229537A0161356A3A68175E5809621740382083BEDD5810921240\",\"originIp\":\"172.20.0.1\"},\"payload\":{\"data\":{\"msgCnt\":93,\"timeStamp\":291367,\"packetID\":\"4F4354455420535452\",\"urlB\":\"IA5\",\"dataFrames\":[{\"doNotUse1\":0,\"frameType\":\"commercialSignage\",\"msgId\":{\"furtherInfoID\":\"4F43\"},\"startYear\":1150,\"startTime\":473045,\"durationTime\":3687,\"priority\":7,\"doNotUse2\":22,\"regions\":[{\"name\":\"IA\",\"id\":{\"region\":64764,\"id\":18642},\"anchor\":{\"lat\":172032029,\"long\":-1025506517,\"elevation\":13386},\"laneWidth\":19949,\"directionality\":\"unavailable\",\"closedPath\":true,\"direction\":{\"from000-0to022-5degrees\":false,\"from022-5to045-0degrees\":false,\"from045-0to067-5degrees\":false,\"from067-5to090-0degrees\":false,\"from090-0to112-5degrees\":false,\"from112-5to135-0degrees\":false,\"from135-0to157-5degrees\":true,\"from157-5to180-0degrees\":false,\"from180-0to202-5degrees\":false,\"from202-5to225-0degrees\":false,\"from225-0to247-5degrees\":false,\"from247-5to270-0degrees\":false,\"from270-0to292-5degrees\":false,\"from292-5to315-0degrees\":false,\"from315-0to337-5degrees\":false,\"from337-5to360-0degrees\":false},\"description\":{\"path\":{\"scale\":9,\"offset\":{\"xy\":{\"computed\":{\"referenceLaneId\":252,\"offsetXaxis\":{\"large\":-5120},\"offsetYaxis\":{\"small\":-585},\"rotateXY\":8692,\"scaleXaxis\":-422,\"scaleYaxis\":464}}}}}},{\"name\":\"IA\",\"id\":{\"region\":2911,\"id\":24513},\"anchor\":{\"lat\":217001329,\"long\":-436271951,\"elevation\":28809},\"laneWidth\":30930,\"directionality\":\"both\",\"closedPath\":true,\"direction\":{\"from000-0to022-5degrees\":false,\"from022-5to045-0degrees\":false,\"from045-0to067-5degrees\":false,\"from067-5to090-0degrees\":false,\"from090-0to112-5degrees\":true,\"from112-5to135-0degrees\":false,\"from135-0to157-5degrees\":false,\"from157-5to180-0degrees\":false,\"from180-0to202-5degrees\":false,\"from202-5to225-0degrees\":false,\"from225-0to247-5degrees\":false,\"from247-5to270-0degrees\":false,\"from270-0to292-5degrees\":false,\"from292-5to315-0degrees\":false,\"from315-0to337-5degrees\":false,\"from337-5to360-0degrees\":false},\"description\":{\"path\":{\"scale\":8,\"offset\":{\"ll\":{\"nodes\":[{\"delta\":{\"node-LL4\":{\"lon\":115258,\"lat\":80231}},\"attributes\":{\"localNode\":[\"curbPresentAtStepOff\",\"hydrantPresent\",\"mergePoint\",\"divergePoint\",\"reserved\"],\"disabled\":[\"transitStopOnRight\",\"adaptiveTimingPresent\",\"loadingzoneOnLeft\",\"costToPark\"],\"enabled\":[\"curbOnLeft\"],\"data\":[{\"speedLimits\":[{\"type\":\"truckNightMaxSpeed\",\"speed\":6769},{\"type\":\"truckMaxSpeed\",\"speed\":4438},{\"type\":\"maxSpeedInSchoolZone\",\"speed\":2679},{\"type\":\"vehiclesWithTrailersNightMaxSpeed\",\"speed\":3110},{\"type\":\"vehicleMaxSpeed\",\"speed\":1987}]}],\"dWidth\":-188,\"dElevation\":-61}},{\"delta\":{\"node-LL6\":{\"lon\":5893850,\"lat\":-6770613}},\"attributes\":{\"localNode\":[\"closedToTraffic\"],\"disabled\":[\"bikeBoxInFront\"],\"enabled\":[\"mergingLaneRight\"],\"data\":[{\"laneCrownPointLeft\":-17}],\"dWidth\":-396,\"dElevation\":-88}},{\"delta\":{\"node-LL1\":{\"lon\":-924,\"lat\":-109}},\"attributes\":{\"localNode\":[\"downstreamStopLine\",\"roundedCapStyleB\"],\"disabled\":[\"whiteLine\",\"partialCurbIntrusion\"],\"enabled\":[\"loadingzoneOnLeft\",\"audibleSignalingPresent\",\"freeParking\"],\"data\":[{\"laneCrownPointCenter\":55},{\"laneAngle\":-98}],\"dWidth\":-319,\"dElevation\":-89}}]}}}}},{\"name\":\"IA\",\"id\":{\"region\":23018,\"id\":35659},\"anchor\":{\"lat\":-544509288,\"long\":-1334375239,\"elevation\":-3608},\"laneWidth\":14780,\"directionality\":\"forward\",\"closedPath\":true,\"direction\":{\"from000-0to022-5degrees\":false,\"from022-5to045-0degrees\":false,\"from045-0to067-5degrees\":true,\"from067-5to090-0degrees\":false,\"from090-0to112-5degrees\":false,\"from112-5to135-0degrees\":false,\"from135-0to157-5degrees\":false,\"from157-5to180-0degrees\":false,\"from180-0to202-5degrees\":false,\"from202-5to225-0degrees\":false,\"from225-0to247-5degrees\":false,\"from247-5to270-0degrees\":false,\"from270-0to292-5degrees\":false,\"from292-5to315-0degrees\":false,\"from315-0to337-5degrees\":false,\"from337-5to360-0degrees\":false},\"description\":{\"path\":{\"scale\":5,\"offset\":{\"xy\":{\"computed\":{\"referenceLaneId\":108,\"offsetXaxis\":{\"small\":-1574},\"offsetYaxis\":{\"large\":-635},\"rotateXY\":21792,\"scaleXaxis\":689,\"scaleYaxis\":640}}}}}},{\"name\":\"I\",\"id\":{\"region\":32256,\"id\":28265},\"anchor\":{\"lat\":725366646,\"long\":-566506763,\"elevation\":6227},\"laneWidth\":26178,\"directionality\":\"reverse\",\"closedPath\":true,\"direction\":{\"from000-0to022-5degrees\":false,\"from022-5to045-0degrees\":false,\"from045-0to067-5degrees\":false,\"from067-5to090-0degrees\":false,\"from090-0to112-5degrees\":false,\"from112-5to135-0degrees\":false,\"from135-0to157-5degrees\":false,\"from157-5to180-0degrees\":true,\"from180-0to202-5degrees\":false,\"from202-5to225-0degrees\":false,\"from225-0to247-5degrees\":false,\"from247-5to270-0degrees\":false,\"from270-0to292-5degrees\":false,\"from292-5to315-0degrees\":false,\"from315-0to337-5degrees\":false,\"from337-5to360-0degrees\":false},\"description\":{\"path\":{\"scale\":1,\"offset\":{\"ll\":{\"nodes\":[{\"delta\":{\"node-LL5\":{\"lon\":2030663,\"lat\":-517129}},\"attributes\":{\"localNode\":[\"safeIsland\",\"hydrantPresent\",\"curbPresentAtStepOff\"],\"disabled\":[\"sharedWithTrackedVehicle\",\"transitStopOnLeft\",\"headInParking\",\"audibleSignalingPresent\"],\"enabled\":[\"doNotBlock\",\"mergingLaneLeft\"],\"data\":[{\"laneCrownPointRight\":48},{\"laneCrownPointRight\":-114}],\"dWidth\":-505,\"dElevation\":-119}},{\"delta\":{\"node-LL6\":{\"lon\":-5645920,\"lat\":-5242762}},\"attributes\":{\"localNode\":[\"reserved\",\"safeIsland\",\"mergePoint\"],\"disabled\":[\"turnOutPointOnLeft\"],\"enabled\":[\"timeRestrictionsOnParking\",\"adaptiveTimingPresent\",\"turnOutPointOnRight\",\"bikeBoxInFront\"],\"data\":[{\"laneCrownPointCenter\":-58},{\"pathEndPointAngle\":-55},{\"pathEndPointAngle\":-58}],\"dWidth\":472,\"dElevation\":-190}}]}}}}}],\"doNotUse3\":16,\"doNotUse4\":13,\"content\":{\"genericSign\":[{\"item\":{\"itis\":61599}},{\"item\":{\"itis\":47850}},{\"item\":{\"itis\":39204}},{\"item\":{\"text\":\"IA5St\"}},{\"item\":{\"text\":\"IA5S\"}}]},\"url\":\"IA5\"},{\"doNotUse1\":7,\"frameType\":\"roadSignage\",\"msgId\":{\"furtherInfoID\":\"4F43\"},\"startYear\":2457,\"startTime\":66787,\"durationTime\":19034,\"priority\":4,\"doNotUse2\":16,\"regions\":[{\"name\":\"IA5St\",\"id\":{\"region\":61846,\"id\":12218},\"anchor\":{\"lat\":202451669,\"long\":-1016248785,\"elevation\":14777},\"laneWidth\":4825,\"directionality\":\"unavailable\",\"closedPath\":true,\"direction\":{\"from000-0to022-5degrees\":false,\"from022-5to045-0degrees\":false,\"from045-0to067-5degrees\":false,\"from067-5to090-0degrees\":false,\"from090-0to112-5degrees\":false,\"from112-5to135-0degrees\":false,\"from135-0to157-5degrees\":false,\"from157-5to180-0degrees\":false,\"from180-0to202-5degrees\":true,\"from202-5to225-0degrees\":false,\"from225-0to247-5degrees\":false,\"from247-5to270-0degrees\":false,\"from270-0to292-5degrees\":false,\"from292-5to315-0degrees\":false,\"from315-0to337-5degrees\":false,\"from337-5to360-0degrees\":false},\"description\":{\"geometry\":{\"direction\":{\"from000-0to022-5degrees\":false,\"from022-5to045-0degrees\":false,\"from045-0to067-5degrees\":false,\"from067-5to090-0degrees\":false,\"from090-0to112-5degrees\":false,\"from112-5to135-0degrees\":false,\"from135-0to157-5degrees\":false,\"from157-5to180-0degrees\":false,\"from180-0to202-5degrees\":false,\"from202-5to225-0degrees\":false,\"from225-0to247-5degrees\":false,\"from247-5to270-0degrees\":false,\"from270-0to292-5degrees\":false,\"from292-5to315-0degrees\":false,\"from315-0to337-5degrees\":true,\"from337-5to360-0degrees\":false},\"extent\":\"useFor100meters\",\"laneWidth\":23305,\"circle\":{\"center\":{\"lat\":257084126,\"long\":-1572221105,\"elevation\":10372},\"radius\":3021,\"units\":\"cm2-5\"}}}},{\"name\":\"IA5S\",\"id\":{\"region\":44916,\"id\":14928},\"anchor\":{\"lat\":-391962488,\"long\":-1442690475,\"elevation\":975},\"laneWidth\":8081,\"directionality\":\"forward\",\"closedPath\":true,\"direction\":{\"from000-0to022-5degrees\":false,\"from022-5to045-0degrees\":false,\"from045-0to067-5degrees\":false,\"from067-5to090-0degrees\":false,\"from090-0to112-5degrees\":false,\"from112-5to135-0degrees\":false,\"from135-0to157-5degrees\":false,\"from157-5to180-0degrees\":true,\"from180-0to202-5degrees\":false,\"from202-5to225-0degrees\":false,\"from225-0to247-5degrees\":false,\"from247-5to270-0degrees\":false,\"from270-0to292-5degrees\":false,\"from292-5to315-0degrees\":false,\"from315-0to337-5degrees\":false,\"from337-5to360-0degrees\":false},\"description\":{\"path\":{\"scale\":15,\"offset\":{\"xy\":{\"computed\":{\"referenceLaneId\":216,\"offsetXaxis\":{\"small\":682},\"offsetYaxis\":{\"large\":-6571},\"rotateXY\":11786,\"scaleXaxis\":-269,\"scaleYaxis\":-432}}}}}},{\"name\":\"IA5\",\"id\":{\"region\":15268,\"id\":63916},\"anchor\":{\"lat\":-14883901,\"long\":1470459302,\"elevation\":47965},\"laneWidth\":374,\"directionality\":\"forward\",\"closedPath\":true,\"direction\":{\"from000-0to022-5degrees\":true,\"from022-5to045-0degrees\":false,\"from045-0to067-5degrees\":false,\"from067-5to090-0degrees\":false,\"from090-0to112-5degrees\":false,\"from112-5to135-0degrees\":false,\"from135-0to157-5degrees\":false,\"from157-5to180-0degrees\":false,\"from180-0to202-5degrees\":false,\"from202-5to225-0degrees\":false,\"from225-0to247-5degrees\":false,\"from247-5to270-0degrees\":false,\"from270-0to292-5degrees\":false,\"from292-5to315-0degrees\":false,\"from315-0to337-5degrees\":false,\"from337-5to360-0degrees\":false},\"description\":{\"oldRegion\":{\"direction\":{\"from000-0to022-5degrees\":false,\"from022-5to045-0degrees\":false,\"from045-0to067-5degrees\":false,\"from067-5to090-0degrees\":false,\"from090-0to112-5degrees\":true,\"from112-5to135-0degrees\":false,\"from135-0to157-5degrees\":false,\"from157-5to180-0degrees\":false,\"from180-0to202-5degrees\":false,\"from202-5to225-0degrees\":false,\"from225-0to247-5degrees\":false,\"from247-5to270-0degrees\":false,\"from270-0to292-5degrees\":false,\"from292-5to315-0degrees\":false,\"from315-0to337-5degrees\":false,\"from337-5to360-0degrees\":false},\"extent\":\"useFor100000meters\",\"area\":{\"circle\":{\"center\":{\"lat\":223434207,\"long\":-714422034,\"elevation\":41663},\"radius\":737,\"units\":\"cm2-5\"}}}}}],\"doNotUse3\":2,\"doNotUse4\":31,\"content\":{\"workZone\":[{\"item\":{\"text\":\"IA5St\"}},{\"item\":{\"text\":\"IA5St\"}},{\"item\":{\"itis\":52884}}]},\"url\":\"I\"},{\"doNotUse1\":16,\"frameType\":\"roadSignage\",\"msgId\":{\"roadSignID\":{\"position\":{\"lat\":604037802,\"long\":-124613998,\"elevation\":46289},\"viewAngle\":{\"from000-0to022-5degrees\":false,\"from022-5to045-0degrees\":false,\"from045-0to067-5degrees\":false,\"from067-5to090-0degrees\":false,\"from090-0to112-5degrees\":false,\"from112-5to135-0degrees\":false,\"from135-0to157-5degrees\":false,\"from157-5to180-0degrees\":false,\"from180-0to202-5degrees\":false,\"from202-5to225-0degrees\":true,\"from225-0to247-5degrees\":false,\"from247-5to270-0degrees\":false,\"from270-0to292-5degrees\":false,\"from292-5to315-0degrees\":false,\"from315-0to337-5degrees\":false,\"from337-5to360-0degrees\":false},\"mutcdCode\":\"guide\",\"crc\":\"4F43\"}},\"startYear\":135,\"startTime\":30119,\"durationTime\":17072,\"priority\":7,\"doNotUse2\":6,\"regions\":[{\"name\":\"IA5S\",\"id\":{\"region\":35731,\"id\":64365},\"anchor\":{\"lat\":251341270,\"long\":-1550588968,\"elevation\":18073},\"laneWidth\":19174,\"directionality\":\"forward\",\"closedPath\":true,\"direction\":{\"from000-0to022-5degrees\":false,\"from022-5to045-0degrees\":false,\"from045-0to067-5degrees\":false,\"from067-5to090-0degrees\":false,\"from090-0to112-5degrees\":false,\"from112-5to135-0degrees\":false,\"from135-0to157-5degrees\":false,\"from157-5to180-0degrees\":false,\"from180-0to202-5degrees\":false,\"from202-5to225-0degrees\":false,\"from225-0to247-5degrees\":false,\"from247-5to270-0degrees\":false,\"from270-0to292-5degrees\":false,\"from292-5to315-0degrees\":true,\"from315-0to337-5degrees\":true,\"from337-5to360-0degrees\":true},\"description\":{\"geometry\":{\"direction\":{\"from000-0to022-5degrees\":false,\"from022-5to045-0degrees\":false,\"from045-0to067-5degrees\":false,\"from067-5to090-0degrees\":false,\"from090-0to112-5degrees\":false,\"from112-5to135-0degrees\":true,\"from135-0to157-5degrees\":false,\"from157-5to180-0degrees\":false,\"from180-0to202-5degrees\":false,\"from202-5to225-0degrees\":false,\"from225-0to247-5degrees\":false,\"from247-5to270-0degrees\":false,\"from270-0to292-5degrees\":false,\"from292-5to315-0degrees\":false,\"from315-0to337-5degrees\":false,\"from337-5to360-0degrees\":false},\"extent\":\"useFor3meters\",\"laneWidth\":19339,\"circle\":{\"center\":{\"lat\":-590142898,\"long\":192563845,\"elevation\":3040},\"radius\":734,\"units\":\"meter\"}}}},{\"name\":\"IA5\",\"id\":{\"region\":13160,\"id\":48242},\"anchor\":{\"lat\":227302831,\"long\":-891580621,\"elevation\":7072},\"laneWidth\":5923,\"directionality\":\"reverse\",\"closedPath\":true,\"direction\":{\"from000-0to022-5degrees\":true,\"from022-5to045-0degrees\":false,\"from045-0to067-5degrees\":false,\"from067-5to090-0degrees\":false,\"from090-0to112-5degrees\":false,\"from112-5to135-0degrees\":false,\"from135-0to157-5degrees\":false,\"from157-5to180-0degrees\":false,\"from180-0to202-5degrees\":false,\"from202-5to225-0degrees\":false,\"from225-0to247-5degrees\":false,\"from247-5to270-0degrees\":false,\"from270-0to292-5degrees\":false,\"from292-5to315-0degrees\":false,\"from315-0to337-5degrees\":false,\"from337-5to360-0degrees\":false},\"description\":{\"oldRegion\":{\"direction\":{\"from000-0to022-5degrees\":false,\"from022-5to045-0degrees\":false,\"from045-0to067-5degrees\":false,\"from067-5to090-0degrees\":false,\"from090-0to112-5degrees\":true,\"from112-5to135-0degrees\":false,\"from135-0to157-5degrees\":false,\"from157-5to180-0degrees\":false,\"from180-0to202-5degrees\":false,\"from202-5to225-0degrees\":false,\"from225-0to247-5degrees\":false,\"from247-5to270-0degrees\":false,\"from270-0to292-5degrees\":false,\"from292-5to315-0degrees\":false,\"from315-0to337-5degrees\":false,\"from337-5to360-0degrees\":false},\"extent\":\"useFor3meters\",\"area\":{\"circle\":{\"center\":{\"lat\":368610426,\"long\":-1703460317,\"elevation\":1004},\"radius\":2194,\"units\":\"meter\"}}}}},{\"name\":\"I\",\"id\":{\"region\":58508,\"id\":15927},\"anchor\":{\"lat\":892488592,\"long\":-431640924,\"elevation\":41561},\"laneWidth\":26527,\"directionality\":\"both\",\"closedPath\":true,\"direction\":{\"from000-0to022-5degrees\":false,\"from022-5to045-0degrees\":false,\"from045-0to067-5degrees\":false,\"from067-5to090-0degrees\":true,\"from090-0to112-5degrees\":false,\"from112-5to135-0degrees\":false,\"from135-0to157-5degrees\":false,\"from157-5to180-0degrees\":false,\"from180-0to202-5degrees\":false,\"from202-5to225-0degrees\":false,\"from225-0to247-5degrees\":false,\"from247-5to270-0degrees\":false,\"from270-0to292-5degrees\":false,\"from292-5to315-0degrees\":false,\"from315-0to337-5degrees\":false,\"from337-5to360-0degrees\":false},\"description\":{\"oldRegion\":{\"direction\":{\"from000-0to022-5degrees\":false,\"from022-5to045-0degrees\":false,\"from045-0to067-5degrees\":false,\"from067-5to090-0degrees\":false,\"from090-0to112-5degrees\":false,\"from112-5to135-0degrees\":false,\"from135-0to157-5degrees\":false,\"from157-5to180-0degrees\":false,\"from180-0to202-5degrees\":false,\"from202-5to225-0degrees\":false,\"from225-0to247-5degrees\":false,\"from247-5to270-0degrees\":false,\"from270-0to292-5degrees\":false,\"from292-5to315-0degrees\":true,\"from315-0to337-5degrees\":false,\"from337-5to360-0degrees\":false},\"extent\":\"useFor50000meters\",\"area\":{\"regionPointSet\":{\"anchor\":{\"lat\":-113602543,\"long\":717746718,\"elevation\":49498},\"scale\":1,\"nodeList\":[{\"xOffset\":27670,\"yOffset\":-14790,\"zOffset\":-21638},{\"xOffset\":3020,\"yOffset\":-9872,\"zOffset\":-109},{\"xOffset\":-24382,\"yOffset\":23709,\"zOffset\":-862},{\"xOffset\":-26476,\"yOffset\":-6439,\"zOffset\":-23411}]}}}}},{\"name\":\"IA5\",\"id\":{\"region\":379,\"id\":22438},\"anchor\":{\"lat\":-281093797,\"long\":556669965,\"elevation\":29497},\"laneWidth\":7880,\"directionality\":\"reverse\",\"closedPath\":true,\"direction\":{\"from000-0to022-5degrees\":false,\"from022-5to045-0degrees\":false,\"from045-0to067-5degrees\":false,\"from067-5to090-0degrees\":false,\"from090-0to112-5degrees\":false,\"from112-5to135-0degrees\":false,\"from135-0to157-5degrees\":false,\"from157-5to180-0degrees\":false,\"from180-0to202-5degrees\":false,\"from202-5to225-0degrees\":false,\"from225-0to247-5degrees\":false,\"from247-5to270-0degrees\":false,\"from270-0to292-5degrees\":false,\"from292-5to315-0degrees\":false,\"from315-0to337-5degrees\":true,\"from337-5to360-0degrees\":false},\"description\":{\"geometry\":{\"direction\":{\"from000-0to022-5degrees\":false,\"from022-5to045-0degrees\":false,\"from045-0to067-5degrees\":false,\"from067-5to090-0degrees\":false,\"from090-0to112-5degrees\":false,\"from112-5to135-0degrees\":false,\"from135-0to157-5degrees\":false,\"from157-5to180-0degrees\":false,\"from180-0to202-5degrees\":false,\"from202-5to225-0degrees\":false,\"from225-0to247-5degrees\":false,\"from247-5to270-0degrees\":false,\"from270-0to292-5degrees\":false,\"from292-5to315-0degrees\":false,\"from315-0to337-5degrees\":true,\"from337-5to360-0degrees\":false},\"extent\":\"useFor500000meters\",\"laneWidth\":2148,\"circle\":{\"center\":{\"lat\":163173661,\"long\":-872411303,\"elevation\":55588},\"radius\":489,\"units\":\"cm2-5\"}}}}],\"doNotUse3\":8,\"doNotUse4\":29,\"content\":{\"advisory\":[{\"item\":{\"itis\":44093}},{\"item\":{\"itis\":65240}},{\"item\":{\"text\":\"IA\"}}]},\"url\":\"I\"},{\"doNotUse1\":31,\"frameType\":\"advisory\",\"msgId\":{\"roadSignID\":{\"position\":{\"lat\":-864002503,\"long\":-654286715,\"elevation\":43804},\"viewAngle\":{\"from000-0to022-5degrees\":false,\"from022-5to045-0degrees\":false,\"from045-0to067-5degrees\":false,\"from067-5to090-0degrees\":false,\"from090-0to112-5degrees\":false,\"from112-5to135-0degrees\":false,\"from135-0to157-5degrees\":true,\"from157-5to180-0degrees\":false,\"from180-0to202-5degrees\":false,\"from202-5to225-0degrees\":false,\"from225-0to247-5degrees\":false,\"from247-5to270-0degrees\":false,\"from270-0to292-5degrees\":false,\"from292-5to315-0degrees\":false,\"from315-0to337-5degrees\":false,\"from337-5to360-0degrees\":false},\"mutcdCode\":\"maintenance\",\"crc\":\"4F43\"}},\"startYear\":3076,\"startTime\":282183,\"durationTime\":14436,\"priority\":6,\"doNotUse2\":11,\"regions\":[{\"name\":\"IA5St\",\"id\":{\"region\":11880,\"id\":33814},\"anchor\":{\"lat\":51295938,\"long\":799818234,\"elevation\":10466},\"laneWidth\":10554,\"directionality\":\"forward\",\"closedPath\":true,\"direction\":{\"from000-0to022-5degrees\":false,\"from022-5to045-0degrees\":false,\"from045-0to067-5degrees\":false,\"from067-5to090-0degrees\":false,\"from090-0to112-5degrees\":false,\"from112-5to135-0degrees\":false,\"from135-0to157-5degrees\":false,\"from157-5to180-0degrees\":false,\"from180-0to202-5degrees\":false,\"from202-5to225-0degrees\":false,\"from225-0to247-5degrees\":false,\"from247-5to270-0degrees\":false,\"from270-0to292-5degrees\":true,\"from292-5to315-0degrees\":false,\"from315-0to337-5degrees\":false,\"from337-5to360-0degrees\":false},\"description\":{\"path\":{\"scale\":10,\"offset\":{\"xy\":{\"nodes\":[{\"delta\":{\"node-XY1\":{\"x\":144,\"y\":-502}},\"attributes\":{\"localNode\":[\"mergePoint\"],\"disabled\":[\"transitStopOnLeft\",\"bikeBoxInFront\",\"doNotBlock\"],\"enabled\":[\"mergingLaneLeft\",\"mergingLaneRight\"],\"data\":[{\"laneCrownPointCenter\":91},{\"laneCrownPointLeft\":-60},{\"laneCrownPointLeft\":-118}],\"dWidth\":-80,\"dElevation\":-211}},{\"delta\":{\"node-XY1\":{\"x\":144,\"y\":-502}},\"attributes\":{\"localNode\":[\"hydrantPresent\",\"roundedCapStyleA\",\"roundedCapStyleB\"],\"disabled\":[\"turnOutPointOnRight\"],\"enabled\":[\"adjacentParkingOnRight\",\"curbOnLeft\"],\"data\":[{\"laneCrownPointCenter\":-3},{\"laneCrownPointCenter\":-23},{\"speedLimits\":[{\"type\":\"vehicleMinSpeed\",\"speed\":5260},{\"type\":\"maxSpeedInConstructionZone\",\"speed\":7676}]}],\"dWidth\":-98,\"dElevation\":-300}},{\"delta\":{\"node-XY5\":{\"x\":6552,\"y\":-7382}},\"attributes\":{\"localNode\":[\"curbPresentAtStepOff\",\"stopLine\",\"reserved\",\"roundedCapStyleB\"],\"disabled\":[\"curbOnLeft\",\"turnOutPointOnRight\",\"whiteLine\",\"curbOnRight\"],\"enabled\":[\"sharedWithTrackedVehicle\",\"audibleSignalingPresent\",\"headInParking\"],\"data\":[{\"laneCrownPointCenter\":-7},{\"laneAngle\":68},{\"laneCrownPointLeft\":-39}],\"dWidth\":287,\"dElevation\":510}},{\"delta\":{\"node-XY1\":{\"x\":-310,\"y\":-500}},\"attributes\":{\"localNode\":[\"roundedCapStyleA\"],\"disabled\":[\"timeRestrictionsOnParking\",\"reserved\",\"parallelParking\",\"midBlockCurbPresent\"],\"enabled\":[\"transitStopOnRight\",\"whiteLine\",\"taperToCenterLine\",\"adjacentParkingOnLeft\",\"timeRestrictionsOnParking\"],\"data\":[{\"laneAngle\":-59},{\"laneCrownPointCenter\":105},{\"laneCrownPointCenter\":25},{\"speedLimits\":[{\"type\":\"vehicleNightMaxSpeed\",\"speed\":2245},{\"type\":\"vehicleMaxSpeed\",\"speed\":1700}]},{\"speedLimits\":[{\"type\":\"maxSpeedInSchoolZone\",\"speed\":7839},{\"type\":\"maxSpeedInSchoolZone\",\"speed\":1190},{\"type\":\"truckMaxSpeed\",\"speed\":3947}]}],\"dWidth\":497,\"dElevation\":-208}},{\"delta\":{\"node-LatLon\":{\"lon\":-1625296958,\"lat\":501091223}},\"attributes\":{\"localNode\":[\"downstreamStartNode\",\"downstreamStopLine\",\"safeIsland\"],\"disabled\":[\"adjacentParkingOnLeft\",\"partialCurbIntrusion\",\"taperToRight\"],\"enabled\":[\"unEvenPavementPresent\",\"adjacentParkingOnRight\"],\"data\":[{\"laneCrownPointCenter\":86}],\"dWidth\":-90,\"dElevation\":131}}]}}}}},{\"name\":\"IA5S\",\"id\":{\"region\":48039,\"id\":14622},\"anchor\":{\"lat\":419808681,\"long\":-1470200813,\"elevation\":37213},\"laneWidth\":25845,\"directionality\":\"unavailable\",\"closedPath\":true,\"direction\":{\"from000-0to022-5degrees\":false,\"from022-5to045-0degrees\":false,\"from045-0to067-5degrees\":false,\"from067-5to090-0degrees\":true,\"from090-0to112-5degrees\":false,\"from112-5to135-0degrees\":false,\"from135-0to157-5degrees\":false,\"from157-5to180-0degrees\":false,\"from180-0to202-5degrees\":false,\"from202-5to225-0degrees\":false,\"from225-0to247-5degrees\":false,\"from247-5to270-0degrees\":false,\"from270-0to292-5degrees\":false,\"from292-5to315-0degrees\":false,\"from315-0to337-5degrees\":false,\"from337-5to360-0degrees\":false},\"description\":{\"geometry\":{\"direction\":{\"from000-0to022-5degrees\":false,\"from022-5to045-0degrees\":false,\"from045-0to067-5degrees\":false,\"from067-5to090-0degrees\":false,\"from090-0to112-5degrees\":false,\"from112-5to135-0degrees\":false,\"from135-0to157-5degrees\":false,\"from157-5to180-0degrees\":false,\"from180-0to202-5degrees\":false,\"from202-5to225-0degrees\":false,\"from225-0to247-5degrees\":false,\"from247-5to270-0degrees\":true,\"from270-0to292-5degrees\":false,\"from292-5to315-0degrees\":false,\"from315-0to337-5degrees\":false,\"from337-5to360-0degrees\":false},\"extent\":\"useFor3meters\",\"laneWidth\":25719,\"circle\":{\"center\":{\"lat\":-666313075,\"long\":639822734,\"elevation\":29597},\"radius\":1325,\"units\":\"foot\"}}}}],\"doNotUse3\":11,\"doNotUse4\":27,\"content\":{\"speedLimit\":[{\"item\":{\"text\":\"I\"}}]},\"url\":\"IA\"},{\"doNotUse1\":18,\"frameType\":\"roadSignage\",\"msgId\":{\"roadSignID\":{\"position\":{\"lat\":889823043,\"long\":-537303585,\"elevation\":29359},\"viewAngle\":{\"from000-0to022-5degrees\":false,\"from022-5to045-0degrees\":false,\"from045-0to067-5degrees\":false,\"from067-5to090-0degrees\":false,\"from090-0to112-5degrees\":false,\"from112-5to135-0degrees\":true,\"from135-0to157-5degrees\":false,\"from157-5to180-0degrees\":false,\"from180-0to202-5degrees\":false,\"from202-5to225-0degrees\":false,\"from225-0to247-5degrees\":false,\"from247-5to270-0degrees\":false,\"from270-0to292-5degrees\":false,\"from292-5to315-0degrees\":false,\"from315-0to337-5degrees\":false,\"from337-5to360-0degrees\":false},\"mutcdCode\":\"maintenance\",\"crc\":\"4F43\"}},\"startYear\":1652,\"startTime\":115878,\"durationTime\":7970,\"priority\":6,\"doNotUse2\":27,\"regions\":[{\"name\":\"I\",\"id\":{\"region\":26015,\"id\":40525},\"anchor\":{\"lat\":112058765,\"long\":1125609019,\"elevation\":54648},\"laneWidth\":31409,\"directionality\":\"both\",\"closedPath\":true,\"direction\":{\"from000-0to022-5degrees\":false,\"from022-5to045-0degrees\":false,\"from045-0to067-5degrees\":false,\"from067-5to090-0degrees\":false,\"from090-0to112-5degrees\":false,\"from112-5to135-0degrees\":false,\"from135-0to157-5degrees\":false,\"from157-5to180-0degrees\":false,\"from180-0to202-5degrees\":false,\"from202-5to225-0degrees\":false,\"from225-0to247-5degrees\":false,\"from247-5to270-0degrees\":false,\"from270-0to292-5degrees\":true,\"from292-5to315-0degrees\":false,\"from315-0to337-5degrees\":false,\"from337-5to360-0degrees\":false},\"description\":{\"oldRegion\":{\"direction\":{\"from000-0to022-5degrees\":false,\"from022-5to045-0degrees\":false,\"from045-0to067-5degrees\":false,\"from067-5to090-0degrees\":false,\"from090-0to112-5degrees\":false,\"from112-5to135-0degrees\":false,\"from135-0to157-5degrees\":false,\"from157-5to180-0degrees\":true,\"from180-0to202-5degrees\":false,\"from202-5to225-0degrees\":false,\"from225-0to247-5degrees\":false,\"from247-5to270-0degrees\":false,\"from270-0to292-5degrees\":false,\"from292-5to315-0degrees\":false,\"from315-0to337-5degrees\":false,\"from337-5to360-0degrees\":false},\"extent\":\"useFor50000meters\",\"area\":{\"shapePointSet\":{\"anchor\":{\"lat\":733403986,\"long\":1001009347,\"elevation\":23252},\"laneWidth\":14952,\"directionality\":\"unavailable\",\"nodeList\":{\"computed\":{\"referenceLaneId\":188,\"offsetXaxis\":{\"large\":-8154},\"offsetYaxis\":{\"large\":-28485},\"rotateXY\":224,\"scaleXaxis\":32,\"scaleYaxis\":1787}}}}}}}],\"doNotUse3\":14,\"doNotUse4\":21,\"content\":{\"exitService\":[{\"item\":{\"text\":\"I\"}}]},\"url\":\"I\"}]},\"dataType\":\"us.dot.its.jpo.ode.plugin.j2735.travelerinformation.TravelerInformation\"}}"; + + // Has a different payload ID. Should be allowed through + String inputTim4 = "{\"metadata\":{\"logFileName\":\"\",\"recordType\":\"timMsg\",\"securityResultCode\":\"success\",\"receivedMessageDetails\":{\"rxSource\":\"NA\"},\"payloadType\":\"us.dot.its.jpo.ode.model.OdeTimPayload\",\"serialId\":{\"streamId\":\"b2d15f2d-7461-4083-b3df-b4efadab4d17\",\"bundleSize\":1,\"bundleId\":0,\"recordId\":0,\"serialNumber\":0},\"odeReceivedAt\":\"2025-02-01T01:20:45.739Z\",\"schemaVersion\":8,\"maxDurationTime\":0,\"recordGeneratedAt\":\"\",\"recordGeneratedBy\":\"RSU\",\"sanitized\":false,\"odePacketID\":\"\",\"odeTimStartDateTime\":\"\",\"asn1\":\"001F83A175D472274F43544554205354520A4C16B18193D0D1F9CDF54733FB1BFC0C983FCFC48D24FF97A474B8A754A9112A6F690200192EFCB5FF96D90FA32D4E83FC0C9830B5F5FC150A5059C545235AC20227C697080018815F84759CB3BF452C850424643A30E028544E9C511560A9DD8C2629F0D4470DBB3DDB4316096FC100800809BC746A108C8F26FC4C3208DA0E61091B7429182D3BFC0C98359EA8B4B454C16E606F037AE007A1CDE32000152E6C0ECDF612A90558D403FC049BF003734AC1C240EC930B39E850A7990A808008C033EFC47606FDDFA252B4A9942280C1020C9D818700EC4B4A76680C001D9F981240013111914408214602F8173D850A0D48F09F5D75264929260B5A7D27260B5A65260B56744F43999104E394B5204FF09260B5A7D3E32C5F74A0DB09EA975B8C1724DC92D9201005800092D84A89EF67BC1B27429C710979A5FE0E4C16B4F5EE874A08F2404C40AA60E2A09E79F91602003E5DB0AA9B32A2E0A6F36507F829305ACEE93E6B134C1CCC3C2EF3FA5CB5D02ECE000142002950BD8FB7D02D26BB6CAFCB848BE4A9260B5A7D29260B5A7D19D28125C17566972EA98F7172471344010153D0C21C1D69E158731BFC1C982D69E2E4FEDB544A012D60EDDB5D7569995CCC001CB02000CB8B449E02D39DB1072106F80B79BFC14982D666D178E4A198A3579B12B09915D01723B0000A10002A973AEAF40B82284427D9124DFE024F9230F8DD6AD73490518F80A3B259CF3FC40014001266976FBC88CB08E20EE8AD087EC16463A2B7AC5E62CB83FC9C830B7275F28A3128CDB2491AFF05260B580BDABD3249C784B718EFDC1906727B228001160002B10C89FAF5F0E9BA4F0AC74920F4947402561EBFB6201930424BF9E8112A39CA22519425D8E01001A7A1E0222723B864CB17F849305AD3E92E6884164E2CE7F0A6BD84FE4E38949D300081A01A290029F8111120048308876C910829B04B5148014FC9621814460542FAA24A460FBF82D2CF1A8CE66032A7E6A0807028A04283228610217947C12CE3FFF20CA031F809A2007D242408F0B4510F23D2A2646294D48A41F4F8494C87B58CCFE2983829A707069C17A4BBF23992859B3A528C03ACD3506FF07260B5A7BBA7391E53AAABAA44EA1584A857727A910002C0020391DD0DEDC78D916CBD8D839D52DABDB084919305C975AABA210D2D0CDF7A0ABC1000D3D0D9D071298F916D83FC049B2CFCF26A78A5951B5CC28075CAF1EAC780042808048EB0ADE229537A0161356A3A68175E5809621740382083BEDD5810921240\",\"originIp\":\"172.20.0.1\"},\"payload\":{\"data\":{\"msgCnt\":93,\"timeStamp\":291367,\"packetID\":\"4F4354455420535453\",\"urlB\":\"IA5\",\"dataFrames\":[{\"doNotUse1\":0,\"frameType\":\"commercialSignage\",\"msgId\":{\"furtherInfoID\":\"4F43\"},\"startYear\":1150,\"startTime\":473045,\"durationTime\":3687,\"priority\":7,\"doNotUse2\":22,\"regions\":[{\"name\":\"IA\",\"id\":{\"region\":64764,\"id\":18642},\"anchor\":{\"lat\":172032029,\"long\":-1025506517,\"elevation\":13386},\"laneWidth\":19949,\"directionality\":\"unavailable\",\"closedPath\":true,\"direction\":{\"from000-0to022-5degrees\":false,\"from022-5to045-0degrees\":false,\"from045-0to067-5degrees\":false,\"from067-5to090-0degrees\":false,\"from090-0to112-5degrees\":false,\"from112-5to135-0degrees\":false,\"from135-0to157-5degrees\":true,\"from157-5to180-0degrees\":false,\"from180-0to202-5degrees\":false,\"from202-5to225-0degrees\":false,\"from225-0to247-5degrees\":false,\"from247-5to270-0degrees\":false,\"from270-0to292-5degrees\":false,\"from292-5to315-0degrees\":false,\"from315-0to337-5degrees\":false,\"from337-5to360-0degrees\":false},\"description\":{\"path\":{\"scale\":9,\"offset\":{\"xy\":{\"computed\":{\"referenceLaneId\":252,\"offsetXaxis\":{\"large\":-5120},\"offsetYaxis\":{\"small\":-585},\"rotateXY\":8692,\"scaleXaxis\":-422,\"scaleYaxis\":464}}}}}},{\"name\":\"IA\",\"id\":{\"region\":2911,\"id\":24513},\"anchor\":{\"lat\":217001329,\"long\":-436271951,\"elevation\":28809},\"laneWidth\":30930,\"directionality\":\"both\",\"closedPath\":true,\"direction\":{\"from000-0to022-5degrees\":false,\"from022-5to045-0degrees\":false,\"from045-0to067-5degrees\":false,\"from067-5to090-0degrees\":false,\"from090-0to112-5degrees\":true,\"from112-5to135-0degrees\":false,\"from135-0to157-5degrees\":false,\"from157-5to180-0degrees\":false,\"from180-0to202-5degrees\":false,\"from202-5to225-0degrees\":false,\"from225-0to247-5degrees\":false,\"from247-5to270-0degrees\":false,\"from270-0to292-5degrees\":false,\"from292-5to315-0degrees\":false,\"from315-0to337-5degrees\":false,\"from337-5to360-0degrees\":false},\"description\":{\"path\":{\"scale\":8,\"offset\":{\"ll\":{\"nodes\":[{\"delta\":{\"node-LL4\":{\"lon\":115258,\"lat\":80231}},\"attributes\":{\"localNode\":[\"curbPresentAtStepOff\",\"hydrantPresent\",\"mergePoint\",\"divergePoint\",\"reserved\"],\"disabled\":[\"transitStopOnRight\",\"adaptiveTimingPresent\",\"loadingzoneOnLeft\",\"costToPark\"],\"enabled\":[\"curbOnLeft\"],\"data\":[{\"speedLimits\":[{\"type\":\"truckNightMaxSpeed\",\"speed\":6769},{\"type\":\"truckMaxSpeed\",\"speed\":4438},{\"type\":\"maxSpeedInSchoolZone\",\"speed\":2679},{\"type\":\"vehiclesWithTrailersNightMaxSpeed\",\"speed\":3110},{\"type\":\"vehicleMaxSpeed\",\"speed\":1987}]}],\"dWidth\":-188,\"dElevation\":-61}},{\"delta\":{\"node-LL6\":{\"lon\":5893850,\"lat\":-6770613}},\"attributes\":{\"localNode\":[\"closedToTraffic\"],\"disabled\":[\"bikeBoxInFront\"],\"enabled\":[\"mergingLaneRight\"],\"data\":[{\"laneCrownPointLeft\":-17}],\"dWidth\":-396,\"dElevation\":-88}},{\"delta\":{\"node-LL1\":{\"lon\":-924,\"lat\":-109}},\"attributes\":{\"localNode\":[\"downstreamStopLine\",\"roundedCapStyleB\"],\"disabled\":[\"whiteLine\",\"partialCurbIntrusion\"],\"enabled\":[\"loadingzoneOnLeft\",\"audibleSignalingPresent\",\"freeParking\"],\"data\":[{\"laneCrownPointCenter\":55},{\"laneAngle\":-98}],\"dWidth\":-319,\"dElevation\":-89}}]}}}}},{\"name\":\"IA\",\"id\":{\"region\":23018,\"id\":35659},\"anchor\":{\"lat\":-544509288,\"long\":-1334375239,\"elevation\":-3608},\"laneWidth\":14780,\"directionality\":\"forward\",\"closedPath\":true,\"direction\":{\"from000-0to022-5degrees\":false,\"from022-5to045-0degrees\":false,\"from045-0to067-5degrees\":true,\"from067-5to090-0degrees\":false,\"from090-0to112-5degrees\":false,\"from112-5to135-0degrees\":false,\"from135-0to157-5degrees\":false,\"from157-5to180-0degrees\":false,\"from180-0to202-5degrees\":false,\"from202-5to225-0degrees\":false,\"from225-0to247-5degrees\":false,\"from247-5to270-0degrees\":false,\"from270-0to292-5degrees\":false,\"from292-5to315-0degrees\":false,\"from315-0to337-5degrees\":false,\"from337-5to360-0degrees\":false},\"description\":{\"path\":{\"scale\":5,\"offset\":{\"xy\":{\"computed\":{\"referenceLaneId\":108,\"offsetXaxis\":{\"small\":-1574},\"offsetYaxis\":{\"large\":-635},\"rotateXY\":21792,\"scaleXaxis\":689,\"scaleYaxis\":640}}}}}},{\"name\":\"I\",\"id\":{\"region\":32256,\"id\":28265},\"anchor\":{\"lat\":725366646,\"long\":-566506763,\"elevation\":6227},\"laneWidth\":26178,\"directionality\":\"reverse\",\"closedPath\":true,\"direction\":{\"from000-0to022-5degrees\":false,\"from022-5to045-0degrees\":false,\"from045-0to067-5degrees\":false,\"from067-5to090-0degrees\":false,\"from090-0to112-5degrees\":false,\"from112-5to135-0degrees\":false,\"from135-0to157-5degrees\":false,\"from157-5to180-0degrees\":true,\"from180-0to202-5degrees\":false,\"from202-5to225-0degrees\":false,\"from225-0to247-5degrees\":false,\"from247-5to270-0degrees\":false,\"from270-0to292-5degrees\":false,\"from292-5to315-0degrees\":false,\"from315-0to337-5degrees\":false,\"from337-5to360-0degrees\":false},\"description\":{\"path\":{\"scale\":1,\"offset\":{\"ll\":{\"nodes\":[{\"delta\":{\"node-LL5\":{\"lon\":2030663,\"lat\":-517129}},\"attributes\":{\"localNode\":[\"safeIsland\",\"hydrantPresent\",\"curbPresentAtStepOff\"],\"disabled\":[\"sharedWithTrackedVehicle\",\"transitStopOnLeft\",\"headInParking\",\"audibleSignalingPresent\"],\"enabled\":[\"doNotBlock\",\"mergingLaneLeft\"],\"data\":[{\"laneCrownPointRight\":48},{\"laneCrownPointRight\":-114}],\"dWidth\":-505,\"dElevation\":-119}},{\"delta\":{\"node-LL6\":{\"lon\":-5645920,\"lat\":-5242762}},\"attributes\":{\"localNode\":[\"reserved\",\"safeIsland\",\"mergePoint\"],\"disabled\":[\"turnOutPointOnLeft\"],\"enabled\":[\"timeRestrictionsOnParking\",\"adaptiveTimingPresent\",\"turnOutPointOnRight\",\"bikeBoxInFront\"],\"data\":[{\"laneCrownPointCenter\":-58},{\"pathEndPointAngle\":-55},{\"pathEndPointAngle\":-58}],\"dWidth\":472,\"dElevation\":-190}}]}}}}}],\"doNotUse3\":16,\"doNotUse4\":13,\"content\":{\"genericSign\":[{\"item\":{\"itis\":61599}},{\"item\":{\"itis\":47850}},{\"item\":{\"itis\":39204}},{\"item\":{\"text\":\"IA5St\"}},{\"item\":{\"text\":\"IA5S\"}}]},\"url\":\"IA5\"},{\"doNotUse1\":7,\"frameType\":\"roadSignage\",\"msgId\":{\"furtherInfoID\":\"4F43\"},\"startYear\":2457,\"startTime\":66787,\"durationTime\":19034,\"priority\":4,\"doNotUse2\":16,\"regions\":[{\"name\":\"IA5St\",\"id\":{\"region\":61846,\"id\":12218},\"anchor\":{\"lat\":202451669,\"long\":-1016248785,\"elevation\":14777},\"laneWidth\":4825,\"directionality\":\"unavailable\",\"closedPath\":true,\"direction\":{\"from000-0to022-5degrees\":false,\"from022-5to045-0degrees\":false,\"from045-0to067-5degrees\":false,\"from067-5to090-0degrees\":false,\"from090-0to112-5degrees\":false,\"from112-5to135-0degrees\":false,\"from135-0to157-5degrees\":false,\"from157-5to180-0degrees\":false,\"from180-0to202-5degrees\":true,\"from202-5to225-0degrees\":false,\"from225-0to247-5degrees\":false,\"from247-5to270-0degrees\":false,\"from270-0to292-5degrees\":false,\"from292-5to315-0degrees\":false,\"from315-0to337-5degrees\":false,\"from337-5to360-0degrees\":false},\"description\":{\"geometry\":{\"direction\":{\"from000-0to022-5degrees\":false,\"from022-5to045-0degrees\":false,\"from045-0to067-5degrees\":false,\"from067-5to090-0degrees\":false,\"from090-0to112-5degrees\":false,\"from112-5to135-0degrees\":false,\"from135-0to157-5degrees\":false,\"from157-5to180-0degrees\":false,\"from180-0to202-5degrees\":false,\"from202-5to225-0degrees\":false,\"from225-0to247-5degrees\":false,\"from247-5to270-0degrees\":false,\"from270-0to292-5degrees\":false,\"from292-5to315-0degrees\":false,\"from315-0to337-5degrees\":true,\"from337-5to360-0degrees\":false},\"extent\":\"useFor100meters\",\"laneWidth\":23305,\"circle\":{\"center\":{\"lat\":257084126,\"long\":-1572221105,\"elevation\":10372},\"radius\":3021,\"units\":\"cm2-5\"}}}},{\"name\":\"IA5S\",\"id\":{\"region\":44916,\"id\":14928},\"anchor\":{\"lat\":-391962488,\"long\":-1442690475,\"elevation\":975},\"laneWidth\":8081,\"directionality\":\"forward\",\"closedPath\":true,\"direction\":{\"from000-0to022-5degrees\":false,\"from022-5to045-0degrees\":false,\"from045-0to067-5degrees\":false,\"from067-5to090-0degrees\":false,\"from090-0to112-5degrees\":false,\"from112-5to135-0degrees\":false,\"from135-0to157-5degrees\":false,\"from157-5to180-0degrees\":true,\"from180-0to202-5degrees\":false,\"from202-5to225-0degrees\":false,\"from225-0to247-5degrees\":false,\"from247-5to270-0degrees\":false,\"from270-0to292-5degrees\":false,\"from292-5to315-0degrees\":false,\"from315-0to337-5degrees\":false,\"from337-5to360-0degrees\":false},\"description\":{\"path\":{\"scale\":15,\"offset\":{\"xy\":{\"computed\":{\"referenceLaneId\":216,\"offsetXaxis\":{\"small\":682},\"offsetYaxis\":{\"large\":-6571},\"rotateXY\":11786,\"scaleXaxis\":-269,\"scaleYaxis\":-432}}}}}},{\"name\":\"IA5\",\"id\":{\"region\":15268,\"id\":63916},\"anchor\":{\"lat\":-14883901,\"long\":1470459302,\"elevation\":47965},\"laneWidth\":374,\"directionality\":\"forward\",\"closedPath\":true,\"direction\":{\"from000-0to022-5degrees\":true,\"from022-5to045-0degrees\":false,\"from045-0to067-5degrees\":false,\"from067-5to090-0degrees\":false,\"from090-0to112-5degrees\":false,\"from112-5to135-0degrees\":false,\"from135-0to157-5degrees\":false,\"from157-5to180-0degrees\":false,\"from180-0to202-5degrees\":false,\"from202-5to225-0degrees\":false,\"from225-0to247-5degrees\":false,\"from247-5to270-0degrees\":false,\"from270-0to292-5degrees\":false,\"from292-5to315-0degrees\":false,\"from315-0to337-5degrees\":false,\"from337-5to360-0degrees\":false},\"description\":{\"oldRegion\":{\"direction\":{\"from000-0to022-5degrees\":false,\"from022-5to045-0degrees\":false,\"from045-0to067-5degrees\":false,\"from067-5to090-0degrees\":false,\"from090-0to112-5degrees\":true,\"from112-5to135-0degrees\":false,\"from135-0to157-5degrees\":false,\"from157-5to180-0degrees\":false,\"from180-0to202-5degrees\":false,\"from202-5to225-0degrees\":false,\"from225-0to247-5degrees\":false,\"from247-5to270-0degrees\":false,\"from270-0to292-5degrees\":false,\"from292-5to315-0degrees\":false,\"from315-0to337-5degrees\":false,\"from337-5to360-0degrees\":false},\"extent\":\"useFor100000meters\",\"area\":{\"circle\":{\"center\":{\"lat\":223434207,\"long\":-714422034,\"elevation\":41663},\"radius\":737,\"units\":\"cm2-5\"}}}}}],\"doNotUse3\":2,\"doNotUse4\":31,\"content\":{\"workZone\":[{\"item\":{\"text\":\"IA5St\"}},{\"item\":{\"text\":\"IA5St\"}},{\"item\":{\"itis\":52884}}]},\"url\":\"I\"},{\"doNotUse1\":16,\"frameType\":\"roadSignage\",\"msgId\":{\"roadSignID\":{\"position\":{\"lat\":604037802,\"long\":-124613998,\"elevation\":46289},\"viewAngle\":{\"from000-0to022-5degrees\":false,\"from022-5to045-0degrees\":false,\"from045-0to067-5degrees\":false,\"from067-5to090-0degrees\":false,\"from090-0to112-5degrees\":false,\"from112-5to135-0degrees\":false,\"from135-0to157-5degrees\":false,\"from157-5to180-0degrees\":false,\"from180-0to202-5degrees\":false,\"from202-5to225-0degrees\":true,\"from225-0to247-5degrees\":false,\"from247-5to270-0degrees\":false,\"from270-0to292-5degrees\":false,\"from292-5to315-0degrees\":false,\"from315-0to337-5degrees\":false,\"from337-5to360-0degrees\":false},\"mutcdCode\":\"guide\",\"crc\":\"4F43\"}},\"startYear\":135,\"startTime\":30119,\"durationTime\":17072,\"priority\":7,\"doNotUse2\":6,\"regions\":[{\"name\":\"IA5S\",\"id\":{\"region\":35731,\"id\":64365},\"anchor\":{\"lat\":251341270,\"long\":-1550588968,\"elevation\":18073},\"laneWidth\":19174,\"directionality\":\"forward\",\"closedPath\":true,\"direction\":{\"from000-0to022-5degrees\":false,\"from022-5to045-0degrees\":false,\"from045-0to067-5degrees\":false,\"from067-5to090-0degrees\":false,\"from090-0to112-5degrees\":false,\"from112-5to135-0degrees\":false,\"from135-0to157-5degrees\":false,\"from157-5to180-0degrees\":false,\"from180-0to202-5degrees\":false,\"from202-5to225-0degrees\":false,\"from225-0to247-5degrees\":false,\"from247-5to270-0degrees\":false,\"from270-0to292-5degrees\":false,\"from292-5to315-0degrees\":true,\"from315-0to337-5degrees\":true,\"from337-5to360-0degrees\":true},\"description\":{\"geometry\":{\"direction\":{\"from000-0to022-5degrees\":false,\"from022-5to045-0degrees\":false,\"from045-0to067-5degrees\":false,\"from067-5to090-0degrees\":false,\"from090-0to112-5degrees\":false,\"from112-5to135-0degrees\":true,\"from135-0to157-5degrees\":false,\"from157-5to180-0degrees\":false,\"from180-0to202-5degrees\":false,\"from202-5to225-0degrees\":false,\"from225-0to247-5degrees\":false,\"from247-5to270-0degrees\":false,\"from270-0to292-5degrees\":false,\"from292-5to315-0degrees\":false,\"from315-0to337-5degrees\":false,\"from337-5to360-0degrees\":false},\"extent\":\"useFor3meters\",\"laneWidth\":19339,\"circle\":{\"center\":{\"lat\":-590142898,\"long\":192563845,\"elevation\":3040},\"radius\":734,\"units\":\"meter\"}}}},{\"name\":\"IA5\",\"id\":{\"region\":13160,\"id\":48242},\"anchor\":{\"lat\":227302831,\"long\":-891580621,\"elevation\":7072},\"laneWidth\":5923,\"directionality\":\"reverse\",\"closedPath\":true,\"direction\":{\"from000-0to022-5degrees\":true,\"from022-5to045-0degrees\":false,\"from045-0to067-5degrees\":false,\"from067-5to090-0degrees\":false,\"from090-0to112-5degrees\":false,\"from112-5to135-0degrees\":false,\"from135-0to157-5degrees\":false,\"from157-5to180-0degrees\":false,\"from180-0to202-5degrees\":false,\"from202-5to225-0degrees\":false,\"from225-0to247-5degrees\":false,\"from247-5to270-0degrees\":false,\"from270-0to292-5degrees\":false,\"from292-5to315-0degrees\":false,\"from315-0to337-5degrees\":false,\"from337-5to360-0degrees\":false},\"description\":{\"oldRegion\":{\"direction\":{\"from000-0to022-5degrees\":false,\"from022-5to045-0degrees\":false,\"from045-0to067-5degrees\":false,\"from067-5to090-0degrees\":false,\"from090-0to112-5degrees\":true,\"from112-5to135-0degrees\":false,\"from135-0to157-5degrees\":false,\"from157-5to180-0degrees\":false,\"from180-0to202-5degrees\":false,\"from202-5to225-0degrees\":false,\"from225-0to247-5degrees\":false,\"from247-5to270-0degrees\":false,\"from270-0to292-5degrees\":false,\"from292-5to315-0degrees\":false,\"from315-0to337-5degrees\":false,\"from337-5to360-0degrees\":false},\"extent\":\"useFor3meters\",\"area\":{\"circle\":{\"center\":{\"lat\":368610426,\"long\":-1703460317,\"elevation\":1004},\"radius\":2194,\"units\":\"meter\"}}}}},{\"name\":\"I\",\"id\":{\"region\":58508,\"id\":15927},\"anchor\":{\"lat\":892488592,\"long\":-431640924,\"elevation\":41561},\"laneWidth\":26527,\"directionality\":\"both\",\"closedPath\":true,\"direction\":{\"from000-0to022-5degrees\":false,\"from022-5to045-0degrees\":false,\"from045-0to067-5degrees\":false,\"from067-5to090-0degrees\":true,\"from090-0to112-5degrees\":false,\"from112-5to135-0degrees\":false,\"from135-0to157-5degrees\":false,\"from157-5to180-0degrees\":false,\"from180-0to202-5degrees\":false,\"from202-5to225-0degrees\":false,\"from225-0to247-5degrees\":false,\"from247-5to270-0degrees\":false,\"from270-0to292-5degrees\":false,\"from292-5to315-0degrees\":false,\"from315-0to337-5degrees\":false,\"from337-5to360-0degrees\":false},\"description\":{\"oldRegion\":{\"direction\":{\"from000-0to022-5degrees\":false,\"from022-5to045-0degrees\":false,\"from045-0to067-5degrees\":false,\"from067-5to090-0degrees\":false,\"from090-0to112-5degrees\":false,\"from112-5to135-0degrees\":false,\"from135-0to157-5degrees\":false,\"from157-5to180-0degrees\":false,\"from180-0to202-5degrees\":false,\"from202-5to225-0degrees\":false,\"from225-0to247-5degrees\":false,\"from247-5to270-0degrees\":false,\"from270-0to292-5degrees\":false,\"from292-5to315-0degrees\":true,\"from315-0to337-5degrees\":false,\"from337-5to360-0degrees\":false},\"extent\":\"useFor50000meters\",\"area\":{\"regionPointSet\":{\"anchor\":{\"lat\":-113602543,\"long\":717746718,\"elevation\":49498},\"scale\":1,\"nodeList\":[{\"xOffset\":27670,\"yOffset\":-14790,\"zOffset\":-21638},{\"xOffset\":3020,\"yOffset\":-9872,\"zOffset\":-109},{\"xOffset\":-24382,\"yOffset\":23709,\"zOffset\":-862},{\"xOffset\":-26476,\"yOffset\":-6439,\"zOffset\":-23411}]}}}}},{\"name\":\"IA5\",\"id\":{\"region\":379,\"id\":22438},\"anchor\":{\"lat\":-281093797,\"long\":556669965,\"elevation\":29497},\"laneWidth\":7880,\"directionality\":\"reverse\",\"closedPath\":true,\"direction\":{\"from000-0to022-5degrees\":false,\"from022-5to045-0degrees\":false,\"from045-0to067-5degrees\":false,\"from067-5to090-0degrees\":false,\"from090-0to112-5degrees\":false,\"from112-5to135-0degrees\":false,\"from135-0to157-5degrees\":false,\"from157-5to180-0degrees\":false,\"from180-0to202-5degrees\":false,\"from202-5to225-0degrees\":false,\"from225-0to247-5degrees\":false,\"from247-5to270-0degrees\":false,\"from270-0to292-5degrees\":false,\"from292-5to315-0degrees\":false,\"from315-0to337-5degrees\":true,\"from337-5to360-0degrees\":false},\"description\":{\"geometry\":{\"direction\":{\"from000-0to022-5degrees\":false,\"from022-5to045-0degrees\":false,\"from045-0to067-5degrees\":false,\"from067-5to090-0degrees\":false,\"from090-0to112-5degrees\":false,\"from112-5to135-0degrees\":false,\"from135-0to157-5degrees\":false,\"from157-5to180-0degrees\":false,\"from180-0to202-5degrees\":false,\"from202-5to225-0degrees\":false,\"from225-0to247-5degrees\":false,\"from247-5to270-0degrees\":false,\"from270-0to292-5degrees\":false,\"from292-5to315-0degrees\":false,\"from315-0to337-5degrees\":true,\"from337-5to360-0degrees\":false},\"extent\":\"useFor500000meters\",\"laneWidth\":2148,\"circle\":{\"center\":{\"lat\":163173661,\"long\":-872411303,\"elevation\":55588},\"radius\":489,\"units\":\"cm2-5\"}}}}],\"doNotUse3\":8,\"doNotUse4\":29,\"content\":{\"advisory\":[{\"item\":{\"itis\":44093}},{\"item\":{\"itis\":65240}},{\"item\":{\"text\":\"IA\"}}]},\"url\":\"I\"},{\"doNotUse1\":31,\"frameType\":\"advisory\",\"msgId\":{\"roadSignID\":{\"position\":{\"lat\":-864002503,\"long\":-654286715,\"elevation\":43804},\"viewAngle\":{\"from000-0to022-5degrees\":false,\"from022-5to045-0degrees\":false,\"from045-0to067-5degrees\":false,\"from067-5to090-0degrees\":false,\"from090-0to112-5degrees\":false,\"from112-5to135-0degrees\":false,\"from135-0to157-5degrees\":true,\"from157-5to180-0degrees\":false,\"from180-0to202-5degrees\":false,\"from202-5to225-0degrees\":false,\"from225-0to247-5degrees\":false,\"from247-5to270-0degrees\":false,\"from270-0to292-5degrees\":false,\"from292-5to315-0degrees\":false,\"from315-0to337-5degrees\":false,\"from337-5to360-0degrees\":false},\"mutcdCode\":\"maintenance\",\"crc\":\"4F43\"}},\"startYear\":3076,\"startTime\":282183,\"durationTime\":14436,\"priority\":6,\"doNotUse2\":11,\"regions\":[{\"name\":\"IA5St\",\"id\":{\"region\":11880,\"id\":33814},\"anchor\":{\"lat\":51295938,\"long\":799818234,\"elevation\":10466},\"laneWidth\":10554,\"directionality\":\"forward\",\"closedPath\":true,\"direction\":{\"from000-0to022-5degrees\":false,\"from022-5to045-0degrees\":false,\"from045-0to067-5degrees\":false,\"from067-5to090-0degrees\":false,\"from090-0to112-5degrees\":false,\"from112-5to135-0degrees\":false,\"from135-0to157-5degrees\":false,\"from157-5to180-0degrees\":false,\"from180-0to202-5degrees\":false,\"from202-5to225-0degrees\":false,\"from225-0to247-5degrees\":false,\"from247-5to270-0degrees\":false,\"from270-0to292-5degrees\":true,\"from292-5to315-0degrees\":false,\"from315-0to337-5degrees\":false,\"from337-5to360-0degrees\":false},\"description\":{\"path\":{\"scale\":10,\"offset\":{\"xy\":{\"nodes\":[{\"delta\":{\"node-XY1\":{\"x\":144,\"y\":-502}},\"attributes\":{\"localNode\":[\"mergePoint\"],\"disabled\":[\"transitStopOnLeft\",\"bikeBoxInFront\",\"doNotBlock\"],\"enabled\":[\"mergingLaneLeft\",\"mergingLaneRight\"],\"data\":[{\"laneCrownPointCenter\":91},{\"laneCrownPointLeft\":-60},{\"laneCrownPointLeft\":-118}],\"dWidth\":-80,\"dElevation\":-211}},{\"delta\":{\"node-XY1\":{\"x\":144,\"y\":-502}},\"attributes\":{\"localNode\":[\"hydrantPresent\",\"roundedCapStyleA\",\"roundedCapStyleB\"],\"disabled\":[\"turnOutPointOnRight\"],\"enabled\":[\"adjacentParkingOnRight\",\"curbOnLeft\"],\"data\":[{\"laneCrownPointCenter\":-3},{\"laneCrownPointCenter\":-23},{\"speedLimits\":[{\"type\":\"vehicleMinSpeed\",\"speed\":5260},{\"type\":\"maxSpeedInConstructionZone\",\"speed\":7676}]}],\"dWidth\":-98,\"dElevation\":-300}},{\"delta\":{\"node-XY5\":{\"x\":6552,\"y\":-7382}},\"attributes\":{\"localNode\":[\"curbPresentAtStepOff\",\"stopLine\",\"reserved\",\"roundedCapStyleB\"],\"disabled\":[\"curbOnLeft\",\"turnOutPointOnRight\",\"whiteLine\",\"curbOnRight\"],\"enabled\":[\"sharedWithTrackedVehicle\",\"audibleSignalingPresent\",\"headInParking\"],\"data\":[{\"laneCrownPointCenter\":-7},{\"laneAngle\":68},{\"laneCrownPointLeft\":-39}],\"dWidth\":287,\"dElevation\":510}},{\"delta\":{\"node-XY1\":{\"x\":-310,\"y\":-500}},\"attributes\":{\"localNode\":[\"roundedCapStyleA\"],\"disabled\":[\"timeRestrictionsOnParking\",\"reserved\",\"parallelParking\",\"midBlockCurbPresent\"],\"enabled\":[\"transitStopOnRight\",\"whiteLine\",\"taperToCenterLine\",\"adjacentParkingOnLeft\",\"timeRestrictionsOnParking\"],\"data\":[{\"laneAngle\":-59},{\"laneCrownPointCenter\":105},{\"laneCrownPointCenter\":25},{\"speedLimits\":[{\"type\":\"vehicleNightMaxSpeed\",\"speed\":2245},{\"type\":\"vehicleMaxSpeed\",\"speed\":1700}]},{\"speedLimits\":[{\"type\":\"maxSpeedInSchoolZone\",\"speed\":7839},{\"type\":\"maxSpeedInSchoolZone\",\"speed\":1190},{\"type\":\"truckMaxSpeed\",\"speed\":3947}]}],\"dWidth\":497,\"dElevation\":-208}},{\"delta\":{\"node-LatLon\":{\"lon\":-1625296958,\"lat\":501091223}},\"attributes\":{\"localNode\":[\"downstreamStartNode\",\"downstreamStopLine\",\"safeIsland\"],\"disabled\":[\"adjacentParkingOnLeft\",\"partialCurbIntrusion\",\"taperToRight\"],\"enabled\":[\"unEvenPavementPresent\",\"adjacentParkingOnRight\"],\"data\":[{\"laneCrownPointCenter\":86}],\"dWidth\":-90,\"dElevation\":131}}]}}}}},{\"name\":\"IA5S\",\"id\":{\"region\":48039,\"id\":14622},\"anchor\":{\"lat\":419808681,\"long\":-1470200813,\"elevation\":37213},\"laneWidth\":25845,\"directionality\":\"unavailable\",\"closedPath\":true,\"direction\":{\"from000-0to022-5degrees\":false,\"from022-5to045-0degrees\":false,\"from045-0to067-5degrees\":false,\"from067-5to090-0degrees\":true,\"from090-0to112-5degrees\":false,\"from112-5to135-0degrees\":false,\"from135-0to157-5degrees\":false,\"from157-5to180-0degrees\":false,\"from180-0to202-5degrees\":false,\"from202-5to225-0degrees\":false,\"from225-0to247-5degrees\":false,\"from247-5to270-0degrees\":false,\"from270-0to292-5degrees\":false,\"from292-5to315-0degrees\":false,\"from315-0to337-5degrees\":false,\"from337-5to360-0degrees\":false},\"description\":{\"geometry\":{\"direction\":{\"from000-0to022-5degrees\":false,\"from022-5to045-0degrees\":false,\"from045-0to067-5degrees\":false,\"from067-5to090-0degrees\":false,\"from090-0to112-5degrees\":false,\"from112-5to135-0degrees\":false,\"from135-0to157-5degrees\":false,\"from157-5to180-0degrees\":false,\"from180-0to202-5degrees\":false,\"from202-5to225-0degrees\":false,\"from225-0to247-5degrees\":false,\"from247-5to270-0degrees\":true,\"from270-0to292-5degrees\":false,\"from292-5to315-0degrees\":false,\"from315-0to337-5degrees\":false,\"from337-5to360-0degrees\":false},\"extent\":\"useFor3meters\",\"laneWidth\":25719,\"circle\":{\"center\":{\"lat\":-666313075,\"long\":639822734,\"elevation\":29597},\"radius\":1325,\"units\":\"foot\"}}}}],\"doNotUse3\":11,\"doNotUse4\":27,\"content\":{\"speedLimit\":[{\"item\":{\"text\":\"I\"}}]},\"url\":\"IA\"},{\"doNotUse1\":18,\"frameType\":\"roadSignage\",\"msgId\":{\"roadSignID\":{\"position\":{\"lat\":889823043,\"long\":-537303585,\"elevation\":29359},\"viewAngle\":{\"from000-0to022-5degrees\":false,\"from022-5to045-0degrees\":false,\"from045-0to067-5degrees\":false,\"from067-5to090-0degrees\":false,\"from090-0to112-5degrees\":false,\"from112-5to135-0degrees\":true,\"from135-0to157-5degrees\":false,\"from157-5to180-0degrees\":false,\"from180-0to202-5degrees\":false,\"from202-5to225-0degrees\":false,\"from225-0to247-5degrees\":false,\"from247-5to270-0degrees\":false,\"from270-0to292-5degrees\":false,\"from292-5to315-0degrees\":false,\"from315-0to337-5degrees\":false,\"from337-5to360-0degrees\":false},\"mutcdCode\":\"maintenance\",\"crc\":\"4F43\"}},\"startYear\":1652,\"startTime\":115878,\"durationTime\":7970,\"priority\":6,\"doNotUse2\":27,\"regions\":[{\"name\":\"I\",\"id\":{\"region\":26015,\"id\":40525},\"anchor\":{\"lat\":112058765,\"long\":1125609019,\"elevation\":54648},\"laneWidth\":31409,\"directionality\":\"both\",\"closedPath\":true,\"direction\":{\"from000-0to022-5degrees\":false,\"from022-5to045-0degrees\":false,\"from045-0to067-5degrees\":false,\"from067-5to090-0degrees\":false,\"from090-0to112-5degrees\":false,\"from112-5to135-0degrees\":false,\"from135-0to157-5degrees\":false,\"from157-5to180-0degrees\":false,\"from180-0to202-5degrees\":false,\"from202-5to225-0degrees\":false,\"from225-0to247-5degrees\":false,\"from247-5to270-0degrees\":false,\"from270-0to292-5degrees\":true,\"from292-5to315-0degrees\":false,\"from315-0to337-5degrees\":false,\"from337-5to360-0degrees\":false},\"description\":{\"oldRegion\":{\"direction\":{\"from000-0to022-5degrees\":false,\"from022-5to045-0degrees\":false,\"from045-0to067-5degrees\":false,\"from067-5to090-0degrees\":false,\"from090-0to112-5degrees\":false,\"from112-5to135-0degrees\":false,\"from135-0to157-5degrees\":false,\"from157-5to180-0degrees\":true,\"from180-0to202-5degrees\":false,\"from202-5to225-0degrees\":false,\"from225-0to247-5degrees\":false,\"from247-5to270-0degrees\":false,\"from270-0to292-5degrees\":false,\"from292-5to315-0degrees\":false,\"from315-0to337-5degrees\":false,\"from337-5to360-0degrees\":false},\"extent\":\"useFor50000meters\",\"area\":{\"shapePointSet\":{\"anchor\":{\"lat\":733403986,\"long\":1001009347,\"elevation\":23252},\"laneWidth\":14952,\"directionality\":\"unavailable\",\"nodeList\":{\"computed\":{\"referenceLaneId\":188,\"offsetXaxis\":{\"large\":-8154},\"offsetYaxis\":{\"large\":-28485},\"rotateXY\":224,\"scaleXaxis\":32,\"scaleYaxis\":1787}}}}}}}],\"doNotUse3\":14,\"doNotUse4\":21,\"content\":{\"exitService\":[{\"item\":{\"text\":\"I\"}}]},\"url\":\"I\"}]},\"dataType\":\"us.dot.its.jpo.ode.plugin.j2735.travelerinformation.TravelerInformation\"}}"; + + @Autowired + DeduplicatorProperties props; + + @Test + public void testTopology() { + + props = new DeduplicatorProperties(); + props.setKafkaTopicOdeTimJson(inputTopic); + props.setKafkaTopicDeduplicatedOdeTimJson(outputTopic); + + TimDeduplicatorTopology TimDeduplicatorTopology = new TimDeduplicatorTopology(props, null); + + Topology topology = TimDeduplicatorTopology.buildTopology(); + objectMapper.registerModule(new JavaTimeModule()); + + try (TopologyTestDriver driver = new TopologyTestDriver(topology)) { + + + TestInputTopic inputTimData = driver.createInputTopic( + inputTopic, + Serdes.Void().serializer(), + Serdes.String().serializer()); + + + TestOutputTopic outputTimData = driver.createOutputTopic( + outputTopic, + Serdes.String().deserializer(), + Serdes.String().deserializer()); + + inputTimData.pipeInput(null, inputTim1); + inputTimData.pipeInput(null, inputTim2); + inputTimData.pipeInput(null, inputTim3); + inputTimData.pipeInput(null, inputTim4); + + List> timDeduplicatedResults = outputTimData.readKeyValuesToList(); + + // validate that only 3 messages make it through + assertEquals(3, timDeduplicatedResults.size()); + inputTim1 = inputTim1.strip(); + + assertEquals(inputTim1.replace(" ", ""), timDeduplicatedResults.get(0).value.replace(" ", "")); + assertEquals(inputTim3.replace(" ", ""), timDeduplicatedResults.get(1).value.replace(" ", "")); + assertEquals(inputTim4.replace(" ", ""), timDeduplicatedResults.get(2).value.replace(" ", "")); + + }catch(Exception e){ + e.printStackTrace(); + } + } +} diff --git a/jpo-deduplicator/src/test/resources/application-testConfig.yaml b/jpo-deduplicator/src/test/resources/application-testConfig.yaml new file mode 100644 index 0000000..4f102d0 --- /dev/null +++ b/jpo-deduplicator/src/test/resources/application-testConfig.yaml @@ -0,0 +1 @@ +spring.kafka.bootstrap-servers: localhost:10093 \ No newline at end of file diff --git a/jpo-deduplicator/src/test/resources/json/map/sample.map-different.json b/jpo-deduplicator/src/test/resources/json/map/sample.map-different.json new file mode 100644 index 0000000..9af4acc --- /dev/null +++ b/jpo-deduplicator/src/test/resources/json/map/sample.map-different.json @@ -0,0 +1,1524 @@ +{ + "metadata": { + "logFileName": "", + "recordType": "mapTx", + "securityResultCode": "success", + "receivedMessageDetails": { + "rxSource": "NA" + }, + "payloadType": "us.dot.its.jpo.ode.model.OdeMapPayload", + "serialId": { + "streamId": "35ecef57-56ce-44ca-beca-16279d7471e1", + "bundleSize": 1, + "bundleId": 0, + "recordId": 0, + "serialNumber": 0 + }, + "odeReceivedAt": "2025-01-31T00:00:00.000Z", + "schemaVersion": 8, + "maxDurationTime": 0, + "recordGeneratedAt": "", + "recordGeneratedBy": "RSU", + "sanitized": false, + "odePacketID": "", + "odeTimStartDateTime": "", + "asn1": "0012820038033000205EA60D4D383C3B2CA7114251C802DC1C580C68000002000195D3B9FDA4ACED70318D6FAE8119027D9ACA8F03C4050535DEF6012C0A0A0586200020096029A000001C000A574B07DF62B39E40D4B5B99604D809F66B34DC0B5014145673C82726B69A414D013D857A7C81141587C000200AC350001008B0211000000800026BDF34287036E50516257A64D1B0FE52B3C04FB3620E259C809E20581C0003009603A200000100004D7A89855A02828B11C9306ED882C9644027D9B11292E5E04F102C120001804B0255000000400036BFAC42D4814145805684DE2C39D4A22B61F9E55D409F66C3F6CABA813C40B0F40001012C0A540000010000DB01D10B4E050516005E1279B0F892AC804FB361F42566009F66C3B449EC013D80B0E4000101100B6200000001B08A50C0805051601FE042040318800000006C2D042C3014145806E80FD100D6200000000B0E0B09D6D80568102028284039C800000002C42E3FA6960805FE4C403DC800000002C3E33EAA160779FF30B0085000000800032C07ABCE5B5ED2DC8D809EC6B88CABE88139CD6EFD53BB02761ADDC4A69E04E70AC32000080561700004045802280000050001960A91E72DAF618E3A804F635C3D55F2409CE6B761A9B2013B0D6F02536F02738561B000040230F2000210042200000000AECF8F5C257FAA7EBF10032200000000AF07CF58857FAF7ED00142857ED47FFA10072200000001AF1150904050A15FB9A000040208800000006BC4AC2F00142857EE080002C0A3400000200019AFB5D1346050A35FFA6177C0A0A2BFE64464B5FD921F600A0A6BF14443981428D7CF6891302851AF5E11142050A35EED218340A0A058EC00020096049A0000004000ED7C1B896902851AFFE90DCE050535FE5E2E3C0A0A6BFB3C26781414D7E5C883402829AF9911096050A35F57A14CC0A142BE86C25D35F2F610940A0A218412000AC7A000100C60E40004581668000002000135FB8226D80A146BFF1C7C401414D7F3C878202829AFB531352050A02C590001C04B030D000000400036C00BC4E681428D801789A302828AFF8D0F76D7F0E877C02829AFC950CA4050502C554001C0440350800000006C0DD44F88142858000814D100E4200000001B06A713CA050536000205480A0A2C197400000200001B079CED3004F135FF1113200A3205874000400960D3A00000100000D8234765D027B1AFFF08A14051402C360002004B06DD000000400006C0653B22013D8D800A4518028A0160C80006025838E8000002000035FDB1D84C09EC6C003BA14814140B0540003012C187400000080011B13F6EDB804F115FA6DFC10AFC94FC6A57EE07DCE2BFA7BED3B5FFCD72E80A1E018C9000082DA50180060282814420202000", + "mapSource": "RSU", + "originIp": "8.8.8.8" + }, + "payload": { + "data": { + "msgIssueRevision": 3, + "layerType": "intersectionData", + "layerID": 0, + "intersections": { + "intersectionGeometry": [ + { + "id": { + "id": 12115 + }, + "revision": 3, + "refPoint": { + "latitude": 39.5531067, + "longitude": -105.0853565, + "elevation": 1684.0 + }, + "laneWidth": 366, + "laneSet": { + "GenericLane": [ + { + "laneID": 6, + "ingressApproach": 3, + "laneAttributes": { + "directionalUse": { + "ingressPath": true, + "egressPath": false + }, + "shareWith": { + "busVehicleTraffic": false, + "trackedVehicleTraffic": false, + "individualMotorizedVehicleTraffic": false, + "taxiVehicleTraffic": false, + "overlappingLaneDescriptionProvided": false, + "cyclistVehicleTraffic": false, + "otherNonMotorizedTrafficTypes": false, + "multipleLanesTreatedAsOneLane": false, + "pedestrianTraffic": false, + "pedestriansTraffic": false + }, + "laneType": { + "vehicle": { + "isVehicleRevocableLane": false, + "isVehicleFlyOverLane": false, + "permissionOnRequest": false, + "hasIRbeaconCoverage": false, + "restrictedToBusUse": false, + "restrictedToTaxiUse": false, + "restrictedFromPublicUse": false, + "hovLaneUseOnly": false + } + } + }, + "maneuvers": { + "maneuverStraightAllowed": false, + "maneuverNoStoppingAllowed": false, + "goWithHalt": false, + "maneuverLeftAllowed": true, + "maneuverUTurnAllowed": false, + "maneuverLeftTurnOnRedAllowed": false, + "reserved1": false, + "maneuverRightAllowed": false, + "maneuverLaneChangeAllowed": false, + "yieldAllwaysRequired": false, + "maneuverRightTurnOnRedAllowed": false, + "caution": false + }, + "nodeList": { + "nodes": [ + { + "delta": { + "nodeXY6": { + "x": -2834, + "y": -151 + } + } + }, + { + "delta": { + "nodeXY6": { + "x": -6293, + "y": 396 + } + } + }, + { + "delta": { + "nodeXY6": { + "x": -4178, + "y": 281 + } + }, + "attributes": { + "dElevation": -10 + } + }, + { + "delta": { + "nodeXY6": { + "x": -6841, + "y": 482 + } + }, + "attributes": { + "dElevation": 10 + } + }, + { + "delta": { + "nodeXY6": { + "x": -2115, + "y": 75 + } + }, + "attributes": { + "dElevation": 10 + } + } + ] + }, + "connectsTo": { + "connectsTo": [ + { + "connectingLane": { + "lane": 12, + "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 + } + ] + } + }, + { + "laneID": 5, + "ingressApproach": 3, + "laneAttributes": { + "directionalUse": { + "ingressPath": true, + "egressPath": false + }, + "shareWith": { + "busVehicleTraffic": false, + "trackedVehicleTraffic": false, + "individualMotorizedVehicleTraffic": false, + "taxiVehicleTraffic": false, + "overlappingLaneDescriptionProvided": false, + "cyclistVehicleTraffic": false, + "otherNonMotorizedTrafficTypes": false, + "multipleLanesTreatedAsOneLane": false, + "pedestrianTraffic": false, + "pedestriansTraffic": false + }, + "laneType": { + "vehicle": { + "isVehicleRevocableLane": false, + "isVehicleFlyOverLane": false, + "permissionOnRequest": false, + "hasIRbeaconCoverage": false, + "restrictedToBusUse": false, + "restrictedToTaxiUse": false, + "restrictedFromPublicUse": false, + "hovLaneUseOnly": false + } + } + }, + "maneuvers": { + "maneuverStraightAllowed": true, + "maneuverNoStoppingAllowed": false, + "goWithHalt": false, + "maneuverLeftAllowed": true, + "maneuverUTurnAllowed": false, + "maneuverLeftTurnOnRedAllowed": false, + "reserved1": false, + "maneuverRightAllowed": true, + "maneuverLaneChangeAllowed": false, + "yieldAllwaysRequired": false, + "maneuverRightTurnOnRedAllowed": false, + "caution": false + }, + "nodeList": { + "nodes": [ + { + "delta": { + "nodeXY6": { + "x": -2896, + "y": -522 + } + } + }, + { + "delta": { + "nodeXY6": { + "x": -6340, + "y": 425 + } + } + }, + { + "delta": { + "nodeXY6": { + "x": -4507, + "y": 310 + } + }, + "attributes": { + "dElevation": -10 + } + }, + { + "delta": { + "nodeXY6": { + "x": -6501, + "y": 362 + } + }, + "attributes": { + "dElevation": 10 + } + }, + { + "delta": { + "nodeXY6": { + "x": -6340, + "y": 626 + } + } + }, + { + "delta": { + "nodeXY6": { + "x": -4812, + "y": 666 + } + }, + "attributes": { + "dElevation": -20 + } + }, + { + "delta": { + "nodeXY6": { + "x": -1412, + "y": 276 + } + } + } + ] + }, + "connectsTo": { + "connectsTo": [ + { + "connectingLane": { + "lane": 15, + "maneuver": { + "maneuverStraightAllowed": true, + "maneuverNoStoppingAllowed": false, + "goWithHalt": false, + "maneuverLeftAllowed": false, + "maneuverUTurnAllowed": false, + "maneuverLeftTurnOnRedAllowed": false, + "reserved1": false, + "maneuverRightAllowed": false, + "maneuverLaneChangeAllowed": false, + "yieldAllwaysRequired": false, + "maneuverRightTurnOnRedAllowed": false, + "caution": false + } + }, + "signalGroup": 4, + "connectionID": 1 + }, + { + "connectingLane": { + "lane": 13, + "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": 2 + } + ] + } + }, + { + "laneID": 8, + "ingressApproach": 4, + "laneAttributes": { + "directionalUse": { + "ingressPath": true, + "egressPath": false + }, + "shareWith": { + "busVehicleTraffic": false, + "trackedVehicleTraffic": false, + "individualMotorizedVehicleTraffic": false, + "taxiVehicleTraffic": false, + "overlappingLaneDescriptionProvided": false, + "cyclistVehicleTraffic": false, + "otherNonMotorizedTrafficTypes": false, + "multipleLanesTreatedAsOneLane": false, + "pedestrianTraffic": false, + "pedestriansTraffic": false + }, + "laneType": { + "vehicle": { + "isVehicleRevocableLane": false, + "isVehicleFlyOverLane": false, + "permissionOnRequest": false, + "hasIRbeaconCoverage": false, + "restrictedToBusUse": false, + "restrictedToTaxiUse": false, + "restrictedFromPublicUse": false, + "hovLaneUseOnly": false + } + } + }, + "maneuvers": { + "maneuverStraightAllowed": true, + "maneuverNoStoppingAllowed": false, + "goWithHalt": false, + "maneuverLeftAllowed": false, + "maneuverUTurnAllowed": false, + "maneuverLeftTurnOnRedAllowed": false, + "reserved1": false, + "maneuverRightAllowed": false, + "maneuverLaneChangeAllowed": false, + "yieldAllwaysRequired": false, + "maneuverRightTurnOnRedAllowed": false, + "caution": false + }, + "nodeList": { + "nodes": [ + { + "delta": { + "nodeXY6": { + "x": -1050, + "y": 1294 + } + }, + "attributes": { + "dWidth": 370, + "dElevation": 10 + } + }, + { + "delta": { + "nodeXY6": { + "x": 2398, + "y": 6452 + } + } + }, + { + "delta": { + "nodeXY6": { + "x": 2034, + "y": 5534 + } + }, + "attributes": { + "dElevation": -10 + } + }, + { + "delta": { + "nodeXY6": { + "x": 2104, + "y": 5746 + } + }, + "attributes": { + "dElevation": -30 + } + } + ] + }, + "connectsTo": { + "connectsTo": [ + { + "connectingLane": { + "lane": 3, + "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 + } + ] + } + }, + { + "laneID": 7, + "ingressApproach": 4, + "laneAttributes": { + "directionalUse": { + "ingressPath": true, + "egressPath": false + }, + "shareWith": { + "busVehicleTraffic": false, + "trackedVehicleTraffic": false, + "individualMotorizedVehicleTraffic": false, + "taxiVehicleTraffic": false, + "overlappingLaneDescriptionProvided": false, + "cyclistVehicleTraffic": false, + "otherNonMotorizedTrafficTypes": false, + "multipleLanesTreatedAsOneLane": false, + "pedestrianTraffic": false, + "pedestriansTraffic": false + }, + "laneType": { + "vehicle": { + "isVehicleRevocableLane": false, + "isVehicleFlyOverLane": false, + "permissionOnRequest": false, + "hasIRbeaconCoverage": false, + "restrictedToBusUse": false, + "restrictedToTaxiUse": false, + "restrictedFromPublicUse": false, + "hovLaneUseOnly": false + } + } + }, + "maneuvers": { + "maneuverStraightAllowed": true, + "maneuverNoStoppingAllowed": false, + "goWithHalt": false, + "maneuverLeftAllowed": false, + "maneuverUTurnAllowed": false, + "maneuverLeftTurnOnRedAllowed": false, + "reserved1": false, + "maneuverRightAllowed": false, + "maneuverLaneChangeAllowed": false, + "yieldAllwaysRequired": false, + "maneuverRightTurnOnRedAllowed": false, + "caution": false + }, + "nodeList": { + "nodes": [ + { + "delta": { + "nodeXY6": { + "x": -1399, + "y": 1370 + } + }, + "attributes": { + "dElevation": 10 + } + }, + { + "delta": { + "nodeXY6": { + "x": 2276, + "y": 6199 + } + } + }, + { + "delta": { + "nodeXY6": { + "x": 2092, + "y": 5700 + } + }, + "attributes": { + "dElevation": -10 + } + }, + { + "delta": { + "nodeXY6": { + "x": 2196, + "y": 5935 + } + }, + "attributes": { + "dElevation": -30 + } + } + ] + }, + "connectsTo": { + "connectsTo": [ + { + "connectingLane": { + "lane": 4, + "maneuver": { + "maneuverStraightAllowed": true, + "maneuverNoStoppingAllowed": false, + "goWithHalt": false, + "maneuverLeftAllowed": false, + "maneuverUTurnAllowed": false, + "maneuverLeftTurnOnRedAllowed": false, + "reserved1": false, + "maneuverRightAllowed": false, + "maneuverLaneChangeAllowed": false, + "yieldAllwaysRequired": false, + "maneuverRightTurnOnRedAllowed": false, + "caution": false + } + }, + "signalGroup": 6, + "connectionID": 1 + } + ] + } + }, + { + "laneID": 9, + "ingressApproach": 5, + "laneAttributes": { + "directionalUse": { + "ingressPath": true, + "egressPath": false + }, + "shareWith": { + "busVehicleTraffic": false, + "trackedVehicleTraffic": false, + "individualMotorizedVehicleTraffic": false, + "taxiVehicleTraffic": false, + "overlappingLaneDescriptionProvided": false, + "cyclistVehicleTraffic": false, + "otherNonMotorizedTrafficTypes": false, + "multipleLanesTreatedAsOneLane": false, + "pedestrianTraffic": false, + "pedestriansTraffic": false + }, + "laneType": { + "vehicle": { + "isVehicleRevocableLane": false, + "isVehicleFlyOverLane": false, + "permissionOnRequest": false, + "hasIRbeaconCoverage": false, + "restrictedToBusUse": false, + "restrictedToTaxiUse": false, + "restrictedFromPublicUse": false, + "hovLaneUseOnly": false + } + } + }, + "maneuvers": { + "maneuverStraightAllowed": false, + "maneuverNoStoppingAllowed": false, + "goWithHalt": false, + "maneuverLeftAllowed": true, + "maneuverUTurnAllowed": false, + "maneuverLeftTurnOnRedAllowed": false, + "reserved1": false, + "maneuverRightAllowed": false, + "maneuverLaneChangeAllowed": false, + "yieldAllwaysRequired": false, + "maneuverRightTurnOnRedAllowed": false, + "caution": false + }, + "nodeList": { + "nodes": [ + { + "delta": { + "nodeXY6": { + "x": -168, + "y": 1449 + } + }, + "attributes": { + "dElevation": 10 + } + }, + { + "delta": { + "nodeXY6": { + "x": 86, + "y": 1246 + } + } + }, + { + "delta": { + "nodeXY6": { + "x": 1850, + "y": 5189 + } + } + }, + { + "delta": { + "nodeXY6": { + "x": 2023, + "y": 5493 + } + }, + "attributes": { + "dElevation": -10 + } + }, + { + "delta": { + "nodeXY6": { + "x": 2029, + "y": 5493 + } + }, + "attributes": { + "dElevation": -30 + } + } + ] + }, + "connectsTo": { + "connectsTo": [ + { + "connectingLane": { + "lane": 15, + "maneuver": { + "maneuverStraightAllowed": false, + "maneuverNoStoppingAllowed": false, + "goWithHalt": false, + "maneuverLeftAllowed": true, + "maneuverUTurnAllowed": false, + "maneuverLeftTurnOnRedAllowed": false, + "reserved1": false, + "maneuverRightAllowed": false, + "maneuverLaneChangeAllowed": false, + "yieldAllwaysRequired": false, + "maneuverRightTurnOnRedAllowed": false, + "caution": false + } + }, + "signalGroup": 1, + "connectionID": 1 + } + ] + } + }, + { + "laneID": 10, + "ingressApproach": 5, + "laneAttributes": { + "directionalUse": { + "ingressPath": true, + "egressPath": false + }, + "shareWith": { + "busVehicleTraffic": false, + "trackedVehicleTraffic": false, + "individualMotorizedVehicleTraffic": false, + "taxiVehicleTraffic": false, + "overlappingLaneDescriptionProvided": false, + "cyclistVehicleTraffic": false, + "otherNonMotorizedTrafficTypes": false, + "multipleLanesTreatedAsOneLane": false, + "pedestrianTraffic": false, + "pedestriansTraffic": false + }, + "laneType": { + "vehicle": { + "isVehicleRevocableLane": false, + "isVehicleFlyOverLane": false, + "permissionOnRequest": false, + "hasIRbeaconCoverage": false, + "restrictedToBusUse": false, + "restrictedToTaxiUse": false, + "restrictedFromPublicUse": false, + "hovLaneUseOnly": false + } + } + }, + "maneuvers": { + "maneuverStraightAllowed": false, + "maneuverNoStoppingAllowed": false, + "goWithHalt": false, + "maneuverLeftAllowed": true, + "maneuverUTurnAllowed": false, + "maneuverLeftTurnOnRedAllowed": false, + "reserved1": false, + "maneuverRightAllowed": false, + "maneuverLaneChangeAllowed": false, + "yieldAllwaysRequired": false, + "maneuverRightTurnOnRedAllowed": false, + "caution": false + }, + "nodeList": { + "nodes": [ + { + "delta": { + "nodeXY6": { + "x": 232, + "y": 1447 + } + }, + "attributes": { + "dElevation": 10 + } + }, + { + "delta": { + "nodeXY6": { + "x": 23, + "y": 1182 + } + } + }, + { + "delta": { + "nodeXY6": { + "x": 1988, + "y": 5476 + } + }, + "attributes": { + "dElevation": -10 + } + }, + { + "delta": { + "nodeXY6": { + "x": 2000, + "y": 5528 + } + }, + "attributes": { + "dElevation": -10 + } + }, + { + "delta": { + "nodeXY6": { + "x": 1896, + "y": 5080 + } + }, + "attributes": { + "dElevation": -20 + } + } + ] + }, + "connectsTo": { + "connectsTo": [ + { + "connectingLane": { + "lane": 14, + "maneuver": { + "maneuverStraightAllowed": false, + "maneuverNoStoppingAllowed": false, + "goWithHalt": false, + "maneuverLeftAllowed": true, + "maneuverUTurnAllowed": false, + "maneuverLeftTurnOnRedAllowed": false, + "reserved1": false, + "maneuverRightAllowed": false, + "maneuverLaneChangeAllowed": false, + "yieldAllwaysRequired": false, + "maneuverRightTurnOnRedAllowed": false, + "caution": false + } + }, + "signalGroup": 1, + "connectionID": 1 + } + ] + } + }, + { + "laneID": 11, + "egressApproach": 6, + "laneAttributes": { + "directionalUse": { + "ingressPath": false, + "egressPath": true + }, + "shareWith": { + "busVehicleTraffic": false, + "trackedVehicleTraffic": false, + "individualMotorizedVehicleTraffic": false, + "taxiVehicleTraffic": false, + "overlappingLaneDescriptionProvided": false, + "cyclistVehicleTraffic": false, + "otherNonMotorizedTrafficTypes": false, + "multipleLanesTreatedAsOneLane": false, + "pedestrianTraffic": false, + "pedestriansTraffic": false + }, + "laneType": { + "vehicle": { + "isVehicleRevocableLane": false, + "isVehicleFlyOverLane": false, + "permissionOnRequest": false, + "hasIRbeaconCoverage": false, + "restrictedToBusUse": false, + "restrictedToTaxiUse": false, + "restrictedFromPublicUse": false, + "hovLaneUseOnly": false + } + } + }, + "nodeList": { + "nodes": [ + { + "delta": { + "nodeXY6": { + "x": 1106, + "y": 1540 + } + }, + "attributes": { + "dElevation": 10 + } + }, + { + "delta": { + "nodeXY6": { + "x": 127, + "y": 264 + } + } + } + ] + } + }, + { + "laneID": 12, + "egressApproach": 6, + "laneAttributes": { + "directionalUse": { + "ingressPath": false, + "egressPath": true + }, + "shareWith": { + "busVehicleTraffic": false, + "trackedVehicleTraffic": false, + "individualMotorizedVehicleTraffic": false, + "taxiVehicleTraffic": false, + "overlappingLaneDescriptionProvided": false, + "cyclistVehicleTraffic": false, + "otherNonMotorizedTrafficTypes": false, + "multipleLanesTreatedAsOneLane": false, + "pedestrianTraffic": false, + "pedestriansTraffic": false + }, + "laneType": { + "vehicle": { + "isVehicleRevocableLane": false, + "isVehicleFlyOverLane": false, + "permissionOnRequest": false, + "hasIRbeaconCoverage": false, + "restrictedToBusUse": false, + "restrictedToTaxiUse": false, + "restrictedFromPublicUse": false, + "hovLaneUseOnly": false + } + } + }, + "nodeList": { + "nodes": [ + { + "delta": { + "nodeXY6": { + "x": 1440, + "y": 1414 + } + }, + "attributes": { + "dElevation": 10 + } + }, + { + "delta": { + "nodeXY6": { + "x": 110, + "y": 253 + } + } + } + ] + } + }, + { + "laneID": 13, + "egressApproach": 6, + "laneAttributes": { + "directionalUse": { + "ingressPath": false, + "egressPath": true + }, + "shareWith": { + "busVehicleTraffic": false, + "trackedVehicleTraffic": false, + "individualMotorizedVehicleTraffic": false, + "taxiVehicleTraffic": false, + "overlappingLaneDescriptionProvided": false, + "cyclistVehicleTraffic": false, + "otherNonMotorizedTrafficTypes": false, + "multipleLanesTreatedAsOneLane": false, + "pedestrianTraffic": false, + "pedestriansTraffic": false + }, + "laneType": { + "vehicle": { + "isVehicleRevocableLane": false, + "isVehicleFlyOverLane": false, + "permissionOnRequest": false, + "hasIRbeaconCoverage": false, + "restrictedToBusUse": false, + "restrictedToTaxiUse": false, + "restrictedFromPublicUse": false, + "hovLaneUseOnly": false + } + } + }, + "nodeList": { + "nodes": [ + { + "delta": { + "nodeXY6": { + "x": 1797, + "y": 1259 + } + } + }, + { + "delta": { + "nodeXY6": { + "x": 86, + "y": 258 + } + }, + "attributes": { + "dElevation": 10 + } + } + ] + } + }, + { + "laneID": 14, + "egressApproach": 7, + "laneAttributes": { + "directionalUse": { + "ingressPath": false, + "egressPath": true + }, + "shareWith": { + "busVehicleTraffic": false, + "trackedVehicleTraffic": false, + "individualMotorizedVehicleTraffic": false, + "taxiVehicleTraffic": false, + "overlappingLaneDescriptionProvided": false, + "cyclistVehicleTraffic": false, + "otherNonMotorizedTrafficTypes": false, + "multipleLanesTreatedAsOneLane": false, + "pedestrianTraffic": false, + "pedestriansTraffic": false + }, + "laneType": { + "vehicle": { + "isVehicleRevocableLane": false, + "isVehicleFlyOverLane": false, + "permissionOnRequest": false, + "hasIRbeaconCoverage": false, + "restrictedToBusUse": false, + "restrictedToTaxiUse": false, + "restrictedFromPublicUse": false, + "hovLaneUseOnly": false + } + } + }, + "nodeList": { + "nodes": [ + { + "delta": { + "nodeXY6": { + "x": 2140, + "y": -179 + } + } + }, + { + "delta": { + "nodeXY6": { + "x": 513, + "y": -109 + } + } + } + ] + } + }, + { + "laneID": 15, + "egressApproach": 7, + "laneAttributes": { + "directionalUse": { + "ingressPath": false, + "egressPath": true + }, + "shareWith": { + "busVehicleTraffic": false, + "trackedVehicleTraffic": false, + "individualMotorizedVehicleTraffic": false, + "taxiVehicleTraffic": false, + "overlappingLaneDescriptionProvided": false, + "cyclistVehicleTraffic": false, + "otherNonMotorizedTrafficTypes": false, + "multipleLanesTreatedAsOneLane": false, + "pedestrianTraffic": false, + "pedestriansTraffic": false + }, + "laneType": { + "vehicle": { + "isVehicleRevocableLane": false, + "isVehicleFlyOverLane": false, + "permissionOnRequest": false, + "hasIRbeaconCoverage": false, + "restrictedToBusUse": false, + "restrictedToTaxiUse": false, + "restrictedFromPublicUse": false, + "hovLaneUseOnly": false + } + } + }, + "nodeList": { + "nodes": [ + { + "delta": { + "nodeXY6": { + "x": 1990, + "y": -684 + } + } + }, + { + "delta": { + "nodeXY6": { + "x": 478, + "y": -52 + } + } + } + ] + } + }, + { + "laneID": 2, + "ingressApproach": 1, + "laneAttributes": { + "directionalUse": { + "ingressPath": true, + "egressPath": false + }, + "shareWith": { + "busVehicleTraffic": false, + "trackedVehicleTraffic": false, + "individualMotorizedVehicleTraffic": false, + "taxiVehicleTraffic": false, + "overlappingLaneDescriptionProvided": false, + "cyclistVehicleTraffic": false, + "otherNonMotorizedTrafficTypes": false, + "multipleLanesTreatedAsOneLane": false, + "pedestrianTraffic": false, + "pedestriansTraffic": false + }, + "laneType": { + "vehicle": { + "isVehicleRevocableLane": false, + "isVehicleFlyOverLane": false, + "permissionOnRequest": false, + "hasIRbeaconCoverage": false, + "restrictedToBusUse": false, + "restrictedToTaxiUse": false, + "restrictedFromPublicUse": false, + "hovLaneUseOnly": false + } + } + }, + "maneuvers": { + "maneuverStraightAllowed": true, + "maneuverNoStoppingAllowed": false, + "goWithHalt": false, + "maneuverLeftAllowed": false, + "maneuverUTurnAllowed": false, + "maneuverLeftTurnOnRedAllowed": false, + "reserved1": false, + "maneuverRightAllowed": false, + "maneuverLaneChangeAllowed": false, + "yieldAllwaysRequired": false, + "maneuverRightTurnOnRedAllowed": false, + "caution": false + }, + "nodeList": { + "nodes": [ + { + "delta": { + "nodeXY6": { + "x": 245, + "y": -1589 + } + } + }, + { + "delta": { + "nodeXY6": { + "x": -1205, + "y": -3530 + } + }, + "attributes": { + "dElevation": -20 + } + }, + { + "delta": { + "nodeXY6": { + "x": -3815, + "y": -10287 + } + }, + "attributes": { + "dElevation": -50 + } + }, + { + "delta": { + "nodeXY6": { + "x": -4355, + "y": -11333 + } + }, + "attributes": { + "dElevation": -40 + } + }, + { + "delta": { + "nodeXY6": { + "x": -4382, + "y": -11441 + } + }, + "attributes": { + "dElevation": -50 + } + } + ] + }, + "connectsTo": { + "connectsTo": [ + { + "connectingLane": { + "lane": 12, + "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 + }, + { + "connectingLane": { + "lane": 11, + "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": 2 + } + ] + } + }, + { + "laneID": 1, + "ingressApproach": 1, + "laneAttributes": { + "directionalUse": { + "ingressPath": true, + "egressPath": false + }, + "shareWith": { + "busVehicleTraffic": false, + "trackedVehicleTraffic": false, + "individualMotorizedVehicleTraffic": false, + "taxiVehicleTraffic": false, + "overlappingLaneDescriptionProvided": false, + "cyclistVehicleTraffic": false, + "otherNonMotorizedTrafficTypes": false, + "multipleLanesTreatedAsOneLane": false, + "pedestrianTraffic": false, + "pedestriansTraffic": false + }, + "laneType": { + "vehicle": { + "isVehicleRevocableLane": false, + "isVehicleFlyOverLane": false, + "permissionOnRequest": false, + "hasIRbeaconCoverage": false, + "restrictedToBusUse": false, + "restrictedToTaxiUse": false, + "restrictedFromPublicUse": false, + "hovLaneUseOnly": false + } + } + }, + "maneuvers": { + "maneuverStraightAllowed": true, + "maneuverNoStoppingAllowed": false, + "goWithHalt": false, + "maneuverLeftAllowed": false, + "maneuverUTurnAllowed": false, + "maneuverLeftTurnOnRedAllowed": false, + "reserved1": false, + "maneuverRightAllowed": true, + "maneuverLaneChangeAllowed": false, + "yieldAllwaysRequired": false, + "maneuverRightTurnOnRedAllowed": false, + "caution": false + }, + "nodeList": { + "nodes": [ + { + "delta": { + "nodeXY6": { + "x": 676, + "y": -1589 + } + } + }, + { + "delta": { + "nodeXY6": { + "x": -1268, + "y": -3628 + } + }, + "attributes": { + "dElevation": -20 + } + }, + { + "delta": { + "nodeXY6": { + "x": -3851, + "y": -10295 + } + }, + "attributes": { + "dElevation": -50 + } + }, + { + "delta": { + "nodeXY6": { + "x": -4413, + "y": -11420 + } + }, + "attributes": { + "dElevation": -40 + } + }, + { + "delta": { + "nodeXY6": { + "x": -4350, + "y": -11409 + } + }, + "attributes": { + "dElevation": -50 + } + } + ] + }, + "connectsTo": { + "connectsTo": [ + { + "connectingLane": { + "lane": 13, + "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 + }, + { + "connectingLane": { + "lane": 15, + "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": 2 + } + ] + } + }, + { + "laneID": 4, + "egressApproach": 2, + "laneAttributes": { + "directionalUse": { + "ingressPath": false, + "egressPath": true + }, + "shareWith": { + "busVehicleTraffic": false, + "trackedVehicleTraffic": false, + "individualMotorizedVehicleTraffic": false, + "taxiVehicleTraffic": false, + "overlappingLaneDescriptionProvided": false, + "cyclistVehicleTraffic": false, + "otherNonMotorizedTrafficTypes": false, + "multipleLanesTreatedAsOneLane": false, + "pedestrianTraffic": false, + "pedestriansTraffic": false + }, + "laneType": { + "vehicle": { + "isVehicleRevocableLane": false, + "isVehicleFlyOverLane": false, + "permissionOnRequest": false, + "hasIRbeaconCoverage": false, + "restrictedToBusUse": false, + "restrictedToTaxiUse": false, + "restrictedFromPublicUse": false, + "hovLaneUseOnly": false + } + } + }, + "nodeList": { + "nodes": [ + { + "delta": { + "nodeXY6": { + "x": -2436, + "y": -1311 + } + } + }, + { + "delta": { + "nodeXY6": { + "x": -86, + "y": -321 + } + } + } + ] + } + }, + { + "laneID": 3, + "egressApproach": 2, + "laneAttributes": { + "directionalUse": { + "ingressPath": false, + "egressPath": true + }, + "shareWith": { + "busVehicleTraffic": false, + "trackedVehicleTraffic": false, + "individualMotorizedVehicleTraffic": false, + "taxiVehicleTraffic": false, + "overlappingLaneDescriptionProvided": false, + "cyclistVehicleTraffic": false, + "otherNonMotorizedTrafficTypes": false, + "multipleLanesTreatedAsOneLane": false, + "pedestrianTraffic": false, + "pedestriansTraffic": false + }, + "laneType": { + "vehicle": { + "isVehicleRevocableLane": false, + "isVehicleFlyOverLane": false, + "permissionOnRequest": false, + "hasIRbeaconCoverage": false, + "restrictedToBusUse": false, + "restrictedToTaxiUse": false, + "restrictedFromPublicUse": false, + "hovLaneUseOnly": false + } + } + }, + "nodeList": { + "nodes": [ + { + "delta": { + "nodeXY6": { + "x": -1986, + "y": -1340 + } + } + }, + { + "delta": { + "nodeXY6": { + "x": -81, + "y": -304 + } + } + } + ] + } + } + ] + } + } + ] + } + }, + "dataType": "us.dot.its.jpo.ode.plugin.j2735.J2735MAP" + } +} \ No newline at end of file diff --git a/jpo-deduplicator/src/test/resources/json/map/sample.map-reference-1-hour-later.json b/jpo-deduplicator/src/test/resources/json/map/sample.map-reference-1-hour-later.json new file mode 100644 index 0000000..e7df02d --- /dev/null +++ b/jpo-deduplicator/src/test/resources/json/map/sample.map-reference-1-hour-later.json @@ -0,0 +1,2814 @@ +{ + "metadata": { + "logFileName": "", + "recordType": "mapTx", + "securityResultCode": "success", + "receivedMessageDetails": { + "rxSource": "NA" + }, + "payloadType": "us.dot.its.jpo.ode.model.OdeMapPayload", + "serialId": { + "streamId": "d963d421-fba0-4b21-b991-229e8d3bf9c1", + "bundleSize": 1, + "bundleId": 0, + "recordId": 0, + "serialNumber": 0 + }, + "odeReceivedAt": "2025-01-31T01:01:00.000Z", + "schemaVersion": 8, + "maxDurationTime": 0, + "recordGeneratedAt": "", + "recordGeneratedBy": "RSU", + "sanitized": false, + "odePacketID": "", + "odeTimStartDateTime": "", + "asn1": "001283C138003000205E9C014D3EAB092CA624B5518202DC3658042800000400023622C60CA009F66D48ABFAF81388D8AD18070027D9B2FFCFE9804F13667B1FFD009EC2C76E3FFC82C4E0001004B00C5000000800066C4574101813ECD8B757FAE027D9B30E6FF5604EC363561FE7809EC6CD69BFEC813C4D8A617FC9027D9B2147008604FB163666000016250000802580228000001000096229E1309B51A6FE4204DD361CF1FE5009F6018E1000096020A00000080004D88A57F84027D9B3827002804EC36087600A009F62C289407282C310001C0440188800000006C46DBE02813EC5816D800710052200000001B11B6FAD404FB16054A0000401C8800000006C47B3D24813EC5816D801B100C4200000000AF890F12C580007E87100D4200000008AF4C0F12C580077E7A2C0004000160002001CB028D000000800052C160BC40B5FFFD8A9409D86BFEBB5B40141457FEF53B76C008B467014145800080002BFFCBFFC82C6A0001804B024D000000800036C2213C3B013ECD80096D64027D9AFFD8CDFC04F635FF7983BC09F66C0082AA2014280B1B80006012C0B3400000100004B02BCF0F6D7FE065D602788B0138EB900B1240001012C083400000080009B0C2AF0B804FB15FE6DE171AFFF6C63E04EC15FE1DE670060E40002581EA8000004000135DA6DF0180A0A6ADC2C00D0143CD51897FDA028C8ABB25001A0B0680008012C105400000200009AEDBEFAE005053540EE003C0A326A9CF3FED8143C5667780010582C0004009608AA00000080004D76DE7EE402829ABA88FFDC050F354525FFF80A322BCF23FA602C690000C04B0395000000200016BB4FBD4E01414D3215800802940AB108FFF2030D2000110126200000001AEE5103BE050A15F6F1FFC8404D8800000006BB97C18E0142857DFA800010146200000001AEE89099A050A15F8720000B05DD000000800046BE3743B781428D80E1B00002879B00514B4404F63600827D8C09E22C000400015FFE6007016190000402582CE8000004000135ECEE1DE80A146C02E54758143CD8059AD3E027B1B00613DD004F102C360000804B055D000000200046BCC7C3C781428D80108C6E02829B002B2ECE050A16019A4B29B00AB5C3604F136004E410409EC018A10000960C3A00000080004D7DE9878602851B003923CC05053601623B440A0A6BFB8C3A5014140B0640005012C197400000100005AFE570EF2050A36003A47C80A0A6BFD2C45F014140B054000501101A8200000001B05A90EDC050535FFE605800A0A101B8200000001B08A30EC0050535FFE605300A0A101C8200000005B0C6F0EA4050515FFCA0568B0001000E", + "mapSource": "RSU", + "originIp": "8.8.8.8" + }, + "payload": { + "data": { + "msgIssueRevision": 0, + "layerType": "intersectionData", + "layerID": 0, + "intersections": { + "intersectionGeometry": [ + { + "id": { + "id": 12110 + }, + "revision": 0, + "refPoint": { + "latitude": 39.5952649, + "longitude": -105.0914122, + "elevation": 1677.0 + }, + "laneWidth": 366, + "laneSet": { + "GenericLane": [ + { + "laneID": 2, + "ingressApproach": 1, + "laneAttributes": { + "directionalUse": { + "ingressPath": true, + "egressPath": false + }, + "shareWith": { + "busVehicleTraffic": false, + "trackedVehicleTraffic": false, + "individualMotorizedVehicleTraffic": false, + "taxiVehicleTraffic": false, + "overlappingLaneDescriptionProvided": false, + "cyclistVehicleTraffic": false, + "otherNonMotorizedTrafficTypes": false, + "multipleLanesTreatedAsOneLane": false, + "pedestrianTraffic": false, + "pedestriansTraffic": false + }, + "laneType": { + "vehicle": { + "isVehicleRevocableLane": false, + "isVehicleFlyOverLane": false, + "permissionOnRequest": false, + "hasIRbeaconCoverage": false, + "restrictedToBusUse": false, + "restrictedToTaxiUse": false, + "restrictedFromPublicUse": false, + "hovLaneUseOnly": false + } + } + }, + "maneuvers": { + "maneuverStraightAllowed": true, + "maneuverNoStoppingAllowed": false, + "goWithHalt": false, + "maneuverLeftAllowed": false, + "maneuverUTurnAllowed": false, + "maneuverLeftTurnOnRedAllowed": false, + "reserved1": false, + "maneuverRightAllowed": false, + "maneuverLaneChangeAllowed": false, + "yieldAllwaysRequired": false, + "maneuverRightTurnOnRedAllowed": false, + "caution": false + }, + "nodeList": { + "nodes": [ + { + "delta": { + "nodeXY6": { + "x": 2225, + "y": 808 + } + }, + "attributes": { + "dElevation": -10 + } + }, + { + "delta": { + "nodeXY6": { + "x": 10517, + "y": -161 + } + }, + "attributes": { + "dElevation": -60 + } + }, + { + "delta": { + "nodeXY6": { + "x": 2769, + "y": 112 + } + }, + "attributes": { + "dElevation": -10 + } + }, + { + "delta": { + "nodeXY6": { + "x": 6142, + "y": -180 + } + }, + "attributes": { + "dElevation": -30 + } + }, + { + "delta": { + "nodeXY6": { + "x": 6636, + "y": -12 + } + }, + "attributes": { + "dElevation": -20 + } + }, + { + "delta": { + "nodeXY6": { + "x": 3804, + "y": -7 + } + } + } + ] + }, + "connectsTo": { + "connectsTo": [ + { + "connectingLane": { + "lane": 19, + "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": 4, + "connectionID": 1 + } + ] + } + }, + { + "laneID": 3, + "ingressApproach": 1, + "laneAttributes": { + "directionalUse": { + "ingressPath": true, + "egressPath": false + }, + "shareWith": { + "busVehicleTraffic": false, + "trackedVehicleTraffic": false, + "individualMotorizedVehicleTraffic": false, + "taxiVehicleTraffic": false, + "overlappingLaneDescriptionProvided": false, + "cyclistVehicleTraffic": false, + "otherNonMotorizedTrafficTypes": false, + "multipleLanesTreatedAsOneLane": false, + "pedestrianTraffic": false, + "pedestriansTraffic": false + }, + "laneType": { + "vehicle": { + "isVehicleRevocableLane": false, + "isVehicleFlyOverLane": false, + "permissionOnRequest": false, + "hasIRbeaconCoverage": false, + "restrictedToBusUse": false, + "restrictedToTaxiUse": false, + "restrictedFromPublicUse": false, + "hovLaneUseOnly": false + } + } + }, + "maneuvers": { + "maneuverStraightAllowed": true, + "maneuverNoStoppingAllowed": false, + "goWithHalt": false, + "maneuverLeftAllowed": false, + "maneuverUTurnAllowed": false, + "maneuverLeftTurnOnRedAllowed": false, + "reserved1": false, + "maneuverRightAllowed": false, + "maneuverLaneChangeAllowed": false, + "yieldAllwaysRequired": false, + "maneuverRightTurnOnRedAllowed": false, + "caution": false + }, + "nodeList": { + "nodes": [ + { + "delta": { + "nodeXY6": { + "x": 2222, + "y": 515 + } + }, + "attributes": { + "dElevation": -10 + } + }, + { + "delta": { + "nodeXY6": { + "x": 2933, + "y": -82 + } + }, + "attributes": { + "dElevation": -10 + } + }, + { + "delta": { + "nodeXY6": { + "x": 6259, + "y": -85 + } + }, + "attributes": { + "dElevation": -40 + } + }, + { + "delta": { + "nodeXY6": { + "x": 3416, + "y": -98 + } + }, + "attributes": { + "dElevation": -20 + } + }, + { + "delta": { + "nodeXY6": { + "x": 6867, + "y": -39 + } + }, + "attributes": { + "dElevation": -30 + } + }, + { + "delta": { + "nodeXY6": { + "x": 2657, + "y": -55 + } + }, + "attributes": { + "dElevation": -10 + } + }, + { + "delta": { + "nodeXY6": { + "x": 4259, + "y": 67 + } + }, + "attributes": { + "dElevation": -10 + } + }, + { + "delta": { + "nodeXY6": { + "x": 3481, + "y": 0 + } + } + } + ] + }, + "connectsTo": { + "connectsTo": [ + { + "connectingLane": { + "lane": 18, + "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": 4, + "connectionID": 1 + } + ] + } + }, + { + "laneID": 1, + "ingressApproach": 1, + "laneAttributes": { + "directionalUse": { + "ingressPath": true, + "egressPath": false + }, + "shareWith": { + "busVehicleTraffic": false, + "trackedVehicleTraffic": false, + "individualMotorizedVehicleTraffic": false, + "taxiVehicleTraffic": false, + "overlappingLaneDescriptionProvided": false, + "cyclistVehicleTraffic": false, + "otherNonMotorizedTrafficTypes": false, + "multipleLanesTreatedAsOneLane": false, + "pedestrianTraffic": false, + "pedestriansTraffic": false + }, + "laneType": { + "vehicle": { + "isVehicleRevocableLane": false, + "isVehicleFlyOverLane": false, + "permissionOnRequest": false, + "hasIRbeaconCoverage": false, + "restrictedToBusUse": false, + "restrictedToTaxiUse": false, + "restrictedFromPublicUse": false, + "hovLaneUseOnly": false + } + } + }, + "maneuvers": { + "maneuverStraightAllowed": false, + "maneuverNoStoppingAllowed": false, + "goWithHalt": false, + "maneuverLeftAllowed": false, + "maneuverUTurnAllowed": false, + "maneuverLeftTurnOnRedAllowed": false, + "reserved1": false, + "maneuverRightAllowed": true, + "maneuverLaneChangeAllowed": false, + "yieldAllwaysRequired": false, + "maneuverRightTurnOnRedAllowed": false, + "caution": false + }, + "nodeList": { + "nodes": [ + { + "delta": { + "nodeXY6": { + "x": 2215, + "y": 1218 + } + } + }, + { + "delta": { + "nodeXY6": { + "x": 10451, + "y": -223 + } + }, + "attributes": { + "dElevation": -70 + } + }, + { + "delta": { + "nodeXY6": { + "x": 1852, + "y": -108 + } + }, + "attributes": { + "dElevation": -10 + } + } + ] + }, + "connectsTo": { + "connectsTo": [ + { + "connectingLane": { + "lane": 28, + "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 + } + ] + } + }, + { + "laneID": 4, + "ingressApproach": 1, + "laneAttributes": { + "directionalUse": { + "ingressPath": true, + "egressPath": false + }, + "shareWith": { + "busVehicleTraffic": false, + "trackedVehicleTraffic": false, + "individualMotorizedVehicleTraffic": false, + "taxiVehicleTraffic": false, + "overlappingLaneDescriptionProvided": false, + "cyclistVehicleTraffic": false, + "otherNonMotorizedTrafficTypes": false, + "multipleLanesTreatedAsOneLane": false, + "pedestrianTraffic": false, + "pedestriansTraffic": false + }, + "laneType": { + "vehicle": { + "isVehicleRevocableLane": false, + "isVehicleFlyOverLane": false, + "permissionOnRequest": false, + "hasIRbeaconCoverage": false, + "restrictedToBusUse": false, + "restrictedToTaxiUse": false, + "restrictedFromPublicUse": false, + "hovLaneUseOnly": false + } + } + }, + "maneuvers": { + "maneuverStraightAllowed": false, + "maneuverNoStoppingAllowed": false, + "goWithHalt": false, + "maneuverLeftAllowed": true, + "maneuverUTurnAllowed": false, + "maneuverLeftTurnOnRedAllowed": false, + "reserved1": false, + "maneuverRightAllowed": false, + "maneuverLaneChangeAllowed": false, + "yieldAllwaysRequired": false, + "maneuverRightTurnOnRedAllowed": false, + "caution": false + }, + "nodeList": { + "nodes": [ + { + "delta": { + "nodeXY6": { + "x": 2213, + "y": -124 + } + }, + "attributes": { + "dElevation": -10 + } + }, + { + "delta": { + "nodeXY6": { + "x": 7187, + "y": 20 + } + }, + "attributes": { + "dElevation": -40 + } + }, + { + "delta": { + "nodeXY6": { + "x": 541, + "y": 40 + } + }, + "attributes": { + "dElevation": -10 + } + }, + { + "delta": { + "nodeXY6": { + "x": 1298, + "y": 229 + } + } + } + ] + }, + "connectsTo": { + "connectsTo": [ + { + "connectingLane": { + "lane": 12, + "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": 7, + "connectionID": 1 + } + ] + } + }, + { + "laneID": 6, + "egressApproach": 2, + "laneAttributes": { + "directionalUse": { + "ingressPath": false, + "egressPath": true + }, + "shareWith": { + "busVehicleTraffic": false, + "trackedVehicleTraffic": false, + "individualMotorizedVehicleTraffic": false, + "taxiVehicleTraffic": false, + "overlappingLaneDescriptionProvided": false, + "cyclistVehicleTraffic": false, + "otherNonMotorizedTrafficTypes": false, + "multipleLanesTreatedAsOneLane": false, + "pedestrianTraffic": false, + "pedestriansTraffic": false + }, + "laneType": { + "vehicle": { + "isVehicleRevocableLane": false, + "isVehicleFlyOverLane": false, + "permissionOnRequest": false, + "hasIRbeaconCoverage": false, + "restrictedToBusUse": false, + "restrictedToTaxiUse": false, + "restrictedFromPublicUse": false, + "hovLaneUseOnly": false + } + } + }, + "nodeList": { + "nodes": [ + { + "delta": { + "nodeXY6": { + "x": 2267, + "y": -1019 + } + }, + "attributes": { + "dElevation": -10 + } + }, + { + "delta": { + "nodeXY6": { + "x": 365, + "y": 7 + } + } + } + ] + } + }, + { + "laneID": 5, + "egressApproach": 2, + "laneAttributes": { + "directionalUse": { + "ingressPath": false, + "egressPath": true + }, + "shareWith": { + "busVehicleTraffic": false, + "trackedVehicleTraffic": false, + "individualMotorizedVehicleTraffic": false, + "taxiVehicleTraffic": false, + "overlappingLaneDescriptionProvided": false, + "cyclistVehicleTraffic": false, + "otherNonMotorizedTrafficTypes": false, + "multipleLanesTreatedAsOneLane": false, + "pedestrianTraffic": false, + "pedestriansTraffic": false + }, + "laneType": { + "vehicle": { + "isVehicleRevocableLane": false, + "isVehicleFlyOverLane": false, + "permissionOnRequest": false, + "hasIRbeaconCoverage": false, + "restrictedToBusUse": false, + "restrictedToTaxiUse": false, + "restrictedFromPublicUse": false, + "hovLaneUseOnly": false + } + } + }, + "nodeList": { + "nodes": [ + { + "delta": { + "nodeXY6": { + "x": 2267, + "y": -662 + } + }, + "attributes": { + "dElevation": -10 + } + }, + { + "delta": { + "nodeXY6": { + "x": 338, + "y": 0 + } + } + } + ] + } + }, + { + "laneID": 7, + "egressApproach": 2, + "laneAttributes": { + "directionalUse": { + "ingressPath": false, + "egressPath": true + }, + "shareWith": { + "busVehicleTraffic": false, + "trackedVehicleTraffic": false, + "individualMotorizedVehicleTraffic": false, + "taxiVehicleTraffic": false, + "overlappingLaneDescriptionProvided": false, + "cyclistVehicleTraffic": false, + "otherNonMotorizedTrafficTypes": false, + "multipleLanesTreatedAsOneLane": false, + "pedestrianTraffic": false, + "pedestriansTraffic": false + }, + "laneType": { + "vehicle": { + "isVehicleRevocableLane": false, + "isVehicleFlyOverLane": false, + "permissionOnRequest": false, + "hasIRbeaconCoverage": false, + "restrictedToBusUse": false, + "restrictedToTaxiUse": false, + "restrictedFromPublicUse": false, + "hovLaneUseOnly": false + } + } + }, + "nodeList": { + "nodes": [ + { + "delta": { + "nodeXY6": { + "x": 2294, + "y": -1463 + } + }, + "attributes": { + "dElevation": -10 + } + }, + { + "delta": { + "nodeXY6": { + "x": 365, + "y": 27 + } + } + } + ] + } + }, + { + "laneID": 12, + "egressApproach": 4, + "laneAttributes": { + "directionalUse": { + "ingressPath": false, + "egressPath": true + }, + "shareWith": { + "busVehicleTraffic": false, + "trackedVehicleTraffic": false, + "individualMotorizedVehicleTraffic": false, + "taxiVehicleTraffic": false, + "overlappingLaneDescriptionProvided": false, + "cyclistVehicleTraffic": false, + "otherNonMotorizedTrafficTypes": false, + "multipleLanesTreatedAsOneLane": false, + "pedestrianTraffic": false, + "pedestriansTraffic": false + }, + "laneType": { + "vehicle": { + "isVehicleRevocableLane": false, + "isVehicleFlyOverLane": false, + "permissionOnRequest": false, + "hasIRbeaconCoverage": false, + "restrictedToBusUse": false, + "restrictedToTaxiUse": false, + "restrictedFromPublicUse": false, + "hovLaneUseOnly": false + } + } + }, + "nodeList": { + "nodes": [ + { + "delta": { + "nodeXY6": { + "x": -952, + "y": -1898 + } + } + }, + { + "delta": { + "nodeXY6": { + "x": 0, + "y": -377 + } + } + } + ] + } + }, + { + "laneID": 13, + "egressApproach": 4, + "laneAttributes": { + "directionalUse": { + "ingressPath": false, + "egressPath": true + }, + "shareWith": { + "busVehicleTraffic": false, + "trackedVehicleTraffic": false, + "individualMotorizedVehicleTraffic": false, + "taxiVehicleTraffic": false, + "overlappingLaneDescriptionProvided": false, + "cyclistVehicleTraffic": false, + "otherNonMotorizedTrafficTypes": false, + "multipleLanesTreatedAsOneLane": false, + "pedestrianTraffic": false, + "pedestriansTraffic": false + }, + "laneType": { + "vehicle": { + "isVehicleRevocableLane": false, + "isVehicleFlyOverLane": false, + "permissionOnRequest": false, + "hasIRbeaconCoverage": false, + "restrictedToBusUse": false, + "restrictedToTaxiUse": false, + "restrictedFromPublicUse": false, + "hovLaneUseOnly": false + } + } + }, + "nodeList": { + "nodes": [ + { + "delta": { + "nodeXY6": { + "x": -1440, + "y": -1898 + } + } + }, + { + "delta": { + "nodeXY6": { + "x": 7, + "y": -390 + } + } + }, + { + "delta": { + "nodeXY6": { + "x": 0, + "y": 0 + } + } + }, + { + "delta": { + "nodeXY6": { + "x": 0, + "y": 7 + } + } + } + ] + } + }, + { + "laneID": 10, + "ingressApproach": 3, + "laneAttributes": { + "directionalUse": { + "ingressPath": true, + "egressPath": false + }, + "shareWith": { + "busVehicleTraffic": false, + "trackedVehicleTraffic": false, + "individualMotorizedVehicleTraffic": false, + "taxiVehicleTraffic": false, + "overlappingLaneDescriptionProvided": false, + "cyclistVehicleTraffic": false, + "otherNonMotorizedTrafficTypes": false, + "multipleLanesTreatedAsOneLane": false, + "pedestrianTraffic": false, + "pedestriansTraffic": false + }, + "laneType": { + "vehicle": { + "isVehicleRevocableLane": false, + "isVehicleFlyOverLane": false, + "permissionOnRequest": false, + "hasIRbeaconCoverage": false, + "restrictedToBusUse": false, + "restrictedToTaxiUse": false, + "restrictedFromPublicUse": false, + "hovLaneUseOnly": false + } + } + }, + "maneuvers": { + "maneuverStraightAllowed": true, + "maneuverNoStoppingAllowed": false, + "goWithHalt": false, + "maneuverLeftAllowed": false, + "maneuverUTurnAllowed": false, + "maneuverLeftTurnOnRedAllowed": false, + "reserved1": false, + "maneuverRightAllowed": false, + "maneuverLaneChangeAllowed": false, + "yieldAllwaysRequired": false, + "maneuverRightTurnOnRedAllowed": false, + "caution": false + }, + "nodeList": { + "nodes": [ + { + "delta": { + "nodeXY6": { + "x": 705, + "y": -1919 + } + } + }, + { + "delta": { + "nodeXY6": { + "x": -1, + "y": -7515 + } + }, + "attributes": { + "dElevation": -40 + } + }, + { + "delta": { + "nodeXY6": { + "x": -41, + "y": -5272 + } + }, + "attributes": { + "dElevation": 10 + } + }, + { + "delta": { + "nodeXY6": { + "x": -17, + "y": -11337 + } + } + }, + { + "delta": { + "nodeXY6": { + "x": 17, + "y": -5938 + } + }, + "attributes": { + "dElevation": 10 + } + }, + { + "delta": { + "nodeXY6": { + "x": 0, + "y": 0 + } + } + }, + { + "delta": { + "nodeXY6": { + "x": -7, + "y": -7 + } + } + } + ] + }, + "connectsTo": { + "connectsTo": [ + { + "connectingLane": { + "lane": 26, + "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 + } + ] + } + }, + { + "laneID": 9, + "ingressApproach": 3, + "laneAttributes": { + "directionalUse": { + "ingressPath": true, + "egressPath": false + }, + "shareWith": { + "busVehicleTraffic": false, + "trackedVehicleTraffic": false, + "individualMotorizedVehicleTraffic": false, + "taxiVehicleTraffic": false, + "overlappingLaneDescriptionProvided": false, + "cyclistVehicleTraffic": false, + "otherNonMotorizedTrafficTypes": false, + "multipleLanesTreatedAsOneLane": false, + "pedestrianTraffic": false, + "pedestriansTraffic": false + }, + "laneType": { + "vehicle": { + "isVehicleRevocableLane": false, + "isVehicleFlyOverLane": false, + "permissionOnRequest": false, + "hasIRbeaconCoverage": false, + "restrictedToBusUse": false, + "restrictedToTaxiUse": false, + "restrictedFromPublicUse": false, + "hovLaneUseOnly": false + } + } + }, + "maneuvers": { + "maneuverStraightAllowed": true, + "maneuverNoStoppingAllowed": false, + "goWithHalt": false, + "maneuverLeftAllowed": false, + "maneuverUTurnAllowed": false, + "maneuverLeftTurnOnRedAllowed": false, + "reserved1": false, + "maneuverRightAllowed": false, + "maneuverLaneChangeAllowed": false, + "yieldAllwaysRequired": false, + "maneuverRightTurnOnRedAllowed": false, + "caution": false + }, + "nodeList": { + "nodes": [ + { + "delta": { + "nodeXY6": { + "x": 1090, + "y": -1930 + } + }, + "attributes": { + "dElevation": -10 + } + }, + { + "delta": { + "nodeXY6": { + "x": 9, + "y": -4764 + } + }, + "attributes": { + "dElevation": -10 + } + }, + { + "delta": { + "nodeXY6": { + "x": -20, + "y": -6402 + } + }, + "attributes": { + "dElevation": -20 + } + }, + { + "delta": { + "nodeXY6": { + "x": -34, + "y": -7953 + } + }, + "attributes": { + "dElevation": -10 + } + }, + { + "delta": { + "nodeXY6": { + "x": 16, + "y": -10940 + } + }, + "attributes": { + "dElevation": 20 + } + } + ] + }, + "connectsTo": { + "connectsTo": [ + { + "connectingLane": { + "lane": 27, + "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 + } + ] + } + }, + { + "laneID": 11, + "ingressApproach": 3, + "laneAttributes": { + "directionalUse": { + "ingressPath": true, + "egressPath": false + }, + "shareWith": { + "busVehicleTraffic": false, + "trackedVehicleTraffic": false, + "individualMotorizedVehicleTraffic": false, + "taxiVehicleTraffic": false, + "overlappingLaneDescriptionProvided": false, + "cyclistVehicleTraffic": false, + "otherNonMotorizedTrafficTypes": false, + "multipleLanesTreatedAsOneLane": false, + "pedestrianTraffic": false, + "pedestriansTraffic": false + }, + "laneType": { + "vehicle": { + "isVehicleRevocableLane": false, + "isVehicleFlyOverLane": false, + "permissionOnRequest": false, + "hasIRbeaconCoverage": false, + "restrictedToBusUse": false, + "restrictedToTaxiUse": false, + "restrictedFromPublicUse": false, + "hovLaneUseOnly": false + } + } + }, + "maneuvers": { + "maneuverStraightAllowed": false, + "maneuverNoStoppingAllowed": false, + "goWithHalt": false, + "maneuverLeftAllowed": true, + "maneuverUTurnAllowed": false, + "maneuverLeftTurnOnRedAllowed": false, + "reserved1": false, + "maneuverRightAllowed": false, + "maneuverLaneChangeAllowed": false, + "yieldAllwaysRequired": false, + "maneuverRightTurnOnRedAllowed": false, + "caution": false + }, + "nodeList": { + "nodes": [ + { + "delta": { + "nodeXY6": { + "x": 350, + "y": -1925 + } + } + }, + { + "delta": { + "nodeXY6": { + "x": -32, + "y": -6698 + } + }, + "attributes": { + "dElevation": -30 + } + }, + { + "delta": { + "nodeXY6": { + "x": 156, + "y": -2616 + } + } + } + ] + }, + "connectsTo": { + "connectsTo": [ + { + "connectingLane": { + "lane": 18, + "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": 1, + "connectionID": 1 + } + ] + } + }, + { + "laneID": 8, + "ingressApproach": 3, + "laneAttributes": { + "directionalUse": { + "ingressPath": true, + "egressPath": false + }, + "shareWith": { + "busVehicleTraffic": false, + "trackedVehicleTraffic": false, + "individualMotorizedVehicleTraffic": false, + "taxiVehicleTraffic": false, + "overlappingLaneDescriptionProvided": false, + "cyclistVehicleTraffic": false, + "otherNonMotorizedTrafficTypes": false, + "multipleLanesTreatedAsOneLane": false, + "pedestrianTraffic": false, + "pedestriansTraffic": false + }, + "laneType": { + "vehicle": { + "isVehicleRevocableLane": false, + "isVehicleFlyOverLane": false, + "permissionOnRequest": false, + "hasIRbeaconCoverage": false, + "restrictedToBusUse": false, + "restrictedToTaxiUse": false, + "restrictedFromPublicUse": false, + "hovLaneUseOnly": false + } + } + }, + "maneuvers": { + "maneuverStraightAllowed": false, + "maneuverNoStoppingAllowed": false, + "goWithHalt": false, + "maneuverLeftAllowed": false, + "maneuverUTurnAllowed": false, + "maneuverLeftTurnOnRedAllowed": false, + "reserved1": false, + "maneuverRightAllowed": true, + "maneuverLaneChangeAllowed": false, + "yieldAllwaysRequired": false, + "maneuverRightTurnOnRedAllowed": false, + "caution": false + }, + "nodeList": { + "nodes": [ + { + "delta": { + "nodeXY6": { + "x": 1557, + "y": -1956 + } + }, + "attributes": { + "dElevation": -10 + } + }, + { + "delta": { + "nodeXY6": { + "x": -101, + "y": -1956 + } + } + }, + { + "delta": { + "nodeXY6": { + "x": -5, + "y": -7393 + } + }, + "attributes": { + "dElevation": -40 + } + }, + { + "delta": { + "nodeXY6": { + "x": -121, + "y": -1636 + } + } + } + ] + }, + "connectsTo": { + "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 + } + }, + "connectionID": 1 + } + ] + } + }, + { + "laneID": 15, + "ingressApproach": 5, + "laneAttributes": { + "directionalUse": { + "ingressPath": true, + "egressPath": false + }, + "shareWith": { + "busVehicleTraffic": false, + "trackedVehicleTraffic": false, + "individualMotorizedVehicleTraffic": false, + "taxiVehicleTraffic": false, + "overlappingLaneDescriptionProvided": false, + "cyclistVehicleTraffic": false, + "otherNonMotorizedTrafficTypes": false, + "multipleLanesTreatedAsOneLane": false, + "pedestrianTraffic": false, + "pedestriansTraffic": false + }, + "laneType": { + "vehicle": { + "isVehicleRevocableLane": false, + "isVehicleFlyOverLane": false, + "permissionOnRequest": false, + "hasIRbeaconCoverage": false, + "restrictedToBusUse": false, + "restrictedToTaxiUse": false, + "restrictedFromPublicUse": false, + "hovLaneUseOnly": false + } + } + }, + "maneuvers": { + "maneuverStraightAllowed": true, + "maneuverNoStoppingAllowed": false, + "goWithHalt": false, + "maneuverLeftAllowed": false, + "maneuverUTurnAllowed": false, + "maneuverLeftTurnOnRedAllowed": false, + "reserved1": false, + "maneuverRightAllowed": false, + "maneuverLaneChangeAllowed": false, + "yieldAllwaysRequired": false, + "maneuverRightTurnOnRedAllowed": false, + "caution": false + }, + "nodeList": { + "nodes": [ + { + "delta": { + "nodeXY6": { + "x": -2405, + "y": -1018 + } + }, + "attributes": { + "dElevation": 10 + } + }, + { + "delta": { + "nodeXY6": { + "x": -9339, + "y": 26 + } + }, + "attributes": { + "dElevation": 30 + } + }, + { + "delta": { + "nodeXY6": { + "x": -11895, + "y": -38 + } + }, + "attributes": { + "dElevation": 50 + } + }, + { + "delta": { + "nodeXY6": { + "x": -8814, + "y": 13 + } + } + } + ] + }, + "connectsTo": { + "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 + } + }, + "signalGroup": 8, + "connectionID": 1 + } + ] + } + }, + { + "laneID": 16, + "ingressApproach": 5, + "laneAttributes": { + "directionalUse": { + "ingressPath": true, + "egressPath": false + }, + "shareWith": { + "busVehicleTraffic": false, + "trackedVehicleTraffic": false, + "individualMotorizedVehicleTraffic": false, + "taxiVehicleTraffic": false, + "overlappingLaneDescriptionProvided": false, + "cyclistVehicleTraffic": false, + "otherNonMotorizedTrafficTypes": false, + "multipleLanesTreatedAsOneLane": false, + "pedestrianTraffic": false, + "pedestriansTraffic": false + }, + "laneType": { + "vehicle": { + "isVehicleRevocableLane": false, + "isVehicleFlyOverLane": false, + "permissionOnRequest": false, + "hasIRbeaconCoverage": false, + "restrictedToBusUse": false, + "restrictedToTaxiUse": false, + "restrictedFromPublicUse": false, + "hovLaneUseOnly": false + } + } + }, + "maneuvers": { + "maneuverStraightAllowed": true, + "maneuverNoStoppingAllowed": false, + "goWithHalt": false, + "maneuverLeftAllowed": false, + "maneuverUTurnAllowed": false, + "maneuverLeftTurnOnRedAllowed": false, + "reserved1": false, + "maneuverRightAllowed": false, + "maneuverLaneChangeAllowed": false, + "yieldAllwaysRequired": false, + "maneuverRightTurnOnRedAllowed": false, + "caution": false + }, + "nodeList": { + "nodes": [ + { + "delta": { + "nodeXY6": { + "x": -2337, + "y": -656 + } + }, + "attributes": { + "dElevation": 10 + } + }, + { + "delta": { + "nodeXY6": { + "x": -12229, + "y": 15 + } + }, + "attributes": { + "dElevation": 50 + } + }, + { + "delta": { + "nodeXY6": { + "x": -11362, + "y": -37 + } + }, + "attributes": { + "dElevation": 30 + } + }, + { + "delta": { + "nodeXY6": { + "x": -6537, + "y": 1 + } + } + } + ] + }, + "connectsTo": { + "connectsTo": [ + { + "connectingLane": { + "lane": 5, + "maneuver": { + "maneuverStraightAllowed": true, + "maneuverNoStoppingAllowed": false, + "goWithHalt": false, + "maneuverLeftAllowed": false, + "maneuverUTurnAllowed": false, + "maneuverLeftTurnOnRedAllowed": false, + "reserved1": false, + "maneuverRightAllowed": false, + "maneuverLaneChangeAllowed": false, + "yieldAllwaysRequired": false, + "maneuverRightTurnOnRedAllowed": false, + "caution": false + } + }, + "signalGroup": 8, + "connectionID": 1 + } + ] + } + }, + { + "laneID": 17, + "ingressApproach": 5, + "laneAttributes": { + "directionalUse": { + "ingressPath": true, + "egressPath": false + }, + "shareWith": { + "busVehicleTraffic": false, + "trackedVehicleTraffic": false, + "individualMotorizedVehicleTraffic": false, + "taxiVehicleTraffic": false, + "overlappingLaneDescriptionProvided": false, + "cyclistVehicleTraffic": false, + "otherNonMotorizedTrafficTypes": false, + "multipleLanesTreatedAsOneLane": false, + "pedestrianTraffic": false, + "pedestriansTraffic": false + }, + "laneType": { + "vehicle": { + "isVehicleRevocableLane": false, + "isVehicleFlyOverLane": false, + "permissionOnRequest": false, + "hasIRbeaconCoverage": false, + "restrictedToBusUse": false, + "restrictedToTaxiUse": false, + "restrictedFromPublicUse": false, + "hovLaneUseOnly": false + } + } + }, + "maneuvers": { + "maneuverStraightAllowed": false, + "maneuverNoStoppingAllowed": false, + "goWithHalt": false, + "maneuverLeftAllowed": true, + "maneuverUTurnAllowed": false, + "maneuverLeftTurnOnRedAllowed": false, + "reserved1": false, + "maneuverRightAllowed": false, + "maneuverLaneChangeAllowed": false, + "yieldAllwaysRequired": false, + "maneuverRightTurnOnRedAllowed": false, + "caution": false + }, + "nodeList": { + "nodes": [ + { + "delta": { + "nodeXY6": { + "x": -2338, + "y": -284 + } + }, + "attributes": { + "dElevation": 10 + } + }, + { + "delta": { + "nodeXY6": { + "x": -8892, + "y": -18 + } + }, + "attributes": { + "dElevation": 30 + } + }, + { + "delta": { + "nodeXY6": { + "x": -11959, + "y": -2 + } + }, + "attributes": { + "dElevation": 50 + } + }, + { + "delta": { + "nodeXY6": { + "x": -1564, + "y": -180 + } + } + } + ] + }, + "connectsTo": { + "connectsTo": [ + { + "connectingLane": { + "lane": 26, + "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": 3, + "connectionID": 1 + } + ] + } + }, + { + "laneID": 14, + "ingressApproach": 5, + "laneAttributes": { + "directionalUse": { + "ingressPath": true, + "egressPath": false + }, + "shareWith": { + "busVehicleTraffic": false, + "trackedVehicleTraffic": false, + "individualMotorizedVehicleTraffic": false, + "taxiVehicleTraffic": false, + "overlappingLaneDescriptionProvided": false, + "cyclistVehicleTraffic": false, + "otherNonMotorizedTrafficTypes": false, + "multipleLanesTreatedAsOneLane": false, + "pedestrianTraffic": false, + "pedestriansTraffic": false + }, + "laneType": { + "vehicle": { + "isVehicleRevocableLane": false, + "isVehicleFlyOverLane": false, + "permissionOnRequest": false, + "hasIRbeaconCoverage": false, + "restrictedToBusUse": false, + "restrictedToTaxiUse": false, + "restrictedFromPublicUse": false, + "hovLaneUseOnly": false + } + } + }, + "maneuvers": { + "maneuverStraightAllowed": false, + "maneuverNoStoppingAllowed": false, + "goWithHalt": false, + "maneuverLeftAllowed": false, + "maneuverUTurnAllowed": false, + "maneuverLeftTurnOnRedAllowed": false, + "reserved1": false, + "maneuverRightAllowed": true, + "maneuverLaneChangeAllowed": false, + "yieldAllwaysRequired": false, + "maneuverRightTurnOnRedAllowed": false, + "caution": false + }, + "nodeList": { + "nodes": [ + { + "delta": { + "nodeXY6": { + "x": -2401, + "y": -1380 + } + }, + "attributes": { + "dElevation": 10 + } + }, + { + "delta": { + "nodeXY6": { + "x": -19947, + "y": 8 + } + }, + "attributes": { + "dElevation": 80 + } + }, + { + "delta": { + "nodeXY6": { + "x": -10108, + "y": -7 + } + } + } + ] + }, + "connectsTo": { + "connectsTo": [ + { + "connectingLane": { + "lane": 13, + "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 + } + ] + } + }, + { + "laneID": 18, + "egressApproach": 6, + "laneAttributes": { + "directionalUse": { + "ingressPath": false, + "egressPath": true + }, + "shareWith": { + "busVehicleTraffic": false, + "trackedVehicleTraffic": false, + "individualMotorizedVehicleTraffic": false, + "taxiVehicleTraffic": false, + "overlappingLaneDescriptionProvided": false, + "cyclistVehicleTraffic": false, + "otherNonMotorizedTrafficTypes": false, + "multipleLanesTreatedAsOneLane": false, + "pedestrianTraffic": false, + "pedestriansTraffic": false + }, + "laneType": { + "vehicle": { + "isVehicleRevocableLane": false, + "isVehicleFlyOverLane": false, + "permissionOnRequest": false, + "hasIRbeaconCoverage": false, + "restrictedToBusUse": false, + "restrictedToTaxiUse": false, + "restrictedFromPublicUse": false, + "hovLaneUseOnly": false + } + } + }, + "nodeList": { + "nodes": [ + { + "delta": { + "nodeXY6": { + "x": -2264, + "y": 479 + } + }, + "attributes": { + "dElevation": 20 + } + }, + { + "delta": { + "nodeXY6": { + "x": -580, + "y": -14 + } + } + } + ] + } + }, + { + "laneID": 19, + "egressApproach": 6, + "laneAttributes": { + "directionalUse": { + "ingressPath": false, + "egressPath": true + }, + "shareWith": { + "busVehicleTraffic": false, + "trackedVehicleTraffic": false, + "individualMotorizedVehicleTraffic": false, + "taxiVehicleTraffic": false, + "overlappingLaneDescriptionProvided": false, + "cyclistVehicleTraffic": false, + "otherNonMotorizedTrafficTypes": false, + "multipleLanesTreatedAsOneLane": false, + "pedestrianTraffic": false, + "pedestriansTraffic": false + }, + "laneType": { + "vehicle": { + "isVehicleRevocableLane": false, + "isVehicleFlyOverLane": false, + "permissionOnRequest": false, + "hasIRbeaconCoverage": false, + "restrictedToBusUse": false, + "restrictedToTaxiUse": false, + "restrictedFromPublicUse": false, + "hovLaneUseOnly": false + } + } + }, + "nodeList": { + "nodes": [ + { + "delta": { + "nodeXY6": { + "x": -2257, + "y": 796 + } + }, + "attributes": { + "dElevation": 20 + } + }, + { + "delta": { + "nodeXY6": { + "x": -518, + "y": 0 + } + } + } + ] + } + }, + { + "laneID": 20, + "egressApproach": 6, + "laneAttributes": { + "directionalUse": { + "ingressPath": false, + "egressPath": true + }, + "shareWith": { + "busVehicleTraffic": false, + "trackedVehicleTraffic": false, + "individualMotorizedVehicleTraffic": false, + "taxiVehicleTraffic": false, + "overlappingLaneDescriptionProvided": false, + "cyclistVehicleTraffic": false, + "otherNonMotorizedTrafficTypes": false, + "multipleLanesTreatedAsOneLane": false, + "pedestrianTraffic": false, + "pedestriansTraffic": false + }, + "laneType": { + "vehicle": { + "isVehicleRevocableLane": false, + "isVehicleFlyOverLane": false, + "permissionOnRequest": false, + "hasIRbeaconCoverage": false, + "restrictedToBusUse": false, + "restrictedToTaxiUse": false, + "restrictedFromPublicUse": false, + "hovLaneUseOnly": false + } + } + }, + "nodeList": { + "nodes": [ + { + "delta": { + "nodeXY6": { + "x": -2236, + "y": 1229 + } + }, + "attributes": { + "dElevation": 20 + } + }, + { + "delta": { + "nodeXY6": { + "x": -484, + "y": 0 + } + } + } + ] + } + }, + { + "laneID": 23, + "ingressApproach": 7, + "laneAttributes": { + "directionalUse": { + "ingressPath": true, + "egressPath": false + }, + "shareWith": { + "busVehicleTraffic": false, + "trackedVehicleTraffic": false, + "individualMotorizedVehicleTraffic": false, + "taxiVehicleTraffic": false, + "overlappingLaneDescriptionProvided": false, + "cyclistVehicleTraffic": false, + "otherNonMotorizedTrafficTypes": false, + "multipleLanesTreatedAsOneLane": false, + "pedestrianTraffic": false, + "pedestriansTraffic": false + }, + "laneType": { + "vehicle": { + "isVehicleRevocableLane": false, + "isVehicleFlyOverLane": false, + "permissionOnRequest": false, + "hasIRbeaconCoverage": false, + "restrictedToBusUse": false, + "restrictedToTaxiUse": false, + "restrictedFromPublicUse": false, + "hovLaneUseOnly": false + } + } + }, + "maneuvers": { + "maneuverStraightAllowed": true, + "maneuverNoStoppingAllowed": false, + "goWithHalt": false, + "maneuverLeftAllowed": false, + "maneuverUTurnAllowed": false, + "maneuverLeftTurnOnRedAllowed": false, + "reserved1": false, + "maneuverRightAllowed": false, + "maneuverLaneChangeAllowed": false, + "yieldAllwaysRequired": false, + "maneuverRightTurnOnRedAllowed": false, + "caution": false + }, + "nodeList": { + "nodes": [ + { + "delta": { + "nodeXY6": { + "x": -914, + "y": 1903 + } + }, + "attributes": { + "dElevation": 20 + } + }, + { + "delta": { + "nodeXY6": { + "x": 225, + "y": 12288 + } + }, + "attributes": { + "dElevation": 30 + } + }, + { + "delta": { + "nodeXY6": { + "x": 40, + "y": 9634 + } + }, + "attributes": { + "dElevation": -20 + } + }, + { + "delta": { + "nodeXY6": { + "x": 32, + "y": 8035 + } + }, + "attributes": { + "dElevation": -30 + } + }, + { + "delta": { + "nodeXY6": { + "x": 0, + "y": 0 + } + } + }, + { + "delta": { + "nodeXY6": { + "x": -7, + "y": 28 + } + } + } + ] + }, + "connectsTo": { + "connectsTo": [ + { + "connectingLane": { + "lane": 12, + "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 + } + ] + } + }, + { + "laneID": 22, + "ingressApproach": 7, + "laneAttributes": { + "directionalUse": { + "ingressPath": true, + "egressPath": false + }, + "shareWith": { + "busVehicleTraffic": false, + "trackedVehicleTraffic": false, + "individualMotorizedVehicleTraffic": false, + "taxiVehicleTraffic": false, + "overlappingLaneDescriptionProvided": false, + "cyclistVehicleTraffic": false, + "otherNonMotorizedTrafficTypes": false, + "multipleLanesTreatedAsOneLane": false, + "pedestrianTraffic": false, + "pedestriansTraffic": false + }, + "laneType": { + "vehicle": { + "isVehicleRevocableLane": false, + "isVehicleFlyOverLane": false, + "permissionOnRequest": false, + "hasIRbeaconCoverage": false, + "restrictedToBusUse": false, + "restrictedToTaxiUse": false, + "restrictedFromPublicUse": false, + "hovLaneUseOnly": false + } + } + }, + "maneuvers": { + "maneuverStraightAllowed": true, + "maneuverNoStoppingAllowed": false, + "goWithHalt": false, + "maneuverLeftAllowed": false, + "maneuverUTurnAllowed": false, + "maneuverLeftTurnOnRedAllowed": false, + "reserved1": false, + "maneuverRightAllowed": false, + "maneuverLaneChangeAllowed": false, + "yieldAllwaysRequired": false, + "maneuverRightTurnOnRedAllowed": false, + "caution": false + }, + "nodeList": { + "nodes": [ + { + "delta": { + "nodeXY6": { + "x": -1221, + "y": 1914 + } + }, + "attributes": { + "dElevation": 20 + } + }, + { + "delta": { + "nodeXY6": { + "x": 92, + "y": 10475 + } + }, + "attributes": { + "dElevation": 30 + } + }, + { + "delta": { + "nodeXY6": { + "x": 89, + "y": 11582 + } + }, + "attributes": { + "dElevation": -20 + } + }, + { + "delta": { + "nodeXY6": { + "x": 48, + "y": 7912 + } + }, + "attributes": { + "dElevation": -30 + } + } + ] + }, + "connectsTo": { + "connectsTo": [ + { + "connectingLane": { + "lane": 13, + "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 + } + ] + } + }, + { + "laneID": 21, + "ingressApproach": 7, + "laneAttributes": { + "directionalUse": { + "ingressPath": true, + "egressPath": false + }, + "shareWith": { + "busVehicleTraffic": false, + "trackedVehicleTraffic": false, + "individualMotorizedVehicleTraffic": false, + "taxiVehicleTraffic": false, + "overlappingLaneDescriptionProvided": false, + "cyclistVehicleTraffic": false, + "otherNonMotorizedTrafficTypes": false, + "multipleLanesTreatedAsOneLane": false, + "pedestrianTraffic": false, + "pedestriansTraffic": false + }, + "laneType": { + "vehicle": { + "isVehicleRevocableLane": false, + "isVehicleFlyOverLane": false, + "permissionOnRequest": false, + "hasIRbeaconCoverage": false, + "restrictedToBusUse": false, + "restrictedToTaxiUse": false, + "restrictedFromPublicUse": false, + "hovLaneUseOnly": false + } + } + }, + "maneuvers": { + "maneuverStraightAllowed": false, + "maneuverNoStoppingAllowed": false, + "goWithHalt": false, + "maneuverLeftAllowed": false, + "maneuverUTurnAllowed": false, + "maneuverLeftTurnOnRedAllowed": false, + "reserved1": false, + "maneuverRightAllowed": true, + "maneuverLaneChangeAllowed": false, + "yieldAllwaysRequired": false, + "maneuverRightTurnOnRedAllowed": false, + "caution": false + }, + "nodeList": { + "nodes": [ + { + "delta": { + "nodeXY6": { + "x": -1649, + "y": 1935 + } + }, + "attributes": { + "dElevation": 20 + } + }, + { + "delta": { + "nodeXY6": { + "x": 16, + "y": 3182 + } + }, + "attributes": { + "dElevation": 10 + } + }, + { + "delta": { + "nodeXY6": { + "x": 21, + "y": 5991 + } + }, + "attributes": { + "dElevation": 20 + } + }, + { + "delta": { + "nodeXY6": { + "x": 102, + "y": 4810 + } + } + }, + { + "delta": { + "nodeXY6": { + "x": 85, + "y": 11803 + } + }, + "attributes": { + "dElevation": -30 + } + }, + { + "delta": { + "nodeXY6": { + "x": 19, + "y": 4161 + } + }, + "attributes": { + "dElevation": -20 + } + } + ] + }, + "connectsTo": { + "connectsTo": [ + { + "connectingLane": { + "lane": 20, + "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 + } + ] + } + }, + { + "laneID": 24, + "ingressApproach": 7, + "laneAttributes": { + "directionalUse": { + "ingressPath": true, + "egressPath": false + }, + "shareWith": { + "busVehicleTraffic": false, + "trackedVehicleTraffic": false, + "individualMotorizedVehicleTraffic": false, + "taxiVehicleTraffic": false, + "overlappingLaneDescriptionProvided": false, + "cyclistVehicleTraffic": false, + "otherNonMotorizedTrafficTypes": false, + "multipleLanesTreatedAsOneLane": false, + "pedestrianTraffic": false, + "pedestriansTraffic": false + }, + "laneType": { + "vehicle": { + "isVehicleRevocableLane": false, + "isVehicleFlyOverLane": false, + "permissionOnRequest": false, + "hasIRbeaconCoverage": false, + "restrictedToBusUse": false, + "restrictedToTaxiUse": false, + "restrictedFromPublicUse": false, + "hovLaneUseOnly": false + } + } + }, + "maneuvers": { + "maneuverStraightAllowed": false, + "maneuverNoStoppingAllowed": false, + "goWithHalt": false, + "maneuverLeftAllowed": true, + "maneuverUTurnAllowed": false, + "maneuverLeftTurnOnRedAllowed": false, + "reserved1": false, + "maneuverRightAllowed": false, + "maneuverLaneChangeAllowed": false, + "yieldAllwaysRequired": false, + "maneuverRightTurnOnRedAllowed": false, + "caution": false + }, + "nodeList": { + "nodes": [ + { + "delta": { + "nodeXY6": { + "x": -535, + "y": 1926 + } + }, + "attributes": { + "dElevation": 20 + } + }, + { + "delta": { + "nodeXY6": { + "x": 28, + "y": 4582 + } + }, + "attributes": { + "dElevation": 10 + } + }, + { + "delta": { + "nodeXY6": { + "x": 88, + "y": 3793 + } + }, + "attributes": { + "dElevation": 10 + } + }, + { + "delta": { + "nodeXY6": { + "x": -143, + "y": 1866 + } + }, + "attributes": { + "dElevation": 10 + } + } + ] + }, + "connectsTo": { + "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 + } + }, + "signalGroup": 5, + "connectionID": 1 + } + ] + } + }, + { + "laneID": 25, + "ingressApproach": 7, + "laneAttributes": { + "directionalUse": { + "ingressPath": true, + "egressPath": false + }, + "shareWith": { + "busVehicleTraffic": false, + "trackedVehicleTraffic": false, + "individualMotorizedVehicleTraffic": false, + "taxiVehicleTraffic": false, + "overlappingLaneDescriptionProvided": false, + "cyclistVehicleTraffic": false, + "otherNonMotorizedTrafficTypes": false, + "multipleLanesTreatedAsOneLane": false, + "pedestrianTraffic": false, + "pedestriansTraffic": false + }, + "laneType": { + "vehicle": { + "isVehicleRevocableLane": false, + "isVehicleFlyOverLane": false, + "permissionOnRequest": false, + "hasIRbeaconCoverage": false, + "restrictedToBusUse": false, + "restrictedToTaxiUse": false, + "restrictedFromPublicUse": false, + "hovLaneUseOnly": false + } + } + }, + "maneuvers": { + "maneuverStraightAllowed": false, + "maneuverNoStoppingAllowed": false, + "goWithHalt": false, + "maneuverLeftAllowed": true, + "maneuverUTurnAllowed": false, + "maneuverLeftTurnOnRedAllowed": false, + "reserved1": false, + "maneuverRightAllowed": false, + "maneuverLaneChangeAllowed": false, + "yieldAllwaysRequired": false, + "maneuverRightTurnOnRedAllowed": false, + "caution": false + }, + "nodeList": { + "nodes": [ + { + "delta": { + "nodeXY6": { + "x": -213, + "y": 1913 + } + }, + "attributes": { + "dElevation": 20 + } + }, + { + "delta": { + "nodeXY6": { + "x": 14, + "y": 4594 + } + }, + "attributes": { + "dElevation": 10 + } + }, + { + "delta": { + "nodeXY6": { + "x": -91, + "y": 2238 + } + }, + "attributes": { + "dElevation": 10 + } + } + ] + }, + "connectsTo": { + "connectsTo": [ + { + "connectingLane": { + "lane": 5, + "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": 5, + "connectionID": 1 + } + ] + } + }, + { + "laneID": 26, + "egressApproach": 8, + "laneAttributes": { + "directionalUse": { + "ingressPath": false, + "egressPath": true + }, + "shareWith": { + "busVehicleTraffic": false, + "trackedVehicleTraffic": false, + "individualMotorizedVehicleTraffic": false, + "taxiVehicleTraffic": false, + "overlappingLaneDescriptionProvided": false, + "cyclistVehicleTraffic": false, + "otherNonMotorizedTrafficTypes": false, + "multipleLanesTreatedAsOneLane": false, + "pedestrianTraffic": false, + "pedestriansTraffic": false + }, + "laneType": { + "vehicle": { + "isVehicleRevocableLane": false, + "isVehicleFlyOverLane": false, + "permissionOnRequest": false, + "hasIRbeaconCoverage": false, + "restrictedToBusUse": false, + "restrictedToTaxiUse": false, + "restrictedFromPublicUse": false, + "hovLaneUseOnly": false + } + } + }, + "nodeList": { + "nodes": [ + { + "delta": { + "nodeXY6": { + "x": 724, + "y": 1902 + } + }, + "attributes": { + "dElevation": 10 + } + }, + { + "delta": { + "nodeXY6": { + "x": -7, + "y": 352 + } + }, + "attributes": { + "dElevation": 10 + } + } + ] + } + }, + { + "laneID": 27, + "egressApproach": 8, + "laneAttributes": { + "directionalUse": { + "ingressPath": false, + "egressPath": true + }, + "shareWith": { + "busVehicleTraffic": false, + "trackedVehicleTraffic": false, + "individualMotorizedVehicleTraffic": false, + "taxiVehicleTraffic": false, + "overlappingLaneDescriptionProvided": false, + "cyclistVehicleTraffic": false, + "otherNonMotorizedTrafficTypes": false, + "multipleLanesTreatedAsOneLane": false, + "pedestrianTraffic": false, + "pedestriansTraffic": false + }, + "laneType": { + "vehicle": { + "isVehicleRevocableLane": false, + "isVehicleFlyOverLane": false, + "permissionOnRequest": false, + "hasIRbeaconCoverage": false, + "restrictedToBusUse": false, + "restrictedToTaxiUse": false, + "restrictedFromPublicUse": false, + "hovLaneUseOnly": false + } + } + }, + "nodeList": { + "nodes": [ + { + "delta": { + "nodeXY6": { + "x": 1105, + "y": 1888 + } + }, + "attributes": { + "dElevation": 10 + } + }, + { + "delta": { + "nodeXY6": { + "x": -7, + "y": 332 + } + }, + "attributes": { + "dElevation": 10 + } + } + ] + } + }, + { + "laneID": 28, + "egressApproach": 8, + "laneAttributes": { + "directionalUse": { + "ingressPath": false, + "egressPath": true + }, + "shareWith": { + "busVehicleTraffic": false, + "trackedVehicleTraffic": false, + "individualMotorizedVehicleTraffic": false, + "taxiVehicleTraffic": false, + "overlappingLaneDescriptionProvided": false, + "cyclistVehicleTraffic": false, + "otherNonMotorizedTrafficTypes": false, + "multipleLanesTreatedAsOneLane": false, + "pedestrianTraffic": false, + "pedestriansTraffic": false + }, + "laneType": { + "vehicle": { + "isVehicleRevocableLane": false, + "isVehicleFlyOverLane": false, + "permissionOnRequest": false, + "hasIRbeaconCoverage": false, + "restrictedToBusUse": false, + "restrictedToTaxiUse": false, + "restrictedFromPublicUse": false, + "hovLaneUseOnly": false + } + } + }, + "nodeList": { + "nodes": [ + { + "delta": { + "nodeXY6": { + "x": 1591, + "y": 1874 + } + }, + "attributes": { + "dElevation": 10 + } + }, + { + "delta": { + "nodeXY6": { + "x": -14, + "y": 346 + } + } + }, + { + "delta": { + "nodeXY6": { + "x": 0, + "y": 7 + } + } + } + ] + } + } + ] + } + } + ] + } + }, + "dataType": "us.dot.its.jpo.ode.plugin.j2735.J2735MAP" + } +} \ No newline at end of file diff --git a/jpo-deduplicator/src/test/resources/json/map/sample.map-reference.json b/jpo-deduplicator/src/test/resources/json/map/sample.map-reference.json new file mode 100644 index 0000000..e1a7a87 --- /dev/null +++ b/jpo-deduplicator/src/test/resources/json/map/sample.map-reference.json @@ -0,0 +1,2814 @@ +{ + "metadata": { + "logFileName": "", + "recordType": "mapTx", + "securityResultCode": "success", + "receivedMessageDetails": { + "rxSource": "NA" + }, + "payloadType": "us.dot.its.jpo.ode.model.OdeMapPayload", + "serialId": { + "streamId": "d963d421-fba0-4b21-b991-229e8d3bf9c1", + "bundleSize": 1, + "bundleId": 0, + "recordId": 0, + "serialNumber": 0 + }, + "odeReceivedAt": "2025-01-31T00:00:00.000Z", + "schemaVersion": 8, + "maxDurationTime": 0, + "recordGeneratedAt": "", + "recordGeneratedBy": "RSU", + "sanitized": false, + "odePacketID": "", + "odeTimStartDateTime": "", + "asn1": "001283C138003000205E9C014D3EAB092CA624B5518202DC3658042800000400023622C60CA009F66D48ABFAF81388D8AD18070027D9B2FFCFE9804F13667B1FFD009EC2C76E3FFC82C4E0001004B00C5000000800066C4574101813ECD8B757FAE027D9B30E6FF5604EC363561FE7809EC6CD69BFEC813C4D8A617FC9027D9B2147008604FB163666000016250000802580228000001000096229E1309B51A6FE4204DD361CF1FE5009F6018E1000096020A00000080004D88A57F84027D9B3827002804EC36087600A009F62C289407282C310001C0440188800000006C46DBE02813EC5816D800710052200000001B11B6FAD404FB16054A0000401C8800000006C47B3D24813EC5816D801B100C4200000000AF890F12C580007E87100D4200000008AF4C0F12C580077E7A2C0004000160002001CB028D000000800052C160BC40B5FFFD8A9409D86BFEBB5B40141457FEF53B76C008B467014145800080002BFFCBFFC82C6A0001804B024D000000800036C2213C3B013ECD80096D64027D9AFFD8CDFC04F635FF7983BC09F66C0082AA2014280B1B80006012C0B3400000100004B02BCF0F6D7FE065D602788B0138EB900B1240001012C083400000080009B0C2AF0B804FB15FE6DE171AFFF6C63E04EC15FE1DE670060E40002581EA8000004000135DA6DF0180A0A6ADC2C00D0143CD51897FDA028C8ABB25001A0B0680008012C105400000200009AEDBEFAE005053540EE003C0A326A9CF3FED8143C5667780010582C0004009608AA00000080004D76DE7EE402829ABA88FFDC050F354525FFF80A322BCF23FA602C690000C04B0395000000200016BB4FBD4E01414D3215800802940AB108FFF2030D2000110126200000001AEE5103BE050A15F6F1FFC8404D8800000006BB97C18E0142857DFA800010146200000001AEE89099A050A15F8720000B05DD000000800046BE3743B781428D80E1B00002879B00514B4404F63600827D8C09E22C000400015FFE6007016190000402582CE8000004000135ECEE1DE80A146C02E54758143CD8059AD3E027B1B00613DD004F102C360000804B055D000000200046BCC7C3C781428D80108C6E02829B002B2ECE050A16019A4B29B00AB5C3604F136004E410409EC018A10000960C3A00000080004D7DE9878602851B003923CC05053601623B440A0A6BFB8C3A5014140B0640005012C197400000100005AFE570EF2050A36003A47C80A0A6BFD2C45F014140B054000501101A8200000001B05A90EDC050535FFE605800A0A101B8200000001B08A30EC0050535FFE605300A0A101C8200000005B0C6F0EA4050515FFCA0568B0001000E", + "mapSource": "RSU", + "originIp": "8.8.8.8" + }, + "payload": { + "data": { + "msgIssueRevision": 0, + "layerType": "intersectionData", + "layerID": 0, + "intersections": { + "intersectionGeometry": [ + { + "id": { + "id": 12110 + }, + "revision": 0, + "refPoint": { + "latitude": 39.5952649, + "longitude": -105.0914122, + "elevation": 1677.0 + }, + "laneWidth": 366, + "laneSet": { + "GenericLane": [ + { + "laneID": 2, + "ingressApproach": 1, + "laneAttributes": { + "directionalUse": { + "ingressPath": true, + "egressPath": false + }, + "shareWith": { + "busVehicleTraffic": false, + "trackedVehicleTraffic": false, + "individualMotorizedVehicleTraffic": false, + "taxiVehicleTraffic": false, + "overlappingLaneDescriptionProvided": false, + "cyclistVehicleTraffic": false, + "otherNonMotorizedTrafficTypes": false, + "multipleLanesTreatedAsOneLane": false, + "pedestrianTraffic": false, + "pedestriansTraffic": false + }, + "laneType": { + "vehicle": { + "isVehicleRevocableLane": false, + "isVehicleFlyOverLane": false, + "permissionOnRequest": false, + "hasIRbeaconCoverage": false, + "restrictedToBusUse": false, + "restrictedToTaxiUse": false, + "restrictedFromPublicUse": false, + "hovLaneUseOnly": false + } + } + }, + "maneuvers": { + "maneuverStraightAllowed": true, + "maneuverNoStoppingAllowed": false, + "goWithHalt": false, + "maneuverLeftAllowed": false, + "maneuverUTurnAllowed": false, + "maneuverLeftTurnOnRedAllowed": false, + "reserved1": false, + "maneuverRightAllowed": false, + "maneuverLaneChangeAllowed": false, + "yieldAllwaysRequired": false, + "maneuverRightTurnOnRedAllowed": false, + "caution": false + }, + "nodeList": { + "nodes": [ + { + "delta": { + "nodeXY6": { + "x": 2225, + "y": 808 + } + }, + "attributes": { + "dElevation": -10 + } + }, + { + "delta": { + "nodeXY6": { + "x": 10517, + "y": -161 + } + }, + "attributes": { + "dElevation": -60 + } + }, + { + "delta": { + "nodeXY6": { + "x": 2769, + "y": 112 + } + }, + "attributes": { + "dElevation": -10 + } + }, + { + "delta": { + "nodeXY6": { + "x": 6142, + "y": -180 + } + }, + "attributes": { + "dElevation": -30 + } + }, + { + "delta": { + "nodeXY6": { + "x": 6636, + "y": -12 + } + }, + "attributes": { + "dElevation": -20 + } + }, + { + "delta": { + "nodeXY6": { + "x": 3804, + "y": -7 + } + } + } + ] + }, + "connectsTo": { + "connectsTo": [ + { + "connectingLane": { + "lane": 19, + "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": 4, + "connectionID": 1 + } + ] + } + }, + { + "laneID": 3, + "ingressApproach": 1, + "laneAttributes": { + "directionalUse": { + "ingressPath": true, + "egressPath": false + }, + "shareWith": { + "busVehicleTraffic": false, + "trackedVehicleTraffic": false, + "individualMotorizedVehicleTraffic": false, + "taxiVehicleTraffic": false, + "overlappingLaneDescriptionProvided": false, + "cyclistVehicleTraffic": false, + "otherNonMotorizedTrafficTypes": false, + "multipleLanesTreatedAsOneLane": false, + "pedestrianTraffic": false, + "pedestriansTraffic": false + }, + "laneType": { + "vehicle": { + "isVehicleRevocableLane": false, + "isVehicleFlyOverLane": false, + "permissionOnRequest": false, + "hasIRbeaconCoverage": false, + "restrictedToBusUse": false, + "restrictedToTaxiUse": false, + "restrictedFromPublicUse": false, + "hovLaneUseOnly": false + } + } + }, + "maneuvers": { + "maneuverStraightAllowed": true, + "maneuverNoStoppingAllowed": false, + "goWithHalt": false, + "maneuverLeftAllowed": false, + "maneuverUTurnAllowed": false, + "maneuverLeftTurnOnRedAllowed": false, + "reserved1": false, + "maneuverRightAllowed": false, + "maneuverLaneChangeAllowed": false, + "yieldAllwaysRequired": false, + "maneuverRightTurnOnRedAllowed": false, + "caution": false + }, + "nodeList": { + "nodes": [ + { + "delta": { + "nodeXY6": { + "x": 2222, + "y": 515 + } + }, + "attributes": { + "dElevation": -10 + } + }, + { + "delta": { + "nodeXY6": { + "x": 2933, + "y": -82 + } + }, + "attributes": { + "dElevation": -10 + } + }, + { + "delta": { + "nodeXY6": { + "x": 6259, + "y": -85 + } + }, + "attributes": { + "dElevation": -40 + } + }, + { + "delta": { + "nodeXY6": { + "x": 3416, + "y": -98 + } + }, + "attributes": { + "dElevation": -20 + } + }, + { + "delta": { + "nodeXY6": { + "x": 6867, + "y": -39 + } + }, + "attributes": { + "dElevation": -30 + } + }, + { + "delta": { + "nodeXY6": { + "x": 2657, + "y": -55 + } + }, + "attributes": { + "dElevation": -10 + } + }, + { + "delta": { + "nodeXY6": { + "x": 4259, + "y": 67 + } + }, + "attributes": { + "dElevation": -10 + } + }, + { + "delta": { + "nodeXY6": { + "x": 3481, + "y": 0 + } + } + } + ] + }, + "connectsTo": { + "connectsTo": [ + { + "connectingLane": { + "lane": 18, + "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": 4, + "connectionID": 1 + } + ] + } + }, + { + "laneID": 1, + "ingressApproach": 1, + "laneAttributes": { + "directionalUse": { + "ingressPath": true, + "egressPath": false + }, + "shareWith": { + "busVehicleTraffic": false, + "trackedVehicleTraffic": false, + "individualMotorizedVehicleTraffic": false, + "taxiVehicleTraffic": false, + "overlappingLaneDescriptionProvided": false, + "cyclistVehicleTraffic": false, + "otherNonMotorizedTrafficTypes": false, + "multipleLanesTreatedAsOneLane": false, + "pedestrianTraffic": false, + "pedestriansTraffic": false + }, + "laneType": { + "vehicle": { + "isVehicleRevocableLane": false, + "isVehicleFlyOverLane": false, + "permissionOnRequest": false, + "hasIRbeaconCoverage": false, + "restrictedToBusUse": false, + "restrictedToTaxiUse": false, + "restrictedFromPublicUse": false, + "hovLaneUseOnly": false + } + } + }, + "maneuvers": { + "maneuverStraightAllowed": false, + "maneuverNoStoppingAllowed": false, + "goWithHalt": false, + "maneuverLeftAllowed": false, + "maneuverUTurnAllowed": false, + "maneuverLeftTurnOnRedAllowed": false, + "reserved1": false, + "maneuverRightAllowed": true, + "maneuverLaneChangeAllowed": false, + "yieldAllwaysRequired": false, + "maneuverRightTurnOnRedAllowed": false, + "caution": false + }, + "nodeList": { + "nodes": [ + { + "delta": { + "nodeXY6": { + "x": 2215, + "y": 1218 + } + } + }, + { + "delta": { + "nodeXY6": { + "x": 10451, + "y": -223 + } + }, + "attributes": { + "dElevation": -70 + } + }, + { + "delta": { + "nodeXY6": { + "x": 1852, + "y": -108 + } + }, + "attributes": { + "dElevation": -10 + } + } + ] + }, + "connectsTo": { + "connectsTo": [ + { + "connectingLane": { + "lane": 28, + "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 + } + ] + } + }, + { + "laneID": 4, + "ingressApproach": 1, + "laneAttributes": { + "directionalUse": { + "ingressPath": true, + "egressPath": false + }, + "shareWith": { + "busVehicleTraffic": false, + "trackedVehicleTraffic": false, + "individualMotorizedVehicleTraffic": false, + "taxiVehicleTraffic": false, + "overlappingLaneDescriptionProvided": false, + "cyclistVehicleTraffic": false, + "otherNonMotorizedTrafficTypes": false, + "multipleLanesTreatedAsOneLane": false, + "pedestrianTraffic": false, + "pedestriansTraffic": false + }, + "laneType": { + "vehicle": { + "isVehicleRevocableLane": false, + "isVehicleFlyOverLane": false, + "permissionOnRequest": false, + "hasIRbeaconCoverage": false, + "restrictedToBusUse": false, + "restrictedToTaxiUse": false, + "restrictedFromPublicUse": false, + "hovLaneUseOnly": false + } + } + }, + "maneuvers": { + "maneuverStraightAllowed": false, + "maneuverNoStoppingAllowed": false, + "goWithHalt": false, + "maneuverLeftAllowed": true, + "maneuverUTurnAllowed": false, + "maneuverLeftTurnOnRedAllowed": false, + "reserved1": false, + "maneuverRightAllowed": false, + "maneuverLaneChangeAllowed": false, + "yieldAllwaysRequired": false, + "maneuverRightTurnOnRedAllowed": false, + "caution": false + }, + "nodeList": { + "nodes": [ + { + "delta": { + "nodeXY6": { + "x": 2213, + "y": -124 + } + }, + "attributes": { + "dElevation": -10 + } + }, + { + "delta": { + "nodeXY6": { + "x": 7187, + "y": 20 + } + }, + "attributes": { + "dElevation": -40 + } + }, + { + "delta": { + "nodeXY6": { + "x": 541, + "y": 40 + } + }, + "attributes": { + "dElevation": -10 + } + }, + { + "delta": { + "nodeXY6": { + "x": 1298, + "y": 229 + } + } + } + ] + }, + "connectsTo": { + "connectsTo": [ + { + "connectingLane": { + "lane": 12, + "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": 7, + "connectionID": 1 + } + ] + } + }, + { + "laneID": 6, + "egressApproach": 2, + "laneAttributes": { + "directionalUse": { + "ingressPath": false, + "egressPath": true + }, + "shareWith": { + "busVehicleTraffic": false, + "trackedVehicleTraffic": false, + "individualMotorizedVehicleTraffic": false, + "taxiVehicleTraffic": false, + "overlappingLaneDescriptionProvided": false, + "cyclistVehicleTraffic": false, + "otherNonMotorizedTrafficTypes": false, + "multipleLanesTreatedAsOneLane": false, + "pedestrianTraffic": false, + "pedestriansTraffic": false + }, + "laneType": { + "vehicle": { + "isVehicleRevocableLane": false, + "isVehicleFlyOverLane": false, + "permissionOnRequest": false, + "hasIRbeaconCoverage": false, + "restrictedToBusUse": false, + "restrictedToTaxiUse": false, + "restrictedFromPublicUse": false, + "hovLaneUseOnly": false + } + } + }, + "nodeList": { + "nodes": [ + { + "delta": { + "nodeXY6": { + "x": 2267, + "y": -1019 + } + }, + "attributes": { + "dElevation": -10 + } + }, + { + "delta": { + "nodeXY6": { + "x": 365, + "y": 7 + } + } + } + ] + } + }, + { + "laneID": 5, + "egressApproach": 2, + "laneAttributes": { + "directionalUse": { + "ingressPath": false, + "egressPath": true + }, + "shareWith": { + "busVehicleTraffic": false, + "trackedVehicleTraffic": false, + "individualMotorizedVehicleTraffic": false, + "taxiVehicleTraffic": false, + "overlappingLaneDescriptionProvided": false, + "cyclistVehicleTraffic": false, + "otherNonMotorizedTrafficTypes": false, + "multipleLanesTreatedAsOneLane": false, + "pedestrianTraffic": false, + "pedestriansTraffic": false + }, + "laneType": { + "vehicle": { + "isVehicleRevocableLane": false, + "isVehicleFlyOverLane": false, + "permissionOnRequest": false, + "hasIRbeaconCoverage": false, + "restrictedToBusUse": false, + "restrictedToTaxiUse": false, + "restrictedFromPublicUse": false, + "hovLaneUseOnly": false + } + } + }, + "nodeList": { + "nodes": [ + { + "delta": { + "nodeXY6": { + "x": 2267, + "y": -662 + } + }, + "attributes": { + "dElevation": -10 + } + }, + { + "delta": { + "nodeXY6": { + "x": 338, + "y": 0 + } + } + } + ] + } + }, + { + "laneID": 7, + "egressApproach": 2, + "laneAttributes": { + "directionalUse": { + "ingressPath": false, + "egressPath": true + }, + "shareWith": { + "busVehicleTraffic": false, + "trackedVehicleTraffic": false, + "individualMotorizedVehicleTraffic": false, + "taxiVehicleTraffic": false, + "overlappingLaneDescriptionProvided": false, + "cyclistVehicleTraffic": false, + "otherNonMotorizedTrafficTypes": false, + "multipleLanesTreatedAsOneLane": false, + "pedestrianTraffic": false, + "pedestriansTraffic": false + }, + "laneType": { + "vehicle": { + "isVehicleRevocableLane": false, + "isVehicleFlyOverLane": false, + "permissionOnRequest": false, + "hasIRbeaconCoverage": false, + "restrictedToBusUse": false, + "restrictedToTaxiUse": false, + "restrictedFromPublicUse": false, + "hovLaneUseOnly": false + } + } + }, + "nodeList": { + "nodes": [ + { + "delta": { + "nodeXY6": { + "x": 2294, + "y": -1463 + } + }, + "attributes": { + "dElevation": -10 + } + }, + { + "delta": { + "nodeXY6": { + "x": 365, + "y": 27 + } + } + } + ] + } + }, + { + "laneID": 12, + "egressApproach": 4, + "laneAttributes": { + "directionalUse": { + "ingressPath": false, + "egressPath": true + }, + "shareWith": { + "busVehicleTraffic": false, + "trackedVehicleTraffic": false, + "individualMotorizedVehicleTraffic": false, + "taxiVehicleTraffic": false, + "overlappingLaneDescriptionProvided": false, + "cyclistVehicleTraffic": false, + "otherNonMotorizedTrafficTypes": false, + "multipleLanesTreatedAsOneLane": false, + "pedestrianTraffic": false, + "pedestriansTraffic": false + }, + "laneType": { + "vehicle": { + "isVehicleRevocableLane": false, + "isVehicleFlyOverLane": false, + "permissionOnRequest": false, + "hasIRbeaconCoverage": false, + "restrictedToBusUse": false, + "restrictedToTaxiUse": false, + "restrictedFromPublicUse": false, + "hovLaneUseOnly": false + } + } + }, + "nodeList": { + "nodes": [ + { + "delta": { + "nodeXY6": { + "x": -952, + "y": -1898 + } + } + }, + { + "delta": { + "nodeXY6": { + "x": 0, + "y": -377 + } + } + } + ] + } + }, + { + "laneID": 13, + "egressApproach": 4, + "laneAttributes": { + "directionalUse": { + "ingressPath": false, + "egressPath": true + }, + "shareWith": { + "busVehicleTraffic": false, + "trackedVehicleTraffic": false, + "individualMotorizedVehicleTraffic": false, + "taxiVehicleTraffic": false, + "overlappingLaneDescriptionProvided": false, + "cyclistVehicleTraffic": false, + "otherNonMotorizedTrafficTypes": false, + "multipleLanesTreatedAsOneLane": false, + "pedestrianTraffic": false, + "pedestriansTraffic": false + }, + "laneType": { + "vehicle": { + "isVehicleRevocableLane": false, + "isVehicleFlyOverLane": false, + "permissionOnRequest": false, + "hasIRbeaconCoverage": false, + "restrictedToBusUse": false, + "restrictedToTaxiUse": false, + "restrictedFromPublicUse": false, + "hovLaneUseOnly": false + } + } + }, + "nodeList": { + "nodes": [ + { + "delta": { + "nodeXY6": { + "x": -1440, + "y": -1898 + } + } + }, + { + "delta": { + "nodeXY6": { + "x": 7, + "y": -390 + } + } + }, + { + "delta": { + "nodeXY6": { + "x": 0, + "y": 0 + } + } + }, + { + "delta": { + "nodeXY6": { + "x": 0, + "y": 7 + } + } + } + ] + } + }, + { + "laneID": 10, + "ingressApproach": 3, + "laneAttributes": { + "directionalUse": { + "ingressPath": true, + "egressPath": false + }, + "shareWith": { + "busVehicleTraffic": false, + "trackedVehicleTraffic": false, + "individualMotorizedVehicleTraffic": false, + "taxiVehicleTraffic": false, + "overlappingLaneDescriptionProvided": false, + "cyclistVehicleTraffic": false, + "otherNonMotorizedTrafficTypes": false, + "multipleLanesTreatedAsOneLane": false, + "pedestrianTraffic": false, + "pedestriansTraffic": false + }, + "laneType": { + "vehicle": { + "isVehicleRevocableLane": false, + "isVehicleFlyOverLane": false, + "permissionOnRequest": false, + "hasIRbeaconCoverage": false, + "restrictedToBusUse": false, + "restrictedToTaxiUse": false, + "restrictedFromPublicUse": false, + "hovLaneUseOnly": false + } + } + }, + "maneuvers": { + "maneuverStraightAllowed": true, + "maneuverNoStoppingAllowed": false, + "goWithHalt": false, + "maneuverLeftAllowed": false, + "maneuverUTurnAllowed": false, + "maneuverLeftTurnOnRedAllowed": false, + "reserved1": false, + "maneuverRightAllowed": false, + "maneuverLaneChangeAllowed": false, + "yieldAllwaysRequired": false, + "maneuverRightTurnOnRedAllowed": false, + "caution": false + }, + "nodeList": { + "nodes": [ + { + "delta": { + "nodeXY6": { + "x": 705, + "y": -1919 + } + } + }, + { + "delta": { + "nodeXY6": { + "x": -1, + "y": -7515 + } + }, + "attributes": { + "dElevation": -40 + } + }, + { + "delta": { + "nodeXY6": { + "x": -41, + "y": -5272 + } + }, + "attributes": { + "dElevation": 10 + } + }, + { + "delta": { + "nodeXY6": { + "x": -17, + "y": -11337 + } + } + }, + { + "delta": { + "nodeXY6": { + "x": 17, + "y": -5938 + } + }, + "attributes": { + "dElevation": 10 + } + }, + { + "delta": { + "nodeXY6": { + "x": 0, + "y": 0 + } + } + }, + { + "delta": { + "nodeXY6": { + "x": -7, + "y": -7 + } + } + } + ] + }, + "connectsTo": { + "connectsTo": [ + { + "connectingLane": { + "lane": 26, + "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 + } + ] + } + }, + { + "laneID": 9, + "ingressApproach": 3, + "laneAttributes": { + "directionalUse": { + "ingressPath": true, + "egressPath": false + }, + "shareWith": { + "busVehicleTraffic": false, + "trackedVehicleTraffic": false, + "individualMotorizedVehicleTraffic": false, + "taxiVehicleTraffic": false, + "overlappingLaneDescriptionProvided": false, + "cyclistVehicleTraffic": false, + "otherNonMotorizedTrafficTypes": false, + "multipleLanesTreatedAsOneLane": false, + "pedestrianTraffic": false, + "pedestriansTraffic": false + }, + "laneType": { + "vehicle": { + "isVehicleRevocableLane": false, + "isVehicleFlyOverLane": false, + "permissionOnRequest": false, + "hasIRbeaconCoverage": false, + "restrictedToBusUse": false, + "restrictedToTaxiUse": false, + "restrictedFromPublicUse": false, + "hovLaneUseOnly": false + } + } + }, + "maneuvers": { + "maneuverStraightAllowed": true, + "maneuverNoStoppingAllowed": false, + "goWithHalt": false, + "maneuverLeftAllowed": false, + "maneuverUTurnAllowed": false, + "maneuverLeftTurnOnRedAllowed": false, + "reserved1": false, + "maneuverRightAllowed": false, + "maneuverLaneChangeAllowed": false, + "yieldAllwaysRequired": false, + "maneuverRightTurnOnRedAllowed": false, + "caution": false + }, + "nodeList": { + "nodes": [ + { + "delta": { + "nodeXY6": { + "x": 1090, + "y": -1930 + } + }, + "attributes": { + "dElevation": -10 + } + }, + { + "delta": { + "nodeXY6": { + "x": 9, + "y": -4764 + } + }, + "attributes": { + "dElevation": -10 + } + }, + { + "delta": { + "nodeXY6": { + "x": -20, + "y": -6402 + } + }, + "attributes": { + "dElevation": -20 + } + }, + { + "delta": { + "nodeXY6": { + "x": -34, + "y": -7953 + } + }, + "attributes": { + "dElevation": -10 + } + }, + { + "delta": { + "nodeXY6": { + "x": 16, + "y": -10940 + } + }, + "attributes": { + "dElevation": 20 + } + } + ] + }, + "connectsTo": { + "connectsTo": [ + { + "connectingLane": { + "lane": 27, + "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 + } + ] + } + }, + { + "laneID": 11, + "ingressApproach": 3, + "laneAttributes": { + "directionalUse": { + "ingressPath": true, + "egressPath": false + }, + "shareWith": { + "busVehicleTraffic": false, + "trackedVehicleTraffic": false, + "individualMotorizedVehicleTraffic": false, + "taxiVehicleTraffic": false, + "overlappingLaneDescriptionProvided": false, + "cyclistVehicleTraffic": false, + "otherNonMotorizedTrafficTypes": false, + "multipleLanesTreatedAsOneLane": false, + "pedestrianTraffic": false, + "pedestriansTraffic": false + }, + "laneType": { + "vehicle": { + "isVehicleRevocableLane": false, + "isVehicleFlyOverLane": false, + "permissionOnRequest": false, + "hasIRbeaconCoverage": false, + "restrictedToBusUse": false, + "restrictedToTaxiUse": false, + "restrictedFromPublicUse": false, + "hovLaneUseOnly": false + } + } + }, + "maneuvers": { + "maneuverStraightAllowed": false, + "maneuverNoStoppingAllowed": false, + "goWithHalt": false, + "maneuverLeftAllowed": true, + "maneuverUTurnAllowed": false, + "maneuverLeftTurnOnRedAllowed": false, + "reserved1": false, + "maneuverRightAllowed": false, + "maneuverLaneChangeAllowed": false, + "yieldAllwaysRequired": false, + "maneuverRightTurnOnRedAllowed": false, + "caution": false + }, + "nodeList": { + "nodes": [ + { + "delta": { + "nodeXY6": { + "x": 350, + "y": -1925 + } + } + }, + { + "delta": { + "nodeXY6": { + "x": -32, + "y": -6698 + } + }, + "attributes": { + "dElevation": -30 + } + }, + { + "delta": { + "nodeXY6": { + "x": 156, + "y": -2616 + } + } + } + ] + }, + "connectsTo": { + "connectsTo": [ + { + "connectingLane": { + "lane": 18, + "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": 1, + "connectionID": 1 + } + ] + } + }, + { + "laneID": 8, + "ingressApproach": 3, + "laneAttributes": { + "directionalUse": { + "ingressPath": true, + "egressPath": false + }, + "shareWith": { + "busVehicleTraffic": false, + "trackedVehicleTraffic": false, + "individualMotorizedVehicleTraffic": false, + "taxiVehicleTraffic": false, + "overlappingLaneDescriptionProvided": false, + "cyclistVehicleTraffic": false, + "otherNonMotorizedTrafficTypes": false, + "multipleLanesTreatedAsOneLane": false, + "pedestrianTraffic": false, + "pedestriansTraffic": false + }, + "laneType": { + "vehicle": { + "isVehicleRevocableLane": false, + "isVehicleFlyOverLane": false, + "permissionOnRequest": false, + "hasIRbeaconCoverage": false, + "restrictedToBusUse": false, + "restrictedToTaxiUse": false, + "restrictedFromPublicUse": false, + "hovLaneUseOnly": false + } + } + }, + "maneuvers": { + "maneuverStraightAllowed": false, + "maneuverNoStoppingAllowed": false, + "goWithHalt": false, + "maneuverLeftAllowed": false, + "maneuverUTurnAllowed": false, + "maneuverLeftTurnOnRedAllowed": false, + "reserved1": false, + "maneuverRightAllowed": true, + "maneuverLaneChangeAllowed": false, + "yieldAllwaysRequired": false, + "maneuverRightTurnOnRedAllowed": false, + "caution": false + }, + "nodeList": { + "nodes": [ + { + "delta": { + "nodeXY6": { + "x": 1557, + "y": -1956 + } + }, + "attributes": { + "dElevation": -10 + } + }, + { + "delta": { + "nodeXY6": { + "x": -101, + "y": -1956 + } + } + }, + { + "delta": { + "nodeXY6": { + "x": -5, + "y": -7393 + } + }, + "attributes": { + "dElevation": -40 + } + }, + { + "delta": { + "nodeXY6": { + "x": -121, + "y": -1636 + } + } + } + ] + }, + "connectsTo": { + "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 + } + }, + "connectionID": 1 + } + ] + } + }, + { + "laneID": 15, + "ingressApproach": 5, + "laneAttributes": { + "directionalUse": { + "ingressPath": true, + "egressPath": false + }, + "shareWith": { + "busVehicleTraffic": false, + "trackedVehicleTraffic": false, + "individualMotorizedVehicleTraffic": false, + "taxiVehicleTraffic": false, + "overlappingLaneDescriptionProvided": false, + "cyclistVehicleTraffic": false, + "otherNonMotorizedTrafficTypes": false, + "multipleLanesTreatedAsOneLane": false, + "pedestrianTraffic": false, + "pedestriansTraffic": false + }, + "laneType": { + "vehicle": { + "isVehicleRevocableLane": false, + "isVehicleFlyOverLane": false, + "permissionOnRequest": false, + "hasIRbeaconCoverage": false, + "restrictedToBusUse": false, + "restrictedToTaxiUse": false, + "restrictedFromPublicUse": false, + "hovLaneUseOnly": false + } + } + }, + "maneuvers": { + "maneuverStraightAllowed": true, + "maneuverNoStoppingAllowed": false, + "goWithHalt": false, + "maneuverLeftAllowed": false, + "maneuverUTurnAllowed": false, + "maneuverLeftTurnOnRedAllowed": false, + "reserved1": false, + "maneuverRightAllowed": false, + "maneuverLaneChangeAllowed": false, + "yieldAllwaysRequired": false, + "maneuverRightTurnOnRedAllowed": false, + "caution": false + }, + "nodeList": { + "nodes": [ + { + "delta": { + "nodeXY6": { + "x": -2405, + "y": -1018 + } + }, + "attributes": { + "dElevation": 10 + } + }, + { + "delta": { + "nodeXY6": { + "x": -9339, + "y": 26 + } + }, + "attributes": { + "dElevation": 30 + } + }, + { + "delta": { + "nodeXY6": { + "x": -11895, + "y": -38 + } + }, + "attributes": { + "dElevation": 50 + } + }, + { + "delta": { + "nodeXY6": { + "x": -8814, + "y": 13 + } + } + } + ] + }, + "connectsTo": { + "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 + } + }, + "signalGroup": 8, + "connectionID": 1 + } + ] + } + }, + { + "laneID": 16, + "ingressApproach": 5, + "laneAttributes": { + "directionalUse": { + "ingressPath": true, + "egressPath": false + }, + "shareWith": { + "busVehicleTraffic": false, + "trackedVehicleTraffic": false, + "individualMotorizedVehicleTraffic": false, + "taxiVehicleTraffic": false, + "overlappingLaneDescriptionProvided": false, + "cyclistVehicleTraffic": false, + "otherNonMotorizedTrafficTypes": false, + "multipleLanesTreatedAsOneLane": false, + "pedestrianTraffic": false, + "pedestriansTraffic": false + }, + "laneType": { + "vehicle": { + "isVehicleRevocableLane": false, + "isVehicleFlyOverLane": false, + "permissionOnRequest": false, + "hasIRbeaconCoverage": false, + "restrictedToBusUse": false, + "restrictedToTaxiUse": false, + "restrictedFromPublicUse": false, + "hovLaneUseOnly": false + } + } + }, + "maneuvers": { + "maneuverStraightAllowed": true, + "maneuverNoStoppingAllowed": false, + "goWithHalt": false, + "maneuverLeftAllowed": false, + "maneuverUTurnAllowed": false, + "maneuverLeftTurnOnRedAllowed": false, + "reserved1": false, + "maneuverRightAllowed": false, + "maneuverLaneChangeAllowed": false, + "yieldAllwaysRequired": false, + "maneuverRightTurnOnRedAllowed": false, + "caution": false + }, + "nodeList": { + "nodes": [ + { + "delta": { + "nodeXY6": { + "x": -2337, + "y": -656 + } + }, + "attributes": { + "dElevation": 10 + } + }, + { + "delta": { + "nodeXY6": { + "x": -12229, + "y": 15 + } + }, + "attributes": { + "dElevation": 50 + } + }, + { + "delta": { + "nodeXY6": { + "x": -11362, + "y": -37 + } + }, + "attributes": { + "dElevation": 30 + } + }, + { + "delta": { + "nodeXY6": { + "x": -6537, + "y": 1 + } + } + } + ] + }, + "connectsTo": { + "connectsTo": [ + { + "connectingLane": { + "lane": 5, + "maneuver": { + "maneuverStraightAllowed": true, + "maneuverNoStoppingAllowed": false, + "goWithHalt": false, + "maneuverLeftAllowed": false, + "maneuverUTurnAllowed": false, + "maneuverLeftTurnOnRedAllowed": false, + "reserved1": false, + "maneuverRightAllowed": false, + "maneuverLaneChangeAllowed": false, + "yieldAllwaysRequired": false, + "maneuverRightTurnOnRedAllowed": false, + "caution": false + } + }, + "signalGroup": 8, + "connectionID": 1 + } + ] + } + }, + { + "laneID": 17, + "ingressApproach": 5, + "laneAttributes": { + "directionalUse": { + "ingressPath": true, + "egressPath": false + }, + "shareWith": { + "busVehicleTraffic": false, + "trackedVehicleTraffic": false, + "individualMotorizedVehicleTraffic": false, + "taxiVehicleTraffic": false, + "overlappingLaneDescriptionProvided": false, + "cyclistVehicleTraffic": false, + "otherNonMotorizedTrafficTypes": false, + "multipleLanesTreatedAsOneLane": false, + "pedestrianTraffic": false, + "pedestriansTraffic": false + }, + "laneType": { + "vehicle": { + "isVehicleRevocableLane": false, + "isVehicleFlyOverLane": false, + "permissionOnRequest": false, + "hasIRbeaconCoverage": false, + "restrictedToBusUse": false, + "restrictedToTaxiUse": false, + "restrictedFromPublicUse": false, + "hovLaneUseOnly": false + } + } + }, + "maneuvers": { + "maneuverStraightAllowed": false, + "maneuverNoStoppingAllowed": false, + "goWithHalt": false, + "maneuverLeftAllowed": true, + "maneuverUTurnAllowed": false, + "maneuverLeftTurnOnRedAllowed": false, + "reserved1": false, + "maneuverRightAllowed": false, + "maneuverLaneChangeAllowed": false, + "yieldAllwaysRequired": false, + "maneuverRightTurnOnRedAllowed": false, + "caution": false + }, + "nodeList": { + "nodes": [ + { + "delta": { + "nodeXY6": { + "x": -2338, + "y": -284 + } + }, + "attributes": { + "dElevation": 10 + } + }, + { + "delta": { + "nodeXY6": { + "x": -8892, + "y": -18 + } + }, + "attributes": { + "dElevation": 30 + } + }, + { + "delta": { + "nodeXY6": { + "x": -11959, + "y": -2 + } + }, + "attributes": { + "dElevation": 50 + } + }, + { + "delta": { + "nodeXY6": { + "x": -1564, + "y": -180 + } + } + } + ] + }, + "connectsTo": { + "connectsTo": [ + { + "connectingLane": { + "lane": 26, + "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": 3, + "connectionID": 1 + } + ] + } + }, + { + "laneID": 14, + "ingressApproach": 5, + "laneAttributes": { + "directionalUse": { + "ingressPath": true, + "egressPath": false + }, + "shareWith": { + "busVehicleTraffic": false, + "trackedVehicleTraffic": false, + "individualMotorizedVehicleTraffic": false, + "taxiVehicleTraffic": false, + "overlappingLaneDescriptionProvided": false, + "cyclistVehicleTraffic": false, + "otherNonMotorizedTrafficTypes": false, + "multipleLanesTreatedAsOneLane": false, + "pedestrianTraffic": false, + "pedestriansTraffic": false + }, + "laneType": { + "vehicle": { + "isVehicleRevocableLane": false, + "isVehicleFlyOverLane": false, + "permissionOnRequest": false, + "hasIRbeaconCoverage": false, + "restrictedToBusUse": false, + "restrictedToTaxiUse": false, + "restrictedFromPublicUse": false, + "hovLaneUseOnly": false + } + } + }, + "maneuvers": { + "maneuverStraightAllowed": false, + "maneuverNoStoppingAllowed": false, + "goWithHalt": false, + "maneuverLeftAllowed": false, + "maneuverUTurnAllowed": false, + "maneuverLeftTurnOnRedAllowed": false, + "reserved1": false, + "maneuverRightAllowed": true, + "maneuverLaneChangeAllowed": false, + "yieldAllwaysRequired": false, + "maneuverRightTurnOnRedAllowed": false, + "caution": false + }, + "nodeList": { + "nodes": [ + { + "delta": { + "nodeXY6": { + "x": -2401, + "y": -1380 + } + }, + "attributes": { + "dElevation": 10 + } + }, + { + "delta": { + "nodeXY6": { + "x": -19947, + "y": 8 + } + }, + "attributes": { + "dElevation": 80 + } + }, + { + "delta": { + "nodeXY6": { + "x": -10108, + "y": -7 + } + } + } + ] + }, + "connectsTo": { + "connectsTo": [ + { + "connectingLane": { + "lane": 13, + "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 + } + ] + } + }, + { + "laneID": 18, + "egressApproach": 6, + "laneAttributes": { + "directionalUse": { + "ingressPath": false, + "egressPath": true + }, + "shareWith": { + "busVehicleTraffic": false, + "trackedVehicleTraffic": false, + "individualMotorizedVehicleTraffic": false, + "taxiVehicleTraffic": false, + "overlappingLaneDescriptionProvided": false, + "cyclistVehicleTraffic": false, + "otherNonMotorizedTrafficTypes": false, + "multipleLanesTreatedAsOneLane": false, + "pedestrianTraffic": false, + "pedestriansTraffic": false + }, + "laneType": { + "vehicle": { + "isVehicleRevocableLane": false, + "isVehicleFlyOverLane": false, + "permissionOnRequest": false, + "hasIRbeaconCoverage": false, + "restrictedToBusUse": false, + "restrictedToTaxiUse": false, + "restrictedFromPublicUse": false, + "hovLaneUseOnly": false + } + } + }, + "nodeList": { + "nodes": [ + { + "delta": { + "nodeXY6": { + "x": -2264, + "y": 479 + } + }, + "attributes": { + "dElevation": 20 + } + }, + { + "delta": { + "nodeXY6": { + "x": -580, + "y": -14 + } + } + } + ] + } + }, + { + "laneID": 19, + "egressApproach": 6, + "laneAttributes": { + "directionalUse": { + "ingressPath": false, + "egressPath": true + }, + "shareWith": { + "busVehicleTraffic": false, + "trackedVehicleTraffic": false, + "individualMotorizedVehicleTraffic": false, + "taxiVehicleTraffic": false, + "overlappingLaneDescriptionProvided": false, + "cyclistVehicleTraffic": false, + "otherNonMotorizedTrafficTypes": false, + "multipleLanesTreatedAsOneLane": false, + "pedestrianTraffic": false, + "pedestriansTraffic": false + }, + "laneType": { + "vehicle": { + "isVehicleRevocableLane": false, + "isVehicleFlyOverLane": false, + "permissionOnRequest": false, + "hasIRbeaconCoverage": false, + "restrictedToBusUse": false, + "restrictedToTaxiUse": false, + "restrictedFromPublicUse": false, + "hovLaneUseOnly": false + } + } + }, + "nodeList": { + "nodes": [ + { + "delta": { + "nodeXY6": { + "x": -2257, + "y": 796 + } + }, + "attributes": { + "dElevation": 20 + } + }, + { + "delta": { + "nodeXY6": { + "x": -518, + "y": 0 + } + } + } + ] + } + }, + { + "laneID": 20, + "egressApproach": 6, + "laneAttributes": { + "directionalUse": { + "ingressPath": false, + "egressPath": true + }, + "shareWith": { + "busVehicleTraffic": false, + "trackedVehicleTraffic": false, + "individualMotorizedVehicleTraffic": false, + "taxiVehicleTraffic": false, + "overlappingLaneDescriptionProvided": false, + "cyclistVehicleTraffic": false, + "otherNonMotorizedTrafficTypes": false, + "multipleLanesTreatedAsOneLane": false, + "pedestrianTraffic": false, + "pedestriansTraffic": false + }, + "laneType": { + "vehicle": { + "isVehicleRevocableLane": false, + "isVehicleFlyOverLane": false, + "permissionOnRequest": false, + "hasIRbeaconCoverage": false, + "restrictedToBusUse": false, + "restrictedToTaxiUse": false, + "restrictedFromPublicUse": false, + "hovLaneUseOnly": false + } + } + }, + "nodeList": { + "nodes": [ + { + "delta": { + "nodeXY6": { + "x": -2236, + "y": 1229 + } + }, + "attributes": { + "dElevation": 20 + } + }, + { + "delta": { + "nodeXY6": { + "x": -484, + "y": 0 + } + } + } + ] + } + }, + { + "laneID": 23, + "ingressApproach": 7, + "laneAttributes": { + "directionalUse": { + "ingressPath": true, + "egressPath": false + }, + "shareWith": { + "busVehicleTraffic": false, + "trackedVehicleTraffic": false, + "individualMotorizedVehicleTraffic": false, + "taxiVehicleTraffic": false, + "overlappingLaneDescriptionProvided": false, + "cyclistVehicleTraffic": false, + "otherNonMotorizedTrafficTypes": false, + "multipleLanesTreatedAsOneLane": false, + "pedestrianTraffic": false, + "pedestriansTraffic": false + }, + "laneType": { + "vehicle": { + "isVehicleRevocableLane": false, + "isVehicleFlyOverLane": false, + "permissionOnRequest": false, + "hasIRbeaconCoverage": false, + "restrictedToBusUse": false, + "restrictedToTaxiUse": false, + "restrictedFromPublicUse": false, + "hovLaneUseOnly": false + } + } + }, + "maneuvers": { + "maneuverStraightAllowed": true, + "maneuverNoStoppingAllowed": false, + "goWithHalt": false, + "maneuverLeftAllowed": false, + "maneuverUTurnAllowed": false, + "maneuverLeftTurnOnRedAllowed": false, + "reserved1": false, + "maneuverRightAllowed": false, + "maneuverLaneChangeAllowed": false, + "yieldAllwaysRequired": false, + "maneuverRightTurnOnRedAllowed": false, + "caution": false + }, + "nodeList": { + "nodes": [ + { + "delta": { + "nodeXY6": { + "x": -914, + "y": 1903 + } + }, + "attributes": { + "dElevation": 20 + } + }, + { + "delta": { + "nodeXY6": { + "x": 225, + "y": 12288 + } + }, + "attributes": { + "dElevation": 30 + } + }, + { + "delta": { + "nodeXY6": { + "x": 40, + "y": 9634 + } + }, + "attributes": { + "dElevation": -20 + } + }, + { + "delta": { + "nodeXY6": { + "x": 32, + "y": 8035 + } + }, + "attributes": { + "dElevation": -30 + } + }, + { + "delta": { + "nodeXY6": { + "x": 0, + "y": 0 + } + } + }, + { + "delta": { + "nodeXY6": { + "x": -7, + "y": 28 + } + } + } + ] + }, + "connectsTo": { + "connectsTo": [ + { + "connectingLane": { + "lane": 12, + "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 + } + ] + } + }, + { + "laneID": 22, + "ingressApproach": 7, + "laneAttributes": { + "directionalUse": { + "ingressPath": true, + "egressPath": false + }, + "shareWith": { + "busVehicleTraffic": false, + "trackedVehicleTraffic": false, + "individualMotorizedVehicleTraffic": false, + "taxiVehicleTraffic": false, + "overlappingLaneDescriptionProvided": false, + "cyclistVehicleTraffic": false, + "otherNonMotorizedTrafficTypes": false, + "multipleLanesTreatedAsOneLane": false, + "pedestrianTraffic": false, + "pedestriansTraffic": false + }, + "laneType": { + "vehicle": { + "isVehicleRevocableLane": false, + "isVehicleFlyOverLane": false, + "permissionOnRequest": false, + "hasIRbeaconCoverage": false, + "restrictedToBusUse": false, + "restrictedToTaxiUse": false, + "restrictedFromPublicUse": false, + "hovLaneUseOnly": false + } + } + }, + "maneuvers": { + "maneuverStraightAllowed": true, + "maneuverNoStoppingAllowed": false, + "goWithHalt": false, + "maneuverLeftAllowed": false, + "maneuverUTurnAllowed": false, + "maneuverLeftTurnOnRedAllowed": false, + "reserved1": false, + "maneuverRightAllowed": false, + "maneuverLaneChangeAllowed": false, + "yieldAllwaysRequired": false, + "maneuverRightTurnOnRedAllowed": false, + "caution": false + }, + "nodeList": { + "nodes": [ + { + "delta": { + "nodeXY6": { + "x": -1221, + "y": 1914 + } + }, + "attributes": { + "dElevation": 20 + } + }, + { + "delta": { + "nodeXY6": { + "x": 92, + "y": 10475 + } + }, + "attributes": { + "dElevation": 30 + } + }, + { + "delta": { + "nodeXY6": { + "x": 89, + "y": 11582 + } + }, + "attributes": { + "dElevation": -20 + } + }, + { + "delta": { + "nodeXY6": { + "x": 48, + "y": 7912 + } + }, + "attributes": { + "dElevation": -30 + } + } + ] + }, + "connectsTo": { + "connectsTo": [ + { + "connectingLane": { + "lane": 13, + "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 + } + ] + } + }, + { + "laneID": 21, + "ingressApproach": 7, + "laneAttributes": { + "directionalUse": { + "ingressPath": true, + "egressPath": false + }, + "shareWith": { + "busVehicleTraffic": false, + "trackedVehicleTraffic": false, + "individualMotorizedVehicleTraffic": false, + "taxiVehicleTraffic": false, + "overlappingLaneDescriptionProvided": false, + "cyclistVehicleTraffic": false, + "otherNonMotorizedTrafficTypes": false, + "multipleLanesTreatedAsOneLane": false, + "pedestrianTraffic": false, + "pedestriansTraffic": false + }, + "laneType": { + "vehicle": { + "isVehicleRevocableLane": false, + "isVehicleFlyOverLane": false, + "permissionOnRequest": false, + "hasIRbeaconCoverage": false, + "restrictedToBusUse": false, + "restrictedToTaxiUse": false, + "restrictedFromPublicUse": false, + "hovLaneUseOnly": false + } + } + }, + "maneuvers": { + "maneuverStraightAllowed": false, + "maneuverNoStoppingAllowed": false, + "goWithHalt": false, + "maneuverLeftAllowed": false, + "maneuverUTurnAllowed": false, + "maneuverLeftTurnOnRedAllowed": false, + "reserved1": false, + "maneuverRightAllowed": true, + "maneuverLaneChangeAllowed": false, + "yieldAllwaysRequired": false, + "maneuverRightTurnOnRedAllowed": false, + "caution": false + }, + "nodeList": { + "nodes": [ + { + "delta": { + "nodeXY6": { + "x": -1649, + "y": 1935 + } + }, + "attributes": { + "dElevation": 20 + } + }, + { + "delta": { + "nodeXY6": { + "x": 16, + "y": 3182 + } + }, + "attributes": { + "dElevation": 10 + } + }, + { + "delta": { + "nodeXY6": { + "x": 21, + "y": 5991 + } + }, + "attributes": { + "dElevation": 20 + } + }, + { + "delta": { + "nodeXY6": { + "x": 102, + "y": 4810 + } + } + }, + { + "delta": { + "nodeXY6": { + "x": 85, + "y": 11803 + } + }, + "attributes": { + "dElevation": -30 + } + }, + { + "delta": { + "nodeXY6": { + "x": 19, + "y": 4161 + } + }, + "attributes": { + "dElevation": -20 + } + } + ] + }, + "connectsTo": { + "connectsTo": [ + { + "connectingLane": { + "lane": 20, + "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 + } + ] + } + }, + { + "laneID": 24, + "ingressApproach": 7, + "laneAttributes": { + "directionalUse": { + "ingressPath": true, + "egressPath": false + }, + "shareWith": { + "busVehicleTraffic": false, + "trackedVehicleTraffic": false, + "individualMotorizedVehicleTraffic": false, + "taxiVehicleTraffic": false, + "overlappingLaneDescriptionProvided": false, + "cyclistVehicleTraffic": false, + "otherNonMotorizedTrafficTypes": false, + "multipleLanesTreatedAsOneLane": false, + "pedestrianTraffic": false, + "pedestriansTraffic": false + }, + "laneType": { + "vehicle": { + "isVehicleRevocableLane": false, + "isVehicleFlyOverLane": false, + "permissionOnRequest": false, + "hasIRbeaconCoverage": false, + "restrictedToBusUse": false, + "restrictedToTaxiUse": false, + "restrictedFromPublicUse": false, + "hovLaneUseOnly": false + } + } + }, + "maneuvers": { + "maneuverStraightAllowed": false, + "maneuverNoStoppingAllowed": false, + "goWithHalt": false, + "maneuverLeftAllowed": true, + "maneuverUTurnAllowed": false, + "maneuverLeftTurnOnRedAllowed": false, + "reserved1": false, + "maneuverRightAllowed": false, + "maneuverLaneChangeAllowed": false, + "yieldAllwaysRequired": false, + "maneuverRightTurnOnRedAllowed": false, + "caution": false + }, + "nodeList": { + "nodes": [ + { + "delta": { + "nodeXY6": { + "x": -535, + "y": 1926 + } + }, + "attributes": { + "dElevation": 20 + } + }, + { + "delta": { + "nodeXY6": { + "x": 28, + "y": 4582 + } + }, + "attributes": { + "dElevation": 10 + } + }, + { + "delta": { + "nodeXY6": { + "x": 88, + "y": 3793 + } + }, + "attributes": { + "dElevation": 10 + } + }, + { + "delta": { + "nodeXY6": { + "x": -143, + "y": 1866 + } + }, + "attributes": { + "dElevation": 10 + } + } + ] + }, + "connectsTo": { + "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 + } + }, + "signalGroup": 5, + "connectionID": 1 + } + ] + } + }, + { + "laneID": 25, + "ingressApproach": 7, + "laneAttributes": { + "directionalUse": { + "ingressPath": true, + "egressPath": false + }, + "shareWith": { + "busVehicleTraffic": false, + "trackedVehicleTraffic": false, + "individualMotorizedVehicleTraffic": false, + "taxiVehicleTraffic": false, + "overlappingLaneDescriptionProvided": false, + "cyclistVehicleTraffic": false, + "otherNonMotorizedTrafficTypes": false, + "multipleLanesTreatedAsOneLane": false, + "pedestrianTraffic": false, + "pedestriansTraffic": false + }, + "laneType": { + "vehicle": { + "isVehicleRevocableLane": false, + "isVehicleFlyOverLane": false, + "permissionOnRequest": false, + "hasIRbeaconCoverage": false, + "restrictedToBusUse": false, + "restrictedToTaxiUse": false, + "restrictedFromPublicUse": false, + "hovLaneUseOnly": false + } + } + }, + "maneuvers": { + "maneuverStraightAllowed": false, + "maneuverNoStoppingAllowed": false, + "goWithHalt": false, + "maneuverLeftAllowed": true, + "maneuverUTurnAllowed": false, + "maneuverLeftTurnOnRedAllowed": false, + "reserved1": false, + "maneuverRightAllowed": false, + "maneuverLaneChangeAllowed": false, + "yieldAllwaysRequired": false, + "maneuverRightTurnOnRedAllowed": false, + "caution": false + }, + "nodeList": { + "nodes": [ + { + "delta": { + "nodeXY6": { + "x": -213, + "y": 1913 + } + }, + "attributes": { + "dElevation": 20 + } + }, + { + "delta": { + "nodeXY6": { + "x": 14, + "y": 4594 + } + }, + "attributes": { + "dElevation": 10 + } + }, + { + "delta": { + "nodeXY6": { + "x": -91, + "y": 2238 + } + }, + "attributes": { + "dElevation": 10 + } + } + ] + }, + "connectsTo": { + "connectsTo": [ + { + "connectingLane": { + "lane": 5, + "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": 5, + "connectionID": 1 + } + ] + } + }, + { + "laneID": 26, + "egressApproach": 8, + "laneAttributes": { + "directionalUse": { + "ingressPath": false, + "egressPath": true + }, + "shareWith": { + "busVehicleTraffic": false, + "trackedVehicleTraffic": false, + "individualMotorizedVehicleTraffic": false, + "taxiVehicleTraffic": false, + "overlappingLaneDescriptionProvided": false, + "cyclistVehicleTraffic": false, + "otherNonMotorizedTrafficTypes": false, + "multipleLanesTreatedAsOneLane": false, + "pedestrianTraffic": false, + "pedestriansTraffic": false + }, + "laneType": { + "vehicle": { + "isVehicleRevocableLane": false, + "isVehicleFlyOverLane": false, + "permissionOnRequest": false, + "hasIRbeaconCoverage": false, + "restrictedToBusUse": false, + "restrictedToTaxiUse": false, + "restrictedFromPublicUse": false, + "hovLaneUseOnly": false + } + } + }, + "nodeList": { + "nodes": [ + { + "delta": { + "nodeXY6": { + "x": 724, + "y": 1902 + } + }, + "attributes": { + "dElevation": 10 + } + }, + { + "delta": { + "nodeXY6": { + "x": -7, + "y": 352 + } + }, + "attributes": { + "dElevation": 10 + } + } + ] + } + }, + { + "laneID": 27, + "egressApproach": 8, + "laneAttributes": { + "directionalUse": { + "ingressPath": false, + "egressPath": true + }, + "shareWith": { + "busVehicleTraffic": false, + "trackedVehicleTraffic": false, + "individualMotorizedVehicleTraffic": false, + "taxiVehicleTraffic": false, + "overlappingLaneDescriptionProvided": false, + "cyclistVehicleTraffic": false, + "otherNonMotorizedTrafficTypes": false, + "multipleLanesTreatedAsOneLane": false, + "pedestrianTraffic": false, + "pedestriansTraffic": false + }, + "laneType": { + "vehicle": { + "isVehicleRevocableLane": false, + "isVehicleFlyOverLane": false, + "permissionOnRequest": false, + "hasIRbeaconCoverage": false, + "restrictedToBusUse": false, + "restrictedToTaxiUse": false, + "restrictedFromPublicUse": false, + "hovLaneUseOnly": false + } + } + }, + "nodeList": { + "nodes": [ + { + "delta": { + "nodeXY6": { + "x": 1105, + "y": 1888 + } + }, + "attributes": { + "dElevation": 10 + } + }, + { + "delta": { + "nodeXY6": { + "x": -7, + "y": 332 + } + }, + "attributes": { + "dElevation": 10 + } + } + ] + } + }, + { + "laneID": 28, + "egressApproach": 8, + "laneAttributes": { + "directionalUse": { + "ingressPath": false, + "egressPath": true + }, + "shareWith": { + "busVehicleTraffic": false, + "trackedVehicleTraffic": false, + "individualMotorizedVehicleTraffic": false, + "taxiVehicleTraffic": false, + "overlappingLaneDescriptionProvided": false, + "cyclistVehicleTraffic": false, + "otherNonMotorizedTrafficTypes": false, + "multipleLanesTreatedAsOneLane": false, + "pedestrianTraffic": false, + "pedestriansTraffic": false + }, + "laneType": { + "vehicle": { + "isVehicleRevocableLane": false, + "isVehicleFlyOverLane": false, + "permissionOnRequest": false, + "hasIRbeaconCoverage": false, + "restrictedToBusUse": false, + "restrictedToTaxiUse": false, + "restrictedFromPublicUse": false, + "hovLaneUseOnly": false + } + } + }, + "nodeList": { + "nodes": [ + { + "delta": { + "nodeXY6": { + "x": 1591, + "y": 1874 + } + }, + "attributes": { + "dElevation": 10 + } + }, + { + "delta": { + "nodeXY6": { + "x": -14, + "y": 346 + } + } + }, + { + "delta": { + "nodeXY6": { + "x": 0, + "y": 7 + } + } + } + ] + } + } + ] + } + } + ] + } + }, + "dataType": "us.dot.its.jpo.ode.plugin.j2735.J2735MAP" + } +} \ No newline at end of file diff --git a/jpo-deduplicator/src/test/resources/json/processed_map/sample.processed_map-different.json b/jpo-deduplicator/src/test/resources/json/processed_map/sample.processed_map-different.json new file mode 100644 index 0000000..d839175 --- /dev/null +++ b/jpo-deduplicator/src/test/resources/json/processed_map/sample.processed_map-different.json @@ -0,0 +1,3443 @@ +{ + "mapFeatureCollection": { + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "id": 2, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0911523, + 39.5953376 + ], + [ + -105.0899239, + 39.5953231 + ], + [ + -105.0896005, + 39.5953332 + ], + [ + -105.0888831, + 39.595317 + ], + [ + -105.088108, + 39.5953159 + ], + [ + -105.0876637, + 39.5953153 + ] + ] + }, + "properties": { + "nodes": [ + { + "delta": [ + 2225, + 808 + ], + "delevation": -10 + }, + { + "delta": [ + 10517, + -161 + ], + "delevation": -60 + }, + { + "delta": [ + 2769, + 112 + ], + "delevation": -10 + }, + { + "delta": [ + 6142, + -180 + ], + "delevation": -30 + }, + { + "delta": [ + 6636, + -12 + ], + "delevation": -20 + }, + { + "delta": [ + 3804, + -7 + ] + } + ], + "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": 19, + "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": 4, + "connectionID": 1 + } + ] + } + }, + { + "type": "Feature", + "id": 3, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0911527, + 39.5953113 + ], + [ + -105.0908101, + 39.5953039 + ], + [ + -105.0900791, + 39.5952962 + ], + [ + -105.0896801, + 39.5952874 + ], + [ + -105.0888781, + 39.5952839 + ], + [ + -105.0885678, + 39.5952789 + ], + [ + -105.0880704, + 39.5952849 + ], + [ + -105.0876638, + 39.5952849 + ] + ] + }, + "properties": { + "nodes": [ + { + "delta": [ + 2222, + 515 + ], + "delevation": -10 + }, + { + "delta": [ + 2933, + -82 + ], + "delevation": -10 + }, + { + "delta": [ + 6259, + -85 + ], + "delevation": -40 + }, + { + "delta": [ + 3416, + -98 + ], + "delevation": -20 + }, + { + "delta": [ + 6867, + -39 + ], + "delevation": -30 + }, + { + "delta": [ + 2657, + -55 + ], + "delevation": -10 + }, + { + "delta": [ + 4259, + 67 + ], + "delevation": -10 + }, + { + "delta": [ + 3481, + 0 + ] + } + ], + "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": 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": 18, + "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": 4, + "connectionID": 1 + } + ] + } + }, + { + "type": "Feature", + "id": 1, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0911535, + 39.5953745 + ], + [ + -105.0899328, + 39.5953544 + ], + [ + -105.0897165, + 39.5953447 + ] + ] + }, + "properties": { + "nodes": [ + { + "delta": [ + 2215, + 1218 + ] + }, + { + "delta": [ + 10451, + -223 + ], + "delevation": -70 + }, + { + "delta": [ + 1852, + -108 + ], + "delevation": -10 + } + ], + "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": 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": 28, + "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": 4, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0911537, + 39.5952537 + ], + [ + -105.0903143, + 39.5952555 + ], + [ + -105.0902511, + 39.5952591 + ], + [ + -105.0900995, + 39.5952797 + ] + ] + }, + "properties": { + "nodes": [ + { + "delta": [ + 2213, + -124 + ], + "delevation": -10 + }, + { + "delta": [ + 7187, + 20 + ], + "delevation": -40 + }, + { + "delta": [ + 541, + 40 + ], + "delevation": -10 + }, + { + "delta": [ + 1298, + 229 + ] + } + ], + "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": 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": 12, + "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": 7, + "connectionID": 1 + } + ] + } + }, + { + "type": "Feature", + "id": 6, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0911474, + 39.5951732 + ], + [ + -105.0911048, + 39.5951738 + ] + ] + }, + "properties": { + "nodes": [ + { + "delta": [ + 2267, + -1019 + ], + "delevation": -10 + }, + { + "delta": [ + 365, + 7 + ] + } + ], + "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.0911474, + 39.5952053 + ], + [ + -105.0911079, + 39.5952053 + ] + ] + }, + "properties": { + "nodes": [ + { + "delta": [ + 2267, + -662 + ], + "delevation": -10 + }, + { + "delta": [ + 338, + 0 + ] + } + ], + "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": 7, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0911443, + 39.5951332 + ], + [ + -105.0911017, + 39.5951356 + ] + ] + }, + "properties": { + "nodes": [ + { + "delta": [ + 2294, + -1463 + ], + "delevation": -10 + }, + { + "delta": [ + 365, + 27 + ] + } + ], + "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": 2, + "ingressApproach": 0, + "ingressPath": false, + "egressPath": true + } + }, + { + "type": "Feature", + "id": 12, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0915234, + 39.5950941 + ], + [ + -105.0915234, + 39.5950602 + ] + ] + }, + "properties": { + "nodes": [ + { + "delta": [ + -952, + -1898 + ] + }, + { + "delta": [ + 0, + -377 + ] + } + ], + "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": 4, + "ingressApproach": 0, + "ingressPath": false, + "egressPath": true + } + }, + { + "type": "Feature", + "id": 13, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0915804, + 39.5950941 + ], + [ + -105.0915796, + 39.595059 + ], + [ + -105.0915796, + 39.595059 + ], + [ + -105.0915796, + 39.5950596 + ] + ] + }, + "properties": { + "nodes": [ + { + "delta": [ + -1440, + -1898 + ] + }, + { + "delta": [ + 7, + -390 + ] + }, + { + "delta": [ + 0, + 0 + ] + }, + { + "delta": [ + 0, + 7 + ] + } + ], + "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": 4, + "ingressApproach": 0, + "ingressPath": false, + "egressPath": true + } + }, + { + "type": "Feature", + "id": 10, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0913299, + 39.5950922 + ], + [ + -105.09133, + 39.5944158 + ], + [ + -105.0913348, + 39.5939413 + ], + [ + -105.0913368, + 39.592921 + ], + [ + -105.0913348, + 39.5923866 + ], + [ + -105.0913348, + 39.5923866 + ], + [ + -105.0913356, + 39.592386 + ] + ] + }, + "properties": { + "nodes": [ + { + "delta": [ + 705, + -1919 + ] + }, + { + "delta": [ + -1, + -7515 + ], + "delevation": -40 + }, + { + "delta": [ + -41, + -5272 + ], + "delevation": 10 + }, + { + "delta": [ + -17, + -11337 + ] + }, + { + "delta": [ + 17, + -5938 + ], + "delevation": 10 + }, + { + "delta": [ + 0, + 0 + ] + }, + { + "delta": [ + -7, + -7 + ] + } + ], + "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": 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": 26, + "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": 9, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0912849, + 39.5950912 + ], + [ + -105.0912838, + 39.5946624 + ], + [ + -105.0912861, + 39.5940862 + ], + [ + -105.0912901, + 39.5933704 + ], + [ + -105.0912882, + 39.5923858 + ] + ] + }, + "properties": { + "nodes": [ + { + "delta": [ + 1090, + -1930 + ], + "delevation": -10 + }, + { + "delta": [ + 9, + -4764 + ], + "delevation": -10 + }, + { + "delta": [ + -20, + -6402 + ], + "delevation": -20 + }, + { + "delta": [ + -34, + -7953 + ], + "delevation": -10 + }, + { + "delta": [ + 16, + -10940 + ], + "delevation": 20 + } + ], + "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": 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": 27, + "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.0913713, + 39.5950916 + ], + [ + -105.091375, + 39.5944888 + ], + [ + -105.0913568, + 39.5942534 + ] + ] + }, + "properties": { + "nodes": [ + { + "delta": [ + 350, + -1925 + ] + }, + { + "delta": [ + -32, + -6698 + ], + "delevation": -30 + }, + { + "delta": [ + 156, + -2616 + ] + } + ], + "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": 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": 18, + "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": 1, + "connectionID": 1 + } + ] + } + }, + { + "type": "Feature", + "id": 8, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0912303, + 39.5950889 + ], + [ + -105.0912421, + 39.5949129 + ], + [ + -105.0912427, + 39.5942475 + ], + [ + -105.0912568, + 39.5941003 + ] + ] + }, + "properties": { + "nodes": [ + { + "delta": [ + 1557, + -1956 + ], + "delevation": -10 + }, + { + "delta": [ + -101, + -1956 + ] + }, + { + "delta": [ + -5, + -7393 + ], + "delevation": -40 + }, + { + "delta": [ + -121, + -1636 + ] + } + ], + "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": 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 + } + }, + "connectionID": 1 + } + ] + } + }, + { + "type": "Feature", + "id": 15, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0916931, + 39.5951733 + ], + [ + -105.0927839, + 39.5951756 + ], + [ + -105.0941732, + 39.5951722 + ], + [ + -105.0952027, + 39.5951734 + ] + ] + }, + "properties": { + "nodes": [ + { + "delta": [ + -2405, + -1018 + ], + "delevation": 10 + }, + { + "delta": [ + -9339, + 26 + ], + "delevation": 30 + }, + { + "delta": [ + -11895, + -38 + ], + "delevation": 50 + }, + { + "delta": [ + -8814, + 13 + ] + } + ], + "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": 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 + } + }, + "signalGroup": 8, + "connectionID": 1 + } + ] + } + }, + { + "type": "Feature", + "id": 16, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0916852, + 39.5952059 + ], + [ + -105.0931135, + 39.5952073 + ], + [ + -105.0944406, + 39.595204 + ], + [ + -105.0952041, + 39.5952041 + ] + ] + }, + "properties": { + "nodes": [ + { + "delta": [ + -2337, + -656 + ], + "delevation": 10 + }, + { + "delta": [ + -12229, + 15 + ], + "delevation": 50 + }, + { + "delta": [ + -11362, + -37 + ], + "delevation": 30 + }, + { + "delta": [ + -6537, + 1 + ] + } + ], + "laneId": 16, + "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": 8, + "connectionID": 1 + } + ] + } + }, + { + "type": "Feature", + "id": 17, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0916853, + 39.5952393 + ], + [ + -105.0927239, + 39.5952377 + ], + [ + -105.0941207, + 39.5952375 + ], + [ + -105.0943034, + 39.5952213 + ] + ] + }, + "properties": { + "nodes": [ + { + "delta": [ + -2338, + -284 + ], + "delevation": 10 + }, + { + "delta": [ + -8892, + -18 + ], + "delevation": 30 + }, + { + "delta": [ + -11959, + -2 + ], + "delevation": 50 + }, + { + "delta": [ + -1564, + -180 + ] + } + ], + "laneId": 17, + "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": true, + "maneuverUTurnAllowed": false, + "maneuverLeftTurnOnRedAllowed": false, + "reserved1": false, + "maneuverRightAllowed": false, + "maneuverLaneChangeAllowed": false, + "yieldAllwaysRequired": false, + "maneuverRightTurnOnRedAllowed": false, + "caution": false + }, + "connectsTo": [ + { + "connectingLane": { + "lane": 26, + "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": 3, + "connectionID": 1 + } + ] + } + }, + { + "type": "Feature", + "id": 14, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0916926, + 39.5951407 + ], + [ + -105.0940224, + 39.5951414 + ], + [ + -105.095203, + 39.5951408 + ] + ] + }, + "properties": { + "nodes": [ + { + "delta": [ + -2401, + -1380 + ], + "delevation": 10 + }, + { + "delta": [ + -19947, + 8 + ], + "delevation": 80 + }, + { + "delta": [ + -10108, + -7 + ] + } + ], + "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": 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": 13, + "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": 18, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0916766, + 39.595308 + ], + [ + -105.0917443, + 39.5953067 + ] + ] + }, + "properties": { + "nodes": [ + { + "delta": [ + -2264, + 479 + ], + "delevation": 20 + }, + { + "delta": [ + -580, + -14 + ] + } + ], + "laneId": 18, + "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": 19, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0916758, + 39.5953365 + ], + [ + -105.0917363, + 39.5953365 + ] + ] + }, + "properties": { + "nodes": [ + { + "delta": [ + -2257, + 796 + ], + "delevation": 20 + }, + { + "delta": [ + -518, + 0 + ] + } + ], + "laneId": 19, + "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": 20, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0916734, + 39.5953755 + ], + [ + -105.0917299, + 39.5953755 + ] + ] + }, + "properties": { + "nodes": [ + { + "delta": [ + -2236, + 1229 + ], + "delevation": 20 + }, + { + "delta": [ + -484, + 0 + ] + } + ], + "laneId": 20, + "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": 23, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.091519, + 39.5954362 + ], + [ + -105.0914927, + 39.5965421 + ], + [ + -105.091488, + 39.5974092 + ], + [ + -105.0914843, + 39.5981324 + ], + [ + -105.0914843, + 39.5981324 + ], + [ + -105.0914851, + 39.5981349 + ] + ] + }, + "properties": { + "nodes": [ + { + "delta": [ + -914, + 1903 + ], + "delevation": 20 + }, + { + "delta": [ + 225, + 12288 + ], + "delevation": 30 + }, + { + "delta": [ + 40, + 9634 + ], + "delevation": -20 + }, + { + "delta": [ + 32, + 8035 + ], + "delevation": -30 + }, + { + "delta": [ + 0, + 0 + ] + }, + { + "delta": [ + -7, + 28 + ] + } + ], + "laneId": 23, + "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": 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": 12, + "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": 22, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0915548, + 39.5954372 + ], + [ + -105.0915441, + 39.59638 + ], + [ + -105.0915337, + 39.5974224 + ], + [ + -105.0915281, + 39.5981345 + ] + ] + }, + "properties": { + "nodes": [ + { + "delta": [ + -1221, + 1914 + ], + "delevation": 20 + }, + { + "delta": [ + 92, + 10475 + ], + "delevation": 30 + }, + { + "delta": [ + 89, + 11582 + ], + "delevation": -20 + }, + { + "delta": [ + 48, + 7912 + ], + "delevation": -30 + } + ], + "laneId": 22, + "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": 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": 13, + "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": 21, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0916048, + 39.5954391 + ], + [ + -105.0916029, + 39.5957255 + ], + [ + -105.0916004, + 39.5962647 + ], + [ + -105.0915885, + 39.5966976 + ], + [ + -105.0915786, + 39.5977599 + ], + [ + -105.0915764, + 39.5981344 + ] + ] + }, + "properties": { + "nodes": [ + { + "delta": [ + -1649, + 1935 + ], + "delevation": 20 + }, + { + "delta": [ + 16, + 3182 + ], + "delevation": 10 + }, + { + "delta": [ + 21, + 5991 + ], + "delevation": 20 + }, + { + "delta": [ + 102, + 4810 + ] + }, + { + "delta": [ + 85, + 11803 + ], + "delevation": -30 + }, + { + "delta": [ + 19, + 4161 + ], + "delevation": -20 + } + ], + "laneId": 21, + "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": 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": 20, + "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": 24, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0914747, + 39.5954382 + ], + [ + -105.0914714, + 39.5958506 + ], + [ + -105.0914611, + 39.596192 + ], + [ + -105.0914778, + 39.5963599 + ] + ] + }, + "properties": { + "nodes": [ + { + "delta": [ + -535, + 1926 + ], + "delevation": 20 + }, + { + "delta": [ + 28, + 4582 + ], + "delevation": 10 + }, + { + "delta": [ + 88, + 3793 + ], + "delevation": 10 + }, + { + "delta": [ + -143, + 1866 + ], + "delevation": 10 + } + ], + "laneId": 24, + "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": 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 + } + }, + "signalGroup": 5, + "connectionID": 1 + } + ] + } + }, + { + "type": "Feature", + "id": 25, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0914371, + 39.5954371 + ], + [ + -105.0914355, + 39.5958506 + ], + [ + -105.0914461, + 39.596052 + ] + ] + }, + "properties": { + "nodes": [ + { + "delta": [ + -213, + 1913 + ], + "delevation": 20 + }, + { + "delta": [ + 14, + 4594 + ], + "delevation": 10 + }, + { + "delta": [ + -91, + 2238 + ], + "delevation": 10 + } + ], + "laneId": 25, + "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": 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": 5, + "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": 5, + "connectionID": 1 + } + ] + } + }, + { + "type": "Feature", + "id": 26, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0913276, + 39.5954361 + ], + [ + -105.0913284, + 39.5954678 + ] + ] + }, + "properties": { + "nodes": [ + { + "delta": [ + 724, + 1902 + ], + "delevation": 10 + }, + { + "delta": [ + -7, + 352 + ], + "delevation": 10 + } + ], + "laneId": 26, + "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": 8, + "ingressApproach": 0, + "ingressPath": false, + "egressPath": true + } + }, + { + "type": "Feature", + "id": 27, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0912831, + 39.5954348 + ], + [ + -105.0912839, + 39.5954647 + ] + ] + }, + "properties": { + "nodes": [ + { + "delta": [ + 1105, + 1888 + ], + "delevation": 10 + }, + { + "delta": [ + -7, + 332 + ], + "delevation": 10 + } + ], + "laneId": 27, + "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": 8, + "ingressApproach": 0, + "ingressPath": false, + "egressPath": true + } + }, + { + "type": "Feature", + "id": 28, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0912264, + 39.5954336 + ], + [ + -105.091228, + 39.5954647 + ], + [ + -105.091228, + 39.5954653 + ] + ] + }, + "properties": { + "nodes": [ + { + "delta": [ + 1591, + 1874 + ], + "delevation": 10 + }, + { + "delta": [ + -14, + 346 + ] + }, + { + "delta": [ + 0, + 7 + ] + } + ], + "laneId": 28, + "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": 8, + "ingressApproach": 0, + "ingressPath": false, + "egressPath": true + } + } + ] + }, + "connectingLanesFeatureCollection": { + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "id": "2-19", + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0911523, + 39.5953376 + ], + [ + -105.0916758, + 39.5953365 + ] + ] + }, + "properties": { + "signalGroupId": 4, + "ingressLaneId": 2, + "egressLaneId": 19 + } + }, + { + "type": "Feature", + "id": "3-18", + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0911527, + 39.5953113 + ], + [ + -105.0916766, + 39.595308 + ] + ] + }, + "properties": { + "signalGroupId": 4, + "ingressLaneId": 3, + "egressLaneId": 18 + } + }, + { + "type": "Feature", + "id": "1-28", + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0911535, + 39.5953745 + ], + [ + -105.0912264, + 39.5954336 + ] + ] + }, + "properties": { + "ingressLaneId": 1, + "egressLaneId": 28 + } + }, + { + "type": "Feature", + "id": "4-12", + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0911537, + 39.5952537 + ], + [ + -105.0915234, + 39.5950941 + ] + ] + }, + "properties": { + "signalGroupId": 7, + "ingressLaneId": 4, + "egressLaneId": 12 + } + }, + { + "type": "Feature", + "id": "10-26", + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0913299, + 39.5950922 + ], + [ + -105.0913276, + 39.5954361 + ] + ] + }, + "properties": { + "signalGroupId": 6, + "ingressLaneId": 10, + "egressLaneId": 26 + } + }, + { + "type": "Feature", + "id": "9-27", + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0912849, + 39.5950912 + ], + [ + -105.0912831, + 39.5954348 + ] + ] + }, + "properties": { + "signalGroupId": 6, + "ingressLaneId": 9, + "egressLaneId": 27 + } + }, + { + "type": "Feature", + "id": "11-18", + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0913713, + 39.5950916 + ], + [ + -105.0916766, + 39.595308 + ] + ] + }, + "properties": { + "signalGroupId": 1, + "ingressLaneId": 11, + "egressLaneId": 18 + } + }, + { + "type": "Feature", + "id": "8-7", + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0912303, + 39.5950889 + ], + [ + -105.0911443, + 39.5951332 + ] + ] + }, + "properties": { + "ingressLaneId": 8, + "egressLaneId": 7 + } + }, + { + "type": "Feature", + "id": "15-6", + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0916931, + 39.5951733 + ], + [ + -105.0911474, + 39.5951732 + ] + ] + }, + "properties": { + "signalGroupId": 8, + "ingressLaneId": 15, + "egressLaneId": 6 + } + }, + { + "type": "Feature", + "id": "16-5", + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0916852, + 39.5952059 + ], + [ + -105.0911474, + 39.5952053 + ] + ] + }, + "properties": { + "signalGroupId": 8, + "ingressLaneId": 16, + "egressLaneId": 5 + } + }, + { + "type": "Feature", + "id": "17-26", + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0916853, + 39.5952393 + ], + [ + -105.0913276, + 39.5954361 + ] + ] + }, + "properties": { + "signalGroupId": 3, + "ingressLaneId": 17, + "egressLaneId": 26 + } + }, + { + "type": "Feature", + "id": "14-13", + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0916926, + 39.5951407 + ], + [ + -105.0915804, + 39.5950941 + ] + ] + }, + "properties": { + "ingressLaneId": 14, + "egressLaneId": 13 + } + }, + { + "type": "Feature", + "id": "23-12", + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.091519, + 39.5954362 + ], + [ + -105.0915234, + 39.5950941 + ] + ] + }, + "properties": { + "signalGroupId": 2, + "ingressLaneId": 23, + "egressLaneId": 12 + } + }, + { + "type": "Feature", + "id": "22-13", + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0915548, + 39.5954372 + ], + [ + -105.0915804, + 39.5950941 + ] + ] + }, + "properties": { + "signalGroupId": 2, + "ingressLaneId": 22, + "egressLaneId": 13 + } + }, + { + "type": "Feature", + "id": "21-20", + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0916048, + 39.5954391 + ], + [ + -105.0916734, + 39.5953755 + ] + ] + }, + "properties": { + "ingressLaneId": 21, + "egressLaneId": 20 + } + }, + { + "type": "Feature", + "id": "24-6", + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0914747, + 39.5954382 + ], + [ + -105.0911474, + 39.5951732 + ] + ] + }, + "properties": { + "signalGroupId": 5, + "ingressLaneId": 24, + "egressLaneId": 6 + } + }, + { + "type": "Feature", + "id": "25-5", + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0914371, + 39.5954371 + ], + [ + -105.0911474, + 39.5952053 + ] + ] + }, + "properties": { + "signalGroupId": 5, + "ingressLaneId": 25, + "egressLaneId": 5 + } + } + ] + }, + "properties": { + "schemaVersion": 1, + "messageType": "MAP", + "odeReceivedAt": "2025-01-31T23:36:23.542Z", + "originIp": "172.20.0.1", + "intersectionId": 13110, + "msgIssueRevision": 0, + "revision": 0, + "refPoint": { + "latitude": 39.5952649, + "longitude": -105.0914122, + "elevation": 1677 + }, + "cti4501Conformant": false, + "validationMessages": [ + { + "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[2].connectsTo.connectsTo[0].signalGroup: is missing but it is required", + "jsonPath": "$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[2].connectsTo.connectsTo[0]", + "schemaPath": "#/$defs/J2735Connection/required" + }, + { + "message": "$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[4].maneuvers: is missing but it is required", + "jsonPath": "$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[4]", + "schemaPath": "#/$defs/J2735GenericLane/required" + }, + { + "message": "$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[4].connectsTo: is missing but it is required", + "jsonPath": "$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[4]", + "schemaPath": "#/$defs/J2735GenericLane/required" + }, + { + "message": "$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[5].maneuvers: is missing but it is required", + "jsonPath": "$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[5]", + "schemaPath": "#/$defs/J2735GenericLane/required" + }, + { + "message": "$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[5].connectsTo: is missing but it is required", + "jsonPath": "$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[5]", + "schemaPath": "#/$defs/J2735GenericLane/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[12].connectsTo.connectsTo[0].signalGroup: is missing but it is required", + "jsonPath": "$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[12].connectsTo.connectsTo[0]", + "schemaPath": "#/$defs/J2735Connection/required" + }, + { + "message": "$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[16].connectsTo.connectsTo[0].signalGroup: is missing but it is required", + "jsonPath": "$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[16].connectsTo.connectsTo[0]", + "schemaPath": "#/$defs/J2735Connection/required" + }, + { + "message": "$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[17].maneuvers: is missing but it is required", + "jsonPath": "$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[17]", + "schemaPath": "#/$defs/J2735GenericLane/required" + }, + { + "message": "$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[17].connectsTo: is missing but it is required", + "jsonPath": "$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[17]", + "schemaPath": "#/$defs/J2735GenericLane/required" + }, + { + "message": "$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[18].maneuvers: is missing but it is required", + "jsonPath": "$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[18]", + "schemaPath": "#/$defs/J2735GenericLane/required" + }, + { + "message": "$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[18].connectsTo: is missing but it is required", + "jsonPath": "$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[18]", + "schemaPath": "#/$defs/J2735GenericLane/required" + }, + { + "message": "$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[19].maneuvers: is missing but it is required", + "jsonPath": "$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[19]", + "schemaPath": "#/$defs/J2735GenericLane/required" + }, + { + "message": "$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[19].connectsTo: is missing but it is required", + "jsonPath": "$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[19]", + "schemaPath": "#/$defs/J2735GenericLane/required" + }, + { + "message": "$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[22].connectsTo.connectsTo[0].signalGroup: is missing but it is required", + "jsonPath": "$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[22].connectsTo.connectsTo[0]", + "schemaPath": "#/$defs/J2735Connection/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[27].maneuvers: is missing but it is required", + "jsonPath": "$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[27]", + "schemaPath": "#/$defs/J2735GenericLane/required" + }, + { + "message": "$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[27].connectsTo: is missing but it is required", + "jsonPath": "$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[27]", + "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": "2025-01-31T23:36:23.542Z" + } + } \ No newline at end of file diff --git a/jpo-deduplicator/src/test/resources/json/processed_map/sample.processed_map-reference-1-hour-later.json b/jpo-deduplicator/src/test/resources/json/processed_map/sample.processed_map-reference-1-hour-later.json new file mode 100644 index 0000000..af91ff7 --- /dev/null +++ b/jpo-deduplicator/src/test/resources/json/processed_map/sample.processed_map-reference-1-hour-later.json @@ -0,0 +1,3443 @@ +{ + "mapFeatureCollection": { + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "id": 2, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0911523, + 39.5953376 + ], + [ + -105.0899239, + 39.5953231 + ], + [ + -105.0896005, + 39.5953332 + ], + [ + -105.0888831, + 39.595317 + ], + [ + -105.088108, + 39.5953159 + ], + [ + -105.0876637, + 39.5953153 + ] + ] + }, + "properties": { + "nodes": [ + { + "delta": [ + 2225, + 808 + ], + "delevation": -10 + }, + { + "delta": [ + 10517, + -161 + ], + "delevation": -60 + }, + { + "delta": [ + 2769, + 112 + ], + "delevation": -10 + }, + { + "delta": [ + 6142, + -180 + ], + "delevation": -30 + }, + { + "delta": [ + 6636, + -12 + ], + "delevation": -20 + }, + { + "delta": [ + 3804, + -7 + ] + } + ], + "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": 19, + "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": 4, + "connectionID": 1 + } + ] + } + }, + { + "type": "Feature", + "id": 3, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0911527, + 39.5953113 + ], + [ + -105.0908101, + 39.5953039 + ], + [ + -105.0900791, + 39.5952962 + ], + [ + -105.0896801, + 39.5952874 + ], + [ + -105.0888781, + 39.5952839 + ], + [ + -105.0885678, + 39.5952789 + ], + [ + -105.0880704, + 39.5952849 + ], + [ + -105.0876638, + 39.5952849 + ] + ] + }, + "properties": { + "nodes": [ + { + "delta": [ + 2222, + 515 + ], + "delevation": -10 + }, + { + "delta": [ + 2933, + -82 + ], + "delevation": -10 + }, + { + "delta": [ + 6259, + -85 + ], + "delevation": -40 + }, + { + "delta": [ + 3416, + -98 + ], + "delevation": -20 + }, + { + "delta": [ + 6867, + -39 + ], + "delevation": -30 + }, + { + "delta": [ + 2657, + -55 + ], + "delevation": -10 + }, + { + "delta": [ + 4259, + 67 + ], + "delevation": -10 + }, + { + "delta": [ + 3481, + 0 + ] + } + ], + "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": 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": 18, + "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": 4, + "connectionID": 1 + } + ] + } + }, + { + "type": "Feature", + "id": 1, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0911535, + 39.5953745 + ], + [ + -105.0899328, + 39.5953544 + ], + [ + -105.0897165, + 39.5953447 + ] + ] + }, + "properties": { + "nodes": [ + { + "delta": [ + 2215, + 1218 + ] + }, + { + "delta": [ + 10451, + -223 + ], + "delevation": -70 + }, + { + "delta": [ + 1852, + -108 + ], + "delevation": -10 + } + ], + "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": 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": 28, + "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": 4, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0911537, + 39.5952537 + ], + [ + -105.0903143, + 39.5952555 + ], + [ + -105.0902511, + 39.5952591 + ], + [ + -105.0900995, + 39.5952797 + ] + ] + }, + "properties": { + "nodes": [ + { + "delta": [ + 2213, + -124 + ], + "delevation": -10 + }, + { + "delta": [ + 7187, + 20 + ], + "delevation": -40 + }, + { + "delta": [ + 541, + 40 + ], + "delevation": -10 + }, + { + "delta": [ + 1298, + 229 + ] + } + ], + "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": 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": 12, + "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": 7, + "connectionID": 1 + } + ] + } + }, + { + "type": "Feature", + "id": 6, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0911474, + 39.5951732 + ], + [ + -105.0911048, + 39.5951738 + ] + ] + }, + "properties": { + "nodes": [ + { + "delta": [ + 2267, + -1019 + ], + "delevation": -10 + }, + { + "delta": [ + 365, + 7 + ] + } + ], + "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.0911474, + 39.5952053 + ], + [ + -105.0911079, + 39.5952053 + ] + ] + }, + "properties": { + "nodes": [ + { + "delta": [ + 2267, + -662 + ], + "delevation": -10 + }, + { + "delta": [ + 338, + 0 + ] + } + ], + "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": 7, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0911443, + 39.5951332 + ], + [ + -105.0911017, + 39.5951356 + ] + ] + }, + "properties": { + "nodes": [ + { + "delta": [ + 2294, + -1463 + ], + "delevation": -10 + }, + { + "delta": [ + 365, + 27 + ] + } + ], + "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": 2, + "ingressApproach": 0, + "ingressPath": false, + "egressPath": true + } + }, + { + "type": "Feature", + "id": 12, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0915234, + 39.5950941 + ], + [ + -105.0915234, + 39.5950602 + ] + ] + }, + "properties": { + "nodes": [ + { + "delta": [ + -952, + -1898 + ] + }, + { + "delta": [ + 0, + -377 + ] + } + ], + "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": 4, + "ingressApproach": 0, + "ingressPath": false, + "egressPath": true + } + }, + { + "type": "Feature", + "id": 13, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0915804, + 39.5950941 + ], + [ + -105.0915796, + 39.595059 + ], + [ + -105.0915796, + 39.595059 + ], + [ + -105.0915796, + 39.5950596 + ] + ] + }, + "properties": { + "nodes": [ + { + "delta": [ + -1440, + -1898 + ] + }, + { + "delta": [ + 7, + -390 + ] + }, + { + "delta": [ + 0, + 0 + ] + }, + { + "delta": [ + 0, + 7 + ] + } + ], + "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": 4, + "ingressApproach": 0, + "ingressPath": false, + "egressPath": true + } + }, + { + "type": "Feature", + "id": 10, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0913299, + 39.5950922 + ], + [ + -105.09133, + 39.5944158 + ], + [ + -105.0913348, + 39.5939413 + ], + [ + -105.0913368, + 39.592921 + ], + [ + -105.0913348, + 39.5923866 + ], + [ + -105.0913348, + 39.5923866 + ], + [ + -105.0913356, + 39.592386 + ] + ] + }, + "properties": { + "nodes": [ + { + "delta": [ + 705, + -1919 + ] + }, + { + "delta": [ + -1, + -7515 + ], + "delevation": -40 + }, + { + "delta": [ + -41, + -5272 + ], + "delevation": 10 + }, + { + "delta": [ + -17, + -11337 + ] + }, + { + "delta": [ + 17, + -5938 + ], + "delevation": 10 + }, + { + "delta": [ + 0, + 0 + ] + }, + { + "delta": [ + -7, + -7 + ] + } + ], + "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": 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": 26, + "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": 9, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0912849, + 39.5950912 + ], + [ + -105.0912838, + 39.5946624 + ], + [ + -105.0912861, + 39.5940862 + ], + [ + -105.0912901, + 39.5933704 + ], + [ + -105.0912882, + 39.5923858 + ] + ] + }, + "properties": { + "nodes": [ + { + "delta": [ + 1090, + -1930 + ], + "delevation": -10 + }, + { + "delta": [ + 9, + -4764 + ], + "delevation": -10 + }, + { + "delta": [ + -20, + -6402 + ], + "delevation": -20 + }, + { + "delta": [ + -34, + -7953 + ], + "delevation": -10 + }, + { + "delta": [ + 16, + -10940 + ], + "delevation": 20 + } + ], + "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": 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": 27, + "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.0913713, + 39.5950916 + ], + [ + -105.091375, + 39.5944888 + ], + [ + -105.0913568, + 39.5942534 + ] + ] + }, + "properties": { + "nodes": [ + { + "delta": [ + 350, + -1925 + ] + }, + { + "delta": [ + -32, + -6698 + ], + "delevation": -30 + }, + { + "delta": [ + 156, + -2616 + ] + } + ], + "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": 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": 18, + "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": 1, + "connectionID": 1 + } + ] + } + }, + { + "type": "Feature", + "id": 8, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0912303, + 39.5950889 + ], + [ + -105.0912421, + 39.5949129 + ], + [ + -105.0912427, + 39.5942475 + ], + [ + -105.0912568, + 39.5941003 + ] + ] + }, + "properties": { + "nodes": [ + { + "delta": [ + 1557, + -1956 + ], + "delevation": -10 + }, + { + "delta": [ + -101, + -1956 + ] + }, + { + "delta": [ + -5, + -7393 + ], + "delevation": -40 + }, + { + "delta": [ + -121, + -1636 + ] + } + ], + "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": 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 + } + }, + "connectionID": 1 + } + ] + } + }, + { + "type": "Feature", + "id": 15, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0916931, + 39.5951733 + ], + [ + -105.0927839, + 39.5951756 + ], + [ + -105.0941732, + 39.5951722 + ], + [ + -105.0952027, + 39.5951734 + ] + ] + }, + "properties": { + "nodes": [ + { + "delta": [ + -2405, + -1018 + ], + "delevation": 10 + }, + { + "delta": [ + -9339, + 26 + ], + "delevation": 30 + }, + { + "delta": [ + -11895, + -38 + ], + "delevation": 50 + }, + { + "delta": [ + -8814, + 13 + ] + } + ], + "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": 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 + } + }, + "signalGroup": 8, + "connectionID": 1 + } + ] + } + }, + { + "type": "Feature", + "id": 16, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0916852, + 39.5952059 + ], + [ + -105.0931135, + 39.5952073 + ], + [ + -105.0944406, + 39.595204 + ], + [ + -105.0952041, + 39.5952041 + ] + ] + }, + "properties": { + "nodes": [ + { + "delta": [ + -2337, + -656 + ], + "delevation": 10 + }, + { + "delta": [ + -12229, + 15 + ], + "delevation": 50 + }, + { + "delta": [ + -11362, + -37 + ], + "delevation": 30 + }, + { + "delta": [ + -6537, + 1 + ] + } + ], + "laneId": 16, + "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": 8, + "connectionID": 1 + } + ] + } + }, + { + "type": "Feature", + "id": 17, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0916853, + 39.5952393 + ], + [ + -105.0927239, + 39.5952377 + ], + [ + -105.0941207, + 39.5952375 + ], + [ + -105.0943034, + 39.5952213 + ] + ] + }, + "properties": { + "nodes": [ + { + "delta": [ + -2338, + -284 + ], + "delevation": 10 + }, + { + "delta": [ + -8892, + -18 + ], + "delevation": 30 + }, + { + "delta": [ + -11959, + -2 + ], + "delevation": 50 + }, + { + "delta": [ + -1564, + -180 + ] + } + ], + "laneId": 17, + "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": true, + "maneuverUTurnAllowed": false, + "maneuverLeftTurnOnRedAllowed": false, + "reserved1": false, + "maneuverRightAllowed": false, + "maneuverLaneChangeAllowed": false, + "yieldAllwaysRequired": false, + "maneuverRightTurnOnRedAllowed": false, + "caution": false + }, + "connectsTo": [ + { + "connectingLane": { + "lane": 26, + "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": 3, + "connectionID": 1 + } + ] + } + }, + { + "type": "Feature", + "id": 14, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0916926, + 39.5951407 + ], + [ + -105.0940224, + 39.5951414 + ], + [ + -105.095203, + 39.5951408 + ] + ] + }, + "properties": { + "nodes": [ + { + "delta": [ + -2401, + -1380 + ], + "delevation": 10 + }, + { + "delta": [ + -19947, + 8 + ], + "delevation": 80 + }, + { + "delta": [ + -10108, + -7 + ] + } + ], + "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": 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": 13, + "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": 18, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0916766, + 39.595308 + ], + [ + -105.0917443, + 39.5953067 + ] + ] + }, + "properties": { + "nodes": [ + { + "delta": [ + -2264, + 479 + ], + "delevation": 20 + }, + { + "delta": [ + -580, + -14 + ] + } + ], + "laneId": 18, + "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": 19, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0916758, + 39.5953365 + ], + [ + -105.0917363, + 39.5953365 + ] + ] + }, + "properties": { + "nodes": [ + { + "delta": [ + -2257, + 796 + ], + "delevation": 20 + }, + { + "delta": [ + -518, + 0 + ] + } + ], + "laneId": 19, + "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": 20, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0916734, + 39.5953755 + ], + [ + -105.0917299, + 39.5953755 + ] + ] + }, + "properties": { + "nodes": [ + { + "delta": [ + -2236, + 1229 + ], + "delevation": 20 + }, + { + "delta": [ + -484, + 0 + ] + } + ], + "laneId": 20, + "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": 23, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.091519, + 39.5954362 + ], + [ + -105.0914927, + 39.5965421 + ], + [ + -105.091488, + 39.5974092 + ], + [ + -105.0914843, + 39.5981324 + ], + [ + -105.0914843, + 39.5981324 + ], + [ + -105.0914851, + 39.5981349 + ] + ] + }, + "properties": { + "nodes": [ + { + "delta": [ + -914, + 1903 + ], + "delevation": 20 + }, + { + "delta": [ + 225, + 12288 + ], + "delevation": 30 + }, + { + "delta": [ + 40, + 9634 + ], + "delevation": -20 + }, + { + "delta": [ + 32, + 8035 + ], + "delevation": -30 + }, + { + "delta": [ + 0, + 0 + ] + }, + { + "delta": [ + -7, + 28 + ] + } + ], + "laneId": 23, + "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": 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": 12, + "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": 22, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0915548, + 39.5954372 + ], + [ + -105.0915441, + 39.59638 + ], + [ + -105.0915337, + 39.5974224 + ], + [ + -105.0915281, + 39.5981345 + ] + ] + }, + "properties": { + "nodes": [ + { + "delta": [ + -1221, + 1914 + ], + "delevation": 20 + }, + { + "delta": [ + 92, + 10475 + ], + "delevation": 30 + }, + { + "delta": [ + 89, + 11582 + ], + "delevation": -20 + }, + { + "delta": [ + 48, + 7912 + ], + "delevation": -30 + } + ], + "laneId": 22, + "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": 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": 13, + "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": 21, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0916048, + 39.5954391 + ], + [ + -105.0916029, + 39.5957255 + ], + [ + -105.0916004, + 39.5962647 + ], + [ + -105.0915885, + 39.5966976 + ], + [ + -105.0915786, + 39.5977599 + ], + [ + -105.0915764, + 39.5981344 + ] + ] + }, + "properties": { + "nodes": [ + { + "delta": [ + -1649, + 1935 + ], + "delevation": 20 + }, + { + "delta": [ + 16, + 3182 + ], + "delevation": 10 + }, + { + "delta": [ + 21, + 5991 + ], + "delevation": 20 + }, + { + "delta": [ + 102, + 4810 + ] + }, + { + "delta": [ + 85, + 11803 + ], + "delevation": -30 + }, + { + "delta": [ + 19, + 4161 + ], + "delevation": -20 + } + ], + "laneId": 21, + "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": 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": 20, + "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": 24, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0914747, + 39.5954382 + ], + [ + -105.0914714, + 39.5958506 + ], + [ + -105.0914611, + 39.596192 + ], + [ + -105.0914778, + 39.5963599 + ] + ] + }, + "properties": { + "nodes": [ + { + "delta": [ + -535, + 1926 + ], + "delevation": 20 + }, + { + "delta": [ + 28, + 4582 + ], + "delevation": 10 + }, + { + "delta": [ + 88, + 3793 + ], + "delevation": 10 + }, + { + "delta": [ + -143, + 1866 + ], + "delevation": 10 + } + ], + "laneId": 24, + "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": 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 + } + }, + "signalGroup": 5, + "connectionID": 1 + } + ] + } + }, + { + "type": "Feature", + "id": 25, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0914371, + 39.5954371 + ], + [ + -105.0914355, + 39.5958506 + ], + [ + -105.0914461, + 39.596052 + ] + ] + }, + "properties": { + "nodes": [ + { + "delta": [ + -213, + 1913 + ], + "delevation": 20 + }, + { + "delta": [ + 14, + 4594 + ], + "delevation": 10 + }, + { + "delta": [ + -91, + 2238 + ], + "delevation": 10 + } + ], + "laneId": 25, + "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": 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": 5, + "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": 5, + "connectionID": 1 + } + ] + } + }, + { + "type": "Feature", + "id": 26, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0913276, + 39.5954361 + ], + [ + -105.0913284, + 39.5954678 + ] + ] + }, + "properties": { + "nodes": [ + { + "delta": [ + 724, + 1902 + ], + "delevation": 10 + }, + { + "delta": [ + -7, + 352 + ], + "delevation": 10 + } + ], + "laneId": 26, + "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": 8, + "ingressApproach": 0, + "ingressPath": false, + "egressPath": true + } + }, + { + "type": "Feature", + "id": 27, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0912831, + 39.5954348 + ], + [ + -105.0912839, + 39.5954647 + ] + ] + }, + "properties": { + "nodes": [ + { + "delta": [ + 1105, + 1888 + ], + "delevation": 10 + }, + { + "delta": [ + -7, + 332 + ], + "delevation": 10 + } + ], + "laneId": 27, + "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": 8, + "ingressApproach": 0, + "ingressPath": false, + "egressPath": true + } + }, + { + "type": "Feature", + "id": 28, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0912264, + 39.5954336 + ], + [ + -105.091228, + 39.5954647 + ], + [ + -105.091228, + 39.5954653 + ] + ] + }, + "properties": { + "nodes": [ + { + "delta": [ + 1591, + 1874 + ], + "delevation": 10 + }, + { + "delta": [ + -14, + 346 + ] + }, + { + "delta": [ + 0, + 7 + ] + } + ], + "laneId": 28, + "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": 8, + "ingressApproach": 0, + "ingressPath": false, + "egressPath": true + } + } + ] + }, + "connectingLanesFeatureCollection": { + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "id": "2-19", + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0911523, + 39.5953376 + ], + [ + -105.0916758, + 39.5953365 + ] + ] + }, + "properties": { + "signalGroupId": 4, + "ingressLaneId": 2, + "egressLaneId": 19 + } + }, + { + "type": "Feature", + "id": "3-18", + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0911527, + 39.5953113 + ], + [ + -105.0916766, + 39.595308 + ] + ] + }, + "properties": { + "signalGroupId": 4, + "ingressLaneId": 3, + "egressLaneId": 18 + } + }, + { + "type": "Feature", + "id": "1-28", + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0911535, + 39.5953745 + ], + [ + -105.0912264, + 39.5954336 + ] + ] + }, + "properties": { + "ingressLaneId": 1, + "egressLaneId": 28 + } + }, + { + "type": "Feature", + "id": "4-12", + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0911537, + 39.5952537 + ], + [ + -105.0915234, + 39.5950941 + ] + ] + }, + "properties": { + "signalGroupId": 7, + "ingressLaneId": 4, + "egressLaneId": 12 + } + }, + { + "type": "Feature", + "id": "10-26", + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0913299, + 39.5950922 + ], + [ + -105.0913276, + 39.5954361 + ] + ] + }, + "properties": { + "signalGroupId": 6, + "ingressLaneId": 10, + "egressLaneId": 26 + } + }, + { + "type": "Feature", + "id": "9-27", + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0912849, + 39.5950912 + ], + [ + -105.0912831, + 39.5954348 + ] + ] + }, + "properties": { + "signalGroupId": 6, + "ingressLaneId": 9, + "egressLaneId": 27 + } + }, + { + "type": "Feature", + "id": "11-18", + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0913713, + 39.5950916 + ], + [ + -105.0916766, + 39.595308 + ] + ] + }, + "properties": { + "signalGroupId": 1, + "ingressLaneId": 11, + "egressLaneId": 18 + } + }, + { + "type": "Feature", + "id": "8-7", + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0912303, + 39.5950889 + ], + [ + -105.0911443, + 39.5951332 + ] + ] + }, + "properties": { + "ingressLaneId": 8, + "egressLaneId": 7 + } + }, + { + "type": "Feature", + "id": "15-6", + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0916931, + 39.5951733 + ], + [ + -105.0911474, + 39.5951732 + ] + ] + }, + "properties": { + "signalGroupId": 8, + "ingressLaneId": 15, + "egressLaneId": 6 + } + }, + { + "type": "Feature", + "id": "16-5", + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0916852, + 39.5952059 + ], + [ + -105.0911474, + 39.5952053 + ] + ] + }, + "properties": { + "signalGroupId": 8, + "ingressLaneId": 16, + "egressLaneId": 5 + } + }, + { + "type": "Feature", + "id": "17-26", + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0916853, + 39.5952393 + ], + [ + -105.0913276, + 39.5954361 + ] + ] + }, + "properties": { + "signalGroupId": 3, + "ingressLaneId": 17, + "egressLaneId": 26 + } + }, + { + "type": "Feature", + "id": "14-13", + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0916926, + 39.5951407 + ], + [ + -105.0915804, + 39.5950941 + ] + ] + }, + "properties": { + "ingressLaneId": 14, + "egressLaneId": 13 + } + }, + { + "type": "Feature", + "id": "23-12", + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.091519, + 39.5954362 + ], + [ + -105.0915234, + 39.5950941 + ] + ] + }, + "properties": { + "signalGroupId": 2, + "ingressLaneId": 23, + "egressLaneId": 12 + } + }, + { + "type": "Feature", + "id": "22-13", + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0915548, + 39.5954372 + ], + [ + -105.0915804, + 39.5950941 + ] + ] + }, + "properties": { + "signalGroupId": 2, + "ingressLaneId": 22, + "egressLaneId": 13 + } + }, + { + "type": "Feature", + "id": "21-20", + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0916048, + 39.5954391 + ], + [ + -105.0916734, + 39.5953755 + ] + ] + }, + "properties": { + "ingressLaneId": 21, + "egressLaneId": 20 + } + }, + { + "type": "Feature", + "id": "24-6", + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0914747, + 39.5954382 + ], + [ + -105.0911474, + 39.5951732 + ] + ] + }, + "properties": { + "signalGroupId": 5, + "ingressLaneId": 24, + "egressLaneId": 6 + } + }, + { + "type": "Feature", + "id": "25-5", + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0914371, + 39.5954371 + ], + [ + -105.0911474, + 39.5952053 + ] + ] + }, + "properties": { + "signalGroupId": 5, + "ingressLaneId": 25, + "egressLaneId": 5 + } + } + ] + }, + "properties": { + "schemaVersion": 1, + "messageType": "MAP", + "odeReceivedAt": "2025-02-01T00:36:23.542Z", + "originIp": "172.20.0.1", + "intersectionId": 12110, + "msgIssueRevision": 0, + "revision": 0, + "refPoint": { + "latitude": 39.5952649, + "longitude": -105.0914122, + "elevation": 1677 + }, + "cti4501Conformant": false, + "validationMessages": [ + { + "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[2].connectsTo.connectsTo[0].signalGroup: is missing but it is required", + "jsonPath": "$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[2].connectsTo.connectsTo[0]", + "schemaPath": "#/$defs/J2735Connection/required" + }, + { + "message": "$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[4].maneuvers: is missing but it is required", + "jsonPath": "$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[4]", + "schemaPath": "#/$defs/J2735GenericLane/required" + }, + { + "message": "$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[4].connectsTo: is missing but it is required", + "jsonPath": "$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[4]", + "schemaPath": "#/$defs/J2735GenericLane/required" + }, + { + "message": "$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[5].maneuvers: is missing but it is required", + "jsonPath": "$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[5]", + "schemaPath": "#/$defs/J2735GenericLane/required" + }, + { + "message": "$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[5].connectsTo: is missing but it is required", + "jsonPath": "$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[5]", + "schemaPath": "#/$defs/J2735GenericLane/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[12].connectsTo.connectsTo[0].signalGroup: is missing but it is required", + "jsonPath": "$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[12].connectsTo.connectsTo[0]", + "schemaPath": "#/$defs/J2735Connection/required" + }, + { + "message": "$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[16].connectsTo.connectsTo[0].signalGroup: is missing but it is required", + "jsonPath": "$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[16].connectsTo.connectsTo[0]", + "schemaPath": "#/$defs/J2735Connection/required" + }, + { + "message": "$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[17].maneuvers: is missing but it is required", + "jsonPath": "$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[17]", + "schemaPath": "#/$defs/J2735GenericLane/required" + }, + { + "message": "$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[17].connectsTo: is missing but it is required", + "jsonPath": "$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[17]", + "schemaPath": "#/$defs/J2735GenericLane/required" + }, + { + "message": "$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[18].maneuvers: is missing but it is required", + "jsonPath": "$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[18]", + "schemaPath": "#/$defs/J2735GenericLane/required" + }, + { + "message": "$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[18].connectsTo: is missing but it is required", + "jsonPath": "$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[18]", + "schemaPath": "#/$defs/J2735GenericLane/required" + }, + { + "message": "$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[19].maneuvers: is missing but it is required", + "jsonPath": "$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[19]", + "schemaPath": "#/$defs/J2735GenericLane/required" + }, + { + "message": "$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[19].connectsTo: is missing but it is required", + "jsonPath": "$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[19]", + "schemaPath": "#/$defs/J2735GenericLane/required" + }, + { + "message": "$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[22].connectsTo.connectsTo[0].signalGroup: is missing but it is required", + "jsonPath": "$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[22].connectsTo.connectsTo[0]", + "schemaPath": "#/$defs/J2735Connection/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[27].maneuvers: is missing but it is required", + "jsonPath": "$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[27]", + "schemaPath": "#/$defs/J2735GenericLane/required" + }, + { + "message": "$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[27].connectsTo: is missing but it is required", + "jsonPath": "$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[27]", + "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": "2025-02-01T00:36:23.542Z" + } + } \ No newline at end of file diff --git a/jpo-deduplicator/src/test/resources/json/processed_map/sample.processed_map-reference.json b/jpo-deduplicator/src/test/resources/json/processed_map/sample.processed_map-reference.json new file mode 100644 index 0000000..fdf4a97 --- /dev/null +++ b/jpo-deduplicator/src/test/resources/json/processed_map/sample.processed_map-reference.json @@ -0,0 +1,3443 @@ +{ + "mapFeatureCollection": { + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "id": 2, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0911523, + 39.5953376 + ], + [ + -105.0899239, + 39.5953231 + ], + [ + -105.0896005, + 39.5953332 + ], + [ + -105.0888831, + 39.595317 + ], + [ + -105.088108, + 39.5953159 + ], + [ + -105.0876637, + 39.5953153 + ] + ] + }, + "properties": { + "nodes": [ + { + "delta": [ + 2225, + 808 + ], + "delevation": -10 + }, + { + "delta": [ + 10517, + -161 + ], + "delevation": -60 + }, + { + "delta": [ + 2769, + 112 + ], + "delevation": -10 + }, + { + "delta": [ + 6142, + -180 + ], + "delevation": -30 + }, + { + "delta": [ + 6636, + -12 + ], + "delevation": -20 + }, + { + "delta": [ + 3804, + -7 + ] + } + ], + "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": 19, + "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": 4, + "connectionID": 1 + } + ] + } + }, + { + "type": "Feature", + "id": 3, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0911527, + 39.5953113 + ], + [ + -105.0908101, + 39.5953039 + ], + [ + -105.0900791, + 39.5952962 + ], + [ + -105.0896801, + 39.5952874 + ], + [ + -105.0888781, + 39.5952839 + ], + [ + -105.0885678, + 39.5952789 + ], + [ + -105.0880704, + 39.5952849 + ], + [ + -105.0876638, + 39.5952849 + ] + ] + }, + "properties": { + "nodes": [ + { + "delta": [ + 2222, + 515 + ], + "delevation": -10 + }, + { + "delta": [ + 2933, + -82 + ], + "delevation": -10 + }, + { + "delta": [ + 6259, + -85 + ], + "delevation": -40 + }, + { + "delta": [ + 3416, + -98 + ], + "delevation": -20 + }, + { + "delta": [ + 6867, + -39 + ], + "delevation": -30 + }, + { + "delta": [ + 2657, + -55 + ], + "delevation": -10 + }, + { + "delta": [ + 4259, + 67 + ], + "delevation": -10 + }, + { + "delta": [ + 3481, + 0 + ] + } + ], + "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": 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": 18, + "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": 4, + "connectionID": 1 + } + ] + } + }, + { + "type": "Feature", + "id": 1, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0911535, + 39.5953745 + ], + [ + -105.0899328, + 39.5953544 + ], + [ + -105.0897165, + 39.5953447 + ] + ] + }, + "properties": { + "nodes": [ + { + "delta": [ + 2215, + 1218 + ] + }, + { + "delta": [ + 10451, + -223 + ], + "delevation": -70 + }, + { + "delta": [ + 1852, + -108 + ], + "delevation": -10 + } + ], + "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": 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": 28, + "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": 4, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0911537, + 39.5952537 + ], + [ + -105.0903143, + 39.5952555 + ], + [ + -105.0902511, + 39.5952591 + ], + [ + -105.0900995, + 39.5952797 + ] + ] + }, + "properties": { + "nodes": [ + { + "delta": [ + 2213, + -124 + ], + "delevation": -10 + }, + { + "delta": [ + 7187, + 20 + ], + "delevation": -40 + }, + { + "delta": [ + 541, + 40 + ], + "delevation": -10 + }, + { + "delta": [ + 1298, + 229 + ] + } + ], + "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": 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": 12, + "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": 7, + "connectionID": 1 + } + ] + } + }, + { + "type": "Feature", + "id": 6, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0911474, + 39.5951732 + ], + [ + -105.0911048, + 39.5951738 + ] + ] + }, + "properties": { + "nodes": [ + { + "delta": [ + 2267, + -1019 + ], + "delevation": -10 + }, + { + "delta": [ + 365, + 7 + ] + } + ], + "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.0911474, + 39.5952053 + ], + [ + -105.0911079, + 39.5952053 + ] + ] + }, + "properties": { + "nodes": [ + { + "delta": [ + 2267, + -662 + ], + "delevation": -10 + }, + { + "delta": [ + 338, + 0 + ] + } + ], + "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": 7, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0911443, + 39.5951332 + ], + [ + -105.0911017, + 39.5951356 + ] + ] + }, + "properties": { + "nodes": [ + { + "delta": [ + 2294, + -1463 + ], + "delevation": -10 + }, + { + "delta": [ + 365, + 27 + ] + } + ], + "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": 2, + "ingressApproach": 0, + "ingressPath": false, + "egressPath": true + } + }, + { + "type": "Feature", + "id": 12, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0915234, + 39.5950941 + ], + [ + -105.0915234, + 39.5950602 + ] + ] + }, + "properties": { + "nodes": [ + { + "delta": [ + -952, + -1898 + ] + }, + { + "delta": [ + 0, + -377 + ] + } + ], + "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": 4, + "ingressApproach": 0, + "ingressPath": false, + "egressPath": true + } + }, + { + "type": "Feature", + "id": 13, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0915804, + 39.5950941 + ], + [ + -105.0915796, + 39.595059 + ], + [ + -105.0915796, + 39.595059 + ], + [ + -105.0915796, + 39.5950596 + ] + ] + }, + "properties": { + "nodes": [ + { + "delta": [ + -1440, + -1898 + ] + }, + { + "delta": [ + 7, + -390 + ] + }, + { + "delta": [ + 0, + 0 + ] + }, + { + "delta": [ + 0, + 7 + ] + } + ], + "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": 4, + "ingressApproach": 0, + "ingressPath": false, + "egressPath": true + } + }, + { + "type": "Feature", + "id": 10, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0913299, + 39.5950922 + ], + [ + -105.09133, + 39.5944158 + ], + [ + -105.0913348, + 39.5939413 + ], + [ + -105.0913368, + 39.592921 + ], + [ + -105.0913348, + 39.5923866 + ], + [ + -105.0913348, + 39.5923866 + ], + [ + -105.0913356, + 39.592386 + ] + ] + }, + "properties": { + "nodes": [ + { + "delta": [ + 705, + -1919 + ] + }, + { + "delta": [ + -1, + -7515 + ], + "delevation": -40 + }, + { + "delta": [ + -41, + -5272 + ], + "delevation": 10 + }, + { + "delta": [ + -17, + -11337 + ] + }, + { + "delta": [ + 17, + -5938 + ], + "delevation": 10 + }, + { + "delta": [ + 0, + 0 + ] + }, + { + "delta": [ + -7, + -7 + ] + } + ], + "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": 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": 26, + "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": 9, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0912849, + 39.5950912 + ], + [ + -105.0912838, + 39.5946624 + ], + [ + -105.0912861, + 39.5940862 + ], + [ + -105.0912901, + 39.5933704 + ], + [ + -105.0912882, + 39.5923858 + ] + ] + }, + "properties": { + "nodes": [ + { + "delta": [ + 1090, + -1930 + ], + "delevation": -10 + }, + { + "delta": [ + 9, + -4764 + ], + "delevation": -10 + }, + { + "delta": [ + -20, + -6402 + ], + "delevation": -20 + }, + { + "delta": [ + -34, + -7953 + ], + "delevation": -10 + }, + { + "delta": [ + 16, + -10940 + ], + "delevation": 20 + } + ], + "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": 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": 27, + "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.0913713, + 39.5950916 + ], + [ + -105.091375, + 39.5944888 + ], + [ + -105.0913568, + 39.5942534 + ] + ] + }, + "properties": { + "nodes": [ + { + "delta": [ + 350, + -1925 + ] + }, + { + "delta": [ + -32, + -6698 + ], + "delevation": -30 + }, + { + "delta": [ + 156, + -2616 + ] + } + ], + "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": 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": 18, + "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": 1, + "connectionID": 1 + } + ] + } + }, + { + "type": "Feature", + "id": 8, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0912303, + 39.5950889 + ], + [ + -105.0912421, + 39.5949129 + ], + [ + -105.0912427, + 39.5942475 + ], + [ + -105.0912568, + 39.5941003 + ] + ] + }, + "properties": { + "nodes": [ + { + "delta": [ + 1557, + -1956 + ], + "delevation": -10 + }, + { + "delta": [ + -101, + -1956 + ] + }, + { + "delta": [ + -5, + -7393 + ], + "delevation": -40 + }, + { + "delta": [ + -121, + -1636 + ] + } + ], + "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": 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 + } + }, + "connectionID": 1 + } + ] + } + }, + { + "type": "Feature", + "id": 15, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0916931, + 39.5951733 + ], + [ + -105.0927839, + 39.5951756 + ], + [ + -105.0941732, + 39.5951722 + ], + [ + -105.0952027, + 39.5951734 + ] + ] + }, + "properties": { + "nodes": [ + { + "delta": [ + -2405, + -1018 + ], + "delevation": 10 + }, + { + "delta": [ + -9339, + 26 + ], + "delevation": 30 + }, + { + "delta": [ + -11895, + -38 + ], + "delevation": 50 + }, + { + "delta": [ + -8814, + 13 + ] + } + ], + "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": 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 + } + }, + "signalGroup": 8, + "connectionID": 1 + } + ] + } + }, + { + "type": "Feature", + "id": 16, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0916852, + 39.5952059 + ], + [ + -105.0931135, + 39.5952073 + ], + [ + -105.0944406, + 39.595204 + ], + [ + -105.0952041, + 39.5952041 + ] + ] + }, + "properties": { + "nodes": [ + { + "delta": [ + -2337, + -656 + ], + "delevation": 10 + }, + { + "delta": [ + -12229, + 15 + ], + "delevation": 50 + }, + { + "delta": [ + -11362, + -37 + ], + "delevation": 30 + }, + { + "delta": [ + -6537, + 1 + ] + } + ], + "laneId": 16, + "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": 8, + "connectionID": 1 + } + ] + } + }, + { + "type": "Feature", + "id": 17, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0916853, + 39.5952393 + ], + [ + -105.0927239, + 39.5952377 + ], + [ + -105.0941207, + 39.5952375 + ], + [ + -105.0943034, + 39.5952213 + ] + ] + }, + "properties": { + "nodes": [ + { + "delta": [ + -2338, + -284 + ], + "delevation": 10 + }, + { + "delta": [ + -8892, + -18 + ], + "delevation": 30 + }, + { + "delta": [ + -11959, + -2 + ], + "delevation": 50 + }, + { + "delta": [ + -1564, + -180 + ] + } + ], + "laneId": 17, + "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": true, + "maneuverUTurnAllowed": false, + "maneuverLeftTurnOnRedAllowed": false, + "reserved1": false, + "maneuverRightAllowed": false, + "maneuverLaneChangeAllowed": false, + "yieldAllwaysRequired": false, + "maneuverRightTurnOnRedAllowed": false, + "caution": false + }, + "connectsTo": [ + { + "connectingLane": { + "lane": 26, + "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": 3, + "connectionID": 1 + } + ] + } + }, + { + "type": "Feature", + "id": 14, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0916926, + 39.5951407 + ], + [ + -105.0940224, + 39.5951414 + ], + [ + -105.095203, + 39.5951408 + ] + ] + }, + "properties": { + "nodes": [ + { + "delta": [ + -2401, + -1380 + ], + "delevation": 10 + }, + { + "delta": [ + -19947, + 8 + ], + "delevation": 80 + }, + { + "delta": [ + -10108, + -7 + ] + } + ], + "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": 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": 13, + "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": 18, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0916766, + 39.595308 + ], + [ + -105.0917443, + 39.5953067 + ] + ] + }, + "properties": { + "nodes": [ + { + "delta": [ + -2264, + 479 + ], + "delevation": 20 + }, + { + "delta": [ + -580, + -14 + ] + } + ], + "laneId": 18, + "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": 19, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0916758, + 39.5953365 + ], + [ + -105.0917363, + 39.5953365 + ] + ] + }, + "properties": { + "nodes": [ + { + "delta": [ + -2257, + 796 + ], + "delevation": 20 + }, + { + "delta": [ + -518, + 0 + ] + } + ], + "laneId": 19, + "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": 20, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0916734, + 39.5953755 + ], + [ + -105.0917299, + 39.5953755 + ] + ] + }, + "properties": { + "nodes": [ + { + "delta": [ + -2236, + 1229 + ], + "delevation": 20 + }, + { + "delta": [ + -484, + 0 + ] + } + ], + "laneId": 20, + "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": 23, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.091519, + 39.5954362 + ], + [ + -105.0914927, + 39.5965421 + ], + [ + -105.091488, + 39.5974092 + ], + [ + -105.0914843, + 39.5981324 + ], + [ + -105.0914843, + 39.5981324 + ], + [ + -105.0914851, + 39.5981349 + ] + ] + }, + "properties": { + "nodes": [ + { + "delta": [ + -914, + 1903 + ], + "delevation": 20 + }, + { + "delta": [ + 225, + 12288 + ], + "delevation": 30 + }, + { + "delta": [ + 40, + 9634 + ], + "delevation": -20 + }, + { + "delta": [ + 32, + 8035 + ], + "delevation": -30 + }, + { + "delta": [ + 0, + 0 + ] + }, + { + "delta": [ + -7, + 28 + ] + } + ], + "laneId": 23, + "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": 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": 12, + "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": 22, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0915548, + 39.5954372 + ], + [ + -105.0915441, + 39.59638 + ], + [ + -105.0915337, + 39.5974224 + ], + [ + -105.0915281, + 39.5981345 + ] + ] + }, + "properties": { + "nodes": [ + { + "delta": [ + -1221, + 1914 + ], + "delevation": 20 + }, + { + "delta": [ + 92, + 10475 + ], + "delevation": 30 + }, + { + "delta": [ + 89, + 11582 + ], + "delevation": -20 + }, + { + "delta": [ + 48, + 7912 + ], + "delevation": -30 + } + ], + "laneId": 22, + "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": 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": 13, + "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": 21, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0916048, + 39.5954391 + ], + [ + -105.0916029, + 39.5957255 + ], + [ + -105.0916004, + 39.5962647 + ], + [ + -105.0915885, + 39.5966976 + ], + [ + -105.0915786, + 39.5977599 + ], + [ + -105.0915764, + 39.5981344 + ] + ] + }, + "properties": { + "nodes": [ + { + "delta": [ + -1649, + 1935 + ], + "delevation": 20 + }, + { + "delta": [ + 16, + 3182 + ], + "delevation": 10 + }, + { + "delta": [ + 21, + 5991 + ], + "delevation": 20 + }, + { + "delta": [ + 102, + 4810 + ] + }, + { + "delta": [ + 85, + 11803 + ], + "delevation": -30 + }, + { + "delta": [ + 19, + 4161 + ], + "delevation": -20 + } + ], + "laneId": 21, + "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": 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": 20, + "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": 24, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0914747, + 39.5954382 + ], + [ + -105.0914714, + 39.5958506 + ], + [ + -105.0914611, + 39.596192 + ], + [ + -105.0914778, + 39.5963599 + ] + ] + }, + "properties": { + "nodes": [ + { + "delta": [ + -535, + 1926 + ], + "delevation": 20 + }, + { + "delta": [ + 28, + 4582 + ], + "delevation": 10 + }, + { + "delta": [ + 88, + 3793 + ], + "delevation": 10 + }, + { + "delta": [ + -143, + 1866 + ], + "delevation": 10 + } + ], + "laneId": 24, + "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": 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 + } + }, + "signalGroup": 5, + "connectionID": 1 + } + ] + } + }, + { + "type": "Feature", + "id": 25, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0914371, + 39.5954371 + ], + [ + -105.0914355, + 39.5958506 + ], + [ + -105.0914461, + 39.596052 + ] + ] + }, + "properties": { + "nodes": [ + { + "delta": [ + -213, + 1913 + ], + "delevation": 20 + }, + { + "delta": [ + 14, + 4594 + ], + "delevation": 10 + }, + { + "delta": [ + -91, + 2238 + ], + "delevation": 10 + } + ], + "laneId": 25, + "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": 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": 5, + "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": 5, + "connectionID": 1 + } + ] + } + }, + { + "type": "Feature", + "id": 26, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0913276, + 39.5954361 + ], + [ + -105.0913284, + 39.5954678 + ] + ] + }, + "properties": { + "nodes": [ + { + "delta": [ + 724, + 1902 + ], + "delevation": 10 + }, + { + "delta": [ + -7, + 352 + ], + "delevation": 10 + } + ], + "laneId": 26, + "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": 8, + "ingressApproach": 0, + "ingressPath": false, + "egressPath": true + } + }, + { + "type": "Feature", + "id": 27, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0912831, + 39.5954348 + ], + [ + -105.0912839, + 39.5954647 + ] + ] + }, + "properties": { + "nodes": [ + { + "delta": [ + 1105, + 1888 + ], + "delevation": 10 + }, + { + "delta": [ + -7, + 332 + ], + "delevation": 10 + } + ], + "laneId": 27, + "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": 8, + "ingressApproach": 0, + "ingressPath": false, + "egressPath": true + } + }, + { + "type": "Feature", + "id": 28, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0912264, + 39.5954336 + ], + [ + -105.091228, + 39.5954647 + ], + [ + -105.091228, + 39.5954653 + ] + ] + }, + "properties": { + "nodes": [ + { + "delta": [ + 1591, + 1874 + ], + "delevation": 10 + }, + { + "delta": [ + -14, + 346 + ] + }, + { + "delta": [ + 0, + 7 + ] + } + ], + "laneId": 28, + "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": 8, + "ingressApproach": 0, + "ingressPath": false, + "egressPath": true + } + } + ] + }, + "connectingLanesFeatureCollection": { + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "id": "2-19", + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0911523, + 39.5953376 + ], + [ + -105.0916758, + 39.5953365 + ] + ] + }, + "properties": { + "signalGroupId": 4, + "ingressLaneId": 2, + "egressLaneId": 19 + } + }, + { + "type": "Feature", + "id": "3-18", + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0911527, + 39.5953113 + ], + [ + -105.0916766, + 39.595308 + ] + ] + }, + "properties": { + "signalGroupId": 4, + "ingressLaneId": 3, + "egressLaneId": 18 + } + }, + { + "type": "Feature", + "id": "1-28", + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0911535, + 39.5953745 + ], + [ + -105.0912264, + 39.5954336 + ] + ] + }, + "properties": { + "ingressLaneId": 1, + "egressLaneId": 28 + } + }, + { + "type": "Feature", + "id": "4-12", + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0911537, + 39.5952537 + ], + [ + -105.0915234, + 39.5950941 + ] + ] + }, + "properties": { + "signalGroupId": 7, + "ingressLaneId": 4, + "egressLaneId": 12 + } + }, + { + "type": "Feature", + "id": "10-26", + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0913299, + 39.5950922 + ], + [ + -105.0913276, + 39.5954361 + ] + ] + }, + "properties": { + "signalGroupId": 6, + "ingressLaneId": 10, + "egressLaneId": 26 + } + }, + { + "type": "Feature", + "id": "9-27", + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0912849, + 39.5950912 + ], + [ + -105.0912831, + 39.5954348 + ] + ] + }, + "properties": { + "signalGroupId": 6, + "ingressLaneId": 9, + "egressLaneId": 27 + } + }, + { + "type": "Feature", + "id": "11-18", + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0913713, + 39.5950916 + ], + [ + -105.0916766, + 39.595308 + ] + ] + }, + "properties": { + "signalGroupId": 1, + "ingressLaneId": 11, + "egressLaneId": 18 + } + }, + { + "type": "Feature", + "id": "8-7", + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0912303, + 39.5950889 + ], + [ + -105.0911443, + 39.5951332 + ] + ] + }, + "properties": { + "ingressLaneId": 8, + "egressLaneId": 7 + } + }, + { + "type": "Feature", + "id": "15-6", + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0916931, + 39.5951733 + ], + [ + -105.0911474, + 39.5951732 + ] + ] + }, + "properties": { + "signalGroupId": 8, + "ingressLaneId": 15, + "egressLaneId": 6 + } + }, + { + "type": "Feature", + "id": "16-5", + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0916852, + 39.5952059 + ], + [ + -105.0911474, + 39.5952053 + ] + ] + }, + "properties": { + "signalGroupId": 8, + "ingressLaneId": 16, + "egressLaneId": 5 + } + }, + { + "type": "Feature", + "id": "17-26", + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0916853, + 39.5952393 + ], + [ + -105.0913276, + 39.5954361 + ] + ] + }, + "properties": { + "signalGroupId": 3, + "ingressLaneId": 17, + "egressLaneId": 26 + } + }, + { + "type": "Feature", + "id": "14-13", + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0916926, + 39.5951407 + ], + [ + -105.0915804, + 39.5950941 + ] + ] + }, + "properties": { + "ingressLaneId": 14, + "egressLaneId": 13 + } + }, + { + "type": "Feature", + "id": "23-12", + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.091519, + 39.5954362 + ], + [ + -105.0915234, + 39.5950941 + ] + ] + }, + "properties": { + "signalGroupId": 2, + "ingressLaneId": 23, + "egressLaneId": 12 + } + }, + { + "type": "Feature", + "id": "22-13", + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0915548, + 39.5954372 + ], + [ + -105.0915804, + 39.5950941 + ] + ] + }, + "properties": { + "signalGroupId": 2, + "ingressLaneId": 22, + "egressLaneId": 13 + } + }, + { + "type": "Feature", + "id": "21-20", + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0916048, + 39.5954391 + ], + [ + -105.0916734, + 39.5953755 + ] + ] + }, + "properties": { + "ingressLaneId": 21, + "egressLaneId": 20 + } + }, + { + "type": "Feature", + "id": "24-6", + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0914747, + 39.5954382 + ], + [ + -105.0911474, + 39.5951732 + ] + ] + }, + "properties": { + "signalGroupId": 5, + "ingressLaneId": 24, + "egressLaneId": 6 + } + }, + { + "type": "Feature", + "id": "25-5", + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -105.0914371, + 39.5954371 + ], + [ + -105.0911474, + 39.5952053 + ] + ] + }, + "properties": { + "signalGroupId": 5, + "ingressLaneId": 25, + "egressLaneId": 5 + } + } + ] + }, + "properties": { + "schemaVersion": 1, + "messageType": "MAP", + "odeReceivedAt": "2025-01-31T23:36:23.542Z", + "originIp": "172.20.0.1", + "intersectionId": 12110, + "msgIssueRevision": 0, + "revision": 0, + "refPoint": { + "latitude": 39.5952649, + "longitude": -105.0914122, + "elevation": 1677 + }, + "cti4501Conformant": false, + "validationMessages": [ + { + "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[2].connectsTo.connectsTo[0].signalGroup: is missing but it is required", + "jsonPath": "$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[2].connectsTo.connectsTo[0]", + "schemaPath": "#/$defs/J2735Connection/required" + }, + { + "message": "$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[4].maneuvers: is missing but it is required", + "jsonPath": "$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[4]", + "schemaPath": "#/$defs/J2735GenericLane/required" + }, + { + "message": "$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[4].connectsTo: is missing but it is required", + "jsonPath": "$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[4]", + "schemaPath": "#/$defs/J2735GenericLane/required" + }, + { + "message": "$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[5].maneuvers: is missing but it is required", + "jsonPath": "$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[5]", + "schemaPath": "#/$defs/J2735GenericLane/required" + }, + { + "message": "$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[5].connectsTo: is missing but it is required", + "jsonPath": "$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[5]", + "schemaPath": "#/$defs/J2735GenericLane/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[12].connectsTo.connectsTo[0].signalGroup: is missing but it is required", + "jsonPath": "$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[12].connectsTo.connectsTo[0]", + "schemaPath": "#/$defs/J2735Connection/required" + }, + { + "message": "$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[16].connectsTo.connectsTo[0].signalGroup: is missing but it is required", + "jsonPath": "$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[16].connectsTo.connectsTo[0]", + "schemaPath": "#/$defs/J2735Connection/required" + }, + { + "message": "$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[17].maneuvers: is missing but it is required", + "jsonPath": "$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[17]", + "schemaPath": "#/$defs/J2735GenericLane/required" + }, + { + "message": "$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[17].connectsTo: is missing but it is required", + "jsonPath": "$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[17]", + "schemaPath": "#/$defs/J2735GenericLane/required" + }, + { + "message": "$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[18].maneuvers: is missing but it is required", + "jsonPath": "$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[18]", + "schemaPath": "#/$defs/J2735GenericLane/required" + }, + { + "message": "$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[18].connectsTo: is missing but it is required", + "jsonPath": "$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[18]", + "schemaPath": "#/$defs/J2735GenericLane/required" + }, + { + "message": "$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[19].maneuvers: is missing but it is required", + "jsonPath": "$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[19]", + "schemaPath": "#/$defs/J2735GenericLane/required" + }, + { + "message": "$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[19].connectsTo: is missing but it is required", + "jsonPath": "$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[19]", + "schemaPath": "#/$defs/J2735GenericLane/required" + }, + { + "message": "$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[22].connectsTo.connectsTo[0].signalGroup: is missing but it is required", + "jsonPath": "$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[22].connectsTo.connectsTo[0]", + "schemaPath": "#/$defs/J2735Connection/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[27].maneuvers: is missing but it is required", + "jsonPath": "$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[27]", + "schemaPath": "#/$defs/J2735GenericLane/required" + }, + { + "message": "$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[27].connectsTo: is missing but it is required", + "jsonPath": "$.payload.data.intersections.intersectionGeometry[0].laneSet.GenericLane[27]", + "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": "2025-01-31T23:36:23.542Z" + } + } \ No newline at end of file diff --git a/jpo-deduplicator/src/test/resources/json/processed_map_wkt/sample.processed_map_wkt-different.json b/jpo-deduplicator/src/test/resources/json/processed_map_wkt/sample.processed_map_wkt-different.json new file mode 100644 index 0000000..b8616d4 --- /dev/null +++ b/jpo-deduplicator/src/test/resources/json/processed_map_wkt/sample.processed_map_wkt-different.json @@ -0,0 +1,1829 @@ +{ + "mapFeatureCollection": { + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "id": 2, + "geometry": "LINESTRING (-105.0911523 39.5953376, -105.0899239 39.5953231, -105.0896005 39.5953332, -105.0888831 39.595317, -105.088108 39.5953159, -105.0876637 39.5953153)", + "properties": { + "laneId": 2, + "laneType": { + "vehicle": { + "isVehicleRevocableLane": false, + "isVehicleFlyOverLane": false, + "permissionOnRequest": false, + "hasIRbeaconCoverage": false, + "restrictedToBusUse": false, + "restrictedToTaxiUse": false, + "restrictedFromPublicUse": false, + "hovLaneUseOnly": false + } + }, + "sharedWith": { + "busVehicleTraffic": false, + "trackedVehicleTraffic": false, + "individualMotorizedVehicleTraffic": false, + "taxiVehicleTraffic": false, + "overlappingLaneDescriptionProvided": false, + "cyclistVehicleTraffic": false, + "otherNonMotorizedTrafficTypes": false, + "multipleLanesTreatedAsOneLane": false, + "pedestrianTraffic": false, + "pedestriansTraffic": false + }, + "egressApproach": 0, + "ingressApproach": 1, + "ingressPath": true, + "egressPath": false, + "maneuvers": { + "maneuverStraightAllowed": true, + "maneuverNoStoppingAllowed": false, + "goWithHalt": false, + "maneuverLeftAllowed": false, + "maneuverUTurnAllowed": false, + "maneuverLeftTurnOnRedAllowed": false, + "reserved1": false, + "maneuverRightAllowed": false, + "maneuverLaneChangeAllowed": false, + "yieldAllwaysRequired": false, + "maneuverRightTurnOnRedAllowed": false, + "caution": false + }, + "connectsTo": [ + { + "connectingLane": { + "lane": 19, + "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": 4, + "connectionID": 1 + } + ] + } + }, + { + "type": "Feature", + "id": 3, + "geometry": "LINESTRING (-105.0911527 39.5953113, -105.0908101 39.5953039, -105.0900791 39.5952962, -105.0896801 39.5952874, -105.0888781 39.5952839, -105.0885678 39.5952789, -105.0880704 39.5952849, -105.0876638 39.5952849)", + "properties": { + "laneId": 3, + "laneType": { + "vehicle": { + "isVehicleRevocableLane": false, + "isVehicleFlyOverLane": false, + "permissionOnRequest": false, + "hasIRbeaconCoverage": false, + "restrictedToBusUse": false, + "restrictedToTaxiUse": false, + "restrictedFromPublicUse": false, + "hovLaneUseOnly": false + } + }, + "sharedWith": { + "busVehicleTraffic": false, + "trackedVehicleTraffic": false, + "individualMotorizedVehicleTraffic": false, + "taxiVehicleTraffic": false, + "overlappingLaneDescriptionProvided": false, + "cyclistVehicleTraffic": false, + "otherNonMotorizedTrafficTypes": false, + "multipleLanesTreatedAsOneLane": false, + "pedestrianTraffic": false, + "pedestriansTraffic": false + }, + "egressApproach": 0, + "ingressApproach": 1, + "ingressPath": true, + "egressPath": false, + "maneuvers": { + "maneuverStraightAllowed": 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": 18, + "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": 4, + "connectionID": 1 + } + ] + } + }, + { + "type": "Feature", + "id": 1, + "geometry": "LINESTRING (-105.0911535 39.5953745, -105.0899328 39.5953544, -105.0897165 39.5953447)", + "properties": { + "laneId": 1, + "laneType": { + "vehicle": { + "isVehicleRevocableLane": false, + "isVehicleFlyOverLane": false, + "permissionOnRequest": false, + "hasIRbeaconCoverage": false, + "restrictedToBusUse": false, + "restrictedToTaxiUse": false, + "restrictedFromPublicUse": false, + "hovLaneUseOnly": false + } + }, + "sharedWith": { + "busVehicleTraffic": false, + "trackedVehicleTraffic": false, + "individualMotorizedVehicleTraffic": false, + "taxiVehicleTraffic": false, + "overlappingLaneDescriptionProvided": false, + "cyclistVehicleTraffic": false, + "otherNonMotorizedTrafficTypes": false, + "multipleLanesTreatedAsOneLane": false, + "pedestrianTraffic": false, + "pedestriansTraffic": false + }, + "egressApproach": 0, + "ingressApproach": 1, + "ingressPath": true, + "egressPath": false, + "maneuvers": { + "maneuverStraightAllowed": 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": 28, + "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": 4, + "geometry": "LINESTRING (-105.0911537 39.5952537, -105.0903143 39.5952555, -105.0902511 39.5952591, -105.0900995 39.5952797)", + "properties": { + "laneId": 4, + "laneType": { + "vehicle": { + "isVehicleRevocableLane": false, + "isVehicleFlyOverLane": false, + "permissionOnRequest": false, + "hasIRbeaconCoverage": false, + "restrictedToBusUse": false, + "restrictedToTaxiUse": false, + "restrictedFromPublicUse": false, + "hovLaneUseOnly": false + } + }, + "sharedWith": { + "busVehicleTraffic": false, + "trackedVehicleTraffic": false, + "individualMotorizedVehicleTraffic": false, + "taxiVehicleTraffic": false, + "overlappingLaneDescriptionProvided": false, + "cyclistVehicleTraffic": false, + "otherNonMotorizedTrafficTypes": false, + "multipleLanesTreatedAsOneLane": false, + "pedestrianTraffic": false, + "pedestriansTraffic": false + }, + "egressApproach": 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": 12, + "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": 7, + "connectionID": 1 + } + ] + } + }, + { + "type": "Feature", + "id": 6, + "geometry": "LINESTRING (-105.0911474 39.5951732, -105.0911048 39.5951738)", + "properties": { + "laneId": 6, + "laneType": { + "vehicle": { + "isVehicleRevocableLane": false, + "isVehicleFlyOverLane": false, + "permissionOnRequest": false, + "hasIRbeaconCoverage": false, + "restrictedToBusUse": false, + "restrictedToTaxiUse": false, + "restrictedFromPublicUse": false, + "hovLaneUseOnly": false + } + }, + "sharedWith": { + "busVehicleTraffic": false, + "trackedVehicleTraffic": false, + "individualMotorizedVehicleTraffic": false, + "taxiVehicleTraffic": false, + "overlappingLaneDescriptionProvided": false, + "cyclistVehicleTraffic": false, + "otherNonMotorizedTrafficTypes": false, + "multipleLanesTreatedAsOneLane": false, + "pedestrianTraffic": false, + "pedestriansTraffic": false + }, + "egressApproach": 2, + "ingressApproach": 0, + "ingressPath": false, + "egressPath": true + } + }, + { + "type": "Feature", + "id": 5, + "geometry": "LINESTRING (-105.0911474 39.5952053, -105.0911079 39.5952053)", + "properties": { + "laneId": 5, + "laneType": { + "vehicle": { + "isVehicleRevocableLane": false, + "isVehicleFlyOverLane": false, + "permissionOnRequest": false, + "hasIRbeaconCoverage": false, + "restrictedToBusUse": false, + "restrictedToTaxiUse": false, + "restrictedFromPublicUse": false, + "hovLaneUseOnly": false + } + }, + "sharedWith": { + "busVehicleTraffic": false, + "trackedVehicleTraffic": false, + "individualMotorizedVehicleTraffic": false, + "taxiVehicleTraffic": false, + "overlappingLaneDescriptionProvided": false, + "cyclistVehicleTraffic": false, + "otherNonMotorizedTrafficTypes": false, + "multipleLanesTreatedAsOneLane": false, + "pedestrianTraffic": false, + "pedestriansTraffic": false + }, + "egressApproach": 2, + "ingressApproach": 0, + "ingressPath": false, + "egressPath": true + } + }, + { + "type": "Feature", + "id": 7, + "geometry": "LINESTRING (-105.0911443 39.5951332, -105.0911017 39.5951356)", + "properties": { + "laneId": 7, + "laneType": { + "vehicle": { + "isVehicleRevocableLane": false, + "isVehicleFlyOverLane": false, + "permissionOnRequest": false, + "hasIRbeaconCoverage": false, + "restrictedToBusUse": false, + "restrictedToTaxiUse": false, + "restrictedFromPublicUse": false, + "hovLaneUseOnly": false + } + }, + "sharedWith": { + "busVehicleTraffic": false, + "trackedVehicleTraffic": false, + "individualMotorizedVehicleTraffic": false, + "taxiVehicleTraffic": false, + "overlappingLaneDescriptionProvided": false, + "cyclistVehicleTraffic": false, + "otherNonMotorizedTrafficTypes": false, + "multipleLanesTreatedAsOneLane": false, + "pedestrianTraffic": false, + "pedestriansTraffic": false + }, + "egressApproach": 2, + "ingressApproach": 0, + "ingressPath": false, + "egressPath": true + } + }, + { + "type": "Feature", + "id": 12, + "geometry": "LINESTRING (-105.0915234 39.5950941, -105.0915234 39.5950602)", + "properties": { + "laneId": 12, + "laneType": { + "vehicle": { + "isVehicleRevocableLane": false, + "isVehicleFlyOverLane": false, + "permissionOnRequest": false, + "hasIRbeaconCoverage": false, + "restrictedToBusUse": false, + "restrictedToTaxiUse": false, + "restrictedFromPublicUse": false, + "hovLaneUseOnly": false + } + }, + "sharedWith": { + "busVehicleTraffic": false, + "trackedVehicleTraffic": false, + "individualMotorizedVehicleTraffic": false, + "taxiVehicleTraffic": false, + "overlappingLaneDescriptionProvided": false, + "cyclistVehicleTraffic": false, + "otherNonMotorizedTrafficTypes": false, + "multipleLanesTreatedAsOneLane": false, + "pedestrianTraffic": false, + "pedestriansTraffic": false + }, + "egressApproach": 4, + "ingressApproach": 0, + "ingressPath": false, + "egressPath": true + } + }, + { + "type": "Feature", + "id": 13, + "geometry": "LINESTRING (-105.0915804 39.5950941, -105.0915796 39.595059, -105.0915796 39.595059, -105.0915796 39.5950596)", + "properties": { + "laneId": 13, + "laneType": { + "vehicle": { + "isVehicleRevocableLane": false, + "isVehicleFlyOverLane": false, + "permissionOnRequest": false, + "hasIRbeaconCoverage": false, + "restrictedToBusUse": false, + "restrictedToTaxiUse": false, + "restrictedFromPublicUse": false, + "hovLaneUseOnly": false + } + }, + "sharedWith": { + "busVehicleTraffic": false, + "trackedVehicleTraffic": false, + "individualMotorizedVehicleTraffic": false, + "taxiVehicleTraffic": false, + "overlappingLaneDescriptionProvided": false, + "cyclistVehicleTraffic": false, + "otherNonMotorizedTrafficTypes": false, + "multipleLanesTreatedAsOneLane": false, + "pedestrianTraffic": false, + "pedestriansTraffic": false + }, + "egressApproach": 4, + "ingressApproach": 0, + "ingressPath": false, + "egressPath": true + } + }, + { + "type": "Feature", + "id": 10, + "geometry": "LINESTRING (-105.0913299 39.5950922, -105.09133 39.5944158, -105.0913348 39.5939413, -105.0913368 39.592921, -105.0913348 39.5923866, -105.0913348 39.5923866, -105.0913356 39.592386)", + "properties": { + "laneId": 10, + "laneType": { + "vehicle": { + "isVehicleRevocableLane": false, + "isVehicleFlyOverLane": false, + "permissionOnRequest": false, + "hasIRbeaconCoverage": false, + "restrictedToBusUse": false, + "restrictedToTaxiUse": false, + "restrictedFromPublicUse": false, + "hovLaneUseOnly": false + } + }, + "sharedWith": { + "busVehicleTraffic": false, + "trackedVehicleTraffic": false, + "individualMotorizedVehicleTraffic": false, + "taxiVehicleTraffic": false, + "overlappingLaneDescriptionProvided": false, + "cyclistVehicleTraffic": false, + "otherNonMotorizedTrafficTypes": false, + "multipleLanesTreatedAsOneLane": false, + "pedestrianTraffic": false, + "pedestriansTraffic": false + }, + "egressApproach": 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": 26, + "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": 9, + "geometry": "LINESTRING (-105.0912849 39.5950912, -105.0912838 39.5946624, -105.0912861 39.5940862, -105.0912901 39.5933704, -105.0912882 39.5923858)", + "properties": { + "laneId": 9, + "laneType": { + "vehicle": { + "isVehicleRevocableLane": false, + "isVehicleFlyOverLane": false, + "permissionOnRequest": false, + "hasIRbeaconCoverage": false, + "restrictedToBusUse": false, + "restrictedToTaxiUse": false, + "restrictedFromPublicUse": false, + "hovLaneUseOnly": false + } + }, + "sharedWith": { + "busVehicleTraffic": false, + "trackedVehicleTraffic": false, + "individualMotorizedVehicleTraffic": false, + "taxiVehicleTraffic": false, + "overlappingLaneDescriptionProvided": false, + "cyclistVehicleTraffic": false, + "otherNonMotorizedTrafficTypes": false, + "multipleLanesTreatedAsOneLane": false, + "pedestrianTraffic": false, + "pedestriansTraffic": false + }, + "egressApproach": 0, + "ingressApproach": 3, + "ingressPath": true, + "egressPath": false, + "maneuvers": { + "maneuverStraightAllowed": 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": 27, + "maneuver": { + "maneuverStraightAllowed": true, + "maneuverNoStoppingAllowed": false, + "goWithHalt": false, + "maneuverLeftAllowed": false, + "maneuverUTurnAllowed": false, + "maneuverLeftTurnOnRedAllowed": false, + "reserved1": false, + "maneuverRightAllowed": false, + "maneuverLaneChangeAllowed": false, + "yieldAllwaysRequired": false, + "maneuverRightTurnOnRedAllowed": false, + "caution": false + } + }, + "signalGroup": 6, + "connectionID": 1 + } + ] + } + }, + { + "type": "Feature", + "id": 11, + "geometry": "LINESTRING (-105.0913713 39.5950916, -105.091375 39.5944888, -105.0913568 39.5942534)", + "properties": { + "laneId": 11, + "laneType": { + "vehicle": { + "isVehicleRevocableLane": false, + "isVehicleFlyOverLane": false, + "permissionOnRequest": false, + "hasIRbeaconCoverage": false, + "restrictedToBusUse": false, + "restrictedToTaxiUse": false, + "restrictedFromPublicUse": false, + "hovLaneUseOnly": false + } + }, + "sharedWith": { + "busVehicleTraffic": false, + "trackedVehicleTraffic": false, + "individualMotorizedVehicleTraffic": false, + "taxiVehicleTraffic": false, + "overlappingLaneDescriptionProvided": false, + "cyclistVehicleTraffic": false, + "otherNonMotorizedTrafficTypes": false, + "multipleLanesTreatedAsOneLane": false, + "pedestrianTraffic": false, + "pedestriansTraffic": false + }, + "egressApproach": 0, + "ingressApproach": 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": 18, + "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": 1, + "connectionID": 1 + } + ] + } + }, + { + "type": "Feature", + "id": 8, + "geometry": "LINESTRING (-105.0912303 39.5950889, -105.0912421 39.5949129, -105.0912427 39.5942475, -105.0912568 39.5941003)", + "properties": { + "laneId": 8, + "laneType": { + "vehicle": { + "isVehicleRevocableLane": false, + "isVehicleFlyOverLane": false, + "permissionOnRequest": false, + "hasIRbeaconCoverage": false, + "restrictedToBusUse": false, + "restrictedToTaxiUse": false, + "restrictedFromPublicUse": false, + "hovLaneUseOnly": false + } + }, + "sharedWith": { + "busVehicleTraffic": false, + "trackedVehicleTraffic": false, + "individualMotorizedVehicleTraffic": false, + "taxiVehicleTraffic": false, + "overlappingLaneDescriptionProvided": false, + "cyclistVehicleTraffic": false, + "otherNonMotorizedTrafficTypes": false, + "multipleLanesTreatedAsOneLane": false, + "pedestrianTraffic": false, + "pedestriansTraffic": false + }, + "egressApproach": 0, + "ingressApproach": 3, + "ingressPath": true, + "egressPath": false, + "maneuvers": { + "maneuverStraightAllowed": false, + "maneuverNoStoppingAllowed": false, + "goWithHalt": false, + "maneuverLeftAllowed": 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 + } + }, + "connectionID": 1 + } + ] + } + }, + { + "type": "Feature", + "id": 15, + "geometry": "LINESTRING (-105.0916931 39.5951733, -105.0927839 39.5951756, -105.0941732 39.5951722, -105.0952027 39.5951734)", + "properties": { + "laneId": 15, + "laneType": { + "vehicle": { + "isVehicleRevocableLane": false, + "isVehicleFlyOverLane": false, + "permissionOnRequest": false, + "hasIRbeaconCoverage": false, + "restrictedToBusUse": false, + "restrictedToTaxiUse": false, + "restrictedFromPublicUse": false, + "hovLaneUseOnly": false + } + }, + "sharedWith": { + "busVehicleTraffic": false, + "trackedVehicleTraffic": false, + "individualMotorizedVehicleTraffic": false, + "taxiVehicleTraffic": false, + "overlappingLaneDescriptionProvided": false, + "cyclistVehicleTraffic": false, + "otherNonMotorizedTrafficTypes": false, + "multipleLanesTreatedAsOneLane": false, + "pedestrianTraffic": false, + "pedestriansTraffic": false + }, + "egressApproach": 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 + } + }, + "signalGroup": 8, + "connectionID": 1 + } + ] + } + }, + { + "type": "Feature", + "id": 16, + "geometry": "LINESTRING (-105.0916852 39.5952059, -105.0931135 39.5952073, -105.0944406 39.595204, -105.0952041 39.5952041)", + "properties": { + "laneId": 16, + "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": 8, + "connectionID": 1 + } + ] + } + }, + { + "type": "Feature", + "id": 17, + "geometry": "LINESTRING (-105.0916853 39.5952393, -105.0927239 39.5952377, -105.0941207 39.5952375, -105.0943034 39.5952213)", + "properties": { + "laneId": 17, + "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": true, + "maneuverUTurnAllowed": false, + "maneuverLeftTurnOnRedAllowed": false, + "reserved1": false, + "maneuverRightAllowed": false, + "maneuverLaneChangeAllowed": false, + "yieldAllwaysRequired": false, + "maneuverRightTurnOnRedAllowed": false, + "caution": false + }, + "connectsTo": [ + { + "connectingLane": { + "lane": 26, + "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": 3, + "connectionID": 1 + } + ] + } + }, + { + "type": "Feature", + "id": 14, + "geometry": "LINESTRING (-105.0916926 39.5951407, -105.0940224 39.5951414, -105.095203 39.5951408)", + "properties": { + "laneId": 14, + "laneType": { + "vehicle": { + "isVehicleRevocableLane": false, + "isVehicleFlyOverLane": false, + "permissionOnRequest": false, + "hasIRbeaconCoverage": false, + "restrictedToBusUse": false, + "restrictedToTaxiUse": false, + "restrictedFromPublicUse": false, + "hovLaneUseOnly": false + } + }, + "sharedWith": { + "busVehicleTraffic": false, + "trackedVehicleTraffic": false, + "individualMotorizedVehicleTraffic": false, + "taxiVehicleTraffic": false, + "overlappingLaneDescriptionProvided": false, + "cyclistVehicleTraffic": false, + "otherNonMotorizedTrafficTypes": false, + "multipleLanesTreatedAsOneLane": false, + "pedestrianTraffic": false, + "pedestriansTraffic": false + }, + "egressApproach": 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": 13, + "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": 18, + "geometry": "LINESTRING (-105.0916766 39.595308, -105.0917443 39.5953067)", + "properties": { + "laneId": 18, + "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": 19, + "geometry": "LINESTRING (-105.0916758 39.5953365, -105.0917363 39.5953365)", + "properties": { + "laneId": 19, + "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": 20, + "geometry": "LINESTRING (-105.0916734 39.5953755, -105.0917299 39.5953755)", + "properties": { + "laneId": 20, + "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": 23, + "geometry": "LINESTRING (-105.091519 39.5954362, -105.0914927 39.5965421, -105.091488 39.5974092, -105.0914843 39.5981324, -105.0914843 39.5981324, -105.0914851 39.5981349)", + "properties": { + "laneId": 23, + "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": 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": 12, + "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": 22, + "geometry": "LINESTRING (-105.0915548 39.5954372, -105.0915441 39.59638, -105.0915337 39.5974224, -105.0915281 39.5981345)", + "properties": { + "laneId": 22, + "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": 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": 13, + "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": 21, + "geometry": "LINESTRING (-105.0916048 39.5954391, -105.0916029 39.5957255, -105.0916004 39.5962647, -105.0915885 39.5966976, -105.0915786 39.5977599, -105.0915764 39.5981344)", + "properties": { + "laneId": 21, + "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": 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": 20, + "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": 24, + "geometry": "LINESTRING (-105.0914747 39.5954382, -105.0914714 39.5958506, -105.0914611 39.596192, -105.0914778 39.5963599)", + "properties": { + "laneId": 24, + "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": 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 + } + }, + "signalGroup": 5, + "connectionID": 1 + } + ] + } + }, + { + "type": "Feature", + "id": 25, + "geometry": "LINESTRING (-105.0914371 39.5954371, -105.0914355 39.5958506, -105.0914461 39.596052)", + "properties": { + "laneId": 25, + "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": 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": 5, + "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": 5, + "connectionID": 1 + } + ] + } + }, + { + "type": "Feature", + "id": 26, + "geometry": "LINESTRING (-105.0913276 39.5954361, -105.0913284 39.5954678)", + "properties": { + "laneId": 26, + "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": 8, + "ingressApproach": 0, + "ingressPath": false, + "egressPath": true + } + }, + { + "type": "Feature", + "id": 27, + "geometry": "LINESTRING (-105.0912831 39.5954348, -105.0912839 39.5954647)", + "properties": { + "laneId": 27, + "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": 8, + "ingressApproach": 0, + "ingressPath": false, + "egressPath": true + } + }, + { + "type": "Feature", + "id": 28, + "geometry": "LINESTRING (-105.0912264 39.5954336, -105.091228 39.5954647, -105.091228 39.5954653)", + "properties": { + "laneId": 28, + "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": 8, + "ingressApproach": 0, + "ingressPath": false, + "egressPath": true + } + } + ] + }, + "connectingLanesFeatureCollection": { + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "id": "2-19", + "geometry": "LINESTRING (-105.0911523 39.5953376, -105.0916758 39.5953365)", + "properties": { + "signalGroupId": 4, + "ingressLaneId": 2, + "egressLaneId": 19 + } + }, + { + "type": "Feature", + "id": "3-18", + "geometry": "LINESTRING (-105.0911527 39.5953113, -105.0916766 39.595308)", + "properties": { + "signalGroupId": 4, + "ingressLaneId": 3, + "egressLaneId": 18 + } + }, + { + "type": "Feature", + "id": "1-28", + "geometry": "LINESTRING (-105.0911535 39.5953745, -105.0912264 39.5954336)", + "properties": { + "ingressLaneId": 1, + "egressLaneId": 28 + } + }, + { + "type": "Feature", + "id": "4-12", + "geometry": "LINESTRING (-105.0911537 39.5952537, -105.0915234 39.5950941)", + "properties": { + "signalGroupId": 7, + "ingressLaneId": 4, + "egressLaneId": 12 + } + }, + { + "type": "Feature", + "id": "10-26", + "geometry": "LINESTRING (-105.0913299 39.5950922, -105.0913276 39.5954361)", + "properties": { + "signalGroupId": 6, + "ingressLaneId": 10, + "egressLaneId": 26 + } + }, + { + "type": "Feature", + "id": "9-27", + "geometry": "LINESTRING (-105.0912849 39.5950912, -105.0912831 39.5954348)", + "properties": { + "signalGroupId": 6, + "ingressLaneId": 9, + "egressLaneId": 27 + } + }, + { + "type": "Feature", + "id": "11-18", + "geometry": "LINESTRING (-105.0913713 39.5950916, -105.0916766 39.595308)", + "properties": { + "signalGroupId": 1, + "ingressLaneId": 11, + "egressLaneId": 18 + } + }, + { + "type": "Feature", + "id": "8-7", + "geometry": "LINESTRING (-105.0912303 39.5950889, -105.0911443 39.5951332)", + "properties": { + "ingressLaneId": 8, + "egressLaneId": 7 + } + }, + { + "type": "Feature", + "id": "15-6", + "geometry": "LINESTRING (-105.0916931 39.5951733, -105.0911474 39.5951732)", + "properties": { + "signalGroupId": 8, + "ingressLaneId": 15, + "egressLaneId": 6 + } + }, + { + "type": "Feature", + "id": "16-5", + "geometry": "LINESTRING (-105.0916852 39.5952059, -105.0911474 39.5952053)", + "properties": { + "signalGroupId": 8, + "ingressLaneId": 16, + "egressLaneId": 5 + } + }, + { + "type": "Feature", + "id": "17-26", + "geometry": "LINESTRING (-105.0916853 39.5952393, -105.0913276 39.5954361)", + "properties": { + "signalGroupId": 3, + "ingressLaneId": 17, + "egressLaneId": 26 + } + }, + { + "type": "Feature", + "id": "14-13", + "geometry": "LINESTRING (-105.0916926 39.5951407, -105.0915804 39.5950941)", + "properties": { + "ingressLaneId": 14, + "egressLaneId": 13 + } + }, + { + "type": "Feature", + "id": "23-12", + "geometry": "LINESTRING (-105.091519 39.5954362, -105.0915234 39.5950941)", + "properties": { + "signalGroupId": 2, + "ingressLaneId": 23, + "egressLaneId": 12 + } + }, + { + "type": "Feature", + "id": "22-13", + "geometry": "LINESTRING (-105.0915548 39.5954372, -105.0915804 39.5950941)", + "properties": { + "signalGroupId": 2, + "ingressLaneId": 22, + "egressLaneId": 13 + } + }, + { + "type": "Feature", + "id": "21-20", + "geometry": "LINESTRING (-105.0916048 39.5954391, -105.0916734 39.5953755)", + "properties": { + "ingressLaneId": 21, + "egressLaneId": 20 + } + }, + { + "type": "Feature", + "id": "24-6", + "geometry": "LINESTRING (-105.0914747 39.5954382, -105.0911474 39.5951732)", + "properties": { + "signalGroupId": 5, + "ingressLaneId": 24, + "egressLaneId": 6 + } + }, + { + "type": "Feature", + "id": "25-5", + "geometry": "LINESTRING (-105.0914371 39.5954371, -105.0911474 39.5952053)", + "properties": { + "signalGroupId": 5, + "ingressLaneId": 25, + "egressLaneId": 5 + } + } + ] + }, + "properties": { + "schemaVersion": 1, + "messageType": "MAP", + "odeReceivedAt": "2025-01-31T23:50:49.19Z", + "originIp": "172.20.0.1", + "intersectionId": 13110, + "msgIssueRevision": 0, + "revision": 0, + "refPoint": { + "latitude": 39.5952649, + "longitude": -105.0914122, + "elevation": 1677 + }, + "cti4501Conformant": false, + "laneWidth": 366, + "mapSource": "RSU", + "timeStamp": "2025-01-31T23:50:49.19Z" + } + } \ No newline at end of file diff --git a/jpo-deduplicator/src/test/resources/json/processed_map_wkt/sample.processed_map_wkt-reference-1-hour-later.json b/jpo-deduplicator/src/test/resources/json/processed_map_wkt/sample.processed_map_wkt-reference-1-hour-later.json new file mode 100644 index 0000000..90dad7d --- /dev/null +++ b/jpo-deduplicator/src/test/resources/json/processed_map_wkt/sample.processed_map_wkt-reference-1-hour-later.json @@ -0,0 +1,1829 @@ +{ + "mapFeatureCollection": { + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "id": 2, + "geometry": "LINESTRING (-105.0911523 39.5953376, -105.0899239 39.5953231, -105.0896005 39.5953332, -105.0888831 39.595317, -105.088108 39.5953159, -105.0876637 39.5953153)", + "properties": { + "laneId": 2, + "laneType": { + "vehicle": { + "isVehicleRevocableLane": false, + "isVehicleFlyOverLane": false, + "permissionOnRequest": false, + "hasIRbeaconCoverage": false, + "restrictedToBusUse": false, + "restrictedToTaxiUse": false, + "restrictedFromPublicUse": false, + "hovLaneUseOnly": false + } + }, + "sharedWith": { + "busVehicleTraffic": false, + "trackedVehicleTraffic": false, + "individualMotorizedVehicleTraffic": false, + "taxiVehicleTraffic": false, + "overlappingLaneDescriptionProvided": false, + "cyclistVehicleTraffic": false, + "otherNonMotorizedTrafficTypes": false, + "multipleLanesTreatedAsOneLane": false, + "pedestrianTraffic": false, + "pedestriansTraffic": false + }, + "egressApproach": 0, + "ingressApproach": 1, + "ingressPath": true, + "egressPath": false, + "maneuvers": { + "maneuverStraightAllowed": true, + "maneuverNoStoppingAllowed": false, + "goWithHalt": false, + "maneuverLeftAllowed": false, + "maneuverUTurnAllowed": false, + "maneuverLeftTurnOnRedAllowed": false, + "reserved1": false, + "maneuverRightAllowed": false, + "maneuverLaneChangeAllowed": false, + "yieldAllwaysRequired": false, + "maneuverRightTurnOnRedAllowed": false, + "caution": false + }, + "connectsTo": [ + { + "connectingLane": { + "lane": 19, + "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": 4, + "connectionID": 1 + } + ] + } + }, + { + "type": "Feature", + "id": 3, + "geometry": "LINESTRING (-105.0911527 39.5953113, -105.0908101 39.5953039, -105.0900791 39.5952962, -105.0896801 39.5952874, -105.0888781 39.5952839, -105.0885678 39.5952789, -105.0880704 39.5952849, -105.0876638 39.5952849)", + "properties": { + "laneId": 3, + "laneType": { + "vehicle": { + "isVehicleRevocableLane": false, + "isVehicleFlyOverLane": false, + "permissionOnRequest": false, + "hasIRbeaconCoverage": false, + "restrictedToBusUse": false, + "restrictedToTaxiUse": false, + "restrictedFromPublicUse": false, + "hovLaneUseOnly": false + } + }, + "sharedWith": { + "busVehicleTraffic": false, + "trackedVehicleTraffic": false, + "individualMotorizedVehicleTraffic": false, + "taxiVehicleTraffic": false, + "overlappingLaneDescriptionProvided": false, + "cyclistVehicleTraffic": false, + "otherNonMotorizedTrafficTypes": false, + "multipleLanesTreatedAsOneLane": false, + "pedestrianTraffic": false, + "pedestriansTraffic": false + }, + "egressApproach": 0, + "ingressApproach": 1, + "ingressPath": true, + "egressPath": false, + "maneuvers": { + "maneuverStraightAllowed": 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": 18, + "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": 4, + "connectionID": 1 + } + ] + } + }, + { + "type": "Feature", + "id": 1, + "geometry": "LINESTRING (-105.0911535 39.5953745, -105.0899328 39.5953544, -105.0897165 39.5953447)", + "properties": { + "laneId": 1, + "laneType": { + "vehicle": { + "isVehicleRevocableLane": false, + "isVehicleFlyOverLane": false, + "permissionOnRequest": false, + "hasIRbeaconCoverage": false, + "restrictedToBusUse": false, + "restrictedToTaxiUse": false, + "restrictedFromPublicUse": false, + "hovLaneUseOnly": false + } + }, + "sharedWith": { + "busVehicleTraffic": false, + "trackedVehicleTraffic": false, + "individualMotorizedVehicleTraffic": false, + "taxiVehicleTraffic": false, + "overlappingLaneDescriptionProvided": false, + "cyclistVehicleTraffic": false, + "otherNonMotorizedTrafficTypes": false, + "multipleLanesTreatedAsOneLane": false, + "pedestrianTraffic": false, + "pedestriansTraffic": false + }, + "egressApproach": 0, + "ingressApproach": 1, + "ingressPath": true, + "egressPath": false, + "maneuvers": { + "maneuverStraightAllowed": 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": 28, + "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": 4, + "geometry": "LINESTRING (-105.0911537 39.5952537, -105.0903143 39.5952555, -105.0902511 39.5952591, -105.0900995 39.5952797)", + "properties": { + "laneId": 4, + "laneType": { + "vehicle": { + "isVehicleRevocableLane": false, + "isVehicleFlyOverLane": false, + "permissionOnRequest": false, + "hasIRbeaconCoverage": false, + "restrictedToBusUse": false, + "restrictedToTaxiUse": false, + "restrictedFromPublicUse": false, + "hovLaneUseOnly": false + } + }, + "sharedWith": { + "busVehicleTraffic": false, + "trackedVehicleTraffic": false, + "individualMotorizedVehicleTraffic": false, + "taxiVehicleTraffic": false, + "overlappingLaneDescriptionProvided": false, + "cyclistVehicleTraffic": false, + "otherNonMotorizedTrafficTypes": false, + "multipleLanesTreatedAsOneLane": false, + "pedestrianTraffic": false, + "pedestriansTraffic": false + }, + "egressApproach": 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": 12, + "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": 7, + "connectionID": 1 + } + ] + } + }, + { + "type": "Feature", + "id": 6, + "geometry": "LINESTRING (-105.0911474 39.5951732, -105.0911048 39.5951738)", + "properties": { + "laneId": 6, + "laneType": { + "vehicle": { + "isVehicleRevocableLane": false, + "isVehicleFlyOverLane": false, + "permissionOnRequest": false, + "hasIRbeaconCoverage": false, + "restrictedToBusUse": false, + "restrictedToTaxiUse": false, + "restrictedFromPublicUse": false, + "hovLaneUseOnly": false + } + }, + "sharedWith": { + "busVehicleTraffic": false, + "trackedVehicleTraffic": false, + "individualMotorizedVehicleTraffic": false, + "taxiVehicleTraffic": false, + "overlappingLaneDescriptionProvided": false, + "cyclistVehicleTraffic": false, + "otherNonMotorizedTrafficTypes": false, + "multipleLanesTreatedAsOneLane": false, + "pedestrianTraffic": false, + "pedestriansTraffic": false + }, + "egressApproach": 2, + "ingressApproach": 0, + "ingressPath": false, + "egressPath": true + } + }, + { + "type": "Feature", + "id": 5, + "geometry": "LINESTRING (-105.0911474 39.5952053, -105.0911079 39.5952053)", + "properties": { + "laneId": 5, + "laneType": { + "vehicle": { + "isVehicleRevocableLane": false, + "isVehicleFlyOverLane": false, + "permissionOnRequest": false, + "hasIRbeaconCoverage": false, + "restrictedToBusUse": false, + "restrictedToTaxiUse": false, + "restrictedFromPublicUse": false, + "hovLaneUseOnly": false + } + }, + "sharedWith": { + "busVehicleTraffic": false, + "trackedVehicleTraffic": false, + "individualMotorizedVehicleTraffic": false, + "taxiVehicleTraffic": false, + "overlappingLaneDescriptionProvided": false, + "cyclistVehicleTraffic": false, + "otherNonMotorizedTrafficTypes": false, + "multipleLanesTreatedAsOneLane": false, + "pedestrianTraffic": false, + "pedestriansTraffic": false + }, + "egressApproach": 2, + "ingressApproach": 0, + "ingressPath": false, + "egressPath": true + } + }, + { + "type": "Feature", + "id": 7, + "geometry": "LINESTRING (-105.0911443 39.5951332, -105.0911017 39.5951356)", + "properties": { + "laneId": 7, + "laneType": { + "vehicle": { + "isVehicleRevocableLane": false, + "isVehicleFlyOverLane": false, + "permissionOnRequest": false, + "hasIRbeaconCoverage": false, + "restrictedToBusUse": false, + "restrictedToTaxiUse": false, + "restrictedFromPublicUse": false, + "hovLaneUseOnly": false + } + }, + "sharedWith": { + "busVehicleTraffic": false, + "trackedVehicleTraffic": false, + "individualMotorizedVehicleTraffic": false, + "taxiVehicleTraffic": false, + "overlappingLaneDescriptionProvided": false, + "cyclistVehicleTraffic": false, + "otherNonMotorizedTrafficTypes": false, + "multipleLanesTreatedAsOneLane": false, + "pedestrianTraffic": false, + "pedestriansTraffic": false + }, + "egressApproach": 2, + "ingressApproach": 0, + "ingressPath": false, + "egressPath": true + } + }, + { + "type": "Feature", + "id": 12, + "geometry": "LINESTRING (-105.0915234 39.5950941, -105.0915234 39.5950602)", + "properties": { + "laneId": 12, + "laneType": { + "vehicle": { + "isVehicleRevocableLane": false, + "isVehicleFlyOverLane": false, + "permissionOnRequest": false, + "hasIRbeaconCoverage": false, + "restrictedToBusUse": false, + "restrictedToTaxiUse": false, + "restrictedFromPublicUse": false, + "hovLaneUseOnly": false + } + }, + "sharedWith": { + "busVehicleTraffic": false, + "trackedVehicleTraffic": false, + "individualMotorizedVehicleTraffic": false, + "taxiVehicleTraffic": false, + "overlappingLaneDescriptionProvided": false, + "cyclistVehicleTraffic": false, + "otherNonMotorizedTrafficTypes": false, + "multipleLanesTreatedAsOneLane": false, + "pedestrianTraffic": false, + "pedestriansTraffic": false + }, + "egressApproach": 4, + "ingressApproach": 0, + "ingressPath": false, + "egressPath": true + } + }, + { + "type": "Feature", + "id": 13, + "geometry": "LINESTRING (-105.0915804 39.5950941, -105.0915796 39.595059, -105.0915796 39.595059, -105.0915796 39.5950596)", + "properties": { + "laneId": 13, + "laneType": { + "vehicle": { + "isVehicleRevocableLane": false, + "isVehicleFlyOverLane": false, + "permissionOnRequest": false, + "hasIRbeaconCoverage": false, + "restrictedToBusUse": false, + "restrictedToTaxiUse": false, + "restrictedFromPublicUse": false, + "hovLaneUseOnly": false + } + }, + "sharedWith": { + "busVehicleTraffic": false, + "trackedVehicleTraffic": false, + "individualMotorizedVehicleTraffic": false, + "taxiVehicleTraffic": false, + "overlappingLaneDescriptionProvided": false, + "cyclistVehicleTraffic": false, + "otherNonMotorizedTrafficTypes": false, + "multipleLanesTreatedAsOneLane": false, + "pedestrianTraffic": false, + "pedestriansTraffic": false + }, + "egressApproach": 4, + "ingressApproach": 0, + "ingressPath": false, + "egressPath": true + } + }, + { + "type": "Feature", + "id": 10, + "geometry": "LINESTRING (-105.0913299 39.5950922, -105.09133 39.5944158, -105.0913348 39.5939413, -105.0913368 39.592921, -105.0913348 39.5923866, -105.0913348 39.5923866, -105.0913356 39.592386)", + "properties": { + "laneId": 10, + "laneType": { + "vehicle": { + "isVehicleRevocableLane": false, + "isVehicleFlyOverLane": false, + "permissionOnRequest": false, + "hasIRbeaconCoverage": false, + "restrictedToBusUse": false, + "restrictedToTaxiUse": false, + "restrictedFromPublicUse": false, + "hovLaneUseOnly": false + } + }, + "sharedWith": { + "busVehicleTraffic": false, + "trackedVehicleTraffic": false, + "individualMotorizedVehicleTraffic": false, + "taxiVehicleTraffic": false, + "overlappingLaneDescriptionProvided": false, + "cyclistVehicleTraffic": false, + "otherNonMotorizedTrafficTypes": false, + "multipleLanesTreatedAsOneLane": false, + "pedestrianTraffic": false, + "pedestriansTraffic": false + }, + "egressApproach": 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": 26, + "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": 9, + "geometry": "LINESTRING (-105.0912849 39.5950912, -105.0912838 39.5946624, -105.0912861 39.5940862, -105.0912901 39.5933704, -105.0912882 39.5923858)", + "properties": { + "laneId": 9, + "laneType": { + "vehicle": { + "isVehicleRevocableLane": false, + "isVehicleFlyOverLane": false, + "permissionOnRequest": false, + "hasIRbeaconCoverage": false, + "restrictedToBusUse": false, + "restrictedToTaxiUse": false, + "restrictedFromPublicUse": false, + "hovLaneUseOnly": false + } + }, + "sharedWith": { + "busVehicleTraffic": false, + "trackedVehicleTraffic": false, + "individualMotorizedVehicleTraffic": false, + "taxiVehicleTraffic": false, + "overlappingLaneDescriptionProvided": false, + "cyclistVehicleTraffic": false, + "otherNonMotorizedTrafficTypes": false, + "multipleLanesTreatedAsOneLane": false, + "pedestrianTraffic": false, + "pedestriansTraffic": false + }, + "egressApproach": 0, + "ingressApproach": 3, + "ingressPath": true, + "egressPath": false, + "maneuvers": { + "maneuverStraightAllowed": 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": 27, + "maneuver": { + "maneuverStraightAllowed": true, + "maneuverNoStoppingAllowed": false, + "goWithHalt": false, + "maneuverLeftAllowed": false, + "maneuverUTurnAllowed": false, + "maneuverLeftTurnOnRedAllowed": false, + "reserved1": false, + "maneuverRightAllowed": false, + "maneuverLaneChangeAllowed": false, + "yieldAllwaysRequired": false, + "maneuverRightTurnOnRedAllowed": false, + "caution": false + } + }, + "signalGroup": 6, + "connectionID": 1 + } + ] + } + }, + { + "type": "Feature", + "id": 11, + "geometry": "LINESTRING (-105.0913713 39.5950916, -105.091375 39.5944888, -105.0913568 39.5942534)", + "properties": { + "laneId": 11, + "laneType": { + "vehicle": { + "isVehicleRevocableLane": false, + "isVehicleFlyOverLane": false, + "permissionOnRequest": false, + "hasIRbeaconCoverage": false, + "restrictedToBusUse": false, + "restrictedToTaxiUse": false, + "restrictedFromPublicUse": false, + "hovLaneUseOnly": false + } + }, + "sharedWith": { + "busVehicleTraffic": false, + "trackedVehicleTraffic": false, + "individualMotorizedVehicleTraffic": false, + "taxiVehicleTraffic": false, + "overlappingLaneDescriptionProvided": false, + "cyclistVehicleTraffic": false, + "otherNonMotorizedTrafficTypes": false, + "multipleLanesTreatedAsOneLane": false, + "pedestrianTraffic": false, + "pedestriansTraffic": false + }, + "egressApproach": 0, + "ingressApproach": 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": 18, + "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": 1, + "connectionID": 1 + } + ] + } + }, + { + "type": "Feature", + "id": 8, + "geometry": "LINESTRING (-105.0912303 39.5950889, -105.0912421 39.5949129, -105.0912427 39.5942475, -105.0912568 39.5941003)", + "properties": { + "laneId": 8, + "laneType": { + "vehicle": { + "isVehicleRevocableLane": false, + "isVehicleFlyOverLane": false, + "permissionOnRequest": false, + "hasIRbeaconCoverage": false, + "restrictedToBusUse": false, + "restrictedToTaxiUse": false, + "restrictedFromPublicUse": false, + "hovLaneUseOnly": false + } + }, + "sharedWith": { + "busVehicleTraffic": false, + "trackedVehicleTraffic": false, + "individualMotorizedVehicleTraffic": false, + "taxiVehicleTraffic": false, + "overlappingLaneDescriptionProvided": false, + "cyclistVehicleTraffic": false, + "otherNonMotorizedTrafficTypes": false, + "multipleLanesTreatedAsOneLane": false, + "pedestrianTraffic": false, + "pedestriansTraffic": false + }, + "egressApproach": 0, + "ingressApproach": 3, + "ingressPath": true, + "egressPath": false, + "maneuvers": { + "maneuverStraightAllowed": false, + "maneuverNoStoppingAllowed": false, + "goWithHalt": false, + "maneuverLeftAllowed": 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 + } + }, + "connectionID": 1 + } + ] + } + }, + { + "type": "Feature", + "id": 15, + "geometry": "LINESTRING (-105.0916931 39.5951733, -105.0927839 39.5951756, -105.0941732 39.5951722, -105.0952027 39.5951734)", + "properties": { + "laneId": 15, + "laneType": { + "vehicle": { + "isVehicleRevocableLane": false, + "isVehicleFlyOverLane": false, + "permissionOnRequest": false, + "hasIRbeaconCoverage": false, + "restrictedToBusUse": false, + "restrictedToTaxiUse": false, + "restrictedFromPublicUse": false, + "hovLaneUseOnly": false + } + }, + "sharedWith": { + "busVehicleTraffic": false, + "trackedVehicleTraffic": false, + "individualMotorizedVehicleTraffic": false, + "taxiVehicleTraffic": false, + "overlappingLaneDescriptionProvided": false, + "cyclistVehicleTraffic": false, + "otherNonMotorizedTrafficTypes": false, + "multipleLanesTreatedAsOneLane": false, + "pedestrianTraffic": false, + "pedestriansTraffic": false + }, + "egressApproach": 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 + } + }, + "signalGroup": 8, + "connectionID": 1 + } + ] + } + }, + { + "type": "Feature", + "id": 16, + "geometry": "LINESTRING (-105.0916852 39.5952059, -105.0931135 39.5952073, -105.0944406 39.595204, -105.0952041 39.5952041)", + "properties": { + "laneId": 16, + "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": 8, + "connectionID": 1 + } + ] + } + }, + { + "type": "Feature", + "id": 17, + "geometry": "LINESTRING (-105.0916853 39.5952393, -105.0927239 39.5952377, -105.0941207 39.5952375, -105.0943034 39.5952213)", + "properties": { + "laneId": 17, + "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": true, + "maneuverUTurnAllowed": false, + "maneuverLeftTurnOnRedAllowed": false, + "reserved1": false, + "maneuverRightAllowed": false, + "maneuverLaneChangeAllowed": false, + "yieldAllwaysRequired": false, + "maneuverRightTurnOnRedAllowed": false, + "caution": false + }, + "connectsTo": [ + { + "connectingLane": { + "lane": 26, + "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": 3, + "connectionID": 1 + } + ] + } + }, + { + "type": "Feature", + "id": 14, + "geometry": "LINESTRING (-105.0916926 39.5951407, -105.0940224 39.5951414, -105.095203 39.5951408)", + "properties": { + "laneId": 14, + "laneType": { + "vehicle": { + "isVehicleRevocableLane": false, + "isVehicleFlyOverLane": false, + "permissionOnRequest": false, + "hasIRbeaconCoverage": false, + "restrictedToBusUse": false, + "restrictedToTaxiUse": false, + "restrictedFromPublicUse": false, + "hovLaneUseOnly": false + } + }, + "sharedWith": { + "busVehicleTraffic": false, + "trackedVehicleTraffic": false, + "individualMotorizedVehicleTraffic": false, + "taxiVehicleTraffic": false, + "overlappingLaneDescriptionProvided": false, + "cyclistVehicleTraffic": false, + "otherNonMotorizedTrafficTypes": false, + "multipleLanesTreatedAsOneLane": false, + "pedestrianTraffic": false, + "pedestriansTraffic": false + }, + "egressApproach": 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": 13, + "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": 18, + "geometry": "LINESTRING (-105.0916766 39.595308, -105.0917443 39.5953067)", + "properties": { + "laneId": 18, + "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": 19, + "geometry": "LINESTRING (-105.0916758 39.5953365, -105.0917363 39.5953365)", + "properties": { + "laneId": 19, + "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": 20, + "geometry": "LINESTRING (-105.0916734 39.5953755, -105.0917299 39.5953755)", + "properties": { + "laneId": 20, + "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": 23, + "geometry": "LINESTRING (-105.091519 39.5954362, -105.0914927 39.5965421, -105.091488 39.5974092, -105.0914843 39.5981324, -105.0914843 39.5981324, -105.0914851 39.5981349)", + "properties": { + "laneId": 23, + "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": 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": 12, + "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": 22, + "geometry": "LINESTRING (-105.0915548 39.5954372, -105.0915441 39.59638, -105.0915337 39.5974224, -105.0915281 39.5981345)", + "properties": { + "laneId": 22, + "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": 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": 13, + "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": 21, + "geometry": "LINESTRING (-105.0916048 39.5954391, -105.0916029 39.5957255, -105.0916004 39.5962647, -105.0915885 39.5966976, -105.0915786 39.5977599, -105.0915764 39.5981344)", + "properties": { + "laneId": 21, + "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": 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": 20, + "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": 24, + "geometry": "LINESTRING (-105.0914747 39.5954382, -105.0914714 39.5958506, -105.0914611 39.596192, -105.0914778 39.5963599)", + "properties": { + "laneId": 24, + "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": 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 + } + }, + "signalGroup": 5, + "connectionID": 1 + } + ] + } + }, + { + "type": "Feature", + "id": 25, + "geometry": "LINESTRING (-105.0914371 39.5954371, -105.0914355 39.5958506, -105.0914461 39.596052)", + "properties": { + "laneId": 25, + "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": 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": 5, + "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": 5, + "connectionID": 1 + } + ] + } + }, + { + "type": "Feature", + "id": 26, + "geometry": "LINESTRING (-105.0913276 39.5954361, -105.0913284 39.5954678)", + "properties": { + "laneId": 26, + "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": 8, + "ingressApproach": 0, + "ingressPath": false, + "egressPath": true + } + }, + { + "type": "Feature", + "id": 27, + "geometry": "LINESTRING (-105.0912831 39.5954348, -105.0912839 39.5954647)", + "properties": { + "laneId": 27, + "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": 8, + "ingressApproach": 0, + "ingressPath": false, + "egressPath": true + } + }, + { + "type": "Feature", + "id": 28, + "geometry": "LINESTRING (-105.0912264 39.5954336, -105.091228 39.5954647, -105.091228 39.5954653)", + "properties": { + "laneId": 28, + "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": 8, + "ingressApproach": 0, + "ingressPath": false, + "egressPath": true + } + } + ] + }, + "connectingLanesFeatureCollection": { + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "id": "2-19", + "geometry": "LINESTRING (-105.0911523 39.5953376, -105.0916758 39.5953365)", + "properties": { + "signalGroupId": 4, + "ingressLaneId": 2, + "egressLaneId": 19 + } + }, + { + "type": "Feature", + "id": "3-18", + "geometry": "LINESTRING (-105.0911527 39.5953113, -105.0916766 39.595308)", + "properties": { + "signalGroupId": 4, + "ingressLaneId": 3, + "egressLaneId": 18 + } + }, + { + "type": "Feature", + "id": "1-28", + "geometry": "LINESTRING (-105.0911535 39.5953745, -105.0912264 39.5954336)", + "properties": { + "ingressLaneId": 1, + "egressLaneId": 28 + } + }, + { + "type": "Feature", + "id": "4-12", + "geometry": "LINESTRING (-105.0911537 39.5952537, -105.0915234 39.5950941)", + "properties": { + "signalGroupId": 7, + "ingressLaneId": 4, + "egressLaneId": 12 + } + }, + { + "type": "Feature", + "id": "10-26", + "geometry": "LINESTRING (-105.0913299 39.5950922, -105.0913276 39.5954361)", + "properties": { + "signalGroupId": 6, + "ingressLaneId": 10, + "egressLaneId": 26 + } + }, + { + "type": "Feature", + "id": "9-27", + "geometry": "LINESTRING (-105.0912849 39.5950912, -105.0912831 39.5954348)", + "properties": { + "signalGroupId": 6, + "ingressLaneId": 9, + "egressLaneId": 27 + } + }, + { + "type": "Feature", + "id": "11-18", + "geometry": "LINESTRING (-105.0913713 39.5950916, -105.0916766 39.595308)", + "properties": { + "signalGroupId": 1, + "ingressLaneId": 11, + "egressLaneId": 18 + } + }, + { + "type": "Feature", + "id": "8-7", + "geometry": "LINESTRING (-105.0912303 39.5950889, -105.0911443 39.5951332)", + "properties": { + "ingressLaneId": 8, + "egressLaneId": 7 + } + }, + { + "type": "Feature", + "id": "15-6", + "geometry": "LINESTRING (-105.0916931 39.5951733, -105.0911474 39.5951732)", + "properties": { + "signalGroupId": 8, + "ingressLaneId": 15, + "egressLaneId": 6 + } + }, + { + "type": "Feature", + "id": "16-5", + "geometry": "LINESTRING (-105.0916852 39.5952059, -105.0911474 39.5952053)", + "properties": { + "signalGroupId": 8, + "ingressLaneId": 16, + "egressLaneId": 5 + } + }, + { + "type": "Feature", + "id": "17-26", + "geometry": "LINESTRING (-105.0916853 39.5952393, -105.0913276 39.5954361)", + "properties": { + "signalGroupId": 3, + "ingressLaneId": 17, + "egressLaneId": 26 + } + }, + { + "type": "Feature", + "id": "14-13", + "geometry": "LINESTRING (-105.0916926 39.5951407, -105.0915804 39.5950941)", + "properties": { + "ingressLaneId": 14, + "egressLaneId": 13 + } + }, + { + "type": "Feature", + "id": "23-12", + "geometry": "LINESTRING (-105.091519 39.5954362, -105.0915234 39.5950941)", + "properties": { + "signalGroupId": 2, + "ingressLaneId": 23, + "egressLaneId": 12 + } + }, + { + "type": "Feature", + "id": "22-13", + "geometry": "LINESTRING (-105.0915548 39.5954372, -105.0915804 39.5950941)", + "properties": { + "signalGroupId": 2, + "ingressLaneId": 22, + "egressLaneId": 13 + } + }, + { + "type": "Feature", + "id": "21-20", + "geometry": "LINESTRING (-105.0916048 39.5954391, -105.0916734 39.5953755)", + "properties": { + "ingressLaneId": 21, + "egressLaneId": 20 + } + }, + { + "type": "Feature", + "id": "24-6", + "geometry": "LINESTRING (-105.0914747 39.5954382, -105.0911474 39.5951732)", + "properties": { + "signalGroupId": 5, + "ingressLaneId": 24, + "egressLaneId": 6 + } + }, + { + "type": "Feature", + "id": "25-5", + "geometry": "LINESTRING (-105.0914371 39.5954371, -105.0911474 39.5952053)", + "properties": { + "signalGroupId": 5, + "ingressLaneId": 25, + "egressLaneId": 5 + } + } + ] + }, + "properties": { + "schemaVersion": 1, + "messageType": "MAP", + "odeReceivedAt": "2025-02-01T00:50:49.19Z", + "originIp": "172.20.0.1", + "intersectionId": 12110, + "msgIssueRevision": 0, + "revision": 0, + "refPoint": { + "latitude": 39.5952649, + "longitude": -105.0914122, + "elevation": 1677 + }, + "cti4501Conformant": false, + "laneWidth": 366, + "mapSource": "RSU", + "timeStamp": "2025-02-01T00:50:49.19Z" + } + } \ No newline at end of file diff --git a/jpo-deduplicator/src/test/resources/json/processed_map_wkt/sample.processed_map_wkt-reference.json b/jpo-deduplicator/src/test/resources/json/processed_map_wkt/sample.processed_map_wkt-reference.json new file mode 100644 index 0000000..f781ea3 --- /dev/null +++ b/jpo-deduplicator/src/test/resources/json/processed_map_wkt/sample.processed_map_wkt-reference.json @@ -0,0 +1 @@ +{"mapFeatureCollection":{"type":"FeatureCollection","features":[{"type":"Feature","id":2,"geometry":"LINESTRING (-105.0911523 39.5953376, -105.0899239 39.5953231, -105.0896005 39.5953332, -105.0888831 39.595317, -105.088108 39.5953159, -105.0876637 39.5953153)","properties":{"laneId":2,"laneType":{"vehicle":{"isVehicleRevocableLane":false,"isVehicleFlyOverLane":false,"permissionOnRequest":false,"hasIRbeaconCoverage":false,"restrictedToBusUse":false,"restrictedToTaxiUse":false,"restrictedFromPublicUse":false,"hovLaneUseOnly":false}},"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":1,"ingressPath":true,"egressPath":false,"maneuvers":{"maneuverStraightAllowed":true,"maneuverNoStoppingAllowed":false,"goWithHalt":false,"maneuverLeftAllowed":false,"maneuverUTurnAllowed":false,"maneuverLeftTurnOnRedAllowed":false,"reserved1":false,"maneuverRightAllowed":false,"maneuverLaneChangeAllowed":false,"yieldAllwaysRequired":false,"maneuverRightTurnOnRedAllowed":false,"caution":false},"connectsTo":[{"connectingLane":{"lane":19,"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":4,"connectionID":1}]}},{"type":"Feature","id":3,"geometry":"LINESTRING (-105.0911527 39.5953113, -105.0908101 39.5953039, -105.0900791 39.5952962, -105.0896801 39.5952874, -105.0888781 39.5952839, -105.0885678 39.5952789, -105.0880704 39.5952849, -105.0876638 39.5952849)","properties":{"laneId":3,"laneType":{"vehicle":{"isVehicleRevocableLane":false,"isVehicleFlyOverLane":false,"permissionOnRequest":false,"hasIRbeaconCoverage":false,"restrictedToBusUse":false,"restrictedToTaxiUse":false,"restrictedFromPublicUse":false,"hovLaneUseOnly":false}},"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":1,"ingressPath":true,"egressPath":false,"maneuvers":{"maneuverStraightAllowed":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":18,"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":4,"connectionID":1}]}},{"type":"Feature","id":1,"geometry":"LINESTRING (-105.0911535 39.5953745, -105.0899328 39.5953544, -105.0897165 39.5953447)","properties":{"laneId":1,"laneType":{"vehicle":{"isVehicleRevocableLane":false,"isVehicleFlyOverLane":false,"permissionOnRequest":false,"hasIRbeaconCoverage":false,"restrictedToBusUse":false,"restrictedToTaxiUse":false,"restrictedFromPublicUse":false,"hovLaneUseOnly":false}},"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":1,"ingressPath":true,"egressPath":false,"maneuvers":{"maneuverStraightAllowed":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":28,"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":4,"geometry":"LINESTRING (-105.0911537 39.5952537, -105.0903143 39.5952555, -105.0902511 39.5952591, -105.0900995 39.5952797)","properties":{"laneId":4,"laneType":{"vehicle":{"isVehicleRevocableLane":false,"isVehicleFlyOverLane":false,"permissionOnRequest":false,"hasIRbeaconCoverage":false,"restrictedToBusUse":false,"restrictedToTaxiUse":false,"restrictedFromPublicUse":false,"hovLaneUseOnly":false}},"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":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":12,"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":7,"connectionID":1}]}},{"type":"Feature","id":6,"geometry":"LINESTRING (-105.0911474 39.5951732, -105.0911048 39.5951738)","properties":{"laneId":6,"laneType":{"vehicle":{"isVehicleRevocableLane":false,"isVehicleFlyOverLane":false,"permissionOnRequest":false,"hasIRbeaconCoverage":false,"restrictedToBusUse":false,"restrictedToTaxiUse":false,"restrictedFromPublicUse":false,"hovLaneUseOnly":false}},"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":2,"ingressApproach":0,"ingressPath":false,"egressPath":true}},{"type":"Feature","id":5,"geometry":"LINESTRING (-105.0911474 39.5952053, -105.0911079 39.5952053)","properties":{"laneId":5,"laneType":{"vehicle":{"isVehicleRevocableLane":false,"isVehicleFlyOverLane":false,"permissionOnRequest":false,"hasIRbeaconCoverage":false,"restrictedToBusUse":false,"restrictedToTaxiUse":false,"restrictedFromPublicUse":false,"hovLaneUseOnly":false}},"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":2,"ingressApproach":0,"ingressPath":false,"egressPath":true}},{"type":"Feature","id":7,"geometry":"LINESTRING (-105.0911443 39.5951332, -105.0911017 39.5951356)","properties":{"laneId":7,"laneType":{"vehicle":{"isVehicleRevocableLane":false,"isVehicleFlyOverLane":false,"permissionOnRequest":false,"hasIRbeaconCoverage":false,"restrictedToBusUse":false,"restrictedToTaxiUse":false,"restrictedFromPublicUse":false,"hovLaneUseOnly":false}},"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":2,"ingressApproach":0,"ingressPath":false,"egressPath":true}},{"type":"Feature","id":12,"geometry":"LINESTRING (-105.0915234 39.5950941, -105.0915234 39.5950602)","properties":{"laneId":12,"laneType":{"vehicle":{"isVehicleRevocableLane":false,"isVehicleFlyOverLane":false,"permissionOnRequest":false,"hasIRbeaconCoverage":false,"restrictedToBusUse":false,"restrictedToTaxiUse":false,"restrictedFromPublicUse":false,"hovLaneUseOnly":false}},"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":4,"ingressApproach":0,"ingressPath":false,"egressPath":true}},{"type":"Feature","id":13,"geometry":"LINESTRING (-105.0915804 39.5950941, -105.0915796 39.595059, -105.0915796 39.595059, -105.0915796 39.5950596)","properties":{"laneId":13,"laneType":{"vehicle":{"isVehicleRevocableLane":false,"isVehicleFlyOverLane":false,"permissionOnRequest":false,"hasIRbeaconCoverage":false,"restrictedToBusUse":false,"restrictedToTaxiUse":false,"restrictedFromPublicUse":false,"hovLaneUseOnly":false}},"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":4,"ingressApproach":0,"ingressPath":false,"egressPath":true}},{"type":"Feature","id":10,"geometry":"LINESTRING (-105.0913299 39.5950922, -105.09133 39.5944158, -105.0913348 39.5939413, -105.0913368 39.592921, -105.0913348 39.5923866, -105.0913348 39.5923866, -105.0913356 39.592386)","properties":{"laneId":10,"laneType":{"vehicle":{"isVehicleRevocableLane":false,"isVehicleFlyOverLane":false,"permissionOnRequest":false,"hasIRbeaconCoverage":false,"restrictedToBusUse":false,"restrictedToTaxiUse":false,"restrictedFromPublicUse":false,"hovLaneUseOnly":false}},"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":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":26,"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":9,"geometry":"LINESTRING (-105.0912849 39.5950912, -105.0912838 39.5946624, -105.0912861 39.5940862, -105.0912901 39.5933704, -105.0912882 39.5923858)","properties":{"laneId":9,"laneType":{"vehicle":{"isVehicleRevocableLane":false,"isVehicleFlyOverLane":false,"permissionOnRequest":false,"hasIRbeaconCoverage":false,"restrictedToBusUse":false,"restrictedToTaxiUse":false,"restrictedFromPublicUse":false,"hovLaneUseOnly":false}},"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":3,"ingressPath":true,"egressPath":false,"maneuvers":{"maneuverStraightAllowed":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":27,"maneuver":{"maneuverStraightAllowed":true,"maneuverNoStoppingAllowed":false,"goWithHalt":false,"maneuverLeftAllowed":false,"maneuverUTurnAllowed":false,"maneuverLeftTurnOnRedAllowed":false,"reserved1":false,"maneuverRightAllowed":false,"maneuverLaneChangeAllowed":false,"yieldAllwaysRequired":false,"maneuverRightTurnOnRedAllowed":false,"caution":false}},"signalGroup":6,"connectionID":1}]}},{"type":"Feature","id":11,"geometry":"LINESTRING (-105.0913713 39.5950916, -105.091375 39.5944888, -105.0913568 39.5942534)","properties":{"laneId":11,"laneType":{"vehicle":{"isVehicleRevocableLane":false,"isVehicleFlyOverLane":false,"permissionOnRequest":false,"hasIRbeaconCoverage":false,"restrictedToBusUse":false,"restrictedToTaxiUse":false,"restrictedFromPublicUse":false,"hovLaneUseOnly":false}},"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":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":18,"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":1,"connectionID":1}]}},{"type":"Feature","id":8,"geometry":"LINESTRING (-105.0912303 39.5950889, -105.0912421 39.5949129, -105.0912427 39.5942475, -105.0912568 39.5941003)","properties":{"laneId":8,"laneType":{"vehicle":{"isVehicleRevocableLane":false,"isVehicleFlyOverLane":false,"permissionOnRequest":false,"hasIRbeaconCoverage":false,"restrictedToBusUse":false,"restrictedToTaxiUse":false,"restrictedFromPublicUse":false,"hovLaneUseOnly":false}},"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":0,"ingressApproach":3,"ingressPath":true,"egressPath":false,"maneuvers":{"maneuverStraightAllowed":false,"maneuverNoStoppingAllowed":false,"goWithHalt":false,"maneuverLeftAllowed":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}},"connectionID":1}]}},{"type":"Feature","id":15,"geometry":"LINESTRING (-105.0916931 39.5951733, -105.0927839 39.5951756, -105.0941732 39.5951722, -105.0952027 39.5951734)","properties":{"laneId":15,"laneType":{"vehicle":{"isVehicleRevocableLane":false,"isVehicleFlyOverLane":false,"permissionOnRequest":false,"hasIRbeaconCoverage":false,"restrictedToBusUse":false,"restrictedToTaxiUse":false,"restrictedFromPublicUse":false,"hovLaneUseOnly":false}},"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":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}},"signalGroup":8,"connectionID":1}]}},{"type":"Feature","id":16,"geometry":"LINESTRING (-105.0916852 39.5952059, -105.0931135 39.5952073, -105.0944406 39.595204, -105.0952041 39.5952041)","properties":{"laneId":16,"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":8,"connectionID":1}]}},{"type":"Feature","id":17,"geometry":"LINESTRING (-105.0916853 39.5952393, -105.0927239 39.5952377, -105.0941207 39.5952375, -105.0943034 39.5952213)","properties":{"laneId":17,"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":true,"maneuverUTurnAllowed":false,"maneuverLeftTurnOnRedAllowed":false,"reserved1":false,"maneuverRightAllowed":false,"maneuverLaneChangeAllowed":false,"yieldAllwaysRequired":false,"maneuverRightTurnOnRedAllowed":false,"caution":false},"connectsTo":[{"connectingLane":{"lane":26,"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":3,"connectionID":1}]}},{"type":"Feature","id":14,"geometry":"LINESTRING (-105.0916926 39.5951407, -105.0940224 39.5951414, -105.095203 39.5951408)","properties":{"laneId":14,"laneType":{"vehicle":{"isVehicleRevocableLane":false,"isVehicleFlyOverLane":false,"permissionOnRequest":false,"hasIRbeaconCoverage":false,"restrictedToBusUse":false,"restrictedToTaxiUse":false,"restrictedFromPublicUse":false,"hovLaneUseOnly":false}},"sharedWith":{"busVehicleTraffic":false,"trackedVehicleTraffic":false,"individualMotorizedVehicleTraffic":false,"taxiVehicleTraffic":false,"overlappingLaneDescriptionProvided":false,"cyclistVehicleTraffic":false,"otherNonMotorizedTrafficTypes":false,"multipleLanesTreatedAsOneLane":false,"pedestrianTraffic":false,"pedestriansTraffic":false},"egressApproach":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":13,"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":18,"geometry":"LINESTRING (-105.0916766 39.595308, -105.0917443 39.5953067)","properties":{"laneId":18,"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":19,"geometry":"LINESTRING (-105.0916758 39.5953365, -105.0917363 39.5953365)","properties":{"laneId":19,"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":20,"geometry":"LINESTRING (-105.0916734 39.5953755, -105.0917299 39.5953755)","properties":{"laneId":20,"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":23,"geometry":"LINESTRING (-105.091519 39.5954362, -105.0914927 39.5965421, -105.091488 39.5974092, -105.0914843 39.5981324, -105.0914843 39.5981324, -105.0914851 39.5981349)","properties":{"laneId":23,"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":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":12,"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":22,"geometry":"LINESTRING (-105.0915548 39.5954372, -105.0915441 39.59638, -105.0915337 39.5974224, -105.0915281 39.5981345)","properties":{"laneId":22,"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":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":13,"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":21,"geometry":"LINESTRING (-105.0916048 39.5954391, -105.0916029 39.5957255, -105.0916004 39.5962647, -105.0915885 39.5966976, -105.0915786 39.5977599, -105.0915764 39.5981344)","properties":{"laneId":21,"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":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":20,"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":24,"geometry":"LINESTRING (-105.0914747 39.5954382, -105.0914714 39.5958506, -105.0914611 39.596192, -105.0914778 39.5963599)","properties":{"laneId":24,"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":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}},"signalGroup":5,"connectionID":1}]}},{"type":"Feature","id":25,"geometry":"LINESTRING (-105.0914371 39.5954371, -105.0914355 39.5958506, -105.0914461 39.596052)","properties":{"laneId":25,"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":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":5,"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":5,"connectionID":1}]}},{"type":"Feature","id":26,"geometry":"LINESTRING (-105.0913276 39.5954361, -105.0913284 39.5954678)","properties":{"laneId":26,"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":8,"ingressApproach":0,"ingressPath":false,"egressPath":true}},{"type":"Feature","id":27,"geometry":"LINESTRING (-105.0912831 39.5954348, -105.0912839 39.5954647)","properties":{"laneId":27,"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":8,"ingressApproach":0,"ingressPath":false,"egressPath":true}},{"type":"Feature","id":28,"geometry":"LINESTRING (-105.0912264 39.5954336, -105.091228 39.5954647, -105.091228 39.5954653)","properties":{"laneId":28,"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":8,"ingressApproach":0,"ingressPath":false,"egressPath":true}}]},"connectingLanesFeatureCollection":{"type":"FeatureCollection","features":[{"type":"Feature","id":"2-19","geometry":"LINESTRING (-105.0911523 39.5953376, -105.0916758 39.5953365)","properties":{"signalGroupId":4,"ingressLaneId":2,"egressLaneId":19}},{"type":"Feature","id":"3-18","geometry":"LINESTRING (-105.0911527 39.5953113, -105.0916766 39.595308)","properties":{"signalGroupId":4,"ingressLaneId":3,"egressLaneId":18}},{"type":"Feature","id":"1-28","geometry":"LINESTRING (-105.0911535 39.5953745, -105.0912264 39.5954336)","properties":{"ingressLaneId":1,"egressLaneId":28}},{"type":"Feature","id":"4-12","geometry":"LINESTRING (-105.0911537 39.5952537, -105.0915234 39.5950941)","properties":{"signalGroupId":7,"ingressLaneId":4,"egressLaneId":12}},{"type":"Feature","id":"10-26","geometry":"LINESTRING (-105.0913299 39.5950922, -105.0913276 39.5954361)","properties":{"signalGroupId":6,"ingressLaneId":10,"egressLaneId":26}},{"type":"Feature","id":"9-27","geometry":"LINESTRING (-105.0912849 39.5950912, -105.0912831 39.5954348)","properties":{"signalGroupId":6,"ingressLaneId":9,"egressLaneId":27}},{"type":"Feature","id":"11-18","geometry":"LINESTRING (-105.0913713 39.5950916, -105.0916766 39.595308)","properties":{"signalGroupId":1,"ingressLaneId":11,"egressLaneId":18}},{"type":"Feature","id":"8-7","geometry":"LINESTRING (-105.0912303 39.5950889, -105.0911443 39.5951332)","properties":{"ingressLaneId":8,"egressLaneId":7}},{"type":"Feature","id":"15-6","geometry":"LINESTRING (-105.0916931 39.5951733, -105.0911474 39.5951732)","properties":{"signalGroupId":8,"ingressLaneId":15,"egressLaneId":6}},{"type":"Feature","id":"16-5","geometry":"LINESTRING (-105.0916852 39.5952059, -105.0911474 39.5952053)","properties":{"signalGroupId":8,"ingressLaneId":16,"egressLaneId":5}},{"type":"Feature","id":"17-26","geometry":"LINESTRING (-105.0916853 39.5952393, -105.0913276 39.5954361)","properties":{"signalGroupId":3,"ingressLaneId":17,"egressLaneId":26}},{"type":"Feature","id":"14-13","geometry":"LINESTRING (-105.0916926 39.5951407, -105.0915804 39.5950941)","properties":{"ingressLaneId":14,"egressLaneId":13}},{"type":"Feature","id":"23-12","geometry":"LINESTRING (-105.091519 39.5954362, -105.0915234 39.5950941)","properties":{"signalGroupId":2,"ingressLaneId":23,"egressLaneId":12}},{"type":"Feature","id":"22-13","geometry":"LINESTRING (-105.0915548 39.5954372, -105.0915804 39.5950941)","properties":{"signalGroupId":2,"ingressLaneId":22,"egressLaneId":13}},{"type":"Feature","id":"21-20","geometry":"LINESTRING (-105.0916048 39.5954391, -105.0916734 39.5953755)","properties":{"ingressLaneId":21,"egressLaneId":20}},{"type":"Feature","id":"24-6","geometry":"LINESTRING (-105.0914747 39.5954382, -105.0911474 39.5951732)","properties":{"signalGroupId":5,"ingressLaneId":24,"egressLaneId":6}},{"type":"Feature","id":"25-5","geometry":"LINESTRING (-105.0914371 39.5954371, -105.0911474 39.5952053)","properties":{"signalGroupId":5,"ingressLaneId":25,"egressLaneId":5}}]},"properties":{"schemaVersion":1,"messageType":"MAP","odeReceivedAt":"2025-01-31T23:50:49.19Z","originIp":"172.20.0.1","intersectionId":12110,"msgIssueRevision":0,"revision":0,"refPoint":{"latitude":39.5952649,"longitude":-105.0914122,"elevation":1677.0},"cti4501Conformant":false,"laneWidth":366,"mapSource":"RSU","timeStamp":"2025-01-31T23:50:49.19Z"}} \ No newline at end of file diff --git a/jpo-deduplicator/src/test/resources/logback-test.xml b/jpo-deduplicator/src/test/resources/logback-test.xml new file mode 100644 index 0000000..cd07f49 --- /dev/null +++ b/jpo-deduplicator/src/test/resources/logback-test.xml @@ -0,0 +1,11 @@ + + + + %msg%n + + + + + + + \ No newline at end of file diff --git a/jpo-utils b/jpo-utils new file mode 160000 index 0000000..8a9d961 --- /dev/null +++ b/jpo-utils @@ -0,0 +1 @@ +Subproject commit 8a9d96122bd33ddcff57880ed1e08ff9bdcf0aa1 diff --git a/sample.env b/sample.env new file mode 100644 index 0000000..912cfb5 --- /dev/null +++ b/sample.env @@ -0,0 +1,62 @@ +### COMMON variables - START ### +# (Required) The IP address of Docker host machine which can be found by running "ifconfig" +# Hint: look for "inet addr:" within "eth0" or "en0" for OSX + + +# Set the HOST IP of where the containers are running +DOCKER_HOST_IP= +KAFKA_BOOTSTRAP_SERVERS=${DOCKER_HOST_IP}:9092 + +# GitHub properties for pulling the latest version of the JPO-ODE +# Required for building the deduplicator. Documentation: https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-apache-maven-registry#authenticating-to-github-packages +MAVEN_GITHUB_TOKEN= +MAVEN_GITHUB_ORG=usdot-jpo-ode + + +# Docker compose restart policy: https://docs.docker.com/engine/containers/start-containers-automatically/ +RESTART_POLICY="on-failure:3" + +# Available profiles: +# - all +# - deduplicator_base +# - deduplicator +# - deduplicator_full +# - deduplicator +# - geojsonconverter +# - ode +# - adm +# +# All profiles from the jpo-utils repo are also allowed +# Example: COMPOSE_PROFILES=kafka,kafka_ui,kafka_setup, deduplicator_full +COMPOSE_PROFILES=kafka,kafka_ui,kafka_setup, deduplicator_full + + +# Set to "CONFLUENT" if broker is a Confluent Cloud broker +KAFKA_TYPE= + +# Set to actual Confluent Cloud access key and secret values for SASL authentication +CONFLUENT_KEY= +CONFLUENT_SECRET= + +KAFKA_TOPIC_CREATE_DEDUPLICATOR=true + +# Deduplicator Feature Flags +ENABLE_PROCESSED_MAP_DEDUPLICATION=true +ENABLE_PROCESSED_MAP_WKT_DEDUPLICATION=true +ENABLE_ODE_MAP_DEDUPLICATION=true +ENABLE_ODE_TIM_DEDUPLICATION=true +ENABLE_ODE_RAW_ENCODED_TIM_DEDUPLICATION=true +ENABLE_PROCESSED_SPAT_DEDUPLICATION=true +ENABLE_ODE_BSM_DEDUPLICATION=true + + +# RocksDB Bounded Memory Config Properties +# 128 MB = 134217728 +# 64 MB = 67108864 +# 16 MB = 16777216 +DEDUPLICATOR_ROCKSDB_TOTAL_OFF_HEAP_MEMORY=134217728 +DEDUPLICATOR_ROCKSDB_INDEX_FILTER_BLOCK_RATIO=0.1 +DEDUPLICATOR_ROCKSDB_TOTAL_MEMTABLE_MEMORY=67108864 +DEDUPLICATOR_ROCKSDB_BLOCK_SIZE=4096 +DEDUPLICATOR_ROCKSDB_N_MEMTABLES=2 +DEDUPLICATOR_ROCKSDB_MEMTABLE_SIZE=16777216 \ No newline at end of file