From 47300f981eb08b2c73125a3937eb77165834f799 Mon Sep 17 00:00:00 2001 From: Teemu Kalvas Date: Tue, 19 Nov 2024 15:47:12 +0200 Subject: [PATCH 01/80] use duration tag from osm as escalator traversal duration --- .../module/osm/EscalatorProcessor.java | 13 ++++-- .../org/opentripplanner/osm/model/OsmWay.java | 15 +++++++ .../street/model/edge/EscalatorEdge.java | 15 +++++-- .../utils/time/DurationUtils.java | 43 +++++++++++++++++++ .../utils/time/DurationUtilsTest.java | 18 ++++++++ 5 files changed, 96 insertions(+), 8 deletions(-) diff --git a/application/src/main/java/org/opentripplanner/graph_builder/module/osm/EscalatorProcessor.java b/application/src/main/java/org/opentripplanner/graph_builder/module/osm/EscalatorProcessor.java index 75e0965d82f..ff439a37f59 100644 --- a/application/src/main/java/org/opentripplanner/graph_builder/module/osm/EscalatorProcessor.java +++ b/application/src/main/java/org/opentripplanner/graph_builder/module/osm/EscalatorProcessor.java @@ -27,30 +27,35 @@ public void buildEscalatorEdge(OsmWay escalatorWay, double length) { .boxed() .toList(); + Long duration = escalatorWay.getDurationSeconds(); for (int i = 0; i < nodes.size() - 1; i++) { if (escalatorWay.isForwardEscalator()) { EscalatorEdge.createEscalatorEdge( intersectionNodes.get(nodes.get(i)), intersectionNodes.get(nodes.get(i + 1)), - length + length, + duration ); } else if (escalatorWay.isBackwardEscalator()) { EscalatorEdge.createEscalatorEdge( intersectionNodes.get(nodes.get(i + 1)), intersectionNodes.get(nodes.get(i)), - length + length, + duration ); } else { EscalatorEdge.createEscalatorEdge( intersectionNodes.get(nodes.get(i)), intersectionNodes.get(nodes.get(i + 1)), - length + length, + duration ); EscalatorEdge.createEscalatorEdge( intersectionNodes.get(nodes.get(i + 1)), intersectionNodes.get(nodes.get(i)), - length + length, + duration ); } } diff --git a/application/src/main/java/org/opentripplanner/osm/model/OsmWay.java b/application/src/main/java/org/opentripplanner/osm/model/OsmWay.java index 7b5fbe56748..24423024311 100644 --- a/application/src/main/java/org/opentripplanner/osm/model/OsmWay.java +++ b/application/src/main/java/org/opentripplanner/osm/model/OsmWay.java @@ -2,9 +2,11 @@ import gnu.trove.list.TLongList; import gnu.trove.list.array.TLongArrayList; +import java.time.format.DateTimeParseException; import java.util.Set; import org.opentripplanner.graph_builder.module.osm.StreetTraversalPermissionPair; import org.opentripplanner.street.model.StreetTraversalPermission; +import org.opentripplanner.utils.time.DurationUtils; public class OsmWay extends OsmWithTags { @@ -130,6 +132,19 @@ public boolean isEscalator() { return (isTag("highway", "steps") && isOneOfTags("conveying", ESCALATOR_CONVEYING_TAGS)); } + public Long getDurationSeconds() { + var duration = getTag("duration"); + if (duration != null) { + try { + return DurationUtils.parseClockDuration(duration).getSeconds(); + } catch (DateTimeParseException e) { + // For malformed duration tags, just pretend they weren't there. + return null; + } + } + return null; + } + public boolean isForwardEscalator() { return isEscalator() && "forward".equals(this.getTag("conveying")); } diff --git a/application/src/main/java/org/opentripplanner/street/model/edge/EscalatorEdge.java b/application/src/main/java/org/opentripplanner/street/model/edge/EscalatorEdge.java index 20fae657c78..35c2db5cbc2 100644 --- a/application/src/main/java/org/opentripplanner/street/model/edge/EscalatorEdge.java +++ b/application/src/main/java/org/opentripplanner/street/model/edge/EscalatorEdge.java @@ -17,10 +17,12 @@ public class EscalatorEdge extends Edge { private static final double HORIZONTAL_SPEED = 0.45; private static final LocalizedString NAME = new LocalizedString("name.escalator"); private final double length; + private final Long duration; - private EscalatorEdge(Vertex v1, Vertex v2, double length) { + private EscalatorEdge(Vertex v1, Vertex v2, double length, Long duration) { super(v1, v2); this.length = length; + this.duration = duration; } @Override @@ -28,7 +30,12 @@ public State[] traverse(State s0) { // Only allow traversal by walking if (s0.currentMode() == TraverseMode.WALK && !s0.getRequest().wheelchair()) { var s1 = s0.edit(this); - var time = getDistanceMeters() / HORIZONTAL_SPEED; + double time; + if (duration == null) { + time = getDistanceMeters() / HORIZONTAL_SPEED; + } else { + time = duration; + } s1.incrementWeight(s0.getPreferences().walk().escalatorReluctance() * time); s1.incrementTimeInSeconds((int) Math.round(time)); s1.incrementWalkDistance(getDistanceMeters()); @@ -51,7 +58,7 @@ public I18NString getName() { return NAME; } - public static EscalatorEdge createEscalatorEdge(Vertex from, Vertex to, double length) { - return connectToGraph(new EscalatorEdge(from, to, length)); + public static EscalatorEdge createEscalatorEdge(Vertex from, Vertex to, double length, Long duration) { + return connectToGraph(new EscalatorEdge(from, to, length, duration)); } } diff --git a/utils/src/main/java/org/opentripplanner/utils/time/DurationUtils.java b/utils/src/main/java/org/opentripplanner/utils/time/DurationUtils.java index d73faecee03..10f04700f3f 100644 --- a/utils/src/main/java/org/opentripplanner/utils/time/DurationUtils.java +++ b/utils/src/main/java/org/opentripplanner/utils/time/DurationUtils.java @@ -11,6 +11,7 @@ import java.util.Optional; import java.util.regex.Pattern; import java.util.stream.Collectors; +import org.opentripplanner.utils.lang.StringUtils; /** * This class extend the Java {@link Duration} with utility functionality to parse and convert @@ -123,6 +124,48 @@ public static Duration duration(String duration) { } } + /** + * Parse a duration string in format hh:mm:ss. + * @param duration string in format hh:mm:ss + * @return Duration + * @throws DateTimeParseException on bad input + */ + public static Duration parseClockDuration(String duration) { + int colonCount = (int) duration.chars().filter(ch -> ch == ':').count(); + if (colonCount <= 2) { + try { + int i, j; + long hours, minutes = 0, seconds = 0; + switch (colonCount) { + case 0: + hours = Long.parseLong(duration); + break; + case 1: + i = duration.indexOf(':'); + hours = Long.parseLong(duration.substring(0, i)); + minutes = Long.parseLong(duration.substring(i + 1)); + break; + default: + //case 2: + i = duration.indexOf(':'); + j = duration.indexOf(':', i + 1); + hours = Long.parseLong(duration.substring(0, i)); + minutes = Long.parseLong(duration.substring(i + 1, j)); + seconds = Long.parseLong(duration.substring(j + 1)); + break; + } + if (hours >= 0 && minutes >= 0 && minutes < 60 && seconds >= 0 && seconds < 60) { + return Duration.ofHours(hours) + .plus(Duration.ofMinutes(minutes)) + .plus(Duration.ofSeconds(seconds)); + } + } catch (NumberFormatException e) { + // fallthrough + } + } + throw new DateTimeParseException("bad clock duration", duration, 0); + } + /** * This is used to parse a string which may be a number {@code NNNN}(number of seconds) or a * duration with format {@code NhNmNs}, where {@code N} is a decimal number and diff --git a/utils/src/test/java/org/opentripplanner/utils/time/DurationUtilsTest.java b/utils/src/test/java/org/opentripplanner/utils/time/DurationUtilsTest.java index ef2e0f50901..1e0839091cb 100644 --- a/utils/src/test/java/org/opentripplanner/utils/time/DurationUtilsTest.java +++ b/utils/src/test/java/org/opentripplanner/utils/time/DurationUtilsTest.java @@ -30,6 +30,8 @@ public class DurationUtilsTest { private final Duration D5m = Duration.ofMinutes(5); private final Duration D9s = Duration.ofSeconds(9); private final Duration D3d5m9s = D3d.plus(D5m).plus(D9s); + private final Duration D2h5m = D2h.plus(D5m); + private final Duration D2h5m9s = D2h.plus(D5m).plus(D9s); private final int I9h31m = durationSec(9, 31, 0); private final int I9h36m55s = durationSec(9, 36, 55); private final int I13h33m57s = durationSec(13, 33, 57); @@ -91,6 +93,22 @@ public void duration() { assertEquals(-D9s.toSeconds(), DurationUtils.duration("-9", ChronoUnit.SECONDS).toSeconds()); } + @Test + public void parseClockDuration() { + assertEquals(D2h, DurationUtils.parseClockDuration("2")); + assertEquals(D2h5m, DurationUtils.parseClockDuration("02:05")); + assertEquals(D2h5m9s, DurationUtils.parseClockDuration("02:05:09")); + assertThrows( + DateTimeParseException.class, + () -> DurationUtils.parseClockDuration("02:65:09")); + assertThrows( + DateTimeParseException.class, + () -> DurationUtils.parseClockDuration("02:05:09:00")); + assertThrows( + DateTimeParseException.class, + () -> DurationUtils.parseClockDuration("02:x5:09")); + } + @Test public void parseSecondsOrDuration() { assertEquals(D9s, DurationUtils.parseSecondsOrDuration("9s").orElseThrow()); From 6186451c845dc4e29b70963d2edb5694c2038f3f Mon Sep 17 00:00:00 2001 From: Thomas Gran Date: Thu, 21 Nov 2024 19:14:22 +0100 Subject: [PATCH 02/80] Split the shaded jar out of application --- application/pom.xml | 81 +------------------------- pom.xml | 3 + raptor/pom.xml | 2 +- shaded-jar/pom.xml | 134 ++++++++++++++++++++++++++++++++++++++++++++ utils/pom.xml | 2 +- 5 files changed, 142 insertions(+), 80 deletions(-) create mode 100644 shaded-jar/pom.xml diff --git a/application/pom.xml b/application/pom.xml index 3fc0193d0af..4b11f1f6527 100644 --- a/application/pom.xml +++ b/application/pom.xml @@ -8,7 +8,7 @@ otp-root 2.7.0-SNAPSHOT - otp + application OpenTripPlanner - Application @@ -20,12 +20,12 @@ ${project.groupId} - otp-utils + utils ${project.version} ${project.groupId} - otp-raptor + raptor ${project.version} @@ -456,81 +456,6 @@ - - - - org.apache.maven.plugins - maven-shade-plugin - 3.6.0 - - - package - - shade - - - - - - *:* - - META-INF/*.SF - META-INF/*.DSA - META-INF/*.RSA - - - - - true - shaded - false - - - - - - - org.opentripplanner.standalone.OTPMain - - Java Advanced Imaging Image I/O - Tools - - 1.1 - Sun Microsystems, Inc. - com.sun.media.imageio - 1.1 - Sun Microsystems, Inc. - com.sun.media.imageio - - - - - - - com.github.bohnman package-info-maven-plugin diff --git a/pom.xml b/pom.xml index b520f3cad63..346dadf50c9 100644 --- a/pom.xml +++ b/pom.xml @@ -98,6 +98,7 @@ gtfs-realtime-protobuf utils raptor + shaded-jar @@ -131,6 +132,7 @@ ${otp.serialization.version.id} + true @@ -143,6 +145,7 @@ ${basedir}/doc/javadoc javadoc + true diff --git a/raptor/pom.xml b/raptor/pom.xml index d2d93e36f9d..b0bb86317e1 100644 --- a/raptor/pom.xml +++ b/raptor/pom.xml @@ -9,7 +9,7 @@ 2.7.0-SNAPSHOT - otp-raptor + raptor OpenTripPlanner - Raptor diff --git a/shaded-jar/pom.xml b/shaded-jar/pom.xml new file mode 100644 index 00000000000..fbea5d99fca --- /dev/null +++ b/shaded-jar/pom.xml @@ -0,0 +1,134 @@ + + + 4.0.0 + + org.opentripplanner + otp-root + 2.7.0-SNAPSHOT + + shaded-jar + pom + OpenTripPlanner - Shaded Jar + + + skip + + + + + + ${project.groupId} + application + ${project.version} + + + + + + + + + + org.apache.maven.plugins + maven-shade-plugin + 3.6.0 + + + ${build.directory}/otp-${project.version}-shaded.jar + + + + *:* + + META-INF/*.SF + META-INF/*.DSA + META-INF/*.RSA + + + + + true + + false + + + + + + + org.opentripplanner.standalone.OTPMain + + Java Advanced Imaging Image I/O + Tools + + 1.1 + Sun Microsystems, Inc. + com.sun.media.imageio + 1.1 + Sun Microsystems, Inc. + + com.sun.media.imageio + + + + + + + + + + shaded-jar + + + + org.apache.maven.plugins + maven-shade-plugin + + + install + + shade + + + + + + + + + diff --git a/utils/pom.xml b/utils/pom.xml index 7a223488dd0..2e70554a678 100644 --- a/utils/pom.xml +++ b/utils/pom.xml @@ -9,7 +9,7 @@ 2.7.0-SNAPSHOT - otp-utils + utils OpenTripPlanner - Utils From d9ead12868cc132284260423c69b6bfdb7582ee0 Mon Sep 17 00:00:00 2001 From: Teemu Kalvas Date: Fri, 22 Nov 2024 12:08:22 +0200 Subject: [PATCH 03/80] make default escalator speed a configuration parameter --- .../module/osm/EscalatorProcessor.java | 2 +- .../org/opentripplanner/osm/model/OsmWay.java | 8 +- .../preference/EscalatorPreferences.java | 74 +++++++++++++++++++ .../request/preference/StreetPreferences.java | 16 ++++ .../routerequest/RouteRequestConfig.java | 11 +++ .../street/model/edge/EscalatorEdge.java | 17 +++-- .../street/model/edge/EscalatorEdgeTest.java | 23 ++++-- doc/user/RouteRequest.md | 1 + .../utils/time/DurationUtils.java | 5 +- .../utils/time/DurationUtilsTest.java | 11 +-- 10 files changed, 141 insertions(+), 27 deletions(-) create mode 100644 application/src/main/java/org/opentripplanner/routing/api/request/preference/EscalatorPreferences.java diff --git a/application/src/main/java/org/opentripplanner/graph_builder/module/osm/EscalatorProcessor.java b/application/src/main/java/org/opentripplanner/graph_builder/module/osm/EscalatorProcessor.java index ff439a37f59..488fc96a0b3 100644 --- a/application/src/main/java/org/opentripplanner/graph_builder/module/osm/EscalatorProcessor.java +++ b/application/src/main/java/org/opentripplanner/graph_builder/module/osm/EscalatorProcessor.java @@ -27,7 +27,7 @@ public void buildEscalatorEdge(OsmWay escalatorWay, double length) { .boxed() .toList(); - Long duration = escalatorWay.getDurationSeconds(); + Integer duration = escalatorWay.getDurationSeconds(); for (int i = 0; i < nodes.size() - 1; i++) { if (escalatorWay.isForwardEscalator()) { EscalatorEdge.createEscalatorEdge( diff --git a/application/src/main/java/org/opentripplanner/osm/model/OsmWay.java b/application/src/main/java/org/opentripplanner/osm/model/OsmWay.java index 24423024311..0819ab57b59 100644 --- a/application/src/main/java/org/opentripplanner/osm/model/OsmWay.java +++ b/application/src/main/java/org/opentripplanner/osm/model/OsmWay.java @@ -132,11 +132,15 @@ public boolean isEscalator() { return (isTag("highway", "steps") && isOneOfTags("conveying", ESCALATOR_CONVEYING_TAGS)); } - public Long getDurationSeconds() { + public Integer getDurationSeconds() { var duration = getTag("duration"); if (duration != null) { try { - return DurationUtils.parseClockDuration(duration).getSeconds(); + long seconds = DurationUtils.parseClockDuration(duration).getSeconds(); + if (seconds < 0 || seconds > Integer.MAX_VALUE) { + return null; + } + return (int) seconds; } catch (DateTimeParseException e) { // For malformed duration tags, just pretend they weren't there. return null; diff --git a/application/src/main/java/org/opentripplanner/routing/api/request/preference/EscalatorPreferences.java b/application/src/main/java/org/opentripplanner/routing/api/request/preference/EscalatorPreferences.java new file mode 100644 index 00000000000..af4cbda39ef --- /dev/null +++ b/application/src/main/java/org/opentripplanner/routing/api/request/preference/EscalatorPreferences.java @@ -0,0 +1,74 @@ +package org.opentripplanner.routing.api.request.preference; + +import java.io.Serializable; +import java.util.function.Consumer; + +public class EscalatorPreferences implements Serializable { + + public static final EscalatorPreferences DEFAULT = new EscalatorPreferences(); + + private final double horizontalSpeed; + + /* A quick internet search gives escalator speed range of 0.3-0.6 m/s and angle of 30 degrees. + * Using the angle of 30 degrees and a speed of 0.5 m/s gives a horizontal component + * of approx. 0.43 m/s */ + private static final double HORIZONTAL_SPEED = 0.45; + + private EscalatorPreferences() { + this.horizontalSpeed = HORIZONTAL_SPEED; + } + + private EscalatorPreferences(Builder builder) { + this.horizontalSpeed = builder.horizontalSpeed; + } + + public static Builder of() { + return DEFAULT.copyOf(); + } + + public Builder copyOf() { + return new Builder(this); + } + + public double horizontalSpeed() { + return horizontalSpeed; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + EscalatorPreferences that = (EscalatorPreferences) o; + return horizontalSpeed == that.horizontalSpeed; + } + + public static class Builder { + + private final EscalatorPreferences original; + private double horizontalSpeed; + + public Builder(EscalatorPreferences original) { + this.original = original; + this.horizontalSpeed = original.horizontalSpeed; + } + + public EscalatorPreferences original() { + return original; + } + + public Builder withHorizontalSpeed(double horizontalSpeed) { + this.horizontalSpeed = horizontalSpeed; + return this; + } + + public Builder apply(Consumer body) { + body.accept(this); + return this; + } + + public EscalatorPreferences build() { + var value = new EscalatorPreferences(this); + return original.equals(value) ? original : value; + } + } +} diff --git a/application/src/main/java/org/opentripplanner/routing/api/request/preference/StreetPreferences.java b/application/src/main/java/org/opentripplanner/routing/api/request/preference/StreetPreferences.java index bb526ceaa31..e20ed82f9a5 100644 --- a/application/src/main/java/org/opentripplanner/routing/api/request/preference/StreetPreferences.java +++ b/application/src/main/java/org/opentripplanner/routing/api/request/preference/StreetPreferences.java @@ -30,6 +30,7 @@ public final class StreetPreferences implements Serializable { private final double turnReluctance; private final DrivingDirection drivingDirection; private final ElevatorPreferences elevator; + private final EscalatorPreferences escalator; private final AccessEgressPreferences accessEgress; private final IntersectionTraversalModel intersectionTraversalModel; private final DurationForEnum maxDirectDuration; @@ -39,6 +40,7 @@ private StreetPreferences() { this.turnReluctance = 1.0; this.drivingDirection = DrivingDirection.RIGHT; this.elevator = ElevatorPreferences.DEFAULT; + this.escalator = EscalatorPreferences.DEFAULT; this.accessEgress = AccessEgressPreferences.DEFAULT; this.intersectionTraversalModel = IntersectionTraversalModel.SIMPLE; this.maxDirectDuration = durationForStreetModeOf(ofHours(4)); @@ -49,6 +51,7 @@ private StreetPreferences(Builder builder) { this.turnReluctance = Units.reluctance(builder.turnReluctance); this.drivingDirection = requireNonNull(builder.drivingDirection); this.elevator = requireNonNull(builder.elevator); + this.escalator = requireNonNull(builder.escalator); this.accessEgress = requireNonNull(builder.accessEgress); this.intersectionTraversalModel = requireNonNull(builder.intersectionTraversalModel); this.maxDirectDuration = requireNonNull(builder.maxDirectDuration); @@ -78,6 +81,10 @@ public ElevatorPreferences elevator() { return elevator; } + public EscalatorPreferences escalator() { + return escalator; + } + /** Preferences for access/egress routing */ public AccessEgressPreferences accessEgress() { return accessEgress; @@ -110,6 +117,7 @@ public boolean equals(Object o) { DoubleUtils.doubleEquals(that.turnReluctance, turnReluctance) && drivingDirection == that.drivingDirection && elevator.equals(that.elevator) && + escalator.equals(that.escalator) && routingTimeout.equals(that.routingTimeout) && intersectionTraversalModel == that.intersectionTraversalModel && maxDirectDuration.equals(that.maxDirectDuration) && @@ -138,6 +146,7 @@ public String toString() { .addEnum("drivingDirection", drivingDirection, DEFAULT.drivingDirection) .addDuration("routingTimeout", routingTimeout, DEFAULT.routingTimeout()) .addObj("elevator", elevator, DEFAULT.elevator) + .addObj("escalator", escalator, DEFAULT.escalator) .addObj( "intersectionTraversalModel", intersectionTraversalModel, @@ -154,6 +163,7 @@ public static class Builder { private double turnReluctance; private DrivingDirection drivingDirection; private ElevatorPreferences elevator; + private EscalatorPreferences escalator; private IntersectionTraversalModel intersectionTraversalModel; private DurationForEnum maxDirectDuration; private Duration routingTimeout; @@ -164,6 +174,7 @@ public Builder(StreetPreferences original) { this.turnReluctance = original.turnReluctance; this.drivingDirection = original.drivingDirection; this.elevator = original.elevator; + this.escalator = original.escalator; this.intersectionTraversalModel = original.intersectionTraversalModel; this.accessEgress = original.accessEgress; this.maxDirectDuration = original.maxDirectDuration; @@ -189,6 +200,11 @@ public Builder withElevator(Consumer body) { return this; } + public Builder withEscalator(Consumer body) { + this.escalator = escalator.copyOf().apply(body).build(); + return this; + } + public Builder withAccessEgress(Consumer body) { this.accessEgress = accessEgress.copyOf().apply(body).build(); return this; diff --git a/application/src/main/java/org/opentripplanner/standalone/config/routerequest/RouteRequestConfig.java b/application/src/main/java/org/opentripplanner/standalone/config/routerequest/RouteRequestConfig.java index d05aee96ccf..9c344afc44c 100644 --- a/application/src/main/java/org/opentripplanner/standalone/config/routerequest/RouteRequestConfig.java +++ b/application/src/main/java/org/opentripplanner/standalone/config/routerequest/RouteRequestConfig.java @@ -6,6 +6,7 @@ import static org.opentripplanner.standalone.config.framework.json.OtpVersion.V2_3; import static org.opentripplanner.standalone.config.framework.json.OtpVersion.V2_4; import static org.opentripplanner.standalone.config.framework.json.OtpVersion.V2_5; +import static org.opentripplanner.standalone.config.framework.json.OtpVersion.V2_7; import static org.opentripplanner.standalone.config.routerequest.ItineraryFiltersConfig.mapItineraryFilterParams; import static org.opentripplanner.standalone.config.routerequest.TransferConfig.mapTransferPreferences; import static org.opentripplanner.standalone.config.routerequest.TriangleOptimizationConfig.mapOptimizationTriangle; @@ -459,6 +460,16 @@ private static void mapStreetPreferences(NodeAdapter c, StreetPreferences.Builde .asInt(dftElevator.hopTime()) ); }) + .withEscalator(escalator -> { + var dftEscalator = dft.escalator(); + escalator.withHorizontalSpeed( + c + .of("escalatorSpeed") + .since(V2_7) + .summary("How fast does an escalator move horizontally?") + .asDouble(dftEscalator.horizontalSpeed()) + ); + }) .withAccessEgress(accessEgress -> { var dftAccessEgress = dft.accessEgress(); accessEgress diff --git a/application/src/main/java/org/opentripplanner/street/model/edge/EscalatorEdge.java b/application/src/main/java/org/opentripplanner/street/model/edge/EscalatorEdge.java index 35c2db5cbc2..6f9e9c74b2f 100644 --- a/application/src/main/java/org/opentripplanner/street/model/edge/EscalatorEdge.java +++ b/application/src/main/java/org/opentripplanner/street/model/edge/EscalatorEdge.java @@ -11,15 +11,11 @@ /** Represents an escalator. An escalator edge can only be traversed by walking */ public class EscalatorEdge extends Edge { - /* A quick internet search gives escalator speed range of 0.3-0.6 m/s and angle of 30 degrees. - * Using the angle of 30 degrees and a speed of 0.5 m/s gives a horizontal component - * of approx. 0.43 m/s */ - private static final double HORIZONTAL_SPEED = 0.45; private static final LocalizedString NAME = new LocalizedString("name.escalator"); private final double length; - private final Long duration; + private final Integer duration; - private EscalatorEdge(Vertex v1, Vertex v2, double length, Long duration) { + private EscalatorEdge(Vertex v1, Vertex v2, double length, Integer duration) { super(v1, v2); this.length = length; this.duration = duration; @@ -32,7 +28,7 @@ public State[] traverse(State s0) { var s1 = s0.edit(this); double time; if (duration == null) { - time = getDistanceMeters() / HORIZONTAL_SPEED; + time = getDistanceMeters() / s0.getPreferences().street().escalator().horizontalSpeed(); } else { time = duration; } @@ -58,7 +54,12 @@ public I18NString getName() { return NAME; } - public static EscalatorEdge createEscalatorEdge(Vertex from, Vertex to, double length, Long duration) { + public static EscalatorEdge createEscalatorEdge( + Vertex from, + Vertex to, + double length, + Integer duration + ) { return connectToGraph(new EscalatorEdge(from, to, length, duration)); } } diff --git a/application/src/test/java/org/opentripplanner/street/model/edge/EscalatorEdgeTest.java b/application/src/test/java/org/opentripplanner/street/model/edge/EscalatorEdgeTest.java index 1cfff635c45..9e0b4f7d297 100644 --- a/application/src/test/java/org/opentripplanner/street/model/edge/EscalatorEdgeTest.java +++ b/application/src/test/java/org/opentripplanner/street/model/edge/EscalatorEdgeTest.java @@ -27,20 +27,29 @@ static Stream args() { @ParameterizedTest(name = "escalatorReluctance of {0} should lead to traversal costs of {1}") @MethodSource("args") void testWalking(double escalatorReluctance, double expectedWeight) { - var edge = EscalatorEdge.createEscalatorEdge(from, to, 45); + var edge = EscalatorEdge.createEscalatorEdge(from, to, 45, null); var req = StreetSearchRequest .of() .withPreferences(p -> p.withWalk(w -> w.withEscalatorReluctance(escalatorReluctance))) .withMode(StreetMode.WALK); var res = edge.traverse(new State(from, req.build()))[0]; - assertEquals(res.weight, expectedWeight); - assertEquals(res.getTimeDeltaSeconds(), 100); + assertEquals(expectedWeight, res.weight); + assertEquals(100, res.getTimeDeltaSeconds()); + } + + @Test + void testDuration() { + // If duration is given, length does not affect timeDeltaSeconds, only duration does. + var edge = EscalatorEdge.createEscalatorEdge(from, to, 45, 60); + var req = StreetSearchRequest.of().withMode(StreetMode.WALK); + var res = edge.traverse(new State(from, req.build()))[0]; + assertEquals(60, res.getTimeDeltaSeconds()); } @Test void testCycling() { - var edge = EscalatorEdge.createEscalatorEdge(from, to, 10); + var edge = EscalatorEdge.createEscalatorEdge(from, to, 10, null); var req = StreetSearchRequest.of().withMode(StreetMode.BIKE); var res = edge.traverse(new State(from, req.build())); assertThat(res).isEmpty(); @@ -48,7 +57,7 @@ void testCycling() { @Test void testWheelchair() { - var edge = EscalatorEdge.createEscalatorEdge(from, to, 10); + var edge = EscalatorEdge.createEscalatorEdge(from, to, 10, null); var req = StreetSearchRequest.of().withMode(StreetMode.WALK).withWheelchair(true); var res = edge.traverse(new State(from, req.build())); assertThat(res).isEmpty(); @@ -56,14 +65,14 @@ void testWheelchair() { @Test void name() { - var edge = EscalatorEdge.createEscalatorEdge(from, to, 10); + var edge = EscalatorEdge.createEscalatorEdge(from, to, 10, null); assertEquals("Rolltreppe", edge.getName().toString(Locale.GERMANY)); assertEquals("escalator", edge.getName().toString(Locale.ENGLISH)); } @Test void geometry() { - var edge = EscalatorEdge.createEscalatorEdge(from, to, 10); + var edge = EscalatorEdge.createEscalatorEdge(from, to, 10, null); assertThat(edge.getGeometry().getCoordinates()).isNotEmpty(); } } diff --git a/doc/user/RouteRequest.md b/doc/user/RouteRequest.md index ea3d0d12c74..c0c5d2bb590 100644 --- a/doc/user/RouteRequest.md +++ b/doc/user/RouteRequest.md @@ -23,6 +23,7 @@ and in the [transferRequests in build-config.json](BuildConfiguration.md#transfe | elevatorBoardTime | `integer` | How long does it take to get on an elevator, on average. | *Optional* | `90` | 2.0 | | elevatorHopCost | `integer` | What is the cost of travelling one floor on an elevator? | *Optional* | `20` | 2.0 | | elevatorHopTime | `integer` | How long does it take to advance one floor on an elevator? | *Optional* | `20` | 2.0 | +| escalatorSpeed | `double` | How fast does an escalator move horizontally? | *Optional* | `0.45` | 2.7 | | geoidElevation | `boolean` | If true, the Graph's ellipsoidToGeoidDifference is applied to all elevations returned by this query. | *Optional* | `false` | 2.0 | | ignoreRealtimeUpdates | `boolean` | When true, real-time updates are ignored during this search. | *Optional* | `false` | 2.0 | | [intersectionTraversalModel](#rd_intersectionTraversalModel) | `enum` | The model that computes the costs of turns. | *Optional* | `"simple"` | 2.2 | diff --git a/utils/src/main/java/org/opentripplanner/utils/time/DurationUtils.java b/utils/src/main/java/org/opentripplanner/utils/time/DurationUtils.java index 10f04700f3f..e1c0b557855 100644 --- a/utils/src/main/java/org/opentripplanner/utils/time/DurationUtils.java +++ b/utils/src/main/java/org/opentripplanner/utils/time/DurationUtils.java @@ -146,7 +146,7 @@ public static Duration parseClockDuration(String duration) { minutes = Long.parseLong(duration.substring(i + 1)); break; default: - //case 2: + //case 2: i = duration.indexOf(':'); j = duration.indexOf(':', i + 1); hours = Long.parseLong(duration.substring(0, i)); @@ -155,7 +155,8 @@ public static Duration parseClockDuration(String duration) { break; } if (hours >= 0 && minutes >= 0 && minutes < 60 && seconds >= 0 && seconds < 60) { - return Duration.ofHours(hours) + return Duration + .ofHours(hours) .plus(Duration.ofMinutes(minutes)) .plus(Duration.ofSeconds(seconds)); } diff --git a/utils/src/test/java/org/opentripplanner/utils/time/DurationUtilsTest.java b/utils/src/test/java/org/opentripplanner/utils/time/DurationUtilsTest.java index 1e0839091cb..15fbd6e5027 100644 --- a/utils/src/test/java/org/opentripplanner/utils/time/DurationUtilsTest.java +++ b/utils/src/test/java/org/opentripplanner/utils/time/DurationUtilsTest.java @@ -98,15 +98,12 @@ public void parseClockDuration() { assertEquals(D2h, DurationUtils.parseClockDuration("2")); assertEquals(D2h5m, DurationUtils.parseClockDuration("02:05")); assertEquals(D2h5m9s, DurationUtils.parseClockDuration("02:05:09")); + assertThrows(DateTimeParseException.class, () -> DurationUtils.parseClockDuration("02:65:09")); assertThrows( DateTimeParseException.class, - () -> DurationUtils.parseClockDuration("02:65:09")); - assertThrows( - DateTimeParseException.class, - () -> DurationUtils.parseClockDuration("02:05:09:00")); - assertThrows( - DateTimeParseException.class, - () -> DurationUtils.parseClockDuration("02:x5:09")); + () -> DurationUtils.parseClockDuration("02:05:09:00") + ); + assertThrows(DateTimeParseException.class, () -> DurationUtils.parseClockDuration("02:x5:09")); } @Test From f3121446ecffee3c539ce287b7f45f09a099c4b4 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Fri, 22 Nov 2024 21:34:12 +0100 Subject: [PATCH 04/80] Fix NPE when fetching minimumBookingNotice --- .../ext/restapi/mapping/BookingInfoMapper.java | 4 ++-- .../apis/gtfs/datafetchers/BookingInfoImpl.java | 5 +++-- .../transit/model/timetable/booking/BookingInfo.java | 11 +++++------ .../model/timetable/booking/RoutingBookingInfo.java | 6 +++--- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/application/src/ext/java/org/opentripplanner/ext/restapi/mapping/BookingInfoMapper.java b/application/src/ext/java/org/opentripplanner/ext/restapi/mapping/BookingInfoMapper.java index b4e3292b435..eafa81195b5 100644 --- a/application/src/ext/java/org/opentripplanner/ext/restapi/mapping/BookingInfoMapper.java +++ b/application/src/ext/java/org/opentripplanner/ext/restapi/mapping/BookingInfoMapper.java @@ -27,8 +27,8 @@ private static ApiBookingInfo mapBookingInfo(BookingInfo info, boolean isPickup) BookingMethodMapper.mapBookingMethods(info.bookingMethods()), BookingTimeMapper.mapBookingTime(info.getEarliestBookingTime()), BookingTimeMapper.mapBookingTime(info.getLatestBookingTime()), - info.getMinimumBookingNotice(), - info.getMaximumBookingNotice(), + info.getMinimumBookingNotice().orElse(null), + info.getMaximumBookingNotice().orElse(null), info.getMessage(), isPickup ? info.getPickupMessage() : null, !isPickup ? info.getDropOffMessage() : null diff --git a/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/BookingInfoImpl.java b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/BookingInfoImpl.java index 44ee0985542..a3ffda526db 100644 --- a/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/BookingInfoImpl.java +++ b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/BookingInfoImpl.java @@ -2,6 +2,7 @@ import graphql.schema.DataFetcher; import graphql.schema.DataFetchingEnvironment; +import java.time.Duration; import org.opentripplanner.apis.gtfs.generated.GraphQLDataFetchers; import org.opentripplanner.transit.model.organization.ContactInfo; import org.opentripplanner.transit.model.timetable.booking.BookingInfo; @@ -31,7 +32,7 @@ public DataFetcher latestBookingTime() { @Override public DataFetcher maximumBookingNoticeSeconds() { - return environment -> getSource(environment).getMaximumBookingNotice().toSeconds(); + return environment -> getSource(environment).getMaximumBookingNotice().map(Duration::toSeconds).orElse(null); } @Override @@ -41,7 +42,7 @@ public DataFetcher message() { @Override public DataFetcher minimumBookingNoticeSeconds() { - return environment -> getSource(environment).getMinimumBookingNotice().toSeconds(); + return environment -> getSource(environment).getMinimumBookingNotice().map(Duration::toSeconds).orElse(null); } @Override diff --git a/application/src/main/java/org/opentripplanner/transit/model/timetable/booking/BookingInfo.java b/application/src/main/java/org/opentripplanner/transit/model/timetable/booking/BookingInfo.java index b21543b717c..8b48a61ffbe 100644 --- a/application/src/main/java/org/opentripplanner/transit/model/timetable/booking/BookingInfo.java +++ b/application/src/main/java/org/opentripplanner/transit/model/timetable/booking/BookingInfo.java @@ -3,6 +3,7 @@ import java.io.Serializable; import java.time.Duration; import java.util.EnumSet; +import java.util.Optional; import javax.annotation.Nullable; import org.opentripplanner.transit.model.organization.ContactInfo; import org.opentripplanner.utils.tostring.ToStringBuilder; @@ -99,14 +100,12 @@ public BookingTime getLatestBookingTime() { return latestBookingTime; } - @Nullable - public Duration getMinimumBookingNotice() { - return minimumBookingNotice; + public Optional getMinimumBookingNotice() { + return Optional.ofNullable(minimumBookingNotice); } - @Nullable - public Duration getMaximumBookingNotice() { - return maximumBookingNotice; + public Optional getMaximumBookingNotice() { + return Optional.ofNullable(maximumBookingNotice); } @Nullable diff --git a/application/src/main/java/org/opentripplanner/transit/model/timetable/booking/RoutingBookingInfo.java b/application/src/main/java/org/opentripplanner/transit/model/timetable/booking/RoutingBookingInfo.java index 471cff394e2..11ea27d48aa 100644 --- a/application/src/main/java/org/opentripplanner/transit/model/timetable/booking/RoutingBookingInfo.java +++ b/application/src/main/java/org/opentripplanner/transit/model/timetable/booking/RoutingBookingInfo.java @@ -151,17 +151,17 @@ Builder withBookingInfo(@Nullable BookingInfo bookingInfo) { return this; } withLatestBookingTime(bookingInfo.getLatestBookingTime()); - withMinimumBookingNotice(bookingInfo.getMinimumBookingNotice()); + withMinimumBookingNotice(bookingInfo.getMinimumBookingNotice().orElse(null)); return this; } - public Builder withLatestBookingTime(BookingTime latestBookingTime) { + public Builder withLatestBookingTime(@Nullable BookingTime latestBookingTime) { this.latestBookingTime = latestBookingTime == null ? NOT_SET : latestBookingTime.relativeTimeSeconds(); return this; } - public Builder withMinimumBookingNotice(Duration minimumBookingNotice) { + public Builder withMinimumBookingNotice(@Nullable Duration minimumBookingNotice) { this.minimumBookingNotice = minimumBookingNotice == null ? NOT_SET : (int) minimumBookingNotice.toSeconds(); return this; From a14df652c8cbf3984aabf59863fd2305e0d905e1 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Fri, 22 Nov 2024 22:02:16 +0100 Subject: [PATCH 05/80] Add test --- .../datafetchers/BookingInfoImplTest.java | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 application/src/test/java/org/opentripplanner/apis/gtfs/datafetchers/BookingInfoImplTest.java diff --git a/application/src/test/java/org/opentripplanner/apis/gtfs/datafetchers/BookingInfoImplTest.java b/application/src/test/java/org/opentripplanner/apis/gtfs/datafetchers/BookingInfoImplTest.java new file mode 100644 index 00000000000..9ab76fae1ca --- /dev/null +++ b/application/src/test/java/org/opentripplanner/apis/gtfs/datafetchers/BookingInfoImplTest.java @@ -0,0 +1,43 @@ +package org.opentripplanner.apis.gtfs.datafetchers; + +import static graphql.execution.ExecutionContextBuilder.newExecutionContextBuilder; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import graphql.ExecutionInput; +import graphql.execution.ExecutionId; +import graphql.schema.DataFetchingEnvironmentImpl; +import java.time.Duration; +import java.util.Locale; +import java.util.Map; +import org.junit.jupiter.api.Test; +import org.opentripplanner.transit.model.timetable.booking.BookingInfo; + +class BookingInfoImplTest { + + @Test + void map() throws Exception { + + ExecutionInput executionInput = ExecutionInput + .newExecutionInput() + .query("") + .operationName("plan") + .locale(Locale.ENGLISH) + .build(); + + var executionContext = newExecutionContextBuilder() + .executionInput(executionInput) + .executionId(ExecutionId.from(this.getClass().getName())) + .build(); + var env = DataFetchingEnvironmentImpl + .newDataFetchingEnvironment(executionContext) + .arguments(Map.of()) + .source(BookingInfo.of().withMinimumBookingNotice(Duration.ofMinutes(10)).build()) + .build(); + var impl = new BookingInfoImpl(); + var seconds = impl.minimumBookingNoticeSeconds().get(env); + assertEquals(600, seconds); + } + + + +} \ No newline at end of file From 91d67845e70cb7ba78c7cb44dd7b646003fa908c Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Fri, 22 Nov 2024 22:14:44 +0100 Subject: [PATCH 06/80] Add tests --- .../gtfs/datafetchers/BookingInfoImpl.java | 6 +- .../datafetchers/BookingInfoImplTest.java | 59 ++++++++++--------- .../netex/mapping/BookingInfoMapperTest.java | 2 +- .../timetable/booking/BookingInfoTest.java | 2 +- 4 files changed, 38 insertions(+), 31 deletions(-) diff --git a/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/BookingInfoImpl.java b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/BookingInfoImpl.java index a3ffda526db..0060e6ad7e1 100644 --- a/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/BookingInfoImpl.java +++ b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/BookingInfoImpl.java @@ -32,7 +32,8 @@ public DataFetcher latestBookingTime() { @Override public DataFetcher maximumBookingNoticeSeconds() { - return environment -> getSource(environment).getMaximumBookingNotice().map(Duration::toSeconds).orElse(null); + return environment -> + getSource(environment).getMaximumBookingNotice().map(Duration::toSeconds).orElse(null); } @Override @@ -42,7 +43,8 @@ public DataFetcher message() { @Override public DataFetcher minimumBookingNoticeSeconds() { - return environment -> getSource(environment).getMinimumBookingNotice().map(Duration::toSeconds).orElse(null); + return environment -> + getSource(environment).getMinimumBookingNotice().map(Duration::toSeconds).orElse(null); } @Override diff --git a/application/src/test/java/org/opentripplanner/apis/gtfs/datafetchers/BookingInfoImplTest.java b/application/src/test/java/org/opentripplanner/apis/gtfs/datafetchers/BookingInfoImplTest.java index 9ab76fae1ca..1103024aa61 100644 --- a/application/src/test/java/org/opentripplanner/apis/gtfs/datafetchers/BookingInfoImplTest.java +++ b/application/src/test/java/org/opentripplanner/apis/gtfs/datafetchers/BookingInfoImplTest.java @@ -2,42 +2,47 @@ import static graphql.execution.ExecutionContextBuilder.newExecutionContextBuilder; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; -import graphql.ExecutionInput; import graphql.execution.ExecutionId; +import graphql.schema.DataFetchingEnvironment; import graphql.schema.DataFetchingEnvironmentImpl; import java.time.Duration; -import java.util.Locale; -import java.util.Map; import org.junit.jupiter.api.Test; import org.opentripplanner.transit.model.timetable.booking.BookingInfo; class BookingInfoImplTest { - @Test - void map() throws Exception { + private static final BookingInfoImpl SUBJECT = new BookingInfoImpl(); + private static final Duration TEN_MINUTES = Duration.ofMinutes(10); - ExecutionInput executionInput = ExecutionInput - .newExecutionInput() - .query("") - .operationName("plan") - .locale(Locale.ENGLISH) - .build(); + @Test + void emptyDurations() throws Exception { + var env = dataFetchingEnvironment(BookingInfo.of().build()); + assertNull(SUBJECT.minimumBookingNoticeSeconds().get(env)); + assertNull(SUBJECT.maximumBookingNoticeSeconds().get(env)); + } - var executionContext = newExecutionContextBuilder() - .executionInput(executionInput) - .executionId(ExecutionId.from(this.getClass().getName())) - .build(); - var env = DataFetchingEnvironmentImpl - .newDataFetchingEnvironment(executionContext) - .arguments(Map.of()) - .source(BookingInfo.of().withMinimumBookingNotice(Duration.ofMinutes(10)).build()) - .build(); - var impl = new BookingInfoImpl(); - var seconds = impl.minimumBookingNoticeSeconds().get(env); - assertEquals(600, seconds); - } - - + @Test + void durations() throws Exception { + var env = dataFetchingEnvironment( + BookingInfo + .of() + .withMinimumBookingNotice(TEN_MINUTES) + .withMaximumBookingNotice(TEN_MINUTES) + .build() + ); + assertEquals(600, SUBJECT.minimumBookingNoticeSeconds().get(env)); + assertEquals(600, SUBJECT.maximumBookingNoticeSeconds().get(env)); + } -} \ No newline at end of file + private DataFetchingEnvironment dataFetchingEnvironment(BookingInfo bookingInfo) { + var executionContext = newExecutionContextBuilder() + .executionId(ExecutionId.from(this.getClass().getName())) + .build(); + return DataFetchingEnvironmentImpl + .newDataFetchingEnvironment(executionContext) + .source(bookingInfo) + .build(); + } +} diff --git a/application/src/test/java/org/opentripplanner/netex/mapping/BookingInfoMapperTest.java b/application/src/test/java/org/opentripplanner/netex/mapping/BookingInfoMapperTest.java index e561a6155d3..7b917dcf912 100644 --- a/application/src/test/java/org/opentripplanner/netex/mapping/BookingInfoMapperTest.java +++ b/application/src/test/java/org/opentripplanner/netex/mapping/BookingInfoMapperTest.java @@ -193,6 +193,6 @@ void testMapMinimumBookingNotice() { BookingInfo bookingInfo = subject.map(stopPoint, null, null); - assertEquals(THIRTY_MINUTES, bookingInfo.getMinimumBookingNotice()); + assertEquals(THIRTY_MINUTES, bookingInfo.getMinimumBookingNotice().get()); } } diff --git a/application/src/test/java/org/opentripplanner/transit/model/timetable/booking/BookingInfoTest.java b/application/src/test/java/org/opentripplanner/transit/model/timetable/booking/BookingInfoTest.java index 0bf189a1c29..36587e1f696 100644 --- a/application/src/test/java/org/opentripplanner/transit/model/timetable/booking/BookingInfoTest.java +++ b/application/src/test/java/org/opentripplanner/transit/model/timetable/booking/BookingInfoTest.java @@ -58,7 +58,7 @@ void testBookingInfoWithMinBookingNotice() { .build(); assertNull(subject.getLatestBookingTime()); - assertEquals(minimumBookingNotice, subject.getMinimumBookingNotice()); + assertEquals(minimumBookingNotice, subject.getMinimumBookingNotice().get()); assertEquals( "BookingInfo{bookingMethods: [CALL_DRIVER], minimumBookingNotice: 45m}", From 8028990ba63ac01bef999087f0e98bde5fb0c683 Mon Sep 17 00:00:00 2001 From: Teemu Kalvas Date: Mon, 25 Nov 2024 10:31:38 +0200 Subject: [PATCH 07/80] test the added duration tag in OsmWay --- .../java/org/opentripplanner/osm/model/OsmWayTest.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/application/src/test/java/org/opentripplanner/osm/model/OsmWayTest.java b/application/src/test/java/org/opentripplanner/osm/model/OsmWayTest.java index 9ac9457a9ec..a659a767ff4 100644 --- a/application/src/test/java/org/opentripplanner/osm/model/OsmWayTest.java +++ b/application/src/test/java/org/opentripplanner/osm/model/OsmWayTest.java @@ -1,6 +1,8 @@ package org.opentripplanner.osm.model; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; import org.junit.jupiter.api.Test; @@ -172,6 +174,13 @@ void escalator() { escalator.addTag("conveying", "yes"); assertTrue(escalator.isEscalator()); + assertNull(escalator.getDurationSeconds()); + + escalator.addTag("duration", "00:00:61"); + assertNull(escalator.getDurationSeconds()); + escalator.addTag("duration", "00:01:01"); + assertEquals(61, escalator.getDurationSeconds()); + escalator.addTag("conveying", "whoknows?"); assertFalse(escalator.isEscalator()); } From aa3de3a455b7c2120268b391999a29596395fc09 Mon Sep 17 00:00:00 2001 From: Teemu Kalvas Date: Mon, 25 Nov 2024 14:10:48 +0200 Subject: [PATCH 08/80] ignore escalator duration tags if the speed are nonsense. include duration in debug client edge popup. --- .../graph_builder/module/osm/EscalatorProcessor.java | 11 +++++++++++ .../inspector/vector/edge/EdgePropertyMapper.java | 5 ++++- .../street/model/edge/EscalatorEdge.java | 4 ++++ 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/application/src/main/java/org/opentripplanner/graph_builder/module/osm/EscalatorProcessor.java b/application/src/main/java/org/opentripplanner/graph_builder/module/osm/EscalatorProcessor.java index 488fc96a0b3..b97458d642a 100644 --- a/application/src/main/java/org/opentripplanner/graph_builder/module/osm/EscalatorProcessor.java +++ b/application/src/main/java/org/opentripplanner/graph_builder/module/osm/EscalatorProcessor.java @@ -14,6 +14,11 @@ class EscalatorProcessor { private final Map intersectionNodes; + // If an escalator is tagged as moving less than 5 cm/s, or more than 5 m/s, + // assume it's an error and ignore it. + private static final double SLOW_ESCALATOR_ERROR_CUTOFF = 0.05; + private static final double FAST_ESCALATOR_ERROR_CUTOFF = 5.0; + public EscalatorProcessor(Map intersectionNodes) { this.intersectionNodes = intersectionNodes; } @@ -28,6 +33,12 @@ public void buildEscalatorEdge(OsmWay escalatorWay, double length) { .toList(); Integer duration = escalatorWay.getDurationSeconds(); + if (duration != null) { + double speed = length / duration; + if (speed < SLOW_ESCALATOR_ERROR_CUTOFF || speed > FAST_ESCALATOR_ERROR_CUTOFF) { + duration = null; + } + } for (int i = 0; i < nodes.size() - 1; i++) { if (escalatorWay.isForwardEscalator()) { EscalatorEdge.createEscalatorEdge( diff --git a/application/src/main/java/org/opentripplanner/inspector/vector/edge/EdgePropertyMapper.java b/application/src/main/java/org/opentripplanner/inspector/vector/edge/EdgePropertyMapper.java index 30763edca9e..13956af99c4 100644 --- a/application/src/main/java/org/opentripplanner/inspector/vector/edge/EdgePropertyMapper.java +++ b/application/src/main/java/org/opentripplanner/inspector/vector/edge/EdgePropertyMapper.java @@ -22,7 +22,10 @@ protected Collection map(Edge input) { List properties = switch (input) { case StreetEdge e -> mapStreetEdge(e); - case EscalatorEdge e -> List.of(kv("distance", e.getDistanceMeters())); + case EscalatorEdge e -> List.of( + kv("distance", e.getDistanceMeters()), + kv("duration", e.getDuration()) + ); default -> List.of(); }; return ListUtils.combine(baseProps, properties); diff --git a/application/src/main/java/org/opentripplanner/street/model/edge/EscalatorEdge.java b/application/src/main/java/org/opentripplanner/street/model/edge/EscalatorEdge.java index 6f9e9c74b2f..2e69793ccf1 100644 --- a/application/src/main/java/org/opentripplanner/street/model/edge/EscalatorEdge.java +++ b/application/src/main/java/org/opentripplanner/street/model/edge/EscalatorEdge.java @@ -49,6 +49,10 @@ public double getDistanceMeters() { return length; } + public Integer getDuration() { + return duration; + } + @Override public I18NString getName() { return NAME; From 456619446b332854f46f8337598847cef845accd Mon Sep 17 00:00:00 2001 From: Teemu Kalvas Date: Mon, 25 Nov 2024 14:29:13 +0200 Subject: [PATCH 09/80] use Optional instead of Integer which can be null --- .../module/osm/EscalatorProcessor.java | 10 ++++++---- .../java/org/opentripplanner/osm/model/OsmWay.java | 14 ++++++-------- .../street/model/edge/EscalatorEdge.java | 14 ++++++++------ 3 files changed, 20 insertions(+), 18 deletions(-) diff --git a/application/src/main/java/org/opentripplanner/graph_builder/module/osm/EscalatorProcessor.java b/application/src/main/java/org/opentripplanner/graph_builder/module/osm/EscalatorProcessor.java index b97458d642a..1d9640f0a6f 100644 --- a/application/src/main/java/org/opentripplanner/graph_builder/module/osm/EscalatorProcessor.java +++ b/application/src/main/java/org/opentripplanner/graph_builder/module/osm/EscalatorProcessor.java @@ -1,8 +1,10 @@ package org.opentripplanner.graph_builder.module.osm; +import java.time.Duration; import java.util.Arrays; import java.util.List; import java.util.Map; +import java.util.Optional; import org.opentripplanner.osm.model.OsmWay; import org.opentripplanner.street.model.edge.EscalatorEdge; import org.opentripplanner.street.model.vertex.IntersectionVertex; @@ -32,11 +34,11 @@ public void buildEscalatorEdge(OsmWay escalatorWay, double length) { .boxed() .toList(); - Integer duration = escalatorWay.getDurationSeconds(); - if (duration != null) { - double speed = length / duration; + Optional duration = escalatorWay.getDuration(); + if (duration.isPresent()) { + double speed = length / duration.get().toSeconds(); if (speed < SLOW_ESCALATOR_ERROR_CUTOFF || speed > FAST_ESCALATOR_ERROR_CUTOFF) { - duration = null; + duration = Optional.empty(); } } for (int i = 0; i < nodes.size() - 1; i++) { diff --git a/application/src/main/java/org/opentripplanner/osm/model/OsmWay.java b/application/src/main/java/org/opentripplanner/osm/model/OsmWay.java index 0819ab57b59..e80a3ab6499 100644 --- a/application/src/main/java/org/opentripplanner/osm/model/OsmWay.java +++ b/application/src/main/java/org/opentripplanner/osm/model/OsmWay.java @@ -2,7 +2,9 @@ import gnu.trove.list.TLongList; import gnu.trove.list.array.TLongArrayList; +import java.time.Duration; import java.time.format.DateTimeParseException; +import java.util.Optional; import java.util.Set; import org.opentripplanner.graph_builder.module.osm.StreetTraversalPermissionPair; import org.opentripplanner.street.model.StreetTraversalPermission; @@ -132,21 +134,17 @@ public boolean isEscalator() { return (isTag("highway", "steps") && isOneOfTags("conveying", ESCALATOR_CONVEYING_TAGS)); } - public Integer getDurationSeconds() { + public Optional getDuration() { var duration = getTag("duration"); if (duration != null) { try { - long seconds = DurationUtils.parseClockDuration(duration).getSeconds(); - if (seconds < 0 || seconds > Integer.MAX_VALUE) { - return null; - } - return (int) seconds; + return Optional.of(DurationUtils.parseClockDuration(duration)); } catch (DateTimeParseException e) { // For malformed duration tags, just pretend they weren't there. - return null; + return Optional.empty(); } } - return null; + return Optional.empty(); } public boolean isForwardEscalator() { diff --git a/application/src/main/java/org/opentripplanner/street/model/edge/EscalatorEdge.java b/application/src/main/java/org/opentripplanner/street/model/edge/EscalatorEdge.java index 2e69793ccf1..825d642373b 100644 --- a/application/src/main/java/org/opentripplanner/street/model/edge/EscalatorEdge.java +++ b/application/src/main/java/org/opentripplanner/street/model/edge/EscalatorEdge.java @@ -1,5 +1,7 @@ package org.opentripplanner.street.model.edge; +import java.time.Duration; +import java.util.Optional; import org.locationtech.jts.geom.LineString; import org.opentripplanner.framework.geometry.GeometryUtils; import org.opentripplanner.framework.i18n.I18NString; @@ -13,9 +15,9 @@ public class EscalatorEdge extends Edge { private static final LocalizedString NAME = new LocalizedString("name.escalator"); private final double length; - private final Integer duration; + private final Optional duration; - private EscalatorEdge(Vertex v1, Vertex v2, double length, Integer duration) { + private EscalatorEdge(Vertex v1, Vertex v2, double length, Optional duration) { super(v1, v2); this.length = length; this.duration = duration; @@ -27,10 +29,10 @@ public State[] traverse(State s0) { if (s0.currentMode() == TraverseMode.WALK && !s0.getRequest().wheelchair()) { var s1 = s0.edit(this); double time; - if (duration == null) { + if (duration.isEmpty()) { time = getDistanceMeters() / s0.getPreferences().street().escalator().horizontalSpeed(); } else { - time = duration; + time = duration.get().toSeconds(); } s1.incrementWeight(s0.getPreferences().walk().escalatorReluctance() * time); s1.incrementTimeInSeconds((int) Math.round(time)); @@ -49,7 +51,7 @@ public double getDistanceMeters() { return length; } - public Integer getDuration() { + public Optional getDuration() { return duration; } @@ -62,7 +64,7 @@ public static EscalatorEdge createEscalatorEdge( Vertex from, Vertex to, double length, - Integer duration + Optional duration ) { return connectToGraph(new EscalatorEdge(from, to, length, duration)); } From 3127cf35b0d8f1169034d9a86cdf571183792b3b Mon Sep 17 00:00:00 2001 From: Teemu Kalvas Date: Mon, 25 Nov 2024 14:34:54 +0200 Subject: [PATCH 10/80] test changes included --- .../org/opentripplanner/osm/model/OsmWayTest.java | 8 +++++--- .../street/model/edge/EscalatorEdgeTest.java | 14 ++++++++------ 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/application/src/test/java/org/opentripplanner/osm/model/OsmWayTest.java b/application/src/test/java/org/opentripplanner/osm/model/OsmWayTest.java index a659a767ff4..869e579e9aa 100644 --- a/application/src/test/java/org/opentripplanner/osm/model/OsmWayTest.java +++ b/application/src/test/java/org/opentripplanner/osm/model/OsmWayTest.java @@ -5,6 +5,8 @@ import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; +import java.time.Duration; +import java.util.Optional; import org.junit.jupiter.api.Test; import org.opentripplanner.osm.wayproperty.specifier.WayTestData; @@ -174,12 +176,12 @@ void escalator() { escalator.addTag("conveying", "yes"); assertTrue(escalator.isEscalator()); - assertNull(escalator.getDurationSeconds()); + assertEquals(Optional.empty(), escalator.getDuration()); escalator.addTag("duration", "00:00:61"); - assertNull(escalator.getDurationSeconds()); + assertEquals(Optional.empty(), escalator.getDuration()); escalator.addTag("duration", "00:01:01"); - assertEquals(61, escalator.getDurationSeconds()); + assertEquals(Optional.of(Duration.ofSeconds(61)), escalator.getDuration()); escalator.addTag("conveying", "whoknows?"); assertFalse(escalator.isEscalator()); diff --git a/application/src/test/java/org/opentripplanner/street/model/edge/EscalatorEdgeTest.java b/application/src/test/java/org/opentripplanner/street/model/edge/EscalatorEdgeTest.java index 9e0b4f7d297..601aeb0bc27 100644 --- a/application/src/test/java/org/opentripplanner/street/model/edge/EscalatorEdgeTest.java +++ b/application/src/test/java/org/opentripplanner/street/model/edge/EscalatorEdgeTest.java @@ -3,7 +3,9 @@ import static com.google.common.truth.Truth.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; +import java.time.Duration; import java.util.Locale; +import java.util.Optional; import java.util.stream.Stream; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; @@ -27,7 +29,7 @@ static Stream args() { @ParameterizedTest(name = "escalatorReluctance of {0} should lead to traversal costs of {1}") @MethodSource("args") void testWalking(double escalatorReluctance, double expectedWeight) { - var edge = EscalatorEdge.createEscalatorEdge(from, to, 45, null); + var edge = EscalatorEdge.createEscalatorEdge(from, to, 45, Optional.empty()); var req = StreetSearchRequest .of() .withPreferences(p -> p.withWalk(w -> w.withEscalatorReluctance(escalatorReluctance))) @@ -41,7 +43,7 @@ void testWalking(double escalatorReluctance, double expectedWeight) { @Test void testDuration() { // If duration is given, length does not affect timeDeltaSeconds, only duration does. - var edge = EscalatorEdge.createEscalatorEdge(from, to, 45, 60); + var edge = EscalatorEdge.createEscalatorEdge(from, to, 45, Optional.of(Duration.ofSeconds(60))); var req = StreetSearchRequest.of().withMode(StreetMode.WALK); var res = edge.traverse(new State(from, req.build()))[0]; assertEquals(60, res.getTimeDeltaSeconds()); @@ -49,7 +51,7 @@ void testDuration() { @Test void testCycling() { - var edge = EscalatorEdge.createEscalatorEdge(from, to, 10, null); + var edge = EscalatorEdge.createEscalatorEdge(from, to, 10, Optional.empty()); var req = StreetSearchRequest.of().withMode(StreetMode.BIKE); var res = edge.traverse(new State(from, req.build())); assertThat(res).isEmpty(); @@ -57,7 +59,7 @@ void testCycling() { @Test void testWheelchair() { - var edge = EscalatorEdge.createEscalatorEdge(from, to, 10, null); + var edge = EscalatorEdge.createEscalatorEdge(from, to, 10, Optional.empty()); var req = StreetSearchRequest.of().withMode(StreetMode.WALK).withWheelchair(true); var res = edge.traverse(new State(from, req.build())); assertThat(res).isEmpty(); @@ -65,14 +67,14 @@ void testWheelchair() { @Test void name() { - var edge = EscalatorEdge.createEscalatorEdge(from, to, 10, null); + var edge = EscalatorEdge.createEscalatorEdge(from, to, 10, Optional.empty()); assertEquals("Rolltreppe", edge.getName().toString(Locale.GERMANY)); assertEquals("escalator", edge.getName().toString(Locale.ENGLISH)); } @Test void geometry() { - var edge = EscalatorEdge.createEscalatorEdge(from, to, 10, null); + var edge = EscalatorEdge.createEscalatorEdge(from, to, 10, Optional.empty()); assertThat(edge.getGeometry().getCoordinates()).isNotEmpty(); } } From c3780efdc991e8dead9bec4ce4e3f534d2a28902 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 26 Nov 2024 04:54:32 +0000 Subject: [PATCH 11/80] Update geotools.version to v32.1 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index b520f3cad63..d7c2fdeeec7 100644 --- a/pom.xml +++ b/pom.xml @@ -60,7 +60,7 @@ 172 - 32.0 + 32.1 2.52 2.18.1 3.1.9 From 8f66e1a0c4bd3c5aad1934493b56b671393cdd40 Mon Sep 17 00:00:00 2001 From: Thomas Gran Date: Tue, 26 Nov 2024 13:22:54 +0100 Subject: [PATCH 12/80] refactor: Use ${project.build.directory} not ${build.directory} inMaven POM --- shaded-jar/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shaded-jar/pom.xml b/shaded-jar/pom.xml index fbea5d99fca..beb88b5d08a 100644 --- a/shaded-jar/pom.xml +++ b/shaded-jar/pom.xml @@ -59,7 +59,7 @@ "otp-SNAPSHOT-shaded.pom". Changing the packaging of the project is not what we want either. --> - ${build.directory}/otp-${project.version}-shaded.jar + ${project.build.directory}/otp-${project.version}-shaded.jar From 1e5aca122c89934b9a9b5382c0bb5575ff54aa1d Mon Sep 17 00:00:00 2001 From: Teemu Kalvas Date: Tue, 26 Nov 2024 14:43:15 +0200 Subject: [PATCH 13/80] use Optional upwards only --- .../module/osm/EscalatorProcessor.java | 8 ++++---- .../street/model/edge/EscalatorEdge.java | 13 +++++++------ .../street/model/edge/EscalatorEdgeTest.java | 13 ++++++------- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/application/src/main/java/org/opentripplanner/graph_builder/module/osm/EscalatorProcessor.java b/application/src/main/java/org/opentripplanner/graph_builder/module/osm/EscalatorProcessor.java index 1d9640f0a6f..22a91305f22 100644 --- a/application/src/main/java/org/opentripplanner/graph_builder/module/osm/EscalatorProcessor.java +++ b/application/src/main/java/org/opentripplanner/graph_builder/module/osm/EscalatorProcessor.java @@ -47,28 +47,28 @@ public void buildEscalatorEdge(OsmWay escalatorWay, double length) { intersectionNodes.get(nodes.get(i)), intersectionNodes.get(nodes.get(i + 1)), length, - duration + duration.orElse(null) ); } else if (escalatorWay.isBackwardEscalator()) { EscalatorEdge.createEscalatorEdge( intersectionNodes.get(nodes.get(i + 1)), intersectionNodes.get(nodes.get(i)), length, - duration + duration.orElse(null) ); } else { EscalatorEdge.createEscalatorEdge( intersectionNodes.get(nodes.get(i)), intersectionNodes.get(nodes.get(i + 1)), length, - duration + duration.orElse(null) ); EscalatorEdge.createEscalatorEdge( intersectionNodes.get(nodes.get(i + 1)), intersectionNodes.get(nodes.get(i)), length, - duration + duration.orElse(null) ); } } diff --git a/application/src/main/java/org/opentripplanner/street/model/edge/EscalatorEdge.java b/application/src/main/java/org/opentripplanner/street/model/edge/EscalatorEdge.java index 825d642373b..7dab48dc3e2 100644 --- a/application/src/main/java/org/opentripplanner/street/model/edge/EscalatorEdge.java +++ b/application/src/main/java/org/opentripplanner/street/model/edge/EscalatorEdge.java @@ -2,6 +2,7 @@ import java.time.Duration; import java.util.Optional; +import javax.annotation.Nullable; import org.locationtech.jts.geom.LineString; import org.opentripplanner.framework.geometry.GeometryUtils; import org.opentripplanner.framework.i18n.I18NString; @@ -15,9 +16,9 @@ public class EscalatorEdge extends Edge { private static final LocalizedString NAME = new LocalizedString("name.escalator"); private final double length; - private final Optional duration; + private final Duration duration; - private EscalatorEdge(Vertex v1, Vertex v2, double length, Optional duration) { + private EscalatorEdge(Vertex v1, Vertex v2, double length, Duration duration) { super(v1, v2); this.length = length; this.duration = duration; @@ -29,10 +30,10 @@ public State[] traverse(State s0) { if (s0.currentMode() == TraverseMode.WALK && !s0.getRequest().wheelchair()) { var s1 = s0.edit(this); double time; - if (duration.isEmpty()) { + if (duration == null) { time = getDistanceMeters() / s0.getPreferences().street().escalator().horizontalSpeed(); } else { - time = duration.get().toSeconds(); + time = duration.toSeconds(); } s1.incrementWeight(s0.getPreferences().walk().escalatorReluctance() * time); s1.incrementTimeInSeconds((int) Math.round(time)); @@ -52,7 +53,7 @@ public double getDistanceMeters() { } public Optional getDuration() { - return duration; + return Optional.ofNullable(duration); } @Override @@ -64,7 +65,7 @@ public static EscalatorEdge createEscalatorEdge( Vertex from, Vertex to, double length, - Optional duration + @Nullable Duration duration ) { return connectToGraph(new EscalatorEdge(from, to, length, duration)); } diff --git a/application/src/test/java/org/opentripplanner/street/model/edge/EscalatorEdgeTest.java b/application/src/test/java/org/opentripplanner/street/model/edge/EscalatorEdgeTest.java index 601aeb0bc27..25199e373a0 100644 --- a/application/src/test/java/org/opentripplanner/street/model/edge/EscalatorEdgeTest.java +++ b/application/src/test/java/org/opentripplanner/street/model/edge/EscalatorEdgeTest.java @@ -5,7 +5,6 @@ import java.time.Duration; import java.util.Locale; -import java.util.Optional; import java.util.stream.Stream; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; @@ -29,7 +28,7 @@ static Stream args() { @ParameterizedTest(name = "escalatorReluctance of {0} should lead to traversal costs of {1}") @MethodSource("args") void testWalking(double escalatorReluctance, double expectedWeight) { - var edge = EscalatorEdge.createEscalatorEdge(from, to, 45, Optional.empty()); + var edge = EscalatorEdge.createEscalatorEdge(from, to, 45, null); var req = StreetSearchRequest .of() .withPreferences(p -> p.withWalk(w -> w.withEscalatorReluctance(escalatorReluctance))) @@ -43,7 +42,7 @@ void testWalking(double escalatorReluctance, double expectedWeight) { @Test void testDuration() { // If duration is given, length does not affect timeDeltaSeconds, only duration does. - var edge = EscalatorEdge.createEscalatorEdge(from, to, 45, Optional.of(Duration.ofSeconds(60))); + var edge = EscalatorEdge.createEscalatorEdge(from, to, 45, Duration.ofSeconds(60)); var req = StreetSearchRequest.of().withMode(StreetMode.WALK); var res = edge.traverse(new State(from, req.build()))[0]; assertEquals(60, res.getTimeDeltaSeconds()); @@ -51,7 +50,7 @@ void testDuration() { @Test void testCycling() { - var edge = EscalatorEdge.createEscalatorEdge(from, to, 10, Optional.empty()); + var edge = EscalatorEdge.createEscalatorEdge(from, to, 10, null); var req = StreetSearchRequest.of().withMode(StreetMode.BIKE); var res = edge.traverse(new State(from, req.build())); assertThat(res).isEmpty(); @@ -59,7 +58,7 @@ void testCycling() { @Test void testWheelchair() { - var edge = EscalatorEdge.createEscalatorEdge(from, to, 10, Optional.empty()); + var edge = EscalatorEdge.createEscalatorEdge(from, to, 10, null); var req = StreetSearchRequest.of().withMode(StreetMode.WALK).withWheelchair(true); var res = edge.traverse(new State(from, req.build())); assertThat(res).isEmpty(); @@ -67,14 +66,14 @@ void testWheelchair() { @Test void name() { - var edge = EscalatorEdge.createEscalatorEdge(from, to, 10, Optional.empty()); + var edge = EscalatorEdge.createEscalatorEdge(from, to, 10, null); assertEquals("Rolltreppe", edge.getName().toString(Locale.GERMANY)); assertEquals("escalator", edge.getName().toString(Locale.ENGLISH)); } @Test void geometry() { - var edge = EscalatorEdge.createEscalatorEdge(from, to, 10, Optional.empty()); + var edge = EscalatorEdge.createEscalatorEdge(from, to, 10, null); assertThat(edge.getGeometry().getCoordinates()).isNotEmpty(); } } From 51faf2c23efcca1ed8711b887c18c4df409a3e77 Mon Sep 17 00:00:00 2001 From: Thomas Gran Date: Tue, 26 Nov 2024 15:07:42 +0100 Subject: [PATCH 14/80] refactor: Fix the raptor dependency on otp utils. --- pom.xml | 5 ++--- raptor/pom.xml | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/pom.xml b/pom.xml index 346dadf50c9..72c80bfc662 100644 --- a/pom.xml +++ b/pom.xml @@ -94,10 +94,10 @@ - application - gtfs-realtime-protobuf utils raptor + gtfs-realtime-protobuf + application shaded-jar @@ -132,7 +132,6 @@ ${otp.serialization.version.id} - true diff --git a/raptor/pom.xml b/raptor/pom.xml index b0bb86317e1..faf38e5f6b3 100644 --- a/raptor/pom.xml +++ b/raptor/pom.xml @@ -17,7 +17,7 @@ ${project.groupId} - otp-utils + utils ${project.version} From f6e71491b53f78a843de8addae0a450fc59e1dde Mon Sep 17 00:00:00 2001 From: Thomas Gran Date: Tue, 26 Nov 2024 16:15:40 +0100 Subject: [PATCH 15/80] refactor: Enable shade-jar by default, skip with '-DskipShadeJar' --- pom.xml | 10 ++++++++++ shaded-jar/pom.xml | 30 ++++++++---------------------- 2 files changed, 18 insertions(+), 22 deletions(-) diff --git a/pom.xml b/pom.xml index 72c80bfc662..97fcdc3b52f 100644 --- a/pom.xml +++ b/pom.xml @@ -101,7 +101,17 @@ shaded-jar + + + + + org.apache.maven.plugins + maven-shade-plugin + 3.6.0 + + + org.apache.maven.plugins diff --git a/shaded-jar/pom.xml b/shaded-jar/pom.xml index beb88b5d08a..5709ef8245f 100644 --- a/shaded-jar/pom.xml +++ b/shaded-jar/pom.xml @@ -14,6 +14,7 @@ skip + false @@ -48,7 +49,6 @@ properly if some input files are missing a terminating newline) --> org.apache.maven.plugins maven-shade-plugin - 3.6.0 true @@ -107,28 +108,13 @@ + + + build-shaded-jar + shade + + - - - shaded-jar - - - - org.apache.maven.plugins - maven-shade-plugin - - - install - - shade - - - - - - - - From 8f2c1465229654fe96e00b6843ef8a8ef4c86231 Mon Sep 17 00:00:00 2001 From: Joel Lappalainen Date: Tue, 26 Nov 2024 21:48:28 +0200 Subject: [PATCH 16/80] Remove unused GtfsGraphQlApiRentalStationFuzzyMatching feature --- .../apis/gtfs/datafetchers/QueryTypeImpl.java | 23 +------ .../framework/application/OTPFeature.java | 5 -- doc/user/Configuration.md | 67 +++++++++---------- 3 files changed, 34 insertions(+), 61 deletions(-) diff --git a/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/QueryTypeImpl.java b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/QueryTypeImpl.java index fa9623f7c55..c0b89b81fef 100644 --- a/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/QueryTypeImpl.java +++ b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/QueryTypeImpl.java @@ -37,7 +37,6 @@ import org.opentripplanner.ext.fares.impl.DefaultFareService; import org.opentripplanner.ext.fares.impl.GtfsFaresService; import org.opentripplanner.ext.fares.model.FareRuleSet; -import org.opentripplanner.framework.application.OTPFeature; import org.opentripplanner.graph_builder.issue.api.DataImportIssueStore; import org.opentripplanner.gtfs.mapping.DirectionMapper; import org.opentripplanner.model.TripTimeOnDate; @@ -56,7 +55,6 @@ import org.opentripplanner.routing.graphfinder.PatternAtStop; import org.opentripplanner.routing.graphfinder.PlaceAtDistance; import org.opentripplanner.routing.graphfinder.PlaceType; -import org.opentripplanner.routing.services.TransitAlertService; import org.opentripplanner.routing.vehicle_parking.VehicleParking; import org.opentripplanner.routing.vehicle_parking.VehicleParkingService; import org.opentripplanner.service.vehiclerental.VehicleRentalService; @@ -886,11 +884,7 @@ public DataFetcher vehicleRentalStation() { return vehicleRentalStationService .getVehicleRentalStations() .stream() - .filter(vehicleRentalStation -> - OTPFeature.GtfsGraphQlApiRentalStationFuzzyMatching.isOn() - ? stationIdFuzzyMatches(vehicleRentalStation, id) - : stationIdMatches(vehicleRentalStation, id) - ) + .filter(vehicleRentalStation -> stationIdMatches(vehicleRentalStation, id)) .findAny() .orElse(null); }; @@ -961,21 +955,6 @@ private boolean stationIdMatches(VehicleRentalStation station, String feedScoped return station.getId().toString().equals(feedScopedId); } - /** - * This matches station's feedScopedId to the given string if the string is feed scoped (i.e - * contains a `:` separator) or only matches the station's id without the feed to the given - * string. This approach can lead to a random station matching the criteria if there are multiple - * stations with the same id in different feeds. - *

- * TODO this can be potentially removed after a while, only used by Digitransit as of now. - */ - private boolean stationIdFuzzyMatches(VehicleRentalStation station, String idWithoutFeed) { - if (idWithoutFeed != null && idWithoutFeed.contains(":")) { - return stationIdMatches(station, idWithoutFeed); - } - return station.getId().getId().equals(idWithoutFeed); - } - private TransitService getTransitService(DataFetchingEnvironment environment) { return environment.getContext().transitService(); } diff --git a/application/src/main/java/org/opentripplanner/framework/application/OTPFeature.java b/application/src/main/java/org/opentripplanner/framework/application/OTPFeature.java index 6631287613b..f71283b572e 100644 --- a/application/src/main/java/org/opentripplanner/framework/application/OTPFeature.java +++ b/application/src/main/java/org/opentripplanner/framework/application/OTPFeature.java @@ -50,11 +50,6 @@ public enum OTPFeature { ), FloatingBike(true, false, "Enable floating bike routing."), GtfsGraphQlApi(true, false, "Enable the [GTFS GraphQL API](apis/GTFS-GraphQL-API.md)."), - GtfsGraphQlApiRentalStationFuzzyMatching( - false, - false, - "Does vehicleRentalStation query also allow ids that are not feed scoped." - ), /** * If this feature flag is switched on, then the minimum transfer time is not the minimum transfer * time, but the definitive transfer time. Use this to override what we think the transfer will diff --git a/doc/user/Configuration.md b/doc/user/Configuration.md index f80966b8cb3..13ba16889b1 100644 --- a/doc/user/Configuration.md +++ b/doc/user/Configuration.md @@ -219,40 +219,39 @@ Here is a list of all features which can be toggled on/off and their default val -| Feature | Description | Enabled by default | Sandbox | -|--------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:------------------:|:-------:| -| `APIBikeRental` | Enable the bike rental endpoint. | ✓️ | | -| `APIServerInfo` | Enable the server info endpoint. | ✓️ | | -| `APIUpdaterStatus` | Enable endpoint for graph updaters status. | ✓️ | | -| `IncludeEmptyRailStopsInTransfers` | Turning this on guarantees that Rail stops without scheduled departures still get included when generating transfers using `ConsiderPatternsForDirectTransfers`. It is common for stops to be assign at real-time for Rail. Turning this on will help to avoid dropping transfers which are needed, when the stop is in use later. Turning this on, if ConsiderPatternsForDirectTransfers is off has no effect. | | | -| `ConsiderPatternsForDirectTransfers` | Enable limiting transfers so that there is only a single transfer to each pattern. | ✓️ | | -| `DebugUi` | Enable the debug GraphQL client and web UI and located at the root of the web server as well as the debug map tiles it uses. Be aware that the map tiles are not a stable API and can change without notice. Use the [vector tiles feature if](sandbox/MapboxVectorTilesApi.md) you want a stable map tiles API. | ✓️ | | -| `ExtraTransferLegOnSameStop` | Should there be a transfer leg when transferring on the very same stop. Note that for in-seat/interlined transfers no transfer leg will be generated. | | | -| `FloatingBike` | Enable floating bike routing. | ✓️ | | -| `GtfsGraphQlApi` | Enable the [GTFS GraphQL API](apis/GTFS-GraphQL-API.md). | ✓️ | | -| `GtfsGraphQlApiRentalStationFuzzyMatching` | Does vehicleRentalStation query also allow ids that are not feed scoped. | | | -| `MinimumTransferTimeIsDefinitive` | If the minimum transfer time is a lower bound (default) or the definitive time for the transfer. Set this to `true` if you want to set a transfer time lower than what OTP derives from OSM data. | | | -| `OptimizeTransfers` | OTP will inspect all itineraries found and optimize where (which stops) the transfer will happen. Waiting time, priority and guaranteed transfers are taken into account. | ✓️ | | -| `ParallelRouting` | Enable performing parts of the trip planning in parallel. | | | -| `TransferConstraints` | Enforce transfers to happen according to the _transfers.txt_ (GTFS) and Interchanges (NeTEx). Turning this _off_ will increase the routing performance a little. | ✓️ | | -| `TransmodelGraphQlApi` | Enable the [Transmodel (NeTEx) GraphQL API](apis/TransmodelApi.md). | ✓️ | ✓️ | -| `ActuatorAPI` | Endpoint for actuators (service health status). | | ✓️ | -| `AsyncGraphQLFetchers` | Whether the @async annotation in the GraphQL schema should lead to the fetch being executed asynchronously. This allows batch or alias queries to run in parallel at the cost of consuming extra threads. | | | -| `Co2Emissions` | Enable the emissions sandbox module. | | ✓️ | -| `DataOverlay` | Enable usage of data overlay when calculating costs for the street network. | | ✓️ | -| `FaresV2` | Enable import of GTFS-Fares v2 data. | | ✓️ | -| `FlexRouting` | Enable FLEX routing. | | ✓️ | -| `GoogleCloudStorage` | Enable Google Cloud Storage integration. | | ✓️ | -| `LegacyRestApi` | Enable legacy REST API. This API will be removed in the future. | | ✓️ | -| `MultiCriteriaGroupMaxFilter` | Keep the best itinerary with respect to each criteria used in the transit-routing search. For example the itinerary with the lowest cost, fewest transfers, and each unique transit-group (transit-group-priority) is kept, even if the max-limit is exceeded. This is turned off by default for now, until this feature is well tested. | | | -| `RealtimeResolver` | When routing with ignoreRealtimeUpdates=true, add an extra step which populates results with real-time data | | ✓️ | -| `ReportApi` | Enable the report API. | | ✓️ | -| `RestAPIPassInDefaultConfigAsJson` | Enable a default RouteRequest to be passed in as JSON on the REST API - FOR DEBUGGING ONLY! | | | -| `SandboxAPIGeocoder` | Enable the Geocoder API. | | ✓️ | -| `SandboxAPIMapboxVectorTilesApi` | Enable Mapbox vector tiles API. | | ✓️ | -| `SandboxAPIParkAndRideApi` | Enable park-and-ride endpoint. | | ✓️ | -| `Sorlandsbanen` | Include train Sørlandsbanen in results when searching in south of Norway. Only relevant in Norway. | | ✓️ | -| `TransferAnalyzer` | Analyze transfers during graph build. | | ✓️ | +| Feature | Description | Enabled by default | Sandbox | +|--------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:------------------:|:-------:| +| `APIBikeRental` | Enable the bike rental endpoint. | ✓️ | | +| `APIServerInfo` | Enable the server info endpoint. | ✓️ | | +| `APIUpdaterStatus` | Enable endpoint for graph updaters status. | ✓️ | | +| `IncludeEmptyRailStopsInTransfers` | Turning this on guarantees that Rail stops without scheduled departures still get included when generating transfers using `ConsiderPatternsForDirectTransfers`. It is common for stops to be assign at real-time for Rail. Turning this on will help to avoid dropping transfers which are needed, when the stop is in use later. Turning this on, if ConsiderPatternsForDirectTransfers is off has no effect. | | | +| `ConsiderPatternsForDirectTransfers` | Enable limiting transfers so that there is only a single transfer to each pattern. | ✓️ | | +| `DebugUi` | Enable the debug GraphQL client and web UI and located at the root of the web server as well as the debug map tiles it uses. Be aware that the map tiles are not a stable API and can change without notice. Use the [vector tiles feature if](sandbox/MapboxVectorTilesApi.md) you want a stable map tiles API. | ✓️ | | +| `ExtraTransferLegOnSameStop` | Should there be a transfer leg when transferring on the very same stop. Note that for in-seat/interlined transfers no transfer leg will be generated. | | | +| `FloatingBike` | Enable floating bike routing. | ✓️ | | +| `GtfsGraphQlApi` | Enable the [GTFS GraphQL API](apis/GTFS-GraphQL-API.md). | ✓️ | | +| `MinimumTransferTimeIsDefinitive` | If the minimum transfer time is a lower bound (default) or the definitive time for the transfer. Set this to `true` if you want to set a transfer time lower than what OTP derives from OSM data. | | | +| `OptimizeTransfers` | OTP will inspect all itineraries found and optimize where (which stops) the transfer will happen. Waiting time, priority and guaranteed transfers are taken into account. | ✓️ | | +| `ParallelRouting` | Enable performing parts of the trip planning in parallel. | | | +| `TransferConstraints` | Enforce transfers to happen according to the _transfers.txt_ (GTFS) and Interchanges (NeTEx). Turning this _off_ will increase the routing performance a little. | ✓️ | | +| `TransmodelGraphQlApi` | Enable the [Transmodel (NeTEx) GraphQL API](apis/TransmodelApi.md). | ✓️ | ✓️ | +| `ActuatorAPI` | Endpoint for actuators (service health status). | | ✓️ | +| `AsyncGraphQLFetchers` | Whether the @async annotation in the GraphQL schema should lead to the fetch being executed asynchronously. This allows batch or alias queries to run in parallel at the cost of consuming extra threads. | | | +| `Co2Emissions` | Enable the emissions sandbox module. | | ✓️ | +| `DataOverlay` | Enable usage of data overlay when calculating costs for the street network. | | ✓️ | +| `FaresV2` | Enable import of GTFS-Fares v2 data. | | ✓️ | +| `FlexRouting` | Enable FLEX routing. | | ✓️ | +| `GoogleCloudStorage` | Enable Google Cloud Storage integration. | | ✓️ | +| `LegacyRestApi` | Enable legacy REST API. This API will be removed in the future. | | ✓️ | +| `MultiCriteriaGroupMaxFilter` | Keep the best itinerary with respect to each criteria used in the transit-routing search. For example the itinerary with the lowest cost, fewest transfers, and each unique transit-group (transit-group-priority) is kept, even if the max-limit is exceeded. This is turned off by default for now, until this feature is well tested. | | | +| `RealtimeResolver` | When routing with ignoreRealtimeUpdates=true, add an extra step which populates results with real-time data | | ✓️ | +| `ReportApi` | Enable the report API. | | ✓️ | +| `RestAPIPassInDefaultConfigAsJson` | Enable a default RouteRequest to be passed in as JSON on the REST API - FOR DEBUGGING ONLY! | | | +| `SandboxAPIGeocoder` | Enable the Geocoder API. | | ✓️ | +| `SandboxAPIMapboxVectorTilesApi` | Enable Mapbox vector tiles API. | | ✓️ | +| `SandboxAPIParkAndRideApi` | Enable park-and-ride endpoint. | | ✓️ | +| `Sorlandsbanen` | Include train Sørlandsbanen in results when searching in south of Norway. Only relevant in Norway. | | ✓️ | +| `TransferAnalyzer` | Analyze transfers during graph build. | | ✓️ | From 7df8f99371d16c45229285cc9697bd67bb8db6c0 Mon Sep 17 00:00:00 2001 From: Thomas Gran Date: Tue, 26 Nov 2024 20:50:31 +0100 Subject: [PATCH 17/80] Analysis and design documentation --- DEVELOPMENT_DECISION_RECORDS.md | 6 +++ doc/dev/decisionrecords/AnalysesAndDesign.md | 51 ++++++++++++++++++++ doc/dev/images/DomainModelNotation.svg | 4 ++ 3 files changed, 61 insertions(+) create mode 100644 doc/dev/decisionrecords/AnalysesAndDesign.md create mode 100644 doc/dev/images/DomainModelNotation.svg diff --git a/DEVELOPMENT_DECISION_RECORDS.md b/DEVELOPMENT_DECISION_RECORDS.md index 44aa031954f..2625be325e8 100644 --- a/DEVELOPMENT_DECISION_RECORDS.md +++ b/DEVELOPMENT_DECISION_RECORDS.md @@ -19,6 +19,12 @@ Use established terminology from GTFS, NeTEx or the existing OTP code. Make sure to read and understand. [Follow naming conventions](doc/dev/decisionrecords/NamingConventions.md#naming-conventions) . +## Do Analysis-and-design if needed + +Be prepared to provide [analyses and/or design documentation](doc/dev/decisionrecords/AnalysesAndDesign.md) +if a task is complex, changes the core model and/or the main APIs. + + ## Write-Code-Documentation - Use JavaDoc Document the business intention and decisions in the relevant code. Do not repeat the logic diff --git a/doc/dev/decisionrecords/AnalysesAndDesign.md b/doc/dev/decisionrecords/AnalysesAndDesign.md new file mode 100644 index 00000000000..dbfca09c693 --- /dev/null +++ b/doc/dev/decisionrecords/AnalysesAndDesign.md @@ -0,0 +1,51 @@ +# Analysis and design + +We want to get better at design, so we want some documentation up font for large changes. If a +problem is complex, changes the core OTP model, and/or the API significantly, then the developer +requesting a change should be prepared to provide some design documentation. + +The analysis should be started and at least mapped out in an issue. The design can be documented +in the issue or the PR. + + +## Analysis & Design + +A discussion in a developer meeting is usually a good point to start. + +- Ask what is expected? +- Diagrams beat words in most cases, and help focus on the problem - not implementation details. + + +### Artifacts + +We usually do not require a long list of requirements and analyses documentation. But these +artifacts may help, none of these are required. Ask in the developer meeting what to expect. + + - [ ] Summarise the discussion in the developer meeting in the issue or PR. + - [ ] List use-cases, one sentence per use-case is often enough. + - [ ] In/out matrix, list features you are NOT planning to implement. + - [ ] Draw diagrams + - [ ] **Domain model** — If the core model or APIs are significantly changed + - [ ] State diagram + - [ ] Collaboration diagram + + +## Domain model + +A domain model focus on the language and the relationships. All implementation details can be left +out. Details witch is not relevant for the problem you are solving can also be left out, focus on +the elements witch helps understand the problem. Use plain english and not tech to describe +the model. For example, only listing the field name, and not the type is ok if the type is obvious. + +Notation is not important, but try to follow the UML syntax below. You may use more advanced UML +syntax if you want, but keep in mind that you should be able to use the diagram to discuss the +problem with a none developer. A product-owner or other person who knows the domain should with +a little help be able to understand the main parts of the drawing. + +When doing review, focus on the domain problem, not syntax — ask about things you do not understand. + + +### Domain model - notation cheat sheet + +![Domain Model Notation](../images/DomainModelNotation.svg) + diff --git a/doc/dev/images/DomainModelNotation.svg b/doc/dev/images/DomainModelNotation.svg new file mode 100644 index 00000000000..836363f4372 --- /dev/null +++ b/doc/dev/images/DomainModelNotation.svg @@ -0,0 +1,4 @@ + + + +ServicecanceledTrips(...) : TripOnDateEntityfield : basic type / scalarA<<interface>>Baseid : IDEvent/Moment/IntervalValueObjectvalue : String
Colors
Colors
Types
Types
objectName : Type/Class<<interface>>Interface/abstract class
Relationship
Relation...
Afield : basic type / scalarB
b
b
?
?
AB
b
b
B
Inheritance
Inherita...
<< use >>
<< use >>
AB
Dependency
Dependen...
[ Bike only ]
[ Bike only ]
Amode : Mode[ GTFS only ]B
Constraint
Constrai...
  • We usually provide a class name only, but you can provide an object name and/or class. 
  • If something is an abstract class or an interface is a implementation detail. Use the <<interface>>` qualifier to tag interfaces.
We usually provide a class name only, but you can...
  • Relationship can be one way (arrow) or both-ways (no arrows).
  • Naming the relationship is optional.
  • Default cardinality is 1. Other values:
    • ? - optional
    • * - many
    • 2 - exact two
    • 3..n - three or more
  • A simple relationship is included as a field. A good indication when to use a field and not an arrow is when the type is a basic type(int, float, boolean, String), enumeration or ValueObject. PS! It is not wrong to use either, both forms are equivalent
Relationship can be one way (arrow) or both-ways (...
2..n
2..n
*
*
AB
a
a
b
b
  • If you are in doubt model things as relationships, do not use inheritance.
  • Interfaces exist:
    • if there is a reference to it - the named interface play a role.
    • if at least one shared operation/field/relationship exist.  
If you are in doubt model things as relationships,...
  • We draw dependencies when they are important and not part of a relationship. For example if we want to map out the details of a ValueObject.
  • The qualifier text << use >> is optonal.
We draw dependencies when they are important and n...
  • Use "[]" to add a constraint.
  • A constraint can be added to all arrows and types.
  • Be careful with constraints, they add a lot of noice to the diagram. It is sometimes better to just list tem in text.
Use "[]" to add a constraint.A constraint can be a...
A has a field b of type B.
A has a field b of type B.
A has a 2 or more b's of type B. B has many a's of type A.
A has a 2 or more b's of type B. B has many a's of type...
We use color for classify the a type by its life-cycle. A service is request or application scoped, an entity is sable - but may change, a ValueObject do not change, and a Event are temporary. A ValueObject can not reference a Entity, an Entity can not reference a Service and always pay close attention to the design of Events - they are hard to model.  
We use color for classify the a type by its life-cycle. A service is request or application scoped, an entity is sable - but may c...
A has a relationship b, if mode is Bike.
B only exist for GTFS imported elements.
A has a relationship b, if mode is Bike....
Text is not SVG - cannot display
\ No newline at end of file From bfea1bc154195e2cb2a06611dd01f9742e64752c Mon Sep 17 00:00:00 2001 From: Thomas Gran Date: Wed, 27 Nov 2024 10:56:18 +0100 Subject: [PATCH 18/80] Apply suggestions from code review Co-authored-by: Leonard Ehrenfried --- doc/dev/decisionrecords/AnalysesAndDesign.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/doc/dev/decisionrecords/AnalysesAndDesign.md b/doc/dev/decisionrecords/AnalysesAndDesign.md index dbfca09c693..4658336812b 100644 --- a/doc/dev/decisionrecords/AnalysesAndDesign.md +++ b/doc/dev/decisionrecords/AnalysesAndDesign.md @@ -1,6 +1,6 @@ # Analysis and design -We want to get better at design, so we want some documentation up font for large changes. If a +We want to get better at design, so we want some documentation up front for large changes. If a problem is complex, changes the core OTP model, and/or the API significantly, then the developer requesting a change should be prepared to provide some design documentation. @@ -19,7 +19,7 @@ A discussion in a developer meeting is usually a good point to start. ### Artifacts We usually do not require a long list of requirements and analyses documentation. But these -artifacts may help, none of these are required. Ask in the developer meeting what to expect. +artifacts may help, but none of these are required. Ask in the developer meeting what to expect. - [ ] Summarise the discussion in the developer meeting in the issue or PR. - [ ] List use-cases, one sentence per use-case is often enough. @@ -32,14 +32,14 @@ artifacts may help, none of these are required. Ask in the developer meeting wha ## Domain model -A domain model focus on the language and the relationships. All implementation details can be left -out. Details witch is not relevant for the problem you are solving can also be left out, focus on +A domain model focusses on the language and the relationships. All implementation details can be left +out. Details which is not relevant for the problem you are solving can also be left out, focus on the elements witch helps understand the problem. Use plain english and not tech to describe the model. For example, only listing the field name, and not the type is ok if the type is obvious. Notation is not important, but try to follow the UML syntax below. You may use more advanced UML syntax if you want, but keep in mind that you should be able to use the diagram to discuss the -problem with a none developer. A product-owner or other person who knows the domain should with +problem with a non-developer. A product-owner or other person who knows the domain should with a little help be able to understand the main parts of the drawing. When doing review, focus on the domain problem, not syntax — ask about things you do not understand. From 307e5393e855d29f513ad28ec410fc53ead905b3 Mon Sep 17 00:00:00 2001 From: Thomas Gran Date: Wed, 27 Nov 2024 11:26:27 +0100 Subject: [PATCH 19/80] doc: Add recommendation for drawing tool --- doc/dev/decisionrecords/AnalysesAndDesign.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/dev/decisionrecords/AnalysesAndDesign.md b/doc/dev/decisionrecords/AnalysesAndDesign.md index 4658336812b..b6c585ba71f 100644 --- a/doc/dev/decisionrecords/AnalysesAndDesign.md +++ b/doc/dev/decisionrecords/AnalysesAndDesign.md @@ -29,6 +29,9 @@ artifacts may help, but none of these are required. Ask in the developer meeting - [ ] State diagram - [ ] Collaboration diagram +We recommend using [draw.io](https://www.drawio.com/). It is free and available as an Intellij +plugin (Diagrams.net), web application and desktop application. + ## Domain model From 90068af8a875600964e8d5adde966fefb7118379 Mon Sep 17 00:00:00 2001 From: Thomas Gran Date: Wed, 27 Nov 2024 11:26:42 +0100 Subject: [PATCH 20/80] doc: Fix broken links --- ARCHITECTURE.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index cf3efcd84a3..36ab454789a 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -55,7 +55,7 @@ Used to import NeTEx transit data files. ### Transit Routing -#### [Raptor transit routing](application/src/main/java/org/opentripplanner/raptor/package.md) +#### [Raptor transit routing](raptor/src/main/java/org/opentripplanner/raptor/package.md) This is the OTP2 new transit routing engine implemented using the Raptor algorithm. It explains how Raptor works, the important concepts and the design. It might be worth reading even if you are not a @@ -71,9 +71,9 @@ implementation is highly critical code, hence we set the bar higher with respect OTP provides transit data to Raptor by implementing the _raptor/spi_. The [RoutingService](application/src/main/java/org/opentripplanner/routing/service/DefaultRoutingService.java) is responsible for mapping from the OTP context to a -[RaptorRequest](application/src/main/java/org/opentripplanner/raptor/api/request/RaptorRequest.java) +[RaptorRequest](raptor/src/main/java/org/opentripplanner/raptor/api/request/RaptorRequest.java) and then map the -result, [Raptor Path](application/src/main/java/org/opentripplanner/raptor/api/path/RaptorPath.java), back to +result, [Raptor Path](raptor/src/main/java/org/opentripplanner/raptor/api/path/RaptorPath.java), back to the OTP internal domain. This might seem like a lot of unnecessary mapping, but mapping is simple - routing is not. From e1d3a22a4f9db80d27176a348a47ccacaeaeb05e Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Thu, 28 Nov 2024 10:57:42 +0100 Subject: [PATCH 21/80] Make ways with motorroad=yes car-only --- .../osm/tagmapping/FinlandMapper.java | 3 -- .../osm/tagmapping/OsmTagMapper.java | 4 +- .../osm/tagmapping/OsmTagMapperTest.java | 42 +++++++++++++------ doc/user/osm/Finland.md | 2 +- doc/user/osm/Germany.md | 1 + doc/user/osm/OsmTag.md | 1 + doc/user/osm/UK.md | 1 + 7 files changed, 36 insertions(+), 18 deletions(-) diff --git a/application/src/main/java/org/opentripplanner/osm/tagmapping/FinlandMapper.java b/application/src/main/java/org/opentripplanner/osm/tagmapping/FinlandMapper.java index e9ac9478552..d9ddd1ede76 100644 --- a/application/src/main/java/org/opentripplanner/osm/tagmapping/FinlandMapper.java +++ b/application/src/main/java/org/opentripplanner/osm/tagmapping/FinlandMapper.java @@ -84,9 +84,6 @@ else if (speedLimit <= 16.65f) { // Don't recommend walking in trunk road tunnels props.setProperties("highway=trunk;tunnel=yes", withModes(CAR).bicycleSafety(7.47)); - // Do not walk on "moottoriliikennetie" - props.setProperties("motorroad=yes", withModes(CAR).bicycleSafety(7.47)); - // Remove informal and private roads props.setProperties("highway=*;informal=yes", withModes(NONE)); props.setProperties("highway=service;access=private", withModes(NONE)); diff --git a/application/src/main/java/org/opentripplanner/osm/tagmapping/OsmTagMapper.java b/application/src/main/java/org/opentripplanner/osm/tagmapping/OsmTagMapper.java index 2df3c22d6a9..60cd8d0ac74 100644 --- a/application/src/main/java/org/opentripplanner/osm/tagmapping/OsmTagMapper.java +++ b/application/src/main/java/org/opentripplanner/osm/tagmapping/OsmTagMapper.java @@ -14,7 +14,6 @@ import org.opentripplanner.osm.wayproperty.WayProperties; import org.opentripplanner.osm.wayproperty.WayPropertySet; import org.opentripplanner.osm.wayproperty.specifier.BestMatchSpecifier; -import org.opentripplanner.osm.wayproperty.specifier.Condition; import org.opentripplanner.osm.wayproperty.specifier.ExactMatchSpecifier; import org.opentripplanner.osm.wayproperty.specifier.LogicalOrSpecifier; import org.opentripplanner.routing.services.notes.StreetNotesService; @@ -104,6 +103,9 @@ public void populateProperties(WayPropertySet props) { props.setProperties("highway=trunk", withModes(CAR).bicycleSafety(7.47)); props.setProperties("highway=motorway", withModes(CAR).bicycleSafety(8)); + // Do not walk on "moottoriliikennetie"/"Kraftfahrstrasse" + props.setProperties(new ExactMatchSpecifier("motorroad=yes"), withModes(CAR)); + /* cycleway=lane */ props.setProperties( "highway=*;cycleway=lane", diff --git a/application/src/test/java/org/opentripplanner/osm/tagmapping/OsmTagMapperTest.java b/application/src/test/java/org/opentripplanner/osm/tagmapping/OsmTagMapperTest.java index b3ee57f9710..c5124fbd55a 100644 --- a/application/src/test/java/org/opentripplanner/osm/tagmapping/OsmTagMapperTest.java +++ b/application/src/test/java/org/opentripplanner/osm/tagmapping/OsmTagMapperTest.java @@ -3,15 +3,18 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.opentripplanner.street.model.StreetTraversalPermission.ALL; import static org.opentripplanner.street.model.StreetTraversalPermission.CAR; import org.junit.jupiter.api.Test; import org.opentripplanner.osm.model.OsmWithTags; +import org.opentripplanner.osm.wayproperty.WayPropertySet; +import org.opentripplanner.osm.wayproperty.specifier.WayTestData; -public class OsmTagMapperTest { +class OsmTagMapperTest { @Test - public void isMotorThroughTrafficExplicitlyDisallowed() { + void isMotorThroughTrafficExplicitlyDisallowed() { OsmWithTags o = new OsmWithTags(); OsmTagMapper osmTagMapper = new OsmTagMapper(); @@ -34,7 +37,7 @@ public void isMotorThroughTrafficExplicitlyDisallowed() { } @Test - public void isBicycleThroughTrafficExplicitlyDisallowed() { + void isBicycleThroughTrafficExplicitlyDisallowed() { OsmTagMapper osmTagMapper = new OsmTagMapper(); assertTrue( osmTagMapper.isBicycleThroughTrafficExplicitlyDisallowed(way("bicycle", "destination")) @@ -45,14 +48,14 @@ public void isBicycleThroughTrafficExplicitlyDisallowed() { } @Test - public void isWalkThroughTrafficExplicitlyDisallowed() { + void isWalkThroughTrafficExplicitlyDisallowed() { OsmTagMapper osmTagMapper = new OsmTagMapper(); assertTrue(osmTagMapper.isWalkThroughTrafficExplicitlyDisallowed(way("foot", "destination"))); assertTrue(osmTagMapper.isWalkThroughTrafficExplicitlyDisallowed(way("access", "destination"))); } @Test - public void testAccessNo() { + void testAccessNo() { OsmWithTags tags = new OsmWithTags(); OsmTagMapper osmTagMapper = new OsmTagMapper(); @@ -64,7 +67,7 @@ public void testAccessNo() { } @Test - public void testAccessPrivate() { + void testAccessPrivate() { OsmWithTags tags = new OsmWithTags(); OsmTagMapper osmTagMapper = new OsmTagMapper(); @@ -76,7 +79,7 @@ public void testAccessPrivate() { } @Test - public void testFootModifier() { + void testFootModifier() { OsmWithTags tags = new OsmWithTags(); OsmTagMapper osmTagMapper = new OsmTagMapper(); @@ -89,7 +92,7 @@ public void testFootModifier() { } @Test - public void testVehicleDenied() { + void testVehicleDenied() { OsmWithTags tags = new OsmWithTags(); OsmTagMapper osmTagMapper = new OsmTagMapper(); @@ -101,7 +104,7 @@ public void testVehicleDenied() { } @Test - public void testVehicleDeniedMotorVehiclePermissive() { + void testVehicleDeniedMotorVehiclePermissive() { OsmWithTags tags = new OsmWithTags(); OsmTagMapper osmTagMapper = new OsmTagMapper(); @@ -114,7 +117,7 @@ public void testVehicleDeniedMotorVehiclePermissive() { } @Test - public void testVehicleDeniedBicyclePermissive() { + void testVehicleDeniedBicyclePermissive() { OsmWithTags tags = new OsmWithTags(); OsmTagMapper osmTagMapper = new OsmTagMapper(); @@ -127,7 +130,7 @@ public void testVehicleDeniedBicyclePermissive() { } @Test - public void testMotorcycleModifier() { + void testMotorcycleModifier() { OsmWithTags tags = new OsmWithTags(); OsmTagMapper osmTagMapper = new OsmTagMapper(); @@ -140,7 +143,7 @@ public void testMotorcycleModifier() { } @Test - public void testBicycleModifier() { + void testBicycleModifier() { OsmWithTags tags = new OsmWithTags(); OsmTagMapper osmTagMapper = new OsmTagMapper(); @@ -153,7 +156,7 @@ public void testBicycleModifier() { } @Test - public void testBicyclePermissive() { + void testBicyclePermissive() { OsmWithTags tags = new OsmWithTags(); OsmTagMapper osmTagMapper = new OsmTagMapper(); @@ -165,6 +168,19 @@ public void testBicyclePermissive() { assertTrue(osmTagMapper.isWalkThroughTrafficExplicitlyDisallowed(tags)); } + @Test + void motorroad() { + OsmTagMapper osmTagMapper = new OsmTagMapper(); + WayPropertySet wps = new WayPropertySet(); + osmTagMapper.populateProperties(wps); + + var way = WayTestData.carTunnel(); + assertEquals(ALL, wps.getDataForWay(way).getPermission()); + + way.addTag("motorroad","yes"); + assertEquals(CAR, wps.getDataForWay(way).getPermission()); + } + public OsmWithTags way(String key, String value) { var way = new OsmWithTags(); way.addTag(key, value); diff --git a/doc/user/osm/Finland.md b/doc/user/osm/Finland.md index 8a60b5f0b13..a5a0341bf94 100644 --- a/doc/user/osm/Finland.md +++ b/doc/user/osm/Finland.md @@ -41,7 +41,6 @@ Lower safety values make an OSM way more desirable and higher values less desira | `highway=trunk_link` | `ALL` | 2.06 | | | `highway=trunk` | `ALL` | 7.47 | | | `highway=trunk; tunnel=yes` | `CAR` | 7.47 | | -| `motorroad=yes` | `CAR` | 7.47 | | | `present(highway); informal=yes` | `NONE` | | | | `highway=service; access=private` | `NONE` | | | | `highway=trail` | `NONE` | | | @@ -105,6 +104,7 @@ Lower safety values make an OSM way more desirable and higher values less desira | `highway=motorway_link` | `CAR` | 2.06 | | | `highway=trunk` | `CAR` | 7.47 | | | `highway=motorway` | `CAR` | 8.0 | | +| `motorroad=yes` | `CAR` | | | | `present(highway); cycleway=lane` | `PEDESTRIAN_AND_BICYCLE` | 0.87 | | | `highway=service; cycleway=lane` | `ALL` | 0.77 | | | `highway=residential; cycleway=lane` | `ALL` | 0.77 | | diff --git a/doc/user/osm/Germany.md b/doc/user/osm/Germany.md index 922aa3af836..ee9e3982362 100644 --- a/doc/user/osm/Germany.md +++ b/doc/user/osm/Germany.md @@ -70,6 +70,7 @@ Lower safety values make an OSM way more desirable and higher values less desira | `highway=motorway_link` | `CAR` | 2.06 | | | `highway=trunk` | `CAR` | 7.47 | | | `highway=motorway` | `CAR` | 8.0 | | +| `motorroad=yes` | `CAR` | | | | `present(highway); cycleway=lane` | `PEDESTRIAN_AND_BICYCLE` | 0.87 | | | `highway=service; cycleway=lane` | `ALL` | 0.77 | | | `highway=residential; cycleway=lane` | `ALL` | 0.77 | | diff --git a/doc/user/osm/OsmTag.md b/doc/user/osm/OsmTag.md index 814420b791f..9456dbc9fa5 100644 --- a/doc/user/osm/OsmTag.md +++ b/doc/user/osm/OsmTag.md @@ -61,6 +61,7 @@ Lower safety values make an OSM way more desirable and higher values less desira | `highway=motorway_link` | `CAR` | 2.06 | | | `highway=trunk` | `CAR` | 7.47 | | | `highway=motorway` | `CAR` | 8.0 | | +| `motorroad=yes` | `CAR` | | | | `present(highway); cycleway=lane` | `PEDESTRIAN_AND_BICYCLE` | 0.87 | | | `highway=service; cycleway=lane` | `ALL` | 0.77 | | | `highway=residential; cycleway=lane` | `ALL` | 0.77 | | diff --git a/doc/user/osm/UK.md b/doc/user/osm/UK.md index 34c4d1c1778..f9d8678fd3c 100644 --- a/doc/user/osm/UK.md +++ b/doc/user/osm/UK.md @@ -77,6 +77,7 @@ Lower safety values make an OSM way more desirable and higher values less desira | `highway=motorway_link` | `CAR` | 2.06 | | | `highway=trunk` | `CAR` | 7.47 | | | `highway=motorway` | `CAR` | 8.0 | | +| `motorroad=yes` | `CAR` | | | | `present(highway); cycleway=lane` | `PEDESTRIAN_AND_BICYCLE` | 0.87 | | | `highway=service; cycleway=lane` | `ALL` | 0.77 | | | `highway=residential; cycleway=lane` | `ALL` | 0.77 | | From 906819c304bbf1f8801e9cf72c2609326a0b5d89 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Thu, 28 Nov 2024 11:15:27 +0100 Subject: [PATCH 22/80] Add test in Finland --- .../osm/tagmapping/FinlandMapperTest.java | 28 ++++++++++++++----- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/application/src/test/java/org/opentripplanner/osm/tagmapping/FinlandMapperTest.java b/application/src/test/java/org/opentripplanner/osm/tagmapping/FinlandMapperTest.java index f8b07e06bf6..84d9d0ca14e 100644 --- a/application/src/test/java/org/opentripplanner/osm/tagmapping/FinlandMapperTest.java +++ b/application/src/test/java/org/opentripplanner/osm/tagmapping/FinlandMapperTest.java @@ -2,6 +2,8 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.opentripplanner.street.model.StreetTraversalPermission.ALL; +import static org.opentripplanner.street.model.StreetTraversalPermission.CAR; import static org.opentripplanner.street.model.StreetTraversalPermission.NONE; import static org.opentripplanner.street.model.StreetTraversalPermission.PEDESTRIAN; import static org.opentripplanner.street.model.StreetTraversalPermission.PEDESTRIAN_AND_BICYCLE; @@ -12,15 +14,16 @@ import org.opentripplanner.osm.model.OsmWithTags; import org.opentripplanner.osm.wayproperty.WayProperties; import org.opentripplanner.osm.wayproperty.WayPropertySet; +import org.opentripplanner.osm.wayproperty.specifier.WayTestData; -public class FinlandMapperTest { +class FinlandMapperTest { private WayPropertySet wps; private OsmTagMapper mapper; static float epsilon = 0.01f; @BeforeEach - public void setup() { + void setup() { this.wps = new WayPropertySet(); this.mapper = new FinlandMapper(); this.mapper.populateProperties(this.wps); @@ -30,7 +33,7 @@ public void setup() { * Test that bike and walk safety factors are calculated accurately */ @Test - public void testSafety() { + void testSafety() { OsmWithTags primaryWay = new OsmWithTags(); primaryWay.addTag("highway", "primary"); primaryWay.addTag("oneway", "no"); @@ -141,7 +144,7 @@ public void testSafety() { } @Test - public void testSafetyWithMixins() { + void testSafetyWithMixins() { OsmWithTags wayWithMixins = new OsmWithTags(); // highway=service has no custom bicycle or walk safety wayWithMixins.addTag("highway", "unclassified"); @@ -179,7 +182,7 @@ public void testSafetyWithMixins() { } @Test - public void testTagMapping() { + void testTagMapping() { OsmWithTags way; WayProperties wayData; @@ -206,7 +209,7 @@ public void testTagMapping() { * Test that biking is not allowed in footway areas and transit platforms */ @Test - public void testArea() { + void testArea() { OsmWithTags way; WayProperties wayData; @@ -227,10 +230,21 @@ public void testArea() { } @Test - public void serviceNoThroughTraffic() { + void serviceNoThroughTraffic() { var way = new OsmWay(); way.addTag("highway", "residential"); way.addTag("service", "driveway"); assertTrue(mapper.isMotorVehicleThroughTrafficExplicitlyDisallowed(way)); } + + @Test + void motorroad() { + OsmTagMapper osmTagMapper = new FinlandMapper(); + WayPropertySet wps = new WayPropertySet(); + osmTagMapper.populateProperties(wps); + var way = WayTestData.carTunnel(); + assertEquals(ALL, wps.getDataForWay(way).getPermission()); + way.addTag("motorroad","yes"); + assertEquals(CAR, wps.getDataForWay(way).getPermission()); + } } From 66acd4546379c8b7c7d5a2a85228d84bc07f6cc6 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Thu, 28 Nov 2024 11:24:25 +0100 Subject: [PATCH 23/80] Add more test parameters --- .../osm/tagmapping/FinlandMapperTest.java | 2 +- .../osm/tagmapping/OsmTagMapperTest.java | 21 +++++++++++++++---- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/application/src/test/java/org/opentripplanner/osm/tagmapping/FinlandMapperTest.java b/application/src/test/java/org/opentripplanner/osm/tagmapping/FinlandMapperTest.java index 84d9d0ca14e..ecbd2eec3be 100644 --- a/application/src/test/java/org/opentripplanner/osm/tagmapping/FinlandMapperTest.java +++ b/application/src/test/java/org/opentripplanner/osm/tagmapping/FinlandMapperTest.java @@ -244,7 +244,7 @@ void motorroad() { osmTagMapper.populateProperties(wps); var way = WayTestData.carTunnel(); assertEquals(ALL, wps.getDataForWay(way).getPermission()); - way.addTag("motorroad","yes"); + way.addTag("motorroad", "yes"); assertEquals(CAR, wps.getDataForWay(way).getPermission()); } } diff --git a/application/src/test/java/org/opentripplanner/osm/tagmapping/OsmTagMapperTest.java b/application/src/test/java/org/opentripplanner/osm/tagmapping/OsmTagMapperTest.java index c5124fbd55a..5448f84294d 100644 --- a/application/src/test/java/org/opentripplanner/osm/tagmapping/OsmTagMapperTest.java +++ b/application/src/test/java/org/opentripplanner/osm/tagmapping/OsmTagMapperTest.java @@ -6,7 +6,10 @@ import static org.opentripplanner.street.model.StreetTraversalPermission.ALL; import static org.opentripplanner.street.model.StreetTraversalPermission.CAR; +import java.util.List; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; import org.opentripplanner.osm.model.OsmWithTags; import org.opentripplanner.osm.wayproperty.WayPropertySet; import org.opentripplanner.osm.wayproperty.specifier.WayTestData; @@ -168,16 +171,26 @@ void testBicyclePermissive() { assertTrue(osmTagMapper.isWalkThroughTrafficExplicitlyDisallowed(tags)); } - @Test - void motorroad() { + public static List roadCases() { + return List.of( + WayTestData.carTunnel(), + WayTestData.southwestMayoStreet(), + WayTestData.southeastLaBonitaWay(), + WayTestData.fiveLanes(), + WayTestData.highwayTertiary() + ); + } + + @ParameterizedTest + @MethodSource("roadCases") + void motorroad(OsmWithTags way) { OsmTagMapper osmTagMapper = new OsmTagMapper(); WayPropertySet wps = new WayPropertySet(); osmTagMapper.populateProperties(wps); - var way = WayTestData.carTunnel(); assertEquals(ALL, wps.getDataForWay(way).getPermission()); - way.addTag("motorroad","yes"); + way.addTag("motorroad", "yes"); assertEquals(CAR, wps.getDataForWay(way).getPermission()); } From 627b3fd84aec882a5f68d09271941e2f1508f588 Mon Sep 17 00:00:00 2001 From: Teemu Kalvas Date: Thu, 28 Nov 2024 15:26:31 +0200 Subject: [PATCH 24/80] add bad duration tags to issue store, better testing of duration parsing --- .../module/osm/EscalatorProcessor.java | 28 ++++++- .../graph_builder/module/osm/OsmModule.java | 5 +- .../org/opentripplanner/osm/model/OsmWay.java | 14 +--- .../osm/model/OsmWithTags.java | 66 +++++++++++++++++ .../preference/EscalatorPreferences.java | 74 ------------------- .../request/preference/StreetPreferences.java | 16 ---- .../request/preference/WalkPreferences.java | 33 +++++++-- .../routerequest/RouteRequestConfig.java | 18 ++--- .../street/model/edge/EscalatorEdge.java | 6 +- .../opentripplanner/osm/model/OsmWayTest.java | 8 +- .../osm/model/OsmWithTagsTest.java | 23 ++++++ .../standalone/config/router-config.json | 3 +- doc/user/RouteRequest.md | 14 +++- doc/user/RouterConfiguration.md | 3 +- .../utils/time/DurationUtils.java | 43 ----------- .../utils/time/DurationUtilsTest.java | 15 ---- 16 files changed, 179 insertions(+), 190 deletions(-) delete mode 100644 application/src/main/java/org/opentripplanner/routing/api/request/preference/EscalatorPreferences.java diff --git a/application/src/main/java/org/opentripplanner/graph_builder/module/osm/EscalatorProcessor.java b/application/src/main/java/org/opentripplanner/graph_builder/module/osm/EscalatorProcessor.java index 22a91305f22..c8f4e0e0042 100644 --- a/application/src/main/java/org/opentripplanner/graph_builder/module/osm/EscalatorProcessor.java +++ b/application/src/main/java/org/opentripplanner/graph_builder/module/osm/EscalatorProcessor.java @@ -5,6 +5,8 @@ import java.util.List; import java.util.Map; import java.util.Optional; +import org.opentripplanner.graph_builder.issue.api.DataImportIssueStore; +import org.opentripplanner.graph_builder.issue.api.Issue; import org.opentripplanner.osm.model.OsmWay; import org.opentripplanner.street.model.edge.EscalatorEdge; import org.opentripplanner.street.model.vertex.IntersectionVertex; @@ -15,14 +17,19 @@ class EscalatorProcessor { private final Map intersectionNodes; + private final DataImportIssueStore issueStore; // If an escalator is tagged as moving less than 5 cm/s, or more than 5 m/s, // assume it's an error and ignore it. private static final double SLOW_ESCALATOR_ERROR_CUTOFF = 0.05; private static final double FAST_ESCALATOR_ERROR_CUTOFF = 5.0; - public EscalatorProcessor(Map intersectionNodes) { + public EscalatorProcessor( + Map intersectionNodes, + DataImportIssueStore issueStore + ) { this.intersectionNodes = intersectionNodes; + this.issueStore = issueStore; } public void buildEscalatorEdge(OsmWay escalatorWay, double length) { @@ -34,11 +41,28 @@ public void buildEscalatorEdge(OsmWay escalatorWay, double length) { .boxed() .toList(); - Optional duration = escalatorWay.getDuration(); + Optional duration = escalatorWay.getDuration(v -> + issueStore.add( + Issue.issue( + "InvalidDuration", + "Duration for osm node %d is not a valid duration: '%s'; it's replaced with 'Optional.empty()' (unknown).", + escalatorWay.getId(), + v + ) + ) + ); if (duration.isPresent()) { double speed = length / duration.get().toSeconds(); if (speed < SLOW_ESCALATOR_ERROR_CUTOFF || speed > FAST_ESCALATOR_ERROR_CUTOFF) { duration = Optional.empty(); + issueStore.add( + Issue.issue( + "InvalidDuration", + "Duration for osm node {} makes implied speed {} be outside acceptable range.", + escalatorWay.getId(), + speed + ) + ); } } for (int i = 0; i < nodes.size() - 1; i++) { diff --git a/application/src/main/java/org/opentripplanner/graph_builder/module/osm/OsmModule.java b/application/src/main/java/org/opentripplanner/graph_builder/module/osm/OsmModule.java index 08d23087a45..e4a08b40177 100644 --- a/application/src/main/java/org/opentripplanner/graph_builder/module/osm/OsmModule.java +++ b/application/src/main/java/org/opentripplanner/graph_builder/module/osm/OsmModule.java @@ -247,7 +247,10 @@ private void buildBasicGraph() { long wayCount = osmdb.getWays().size(); ProgressTracker progress = ProgressTracker.track("Build street graph", 5_000, wayCount); LOG.info(progress.startMessage()); - var escalatorProcessor = new EscalatorProcessor(vertexGenerator.intersectionNodes()); + var escalatorProcessor = new EscalatorProcessor( + vertexGenerator.intersectionNodes(), + issueStore + ); WAY:for (OsmWay way : osmdb.getWays()) { WayProperties wayData = way.getOsmProvider().getWayPropertySet().getDataForWay(way); diff --git a/application/src/main/java/org/opentripplanner/osm/model/OsmWay.java b/application/src/main/java/org/opentripplanner/osm/model/OsmWay.java index e80a3ab6499..0cc19363a0a 100644 --- a/application/src/main/java/org/opentripplanner/osm/model/OsmWay.java +++ b/application/src/main/java/org/opentripplanner/osm/model/OsmWay.java @@ -6,6 +6,7 @@ import java.time.format.DateTimeParseException; import java.util.Optional; import java.util.Set; +import java.util.function.Consumer; import org.opentripplanner.graph_builder.module.osm.StreetTraversalPermissionPair; import org.opentripplanner.street.model.StreetTraversalPermission; import org.opentripplanner.utils.time.DurationUtils; @@ -134,17 +135,8 @@ public boolean isEscalator() { return (isTag("highway", "steps") && isOneOfTags("conveying", ESCALATOR_CONVEYING_TAGS)); } - public Optional getDuration() { - var duration = getTag("duration"); - if (duration != null) { - try { - return Optional.of(DurationUtils.parseClockDuration(duration)); - } catch (DateTimeParseException e) { - // For malformed duration tags, just pretend they weren't there. - return Optional.empty(); - } - } - return Optional.empty(); + public Optional getDuration(Consumer errorHandler) { + return getTagAsDuration("duration", errorHandler); } public boolean isForwardEscalator() { diff --git a/application/src/main/java/org/opentripplanner/osm/model/OsmWithTags.java b/application/src/main/java/org/opentripplanner/osm/model/OsmWithTags.java index 67f737e4c79..bb3e1056f2f 100644 --- a/application/src/main/java/org/opentripplanner/osm/model/OsmWithTags.java +++ b/application/src/main/java/org/opentripplanner/osm/model/OsmWithTags.java @@ -1,5 +1,9 @@ package org.opentripplanner.osm.model; +import java.time.Duration; +import java.time.LocalTime; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; import java.util.Arrays; import java.util.HashMap; import java.util.Map; @@ -221,6 +225,68 @@ public OptionalInt getTagAsInt(String tag, Consumer errorHandler) { return OptionalInt.empty(); } + /** + * Parse an OSM duration tag, which is one of: + * mm + * hh:mm + * hh:mm:ss + * and where the leading value is not limited to any maximum. + * @param duration string in format mm, hh:mm, or hh:mm:ss + * @return Duration + * @throws DateTimeParseException on bad input + */ + public static Duration parseOsmDuration(String duration) { + int colonCount = (int) duration.chars().filter(ch -> ch == ':').count(); + if (colonCount <= 2) { + try { + int i, j; + long hours, minutes, seconds; + switch (colonCount) { + case 0: + minutes = Long.parseLong(duration); + if (minutes >= 0) { + return Duration.ofMinutes(minutes); + } + break; + case 1: + i = duration.indexOf(':'); + hours = Long.parseLong(duration.substring(0, i)); + minutes = Long.parseLong(duration.substring(i + 1)); + if (hours >= 0 && minutes >= 0 && minutes < 60) { + return Duration.ofHours(hours).plusMinutes(minutes); + } + break; + default: + //case 2: + i = duration.indexOf(':'); + j = duration.indexOf(':', i + 1); + hours = Long.parseLong(duration.substring(0, i)); + minutes = Long.parseLong(duration.substring(i + 1, j)); + seconds = Long.parseLong(duration.substring(j + 1)); + if (hours >= 0 && minutes >= 0 && minutes < 60 && seconds >= 0 && seconds < 60) { + return Duration.ofHours(hours).plusMinutes(minutes).plusSeconds(seconds); + } + break; + } + } catch (NumberFormatException e) { + // fallthrough + } + } + throw new DateTimeParseException("bad clock duration", duration, 0); + } + + public Optional getTagAsDuration(String tag, Consumer errorHandler) { + String value = getTag(tag); + if (value != null) { + try { + return Optional.of(parseOsmDuration(value)); + } catch (DateTimeParseException e) { + errorHandler.accept(value); + } + } + return Optional.empty(); + } + /** * Some tags are allowed to have values like 55, "true" or "false". *

diff --git a/application/src/main/java/org/opentripplanner/routing/api/request/preference/EscalatorPreferences.java b/application/src/main/java/org/opentripplanner/routing/api/request/preference/EscalatorPreferences.java deleted file mode 100644 index af4cbda39ef..00000000000 --- a/application/src/main/java/org/opentripplanner/routing/api/request/preference/EscalatorPreferences.java +++ /dev/null @@ -1,74 +0,0 @@ -package org.opentripplanner.routing.api.request.preference; - -import java.io.Serializable; -import java.util.function.Consumer; - -public class EscalatorPreferences implements Serializable { - - public static final EscalatorPreferences DEFAULT = new EscalatorPreferences(); - - private final double horizontalSpeed; - - /* A quick internet search gives escalator speed range of 0.3-0.6 m/s and angle of 30 degrees. - * Using the angle of 30 degrees and a speed of 0.5 m/s gives a horizontal component - * of approx. 0.43 m/s */ - private static final double HORIZONTAL_SPEED = 0.45; - - private EscalatorPreferences() { - this.horizontalSpeed = HORIZONTAL_SPEED; - } - - private EscalatorPreferences(Builder builder) { - this.horizontalSpeed = builder.horizontalSpeed; - } - - public static Builder of() { - return DEFAULT.copyOf(); - } - - public Builder copyOf() { - return new Builder(this); - } - - public double horizontalSpeed() { - return horizontalSpeed; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - EscalatorPreferences that = (EscalatorPreferences) o; - return horizontalSpeed == that.horizontalSpeed; - } - - public static class Builder { - - private final EscalatorPreferences original; - private double horizontalSpeed; - - public Builder(EscalatorPreferences original) { - this.original = original; - this.horizontalSpeed = original.horizontalSpeed; - } - - public EscalatorPreferences original() { - return original; - } - - public Builder withHorizontalSpeed(double horizontalSpeed) { - this.horizontalSpeed = horizontalSpeed; - return this; - } - - public Builder apply(Consumer body) { - body.accept(this); - return this; - } - - public EscalatorPreferences build() { - var value = new EscalatorPreferences(this); - return original.equals(value) ? original : value; - } - } -} diff --git a/application/src/main/java/org/opentripplanner/routing/api/request/preference/StreetPreferences.java b/application/src/main/java/org/opentripplanner/routing/api/request/preference/StreetPreferences.java index e20ed82f9a5..bb526ceaa31 100644 --- a/application/src/main/java/org/opentripplanner/routing/api/request/preference/StreetPreferences.java +++ b/application/src/main/java/org/opentripplanner/routing/api/request/preference/StreetPreferences.java @@ -30,7 +30,6 @@ public final class StreetPreferences implements Serializable { private final double turnReluctance; private final DrivingDirection drivingDirection; private final ElevatorPreferences elevator; - private final EscalatorPreferences escalator; private final AccessEgressPreferences accessEgress; private final IntersectionTraversalModel intersectionTraversalModel; private final DurationForEnum maxDirectDuration; @@ -40,7 +39,6 @@ private StreetPreferences() { this.turnReluctance = 1.0; this.drivingDirection = DrivingDirection.RIGHT; this.elevator = ElevatorPreferences.DEFAULT; - this.escalator = EscalatorPreferences.DEFAULT; this.accessEgress = AccessEgressPreferences.DEFAULT; this.intersectionTraversalModel = IntersectionTraversalModel.SIMPLE; this.maxDirectDuration = durationForStreetModeOf(ofHours(4)); @@ -51,7 +49,6 @@ private StreetPreferences(Builder builder) { this.turnReluctance = Units.reluctance(builder.turnReluctance); this.drivingDirection = requireNonNull(builder.drivingDirection); this.elevator = requireNonNull(builder.elevator); - this.escalator = requireNonNull(builder.escalator); this.accessEgress = requireNonNull(builder.accessEgress); this.intersectionTraversalModel = requireNonNull(builder.intersectionTraversalModel); this.maxDirectDuration = requireNonNull(builder.maxDirectDuration); @@ -81,10 +78,6 @@ public ElevatorPreferences elevator() { return elevator; } - public EscalatorPreferences escalator() { - return escalator; - } - /** Preferences for access/egress routing */ public AccessEgressPreferences accessEgress() { return accessEgress; @@ -117,7 +110,6 @@ public boolean equals(Object o) { DoubleUtils.doubleEquals(that.turnReluctance, turnReluctance) && drivingDirection == that.drivingDirection && elevator.equals(that.elevator) && - escalator.equals(that.escalator) && routingTimeout.equals(that.routingTimeout) && intersectionTraversalModel == that.intersectionTraversalModel && maxDirectDuration.equals(that.maxDirectDuration) && @@ -146,7 +138,6 @@ public String toString() { .addEnum("drivingDirection", drivingDirection, DEFAULT.drivingDirection) .addDuration("routingTimeout", routingTimeout, DEFAULT.routingTimeout()) .addObj("elevator", elevator, DEFAULT.elevator) - .addObj("escalator", escalator, DEFAULT.escalator) .addObj( "intersectionTraversalModel", intersectionTraversalModel, @@ -163,7 +154,6 @@ public static class Builder { private double turnReluctance; private DrivingDirection drivingDirection; private ElevatorPreferences elevator; - private EscalatorPreferences escalator; private IntersectionTraversalModel intersectionTraversalModel; private DurationForEnum maxDirectDuration; private Duration routingTimeout; @@ -174,7 +164,6 @@ public Builder(StreetPreferences original) { this.turnReluctance = original.turnReluctance; this.drivingDirection = original.drivingDirection; this.elevator = original.elevator; - this.escalator = original.escalator; this.intersectionTraversalModel = original.intersectionTraversalModel; this.accessEgress = original.accessEgress; this.maxDirectDuration = original.maxDirectDuration; @@ -200,11 +189,6 @@ public Builder withElevator(Consumer body) { return this; } - public Builder withEscalator(Consumer body) { - this.escalator = escalator.copyOf().apply(body).build(); - return this; - } - public Builder withAccessEgress(Consumer body) { this.accessEgress = accessEgress.copyOf().apply(body).build(); return this; diff --git a/application/src/main/java/org/opentripplanner/routing/api/request/preference/WalkPreferences.java b/application/src/main/java/org/opentripplanner/routing/api/request/preference/WalkPreferences.java index 4a5969049ba..87dcc320c83 100644 --- a/application/src/main/java/org/opentripplanner/routing/api/request/preference/WalkPreferences.java +++ b/application/src/main/java/org/opentripplanner/routing/api/request/preference/WalkPreferences.java @@ -30,6 +30,7 @@ public final class WalkPreferences implements Serializable { private final double safetyFactor; private final double escalatorReluctance; + private final double escalatorSpeed; private WalkPreferences() { this.speed = 1.33; @@ -39,6 +40,7 @@ private WalkPreferences() { this.stairsTimeFactor = 3.0; this.safetyFactor = 1.0; this.escalatorReluctance = 1.5; + this.escalatorSpeed = 0.45; } private WalkPreferences(Builder builder) { @@ -49,6 +51,7 @@ private WalkPreferences(Builder builder) { this.stairsTimeFactor = Units.reluctance(builder.stairsTimeFactor); this.safetyFactor = Units.reluctance(builder.safetyFactor); this.escalatorReluctance = Units.reluctance(builder.escalatorReluctance); + this.escalatorSpeed = Units.speed(builder.escalatorSpeed); } public static Builder of() { @@ -108,6 +111,14 @@ public double safetyFactor() { return safetyFactor; } + public double escalatorReluctance() { + return escalatorReluctance; + } + + public double escalatorSpeed() { + return escalatorSpeed; + } + @Override public boolean equals(Object o) { if (this == o) return true; @@ -120,7 +131,8 @@ public boolean equals(Object o) { doubleEquals(that.stairsReluctance, stairsReluctance) && doubleEquals(that.stairsTimeFactor, stairsTimeFactor) && doubleEquals(that.safetyFactor, safetyFactor) && - doubleEquals(that.escalatorReluctance, escalatorReluctance) + doubleEquals(that.escalatorReluctance, escalatorReluctance) && + doubleEquals(that.escalatorSpeed, escalatorSpeed) ); } @@ -133,7 +145,8 @@ public int hashCode() { stairsReluctance, stairsTimeFactor, safetyFactor, - escalatorReluctance + escalatorReluctance, + escalatorSpeed ); } @@ -148,13 +161,10 @@ public String toString() { .addNum("stairsTimeFactor", stairsTimeFactor, DEFAULT.stairsTimeFactor) .addNum("safetyFactor", safetyFactor, DEFAULT.safetyFactor) .addNum("escalatorReluctance", escalatorReluctance, DEFAULT.escalatorReluctance) + .addNum("escalatorSpeed", escalatorSpeed, DEFAULT.escalatorSpeed) .toString(); } - public double escalatorReluctance() { - return escalatorReluctance; - } - public static class Builder { private final WalkPreferences original; @@ -166,6 +176,7 @@ public static class Builder { private double safetyFactor; private double escalatorReluctance; + private double escalatorSpeed; public Builder(WalkPreferences original) { this.original = original; @@ -176,6 +187,7 @@ public Builder(WalkPreferences original) { this.stairsTimeFactor = original.stairsTimeFactor; this.safetyFactor = original.safetyFactor; this.escalatorReluctance = original.escalatorReluctance; + this.escalatorSpeed = original.escalatorSpeed; } public WalkPreferences original() { @@ -251,6 +263,15 @@ public Builder withEscalatorReluctance(double escalatorReluctance) { return this; } + public double escalatorSpeed() { + return escalatorSpeed; + } + + public Builder withEscalatorSpeed(double escalatorSpeed) { + this.escalatorSpeed = escalatorSpeed; + return this; + } + public Builder apply(Consumer body) { body.accept(this); return this; diff --git a/application/src/main/java/org/opentripplanner/standalone/config/routerequest/RouteRequestConfig.java b/application/src/main/java/org/opentripplanner/standalone/config/routerequest/RouteRequestConfig.java index 9c344afc44c..9f0e0ba17b4 100644 --- a/application/src/main/java/org/opentripplanner/standalone/config/routerequest/RouteRequestConfig.java +++ b/application/src/main/java/org/opentripplanner/standalone/config/routerequest/RouteRequestConfig.java @@ -460,16 +460,6 @@ private static void mapStreetPreferences(NodeAdapter c, StreetPreferences.Builde .asInt(dftElevator.hopTime()) ); }) - .withEscalator(escalator -> { - var dftEscalator = dft.escalator(); - escalator.withHorizontalSpeed( - c - .of("escalatorSpeed") - .since(V2_7) - .summary("How fast does an escalator move horizontally?") - .asDouble(dftEscalator.horizontalSpeed()) - ); - }) .withAccessEgress(accessEgress -> { var dftAccessEgress = dft.accessEgress(); accessEgress @@ -828,6 +818,14 @@ private static void mapWalkPreferences(NodeAdapter root, WalkPreferences.Builder "A multiplier for how bad being in an escalator is compared to being in transit for equal lengths of time" ) .asDouble(dft.escalatorReluctance()) + ) + .withEscalatorSpeed( + c + .of("escalatorSpeed") + .since(V2_7) + .summary("How fast does an escalator move horizontally?") + .description("Horizontal speed of escalator in m/s.") + .asDouble(dft.escalatorSpeed()) ); } } diff --git a/application/src/main/java/org/opentripplanner/street/model/edge/EscalatorEdge.java b/application/src/main/java/org/opentripplanner/street/model/edge/EscalatorEdge.java index 7dab48dc3e2..fdfd4ee44b4 100644 --- a/application/src/main/java/org/opentripplanner/street/model/edge/EscalatorEdge.java +++ b/application/src/main/java/org/opentripplanner/street/model/edge/EscalatorEdge.java @@ -31,7 +31,7 @@ public State[] traverse(State s0) { var s1 = s0.edit(this); double time; if (duration == null) { - time = getDistanceMeters() / s0.getPreferences().street().escalator().horizontalSpeed(); + time = getDistanceMeters() / s0.getPreferences().walk().escalatorSpeed(); } else { time = duration.toSeconds(); } @@ -52,6 +52,10 @@ public double getDistanceMeters() { return length; } + /** + * Parsed content of duration tag in OSM, if any. Not a calculated value. + * @return Duration, or empty + */ public Optional getDuration() { return Optional.ofNullable(duration); } diff --git a/application/src/test/java/org/opentripplanner/osm/model/OsmWayTest.java b/application/src/test/java/org/opentripplanner/osm/model/OsmWayTest.java index 869e579e9aa..277cda7ac9b 100644 --- a/application/src/test/java/org/opentripplanner/osm/model/OsmWayTest.java +++ b/application/src/test/java/org/opentripplanner/osm/model/OsmWayTest.java @@ -7,6 +7,7 @@ import java.time.Duration; import java.util.Optional; +import java.util.function.Consumer; import org.junit.jupiter.api.Test; import org.opentripplanner.osm.wayproperty.specifier.WayTestData; @@ -176,13 +177,6 @@ void escalator() { escalator.addTag("conveying", "yes"); assertTrue(escalator.isEscalator()); - assertEquals(Optional.empty(), escalator.getDuration()); - - escalator.addTag("duration", "00:00:61"); - assertEquals(Optional.empty(), escalator.getDuration()); - escalator.addTag("duration", "00:01:01"); - assertEquals(Optional.of(Duration.ofSeconds(61)), escalator.getDuration()); - escalator.addTag("conveying", "whoknows?"); assertFalse(escalator.isEscalator()); } diff --git a/application/src/test/java/org/opentripplanner/osm/model/OsmWithTagsTest.java b/application/src/test/java/org/opentripplanner/osm/model/OsmWithTagsTest.java index a89f8612040..c379fc11b02 100644 --- a/application/src/test/java/org/opentripplanner/osm/model/OsmWithTagsTest.java +++ b/application/src/test/java/org/opentripplanner/osm/model/OsmWithTagsTest.java @@ -5,9 +5,11 @@ import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; +import java.time.Duration; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.OptionalInt; import java.util.Set; import org.junit.jupiter.api.Test; @@ -298,4 +300,25 @@ void parseIntOrBoolean(String value, OptionalInt expected) { var maybeInt = way.parseIntOrBoolean(key, i -> {}); assertEquals(expected, maybeInt); } + + private static List parseTagAsDurationCases() { + return List.of( + Arguments.of("00:11", Optional.of(Duration.ofMinutes(11))), + Arguments.of("11", Optional.of(Duration.ofMinutes(11))), + Arguments.of("1:22:33", Optional.of(Duration.ofHours(1).plusMinutes(22).plusSeconds(33))), + Arguments.of("22:60", Optional.empty()), + Arguments.of("10:61:40", Optional.empty()), + Arguments.of("10:59:60", Optional.empty()) + ); + } + + @ParameterizedTest + @MethodSource("parseTagAsDurationCases") + void parseTagAsDuration(String value, Optional expected) { + var way = new OsmWithTags(); + var key = "duration"; + way.addTag(key, value); + var duration = way.getTagAsDuration(key, i -> {}); + assertEquals(expected, duration); + } } diff --git a/application/src/test/resources/standalone/config/router-config.json b/application/src/test/resources/standalone/config/router-config.json index f1eac1cb41e..5539ec4de65 100644 --- a/application/src/test/resources/standalone/config/router-config.json +++ b/application/src/test/resources/standalone/config/router-config.json @@ -75,7 +75,8 @@ "reluctance": 4.0, "stairsReluctance": 1.65, "boardCost": 600, - "escalatorReluctance": 1.5 + "escalatorReluctance": 1.5, + "escalatorSpeed": 0.45 }, "waitReluctance": 1.0, "otherThanPreferredRoutesPenalty": 300, diff --git a/doc/user/RouteRequest.md b/doc/user/RouteRequest.md index c0c5d2bb590..c6cdef82c25 100644 --- a/doc/user/RouteRequest.md +++ b/doc/user/RouteRequest.md @@ -23,7 +23,6 @@ and in the [transferRequests in build-config.json](BuildConfiguration.md#transfe | elevatorBoardTime | `integer` | How long does it take to get on an elevator, on average. | *Optional* | `90` | 2.0 | | elevatorHopCost | `integer` | What is the cost of travelling one floor on an elevator? | *Optional* | `20` | 2.0 | | elevatorHopTime | `integer` | How long does it take to advance one floor on an elevator? | *Optional* | `20` | 2.0 | -| escalatorSpeed | `double` | How fast does an escalator move horizontally? | *Optional* | `0.45` | 2.7 | | geoidElevation | `boolean` | If true, the Graph's ellipsoidToGeoidDifference is applied to all elevations returned by this query. | *Optional* | `false` | 2.0 | | ignoreRealtimeUpdates | `boolean` | When true, real-time updates are ignored during this search. | *Optional* | `false` | 2.0 | | [intersectionTraversalModel](#rd_intersectionTraversalModel) | `enum` | The model that computes the costs of turns. | *Optional* | `"simple"` | 2.2 | @@ -157,6 +156,7 @@ and in the [transferRequests in build-config.json](BuildConfiguration.md#transfe | walk | `object` | Walking preferences. | *Optional* | | 2.5 | |    boardCost | `integer` | Prevents unnecessary transfers by adding a cost for boarding a vehicle. This is the cost that is used when boarding while walking. | *Optional* | `600` | 2.0 | |    escalatorReluctance | `double` | A multiplier for how bad being in an escalator is compared to being in transit for equal lengths of time | *Optional* | `1.5` | 2.4 | +|    [escalatorSpeed](#rd_walk_escalatorSpeed) | `double` | How fast does an escalator move horizontally? | *Optional* | `0.45` | 2.7 | |    [reluctance](#rd_walk_reluctance) | `double` | A multiplier for how bad walking is, compared to being in transit for equal lengths of time. | *Optional* | `2.0` | 2.0 | |    [safetyFactor](#rd_walk_safetyFactor) | `double` | Factor for how much the walk safety is considered in routing. | *Optional* | `1.0` | 2.2 | |    speed | `double` | The user's walking speed in meters/second. | *Optional* | `1.33` | 2.0 | @@ -1072,6 +1072,15 @@ The ids of the routes that incur an extra cost when being used. Format: `FeedId: How much cost is added is configured in `unpreferredCost`. +

escalatorSpeed

+ +**Since version:** `2.7` ∙ **Type:** `double` ∙ **Cardinality:** `Optional` ∙ **Default value:** `0.45` +**Path:** /routingDefaults/walk + +How fast does an escalator move horizontally? + +Horizontal speed of escalator in m/s. +

reluctance

**Since version:** `2.0` ∙ **Type:** `double` ∙ **Cardinality:** `Optional` ∙ **Default value:** `2.0` @@ -1215,7 +1224,8 @@ include stairs as a last result. "reluctance" : 4.0, "stairsReluctance" : 1.65, "boardCost" : 600, - "escalatorReluctance" : 1.5 + "escalatorReluctance" : 1.5, + "escalatorSpeed" : 0.45 }, "waitReluctance" : 1.0, "otherThanPreferredRoutesPenalty" : 300, diff --git a/doc/user/RouterConfiguration.md b/doc/user/RouterConfiguration.md index 6dbd1174397..043e4f2f485 100644 --- a/doc/user/RouterConfiguration.md +++ b/doc/user/RouterConfiguration.md @@ -528,7 +528,8 @@ Used to group requests when monitoring OTP. "reluctance" : 4.0, "stairsReluctance" : 1.65, "boardCost" : 600, - "escalatorReluctance" : 1.5 + "escalatorReluctance" : 1.5, + "escalatorSpeed" : 0.45 }, "waitReluctance" : 1.0, "otherThanPreferredRoutesPenalty" : 300, diff --git a/utils/src/main/java/org/opentripplanner/utils/time/DurationUtils.java b/utils/src/main/java/org/opentripplanner/utils/time/DurationUtils.java index e1c0b557855..78a6ae16885 100644 --- a/utils/src/main/java/org/opentripplanner/utils/time/DurationUtils.java +++ b/utils/src/main/java/org/opentripplanner/utils/time/DurationUtils.java @@ -124,49 +124,6 @@ public static Duration duration(String duration) { } } - /** - * Parse a duration string in format hh:mm:ss. - * @param duration string in format hh:mm:ss - * @return Duration - * @throws DateTimeParseException on bad input - */ - public static Duration parseClockDuration(String duration) { - int colonCount = (int) duration.chars().filter(ch -> ch == ':').count(); - if (colonCount <= 2) { - try { - int i, j; - long hours, minutes = 0, seconds = 0; - switch (colonCount) { - case 0: - hours = Long.parseLong(duration); - break; - case 1: - i = duration.indexOf(':'); - hours = Long.parseLong(duration.substring(0, i)); - minutes = Long.parseLong(duration.substring(i + 1)); - break; - default: - //case 2: - i = duration.indexOf(':'); - j = duration.indexOf(':', i + 1); - hours = Long.parseLong(duration.substring(0, i)); - minutes = Long.parseLong(duration.substring(i + 1, j)); - seconds = Long.parseLong(duration.substring(j + 1)); - break; - } - if (hours >= 0 && minutes >= 0 && minutes < 60 && seconds >= 0 && seconds < 60) { - return Duration - .ofHours(hours) - .plus(Duration.ofMinutes(minutes)) - .plus(Duration.ofSeconds(seconds)); - } - } catch (NumberFormatException e) { - // fallthrough - } - } - throw new DateTimeParseException("bad clock duration", duration, 0); - } - /** * This is used to parse a string which may be a number {@code NNNN}(number of seconds) or a * duration with format {@code NhNmNs}, where {@code N} is a decimal number and diff --git a/utils/src/test/java/org/opentripplanner/utils/time/DurationUtilsTest.java b/utils/src/test/java/org/opentripplanner/utils/time/DurationUtilsTest.java index 15fbd6e5027..ef2e0f50901 100644 --- a/utils/src/test/java/org/opentripplanner/utils/time/DurationUtilsTest.java +++ b/utils/src/test/java/org/opentripplanner/utils/time/DurationUtilsTest.java @@ -30,8 +30,6 @@ public class DurationUtilsTest { private final Duration D5m = Duration.ofMinutes(5); private final Duration D9s = Duration.ofSeconds(9); private final Duration D3d5m9s = D3d.plus(D5m).plus(D9s); - private final Duration D2h5m = D2h.plus(D5m); - private final Duration D2h5m9s = D2h.plus(D5m).plus(D9s); private final int I9h31m = durationSec(9, 31, 0); private final int I9h36m55s = durationSec(9, 36, 55); private final int I13h33m57s = durationSec(13, 33, 57); @@ -93,19 +91,6 @@ public void duration() { assertEquals(-D9s.toSeconds(), DurationUtils.duration("-9", ChronoUnit.SECONDS).toSeconds()); } - @Test - public void parseClockDuration() { - assertEquals(D2h, DurationUtils.parseClockDuration("2")); - assertEquals(D2h5m, DurationUtils.parseClockDuration("02:05")); - assertEquals(D2h5m9s, DurationUtils.parseClockDuration("02:05:09")); - assertThrows(DateTimeParseException.class, () -> DurationUtils.parseClockDuration("02:65:09")); - assertThrows( - DateTimeParseException.class, - () -> DurationUtils.parseClockDuration("02:05:09:00") - ); - assertThrows(DateTimeParseException.class, () -> DurationUtils.parseClockDuration("02:x5:09")); - } - @Test public void parseSecondsOrDuration() { assertEquals(D9s, DurationUtils.parseSecondsOrDuration("9s").orElseThrow()); From dccc6d3ddc1b2c23c6ee10f086fef37cdd3addab Mon Sep 17 00:00:00 2001 From: Teemu Kalvas Date: Thu, 28 Nov 2024 16:11:23 +0200 Subject: [PATCH 25/80] add tests for the osm duration tag cases where the leading unit is larger than localdate would allow --- .../java/org/opentripplanner/osm/model/OsmWithTagsTest.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/application/src/test/java/org/opentripplanner/osm/model/OsmWithTagsTest.java b/application/src/test/java/org/opentripplanner/osm/model/OsmWithTagsTest.java index c379fc11b02..a5dc168d3fc 100644 --- a/application/src/test/java/org/opentripplanner/osm/model/OsmWithTagsTest.java +++ b/application/src/test/java/org/opentripplanner/osm/model/OsmWithTagsTest.java @@ -306,6 +306,9 @@ private static List parseTagAsDurationCases() { Arguments.of("00:11", Optional.of(Duration.ofMinutes(11))), Arguments.of("11", Optional.of(Duration.ofMinutes(11))), Arguments.of("1:22:33", Optional.of(Duration.ofHours(1).plusMinutes(22).plusSeconds(33))), + Arguments.of("82", Optional.of(Duration.ofMinutes(82))), + Arguments.of("25:00", Optional.of(Duration.ofHours(25))), + Arguments.of("25:00:00", Optional.of(Duration.ofHours(25))), Arguments.of("22:60", Optional.empty()), Arguments.of("10:61:40", Optional.empty()), Arguments.of("10:59:60", Optional.empty()) From 718b7384d1bcd7ac1959540ff1e0139df41d9087 Mon Sep 17 00:00:00 2001 From: Ivan Aladjoff < Ivan.Aladjoff.Extern@skanetrafiken.se> Date: Mon, 25 Nov 2024 18:56:19 +0100 Subject: [PATCH 26/80] added retry mechanism for Azure service bus --- .../azure/AbstractAzureSiriUpdaterTest.java | 393 ++++++++++++++++++ .../azure/AbstractAzureSiriUpdater.java | 314 ++++++++++---- .../azure/SiriAzureUpdaterConfig.java | 8 +- doc/user/sandbox/siri/SiriAzureUpdater.md | 8 +- 4 files changed, 624 insertions(+), 99 deletions(-) create mode 100644 application/src/ext-test/java/org/opentripplanner/ext/siri/updater/azure/AbstractAzureSiriUpdaterTest.java diff --git a/application/src/ext-test/java/org/opentripplanner/ext/siri/updater/azure/AbstractAzureSiriUpdaterTest.java b/application/src/ext-test/java/org/opentripplanner/ext/siri/updater/azure/AbstractAzureSiriUpdaterTest.java new file mode 100644 index 00000000000..f4cfa8ceb80 --- /dev/null +++ b/application/src/ext-test/java/org/opentripplanner/ext/siri/updater/azure/AbstractAzureSiriUpdaterTest.java @@ -0,0 +1,393 @@ +package org.opentripplanner.ext.siri.updater.azure; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.mockito.Mockito.*; + +import com.azure.core.util.ExpandableStringEnum; +import com.azure.messaging.servicebus.ServiceBusErrorContext; +import com.azure.messaging.servicebus.ServiceBusErrorSource; +import com.azure.messaging.servicebus.ServiceBusException; +import com.azure.messaging.servicebus.ServiceBusFailureReason; +import com.azure.messaging.servicebus.ServiceBusReceivedMessageContext; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.net.URISyntaxException; +import java.time.Duration; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.function.Consumer; +import java.util.stream.Stream; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.mockito.ArgumentCaptor; +import org.mockito.InOrder; +import org.opentripplanner.framework.io.OtpHttpClientException; + +class AbstractAzureSiriUpdaterTest { + + private SiriAzureUpdaterParameters mockConfig; + private AbstractAzureSiriUpdater updater; + private AbstractAzureSiriUpdater.CheckedRunnable task; + + @BeforeEach + public void setUp() throws Exception { + mockConfig = mock(SiriAzureUpdaterParameters.class); + when(mockConfig.configRef()).thenReturn("testConfigRef"); + when(mockConfig.getAuthenticationType()).thenReturn(AuthenticationType.SharedAccessKey); + when(mockConfig.getFullyQualifiedNamespace()).thenReturn("testNamespace"); + when(mockConfig.getServiceBusUrl()).thenReturn("testServiceBusUrl"); + when(mockConfig.getTopicName()).thenReturn("testTopic"); + when(mockConfig.getDataInitializationUrl()).thenReturn("http://testurl.com"); + when(mockConfig.getTimeout()).thenReturn(5000); + when(mockConfig.feedId()).thenReturn("testFeedId"); + when(mockConfig.getAutoDeleteOnIdle()).thenReturn(Duration.ofHours(1)); + when(mockConfig.getPrefetchCount()).thenReturn(10); + when(mockConfig.isFuzzyTripMatching()).thenReturn(true); + + // Create a spy on AbstractAzureSiriUpdater with the mock configuration + updater = spy(new AbstractAzureSiriUpdater(mockConfig) { + @Override + protected void messageConsumer(ServiceBusReceivedMessageContext messageContext) { + } + + @Override + protected void errorConsumer(ServiceBusErrorContext errorContext) { + } + + @Override + protected void initializeData(String url, + Consumer consumer + ) throws URISyntaxException { + } + }); + + task = mock(AbstractAzureSiriUpdater.CheckedRunnable.class); + } + + /** + * Tests the retry mechanism when a retryable ServiceBusException is thrown multiple times + * and checks that it follows the backoff sequence. + */ + @Test + void testExecuteWithRetry_FullBackoffSequence() throws Throwable { + final int totalRunCalls = 10; // 9 failures + 1 success + final int totalSleepCalls = 9; // 9 retries + + doNothing().when(updater).sleep(anyInt()); + + // Configure the task to throw a retryable exception for 9 attempts and then succeed + doThrow(createServiceBusException(ServiceBusFailureReason.SERVICE_BUSY)) + .doThrow(createServiceBusException(ServiceBusFailureReason.SERVICE_BUSY)) + .doThrow(createServiceBusException(ServiceBusFailureReason.SERVICE_BUSY)) + .doThrow(createServiceBusException(ServiceBusFailureReason.SERVICE_BUSY)) + .doThrow(createServiceBusException(ServiceBusFailureReason.SERVICE_BUSY)) + .doThrow(createServiceBusException(ServiceBusFailureReason.SERVICE_BUSY)) + .doThrow(createServiceBusException(ServiceBusFailureReason.SERVICE_BUSY)) + .doThrow(createServiceBusException(ServiceBusFailureReason.SERVICE_BUSY)) + .doThrow(createServiceBusException(ServiceBusFailureReason.SERVICE_BUSY)) + .doNothing() // Succeed on the 10th attempt + .when(task).run(); + + updater.executeWithRetry(task, "Test Task"); + + verify(updater, times(totalSleepCalls)).sleep(anyInt()); + + InOrder inOrder = inOrder(updater); + inOrder.verify(updater).sleep(1000); + inOrder.verify(updater).sleep(2000); + inOrder.verify(updater).sleep(4000); + inOrder.verify(updater).sleep(8000); + inOrder.verify(updater).sleep(16000); + inOrder.verify(updater).sleep(32000); + + for (int i = 0; i < 3; i++) { + inOrder.verify(updater).sleep(60000); + } + + verify(task, times(totalRunCalls)).run(); + } + + /** + * Tests the executeWithRetry method when a non-retryable exception is thrown. + * Ensures that no further retries are attempted and sleep is not called. + */ + @Test + public void testExecuteWithRetry_NonRetryableException() throws Throwable { + doNothing().when(updater).sleep(anyInt()); + + ServiceBusException serviceBusException = createServiceBusException(ServiceBusFailureReason.MESSAGE_SIZE_EXCEEDED); + + doThrow(serviceBusException).when(task).run(); + + try { + updater.executeWithRetry(task, "Test Task"); + } catch (ServiceBusException e) { + assertEquals(ServiceBusFailureReason.MESSAGE_SIZE_EXCEEDED, e.getReason(), "Exception should have reason MESSAGE_SIZE_EXCEEDED"); + } + + verify(updater, never()).sleep(anyInt()); + verify(task, times(1)).run(); + } + + /** + * Tests the executeWithRetry method when the task fails multiple times with retryable exceptions + * and then succeeds, ensuring that sleep is called the expected number of times with correct durations. + */ + @Test + public void testExecuteWithRetry_MultipleRetriesThenSuccess() throws Throwable { + final int retriesBeforeSuccess = 3; + CountDownLatch latch = new CountDownLatch(retriesBeforeSuccess); + + doThrow(createServiceBusException(ServiceBusFailureReason.SERVICE_BUSY)) + .doThrow(createServiceBusException(ServiceBusFailureReason.SERVICE_BUSY)) + .doThrow(createServiceBusException(ServiceBusFailureReason.SERVICE_BUSY)) + .doNothing() + .when(task).run(); + + doAnswer(invocation -> { + latch.countDown(); + return null; + }).when(updater).sleep(anyInt()); + + updater.executeWithRetry(task, "Test Task"); + + boolean completed = latch.await(5, TimeUnit.SECONDS); + assertTrue(completed, "Expected sleep calls were not made."); + + ArgumentCaptor sleepCaptor = ArgumentCaptor.forClass(Integer.class); + verify(updater, times(retriesBeforeSuccess)).sleep(sleepCaptor.capture()); + + var sleepDurations = sleepCaptor.getAllValues(); + long[] expectedBackoffSequence = {1000, 2000, 4000}; + + for (int i = 0; i < expectedBackoffSequence.length; i++) { + assertEquals(expectedBackoffSequence[i], Long.valueOf(sleepDurations.get(i)), + "Backoff duration mismatch at retry " + (i + 1)); + } + + verify(task, times(retriesBeforeSuccess + 1)).run(); + } + + /** + * Tests the executeWithRetry method when the task succeeds on the first attempt. + * Ensures that no sleep calls are made. + */ + @Test + public void testExecuteWithRetry_ImmediateSuccess() throws Throwable { + doNothing().when(task).run(); + doNothing().when(updater).sleep(anyInt()); + + updater.executeWithRetry(task, "Test Task"); + + verify(updater, never()).sleep(anyInt()); + verify(task, times(1)).run(); + } + + /** + * Tests the executeWithRetry method when the task fails once with a retryable exception + * and then succeeds on the first retry. + */ + @Test + public void testExecuteWithRetry_OneRetryThenSuccess() throws Throwable { + final int expectedSleepCalls = 1; + CountDownLatch latch = new CountDownLatch(expectedSleepCalls); + + doThrow(createServiceBusException(ServiceBusFailureReason.SERVICE_BUSY)) + .doNothing() + .when(task).run(); + + doAnswer(invocation -> { + if (invocation.getArgument(0).equals(1000)) { + latch.countDown(); + } + return null; + }).when(updater).sleep(anyInt()); + + updater.executeWithRetry(task, "Test Task"); + + boolean completed = latch.await(5, TimeUnit.SECONDS); + assertTrue(completed, "Expected sleep call was not made."); + + verify(updater, times(expectedSleepCalls)).sleep(1000); + verify(task, times(2)).run(); + } + + /** + * Parameterized test to verify that shouldRetry returns the correct value for each ServiceBusFailureReason. + * + * @param reason The ServiceBusFailureReason to test. + * @param expectedRetry The expected result of shouldRetry. + */ + @ParameterizedTest(name = "shouldRetry with reason {0} should return {1}") + @MethodSource("provideServiceBusFailureReasons") + @DisplayName("Test shouldRetry for all ServiceBusFailureReason values") + void testShouldRetry_ServiceBusFailureReasons(ServiceBusFailureReason reason, boolean expectedRetry) throws Exception { + ServiceBusException serviceBusException = createServiceBusException(reason); + boolean result = updater.shouldRetry(serviceBusException); + assertEquals(expectedRetry, result, "shouldRetry should return " + expectedRetry + " for reason " + reason); + } + + /** + * Test that shouldRetry returns false for non-ServiceBus exceptions. + */ + @Test + @DisplayName("shouldRetry should return false for non-ServiceBus exceptions") + public void testShouldRetry_NonServiceBusException() { + Exception genericException = new Exception("Generic exception"); + boolean result = updater.shouldRetry(genericException); + assertFalse(result, "shouldRetry should return false for non-ServiceBus exceptions"); + } + + /** + * Test that shouldRetry handles all ServiceBusFailureReason values. + * Since enums are closed, this test ensures that the parameterized tests cover all existing values. + */ + @Test + @DisplayName("shouldRetry covers all ServiceBusFailureReason values") + public void testShouldRetry_CoversAllReasons() { + long enumCount = getExpandableStringEnumValues(ServiceBusFailureReason.class).size(); + long testCaseCount = provideServiceBusFailureReasons().count(); + assertEquals(enumCount, testCaseCount, "All ServiceBusFailureReason values should be covered by tests."); + } + + @Test + void testExecuteWithRetry_InterruptedException() throws Throwable { + final int expectedRunCalls = 2; + final int expectedSleepCalls = 1; + + doThrow(createServiceBusException(ServiceBusFailureReason.SERVICE_BUSY)) + .doThrow(new InterruptedException("Sleep interrupted")) + .when(task).run(); + + doNothing().when(updater).sleep(1000); + + InterruptedException thrownException = assertThrows(InterruptedException.class, () -> { + updater.executeWithRetry(task, "Test Task"); + }, "Expected executeWithRetry to throw InterruptedException"); + + assertEquals("Sleep interrupted", thrownException.getMessage(), "Exception message should match"); + verify(updater, times(expectedSleepCalls)).sleep(1000); + verify(task, times(expectedRunCalls)).run(); + assertTrue(Thread.currentThread().isInterrupted(), "Thread should be interrupted"); + } + + @Test + void testExecuteWithRetry_OtpHttpClientException() throws Throwable { + final int retryAttempts = 3; + final int expectedSleepCalls = retryAttempts; + + doThrow(new OtpHttpClientException("could not get historical data")) + .doThrow(new OtpHttpClientException("could not get historical data")) + .doThrow(new OtpHttpClientException("could not get historical data")) + .doNothing() + .when(task).run(); + + doNothing().when(updater).sleep(anyInt()); + + updater.executeWithRetry(task, "Test Task"); + + ArgumentCaptor sleepCaptor = ArgumentCaptor.forClass(Integer.class); + verify(updater, times(expectedSleepCalls)).sleep(sleepCaptor.capture()); + + List sleepDurations = sleepCaptor.getAllValues(); + List expectedBackoffSequence = Arrays.asList(1000, 2000, 4000); + + for (int i = 0; i < retryAttempts; i++) { + assertEquals(expectedBackoffSequence.get(i), sleepDurations.get(i), + "Backoff duration mismatch at retry " + (i + 1)); + } + + verify(task, times(retryAttempts + 1)).run(); + } + + @Test + void testExecuteWithRetry_UnexpectedException() throws Throwable { + doNothing().when(updater).sleep(anyInt()); + + Exception unexpectedException = new NullPointerException("Unexpected null value"); + doThrow(unexpectedException).when(task).run(); + + Exception thrown = assertThrows(NullPointerException.class, () -> { + updater.executeWithRetry(task, "Test Task"); + }, "Expected executeWithRetry to throw NullPointerException"); + + assertEquals("Unexpected null value", thrown.getMessage(), "Exception message should match"); + verify(updater, never()).sleep(anyInt()); + verify(task, times(1)).run(); + } + + /** + * Provides test arguments for each ServiceBusFailureReason and the expected shouldRetry outcome. + * + * @return Stream of Arguments containing ServiceBusFailureReason and expected boolean. + */ + private static Stream provideServiceBusFailureReasons() { + return Stream.of( + // Retryable (Transient) Errors + Arguments.of(ServiceBusFailureReason.SERVICE_BUSY, true), + Arguments.of(ServiceBusFailureReason.SERVICE_TIMEOUT, true), + Arguments.of(ServiceBusFailureReason.SERVICE_COMMUNICATION_ERROR, true), + Arguments.of(ServiceBusFailureReason.MESSAGE_LOCK_LOST, true), + Arguments.of(ServiceBusFailureReason.SESSION_LOCK_LOST, true), + Arguments.of(ServiceBusFailureReason.SESSION_CANNOT_BE_LOCKED, true), + Arguments.of(ServiceBusFailureReason.QUOTA_EXCEEDED, true), + Arguments.of(ServiceBusFailureReason.GENERAL_ERROR, true), + Arguments.of(ServiceBusFailureReason.UNAUTHORIZED, true), + + // Non-Retryable Errors + Arguments.of(ServiceBusFailureReason.MESSAGING_ENTITY_NOT_FOUND, false), + Arguments.of(ServiceBusFailureReason.MESSAGING_ENTITY_DISABLED, false), + Arguments.of(ServiceBusFailureReason.MESSAGE_SIZE_EXCEEDED, false), + Arguments.of(ServiceBusFailureReason.MESSAGE_NOT_FOUND, false), + Arguments.of(ServiceBusFailureReason.MESSAGING_ENTITY_ALREADY_EXISTS, false) + ); + } + + /** + * Helper method to create a ServiceBusException with a specified failure reason. + * + * @param reason The ServiceBusFailureReason to set. + * @return A ServiceBusException instance with the specified reason. + */ + private ServiceBusException createServiceBusException(ServiceBusFailureReason reason) { + ServiceBusException exception = new ServiceBusException(new Throwable(), ServiceBusErrorSource.RECEIVE); + try { + Field reasonField = ServiceBusException.class.getDeclaredField("reason"); + reasonField.setAccessible(true); + reasonField.set(exception, reason); + } catch (NoSuchFieldException | IllegalAccessException e) { + throw new RuntimeException("Failed to set ServiceBusFailureReason via reflection", e); + } + return exception; + } + + /** + * Helper method to retrieve all instances of an ExpandableStringEnum subclass. + * + * @param clazz The class of the ExpandableStringEnum subclass. + * @param The type parameter extending ExpandableStringEnum. + * @return A Collection of all registered instances. + */ + private static > Collection getExpandableStringEnumValues(Class clazz) { + try { + Method valuesMethod = ExpandableStringEnum.class.getDeclaredMethod("values", Class.class); + valuesMethod.setAccessible(true); + @SuppressWarnings("unchecked") + Collection values = (Collection) valuesMethod.invoke(null, clazz); + return values; + } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { + throw new RuntimeException("Failed to retrieve values from ExpandableStringEnum.", e); + } + } +} \ No newline at end of file diff --git a/application/src/ext/java/org/opentripplanner/ext/siri/updater/azure/AbstractAzureSiriUpdater.java b/application/src/ext/java/org/opentripplanner/ext/siri/updater/azure/AbstractAzureSiriUpdater.java index 7a1b32d36e5..545b216dd56 100644 --- a/application/src/ext/java/org/opentripplanner/ext/siri/updater/azure/AbstractAzureSiriUpdater.java +++ b/application/src/ext/java/org/opentripplanner/ext/siri/updater/azure/AbstractAzureSiriUpdater.java @@ -1,5 +1,6 @@ package org.opentripplanner.ext.siri.updater.azure; + import com.azure.identity.DefaultAzureCredentialBuilder; import com.azure.messaging.servicebus.ServiceBusClientBuilder; import com.azure.messaging.servicebus.ServiceBusErrorContext; @@ -18,11 +19,14 @@ import java.time.temporal.ChronoUnit; import java.util.Objects; import java.util.Optional; +import java.util.Set; import java.util.UUID; import java.util.concurrent.TimeUnit; import java.util.function.Consumer; +import org.apache.commons.lang3.exception.ExceptionUtils; import org.apache.hc.client5.http.classic.methods.HttpGet; import org.opentripplanner.framework.application.ApplicationShutdownSupport; +import org.opentripplanner.framework.io.OtpHttpClientException; import org.opentripplanner.framework.io.OtpHttpClientFactory; import org.opentripplanner.updater.spi.GraphUpdater; import org.opentripplanner.updater.spi.HttpHeaders; @@ -34,6 +38,35 @@ public abstract class AbstractAzureSiriUpdater implements GraphUpdater { + /** + * custom functional interface that allows throwing checked exceptions, thereby + * preserving the exception's intent and type. + */ + @FunctionalInterface + interface CheckedRunnable { + void run() throws Exception; + } + + private static final Set RETRYABLE_REASONS = Set.of( + ServiceBusFailureReason.GENERAL_ERROR, + ServiceBusFailureReason.QUOTA_EXCEEDED, + ServiceBusFailureReason.SERVICE_BUSY, + ServiceBusFailureReason.SERVICE_COMMUNICATION_ERROR, + ServiceBusFailureReason.SERVICE_TIMEOUT, + ServiceBusFailureReason.UNAUTHORIZED, + ServiceBusFailureReason.MESSAGE_LOCK_LOST, + ServiceBusFailureReason.SESSION_LOCK_LOST, + ServiceBusFailureReason.SESSION_CANNOT_BE_LOCKED + ); + + private static final Set NON_RETRYABLE_REASONS = Set.of( + ServiceBusFailureReason.MESSAGING_ENTITY_NOT_FOUND, + ServiceBusFailureReason.MESSAGING_ENTITY_DISABLED, + ServiceBusFailureReason.MESSAGE_SIZE_EXCEEDED, + ServiceBusFailureReason.MESSAGE_NOT_FOUND, + ServiceBusFailureReason.MESSAGING_ENTITY_ALREADY_EXISTS + ); + private final Logger LOG = LoggerFactory.getLogger(getClass()); private final AuthenticationType authenticationType; private final String fullyQualifiedNamespace; @@ -64,17 +97,31 @@ public abstract class AbstractAzureSiriUpdater implements GraphUpdater { protected final int timeout; public AbstractAzureSiriUpdater(SiriAzureUpdaterParameters config) { - this.configRef = config.configRef(); - this.authenticationType = config.getAuthenticationType(); - this.fullyQualifiedNamespace = config.getFullyQualifiedNamespace(); - this.serviceBusUrl = config.getServiceBusUrl(); - this.topicName = config.getTopicName(); - this.dataInitializationUrl = config.getDataInitializationUrl(); + this.configRef = Objects.requireNonNull(config.configRef(), "configRef must not be null"); + this.authenticationType = Objects.requireNonNull(config.getAuthenticationType(), "authenticationType must not be null"); + this.topicName = Objects.requireNonNull(config.getTopicName(), "topicName must not be null"); + this.dataInitializationUrl = Objects.requireNonNull(config.getDataInitializationUrl(), "dataInitializationUrl must not be null"); this.timeout = config.getTimeout(); - this.feedId = config.feedId(); + this.feedId = Objects.requireNonNull(config.feedId(), "feedId must not be null"); this.autoDeleteOnIdle = config.getAutoDeleteOnIdle(); this.prefetchCount = config.getPrefetchCount(); this.fuzzyTripMatching = config.isFuzzyTripMatching(); + + if (authenticationType == AuthenticationType.FederatedIdentity) { + this.fullyQualifiedNamespace = Objects.requireNonNull( + config.getFullyQualifiedNamespace(), + "fullyQualifiedNamespace must not be null when using FederatedIdentity authentication" + ); + this.serviceBusUrl = null; + } else if (authenticationType == AuthenticationType.SharedAccessKey) { + this.serviceBusUrl = Objects.requireNonNull( + config.getServiceBusUrl(), + "serviceBusUrl must not be null when using SharedAccessKey authentication" + ); + this.fullyQualifiedNamespace = null; + } else { + throw new IllegalArgumentException("Unsupported authentication type: " + authenticationType); + } } /** @@ -96,10 +143,6 @@ public void setup(WriteToGraphCallback writeToGraphCallback) { @Override public void run() { - Objects.requireNonNull(topicName, "'topic' must be set"); - Objects.requireNonNull(serviceBusUrl, "'servicebus-url' must be set"); - Objects.requireNonNull(feedId, "'feedId' must be set"); - Preconditions.checkState(feedId.length() > 0, "'feedId' must be set"); // In Kubernetes this should be the POD identifier subscriptionName = System.getenv("HOSTNAME"); @@ -107,6 +150,134 @@ public void run() { subscriptionName = "otp-" + UUID.randomUUID(); } + try { + executeWithRetry( + this::setupSubscription, + "Setting up Service Bus subscription to topic" + ); + + executeWithRetry( + () -> initializeData(dataInitializationUrl, messageConsumer), + "Initializing historical Siri data" + ); + + executeWithRetry( + this::startEventProcessor, + "Starting Service Bus event processor" + ); + + setPrimed(); + + ApplicationShutdownSupport.addShutdownHook( + "azure-siri-updater-shutdown", + () -> { + LOG.info("Calling shutdownHook on AbstractAzureSiriUpdater"); + if (eventProcessor != null) { + eventProcessor.close(); + } + if (serviceBusAdmin != null) { + serviceBusAdmin.deleteSubscription(topicName, subscriptionName).block(); + LOG.info("Subscription '{}' deleted on topic '{}'.", subscriptionName, topicName); + } + } + ); + + } catch (ServiceBusException e) { + LOG.error("Service Bus encountered an error during setup: {}", e.getMessage(), e); + } catch (URISyntaxException e) { + LOG.error("Invalid URI provided for Service Bus setup: {}", e.getMessage(), e); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + LOG.warn("Updater was interrupted during setup."); + } catch (Exception e) { + LOG.error("An unexpected error occurred during setup: {}", e.getMessage(), e); + } + } + + /** + * Sleeps. This is to be able to mock testing + * @param millis number of milliseconds + * @throws InterruptedException if sleep is interrupted + */ + protected void sleep(int millis) throws InterruptedException { + Thread.sleep(millis); + } + + /** + * Executes a task with retry logic. Retries indefinitely for retryable exceptions with exponential backoff. + * Does not retry for InterruptedException and propagates it + * @param task The task to execute. + * @param description A description of the task for logging purposes. + * @throws InterruptedException If the thread is interrupted while waiting between retries. + */ + protected void executeWithRetry(CheckedRunnable task, String description) throws Exception { + int sleepPeriod = 1000; // Start with 1-second delay + int attemptCounter = 1; + + while (true) { + try { + task.run(); + LOG.info("{} succeeded.", description); + return; + } catch (InterruptedException ie) { + LOG.warn("{} was interrupted during execution.", description); + Thread.currentThread().interrupt(); // Restore interrupted status + throw ie; + } catch (Exception e) { + LOG.warn("{} failed. Error: {} (Attempt {})", description, e.getMessage(), attemptCounter); + + if (!shouldRetry(e)) { + LOG.error("{} encountered a non-retryable error: {}.", description, e.getMessage()); + throw e; // Stop retries if the error is non-retryable + } + + LOG.warn("{} will retry in {} ms.", description, sleepPeriod); + attemptCounter++; + try { + sleep(sleepPeriod); + } catch (InterruptedException ie){ + LOG.warn("{} was interrupted during sleep.", description); + Thread.currentThread().interrupt(); // Restore interrupted status + throw ie; + } + sleepPeriod = Math.min(sleepPeriod * 2, 60 * 1000); // Exponential backoff with a cap at 60 seconds + } + } + } + + protected boolean shouldRetry(Exception e) { + if (e instanceof ServiceBusException sbException) { + ServiceBusFailureReason reason = sbException.getReason(); + + if (RETRYABLE_REASONS.contains(reason)) { + + LOG.warn("Transient error encountered: {}. Retrying...", reason); + return true; + + } else if (NON_RETRYABLE_REASONS.contains(reason)) { + + LOG.error("Non-recoverable error encountered: {}. Not retrying.", reason); + return false; + + } else { + LOG.warn("Unhandled ServiceBusFailureReason: {}. Retrying by default.", reason); + return true; + } + } + else if (ExceptionUtils.hasCause(e, OtpHttpClientException.class)){ + // retry for OtpHttpClientException as it is thrown if historical data can't be read at the moment + return true; + } + + LOG.warn("Non-ServiceBus exception encountered: {}. Not retrying.", e.getClass().getName()); + return false; + } + + /** + * Sets up the Service Bus subscription, including checking old subscription, deleting if necessary, + * and creating a new subscription. + */ + private void setupSubscription() throws ServiceBusException, URISyntaxException { // Client with permissions to create subscription if (authenticationType == AuthenticationType.FederatedIdentity) { serviceBusAdmin = @@ -121,40 +292,50 @@ public void run() { } // Set options - var options = new CreateSubscriptionOptions(); - options.setDefaultMessageTimeToLive(Duration.of(25, ChronoUnit.HOURS)); - // Set subscription to be deleted if idle for a certain time, so that orphaned instances doesn't linger. - options.setAutoDeleteOnIdle(autoDeleteOnIdle); + CreateSubscriptionOptions options = new CreateSubscriptionOptions() + .setDefaultMessageTimeToLive(Duration.of(25, ChronoUnit.HOURS)) + .setAutoDeleteOnIdle(autoDeleteOnIdle); // Make sure there is no old subscription on serviceBus - if ( - Boolean.TRUE.equals( - serviceBusAdmin.getSubscriptionExists(topicName, subscriptionName).block() - ) - ) { - LOG.info("Subscription {} already exists", subscriptionName); + if ( Boolean.TRUE.equals( serviceBusAdmin.getSubscriptionExists(topicName, subscriptionName).block())) { + LOG.info("Subscription '{}' already exists. Deleting existing subscription.", subscriptionName); serviceBusAdmin.deleteSubscription(topicName, subscriptionName).block(); LOG.info("Service Bus deleted subscription {}.", subscriptionName); } serviceBusAdmin.createSubscription(topicName, subscriptionName, options).block(); - LOG.info("Service Bus created subscription {}", subscriptionName); + LOG.info("{} created subscription {}", getClass().getSimpleName(), subscriptionName); + } - // Initialize historical Siri data - initializeData(); + /** + * Starts the Service Bus event processor. + */ + private void startEventProcessor() throws ServiceBusException { + ServiceBusClientBuilder clientBuilder = new ServiceBusClientBuilder(); - eventProcessor = - new ServiceBusClientBuilder() - .connectionString(serviceBusUrl) - .processor() - .topicName(topicName) - .subscriptionName(subscriptionName) - .receiveMode(ServiceBusReceiveMode.RECEIVE_AND_DELETE) - .disableAutoComplete() // Receive and delete does not need autocomplete - .prefetchCount(prefetchCount) - .processError(errorConsumer) - .processMessage(messageConsumer) - .buildProcessorClient(); + if (authenticationType == AuthenticationType.FederatedIdentity) { + Preconditions.checkNotNull(fullyQualifiedNamespace, "fullyQualifiedNamespace must be set for FederatedIdentity authentication"); + clientBuilder + .fullyQualifiedNamespace(fullyQualifiedNamespace) + .credential(new DefaultAzureCredentialBuilder().build()); + } else if (authenticationType == AuthenticationType.SharedAccessKey) { + Preconditions.checkNotNull(serviceBusUrl, "serviceBusUrl must be set for SharedAccessKey authentication"); + clientBuilder + .connectionString(serviceBusUrl); + } else { + throw new IllegalArgumentException("Unsupported authentication type: " + authenticationType); + } + + eventProcessor = clientBuilder + .processor() + .topicName(topicName) + .subscriptionName(subscriptionName) + .receiveMode(ServiceBusReceiveMode.RECEIVE_AND_DELETE) + .disableAutoComplete() // Receive and delete does not need autocomplete + .prefetchCount(prefetchCount) + .processError(errorConsumer) + .processMessage(messageConsumer) + .buildProcessorClient(); eventProcessor.start(); LOG.info( @@ -163,20 +344,9 @@ public void run() { subscriptionName, prefetchCount ); - - setPrimed(); - - ApplicationShutdownSupport.addShutdownHook( - "azure-siri-updater-shutdown", - () -> { - LOG.info("Calling shutdownHook on AbstractAzureSiriUpdater"); - eventProcessor.close(); - serviceBusAdmin.deleteSubscription(topicName, subscriptionName).block(); - LOG.info("Subscription '{}' deleted on topic '{}'.", subscriptionName, topicName); - } - ); } + @Override public boolean isPrimed() { return this.isPrimed; @@ -221,37 +391,6 @@ boolean fuzzyTripMatching() { return fuzzyTripMatching; } - /** - * InitializeData - wrapping method that calls an implementation of initialize data - and blocks readiness till finished - */ - private void initializeData() { - int sleepPeriod = 1000; - int attemptCounter = 1; - boolean otpIsShuttingDown = false; - - while (!otpIsShuttingDown) { - try { - initializeData(dataInitializationUrl, messageConsumer); - break; - } catch (Exception e) { - sleepPeriod = Math.min(sleepPeriod * 2, 60 * 1000); - - LOG.warn( - "Caught exception while initializing data will retry after {} ms - attempt {}. ({})", - sleepPeriod, - attemptCounter++, - e.toString() - ); - try { - Thread.sleep(sleepPeriod); - } catch (InterruptedException ie) { - Thread.currentThread().interrupt(); - otpIsShuttingDown = true; - LOG.info("OTP is shutting down, cancelling attempt to initialize Azure SIRI Updater."); - } - } - } - } protected abstract void initializeData( String url, @@ -260,7 +399,7 @@ protected abstract void initializeData( /** * Make some sensible logging on error and if Service Bus is busy, sleep for some time before try again to get messages. - * This code snippet is taken from Microsoft example https://docs.microsoft.com/sv-se/azure/service-bus-messaging/service-bus-java-how-to-use-queues. + * This code snippet is taken from Microsoft example .... * @param errorContext Context for errors handled by the ServiceBusProcessorClient. */ protected void defaultErrorConsumer(ServiceBusErrorContext errorContext) { @@ -270,19 +409,15 @@ protected void defaultErrorConsumer(ServiceBusErrorContext errorContext) { errorContext.getEntityPath() ); - if (!(errorContext.getException() instanceof ServiceBusException)) { + if (!(errorContext.getException() instanceof ServiceBusException e)) { LOG.error("Non-ServiceBusException occurred!", errorContext.getException()); return; } - var e = (ServiceBusException) errorContext.getException(); var reason = e.getReason(); - if ( - reason == ServiceBusFailureReason.MESSAGING_ENTITY_DISABLED || - reason == ServiceBusFailureReason.MESSAGING_ENTITY_NOT_FOUND || - reason == ServiceBusFailureReason.UNAUTHORIZED - ) { + if (reason == ServiceBusFailureReason.MESSAGING_ENTITY_DISABLED || + reason == ServiceBusFailureReason.MESSAGING_ENTITY_NOT_FOUND) { LOG.error( "An unrecoverable error occurred. Stopping processing with reason {} {}", reason, @@ -290,8 +425,9 @@ protected void defaultErrorConsumer(ServiceBusErrorContext errorContext) { ); } else if (reason == ServiceBusFailureReason.MESSAGE_LOCK_LOST) { LOG.error("Message lock lost for message", e); - } else if (reason == ServiceBusFailureReason.SERVICE_BUSY) { - LOG.error("Service Bus is busy, wait and try again"); + } else if (reason == ServiceBusFailureReason.SERVICE_BUSY || + reason == ServiceBusFailureReason.UNAUTHORIZED) { + LOG.error("Service Bus is busy or unauthorized, wait and try again"); try { // Choosing an arbitrary amount of time to wait until trying again. TimeUnit.SECONDS.sleep(5); diff --git a/application/src/main/java/org/opentripplanner/standalone/config/routerconfig/updaters/azure/SiriAzureUpdaterConfig.java b/application/src/main/java/org/opentripplanner/standalone/config/routerconfig/updaters/azure/SiriAzureUpdaterConfig.java index ddb6a967f92..28fb7bf9549 100644 --- a/application/src/main/java/org/opentripplanner/standalone/config/routerconfig/updaters/azure/SiriAzureUpdaterConfig.java +++ b/application/src/main/java/org/opentripplanner/standalone/config/routerconfig/updaters/azure/SiriAzureUpdaterConfig.java @@ -33,14 +33,10 @@ public static void populateConfig( .asString(null) ); parameters.setTopicName( - c.of("topic").since(V2_2).summary("Service Bus topic to connect to.").asString(null) + c.of("topic").since(V2_2).summary("Service Bus topic to connect to.").asString() ); parameters.setFeedId( - c - .of("feedId") - .since(V2_2) - .summary("The ID of the feed to apply the updates to.") - .asString(null) + c.of("feedId").since(V2_2).summary("The ID of the feed to apply the updates to.").asString() ); parameters.setAutoDeleteOnIdle( c diff --git a/doc/user/sandbox/siri/SiriAzureUpdater.md b/doc/user/sandbox/siri/SiriAzureUpdater.md index c8e7f4d9255..898e70d7b84 100644 --- a/doc/user/sandbox/siri/SiriAzureUpdater.md +++ b/doc/user/sandbox/siri/SiriAzureUpdater.md @@ -28,12 +28,12 @@ To enable the SIRI updater you need to add it to the updaters section of the `ro | [authenticationType](#u__11__authenticationType) | `enum` | Which authentication type to use | *Optional* | `"sharedaccesskey"` | 2.5 | | autoDeleteOnIdle | `duration` | The time after which an inactive subscription is removed. | *Optional* | `"PT1H"` | 2.5 | | [customMidnight](#u__11__customMidnight) | `integer` | Time on which time breaks into new day. | *Optional* | `0` | 2.2 | -| feedId | `string` | The ID of the feed to apply the updates to. | *Optional* | | 2.2 | +| feedId | `string` | The ID of the feed to apply the updates to. | *Required* | | 2.2 | | [fullyQualifiedNamespace](#u__11__fullyQualifiedNamespace) | `string` | Service Bus fully qualified namespace used for authentication. | *Optional* | | 2.5 | | fuzzyTripMatching | `boolean` | Whether to apply fuzzyTripMatching on the updates | *Optional* | `false` | 2.2 | | prefetchCount | `integer` | The number of messages to fetch from the subscription at a time. | *Optional* | `10` | 2.5 | | [servicebus-url](#u__11__servicebus_url) | `string` | Service Bus connection used for authentication. | *Optional* | | 2.2 | -| topic | `string` | Service Bus topic to connect to. | *Optional* | | 2.2 | +| topic | `string` | Service Bus topic to connect to. | *Required* | | 2.2 | | history | `object` | Configuration for fetching historical data on startup | *Optional* | | 2.2 | |    fromDateTime | `string` | Datetime boundary for historical data | *Optional* | `"-P1D"` | 2.2 | |    timeout | `integer` | Timeout in milliseconds | *Optional* | `300000` | na | @@ -116,12 +116,12 @@ Has to be present for authenticationMethod SharedAccessKey. This should be Prima | [authenticationType](#u__10__authenticationType) | `enum` | Which authentication type to use | *Optional* | `"sharedaccesskey"` | 2.5 | | autoDeleteOnIdle | `duration` | The time after which an inactive subscription is removed. | *Optional* | `"PT1H"` | 2.5 | | [customMidnight](#u__10__customMidnight) | `integer` | Time on which time breaks into new day. | *Optional* | `0` | 2.2 | -| feedId | `string` | The ID of the feed to apply the updates to. | *Optional* | | 2.2 | +| feedId | `string` | The ID of the feed to apply the updates to. | *Required* | | 2.2 | | [fullyQualifiedNamespace](#u__10__fullyQualifiedNamespace) | `string` | Service Bus fully qualified namespace used for authentication. | *Optional* | | 2.5 | | fuzzyTripMatching | `boolean` | Whether to apply fuzzyTripMatching on the updates | *Optional* | `false` | 2.2 | | prefetchCount | `integer` | The number of messages to fetch from the subscription at a time. | *Optional* | `10` | 2.5 | | [servicebus-url](#u__10__servicebus_url) | `string` | Service Bus connection used for authentication. | *Optional* | | 2.2 | -| topic | `string` | Service Bus topic to connect to. | *Optional* | | 2.2 | +| topic | `string` | Service Bus topic to connect to. | *Required* | | 2.2 | | history | `object` | Configuration for fetching historical data on startup | *Optional* | | 2.2 | |    fromDateTime | `string` | Datetime boundary for historical data. | *Optional* | `"-P1D"` | 2.2 | |    timeout | `integer` | Timeout in milliseconds | *Optional* | `300000` | na | From d345a03465f54c8ab912f1c5611eacb2d77341a9 Mon Sep 17 00:00:00 2001 From: Teemu Kalvas Date: Fri, 29 Nov 2024 09:45:11 +0200 Subject: [PATCH 27/80] explain the duration parser better, more tests --- .../osm/model/OsmWithTags.java | 24 +++++++++++++------ .../osm/model/OsmWithTagsTest.java | 6 ++++- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/application/src/main/java/org/opentripplanner/osm/model/OsmWithTags.java b/application/src/main/java/org/opentripplanner/osm/model/OsmWithTags.java index bb3e1056f2f..f5ead1da4d5 100644 --- a/application/src/main/java/org/opentripplanner/osm/model/OsmWithTags.java +++ b/application/src/main/java/org/opentripplanner/osm/model/OsmWithTags.java @@ -1,8 +1,6 @@ package org.opentripplanner.osm.model; import java.time.Duration; -import java.time.LocalTime; -import java.time.format.DateTimeFormatter; import java.time.format.DateTimeParseException; import java.util.Arrays; import java.util.HashMap; @@ -236,34 +234,46 @@ public OptionalInt getTagAsInt(String tag, Consumer errorHandler) { * @throws DateTimeParseException on bad input */ public static Duration parseOsmDuration(String duration) { + // Unfortunately DateFormatParserBuilder doesn't quite do enough for this case. + // It has the capability for expressing optional parts, so it could express hh(:mm(:ss)?)? + // but it cannot express (hh:)?mm(:ss)? where the existence of (:ss) implies the existence + // of (hh:). Even if it did, it would not be able to handle the cases where hours are + // greater than 23 or (if there is no hours part at all) minutes are greater than 59, which + // are both allowed by the spec and exist in OSM data. Durations are not LocalTimes after + // all, in parsing a LocalTime it makes sense and is correct that hours cannot be more than + // 23 or minutes more than 59, but in durations if you have capped the largest unit, it is + // reasonable for the amount of the largest unit to be as large as it needs to be. int colonCount = (int) duration.chars().filter(ch -> ch == ':').count(); if (colonCount <= 2) { try { int i, j; long hours, minutes, seconds; + // The first :-separated element can be any width, and has no maximum. It still has + // to be non-negative. The following elements must be 2 characters wide, non-negative, + // and less than 60. switch (colonCount) { - case 0: + case 0: // case "m" minutes = Long.parseLong(duration); if (minutes >= 0) { return Duration.ofMinutes(minutes); } break; - case 1: + case 1: // case "h:mm" i = duration.indexOf(':'); hours = Long.parseLong(duration.substring(0, i)); minutes = Long.parseLong(duration.substring(i + 1)); - if (hours >= 0 && minutes >= 0 && minutes < 60) { + if (duration.length() - i == 3 && hours >= 0 && minutes >= 0 && minutes < 60) { return Duration.ofHours(hours).plusMinutes(minutes); } break; - default: + default: // case "h:mm:ss" //case 2: i = duration.indexOf(':'); j = duration.indexOf(':', i + 1); hours = Long.parseLong(duration.substring(0, i)); minutes = Long.parseLong(duration.substring(i + 1, j)); seconds = Long.parseLong(duration.substring(j + 1)); - if (hours >= 0 && minutes >= 0 && minutes < 60 && seconds >= 0 && seconds < 60) { + if (j - i == 3 && duration.length() - j == 3 && hours >= 0 && minutes >= 0 && minutes < 60 && seconds >= 0 && seconds < 60) { return Duration.ofHours(hours).plusMinutes(minutes).plusSeconds(seconds); } break; diff --git a/application/src/test/java/org/opentripplanner/osm/model/OsmWithTagsTest.java b/application/src/test/java/org/opentripplanner/osm/model/OsmWithTagsTest.java index a5dc168d3fc..3fe49ded403 100644 --- a/application/src/test/java/org/opentripplanner/osm/model/OsmWithTagsTest.java +++ b/application/src/test/java/org/opentripplanner/osm/model/OsmWithTagsTest.java @@ -311,7 +311,11 @@ private static List parseTagAsDurationCases() { Arguments.of("25:00:00", Optional.of(Duration.ofHours(25))), Arguments.of("22:60", Optional.empty()), Arguments.of("10:61:40", Optional.empty()), - Arguments.of("10:59:60", Optional.empty()) + Arguments.of("10:59:60", Optional.empty()), + Arguments.of("1:12:34", Optional.of(Duration.ofHours(1).plusMinutes(12).plusSeconds(34))), + Arguments.of("1:2:34", Optional.empty()), + Arguments.of("1:12:3", Optional.empty()), + Arguments.of("1:2", Optional.empty()) ); } From c161378b8cf478ecbcb387c978735d1077224dfc Mon Sep 17 00:00:00 2001 From: Teemu Kalvas Date: Fri, 29 Nov 2024 09:47:57 +0200 Subject: [PATCH 28/80] prettier reformatting --- .../org/opentripplanner/osm/model/OsmWithTags.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/application/src/main/java/org/opentripplanner/osm/model/OsmWithTags.java b/application/src/main/java/org/opentripplanner/osm/model/OsmWithTags.java index f5ead1da4d5..74d1ffd25f5 100644 --- a/application/src/main/java/org/opentripplanner/osm/model/OsmWithTags.java +++ b/application/src/main/java/org/opentripplanner/osm/model/OsmWithTags.java @@ -273,7 +273,15 @@ public static Duration parseOsmDuration(String duration) { hours = Long.parseLong(duration.substring(0, i)); minutes = Long.parseLong(duration.substring(i + 1, j)); seconds = Long.parseLong(duration.substring(j + 1)); - if (j - i == 3 && duration.length() - j == 3 && hours >= 0 && minutes >= 0 && minutes < 60 && seconds >= 0 && seconds < 60) { + if ( + j - i == 3 && + duration.length() - j == 3 && + hours >= 0 && + minutes >= 0 && + minutes < 60 && + seconds >= 0 && + seconds < 60 + ) { return Duration.ofHours(hours).plusMinutes(minutes).plusSeconds(seconds); } break; From e919778fd2014be25befa3e60fd7887556c1d59a Mon Sep 17 00:00:00 2001 From: OTP Serialization Version Bot Date: Mon, 2 Dec 2024 07:29:00 +0000 Subject: [PATCH 29/80] Bump serialization version id for #6277 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 770525790f7..54d7e21cc78 100644 --- a/pom.xml +++ b/pom.xml @@ -58,7 +58,7 @@ - 173 + 174 32.1 2.52 From 769e3805f3e77b44c222cd3960ef0e820b9dfb3b Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Mon, 25 Nov 2024 14:08:43 +0100 Subject: [PATCH 30/80] Add background tiles # Conflicts: # application/src/test/resources/org/opentripplanner/apis/vectortiles/style.json --- .../apis/vectortiles/DebugStyleSpec.java | 42 +- .../apis/vectortiles/style.json | 1227 ++++++++++++----- 2 files changed, 888 insertions(+), 381 deletions(-) diff --git a/application/src/main/java/org/opentripplanner/apis/vectortiles/DebugStyleSpec.java b/application/src/main/java/org/opentripplanner/apis/vectortiles/DebugStyleSpec.java index f27d252f250..971884d00a2 100644 --- a/application/src/main/java/org/opentripplanner/apis/vectortiles/DebugStyleSpec.java +++ b/application/src/main/java/org/opentripplanner/apis/vectortiles/DebugStyleSpec.java @@ -4,7 +4,6 @@ import java.util.Arrays; import java.util.List; -import java.util.stream.Collectors; import java.util.stream.Stream; import org.opentripplanner.apis.vectortiles.model.StyleBuilder; import org.opentripplanner.apis.vectortiles.model.StyleSpec; @@ -37,13 +36,24 @@ */ public class DebugStyleSpec { - private static final TileSource BACKGROUND_SOURCE = new RasterSource( - "background", + private static final TileSource OSM_BACKGROUND = new RasterSource( + "background-osm", List.of("https://a.tile.openstreetmap.org/{z}/{x}/{y}.png"), 19, 256, "© OpenStreetMap Contributors" ); + private static final TileSource POSITRON_BACKGROUND = new RasterSource( + "background-carto", + List.of("https://a.basemaps.cartocdn.com/{z}/{x}/{y}"), + 19, + 256, + "© OpenStreetMap, © CARTO" + ); + private static final List BACKGROUND_LAYERS = List.of( + OSM_BACKGROUND, + POSITRON_BACKGROUND + ); private static final String MAGENTA = "#f21d52"; private static final String BRIGHT_GREEN = "#22DD9E"; private static final String DARK_GREEN = "#136b04"; @@ -94,17 +104,18 @@ static StyleSpec build( VectorSourceLayer edges, VectorSourceLayer vertices ) { - var vectorSources = Stream + List vectorSources = List .of(regularStops, edges, vertices) - .map(VectorSourceLayer::vectorSource); - var allSources = Stream - .concat(Stream.of(BACKGROUND_SOURCE), vectorSources) - .collect(Collectors.toSet()); + .stream() + .map(VectorSourceLayer::vectorSource) + .map(TileSource.class::cast) + .toList(); + var allSources = ListUtils.combine(BACKGROUND_LAYERS, vectorSources); return new StyleSpec( "OTP Debug Tiles", allSources, ListUtils.combine( - List.of(StyleBuilder.ofId("background").typeRaster().source(BACKGROUND_SOURCE).minZoom(0)), + backgroundLayers(), wheelchair(edges), noThruTraffic(edges), traversalPermissions(edges), @@ -115,6 +126,19 @@ static StyleSpec build( ); } + private static List backgroundLayers() { + return BACKGROUND_LAYERS + .stream() + .map(layer -> { + var builder = StyleBuilder.ofId(layer.id()).typeRaster().source(layer).minZoom(0); + if(!layer.equals(OSM_BACKGROUND)){ + builder.intiallyHidden(); + } + return builder; + }) + .toList(); + } + private static List stops( VectorSourceLayer regularStops, VectorSourceLayer areaStops, diff --git a/application/src/test/resources/org/opentripplanner/apis/vectortiles/style.json b/application/src/test/resources/org/opentripplanner/apis/vectortiles/style.json index b08a225fde3..fe7b546400d 100644 --- a/application/src/test/resources/org/opentripplanner/apis/vectortiles/style.json +++ b/application/src/test/resources/org/opentripplanner/apis/vectortiles/style.json @@ -1,83 +1,163 @@ { - "name": "OTP Debug Tiles", - "sources": { - "background": { - "id": "background", - "tiles": ["https://a.tile.openstreetmap.org/{z}/{x}/{y}.png"], - "maxzoom": 19, - "tileSize": 256, - "attribution": "© OpenStreetMap Contributors", - "type": "raster" + "name" : "OTP Debug Tiles", + "sources" : { + "vectorSource" : { + "id" : "vectorSource", + "url" : "https://example.com", + "type" : "vector" }, - "vectorSource": { - "id": "vectorSource", - "url": "https://example.com", - "type": "vector" + "background-osm" : { + "id" : "background-osm", + "tiles" : [ + "https://a.tile.openstreetmap.org/{z}/{x}/{y}.png" + ], + "maxzoom" : 19, + "tileSize" : 256, + "attribution" : "© OpenStreetMap Contributors", + "type" : "raster" + }, + "background-carto" : { + "id" : "background-carto", + "tiles" : [ + "https://{s}.basemaps.cartocdn.com/{z}/{x}/{y}" + ], + "maxzoom" : 19, + "tileSize" : 256, + "attribution" : "© OpenStreetMap, © CARTO", + "type" : "raster" } }, - "layers": [ + "layers" : [ { - "id": "background", - "type": "raster", - "source": "background", - "minzoom": 0, - "metadata": { - "group": "Other" + "id" : "background-osm", + "type" : "raster", + "source" : "background-osm", + "minzoom" : 0, + "metadata" : { + "group" : "Other" } }, { - "id": "wheelchair-accessible", - "source": "vectorSource", - "source-layer": "edges", - "type": "line", - "minzoom": 6, - "maxzoom": 23, - "paint": { - "line-color": "#136b04", - "line-width": ["interpolate", ["linear"], ["zoom"], 13, 0.2, 23, 8.0], - "line-offset": ["interpolate", ["linear"], ["zoom"], 13, 0.4, 23, 7.0] - }, - "filter": ["==", "wheelchairAccessible", true], - "layout": { - "line-cap": "round", - "visibility": "none" - }, - "metadata": { - "group": "Wheelchair accessibility" + "id" : "background-carto", + "type" : "raster", + "source" : "background-carto", + "minzoom" : 0, + "metadata" : { + "group" : "Other" + } + }, + { + "id" : "wheelchair-accessible", + "source" : "vectorSource", + "source-layer" : "edges", + "type" : "line", + "minzoom" : 6, + "maxzoom" : 23, + "paint" : { + "line-color" : "#136b04", + "line-width" : [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 13, + 0.2, + 23, + 8.0 + ], + "line-offset" : [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 13, + 0.4, + 23, + 7.0 + ] + }, + "filter" : [ + "==", + "wheelchairAccessible", + true + ], + "layout" : { + "line-cap" : "round", + "visibility" : "none" + }, + "metadata" : { + "group" : "Wheelchair accessibility" } }, { - "id": "wheelchair-inaccessible", - "source": "vectorSource", - "source-layer": "edges", - "type": "line", - "minzoom": 6, - "maxzoom": 23, - "paint": { - "line-color": "#fc0f2a", - "line-width": ["interpolate", ["linear"], ["zoom"], 13, 0.2, 23, 8.0], - "line-offset": ["interpolate", ["linear"], ["zoom"], 13, 0.4, 23, 7.0] - }, - "filter": ["==", "wheelchairAccessible", false], - "layout": { - "line-cap": "round", - "visibility": "none" - }, - "metadata": { - "group": "Wheelchair accessibility" + "id" : "wheelchair-inaccessible", + "source" : "vectorSource", + "source-layer" : "edges", + "type" : "line", + "minzoom" : 6, + "maxzoom" : 23, + "paint" : { + "line-color" : "#fc0f2a", + "line-width" : [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 13, + 0.2, + 23, + 8.0 + ], + "line-offset" : [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 13, + 0.4, + 23, + 7.0 + ] + }, + "filter" : [ + "==", + "wheelchairAccessible", + false + ], + "layout" : { + "line-cap" : "round", + "visibility" : "none" + }, + "metadata" : { + "group" : "Wheelchair accessibility" } }, { - "id": "no-thru-traffic PEDESTRIAN", - "source": "vectorSource", - "source-layer": "edges", - "type": "line", - "minzoom": 13, - "maxzoom": 23, - "paint": { - "line-color": [ + "id" : "no-thru-traffic PEDESTRIAN", + "source" : "vectorSource", + "source-layer" : "edges", + "type" : "line", + "minzoom" : 13, + "maxzoom" : 23, + "paint" : { + "line-color" : [ "match", - ["get", "noThruTraffic"], + [ + "get", + "noThruTraffic" + ], "NONE", "#140d0e", "PEDESTRIAN", @@ -96,33 +176,80 @@ "#adb2b0", "#140d0e" ], - "line-width": ["interpolate", ["linear"], ["zoom"], 13, 0.2, 23, 8.0], - "line-offset": ["interpolate", ["linear"], ["zoom"], 13, 0.4, 23, 7.0] + "line-width" : [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 13, + 0.2, + 23, + 8.0 + ], + "line-offset" : [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 13, + 0.4, + 23, + 7.0 + ] }, - "filter": [ + "filter" : [ "any", - ["in", "PEDESTRIAN", ["string", ["get", "noThruTraffic"]]], - ["in", "ALL", ["string", ["get", "noThruTraffic"]]] + [ + "in", + "PEDESTRIAN", + [ + "string", + [ + "get", + "noThruTraffic" + ] + ] + ], + [ + "in", + "ALL", + [ + "string", + [ + "get", + "noThruTraffic" + ] + ] + ] ], - "layout": { - "line-cap": "butt", - "visibility": "none" + "layout" : { + "line-cap" : "butt", + "visibility" : "none" }, - "metadata": { - "group": "No-thru traffic" + "metadata" : { + "group" : "No-thru traffic" } }, { - "id": "no-thru-traffic BICYCLE", - "source": "vectorSource", - "source-layer": "edges", - "type": "line", - "minzoom": 13, - "maxzoom": 23, - "paint": { - "line-color": [ + "id" : "no-thru-traffic BICYCLE", + "source" : "vectorSource", + "source-layer" : "edges", + "type" : "line", + "minzoom" : 13, + "maxzoom" : 23, + "paint" : { + "line-color" : [ "match", - ["get", "noThruTraffic"], + [ + "get", + "noThruTraffic" + ], "NONE", "#140d0e", "PEDESTRIAN", @@ -141,33 +268,80 @@ "#adb2b0", "#140d0e" ], - "line-width": ["interpolate", ["linear"], ["zoom"], 13, 0.2, 23, 8.0], - "line-offset": ["interpolate", ["linear"], ["zoom"], 13, 0.4, 23, 7.0] + "line-width" : [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 13, + 0.2, + 23, + 8.0 + ], + "line-offset" : [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 13, + 0.4, + 23, + 7.0 + ] }, - "filter": [ + "filter" : [ "any", - ["in", "BICYCLE", ["string", ["get", "noThruTraffic"]]], - ["in", "ALL", ["string", ["get", "noThruTraffic"]]] + [ + "in", + "BICYCLE", + [ + "string", + [ + "get", + "noThruTraffic" + ] + ] + ], + [ + "in", + "ALL", + [ + "string", + [ + "get", + "noThruTraffic" + ] + ] + ] ], - "layout": { - "line-cap": "butt", - "visibility": "none" + "layout" : { + "line-cap" : "butt", + "visibility" : "none" }, - "metadata": { - "group": "No-thru traffic" + "metadata" : { + "group" : "No-thru traffic" } }, { - "id": "no-thru-traffic CAR", - "source": "vectorSource", - "source-layer": "edges", - "type": "line", - "minzoom": 13, - "maxzoom": 23, - "paint": { - "line-color": [ + "id" : "no-thru-traffic CAR", + "source" : "vectorSource", + "source-layer" : "edges", + "type" : "line", + "minzoom" : 13, + "maxzoom" : 23, + "paint" : { + "line-color" : [ "match", - ["get", "noThruTraffic"], + [ + "get", + "noThruTraffic" + ], "NONE", "#140d0e", "PEDESTRIAN", @@ -186,36 +360,80 @@ "#adb2b0", "#140d0e" ], - "line-width": ["interpolate", ["linear"], ["zoom"], 13, 0.2, 23, 8.0], - "line-offset": ["interpolate", ["linear"], ["zoom"], 13, 0.4, 23, 7.0] + "line-width" : [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 13, + 0.2, + 23, + 8.0 + ], + "line-offset" : [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 13, + 0.4, + 23, + 7.0 + ] }, - "filter": [ + "filter" : [ "any", - ["in", "CAR", ["string", ["get", "noThruTraffic"]]], - ["in", "ALL", ["string", ["get", "noThruTraffic"]]] + [ + "in", + "CAR", + [ + "string", + [ + "get", + "noThruTraffic" + ] + ] + ], + [ + "in", + "ALL", + [ + "string", + [ + "get", + "noThruTraffic" + ] + ] + ] ], - "layout": { - "line-cap": "butt", - "visibility": "none" + "layout" : { + "line-cap" : "butt", + "visibility" : "none" }, - "metadata": { - "group": "No-thru traffic" + "metadata" : { + "group" : "No-thru traffic" } }, { - "id": "no-thru-traffic-text", - "source": "vectorSource", - "source-layer": "edges", - "type": "symbol", - "minzoom": 17, - "maxzoom": 23, - "paint": { - "text-color": "#000", - "text-halo-color": "#fff", - "text-halo-blur": 4, - "text-halo-width": 3 - }, - "filter": [ + "id" : "no-thru-traffic-text", + "source" : "vectorSource", + "source-layer" : "edges", + "type" : "symbol", + "minzoom" : 17, + "maxzoom" : 23, + "paint" : { + "text-color" : "#000", + "text-halo-color" : "#fff", + "text-halo-blur" : 4, + "text-halo-width" : 3 + }, + "filter" : [ "in", "class", "StreetEdge", @@ -226,34 +444,54 @@ "TemporaryPartialStreetEdge", "TemporaryFreeEdge" ], - "layout": { - "symbol-placement": "line-center", - "symbol-spacing": 1000, - "text-field": "{noThruTraffic}", - "text-font": ["KlokanTech Noto Sans Regular"], - "text-size": ["interpolate", ["linear"], ["zoom"], 10, 6.0, 24, 12.0], - "text-max-width": 100, - "text-keep-upright": true, - "text-rotation-alignment": "map", - "text-overlap": "never", - "text-offset": [0, 1.0], - "visibility": "none" - }, - "metadata": { - "group": "No-thru traffic" + "layout" : { + "symbol-placement" : "line-center", + "symbol-spacing" : 1000, + "text-field" : "{noThruTraffic}", + "text-font" : [ + "KlokanTech Noto Sans Regular" + ], + "text-size" : [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 10, + 6.0, + 24, + 12.0 + ], + "text-max-width" : 100, + "text-keep-upright" : true, + "text-rotation-alignment" : "map", + "text-overlap" : "never", + "text-offset" : [ + 0, + 1.0 + ], + "visibility" : "none" + }, + "metadata" : { + "group" : "No-thru traffic" } }, { - "id": "permission PEDESTRIAN", - "source": "vectorSource", - "source-layer": "edges", - "type": "line", - "minzoom": 13, - "maxzoom": 23, - "paint": { - "line-color": [ + "id" : "permission PEDESTRIAN", + "source" : "vectorSource", + "source-layer" : "edges", + "type" : "line", + "minzoom" : 13, + "maxzoom" : 23, + "paint" : { + "line-color" : [ "match", - ["get", "permission"], + [ + "get", + "permission" + ], "NONE", "#140d0e", "PEDESTRIAN", @@ -272,33 +510,80 @@ "#adb2b0", "#140d0e" ], - "line-width": ["interpolate", ["linear"], ["zoom"], 13, 0.2, 23, 8.0], - "line-offset": ["interpolate", ["linear"], ["zoom"], 13, 0.4, 23, 7.0] + "line-width" : [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 13, + 0.2, + 23, + 8.0 + ], + "line-offset" : [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 13, + 0.4, + 23, + 7.0 + ] }, - "filter": [ + "filter" : [ "any", - ["in", "PEDESTRIAN", ["string", ["get", "permission"]]], - ["in", "ALL", ["string", ["get", "permission"]]] + [ + "in", + "PEDESTRIAN", + [ + "string", + [ + "get", + "permission" + ] + ] + ], + [ + "in", + "ALL", + [ + "string", + [ + "get", + "permission" + ] + ] + ] ], - "layout": { - "line-cap": "butt", - "visibility": "none" + "layout" : { + "line-cap" : "butt", + "visibility" : "none" }, - "metadata": { - "group": "Permissions" + "metadata" : { + "group" : "Permissions" } }, { - "id": "permission BICYCLE", - "source": "vectorSource", - "source-layer": "edges", - "type": "line", - "minzoom": 13, - "maxzoom": 23, - "paint": { - "line-color": [ + "id" : "permission BICYCLE", + "source" : "vectorSource", + "source-layer" : "edges", + "type" : "line", + "minzoom" : 13, + "maxzoom" : 23, + "paint" : { + "line-color" : [ "match", - ["get", "permission"], + [ + "get", + "permission" + ], "NONE", "#140d0e", "PEDESTRIAN", @@ -317,33 +602,80 @@ "#adb2b0", "#140d0e" ], - "line-width": ["interpolate", ["linear"], ["zoom"], 13, 0.2, 23, 8.0], - "line-offset": ["interpolate", ["linear"], ["zoom"], 13, 0.4, 23, 7.0] + "line-width" : [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 13, + 0.2, + 23, + 8.0 + ], + "line-offset" : [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 13, + 0.4, + 23, + 7.0 + ] }, - "filter": [ + "filter" : [ "any", - ["in", "BICYCLE", ["string", ["get", "permission"]]], - ["in", "ALL", ["string", ["get", "permission"]]] + [ + "in", + "BICYCLE", + [ + "string", + [ + "get", + "permission" + ] + ] + ], + [ + "in", + "ALL", + [ + "string", + [ + "get", + "permission" + ] + ] + ] ], - "layout": { - "line-cap": "butt", - "visibility": "none" + "layout" : { + "line-cap" : "butt", + "visibility" : "none" }, - "metadata": { - "group": "Permissions" + "metadata" : { + "group" : "Permissions" } }, { - "id": "permission CAR", - "source": "vectorSource", - "source-layer": "edges", - "type": "line", - "minzoom": 13, - "maxzoom": 23, - "paint": { - "line-color": [ + "id" : "permission CAR", + "source" : "vectorSource", + "source-layer" : "edges", + "type" : "line", + "minzoom" : 13, + "maxzoom" : 23, + "paint" : { + "line-color" : [ "match", - ["get", "permission"], + [ + "get", + "permission" + ], "NONE", "#140d0e", "PEDESTRIAN", @@ -362,36 +694,80 @@ "#adb2b0", "#140d0e" ], - "line-width": ["interpolate", ["linear"], ["zoom"], 13, 0.2, 23, 8.0], - "line-offset": ["interpolate", ["linear"], ["zoom"], 13, 0.4, 23, 7.0] + "line-width" : [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 13, + 0.2, + 23, + 8.0 + ], + "line-offset" : [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 13, + 0.4, + 23, + 7.0 + ] }, - "filter": [ + "filter" : [ "any", - ["in", "CAR", ["string", ["get", "permission"]]], - ["in", "ALL", ["string", ["get", "permission"]]] + [ + "in", + "CAR", + [ + "string", + [ + "get", + "permission" + ] + ] + ], + [ + "in", + "ALL", + [ + "string", + [ + "get", + "permission" + ] + ] + ] ], - "layout": { - "line-cap": "butt", - "visibility": "none" + "layout" : { + "line-cap" : "butt", + "visibility" : "none" }, - "metadata": { - "group": "Permissions" + "metadata" : { + "group" : "Permissions" } }, { - "id": "permission-text", - "source": "vectorSource", - "source-layer": "edges", - "type": "symbol", - "minzoom": 17, - "maxzoom": 23, - "paint": { - "text-color": "#000", - "text-halo-color": "#fff", - "text-halo-blur": 4, - "text-halo-width": 3 - }, - "filter": [ + "id" : "permission-text", + "source" : "vectorSource", + "source-layer" : "edges", + "type" : "symbol", + "minzoom" : 17, + "maxzoom" : 23, + "paint" : { + "text-color" : "#000", + "text-halo-color" : "#fff", + "text-halo-blur" : 4, + "text-halo-width" : 3 + }, + "filter" : [ "in", "class", "StreetEdge", @@ -402,36 +778,77 @@ "TemporaryPartialStreetEdge", "TemporaryFreeEdge" ], - "layout": { - "symbol-placement": "line-center", - "symbol-spacing": 1000, - "text-field": "{permission}", - "text-font": ["KlokanTech Noto Sans Regular"], - "text-size": ["interpolate", ["linear"], ["zoom"], 10, 6.0, 24, 12.0], - "text-max-width": 100, - "text-keep-upright": true, - "text-rotation-alignment": "map", - "text-overlap": "never", - "text-offset": [0, 1.0], - "visibility": "none" - }, - "metadata": { - "group": "Permissions" + "layout" : { + "symbol-placement" : "line-center", + "symbol-spacing" : 1000, + "text-field" : "{permission}", + "text-font" : [ + "KlokanTech Noto Sans Regular" + ], + "text-size" : [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 10, + 6.0, + 24, + 12.0 + ], + "text-max-width" : 100, + "text-keep-upright" : true, + "text-rotation-alignment" : "map", + "text-overlap" : "never", + "text-offset" : [ + 0, + 1.0 + ], + "visibility" : "none" + }, + "metadata" : { + "group" : "Permissions" } }, { - "id": "edge", - "type": "line", - "source": "vectorSource", - "source-layer": "edges", - "minzoom": 6, - "maxzoom": 23, - "paint": { - "line-color": "#f21d52", - "line-width": ["interpolate", ["linear"], ["zoom"], 13, 0.1, 23, 6.0], - "line-offset": ["interpolate", ["linear"], ["zoom"], 13, 0.4, 23, 7.0] - }, - "filter": [ + "id" : "edge", + "type" : "line", + "source" : "vectorSource", + "source-layer" : "edges", + "minzoom" : 6, + "maxzoom" : 23, + "paint" : { + "line-color" : "#f21d52", + "line-width" : [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 13, + 0.1, + 23, + 6.0 + ], + "line-offset" : [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 13, + 0.4, + 23, + 7.0 + ] + }, + "filter" : [ "in", "class", "StreetEdge", @@ -442,28 +859,28 @@ "TemporaryPartialStreetEdge", "TemporaryFreeEdge" ], - "layout": { - "line-cap": "round", - "visibility": "none" + "layout" : { + "line-cap" : "round", + "visibility" : "none" }, - "metadata": { - "group": "Edges" + "metadata" : { + "group" : "Edges" } }, { - "id": "edge-name", - "type": "symbol", - "source": "vectorSource", - "source-layer": "edges", - "minzoom": 17, - "maxzoom": 23, - "paint": { - "text-color": "#000", - "text-halo-color": "#fff", - "text-halo-blur": 4, - "text-halo-width": 3 - }, - "filter": [ + "id" : "edge-name", + "type" : "symbol", + "source" : "vectorSource", + "source-layer" : "edges", + "minzoom" : 17, + "maxzoom" : 23, + "paint" : { + "text-color" : "#000", + "text-halo-color" : "#fff", + "text-halo-blur" : 4, + "text-halo-width" : 3 + }, + "filter" : [ "in", "class", "StreetEdge", @@ -474,35 +891,73 @@ "TemporaryPartialStreetEdge", "TemporaryFreeEdge" ], - "layout": { - "symbol-placement": "line-center", - "symbol-spacing": 1000, - "text-field": "{name}", - "text-font": ["KlokanTech Noto Sans Regular"], - "text-size": ["interpolate", ["linear"], ["zoom"], 10, 6.0, 24, 12.0], - "text-max-width": 100, - "text-keep-upright": true, - "text-rotation-alignment": "map", - "text-overlap": "never", - "visibility": "none" - }, - "metadata": { - "group": "Edges" + "layout" : { + "symbol-placement" : "line-center", + "symbol-spacing" : 1000, + "text-field" : "{name}", + "text-font" : [ + "KlokanTech Noto Sans Regular" + ], + "text-size" : [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 10, + 6.0, + 24, + 12.0 + ], + "text-max-width" : 100, + "text-keep-upright" : true, + "text-rotation-alignment" : "map", + "text-overlap" : "never", + "visibility" : "none" + }, + "metadata" : { + "group" : "Edges" } }, { - "id": "link", - "type": "line", - "source": "vectorSource", - "source-layer": "edges", - "minzoom": 13, - "maxzoom": 23, - "paint": { - "line-color": "#22DD9E", - "line-width": ["interpolate", ["linear"], ["zoom"], 13, 0.2, 23, 8.0], - "line-offset": ["interpolate", ["linear"], ["zoom"], 13, 0.4, 23, 7.0] - }, - "filter": [ + "id" : "link", + "type" : "line", + "source" : "vectorSource", + "source-layer" : "edges", + "minzoom" : 13, + "maxzoom" : 23, + "paint" : { + "line-color" : "#22DD9E", + "line-width" : [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 13, + 0.2, + 23, + 8.0 + ], + "line-offset" : [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 13, + 0.4, + 23, + 7.0 + ] + }, + "filter" : [ "in", "class", "StreetTransitStopLink", @@ -512,153 +967,181 @@ "StreetVehicleParkingLink", "StreetStationCentroidLink" ], - "layout": { - "line-cap": "round", - "visibility": "none" + "layout" : { + "line-cap" : "round", + "visibility" : "none" }, - "metadata": { - "group": "Edges" + "metadata" : { + "group" : "Edges" } }, { - "id": "vertex", - "type": "circle", - "source": "vectorSource", - "source-layer": "vertices", - "minzoom": 15, - "maxzoom": 23, - "paint": { - "circle-stroke-color": "#140d0e", - "circle-stroke-width": [ + "id" : "vertex", + "type" : "circle", + "source" : "vectorSource", + "source-layer" : "vertices", + "minzoom" : 15, + "maxzoom" : 23, + "paint" : { + "circle-stroke-color" : "#140d0e", + "circle-stroke-width" : [ "interpolate", - ["linear"], - ["zoom"], + [ + "linear" + ], + [ + "zoom" + ], 15, 0.2, 23, 3.0 ], - "circle-radius": [ + "circle-radius" : [ "interpolate", - ["linear"], - ["zoom"], + [ + "linear" + ], + [ + "zoom" + ], 15, 1.0, 23, 7.0 ], - "circle-color": "#BC55F2" + "circle-color" : "#BC55F2" }, - "layout": { - "visibility": "none" + "layout" : { + "visibility" : "none" }, - "metadata": { - "group": "Vertices" + "metadata" : { + "group" : "Vertices" } }, { - "id": "parking-vertex", - "type": "circle", - "source": "vectorSource", - "source-layer": "vertices", - "minzoom": 13, - "maxzoom": 23, - "paint": { - "circle-stroke-color": "#140d0e", - "circle-stroke-width": [ + "id" : "parking-vertex", + "type" : "circle", + "source" : "vectorSource", + "source-layer" : "vertices", + "minzoom" : 13, + "maxzoom" : 23, + "paint" : { + "circle-stroke-color" : "#140d0e", + "circle-stroke-width" : [ "interpolate", - ["linear"], - ["zoom"], + [ + "linear" + ], + [ + "zoom" + ], 15, 0.2, 23, 3.0 ], - "circle-radius": [ + "circle-radius" : [ "interpolate", - ["linear"], - ["zoom"], + [ + "linear" + ], + [ + "zoom" + ], 13, 1.4, 23, 10.0 ], - "circle-color": "#136b04" + "circle-color" : "#136b04" }, - "filter": ["in", "class", "VehicleParkingEntranceVertex"], - "layout": { - "visibility": "none" + "filter" : [ + "in", + "class", + "VehicleParkingEntranceVertex" + ], + "layout" : { + "visibility" : "none" }, - "metadata": { - "group": "Vertices" + "metadata" : { + "group" : "Vertices" } }, { - "id": "area-stop", - "type": "fill", - "source": "vectorSource", - "source-layer": "stops", - "minzoom": 6, - "maxzoom": 23, - "paint": { - "fill-color": "#22DD9E", - "fill-opacity": 0.5, - "fill-outline-color": "#140d0e" - }, - "metadata": { - "group": "Stops" + "id" : "area-stop", + "type" : "fill", + "source" : "vectorSource", + "source-layer" : "stops", + "minzoom" : 6, + "maxzoom" : 23, + "paint" : { + "fill-color" : "#22DD9E", + "fill-opacity" : 0.5, + "fill-outline-color" : "#140d0e" + }, + "metadata" : { + "group" : "Stops" } }, { - "id": "group-stop", - "type": "fill", - "source": "vectorSource", - "source-layer": "stops", - "minzoom": 6, - "maxzoom": 23, - "paint": { - "fill-color": "#22DD9E", - "fill-opacity": 0.5, - "fill-outline-color": "#140d0e" - }, - "metadata": { - "group": "Stops" + "id" : "group-stop", + "type" : "fill", + "source" : "vectorSource", + "source-layer" : "stops", + "minzoom" : 6, + "maxzoom" : 23, + "paint" : { + "fill-color" : "#22DD9E", + "fill-opacity" : 0.5, + "fill-outline-color" : "#140d0e" + }, + "metadata" : { + "group" : "Stops" } }, { - "id": "regular-stop", - "type": "circle", - "source": "vectorSource", - "source-layer": "stops", - "minzoom": 10, - "maxzoom": 23, - "paint": { - "circle-stroke-color": "#140d0e", - "circle-stroke-width": [ + "id" : "regular-stop", + "type" : "circle", + "source" : "vectorSource", + "source-layer" : "stops", + "minzoom" : 10, + "maxzoom" : 23, + "paint" : { + "circle-stroke-color" : "#140d0e", + "circle-stroke-width" : [ "interpolate", - ["linear"], - ["zoom"], + [ + "linear" + ], + [ + "zoom" + ], 11, 0.5, 23, 5.0 ], - "circle-radius": [ + "circle-radius" : [ "interpolate", - ["linear"], - ["zoom"], + [ + "linear" + ], + [ + "zoom" + ], 11, 0.5, 23, 10.0 ], - "circle-color": "#fcf9fa" + "circle-color" : "#fcf9fa" }, - "metadata": { - "group": "Stops" + "metadata" : { + "group" : "Stops" } } ], - "version": 8, - "glyphs": "https://cdn.jsdelivr.net/gh/klokantech/klokantech-gl-fonts@master/{fontstack}/{range}.pbf" -} + "version" : 8, + "glyphs" : "https://cdn.jsdelivr.net/gh/klokantech/klokantech-gl-fonts@master/{fontstack}/{range}.pbf" +} \ No newline at end of file From 77fdc5e66dfc5ccf8ad9a7cfc4b99f1cbc540e56 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Mon, 25 Nov 2024 14:44:06 +0100 Subject: [PATCH 31/80] Add UI elements for selecting background map --- .../apis/vectortiles/DebugStyleSpec.java | 2 +- .../src/components/MapView/LayerControl.tsx | 109 ++++++++++++------ 2 files changed, 76 insertions(+), 35 deletions(-) diff --git a/application/src/main/java/org/opentripplanner/apis/vectortiles/DebugStyleSpec.java b/application/src/main/java/org/opentripplanner/apis/vectortiles/DebugStyleSpec.java index 971884d00a2..d29e6fdf15b 100644 --- a/application/src/main/java/org/opentripplanner/apis/vectortiles/DebugStyleSpec.java +++ b/application/src/main/java/org/opentripplanner/apis/vectortiles/DebugStyleSpec.java @@ -45,7 +45,7 @@ public class DebugStyleSpec { ); private static final TileSource POSITRON_BACKGROUND = new RasterSource( "background-carto", - List.of("https://a.basemaps.cartocdn.com/{z}/{x}/{y}"), + List.of("https://cartodb-basemaps-a.global.ssl.fastly.net/light_all/{z}/{x}/{y}${r}.png"), 19, 256, "© OpenStreetMap, © CARTO" diff --git a/client/src/components/MapView/LayerControl.tsx b/client/src/components/MapView/LayerControl.tsx index 61dd48e4a34..d5f9dbb6424 100644 --- a/client/src/components/MapView/LayerControl.tsx +++ b/client/src/components/MapView/LayerControl.tsx @@ -26,49 +26,90 @@ class LayerControl implements IControl { this.container.className = 'maplibregl-ctrl maplibregl-ctrl-group layer-select'; map.on('load', () => { - // clean on + // clean on rerender while (this.container.firstChild) { this.container.removeChild(this.container.firstChild); } - const title = document.createElement('h4'); - title.textContent = 'Debug layers'; - this.container.appendChild(title); - - const groups: Record = {}; - map - .getLayersOrder() - .map((l) => map.getLayer(l)) - .filter((layer) => !!layer) - .filter((layer) => this.layerInteractive(layer)) - .reverse() - .forEach((layer) => { - if (layer) { - const meta: { group: string } = layer.metadata as { group: string }; - - let groupName: string = 'Misc'; - if (meta.group) { - groupName = meta.group; - } - - const layerDiv = this.buildLayerDiv(layer as TypedStyleLayer, map); - - if (groups[groupName]) { - groups[groupName]?.appendChild(layerDiv); - } else { - const groupDiv = this.buildGroupDiv(groupName, layerDiv); - groups[groupName] = groupDiv; - this.container.appendChild(groupDiv); - } - } - }); - // initialize clickable layers (initially stops) - this.updateInteractiveLayerIds(map); + this.buildBackgroundLayers(map); + this.buildDebugLayers(map); }); return this.container; } + private buildBackgroundLayers(map: Map) { + const title = document.createElement('h4'); + title.textContent = 'Background'; + this.container.appendChild(title); + + const select = document.createElement('select'); + this.container.appendChild(select); + + let rasterLayers = map + .getLayersOrder() + .map((l) => map.getLayer(l)) + .filter((layer) => !!layer) + .filter((layer) => layer?.type == 'raster'); + + rasterLayers.forEach((layer) => { + if (layer) { + const option = document.createElement('option'); + option.textContent = layer.id; + option.id = layer.id; + + select.appendChild(option); + } + }); + select.onchange = (ev) => { + const layerId = select.value; + const layer = map.getLayer(layerId); + if (layer) { + rasterLayers.forEach((l) => { + map.setLayoutProperty(l?.id, 'visibility', 'none'); + }); + + map.setLayoutProperty(layer.id, 'visibility', 'visible'); + } + }; + } + + private buildDebugLayers(map: Map) { + const title = document.createElement('h4'); + title.textContent = 'Debug layers'; + this.container.appendChild(title); + + const groups: Record = {}; + map + .getLayersOrder() + .map((l) => map.getLayer(l)) + .filter((layer) => !!layer) + .filter((layer) => this.layerInteractive(layer)) + .reverse() + .forEach((layer) => { + if (layer) { + const meta: { group: string } = layer.metadata as { group: string }; + + let groupName: string = 'Misc'; + if (meta.group) { + groupName = meta.group; + } + + const layerDiv = this.buildLayerDiv(layer as TypedStyleLayer, map); + + if (groups[groupName]) { + groups[groupName]?.appendChild(layerDiv); + } else { + const groupDiv = this.buildGroupDiv(groupName, layerDiv); + groups[groupName] = groupDiv; + this.container.appendChild(groupDiv); + } + } + }); + // initialize clickable layers (initially stops) + this.updateInteractiveLayerIds(map); + } + private updateInteractiveLayerIds(map: Map) { const visibleInteractiveLayerIds = map .getLayersOrder() From c0b4243be4ef804b02020b06465dfab0593b0318 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Sun, 1 Dec 2024 22:23:21 +0100 Subject: [PATCH 32/80] Add fixed TriMet raster tile --- .../apis/vectortiles/DebugStyleSpec.java | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/application/src/main/java/org/opentripplanner/apis/vectortiles/DebugStyleSpec.java b/application/src/main/java/org/opentripplanner/apis/vectortiles/DebugStyleSpec.java index d29e6fdf15b..c34a421bf5b 100644 --- a/application/src/main/java/org/opentripplanner/apis/vectortiles/DebugStyleSpec.java +++ b/application/src/main/java/org/opentripplanner/apis/vectortiles/DebugStyleSpec.java @@ -44,15 +44,24 @@ public class DebugStyleSpec { "© OpenStreetMap Contributors" ); private static final TileSource POSITRON_BACKGROUND = new RasterSource( - "background-carto", + "background-positron", List.of("https://cartodb-basemaps-a.global.ssl.fastly.net/light_all/{z}/{x}/{y}${r}.png"), 19, 256, "© OpenStreetMap, © CARTO" ); + private static final TileSource TRIMET_BACKGROUND = new RasterSource( + "background-trimet", + List.of("https://maps.trimet.org/wms/reflect?bbox={bbox-epsg-3857}&format=image/png&service=WMS&version=1.1.0&request=GetMap&srs=EPSG:3857&width=256&height=256&layers=aerials"), + 19, + 256, + "TriMet" + ); + private static final List BACKGROUND_LAYERS = List.of( OSM_BACKGROUND, - POSITRON_BACKGROUND + POSITRON_BACKGROUND, + TRIMET_BACKGROUND ); private static final String MAGENTA = "#f21d52"; private static final String BRIGHT_GREEN = "#22DD9E"; From 6ae498d6ac41ad429e9b0ecb660091fabf192cc4 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Sun, 1 Dec 2024 23:13:21 +0100 Subject: [PATCH 33/80] Add configuration for debug ui --- .../apis/vectortiles/DebugStyleSpec.java | 41 ++++--- .../GraphInspectorVectorTileResource.java | 3 +- .../framework/application/OtpFileNames.java | 6 +- .../api/OtpServerRequestContext.java | 3 + .../standalone/config/ConfigModel.java | 24 ++++- .../standalone/config/DebugUiConfig.java | 100 ++++++++++++++++++ .../standalone/config/OtpConfigLoader.java | 9 ++ .../config/configure/ConfigModule.java | 6 ++ .../debuguiconfig/BackgroundTileLayer.java | 12 +++ .../configure/ConstructApplication.java | 5 + .../configure/ConstructApplicationModule.java | 5 +- .../server/DefaultServerRequestContext.java | 17 ++- .../opentripplanner/TestServerContext.java | 4 +- .../mapping/TripRequestMapperTest.java | 4 +- .../apis/vectortiles/DebugStyleSpecTest.java | 3 +- .../transit/speed_test/SpeedTest.java | 4 +- 16 files changed, 215 insertions(+), 31 deletions(-) create mode 100644 application/src/main/java/org/opentripplanner/standalone/config/DebugUiConfig.java create mode 100644 application/src/main/java/org/opentripplanner/standalone/config/debuguiconfig/BackgroundTileLayer.java diff --git a/application/src/main/java/org/opentripplanner/apis/vectortiles/DebugStyleSpec.java b/application/src/main/java/org/opentripplanner/apis/vectortiles/DebugStyleSpec.java index c34a421bf5b..b66aa4fcc2b 100644 --- a/application/src/main/java/org/opentripplanner/apis/vectortiles/DebugStyleSpec.java +++ b/application/src/main/java/org/opentripplanner/apis/vectortiles/DebugStyleSpec.java @@ -13,6 +13,7 @@ import org.opentripplanner.apis.vectortiles.model.ZoomDependentNumber; import org.opentripplanner.apis.vectortiles.model.ZoomDependentNumber.ZoomStop; import org.opentripplanner.service.vehiclerental.street.StreetVehicleRentalLink; +import org.opentripplanner.standalone.config.debuguiconfig.BackgroundTileLayer; import org.opentripplanner.street.model.StreetTraversalPermission; import org.opentripplanner.street.model.edge.AreaEdge; import org.opentripplanner.street.model.edge.BoardingLocationToStopLink; @@ -50,18 +51,10 @@ public class DebugStyleSpec { 256, "© OpenStreetMap, © CARTO" ); - private static final TileSource TRIMET_BACKGROUND = new RasterSource( - "background-trimet", - List.of("https://maps.trimet.org/wms/reflect?bbox={bbox-epsg-3857}&format=image/png&service=WMS&version=1.1.0&request=GetMap&srs=EPSG:3857&width=256&height=256&layers=aerials"), - 19, - 256, - "TriMet" - ); private static final List BACKGROUND_LAYERS = List.of( OSM_BACKGROUND, - POSITRON_BACKGROUND, - TRIMET_BACKGROUND + POSITRON_BACKGROUND ); private static final String MAGENTA = "#f21d52"; private static final String BRIGHT_GREEN = "#22DD9E"; @@ -111,20 +104,33 @@ static StyleSpec build( VectorSourceLayer areaStops, VectorSourceLayer groupStops, VectorSourceLayer edges, - VectorSourceLayer vertices + VectorSourceLayer vertices, + List extraLayers ) { - List vectorSources = List + List vectorSources = Stream .of(regularStops, edges, vertices) - .stream() .map(VectorSourceLayer::vectorSource) .map(TileSource.class::cast) .toList(); - var allSources = ListUtils.combine(BACKGROUND_LAYERS, vectorSources); + + List extraRasterSources = extraLayers + .stream() + .map(l -> + (TileSource) new RasterSource( + l.name(), + List.of(l.templateUrl()), + 19, + l.tileSize(), + l.attribution() + ) + ) + .toList(); + var allSources = ListUtils.combine(BACKGROUND_LAYERS, extraRasterSources, vectorSources); return new StyleSpec( "OTP Debug Tiles", allSources, ListUtils.combine( - backgroundLayers(), + backgroundLayers(extraRasterSources), wheelchair(edges), noThruTraffic(edges), traversalPermissions(edges), @@ -135,12 +141,13 @@ static StyleSpec build( ); } - private static List backgroundLayers() { - return BACKGROUND_LAYERS + private static List backgroundLayers(List extraLayers) { + return ListUtils + .combine(BACKGROUND_LAYERS, extraLayers) .stream() .map(layer -> { var builder = StyleBuilder.ofId(layer.id()).typeRaster().source(layer).minZoom(0); - if(!layer.equals(OSM_BACKGROUND)){ + if (!layer.equals(OSM_BACKGROUND)) { builder.intiallyHidden(); } return builder; diff --git a/application/src/main/java/org/opentripplanner/apis/vectortiles/GraphInspectorVectorTileResource.java b/application/src/main/java/org/opentripplanner/apis/vectortiles/GraphInspectorVectorTileResource.java index d19c25a1f47..0576e91f312 100644 --- a/application/src/main/java/org/opentripplanner/apis/vectortiles/GraphInspectorVectorTileResource.java +++ b/application/src/main/java/org/opentripplanner/apis/vectortiles/GraphInspectorVectorTileResource.java @@ -147,7 +147,8 @@ public StyleSpec getTileJson(@Context UriInfo uri, @Context HttpHeaders headers) AREA_STOPS.toVectorSourceLayer(stopsSource), GROUP_STOPS.toVectorSourceLayer(stopsSource), EDGES.toVectorSourceLayer(streetSource), - VERTICES.toVectorSourceLayer(streetSource) + VERTICES.toVectorSourceLayer(streetSource), + serverContext.debugUiConfig().additionalBackgroundLayers() ); } diff --git a/application/src/main/java/org/opentripplanner/framework/application/OtpFileNames.java b/application/src/main/java/org/opentripplanner/framework/application/OtpFileNames.java index 7b6852cb281..6c3a5b6a007 100644 --- a/application/src/main/java/org/opentripplanner/framework/application/OtpFileNames.java +++ b/application/src/main/java/org/opentripplanner/framework/application/OtpFileNames.java @@ -9,16 +9,18 @@ public class OtpFileNames { public static final String OTP_CONFIG_FILENAME = "otp-config.json"; public static final String BUILD_CONFIG_FILENAME = "build-config.json"; public static final String ROUTER_CONFIG_FILENAME = "router-config.json"; + public static final String DEBUG_UI_CONFIG_FILENAME = "debug-ui-config.json"; /** * Check if a file is a config file using the configuration file name. This method returns {@code - * true} if the file match {@code (otp|build|router)-config.json}. + * true} if the file match {@code (otp|build|router|debug-ui)-config.json}. */ public static boolean isConfigFile(String filename) { return ( OTP_CONFIG_FILENAME.equals(filename) || BUILD_CONFIG_FILENAME.equals(filename) || - ROUTER_CONFIG_FILENAME.equals(filename) + ROUTER_CONFIG_FILENAME.equals(filename) || + DEBUG_UI_CONFIG_FILENAME.equals(filename) ); } } diff --git a/application/src/main/java/org/opentripplanner/standalone/api/OtpServerRequestContext.java b/application/src/main/java/org/opentripplanner/standalone/api/OtpServerRequestContext.java index b5b39ddee18..f088a3de60e 100644 --- a/application/src/main/java/org/opentripplanner/standalone/api/OtpServerRequestContext.java +++ b/application/src/main/java/org/opentripplanner/standalone/api/OtpServerRequestContext.java @@ -26,6 +26,7 @@ import org.opentripplanner.service.vehicleparking.VehicleParkingService; import org.opentripplanner.service.vehiclerental.VehicleRentalService; import org.opentripplanner.service.worldenvelope.WorldEnvelopeService; +import org.opentripplanner.standalone.config.DebugUiConfig; import org.opentripplanner.standalone.config.routerconfig.VectorTileConfig; import org.opentripplanner.street.model.edge.Edge; import org.opentripplanner.street.search.state.State; @@ -127,6 +128,8 @@ default GraphFinder graphFinder() { VectorTileConfig vectorTileConfig(); + DebugUiConfig debugUiConfig(); + /* Sandbox modules */ @Nullable diff --git a/application/src/main/java/org/opentripplanner/standalone/config/ConfigModel.java b/application/src/main/java/org/opentripplanner/standalone/config/ConfigModel.java index c82dd33ddbf..390333f1374 100644 --- a/application/src/main/java/org/opentripplanner/standalone/config/ConfigModel.java +++ b/application/src/main/java/org/opentripplanner/standalone/config/ConfigModel.java @@ -49,16 +49,29 @@ public class ConfigModel { */ private RouterConfig routerConfig; - public ConfigModel(OtpConfig otpConfig, BuildConfig buildConfig, RouterConfig routerConfig) { + private final DebugUiConfig debugUiConfig; + + public ConfigModel( + OtpConfig otpConfig, + BuildConfig buildConfig, + RouterConfig routerConfig, + DebugUiConfig debugUiConfig + ) { this.otpConfig = otpConfig; this.buildConfig = buildConfig; this.routerConfig = routerConfig; + this.debugUiConfig = debugUiConfig; initializeOtpFeatures(otpConfig); } public ConfigModel(OtpConfigLoader loader) { - this(loader.loadOtpConfig(), loader.loadBuildConfig(), loader.loadRouterConfig()); + this( + loader.loadOtpConfig(), + loader.loadBuildConfig(), + loader.loadRouterConfig(), + loader.loadDebugUiConfig() + ); } public void updateConfigFromSerializedGraph(BuildConfig buildConfig, RouterConfig routerConfig) { @@ -102,6 +115,10 @@ public RouterConfig routerConfig() { return routerConfig; } + public DebugUiConfig debugUiConfig() { + return debugUiConfig; + } + public static void initializeOtpFeatures(OtpConfig otpConfig) { OTPFeature.enableFeatures(otpConfig.otpFeatures); OTPFeature.logFeatureSetup(); @@ -117,7 +134,8 @@ public void abortOnUnknownParameters() { ( otpConfig.hasUnknownParameters() || buildConfig.hasUnknownParameters() || - routerConfig.hasUnknownParameters() + routerConfig.hasUnknownParameters() || + debugUiConfig.hasUnknownParameters() ) ) { throw new OtpAppException( diff --git a/application/src/main/java/org/opentripplanner/standalone/config/DebugUiConfig.java b/application/src/main/java/org/opentripplanner/standalone/config/DebugUiConfig.java new file mode 100644 index 00000000000..c32c4dce941 --- /dev/null +++ b/application/src/main/java/org/opentripplanner/standalone/config/DebugUiConfig.java @@ -0,0 +1,100 @@ +package org.opentripplanner.standalone.config; + +import static org.opentripplanner.standalone.config.framework.json.OtpVersion.V2_0; +import static org.opentripplanner.standalone.config.framework.json.OtpVersion.V2_7; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.MissingNode; +import java.io.Serializable; +import java.util.List; +import org.opentripplanner.standalone.config.debuguiconfig.BackgroundTileLayer; +import org.opentripplanner.standalone.config.framework.json.NodeAdapter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * This class is an object representation of the 'debug-ui-config.json'. + */ +public class DebugUiConfig implements Serializable { + + private static final Logger LOG = LoggerFactory.getLogger(DebugUiConfig.class); + + public static final DebugUiConfig DEFAULT = new DebugUiConfig( + MissingNode.getInstance(), + "DEFAULT", + false + ); + + /** + * The node adaptor kept for reference and (de)serialization. + */ + private final NodeAdapter root; + private final List additionalBackgroundLayers; + + public DebugUiConfig(JsonNode node, String source, boolean logUnusedParams) { + this(new NodeAdapter(node, source), logUnusedParams); + } + + /** protected to give unit-test access */ + DebugUiConfig(NodeAdapter root, boolean logUnusedParams) { + this.root = root; + + this.additionalBackgroundLayers = + root + .of("additionalBackgroundLayers") + .asObjects( + List.of(), + node -> + new BackgroundTileLayer( + node + .of("name") + .since(V2_7) + .summary( + "Used in the url to fetch tiles, and as the layer name in the vector tiles." + ) + .asString(), + node + .of("templateUrl") + .since(V2_7) + .summary("Maximum zoom levels the layer is active for.") + .asString(), + node + .of("minZoom") + .since(V2_0) + .summary("Minimum zoom levels the layer is active for.") + .asInt(256), + node + .of("minZoom") + .since(V2_7) + .summary("Minimum zoom levels the layer is active for.") + .asString("© OpenTripPlanner") + ) + ); + + if (logUnusedParams && LOG.isWarnEnabled()) { + root.logAllWarnings(LOG::warn); + } + } + + public NodeAdapter asNodeAdapter() { + return root; + } + + public List additionalBackgroundLayers() { + return additionalBackgroundLayers; + } + + /** + * If {@code true} the config is loaded from file, in not the DEFAULT config is used. + */ + public boolean isDefault() { + return root.isEmpty(); + } + + /** + * Checks if any unknown or invalid parameters were encountered while loading the configuration. + */ + public boolean hasUnknownParameters() { + return root.hasUnknownParameters(); + } +} diff --git a/application/src/main/java/org/opentripplanner/standalone/config/OtpConfigLoader.java b/application/src/main/java/org/opentripplanner/standalone/config/OtpConfigLoader.java index d5c452b3da7..9e24e56ca12 100644 --- a/application/src/main/java/org/opentripplanner/standalone/config/OtpConfigLoader.java +++ b/application/src/main/java/org/opentripplanner/standalone/config/OtpConfigLoader.java @@ -1,6 +1,7 @@ package org.opentripplanner.standalone.config; import static org.opentripplanner.framework.application.OtpFileNames.BUILD_CONFIG_FILENAME; +import static org.opentripplanner.framework.application.OtpFileNames.DEBUG_UI_CONFIG_FILENAME; import static org.opentripplanner.framework.application.OtpFileNames.OTP_CONFIG_FILENAME; import static org.opentripplanner.framework.application.OtpFileNames.ROUTER_CONFIG_FILENAME; @@ -105,6 +106,14 @@ public RouterConfig loadRouterConfig() { return new RouterConfig(node, ROUTER_CONFIG_FILENAME, true); } + public DebugUiConfig loadDebugUiConfig() { + JsonNode node = loadFromFile(DEBUG_UI_CONFIG_FILENAME); + if (node.isMissingNode()) { + return DebugUiConfig.DEFAULT; + } + return new DebugUiConfig(node, DEBUG_UI_CONFIG_FILENAME, true); + } + private static void logConfigVersion(String configVersion, String filename) { if (configVersion != null) { LOG.info("{} config-version is {}.", filename, configVersion); diff --git a/application/src/main/java/org/opentripplanner/standalone/config/configure/ConfigModule.java b/application/src/main/java/org/opentripplanner/standalone/config/configure/ConfigModule.java index 4f75f3984d5..9a4de91f2ab 100644 --- a/application/src/main/java/org/opentripplanner/standalone/config/configure/ConfigModule.java +++ b/application/src/main/java/org/opentripplanner/standalone/config/configure/ConfigModule.java @@ -8,6 +8,7 @@ import org.opentripplanner.routing.algorithm.raptoradapter.transit.TripSchedule; import org.opentripplanner.standalone.config.BuildConfig; import org.opentripplanner.standalone.config.ConfigModel; +import org.opentripplanner.standalone.config.DebugUiConfig; import org.opentripplanner.standalone.config.OtpConfig; import org.opentripplanner.standalone.config.RouterConfig; import org.opentripplanner.standalone.config.routerconfig.RaptorEnvironmentFactory; @@ -34,6 +35,11 @@ static RouterConfig provideRouterConfig(ConfigModel model) { return model.routerConfig(); } + @Provides + static DebugUiConfig provideDebugUiConfig(ConfigModel model) { + return model.debugUiConfig(); + } + @Provides @Singleton static RaptorConfig providesRaptorConfig( diff --git a/application/src/main/java/org/opentripplanner/standalone/config/debuguiconfig/BackgroundTileLayer.java b/application/src/main/java/org/opentripplanner/standalone/config/debuguiconfig/BackgroundTileLayer.java new file mode 100644 index 00000000000..b8b6a4a5f81 --- /dev/null +++ b/application/src/main/java/org/opentripplanner/standalone/config/debuguiconfig/BackgroundTileLayer.java @@ -0,0 +1,12 @@ +package org.opentripplanner.standalone.config.debuguiconfig; + +public record BackgroundTileLayer( + String name, + String templateUrl, + int tileSize, + String attribution +) { + public String name() { + return name.toLowerCase().replace("_", "-").replace(" ", "-"); + } +} diff --git a/application/src/main/java/org/opentripplanner/standalone/configure/ConstructApplication.java b/application/src/main/java/org/opentripplanner/standalone/configure/ConstructApplication.java index eb3fae5275f..b4edbb36299 100644 --- a/application/src/main/java/org/opentripplanner/standalone/configure/ConstructApplication.java +++ b/application/src/main/java/org/opentripplanner/standalone/configure/ConstructApplication.java @@ -27,6 +27,7 @@ import org.opentripplanner.standalone.config.BuildConfig; import org.opentripplanner.standalone.config.CommandLineParameters; import org.opentripplanner.standalone.config.ConfigModel; +import org.opentripplanner.standalone.config.DebugUiConfig; import org.opentripplanner.standalone.config.OtpConfig; import org.opentripplanner.standalone.config.RouterConfig; import org.opentripplanner.standalone.server.GrizzlyServer; @@ -300,6 +301,10 @@ public BuildConfig buildConfig() { return factory.config().buildConfig(); } + public DebugUiConfig debugUiConfig() { + return factory.config().debugUiConfig(); + } + public RaptorConfig raptorConfig() { return factory.raptorConfig(); } diff --git a/application/src/main/java/org/opentripplanner/standalone/configure/ConstructApplicationModule.java b/application/src/main/java/org/opentripplanner/standalone/configure/ConstructApplicationModule.java index bbdd39c57d5..42bd8ee4d87 100644 --- a/application/src/main/java/org/opentripplanner/standalone/configure/ConstructApplicationModule.java +++ b/application/src/main/java/org/opentripplanner/standalone/configure/ConstructApplicationModule.java @@ -20,6 +20,7 @@ import org.opentripplanner.service.vehiclerental.VehicleRentalService; import org.opentripplanner.service.worldenvelope.WorldEnvelopeService; import org.opentripplanner.standalone.api.OtpServerRequestContext; +import org.opentripplanner.standalone.config.DebugUiConfig; import org.opentripplanner.standalone.config.RouterConfig; import org.opentripplanner.standalone.server.DefaultServerRequestContext; import org.opentripplanner.street.service.StreetLimitationParametersService; @@ -32,6 +33,7 @@ public class ConstructApplicationModule { @Provides OtpServerRequestContext providesServerContext( RouterConfig routerConfig, + DebugUiConfig debugUiConfig, RaptorConfig raptorConfig, Graph graph, TransitService transitService, @@ -69,7 +71,8 @@ OtpServerRequestContext providesServerContext( stopConsolidationService, streetLimitationParametersService, traverseVisitor, - luceneIndex + luceneIndex, + debugUiConfig ); } diff --git a/application/src/main/java/org/opentripplanner/standalone/server/DefaultServerRequestContext.java b/application/src/main/java/org/opentripplanner/standalone/server/DefaultServerRequestContext.java index 1427dcf1971..450b6986cb5 100644 --- a/application/src/main/java/org/opentripplanner/standalone/server/DefaultServerRequestContext.java +++ b/application/src/main/java/org/opentripplanner/standalone/server/DefaultServerRequestContext.java @@ -26,6 +26,7 @@ import org.opentripplanner.service.worldenvelope.WorldEnvelopeService; import org.opentripplanner.standalone.api.HttpRequestScoped; import org.opentripplanner.standalone.api.OtpServerRequestContext; +import org.opentripplanner.standalone.config.DebugUiConfig; import org.opentripplanner.standalone.config.routerconfig.TransitRoutingConfig; import org.opentripplanner.standalone.config.routerconfig.VectorTileConfig; import org.opentripplanner.street.service.StreetLimitationParametersService; @@ -57,6 +58,7 @@ public class DefaultServerRequestContext implements OtpServerRequestContext { private final StopConsolidationService stopConsolidationService; private final StreetLimitationParametersService streetLimitationParametersService; private final LuceneIndex luceneIndex; + private final DebugUiConfig debugUiConfig; private RouteRequest defaultRouteRequestWithTimeSet = null; @@ -83,7 +85,8 @@ private DefaultServerRequestContext( StreetLimitationParametersService streetLimitationParametersService, FlexParameters flexParameters, @Nullable TraverseVisitor traverseVisitor, - @Nullable LuceneIndex luceneIndex + @Nullable LuceneIndex luceneIndex, + DebugUiConfig debugUiConfig ) { this.graph = graph; this.transitService = transitService; @@ -105,6 +108,7 @@ private DefaultServerRequestContext( this.stopConsolidationService = stopConsolidationService; this.streetLimitationParametersService = streetLimitationParametersService; this.luceneIndex = luceneIndex; + this.debugUiConfig = debugUiConfig; } /** @@ -129,7 +133,8 @@ public static DefaultServerRequestContext create( @Nullable StopConsolidationService stopConsolidationService, StreetLimitationParametersService streetLimitationParametersService, @Nullable TraverseVisitor traverseVisitor, - @Nullable LuceneIndex luceneIndex + @Nullable LuceneIndex luceneIndex, + DebugUiConfig debugUiConfig ) { return new DefaultServerRequestContext( graph, @@ -151,7 +156,8 @@ public static DefaultServerRequestContext create( streetLimitationParametersService, flexParameters, traverseVisitor, - luceneIndex + luceneIndex, + debugUiConfig ); } @@ -262,6 +268,11 @@ public VectorTileConfig vectorTileConfig() { return vectorTileConfig; } + @Override + public DebugUiConfig debugUiConfig() { + return debugUiConfig; + } + @Nullable @Override public LuceneIndex lucenceIndex() { diff --git a/application/src/test/java/org/opentripplanner/TestServerContext.java b/application/src/test/java/org/opentripplanner/TestServerContext.java index e20720bd7d8..ca818a64a58 100644 --- a/application/src/test/java/org/opentripplanner/TestServerContext.java +++ b/application/src/test/java/org/opentripplanner/TestServerContext.java @@ -21,6 +21,7 @@ import org.opentripplanner.service.worldenvelope.internal.DefaultWorldEnvelopeService; import org.opentripplanner.service.worldenvelope.model.WorldEnvelope; import org.opentripplanner.standalone.api.OtpServerRequestContext; +import org.opentripplanner.standalone.config.DebugUiConfig; import org.opentripplanner.standalone.config.RouterConfig; import org.opentripplanner.standalone.config.routerconfig.RaptorEnvironmentFactory; import org.opentripplanner.standalone.server.DefaultServerRequestContext; @@ -65,7 +66,8 @@ public static OtpServerRequestContext createServerContext( null, createStreetLimitationParametersService(), null, - null + null, + DebugUiConfig.DEFAULT ); creatTransitLayerForRaptor(timetableRepository, routerConfig.transitTuningConfig()); return context; diff --git a/application/src/test/java/org/opentripplanner/apis/transmodel/mapping/TripRequestMapperTest.java b/application/src/test/java/org/opentripplanner/apis/transmodel/mapping/TripRequestMapperTest.java index b3c64e0aecb..dc96a094812 100644 --- a/application/src/test/java/org/opentripplanner/apis/transmodel/mapping/TripRequestMapperTest.java +++ b/application/src/test/java/org/opentripplanner/apis/transmodel/mapping/TripRequestMapperTest.java @@ -52,6 +52,7 @@ import org.opentripplanner.service.vehiclerental.internal.DefaultVehicleRentalService; import org.opentripplanner.service.worldenvelope.internal.DefaultWorldEnvelopeRepository; import org.opentripplanner.service.worldenvelope.internal.DefaultWorldEnvelopeService; +import org.opentripplanner.standalone.config.DebugUiConfig; import org.opentripplanner.standalone.config.RouterConfig; import org.opentripplanner.standalone.server.DefaultServerRequestContext; import org.opentripplanner.street.model.StreetLimitationParameters; @@ -154,7 +155,8 @@ void setup() { null, new DefaultStreetLimitationParametersService(new StreetLimitationParameters()), null, - null + null, + DebugUiConfig.DEFAULT ), null, transitService diff --git a/application/src/test/java/org/opentripplanner/apis/vectortiles/DebugStyleSpecTest.java b/application/src/test/java/org/opentripplanner/apis/vectortiles/DebugStyleSpecTest.java index db056050394..f602a6cb532 100644 --- a/application/src/test/java/org/opentripplanner/apis/vectortiles/DebugStyleSpecTest.java +++ b/application/src/test/java/org/opentripplanner/apis/vectortiles/DebugStyleSpecTest.java @@ -5,6 +5,7 @@ import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; +import java.util.List; import org.junit.jupiter.api.Test; import org.opentripplanner.apis.vectortiles.model.TileSource.VectorSource; import org.opentripplanner.apis.vectortiles.model.VectorSourceLayer; @@ -27,7 +28,7 @@ void spec() throws IOException { var groupStops = new VectorSourceLayer(vectorSource, "stops"); var edges = new VectorSourceLayer(vectorSource, "edges"); var vertices = new VectorSourceLayer(vectorSource, "vertices"); - var spec = DebugStyleSpec.build(regularStops, areaStops, groupStops, edges, vertices); + var spec = DebugStyleSpec.build(regularStops, areaStops, groupStops, edges, vertices, List.of()); var json = ObjectMappers.ignoringExtraFields().valueToTree(spec); try { diff --git a/application/src/test/java/org/opentripplanner/transit/speed_test/SpeedTest.java b/application/src/test/java/org/opentripplanner/transit/speed_test/SpeedTest.java index c55ddff854f..ca4e85eed84 100644 --- a/application/src/test/java/org/opentripplanner/transit/speed_test/SpeedTest.java +++ b/application/src/test/java/org/opentripplanner/transit/speed_test/SpeedTest.java @@ -29,6 +29,7 @@ import org.opentripplanner.standalone.api.OtpServerRequestContext; import org.opentripplanner.standalone.config.BuildConfig; import org.opentripplanner.standalone.config.ConfigModel; +import org.opentripplanner.standalone.config.DebugUiConfig; import org.opentripplanner.standalone.config.OtpConfigLoader; import org.opentripplanner.standalone.config.routerconfig.RaptorEnvironmentFactory; import org.opentripplanner.standalone.config.routerconfig.VectorTileConfig; @@ -130,7 +131,8 @@ public SpeedTest( null, TestServerContext.createStreetLimitationParametersService(), null, - null + null, + DebugUiConfig.DEFAULT ); // Creating transitLayerForRaptor should be integrated into the TimetableRepository, but for now // we do it manually here From a934342baa54370f1f843f65785745d65c3eebea Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Mon, 2 Dec 2024 10:09:50 +0100 Subject: [PATCH 34/80] Update tests --- .../apis/vectortiles/DebugStyleSpec.java | 2 +- .../apis/vectortiles/style.json | 27 ++++++++++--------- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/application/src/main/java/org/opentripplanner/apis/vectortiles/DebugStyleSpec.java b/application/src/main/java/org/opentripplanner/apis/vectortiles/DebugStyleSpec.java index b66aa4fcc2b..12632c90efb 100644 --- a/application/src/main/java/org/opentripplanner/apis/vectortiles/DebugStyleSpec.java +++ b/application/src/main/java/org/opentripplanner/apis/vectortiles/DebugStyleSpec.java @@ -46,7 +46,7 @@ public class DebugStyleSpec { ); private static final TileSource POSITRON_BACKGROUND = new RasterSource( "background-positron", - List.of("https://cartodb-basemaps-a.global.ssl.fastly.net/light_all/{z}/{x}/{y}${r}.png"), + List.of("https://cartodb-basemaps-a.global.ssl.fastly.net/light_all/{z}/{x}/{y}.png"), 19, 256, "© OpenStreetMap, © CARTO" diff --git a/application/src/test/resources/org/opentripplanner/apis/vectortiles/style.json b/application/src/test/resources/org/opentripplanner/apis/vectortiles/style.json index fe7b546400d..00cceab1b06 100644 --- a/application/src/test/resources/org/opentripplanner/apis/vectortiles/style.json +++ b/application/src/test/resources/org/opentripplanner/apis/vectortiles/style.json @@ -1,6 +1,16 @@ { "name" : "OTP Debug Tiles", "sources" : { + "background-positron" : { + "id" : "background-positron", + "tiles" : [ + "https://cartodb-basemaps-a.global.ssl.fastly.net/light_all/{z}/{x}/{y}.png" + ], + "maxzoom" : 19, + "tileSize" : 256, + "attribution" : "© OpenStreetMap, © CARTO", + "type" : "raster" + }, "vectorSource" : { "id" : "vectorSource", "url" : "https://example.com", @@ -15,16 +25,6 @@ "tileSize" : 256, "attribution" : "© OpenStreetMap Contributors", "type" : "raster" - }, - "background-carto" : { - "id" : "background-carto", - "tiles" : [ - "https://{s}.basemaps.cartocdn.com/{z}/{x}/{y}" - ], - "maxzoom" : 19, - "tileSize" : 256, - "attribution" : "© OpenStreetMap, © CARTO", - "type" : "raster" } }, "layers" : [ @@ -38,10 +38,13 @@ } }, { - "id" : "background-carto", + "id" : "background-positron", "type" : "raster", - "source" : "background-carto", + "source" : "background-positron", "minzoom" : 0, + "layout" : { + "visibility" : "none" + }, "metadata" : { "group" : "Other" } From 25b4fee19f174cb8a2c5a1765e2986d1422d7d46 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Mon, 2 Dec 2024 10:40:24 +0100 Subject: [PATCH 35/80] Fix configuration --- .../opentripplanner/apis/vectortiles/DebugStyleSpec.java | 2 +- .../opentripplanner/standalone/config/DebugUiConfig.java | 7 +++---- .../config/debuguiconfig/BackgroundTileLayer.java | 2 +- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/application/src/main/java/org/opentripplanner/apis/vectortiles/DebugStyleSpec.java b/application/src/main/java/org/opentripplanner/apis/vectortiles/DebugStyleSpec.java index 12632c90efb..40dce2f6f10 100644 --- a/application/src/main/java/org/opentripplanner/apis/vectortiles/DebugStyleSpec.java +++ b/application/src/main/java/org/opentripplanner/apis/vectortiles/DebugStyleSpec.java @@ -117,7 +117,7 @@ static StyleSpec build( .stream() .map(l -> (TileSource) new RasterSource( - l.name(), + l.id(), List.of(l.templateUrl()), 19, l.tileSize(), diff --git a/application/src/main/java/org/opentripplanner/standalone/config/DebugUiConfig.java b/application/src/main/java/org/opentripplanner/standalone/config/DebugUiConfig.java index c32c4dce941..085451024b2 100644 --- a/application/src/main/java/org/opentripplanner/standalone/config/DebugUiConfig.java +++ b/application/src/main/java/org/opentripplanner/standalone/config/DebugUiConfig.java @@ -1,6 +1,5 @@ package org.opentripplanner.standalone.config; -import static org.opentripplanner.standalone.config.framework.json.OtpVersion.V2_0; import static org.opentripplanner.standalone.config.framework.json.OtpVersion.V2_7; import com.fasterxml.jackson.databind.JsonNode; @@ -59,12 +58,12 @@ public DebugUiConfig(JsonNode node, String source, boolean logUnusedParams) { .summary("Maximum zoom levels the layer is active for.") .asString(), node - .of("minZoom") - .since(V2_0) + .of("tileSize") + .since(V2_7) .summary("Minimum zoom levels the layer is active for.") .asInt(256), node - .of("minZoom") + .of("attribution") .since(V2_7) .summary("Minimum zoom levels the layer is active for.") .asString("© OpenTripPlanner") diff --git a/application/src/main/java/org/opentripplanner/standalone/config/debuguiconfig/BackgroundTileLayer.java b/application/src/main/java/org/opentripplanner/standalone/config/debuguiconfig/BackgroundTileLayer.java index b8b6a4a5f81..7f8546e1110 100644 --- a/application/src/main/java/org/opentripplanner/standalone/config/debuguiconfig/BackgroundTileLayer.java +++ b/application/src/main/java/org/opentripplanner/standalone/config/debuguiconfig/BackgroundTileLayer.java @@ -6,7 +6,7 @@ public record BackgroundTileLayer( int tileSize, String attribution ) { - public String name() { + public String id() { return name.toLowerCase().replace("_", "-").replace(" ", "-"); } } From 9bd492ab55981929d88cf7dc02a6bf1013cecc5f Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Mon, 2 Dec 2024 11:01:31 +0100 Subject: [PATCH 36/80] Style background layer picker --- client/src/style.css | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/client/src/style.css b/client/src/style.css index c33f5dff711..f838dce2c7b 100644 --- a/client/src/style.css +++ b/client/src/style.css @@ -181,6 +181,10 @@ margin-left: 6px; } +.maplibregl-ctrl-group.layer-select select { + margin-bottom: 14px; +} + .maplibregl-ctrl-group.layer-select h4 { font-size: 17px; } From 441711bf58efd3c364d529b01ecbd4ed718edbda Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Mon, 2 Dec 2024 11:42:19 +0100 Subject: [PATCH 37/80] Add nicer names to UI --- .../apis/vectortiles/DebugStyleSpec.java | 13 +- .../apis/vectortiles/model/StyleBuilder.java | 10 +- .../apis/vectortiles/model/TileSource.java | 20 +- .../debuguiconfig/BackgroundTileLayer.java | 6 +- .../apis/vectortiles/DebugStyleSpecTest.java | 9 +- .../apis/vectortiles/style.json | 1242 ++++++----------- .../src/components/MapView/LayerControl.tsx | 7 +- .../utils/lang/StringUtils.java | 8 + .../utils/lang/StringUtilsTest.java | 6 + 9 files changed, 455 insertions(+), 866 deletions(-) diff --git a/application/src/main/java/org/opentripplanner/apis/vectortiles/DebugStyleSpec.java b/application/src/main/java/org/opentripplanner/apis/vectortiles/DebugStyleSpec.java index 40dce2f6f10..0bcfba51e26 100644 --- a/application/src/main/java/org/opentripplanner/apis/vectortiles/DebugStyleSpec.java +++ b/application/src/main/java/org/opentripplanner/apis/vectortiles/DebugStyleSpec.java @@ -38,14 +38,14 @@ public class DebugStyleSpec { private static final TileSource OSM_BACKGROUND = new RasterSource( - "background-osm", + "OSM Carto", List.of("https://a.tile.openstreetmap.org/{z}/{x}/{y}.png"), 19, 256, "© OpenStreetMap Contributors" ); private static final TileSource POSITRON_BACKGROUND = new RasterSource( - "background-positron", + "Positron", List.of("https://cartodb-basemaps-a.global.ssl.fastly.net/light_all/{z}/{x}/{y}.png"), 19, 256, @@ -117,7 +117,7 @@ static StyleSpec build( .stream() .map(l -> (TileSource) new RasterSource( - l.id(), + l.name(), List.of(l.templateUrl()), 19, l.tileSize(), @@ -146,7 +146,12 @@ private static List backgroundLayers(List extraLayers) .combine(BACKGROUND_LAYERS, extraLayers) .stream() .map(layer -> { - var builder = StyleBuilder.ofId(layer.id()).typeRaster().source(layer).minZoom(0); + var builder = StyleBuilder + .ofId(layer.id()) + .displayName(layer.name()) + .typeRaster() + .source(layer) + .minZoom(0); if (!layer.equals(OSM_BACKGROUND)) { builder.intiallyHidden(); } diff --git a/application/src/main/java/org/opentripplanner/apis/vectortiles/model/StyleBuilder.java b/application/src/main/java/org/opentripplanner/apis/vectortiles/model/StyleBuilder.java index a70acbb8685..4e75f37785d 100644 --- a/application/src/main/java/org/opentripplanner/apis/vectortiles/model/StyleBuilder.java +++ b/application/src/main/java/org/opentripplanner/apis/vectortiles/model/StyleBuilder.java @@ -30,7 +30,7 @@ public class StyleBuilder { private final Map layout = new LinkedHashMap<>(); private final Map metadata = new LinkedHashMap<>(); private final Map line = new LinkedHashMap<>(); - private List filter = List.of(); + private List filter = List.of(); public static StyleBuilder ofId(String id) { return new StyleBuilder(id); @@ -120,6 +120,14 @@ public StyleBuilder group(String group) { return this; } + /** + * A nice human-readable name for the layer. + */ + public StyleBuilder displayName(String name) { + metadata.put("name", name); + return this; + } + public StyleBuilder lineText(String name) { layout.put("symbol-placement", "line-center"); layout.put("symbol-spacing", 1000); diff --git a/application/src/main/java/org/opentripplanner/apis/vectortiles/model/TileSource.java b/application/src/main/java/org/opentripplanner/apis/vectortiles/model/TileSource.java index 088ce63d10a..b7f0ce5d048 100644 --- a/application/src/main/java/org/opentripplanner/apis/vectortiles/model/TileSource.java +++ b/application/src/main/java/org/opentripplanner/apis/vectortiles/model/TileSource.java @@ -2,6 +2,7 @@ import com.fasterxml.jackson.databind.annotation.JsonSerialize; import java.util.List; +import org.opentripplanner.utils.lang.StringUtils; /** * Represent a data source where Maplibre can fetch data for rendering directly in the browser. @@ -12,6 +13,8 @@ public sealed interface TileSource { String id(); + String name(); + /** * Represents a vector tile source which is rendered into a map in the browser. */ @@ -20,17 +23,32 @@ record VectorSource(String id, String url) implements TileSource { public String type() { return "vector"; } + + @Override + public String name() { + return id; + } } /** * Represents a raster-based source for map tiles. These are used mainly for background * map layers with vector data being rendered on top of it. */ - record RasterSource(String id, List tiles, int maxzoom, int tileSize, String attribution) + record RasterSource( + String name, + List tiles, + int maxzoom, + int tileSize, + String attribution + ) implements TileSource { @Override public String type() { return "raster"; } + + public String id() { + return StringUtils.slugify(name); + } } } diff --git a/application/src/main/java/org/opentripplanner/standalone/config/debuguiconfig/BackgroundTileLayer.java b/application/src/main/java/org/opentripplanner/standalone/config/debuguiconfig/BackgroundTileLayer.java index 7f8546e1110..121debcb40e 100644 --- a/application/src/main/java/org/opentripplanner/standalone/config/debuguiconfig/BackgroundTileLayer.java +++ b/application/src/main/java/org/opentripplanner/standalone/config/debuguiconfig/BackgroundTileLayer.java @@ -5,8 +5,4 @@ public record BackgroundTileLayer( String templateUrl, int tileSize, String attribution -) { - public String id() { - return name.toLowerCase().replace("_", "-").replace(" ", "-"); - } -} +) {} diff --git a/application/src/test/java/org/opentripplanner/apis/vectortiles/DebugStyleSpecTest.java b/application/src/test/java/org/opentripplanner/apis/vectortiles/DebugStyleSpecTest.java index f602a6cb532..26d1044047e 100644 --- a/application/src/test/java/org/opentripplanner/apis/vectortiles/DebugStyleSpecTest.java +++ b/application/src/test/java/org/opentripplanner/apis/vectortiles/DebugStyleSpecTest.java @@ -28,7 +28,14 @@ void spec() throws IOException { var groupStops = new VectorSourceLayer(vectorSource, "stops"); var edges = new VectorSourceLayer(vectorSource, "edges"); var vertices = new VectorSourceLayer(vectorSource, "vertices"); - var spec = DebugStyleSpec.build(regularStops, areaStops, groupStops, edges, vertices, List.of()); + var spec = DebugStyleSpec.build( + regularStops, + areaStops, + groupStops, + edges, + vertices, + List.of() + ); var json = ObjectMappers.ignoringExtraFields().valueToTree(spec); try { diff --git a/application/src/test/resources/org/opentripplanner/apis/vectortiles/style.json b/application/src/test/resources/org/opentripplanner/apis/vectortiles/style.json index 00cceab1b06..a1a188ca76a 100644 --- a/application/src/test/resources/org/opentripplanner/apis/vectortiles/style.json +++ b/application/src/test/resources/org/opentripplanner/apis/vectortiles/style.json @@ -1,166 +1,107 @@ { - "name" : "OTP Debug Tiles", - "sources" : { - "background-positron" : { - "id" : "background-positron", - "tiles" : [ + "name": "OTP Debug Tiles", + "sources": { + "positron": { + "name": "Positron", + "tiles": [ "https://cartodb-basemaps-a.global.ssl.fastly.net/light_all/{z}/{x}/{y}.png" ], - "maxzoom" : 19, - "tileSize" : 256, - "attribution" : "© OpenStreetMap, © CARTO", - "type" : "raster" + "maxzoom": 19, + "tileSize": 256, + "attribution": "© OpenStreetMap, © CARTO", + "type": "raster" }, - "vectorSource" : { - "id" : "vectorSource", - "url" : "https://example.com", - "type" : "vector" + "vectorSource": { + "id": "vectorSource", + "url": "https://example.com", + "type": "vector" }, - "background-osm" : { - "id" : "background-osm", - "tiles" : [ - "https://a.tile.openstreetmap.org/{z}/{x}/{y}.png" - ], - "maxzoom" : 19, - "tileSize" : 256, - "attribution" : "© OpenStreetMap Contributors", - "type" : "raster" + "osm-carto": { + "name": "OSM Carto", + "tiles": ["https://a.tile.openstreetmap.org/{z}/{x}/{y}.png"], + "maxzoom": 19, + "tileSize": 256, + "attribution": "© OpenStreetMap Contributors", + "type": "raster" } }, - "layers" : [ + "layers": [ { - "id" : "background-osm", - "type" : "raster", - "source" : "background-osm", - "minzoom" : 0, - "metadata" : { - "group" : "Other" + "id": "osm-carto", + "type": "raster", + "source": "osm-carto", + "minzoom": 0, + "metadata": { + "group": "Other", + "name": "OSM Carto" } }, { - "id" : "background-positron", - "type" : "raster", - "source" : "background-positron", - "minzoom" : 0, - "layout" : { - "visibility" : "none" - }, - "metadata" : { - "group" : "Other" + "id": "positron", + "type": "raster", + "source": "positron", + "minzoom": 0, + "layout": { + "visibility": "none" + }, + "metadata": { + "group": "Other", + "name": "Positron" } }, { - "id" : "wheelchair-accessible", - "source" : "vectorSource", - "source-layer" : "edges", - "type" : "line", - "minzoom" : 6, - "maxzoom" : 23, - "paint" : { - "line-color" : "#136b04", - "line-width" : [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 13, - 0.2, - 23, - 8.0 - ], - "line-offset" : [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 13, - 0.4, - 23, - 7.0 - ] - }, - "filter" : [ - "==", - "wheelchairAccessible", - true - ], - "layout" : { - "line-cap" : "round", - "visibility" : "none" - }, - "metadata" : { - "group" : "Wheelchair accessibility" + "id": "wheelchair-accessible", + "source": "vectorSource", + "source-layer": "edges", + "type": "line", + "minzoom": 6, + "maxzoom": 23, + "paint": { + "line-color": "#136b04", + "line-width": ["interpolate", ["linear"], ["zoom"], 13, 0.2, 23, 8.0], + "line-offset": ["interpolate", ["linear"], ["zoom"], 13, 0.4, 23, 7.0] + }, + "filter": ["==", "wheelchairAccessible", true], + "layout": { + "line-cap": "round", + "visibility": "none" + }, + "metadata": { + "group": "Wheelchair accessibility" } }, { - "id" : "wheelchair-inaccessible", - "source" : "vectorSource", - "source-layer" : "edges", - "type" : "line", - "minzoom" : 6, - "maxzoom" : 23, - "paint" : { - "line-color" : "#fc0f2a", - "line-width" : [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 13, - 0.2, - 23, - 8.0 - ], - "line-offset" : [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 13, - 0.4, - 23, - 7.0 - ] - }, - "filter" : [ - "==", - "wheelchairAccessible", - false - ], - "layout" : { - "line-cap" : "round", - "visibility" : "none" - }, - "metadata" : { - "group" : "Wheelchair accessibility" + "id": "wheelchair-inaccessible", + "source": "vectorSource", + "source-layer": "edges", + "type": "line", + "minzoom": 6, + "maxzoom": 23, + "paint": { + "line-color": "#fc0f2a", + "line-width": ["interpolate", ["linear"], ["zoom"], 13, 0.2, 23, 8.0], + "line-offset": ["interpolate", ["linear"], ["zoom"], 13, 0.4, 23, 7.0] + }, + "filter": ["==", "wheelchairAccessible", false], + "layout": { + "line-cap": "round", + "visibility": "none" + }, + "metadata": { + "group": "Wheelchair accessibility" } }, { - "id" : "no-thru-traffic PEDESTRIAN", - "source" : "vectorSource", - "source-layer" : "edges", - "type" : "line", - "minzoom" : 13, - "maxzoom" : 23, - "paint" : { - "line-color" : [ + "id": "no-thru-traffic PEDESTRIAN", + "source": "vectorSource", + "source-layer": "edges", + "type": "line", + "minzoom": 13, + "maxzoom": 23, + "paint": { + "line-color": [ "match", - [ - "get", - "noThruTraffic" - ], + ["get", "noThruTraffic"], "NONE", "#140d0e", "PEDESTRIAN", @@ -179,80 +120,33 @@ "#adb2b0", "#140d0e" ], - "line-width" : [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 13, - 0.2, - 23, - 8.0 - ], - "line-offset" : [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 13, - 0.4, - 23, - 7.0 - ] + "line-width": ["interpolate", ["linear"], ["zoom"], 13, 0.2, 23, 8.0], + "line-offset": ["interpolate", ["linear"], ["zoom"], 13, 0.4, 23, 7.0] }, - "filter" : [ + "filter": [ "any", - [ - "in", - "PEDESTRIAN", - [ - "string", - [ - "get", - "noThruTraffic" - ] - ] - ], - [ - "in", - "ALL", - [ - "string", - [ - "get", - "noThruTraffic" - ] - ] - ] + ["in", "PEDESTRIAN", ["string", ["get", "noThruTraffic"]]], + ["in", "ALL", ["string", ["get", "noThruTraffic"]]] ], - "layout" : { - "line-cap" : "butt", - "visibility" : "none" + "layout": { + "line-cap": "butt", + "visibility": "none" }, - "metadata" : { - "group" : "No-thru traffic" + "metadata": { + "group": "No-thru traffic" } }, { - "id" : "no-thru-traffic BICYCLE", - "source" : "vectorSource", - "source-layer" : "edges", - "type" : "line", - "minzoom" : 13, - "maxzoom" : 23, - "paint" : { - "line-color" : [ + "id": "no-thru-traffic BICYCLE", + "source": "vectorSource", + "source-layer": "edges", + "type": "line", + "minzoom": 13, + "maxzoom": 23, + "paint": { + "line-color": [ "match", - [ - "get", - "noThruTraffic" - ], + ["get", "noThruTraffic"], "NONE", "#140d0e", "PEDESTRIAN", @@ -271,80 +165,33 @@ "#adb2b0", "#140d0e" ], - "line-width" : [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 13, - 0.2, - 23, - 8.0 - ], - "line-offset" : [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 13, - 0.4, - 23, - 7.0 - ] + "line-width": ["interpolate", ["linear"], ["zoom"], 13, 0.2, 23, 8.0], + "line-offset": ["interpolate", ["linear"], ["zoom"], 13, 0.4, 23, 7.0] }, - "filter" : [ + "filter": [ "any", - [ - "in", - "BICYCLE", - [ - "string", - [ - "get", - "noThruTraffic" - ] - ] - ], - [ - "in", - "ALL", - [ - "string", - [ - "get", - "noThruTraffic" - ] - ] - ] + ["in", "BICYCLE", ["string", ["get", "noThruTraffic"]]], + ["in", "ALL", ["string", ["get", "noThruTraffic"]]] ], - "layout" : { - "line-cap" : "butt", - "visibility" : "none" + "layout": { + "line-cap": "butt", + "visibility": "none" }, - "metadata" : { - "group" : "No-thru traffic" + "metadata": { + "group": "No-thru traffic" } }, { - "id" : "no-thru-traffic CAR", - "source" : "vectorSource", - "source-layer" : "edges", - "type" : "line", - "minzoom" : 13, - "maxzoom" : 23, - "paint" : { - "line-color" : [ + "id": "no-thru-traffic CAR", + "source": "vectorSource", + "source-layer": "edges", + "type": "line", + "minzoom": 13, + "maxzoom": 23, + "paint": { + "line-color": [ "match", - [ - "get", - "noThruTraffic" - ], + ["get", "noThruTraffic"], "NONE", "#140d0e", "PEDESTRIAN", @@ -363,80 +210,36 @@ "#adb2b0", "#140d0e" ], - "line-width" : [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 13, - 0.2, - 23, - 8.0 - ], - "line-offset" : [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 13, - 0.4, - 23, - 7.0 - ] + "line-width": ["interpolate", ["linear"], ["zoom"], 13, 0.2, 23, 8.0], + "line-offset": ["interpolate", ["linear"], ["zoom"], 13, 0.4, 23, 7.0] }, - "filter" : [ + "filter": [ "any", - [ - "in", - "CAR", - [ - "string", - [ - "get", - "noThruTraffic" - ] - ] - ], - [ - "in", - "ALL", - [ - "string", - [ - "get", - "noThruTraffic" - ] - ] - ] + ["in", "CAR", ["string", ["get", "noThruTraffic"]]], + ["in", "ALL", ["string", ["get", "noThruTraffic"]]] ], - "layout" : { - "line-cap" : "butt", - "visibility" : "none" + "layout": { + "line-cap": "butt", + "visibility": "none" }, - "metadata" : { - "group" : "No-thru traffic" + "metadata": { + "group": "No-thru traffic" } }, { - "id" : "no-thru-traffic-text", - "source" : "vectorSource", - "source-layer" : "edges", - "type" : "symbol", - "minzoom" : 17, - "maxzoom" : 23, - "paint" : { - "text-color" : "#000", - "text-halo-color" : "#fff", - "text-halo-blur" : 4, - "text-halo-width" : 3 - }, - "filter" : [ + "id": "no-thru-traffic-text", + "source": "vectorSource", + "source-layer": "edges", + "type": "symbol", + "minzoom": 17, + "maxzoom": 23, + "paint": { + "text-color": "#000", + "text-halo-color": "#fff", + "text-halo-blur": 4, + "text-halo-width": 3 + }, + "filter": [ "in", "class", "StreetEdge", @@ -447,54 +250,34 @@ "TemporaryPartialStreetEdge", "TemporaryFreeEdge" ], - "layout" : { - "symbol-placement" : "line-center", - "symbol-spacing" : 1000, - "text-field" : "{noThruTraffic}", - "text-font" : [ - "KlokanTech Noto Sans Regular" - ], - "text-size" : [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 10, - 6.0, - 24, - 12.0 - ], - "text-max-width" : 100, - "text-keep-upright" : true, - "text-rotation-alignment" : "map", - "text-overlap" : "never", - "text-offset" : [ - 0, - 1.0 - ], - "visibility" : "none" - }, - "metadata" : { - "group" : "No-thru traffic" + "layout": { + "symbol-placement": "line-center", + "symbol-spacing": 1000, + "text-field": "{noThruTraffic}", + "text-font": ["KlokanTech Noto Sans Regular"], + "text-size": ["interpolate", ["linear"], ["zoom"], 10, 6.0, 24, 12.0], + "text-max-width": 100, + "text-keep-upright": true, + "text-rotation-alignment": "map", + "text-overlap": "never", + "text-offset": [0, 1.0], + "visibility": "none" + }, + "metadata": { + "group": "No-thru traffic" } }, { - "id" : "permission PEDESTRIAN", - "source" : "vectorSource", - "source-layer" : "edges", - "type" : "line", - "minzoom" : 13, - "maxzoom" : 23, - "paint" : { - "line-color" : [ + "id": "permission PEDESTRIAN", + "source": "vectorSource", + "source-layer": "edges", + "type": "line", + "minzoom": 13, + "maxzoom": 23, + "paint": { + "line-color": [ "match", - [ - "get", - "permission" - ], + ["get", "permission"], "NONE", "#140d0e", "PEDESTRIAN", @@ -513,80 +296,33 @@ "#adb2b0", "#140d0e" ], - "line-width" : [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 13, - 0.2, - 23, - 8.0 - ], - "line-offset" : [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 13, - 0.4, - 23, - 7.0 - ] + "line-width": ["interpolate", ["linear"], ["zoom"], 13, 0.2, 23, 8.0], + "line-offset": ["interpolate", ["linear"], ["zoom"], 13, 0.4, 23, 7.0] }, - "filter" : [ + "filter": [ "any", - [ - "in", - "PEDESTRIAN", - [ - "string", - [ - "get", - "permission" - ] - ] - ], - [ - "in", - "ALL", - [ - "string", - [ - "get", - "permission" - ] - ] - ] + ["in", "PEDESTRIAN", ["string", ["get", "permission"]]], + ["in", "ALL", ["string", ["get", "permission"]]] ], - "layout" : { - "line-cap" : "butt", - "visibility" : "none" + "layout": { + "line-cap": "butt", + "visibility": "none" }, - "metadata" : { - "group" : "Permissions" + "metadata": { + "group": "Permissions" } }, { - "id" : "permission BICYCLE", - "source" : "vectorSource", - "source-layer" : "edges", - "type" : "line", - "minzoom" : 13, - "maxzoom" : 23, - "paint" : { - "line-color" : [ + "id": "permission BICYCLE", + "source": "vectorSource", + "source-layer": "edges", + "type": "line", + "minzoom": 13, + "maxzoom": 23, + "paint": { + "line-color": [ "match", - [ - "get", - "permission" - ], + ["get", "permission"], "NONE", "#140d0e", "PEDESTRIAN", @@ -605,80 +341,33 @@ "#adb2b0", "#140d0e" ], - "line-width" : [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 13, - 0.2, - 23, - 8.0 - ], - "line-offset" : [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 13, - 0.4, - 23, - 7.0 - ] + "line-width": ["interpolate", ["linear"], ["zoom"], 13, 0.2, 23, 8.0], + "line-offset": ["interpolate", ["linear"], ["zoom"], 13, 0.4, 23, 7.0] }, - "filter" : [ + "filter": [ "any", - [ - "in", - "BICYCLE", - [ - "string", - [ - "get", - "permission" - ] - ] - ], - [ - "in", - "ALL", - [ - "string", - [ - "get", - "permission" - ] - ] - ] + ["in", "BICYCLE", ["string", ["get", "permission"]]], + ["in", "ALL", ["string", ["get", "permission"]]] ], - "layout" : { - "line-cap" : "butt", - "visibility" : "none" + "layout": { + "line-cap": "butt", + "visibility": "none" }, - "metadata" : { - "group" : "Permissions" + "metadata": { + "group": "Permissions" } }, { - "id" : "permission CAR", - "source" : "vectorSource", - "source-layer" : "edges", - "type" : "line", - "minzoom" : 13, - "maxzoom" : 23, - "paint" : { - "line-color" : [ + "id": "permission CAR", + "source": "vectorSource", + "source-layer": "edges", + "type": "line", + "minzoom": 13, + "maxzoom": 23, + "paint": { + "line-color": [ "match", - [ - "get", - "permission" - ], + ["get", "permission"], "NONE", "#140d0e", "PEDESTRIAN", @@ -697,80 +386,36 @@ "#adb2b0", "#140d0e" ], - "line-width" : [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 13, - 0.2, - 23, - 8.0 - ], - "line-offset" : [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 13, - 0.4, - 23, - 7.0 - ] + "line-width": ["interpolate", ["linear"], ["zoom"], 13, 0.2, 23, 8.0], + "line-offset": ["interpolate", ["linear"], ["zoom"], 13, 0.4, 23, 7.0] }, - "filter" : [ + "filter": [ "any", - [ - "in", - "CAR", - [ - "string", - [ - "get", - "permission" - ] - ] - ], - [ - "in", - "ALL", - [ - "string", - [ - "get", - "permission" - ] - ] - ] + ["in", "CAR", ["string", ["get", "permission"]]], + ["in", "ALL", ["string", ["get", "permission"]]] ], - "layout" : { - "line-cap" : "butt", - "visibility" : "none" + "layout": { + "line-cap": "butt", + "visibility": "none" }, - "metadata" : { - "group" : "Permissions" + "metadata": { + "group": "Permissions" } }, { - "id" : "permission-text", - "source" : "vectorSource", - "source-layer" : "edges", - "type" : "symbol", - "minzoom" : 17, - "maxzoom" : 23, - "paint" : { - "text-color" : "#000", - "text-halo-color" : "#fff", - "text-halo-blur" : 4, - "text-halo-width" : 3 - }, - "filter" : [ + "id": "permission-text", + "source": "vectorSource", + "source-layer": "edges", + "type": "symbol", + "minzoom": 17, + "maxzoom": 23, + "paint": { + "text-color": "#000", + "text-halo-color": "#fff", + "text-halo-blur": 4, + "text-halo-width": 3 + }, + "filter": [ "in", "class", "StreetEdge", @@ -781,77 +426,36 @@ "TemporaryPartialStreetEdge", "TemporaryFreeEdge" ], - "layout" : { - "symbol-placement" : "line-center", - "symbol-spacing" : 1000, - "text-field" : "{permission}", - "text-font" : [ - "KlokanTech Noto Sans Regular" - ], - "text-size" : [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 10, - 6.0, - 24, - 12.0 - ], - "text-max-width" : 100, - "text-keep-upright" : true, - "text-rotation-alignment" : "map", - "text-overlap" : "never", - "text-offset" : [ - 0, - 1.0 - ], - "visibility" : "none" - }, - "metadata" : { - "group" : "Permissions" + "layout": { + "symbol-placement": "line-center", + "symbol-spacing": 1000, + "text-field": "{permission}", + "text-font": ["KlokanTech Noto Sans Regular"], + "text-size": ["interpolate", ["linear"], ["zoom"], 10, 6.0, 24, 12.0], + "text-max-width": 100, + "text-keep-upright": true, + "text-rotation-alignment": "map", + "text-overlap": "never", + "text-offset": [0, 1.0], + "visibility": "none" + }, + "metadata": { + "group": "Permissions" } }, { - "id" : "edge", - "type" : "line", - "source" : "vectorSource", - "source-layer" : "edges", - "minzoom" : 6, - "maxzoom" : 23, - "paint" : { - "line-color" : "#f21d52", - "line-width" : [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 13, - 0.1, - 23, - 6.0 - ], - "line-offset" : [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 13, - 0.4, - 23, - 7.0 - ] - }, - "filter" : [ + "id": "edge", + "type": "line", + "source": "vectorSource", + "source-layer": "edges", + "minzoom": 6, + "maxzoom": 23, + "paint": { + "line-color": "#f21d52", + "line-width": ["interpolate", ["linear"], ["zoom"], 13, 0.1, 23, 6.0], + "line-offset": ["interpolate", ["linear"], ["zoom"], 13, 0.4, 23, 7.0] + }, + "filter": [ "in", "class", "StreetEdge", @@ -862,28 +466,28 @@ "TemporaryPartialStreetEdge", "TemporaryFreeEdge" ], - "layout" : { - "line-cap" : "round", - "visibility" : "none" + "layout": { + "line-cap": "round", + "visibility": "none" }, - "metadata" : { - "group" : "Edges" + "metadata": { + "group": "Edges" } }, { - "id" : "edge-name", - "type" : "symbol", - "source" : "vectorSource", - "source-layer" : "edges", - "minzoom" : 17, - "maxzoom" : 23, - "paint" : { - "text-color" : "#000", - "text-halo-color" : "#fff", - "text-halo-blur" : 4, - "text-halo-width" : 3 - }, - "filter" : [ + "id": "edge-name", + "type": "symbol", + "source": "vectorSource", + "source-layer": "edges", + "minzoom": 17, + "maxzoom": 23, + "paint": { + "text-color": "#000", + "text-halo-color": "#fff", + "text-halo-blur": 4, + "text-halo-width": 3 + }, + "filter": [ "in", "class", "StreetEdge", @@ -894,73 +498,35 @@ "TemporaryPartialStreetEdge", "TemporaryFreeEdge" ], - "layout" : { - "symbol-placement" : "line-center", - "symbol-spacing" : 1000, - "text-field" : "{name}", - "text-font" : [ - "KlokanTech Noto Sans Regular" - ], - "text-size" : [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 10, - 6.0, - 24, - 12.0 - ], - "text-max-width" : 100, - "text-keep-upright" : true, - "text-rotation-alignment" : "map", - "text-overlap" : "never", - "visibility" : "none" - }, - "metadata" : { - "group" : "Edges" + "layout": { + "symbol-placement": "line-center", + "symbol-spacing": 1000, + "text-field": "{name}", + "text-font": ["KlokanTech Noto Sans Regular"], + "text-size": ["interpolate", ["linear"], ["zoom"], 10, 6.0, 24, 12.0], + "text-max-width": 100, + "text-keep-upright": true, + "text-rotation-alignment": "map", + "text-overlap": "never", + "visibility": "none" + }, + "metadata": { + "group": "Edges" } }, { - "id" : "link", - "type" : "line", - "source" : "vectorSource", - "source-layer" : "edges", - "minzoom" : 13, - "maxzoom" : 23, - "paint" : { - "line-color" : "#22DD9E", - "line-width" : [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 13, - 0.2, - 23, - 8.0 - ], - "line-offset" : [ - "interpolate", - [ - "linear" - ], - [ - "zoom" - ], - 13, - 0.4, - 23, - 7.0 - ] - }, - "filter" : [ + "id": "link", + "type": "line", + "source": "vectorSource", + "source-layer": "edges", + "minzoom": 13, + "maxzoom": 23, + "paint": { + "line-color": "#22DD9E", + "line-width": ["interpolate", ["linear"], ["zoom"], 13, 0.2, 23, 8.0], + "line-offset": ["interpolate", ["linear"], ["zoom"], 13, 0.4, 23, 7.0] + }, + "filter": [ "in", "class", "StreetTransitStopLink", @@ -970,181 +536,153 @@ "StreetVehicleParkingLink", "StreetStationCentroidLink" ], - "layout" : { - "line-cap" : "round", - "visibility" : "none" + "layout": { + "line-cap": "round", + "visibility": "none" }, - "metadata" : { - "group" : "Edges" + "metadata": { + "group": "Edges" } }, { - "id" : "vertex", - "type" : "circle", - "source" : "vectorSource", - "source-layer" : "vertices", - "minzoom" : 15, - "maxzoom" : 23, - "paint" : { - "circle-stroke-color" : "#140d0e", - "circle-stroke-width" : [ + "id": "vertex", + "type": "circle", + "source": "vectorSource", + "source-layer": "vertices", + "minzoom": 15, + "maxzoom": 23, + "paint": { + "circle-stroke-color": "#140d0e", + "circle-stroke-width": [ "interpolate", - [ - "linear" - ], - [ - "zoom" - ], + ["linear"], + ["zoom"], 15, 0.2, 23, 3.0 ], - "circle-radius" : [ + "circle-radius": [ "interpolate", - [ - "linear" - ], - [ - "zoom" - ], + ["linear"], + ["zoom"], 15, 1.0, 23, 7.0 ], - "circle-color" : "#BC55F2" + "circle-color": "#BC55F2" }, - "layout" : { - "visibility" : "none" + "layout": { + "visibility": "none" }, - "metadata" : { - "group" : "Vertices" + "metadata": { + "group": "Vertices" } }, { - "id" : "parking-vertex", - "type" : "circle", - "source" : "vectorSource", - "source-layer" : "vertices", - "minzoom" : 13, - "maxzoom" : 23, - "paint" : { - "circle-stroke-color" : "#140d0e", - "circle-stroke-width" : [ + "id": "parking-vertex", + "type": "circle", + "source": "vectorSource", + "source-layer": "vertices", + "minzoom": 13, + "maxzoom": 23, + "paint": { + "circle-stroke-color": "#140d0e", + "circle-stroke-width": [ "interpolate", - [ - "linear" - ], - [ - "zoom" - ], + ["linear"], + ["zoom"], 15, 0.2, 23, 3.0 ], - "circle-radius" : [ + "circle-radius": [ "interpolate", - [ - "linear" - ], - [ - "zoom" - ], + ["linear"], + ["zoom"], 13, 1.4, 23, 10.0 ], - "circle-color" : "#136b04" + "circle-color": "#136b04" }, - "filter" : [ - "in", - "class", - "VehicleParkingEntranceVertex" - ], - "layout" : { - "visibility" : "none" + "filter": ["in", "class", "VehicleParkingEntranceVertex"], + "layout": { + "visibility": "none" }, - "metadata" : { - "group" : "Vertices" + "metadata": { + "group": "Vertices" } }, { - "id" : "area-stop", - "type" : "fill", - "source" : "vectorSource", - "source-layer" : "stops", - "minzoom" : 6, - "maxzoom" : 23, - "paint" : { - "fill-color" : "#22DD9E", - "fill-opacity" : 0.5, - "fill-outline-color" : "#140d0e" - }, - "metadata" : { - "group" : "Stops" + "id": "area-stop", + "type": "fill", + "source": "vectorSource", + "source-layer": "stops", + "minzoom": 6, + "maxzoom": 23, + "paint": { + "fill-color": "#22DD9E", + "fill-opacity": 0.5, + "fill-outline-color": "#140d0e" + }, + "metadata": { + "group": "Stops" } }, { - "id" : "group-stop", - "type" : "fill", - "source" : "vectorSource", - "source-layer" : "stops", - "minzoom" : 6, - "maxzoom" : 23, - "paint" : { - "fill-color" : "#22DD9E", - "fill-opacity" : 0.5, - "fill-outline-color" : "#140d0e" - }, - "metadata" : { - "group" : "Stops" + "id": "group-stop", + "type": "fill", + "source": "vectorSource", + "source-layer": "stops", + "minzoom": 6, + "maxzoom": 23, + "paint": { + "fill-color": "#22DD9E", + "fill-opacity": 0.5, + "fill-outline-color": "#140d0e" + }, + "metadata": { + "group": "Stops" } }, { - "id" : "regular-stop", - "type" : "circle", - "source" : "vectorSource", - "source-layer" : "stops", - "minzoom" : 10, - "maxzoom" : 23, - "paint" : { - "circle-stroke-color" : "#140d0e", - "circle-stroke-width" : [ + "id": "regular-stop", + "type": "circle", + "source": "vectorSource", + "source-layer": "stops", + "minzoom": 10, + "maxzoom": 23, + "paint": { + "circle-stroke-color": "#140d0e", + "circle-stroke-width": [ "interpolate", - [ - "linear" - ], - [ - "zoom" - ], + ["linear"], + ["zoom"], 11, 0.5, 23, 5.0 ], - "circle-radius" : [ + "circle-radius": [ "interpolate", - [ - "linear" - ], - [ - "zoom" - ], + ["linear"], + ["zoom"], 11, 0.5, 23, 10.0 ], - "circle-color" : "#fcf9fa" + "circle-color": "#fcf9fa" }, - "metadata" : { - "group" : "Stops" + "metadata": { + "group": "Stops" } } ], - "version" : 8, - "glyphs" : "https://cdn.jsdelivr.net/gh/klokantech/klokantech-gl-fonts@master/{fontstack}/{range}.pbf" -} \ No newline at end of file + "version": 8, + "glyphs": "https://cdn.jsdelivr.net/gh/klokantech/klokantech-gl-fonts@master/{fontstack}/{range}.pbf" +} diff --git a/client/src/components/MapView/LayerControl.tsx b/client/src/components/MapView/LayerControl.tsx index d5f9dbb6424..e3e87fba7bd 100644 --- a/client/src/components/MapView/LayerControl.tsx +++ b/client/src/components/MapView/LayerControl.tsx @@ -55,14 +55,17 @@ class LayerControl implements IControl { rasterLayers.forEach((layer) => { if (layer) { const option = document.createElement('option'); - option.textContent = layer.id; + const meta = layer.metadata as { name: string }; + option.textContent = meta.name; option.id = layer.id; + option.value = layer.id; select.appendChild(option); } }); - select.onchange = (ev) => { + select.onchange = () => { const layerId = select.value; + console.log(select.value); const layer = map.getLayer(layerId); if (layer) { rasterLayers.forEach((l) => { diff --git a/utils/src/main/java/org/opentripplanner/utils/lang/StringUtils.java b/utils/src/main/java/org/opentripplanner/utils/lang/StringUtils.java index 72eb2638c13..c1a2219da72 100644 --- a/utils/src/main/java/org/opentripplanner/utils/lang/StringUtils.java +++ b/utils/src/main/java/org/opentripplanner/utils/lang/StringUtils.java @@ -132,6 +132,14 @@ public static String kebabCase(String input) { return input.toLowerCase().replace('_', '-'); } + /** + * Create a URL-friendly "slug" version of the string, so "Entur Routebanken" becomes + * "entur-routebanken". + */ + public static String slugify(String input) { + return input.toLowerCase().replace('_', '-').replaceAll("\\s+", "-"); + } + /** * Detects unprintable control characters like newlines, tabs and invisible whitespace * like 'ZERO WIDTH SPACE' (U+200B) that don't have an immediate visual representation. diff --git a/utils/src/test/java/org/opentripplanner/utils/lang/StringUtilsTest.java b/utils/src/test/java/org/opentripplanner/utils/lang/StringUtilsTest.java index 7e8f0a6217b..dda9248468e 100644 --- a/utils/src/test/java/org/opentripplanner/utils/lang/StringUtilsTest.java +++ b/utils/src/test/java/org/opentripplanner/utils/lang/StringUtilsTest.java @@ -100,4 +100,10 @@ void containsInvisibleChars(String input) { void noInvisibleChars(String input) { assertFalse(StringUtils.containsInvisibleCharacters(input)); } + + @ParameterizedTest + @ValueSource(strings = { "AAA Bbb", "aAa bbb", "aaa bbb", "aaa bbb", "AAA_BBB" }) + void slugify(String input) { + assertEquals("aaa-bbb", StringUtils.slugify(input)); + } } From 21e183f70d33b6a5f812ec688232667835713cc5 Mon Sep 17 00:00:00 2001 From: Teemu Kalvas Date: Mon, 2 Dec 2024 13:49:13 +0200 Subject: [PATCH 38/80] fix showing duration for escalator edges in debug client --- .../inspector/vector/edge/EdgePropertyMapper.java | 2 +- .../main/java/org/opentripplanner/utils/time/DurationUtils.java | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/application/src/main/java/org/opentripplanner/inspector/vector/edge/EdgePropertyMapper.java b/application/src/main/java/org/opentripplanner/inspector/vector/edge/EdgePropertyMapper.java index 13956af99c4..83b677a62ce 100644 --- a/application/src/main/java/org/opentripplanner/inspector/vector/edge/EdgePropertyMapper.java +++ b/application/src/main/java/org/opentripplanner/inspector/vector/edge/EdgePropertyMapper.java @@ -24,7 +24,7 @@ protected Collection map(Edge input) { case StreetEdge e -> mapStreetEdge(e); case EscalatorEdge e -> List.of( kv("distance", e.getDistanceMeters()), - kv("duration", e.getDuration()) + kv("duration", e.getDuration().map(d -> d.toString()).orElse(null)) ); default -> List.of(); }; diff --git a/utils/src/main/java/org/opentripplanner/utils/time/DurationUtils.java b/utils/src/main/java/org/opentripplanner/utils/time/DurationUtils.java index 78a6ae16885..d73faecee03 100644 --- a/utils/src/main/java/org/opentripplanner/utils/time/DurationUtils.java +++ b/utils/src/main/java/org/opentripplanner/utils/time/DurationUtils.java @@ -11,7 +11,6 @@ import java.util.Optional; import java.util.regex.Pattern; import java.util.stream.Collectors; -import org.opentripplanner.utils.lang.StringUtils; /** * This class extend the Java {@link Duration} with utility functionality to parse and convert From 2f0692bc1341618339da98a3778f6b62783a7511 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Mon, 2 Dec 2024 14:43:45 +0100 Subject: [PATCH 39/80] Add documentation --- .../apis/vectortiles/DebugStyleSpec.java | 2 +- .../standalone/config/DebugUiConfig.java | 28 +++++--- .../doc/DebugUiConfigurationDocTest.java | 67 +++++++++++++++++++ .../standalone/config/ExampleConfigTest.java | 12 ++++ .../apis/vectortiles/style.json | 2 +- .../standalone/config/debug-ui-config.json | 9 +++ doc/templates/DebugUiConfiguration.md | 23 +++++++ doc/user/DebugUiConfiguration.md | 66 ++++++++++++++++++ mkdocs.yml | 1 + 9 files changed, 198 insertions(+), 12 deletions(-) create mode 100644 application/src/test/java/org/opentripplanner/generate/doc/DebugUiConfigurationDocTest.java create mode 100644 application/src/test/resources/standalone/config/debug-ui-config.json create mode 100644 doc/templates/DebugUiConfiguration.md create mode 100644 doc/user/DebugUiConfiguration.md diff --git a/application/src/main/java/org/opentripplanner/apis/vectortiles/DebugStyleSpec.java b/application/src/main/java/org/opentripplanner/apis/vectortiles/DebugStyleSpec.java index 0bcfba51e26..7070f8b486e 100644 --- a/application/src/main/java/org/opentripplanner/apis/vectortiles/DebugStyleSpec.java +++ b/application/src/main/java/org/opentripplanner/apis/vectortiles/DebugStyleSpec.java @@ -46,7 +46,7 @@ public class DebugStyleSpec { ); private static final TileSource POSITRON_BACKGROUND = new RasterSource( "Positron", - List.of("https://cartodb-basemaps-a.global.ssl.fastly.net/light_all/{z}/{x}/{y}.png"), + List.of("https://cartodb-basemaps-a.global.ssl.fastly.net/light_all/{z}/{x}/{y}{ratio}.png"), 19, 256, "© OpenStreetMap, © CARTO" diff --git a/application/src/main/java/org/opentripplanner/standalone/config/DebugUiConfig.java b/application/src/main/java/org/opentripplanner/standalone/config/DebugUiConfig.java index 085451024b2..165bcfe28f4 100644 --- a/application/src/main/java/org/opentripplanner/standalone/config/DebugUiConfig.java +++ b/application/src/main/java/org/opentripplanner/standalone/config/DebugUiConfig.java @@ -41,6 +41,15 @@ public DebugUiConfig(JsonNode node, String source, boolean logUnusedParams) { this.additionalBackgroundLayers = root .of("additionalBackgroundLayers") + .since(V2_7) + .summary("Additional background raster map layers.") + .description( + """ + Add additional background layers that will appear in the Debug UI as one of the choices. + + Current only raster tile layers are supported. + """ + ) .asObjects( List.of(), node -> @@ -48,24 +57,23 @@ public DebugUiConfig(JsonNode node, String source, boolean logUnusedParams) { node .of("name") .since(V2_7) - .summary( - "Used in the url to fetch tiles, and as the layer name in the vector tiles." - ) + .summary("Name to appear in the layer selector.") .asString(), node .of("templateUrl") .since(V2_7) - .summary("Maximum zoom levels the layer is active for.") + .summary( + """ + The [Maplibre-compatible template URL](https://maplibre.org/maplibre-native/ios/api/tile-url-templates.html) + for the raster layer, for example `https://examples.com/tiles/{z}/{x}/{y}.png`. + """ + ) .asString(), - node - .of("tileSize") - .since(V2_7) - .summary("Minimum zoom levels the layer is active for.") - .asInt(256), + node.of("tileSize").since(V2_7).summary("Size of the tile in pixels.").asInt(256), node .of("attribution") .since(V2_7) - .summary("Minimum zoom levels the layer is active for.") + .summary("Attribution for the map data.") .asString("© OpenTripPlanner") ) ); diff --git a/application/src/test/java/org/opentripplanner/generate/doc/DebugUiConfigurationDocTest.java b/application/src/test/java/org/opentripplanner/generate/doc/DebugUiConfigurationDocTest.java new file mode 100644 index 00000000000..a5124c0d3e0 --- /dev/null +++ b/application/src/test/java/org/opentripplanner/generate/doc/DebugUiConfigurationDocTest.java @@ -0,0 +1,67 @@ +package org.opentripplanner.generate.doc; + +import static org.opentripplanner.framework.io.FileUtils.assertFileEquals; +import static org.opentripplanner.framework.io.FileUtils.readFile; +import static org.opentripplanner.framework.io.FileUtils.writeFile; +import static org.opentripplanner.generate.doc.framework.DocsTestConstants.TEMPLATE_PATH; +import static org.opentripplanner.generate.doc.framework.DocsTestConstants.USER_DOC_PATH; +import static org.opentripplanner.generate.doc.framework.TemplateUtil.replaceJsonExample; +import static org.opentripplanner.generate.doc.framework.TemplateUtil.replaceParametersDetails; +import static org.opentripplanner.generate.doc.framework.TemplateUtil.replaceParametersTable; +import static org.opentripplanner.standalone.config.framework.json.JsonSupport.jsonNodeFromResource; +import static org.opentripplanner.utils.text.MarkdownFormatter.HEADER_3; + +import java.io.File; +import org.junit.jupiter.api.Test; +import org.opentripplanner.framework.application.OtpFileNames; +import org.opentripplanner.generate.doc.framework.GeneratesDocumentation; +import org.opentripplanner.generate.doc.framework.ParameterDetailsList; +import org.opentripplanner.generate.doc.framework.ParameterSummaryTable; +import org.opentripplanner.generate.doc.framework.SkipNodes; +import org.opentripplanner.standalone.config.DebugUiConfig; +import org.opentripplanner.standalone.config.framework.json.NodeAdapter; + +@GeneratesDocumentation +public class DebugUiConfigurationDocTest { + + private static final String CONFIG_JSON = OtpFileNames.DEBUG_UI_CONFIG_FILENAME; + private static final File TEMPLATE = new File(TEMPLATE_PATH, "DebugUiConfiguration.md"); + private static final File OUT_FILE = new File(USER_DOC_PATH, "DebugUiConfiguration.md"); + + private static final String CONFIG_PATH = "standalone/config/" + CONFIG_JSON; + + /** + * NOTE! This test updates the {@code doc/user/Configuration.md} document based on the latest + * version of the code. + */ + @Test + public void updateDoc() { + NodeAdapter node = readConfig(); + + // Read and close input file (same as output file) + String doc = readFile(TEMPLATE); + String original = readFile(OUT_FILE); + + doc = replaceParametersTable(doc, getParameterSummaryTable(node)); + doc = replaceParametersDetails(doc, getParameterDetailsTable(node)); + doc = replaceJsonExample(doc, node, CONFIG_JSON); + + writeFile(OUT_FILE, doc); + + assertFileEquals(original, OUT_FILE); + } + + private NodeAdapter readConfig() { + var json = jsonNodeFromResource(CONFIG_PATH); + var conf = new DebugUiConfig(json, CONFIG_PATH, true); + return conf.asNodeAdapter(); + } + + private String getParameterSummaryTable(NodeAdapter node) { + return new ParameterSummaryTable(SkipNodes.of().build()).createTable(node).toMarkdownTable(); + } + + private String getParameterDetailsTable(NodeAdapter node) { + return ParameterDetailsList.listParametersWithDetails(node, SkipNodes.of().build(), HEADER_3); + } +} diff --git a/application/src/test/java/org/opentripplanner/standalone/config/ExampleConfigTest.java b/application/src/test/java/org/opentripplanner/standalone/config/ExampleConfigTest.java index 06b0d8ed592..934da6f923d 100644 --- a/application/src/test/java/org/opentripplanner/standalone/config/ExampleConfigTest.java +++ b/application/src/test/java/org/opentripplanner/standalone/config/ExampleConfigTest.java @@ -2,6 +2,7 @@ import static org.junit.jupiter.api.Assertions.fail; import static org.opentripplanner.framework.application.OtpFileNames.BUILD_CONFIG_FILENAME; +import static org.opentripplanner.framework.application.OtpFileNames.DEBUG_UI_CONFIG_FILENAME; import static org.opentripplanner.framework.application.OtpFileNames.OTP_CONFIG_FILENAME; import static org.opentripplanner.framework.application.OtpFileNames.ROUTER_CONFIG_FILENAME; @@ -60,6 +61,17 @@ void otpConfig(Path filename) { testConfig(filename, nodeAdapter -> new OtpConfig(nodeAdapter, true)); } + @FilePatternSource( + pattern = { + "doc/user/examples/**/" + DEBUG_UI_CONFIG_FILENAME, + "application/src/test/resources/standalone/config/" + DEBUG_UI_CONFIG_FILENAME, + } + ) + @ParameterizedTest(name = "Check validity of {0}") + void debugUiConfig(Path filename) { + testConfig(filename, nodeAdapter -> new DebugUiConfig(nodeAdapter, true)); + } + @FilePatternSource( pattern = { "application/src/test/resources/standalone/config/invalid-config.json" } ) diff --git a/application/src/test/resources/org/opentripplanner/apis/vectortiles/style.json b/application/src/test/resources/org/opentripplanner/apis/vectortiles/style.json index a1a188ca76a..66858390ab5 100644 --- a/application/src/test/resources/org/opentripplanner/apis/vectortiles/style.json +++ b/application/src/test/resources/org/opentripplanner/apis/vectortiles/style.json @@ -4,7 +4,7 @@ "positron": { "name": "Positron", "tiles": [ - "https://cartodb-basemaps-a.global.ssl.fastly.net/light_all/{z}/{x}/{y}.png" + "https://cartodb-basemaps-a.global.ssl.fastly.net/light_all/{z}/{x}/{y}{ratio}.png" ], "maxzoom": 19, "tileSize": 256, diff --git a/application/src/test/resources/standalone/config/debug-ui-config.json b/application/src/test/resources/standalone/config/debug-ui-config.json new file mode 100644 index 00000000000..1ae690a4d37 --- /dev/null +++ b/application/src/test/resources/standalone/config/debug-ui-config.json @@ -0,0 +1,9 @@ +{ + "additionalBackgroundLayers": [ + { + "name": "TriMet aerial photos", + "templateUrl": "https://maps.trimet.org/wms/reflect?bbox={bbox-epsg-3857}&format=image/png&service=WMS&version=1.1.0&request=GetMap&srs=EPSG:3857&width=256&height=256&layers=aerials", + "attribution": "© TriMet" + } + ] +} diff --git a/doc/templates/DebugUiConfiguration.md b/doc/templates/DebugUiConfiguration.md new file mode 100644 index 00000000000..a54b1db8d2a --- /dev/null +++ b/doc/templates/DebugUiConfiguration.md @@ -0,0 +1,23 @@ + + +# Debug UI configuration + +The Debug UI is the standard interface that is bundled with OTP and available by visiting +[`http://localhost:8080`](http://localhost:8080). This page list the configuration options available +by placing a file `debug-ui-config.json` into OTP's working directory. + + + + +## Parameter Details + + + +## Config Example + + diff --git a/doc/user/DebugUiConfiguration.md b/doc/user/DebugUiConfiguration.md new file mode 100644 index 00000000000..5719a606d4a --- /dev/null +++ b/doc/user/DebugUiConfiguration.md @@ -0,0 +1,66 @@ + + +# Debug UI configuration + +The Debug UI is the standard interface that is bundled with OTP and available by visiting +[`http://localhost:8080`](http://localhost:8080). This page list the configuration options available +by placing a file `debug-ui-config.json` into OTP's working directory. + + + + +| Config Parameter | Type | Summary | Req./Opt. | Default Value | Since | +|-----------------------------------------------------------|:----------:|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:----------:|-----------------------|:-----:| +| [additionalBackgroundLayers](#additionalBackgroundLayers) | `object[]` | Additional background raster map layers. | *Optional* | | 2.7 | +|       attribution | `string` | Attribution for the map data. | *Optional* | `"© OpenTripPlanner"` | 2.7 | +|       name | `string` | Name to appear in the layer selector. | *Required* | | 2.7 | +|       templateUrl | `string` | The [Maplibre-compatible template URL](https://maplibre.org/maplibre-native/ios/api/tile-url-templates.html) for the raster layer, for example `https://examples.com/tiles/{z}/{x}/{y}.png`. | *Required* | | 2.7 | +|       tileSize | `integer` | Size of the tile in pixels. | *Optional* | `256` | 2.7 | + + + + +## Parameter Details + + + + +

additionalBackgroundLayers

+ +**Since version:** `2.7` ∙ **Type:** `object[]` ∙ **Cardinality:** `Optional` +**Path:** / + +Additional background raster map layers. + +Add additional background layers that will appear in the Debug UI as one of the choices. + +Current only raster tile layers are supported. + + + + + +## Config Example + + + + +```JSON +// debug-ui-config.json +{ + "additionalBackgroundLayers" : [ + { + "name" : "TriMet aerial photos", + "templateUrl" : "https://maps.trimet.org/wms/reflect?bbox={bbox-epsg-3857}&format=image/png&service=WMS&version=1.1.0&request=GetMap&srs=EPSG:3857&width=256&height=256&layers=aerials", + "attribution" : "© TriMet" + } + ] +} +``` + + diff --git a/mkdocs.yml b/mkdocs.yml index b40f77ff3c0..51245f6c3b8 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -82,6 +82,7 @@ nav: - Router: 'RouterConfiguration.md' - "Route Request": 'RouteRequest.md' - "Realtime Updaters": 'UpdaterConfig.md' + - "Debug UI": 'DebugUiConfiguration.md' - "Migrating between versions/builds": 'Migrating-Configuration.md' - Features explained: - "Routing modes": 'RoutingModes.md' From 57c65936bf55a8a99690bff9a145220d84419896 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Mon, 2 Dec 2024 14:48:21 +0100 Subject: [PATCH 40/80] Update config scope docs --- doc/templates/Configuration.md | 7 ++++--- doc/user/Configuration.md | 7 ++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/doc/templates/Configuration.md b/doc/templates/Configuration.md index 45b2c36c67b..39843b57077 100644 --- a/doc/templates/Configuration.md +++ b/doc/templates/Configuration.md @@ -41,9 +41,9 @@ default behavior of scanning the base directory for input files. Scanning is ove independently for each file type, and can point to remote cloud storage with arbitrary URIs. See [the storage section](Configuration.md#Storage) for further details. -## Three Scopes of Configuration +## Four scopes of configuration -OTP is configured via three configuration JSON files which are read from the directory specified on +OTP is configured via four configuration JSON files which are read from the directory specified on its command line. We try to provide sensible defaults for every option, so all three of these files are optional, as are all the options within each file. Each configuration file corresponds to options that are relevant at a particular phase of OTP usage. @@ -51,7 +51,8 @@ options that are relevant at a particular phase of OTP usage. Options and parameters that are taken into account during the graph building process will be "baked into" the graph, and cannot be changed later in a running server. These are specified in `build-config.json`. Other details of OTP operation can be modified without rebuilding the graph. -These run-time configuration options are found in `router-config.json`. Finally, `otp-config.json` +These run-time configuration options are found in `router-config.json`. If you want to configure +the built-in debug UI add `debug-ui-config.json`. Finally, `otp-config.json` contains simple switches that enable or disable system-wide features. ## Configuration types diff --git a/doc/user/Configuration.md b/doc/user/Configuration.md index f80966b8cb3..21a8fcc61eb 100644 --- a/doc/user/Configuration.md +++ b/doc/user/Configuration.md @@ -41,9 +41,9 @@ default behavior of scanning the base directory for input files. Scanning is ove independently for each file type, and can point to remote cloud storage with arbitrary URIs. See [the storage section](Configuration.md#Storage) for further details. -## Three Scopes of Configuration +## Four scopes of configuration -OTP is configured via three configuration JSON files which are read from the directory specified on +OTP is configured via four configuration JSON files which are read from the directory specified on its command line. We try to provide sensible defaults for every option, so all three of these files are optional, as are all the options within each file. Each configuration file corresponds to options that are relevant at a particular phase of OTP usage. @@ -51,7 +51,8 @@ options that are relevant at a particular phase of OTP usage. Options and parameters that are taken into account during the graph building process will be "baked into" the graph, and cannot be changed later in a running server. These are specified in `build-config.json`. Other details of OTP operation can be modified without rebuilding the graph. -These run-time configuration options are found in `router-config.json`. Finally, `otp-config.json` +These run-time configuration options are found in `router-config.json`. If you want to configure +the built-in debug UI add `debug-ui-config.json`. Finally, `otp-config.json` contains simple switches that enable or disable system-wide features. ## Configuration types From c6c6c3bcdaedf9bdbcc0b12aa807e375d9a35e4a Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Mon, 2 Dec 2024 15:09:13 +0100 Subject: [PATCH 41/80] Fix TS linting --- client/src/components/MapView/LayerControl.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/components/MapView/LayerControl.tsx b/client/src/components/MapView/LayerControl.tsx index e3e87fba7bd..a41e7f133a4 100644 --- a/client/src/components/MapView/LayerControl.tsx +++ b/client/src/components/MapView/LayerControl.tsx @@ -46,7 +46,7 @@ class LayerControl implements IControl { const select = document.createElement('select'); this.container.appendChild(select); - let rasterLayers = map + const rasterLayers = map .getLayersOrder() .map((l) => map.getLayer(l)) .filter((layer) => !!layer) From ff8c23155d7adde12585837f6026054e5fbe2a04 Mon Sep 17 00:00:00 2001 From: Zsombor Welker Date: Tue, 3 Dec 2024 06:40:31 +0100 Subject: [PATCH 42/80] Remove CAR_PICKUP snapshot transfer test --- .../mapping/CarPickupSnapshotTest.java | 71 - .../__snapshots__/CarPickupSnapshotTest.snap | 3438 ----------------- 2 files changed, 3509 deletions(-) delete mode 100644 application/src/test/java/org/opentripplanner/routing/algorithm/mapping/CarPickupSnapshotTest.java delete mode 100644 application/src/test/java/org/opentripplanner/routing/algorithm/mapping/__snapshots__/CarPickupSnapshotTest.snap diff --git a/application/src/test/java/org/opentripplanner/routing/algorithm/mapping/CarPickupSnapshotTest.java b/application/src/test/java/org/opentripplanner/routing/algorithm/mapping/CarPickupSnapshotTest.java deleted file mode 100644 index c233d0c6bbc..00000000000 --- a/application/src/test/java/org/opentripplanner/routing/algorithm/mapping/CarPickupSnapshotTest.java +++ /dev/null @@ -1,71 +0,0 @@ -package org.opentripplanner.routing.algorithm.mapping; - -import au.com.origin.snapshots.junit5.SnapshotExtension; -import java.util.List; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.opentripplanner.model.GenericLocation; -import org.opentripplanner.model.modes.ExcludeAllTransitFilter; -import org.opentripplanner.routing.api.request.RouteRequest; -import org.opentripplanner.routing.api.request.StreetMode; -import org.opentripplanner.routing.api.request.request.filter.AllowAllTransitFilter; - -@ExtendWith(SnapshotExtension.class) -public class CarPickupSnapshotTest extends SnapshotTestBase { - - static GenericLocation p0 = new GenericLocation( - "SE Stark St. & SE 17th Ave. (P0)", - null, - 45.519320, - -122.648567 - ); - - static GenericLocation p1 = new GenericLocation( - "SE Morrison St. & SE 17th Ave. (P1)", - null, - 45.51726, - -122.64847 - ); - - static GenericLocation p2 = new GenericLocation( - "NW Northrup St. & NW 22nd Ave. (P2)", - null, - 45.53122, - -122.69659 - ); - - @BeforeAll - public static void beforeClass() { - loadGraphBeforeClass(false); - } - - @Test - public void test_trip_planning_with_car_pickup_only() { - RouteRequest request = createTestRequest(2009, 11, 17, 10, 0, 0); - - request.journey().direct().setMode(StreetMode.CAR_PICKUP); - request.journey().transit().setFilters(List.of(ExcludeAllTransitFilter.of())); - - request.setFrom(p0); - request.setTo(p2); - - expectRequestResponseToMatchSnapshot(request); - } - - @Test - public void test_trip_planning_with_car_pickup_transfer() { - RouteRequest request = createTestRequest(2009, 11, 17, 10, 0, 0); - - request.journey().access().setMode(StreetMode.WALK); - request.journey().egress().setMode(StreetMode.WALK); - request.journey().direct().setMode(StreetMode.WALK); - request.journey().transfer().setMode(StreetMode.CAR_PICKUP); - request.journey().transit().setFilters(List.of(AllowAllTransitFilter.of())); - - request.setFrom(p0); - request.setTo(p2); - - expectRequestResponseToMatchSnapshot(request); - } -} diff --git a/application/src/test/java/org/opentripplanner/routing/algorithm/mapping/__snapshots__/CarPickupSnapshotTest.snap b/application/src/test/java/org/opentripplanner/routing/algorithm/mapping/__snapshots__/CarPickupSnapshotTest.snap deleted file mode 100644 index a3a515f82b4..00000000000 --- a/application/src/test/java/org/opentripplanner/routing/algorithm/mapping/__snapshots__/CarPickupSnapshotTest.snap +++ /dev/null @@ -1,3438 +0,0 @@ -org.opentripplanner.routing.algorithm.mapping.CarPickupSnapshotTest.test_trip_planning_with_car_pickup_only=[ - [ - { - "arrivedAtDestinationWithRentedBicycle" : false, - "duration" : 634, - "elevationGained" : 0.0, - "elevationLost" : 0.0, - "endTime" : "2009-11-17T18:10:34.000+00:00", - "fare" : { - "details" : { }, - "fare" : { } - }, - "generalizedCost" : 1005, - "legs" : [ - { - "agencyTimeZoneOffset" : -28800000, - "arrivalDelay" : 0, - "departureDelay" : 0, - "distance" : 5050.5, - "endTime" : "2009-11-17T18:10:34.000+00:00", - "from" : { - "departure" : "2009-11-17T18:00:00.000+00:00", - "lat" : 45.51932, - "lon" : -122.648567, - "name" : "SE Stark St. & SE 17th Ave. (P0)", - "vertexType" : "NORMAL" - }, - "generalizedCost" : 1005, - "interlineWithPreviousLeg" : false, - "legGeometry" : { - "length" : 200, - "points" : "unytGpxqkVA??dACpB@P?f@?p@?j@?dAAhE?jE?vD?PK?aC?{BAS?mC??hE?nEAfE?hE?hEAnC?^?Z?pB?J?~@?J}B?O?OAo@?A?w@?U?S?iB?O??Z?xC?XAJ?P?R@H@FBFBFBDDDBBDBF@F?d@@H@D@FBFD@BBDBF@H@L?L?b@@RBTGpJCjEA|CArAAxAAxAAdBEzHClF?@Ax@GTAjBAZQ?qBBuA@Y@[@aCDM@K?aCBCV@pCDZ@|D@N@vD?L?F?JBbD?D?N?BK?uBBM?K?uBBI@K?aBBSAM@M@K?GBEDEHIJUX_@f@KNQRSVGFCBQPIHGDGBIBK@W@a@?mA@E?C@C@A?CBQTKJEHIJeC~CYZo@v@g@d@IJAFAD?L@vC@hB@p@?X?T@P?N@P@nA?j@AX?L@`B@dA?R?RBbD?T?NBbD?R?P@|D@jB?x@@J?N?B?P?LBjD@N@fD?T?LBdD?R?PF`K?RDlJ?R?PFlJ?J" - }, - "mode" : "CAR", - "pathway" : false, - "realTime" : false, - "rentedBike" : false, - "route" : "", - "startTime" : "2009-11-17T18:00:00.000+00:00", - "steps" : [ - { - "absoluteDirection" : "NORTH", - "area" : false, - "bogusName" : false, - "distance" : 0.69, - "elevation" : "", - "lat" : 45.51932, - "lon" : -122.6485648, - "relativeDirection" : "DEPART", - "stayOn" : false, - "streetName" : "Southeast 17th Avenue", - "walkingBike" : false - }, - { - "absoluteDirection" : "WEST", - "area" : false, - "bogusName" : false, - "distance" : 395.42, - "elevation" : "", - "lat" : 45.5193262, - "lon" : -122.6485648, - "relativeDirection" : "LEFT", - "stayOn" : false, - "streetName" : "Southeast Stark Street", - "walkingBike" : false - }, - { - "absoluteDirection" : "NORTH", - "area" : false, - "bogusName" : false, - "distance" : 238.05, - "elevation" : "", - "lat" : 45.5193421, - "lon" : -122.6536397, - "relativeDirection" : "RIGHT", - "stayOn" : false, - "streetName" : "Southeast 12th Avenue", - "walkingBike" : false - }, - { - "absoluteDirection" : "WEST", - "area" : false, - "bogusName" : false, - "distance" : 553.35, - "elevation" : "", - "lat" : 45.5214829, - "lon" : -122.6536226, - "relativeDirection" : "LEFT", - "stayOn" : false, - "streetName" : "Southeast Ash Street", - "walkingBike" : false - }, - { - "absoluteDirection" : "NORTH", - "area" : false, - "bogusName" : false, - "distance" : 158.48, - "elevation" : "", - "lat" : 45.5215062, - "lon" : -122.6607251, - "relativeDirection" : "RIGHT", - "stayOn" : false, - "streetName" : "Southeast Grand Avenue", - "walkingBike" : false - }, - { - "absoluteDirection" : "NORTH", - "area" : false, - "bogusName" : false, - "distance" : 78.88, - "elevation" : "", - "lat" : 45.5229315, - "lon" : -122.6607174, - "relativeDirection" : "CONTINUE", - "stayOn" : false, - "streetName" : "Northeast Grand Avenue", - "walkingBike" : false - }, - { - "absoluteDirection" : "WEST", - "area" : false, - "bogusName" : false, - "distance" : 168.84, - "elevation" : "", - "lat" : 45.5236409, - "lon" : -122.6607123, - "relativeDirection" : "LEFT", - "stayOn" : false, - "streetName" : "Northeast Couch Street", - "walkingBike" : false - }, - { - "absoluteDirection" : "SOUTHWEST", - "area" : false, - "bogusName" : false, - "distance" : 64.13, - "elevation" : "", - "lat" : 45.5231423, - "lon" : -122.6623136, - "relativeDirection" : "SLIGHTLY_RIGHT", - "stayOn" : true, - "streetName" : "Northeast Couch Street", - "walkingBike" : false - }, - { - "absoluteDirection" : "WEST", - "area" : false, - "bogusName" : false, - "distance" : 144.26, - "elevation" : "", - "lat" : 45.522964, - "lon" : -122.6630306, - "relativeDirection" : "CONTINUE", - "stayOn" : false, - "streetName" : "East Burnside Street", - "walkingBike" : false - }, - { - "absoluteDirection" : "WEST", - "area" : false, - "bogusName" : false, - "distance" : 407.38, - "elevation" : "", - "lat" : 45.523001, - "lon" : -122.6648816, - "relativeDirection" : "CONTINUE", - "stayOn" : false, - "streetName" : "Burnside Bridge", - "walkingBike" : false - }, - { - "absoluteDirection" : "WEST", - "area" : false, - "bogusName" : false, - "distance" : 178.19, - "elevation" : "", - "lat" : 45.5231054, - "lon" : -122.6701087, - "relativeDirection" : "CONTINUE", - "stayOn" : false, - "streetName" : "West Burnside Street", - "walkingBike" : false - }, - { - "absoluteDirection" : "NORTH", - "area" : false, - "bogusName" : false, - "distance" : 310.7, - "elevation" : "", - "lat" : 45.5231958, - "lon" : -122.6723802, - "relativeDirection" : "RIGHT", - "stayOn" : false, - "streetName" : "Northwest 2nd Avenue", - "walkingBike" : false - }, - { - "absoluteDirection" : "WEST", - "area" : false, - "bogusName" : false, - "distance" : 317.18, - "elevation" : "", - "lat" : 45.5259887, - "lon" : -122.6724927, - "relativeDirection" : "LEFT", - "stayOn" : false, - "streetName" : "Northwest Flanders Street", - "walkingBike" : false - }, - { - "absoluteDirection" : "NORTH", - "area" : false, - "bogusName" : false, - "distance" : 238.16, - "elevation" : "", - "lat" : 45.5259105, - "lon" : -122.6765581, - "relativeDirection" : "RIGHT", - "stayOn" : false, - "streetName" : "Northwest 6th Avenue", - "walkingBike" : false - }, - { - "absoluteDirection" : "NORTH", - "area" : false, - "bogusName" : false, - "distance" : 465.44, - "elevation" : "", - "lat" : 45.5280515, - "lon" : -122.6766232, - "relativeDirection" : "CONTINUE", - "stayOn" : false, - "streetName" : "Northwest Station Way", - "walkingBike" : false - }, - { - "absoluteDirection" : "WEST", - "area" : false, - "bogusName" : false, - "distance" : 1331.38, - "elevation" : "", - "lat" : 45.5315452, - "lon" : -122.679511, - "relativeDirection" : "LEFT", - "stayOn" : false, - "streetName" : "Northwest Northrup Street", - "walkingBike" : false - } - ], - "to" : { - "arrival" : "2009-11-17T18:10:34.000+00:00", - "lat" : 45.53122, - "lon" : -122.69659, - "name" : "NW Northrup St. & NW 22nd Ave. (P2)", - "vertexType" : "NORMAL" - }, - "transitLeg" : false, - "walkingBike" : false - } - ], - "startTime" : "2009-11-17T18:00:00.000+00:00", - "tooSloped" : false, - "transfers" : 0, - "transitTime" : 0, - "waitingTime" : 0, - "walkDistance" : 5050.5, - "walkLimitExceeded" : false, - "walkTime" : 634 - } - ] -] - - -org.opentripplanner.routing.algorithm.mapping.CarPickupSnapshotTest.test_trip_planning_with_car_pickup_transfer=[ - [ - { - "arrivedAtDestinationWithRentedBicycle" : false, - "duration" : 3804, - "elevationGained" : 0.0, - "elevationLost" : 0.0, - "endTime" : "2009-11-17T19:03:24.000+00:00", - "fare" : { - "details" : { }, - "fare" : { } - }, - "generalizedCost" : 7384, - "legs" : [ - { - "agencyTimeZoneOffset" : -28800000, - "arrivalDelay" : 0, - "departureDelay" : 0, - "distance" : 4875.79, - "endTime" : "2009-11-17T19:03:24.000+00:00", - "from" : { - "departure" : "2009-11-17T18:00:00.000+00:00", - "lat" : 45.51932, - "lon" : -122.648567, - "name" : "SE Stark St. & SE 17th Ave. (P0)", - "vertexType" : "NORMAL" - }, - "generalizedCost" : 7384, - "interlineWithPreviousLeg" : false, - "legGeometry" : { - "length" : 252, - "points" : "unytGpxqkVA??dACpB@P?f@?p@?j@?dAAhE?jE?vD?P?RK?GFCDCFADABADADAF?D?FADCF?B?B?@?D@DADABCBC?A?C?AA??GICAAAA?A?A?AACAC?A@ABABC@CDCBCBC@CBABABCJ?J?@?@MR?hE?fEAdB?dB?lE?`A?T?pBA|D?J?x@?r@y@??bBuA?y@AU?{@?O?}@?E?y@?_@Aa@?u@?W??J@N?hA@x@Ap@ATETGpJCjEA|CArAAxAAxAAdBEzHClF?@Ax@GTAjBAZ?R@hC@h@Q@cBBM?M?_CDsA@Y?Q@O?K?Q?mBB[?C?W@[?]@E?IDI@]DO@SBM?S@G@A?GDEJQ|@AL?L@nA?j@@L?V?d@@~@@NI?E?W@Q?Q?m@@Q@AF?DAJBzB?V?NANM@K?GBEDEHIJUX_@f@KNQRSVGFCBQPIHGDGBIBK@W@a@?mA@E?C@C@A?CBQTKJEHIJeC~CYZo@v@g@d@IJAFAD?L@vC@hB@p@?X?T@P?N@P@nA?j@AX?L@`B@dA?R?RBbD?T?NBbD?R?P@|D@jB?x@@J?N?B?P?LBjD@N@fD?T?LBdD?R?PF`K?RDlJ?R?PFlJ?J" - }, - "mode" : "WALK", - "pathway" : false, - "realTime" : false, - "rentedBike" : false, - "route" : "", - "startTime" : "2009-11-17T18:00:00.000+00:00", - "steps" : [ - { - "absoluteDirection" : "NORTH", - "area" : false, - "bogusName" : false, - "distance" : 0.69, - "elevation" : "", - "lat" : 45.51932, - "lon" : -122.6485648, - "relativeDirection" : "DEPART", - "stayOn" : false, - "streetName" : "Southeast 17th Avenue", - "walkingBike" : false - }, - { - "absoluteDirection" : "WEST", - "area" : false, - "bogusName" : false, - "distance" : 402.49, - "elevation" : "", - "lat" : 45.5193262, - "lon" : -122.6485648, - "relativeDirection" : "LEFT", - "stayOn" : false, - "streetName" : "Southeast Stark Street", - "walkingBike" : false - }, - { - "absoluteDirection" : "NORTH", - "area" : false, - "bogusName" : true, - "distance" : 131.76, - "elevation" : "", - "lat" : 45.5193421, - "lon" : -122.6537305, - "relativeDirection" : "RIGHT", - "stayOn" : false, - "streetName" : "path", - "walkingBike" : false - }, - { - "absoluteDirection" : "WEST", - "area" : false, - "bogusName" : false, - "distance" : 516.5, - "elevation" : "", - "lat" : 45.5200623, - "lon" : -122.6546522, - "relativeDirection" : "LEFT", - "stayOn" : false, - "streetName" : "Southeast Oak Street", - "walkingBike" : false - }, - { - "absoluteDirection" : "NORTH", - "area" : false, - "bogusName" : true, - "distance" : 70.84, - "elevation" : "", - "lat" : 45.5200842, - "lon" : -122.6612814, - "relativeDirection" : "RIGHT", - "stayOn" : false, - "streetName" : "parking aisle", - "walkingBike" : false - }, - { - "absoluteDirection" : "NORTH", - "area" : false, - "bogusName" : false, - "distance" : 284.75, - "elevation" : "", - "lat" : 45.5203736, - "lon" : -122.661783, - "relativeDirection" : "RIGHT", - "stayOn" : false, - "streetName" : "Southeast Martin Luther King, Junior Boulevard", - "walkingBike" : false - }, - { - "absoluteDirection" : "WEST", - "area" : false, - "bogusName" : false, - "distance" : 243.45, - "elevation" : "", - "lat" : 45.5229343, - "lon" : -122.6617665, - "relativeDirection" : "LEFT", - "stayOn" : false, - "streetName" : "East Burnside Street", - "walkingBike" : false - }, - { - "absoluteDirection" : "WEST", - "area" : false, - "bogusName" : false, - "distance" : 407.38, - "elevation" : "", - "lat" : 45.523001, - "lon" : -122.6648816, - "relativeDirection" : "CONTINUE", - "stayOn" : false, - "streetName" : "Burnside Bridge", - "walkingBike" : false - }, - { - "absoluteDirection" : "WEST", - "area" : false, - "bogusName" : false, - "distance" : 256.85, - "elevation" : "", - "lat" : 45.5231054, - "lon" : -122.6701087, - "relativeDirection" : "CONTINUE", - "stayOn" : false, - "streetName" : "West Burnside Street", - "walkingBike" : false - }, - { - "absoluteDirection" : "NORTH", - "area" : false, - "bogusName" : false, - "distance" : 460.65, - "elevation" : "", - "lat" : 45.5231776, - "lon" : -122.6733895, - "relativeDirection" : "RIGHT", - "stayOn" : false, - "streetName" : "Northwest 3rd Avenue", - "walkingBike" : false - }, - { - "absoluteDirection" : "WEST", - "area" : false, - "bogusName" : false, - "distance" : 145.82, - "elevation" : "", - "lat" : 45.5272866, - "lon" : -122.6737165, - "relativeDirection" : "SLIGHTLY_LEFT", - "stayOn" : false, - "streetName" : "Northwest Hoyt Street", - "walkingBike" : false - }, - { - "absoluteDirection" : "NORTH", - "area" : false, - "bogusName" : false, - "distance" : 77.35, - "elevation" : "", - "lat" : 45.5273496, - "lon" : -122.6755629, - "relativeDirection" : "RIGHT", - "stayOn" : false, - "streetName" : "Northwest 5th Avenue", - "walkingBike" : false - }, - { - "absoluteDirection" : "WEST", - "area" : false, - "bogusName" : false, - "distance" : 80.53, - "elevation" : "", - "lat" : 45.5280449, - "lon" : -122.6755935, - "relativeDirection" : "LEFT", - "stayOn" : false, - "streetName" : "Northwest Irving Street", - "walkingBike" : false - }, - { - "absoluteDirection" : "NORTH", - "area" : false, - "bogusName" : false, - "distance" : 465.44, - "elevation" : "", - "lat" : 45.5280515, - "lon" : -122.6766232, - "relativeDirection" : "RIGHT", - "stayOn" : false, - "streetName" : "Northwest Station Way", - "walkingBike" : false - }, - { - "absoluteDirection" : "WEST", - "area" : false, - "bogusName" : false, - "distance" : 1331.38, - "elevation" : "", - "lat" : 45.5315452, - "lon" : -122.679511, - "relativeDirection" : "LEFT", - "stayOn" : false, - "streetName" : "Northwest Northrup Street", - "walkingBike" : false - } - ], - "to" : { - "arrival" : "2009-11-17T19:03:24.000+00:00", - "lat" : 45.53122, - "lon" : -122.69659, - "name" : "NW Northrup St. & NW 22nd Ave. (P2)", - "vertexType" : "NORMAL" - }, - "transitLeg" : false, - "walkingBike" : false - } - ], - "startTime" : "2009-11-17T18:00:00.000+00:00", - "tooSloped" : false, - "transfers" : 0, - "transitTime" : 0, - "waitingTime" : 0, - "walkDistance" : 4875.79, - "walkLimitExceeded" : false, - "walkTime" : 3804 - }, - { - "arrivedAtDestinationWithRentedBicycle" : false, - "duration" : 1815, - "elevationGained" : 0.0, - "elevationLost" : 0.0, - "endTime" : "2009-11-17T18:34:19.000+00:00", - "fare" : { - "details" : { }, - "fare" : { }, - "legProducts" : [ - { - "legIndices" : [ - 1 - ], - "products" : [ - { - "amount" : { - "cents" : 200, - "currency" : { - "currency" : "USD", - "currencyCode" : "USD", - "defaultFractionDigits" : 2, - "symbol" : "$" - } - }, - "id" : "prt:8", - "name" : "regular" - } - ] - }, - { - "legIndices" : [ - 5 - ], - "products" : [ - { - "amount" : { - "cents" : 200, - "currency" : { - "currency" : "USD", - "currencyCode" : "USD", - "defaultFractionDigits" : 2, - "symbol" : "$" - } - }, - "id" : "prt:8", - "name" : "regular" - } - ] - } - ] - }, - "generalizedCost" : 3832, - "legs" : [ - { - "agencyTimeZoneOffset" : -28800000, - "arrivalDelay" : 0, - "departureDelay" : 0, - "distance" : 673.56, - "endTime" : "2009-11-17T18:12:58.000+00:00", - "from" : { - "departure" : "2009-11-17T18:04:04.000+00:00", - "lat" : 45.51932, - "lon" : -122.648567, - "name" : "SE Stark St. & SE 17th Ave. (P0)", - "vertexType" : "NORMAL" - }, - "generalizedCost" : 1031, - "interlineWithPreviousLeg" : false, - "legGeometry" : { - "length" : 42, - "points" : "unytGpxqkVA??dACpB@PoC?_CAM?aC??A?A?A?A??AA?AAA??AAA???A?A?A???A@A??@A@?@??A@?@?BcC?mCAmCAmC?QBIYIWOH" - }, - "mode" : "WALK", - "pathway" : false, - "realTime" : false, - "rentedBike" : false, - "route" : "", - "startTime" : "2009-11-17T18:04:04.000+00:00", - "steps" : [ - { - "absoluteDirection" : "NORTH", - "area" : false, - "bogusName" : false, - "distance" : 0.69, - "elevation" : "", - "lat" : 45.51932, - "lon" : -122.6485648, - "relativeDirection" : "DEPART", - "stayOn" : false, - "streetName" : "Southeast 17th Avenue", - "walkingBike" : false - }, - { - "absoluteDirection" : "WEST", - "area" : false, - "bogusName" : false, - "distance" : 79.12, - "elevation" : "", - "lat" : 45.5193262, - "lon" : -122.6485648, - "relativeDirection" : "LEFT", - "stayOn" : false, - "streetName" : "Southeast Stark Street", - "walkingBike" : false - }, - { - "absoluteDirection" : "NORTH", - "area" : false, - "bogusName" : false, - "distance" : 402.13, - "elevation" : "", - "lat" : 45.5193388, - "lon" : -122.6495798, - "relativeDirection" : "RIGHT", - "stayOn" : false, - "streetName" : "Southeast 16th Avenue", - "walkingBike" : false - }, - { - "absoluteDirection" : "NORTH", - "area" : false, - "bogusName" : false, - "distance" : 168.89, - "elevation" : "", - "lat" : 45.5228912, - "lon" : -122.6495528, - "relativeDirection" : "CONTINUE", - "stayOn" : false, - "streetName" : "Northeast 16th Avenue", - "walkingBike" : false - }, - { - "absoluteDirection" : "NORTHEAST", - "area" : false, - "bogusName" : false, - "distance" : 22.74, - "elevation" : "", - "lat" : 45.524409, - "lon" : -122.6495675, - "relativeDirection" : "RIGHT", - "stayOn" : false, - "streetName" : "Northeast Sandy Boulevard", - "walkingBike" : false - } - ], - "to" : { - "arrival" : "2009-11-17T18:12:58.000+00:00", - "departure" : "2009-11-17T18:12:58.000+00:00", - "lat" : 45.524581, - "lon" : -122.649367, - "name" : "NE Sandy & 16th", - "stopCode" : "5060", - "stopId" : "prt:5060", - "vertexType" : "TRANSIT", - "zoneId" : "1" - }, - "transitLeg" : false, - "walkingBike" : false - }, - { - "agencyId" : "prt:prt", - "agencyName" : "TriMet", - "agencyTimeZoneOffset" : -28800000, - "agencyUrl" : "http://trimet.org", - "arrivalDelay" : 0, - "departureDelay" : 0, - "distance" : 2119.06, - "endTime" : "2009-11-17T18:19:00.000+00:00", - "from" : { - "arrival" : "2009-11-17T18:12:58.000+00:00", - "departure" : "2009-11-17T18:12:58.000+00:00", - "lat" : 45.524581, - "lon" : -122.649367, - "name" : "NE Sandy & 16th", - "stopCode" : "5060", - "stopId" : "prt:5060", - "stopIndex" : 92, - "stopSequence" : 93, - "vertexType" : "TRANSIT", - "zoneId" : "1" - }, - "generalizedCost" : 962, - "headsign" : "Beaverton TC", - "interlineWithPreviousLeg" : false, - "intermediateStops" : [ - { - "arrival" : "2009-11-17T18:13:32.000+00:00", - "departure" : "2009-11-17T18:13:32.000+00:00", - "lat" : 45.523767, - "lon" : -122.651428, - "name" : "NE Sandy & 14th", - "stopCode" : "5058", - "stopId" : "prt:5058", - "stopIndex" : 93, - "stopSequence" : 94, - "vertexType" : "TRANSIT", - "zoneId" : "1" - }, - { - "arrival" : "2009-11-17T18:14:00.000+00:00", - "departure" : "2009-11-17T18:14:00.000+00:00", - "lat" : 45.523103, - "lon" : -122.653064, - "name" : "NE Sandy & 12th", - "stopCode" : "5055", - "stopId" : "prt:5055", - "stopIndex" : 94, - "stopSequence" : 95, - "vertexType" : "TRANSIT", - "zoneId" : "1" - }, - { - "arrival" : "2009-11-17T18:14:47.000+00:00", - "departure" : "2009-11-17T18:14:47.000+00:00", - "lat" : 45.523024, - "lon" : -122.656526, - "name" : "E Burnside & NE 9th", - "stopCode" : "819", - "stopId" : "prt:819", - "stopIndex" : 95, - "stopSequence" : 96, - "vertexType" : "TRANSIT", - "zoneId" : "1" - }, - { - "arrival" : "2009-11-17T18:15:24.000+00:00", - "departure" : "2009-11-17T18:15:24.000+00:00", - "lat" : 45.523012, - "lon" : -122.659365, - "name" : "E Burnside & NE 6th", - "stopCode" : "805", - "stopId" : "prt:805", - "stopIndex" : 96, - "stopSequence" : 97, - "vertexType" : "TRANSIT", - "zoneId" : "1" - }, - { - "arrival" : "2009-11-17T18:15:52.000+00:00", - "departure" : "2009-11-17T18:15:52.000+00:00", - "lat" : 45.523015, - "lon" : -122.661534, - "name" : "E Burnside & NE M L King", - "stopCode" : "705", - "stopId" : "prt:705", - "stopIndex" : 97, - "stopSequence" : 98, - "vertexType" : "TRANSIT", - "zoneId" : "1" - }, - { - "arrival" : "2009-11-17T18:18:00.000+00:00", - "departure" : "2009-11-17T18:18:00.000+00:00", - "lat" : 45.523249, - "lon" : -122.671269, - "name" : "W Burnside & Burnside Bridge", - "stopCode" : "689", - "stopId" : "prt:689", - "stopIndex" : 98, - "stopSequence" : 99, - "vertexType" : "TRANSIT", - "zoneId" : "0" - } - ], - "legGeometry" : { - "length" : 50, - "points" : "coztGd}qkVNl@r@`CZhA`A`D??Ph@l@tBb@rARh@Pd@???BPj@@jA?jEAhE?pD???VAjE?hE?dB?b@???`AAhE?dD???l@C`EAhEEhE?bAA|@?XAZ@\\AzACnGKbKAjC?bE???JEnE@fEDlE@hE@~A" - }, - "mode" : "BUS", - "pathway" : false, - "realTime" : false, - "route" : "Burnside/Stark", - "routeId" : "prt:20", - "routeLongName" : "Burnside/Stark", - "routeShortName" : "20", - "routeType" : 3, - "serviceDate" : "2009-11-17", - "startTime" : "2009-11-17T18:12:58.000+00:00", - "steps" : [ ], - "to" : { - "arrival" : "2009-11-17T18:19:00.000+00:00", - "departure" : "2009-11-17T18:19:00.000+00:00", - "lat" : 45.523169, - "lon" : -122.675893, - "name" : "W Burnside & NW 5th", - "stopCode" : "782", - "stopId" : "prt:782", - "stopIndex" : 99, - "stopSequence" : 100, - "vertexType" : "TRANSIT", - "zoneId" : "0" - }, - "transitLeg" : true, - "tripBlockId" : "2002", - "tripId" : "prt:200W1200" - }, - { - "agencyTimeZoneOffset" : -28800000, - "arrivalDelay" : 0, - "departureDelay" : 0, - "distance" : 0.0, - "endTime" : "2009-11-17T18:19:00.000+00:00", - "from" : { - "arrival" : "2009-11-17T18:19:00.000+00:00", - "departure" : "2009-11-17T18:19:00.000+00:00", - "lat" : 45.523169, - "lon" : -122.675893, - "name" : "W Burnside & NW 5th", - "stopCode" : "782", - "stopId" : "prt:782", - "vertexType" : "TRANSIT", - "zoneId" : "0" - }, - "generalizedCost" : 1, - "interlineWithPreviousLeg" : false, - "legElevation" : "", - "legGeometry" : { - "length" : 2, - "points" : "wfztGjcwkVD?" - }, - "mode" : "WALK", - "pathway" : false, - "realTime" : false, - "rentedBike" : false, - "route" : "", - "startTime" : "2009-11-17T18:19:00.000+00:00", - "steps" : [ ], - "to" : { - "arrival" : "2009-11-17T18:19:00.000+00:00", - "departure" : "2009-11-17T18:19:00.000+00:00", - "lat" : 45.5231324, - "lon" : -122.6758917, - "name" : "West Burnside Street", - "vertexType" : "NORMAL" - }, - "transitLeg" : false, - "walkingBike" : false - }, - { - "agencyTimeZoneOffset" : -28800000, - "arrivalDelay" : 0, - "departureDelay" : 0, - "distance" : 1767.93, - "endTime" : "2009-11-17T18:24:16.000+00:00", - "from" : { - "arrival" : "2009-11-17T18:19:00.000+00:00", - "departure" : "2009-11-17T18:19:00.000+00:00", - "lat" : 45.5231324, - "lon" : -122.6758917, - "name" : "West Burnside Street", - "vertexType" : "NORMAL" - }, - "generalizedCost" : 510, - "interlineWithPreviousLeg" : false, - "legGeometry" : { - "length" : 97, - "points" : "qfztGjcwkV@`B?H?BM?iBBI?K?wBBK?K?sBDM@M@sB@K?K?uBBM?K?uBBI@K?aBBSAM@M@K?GBEDEHIJUX_@f@KNQRSVGFCBQPIHGDGBIBK@W@a@?mA@E?C@C@A?CBQTKJEHIJeC~CYZo@v@g@d@IJAFAD?L@vC@hB@p@?X?T@P?N@P@nA?j@AX?L@`B@dA?R?RBbD?T?NBbD?R?P@|D@jB?x@@J?N?B?P?LBjD@N" - }, - "mode" : "CAR", - "pathway" : false, - "realTime" : false, - "rentedBike" : false, - "route" : "", - "startTime" : "2009-11-17T18:19:00.000+00:00", - "steps" : [ - { - "absoluteDirection" : "WEST", - "area" : false, - "bogusName" : false, - "distance" : 44.21, - "elevation" : "", - "lat" : 45.5231324, - "lon" : -122.6758917, - "relativeDirection" : "DEPART", - "stayOn" : false, - "streetName" : "West Burnside Street", - "walkingBike" : false - }, - { - "absoluteDirection" : "NORTH", - "area" : false, - "bogusName" : false, - "distance" : 548.38, - "elevation" : "", - "lat" : 45.5231221, - "lon" : -122.676459, - "relativeDirection" : "RIGHT", - "stayOn" : false, - "streetName" : "Northwest 6th Avenue", - "walkingBike" : false - }, - { - "absoluteDirection" : "NORTH", - "area" : false, - "bogusName" : false, - "distance" : 465.44, - "elevation" : "", - "lat" : 45.5280515, - "lon" : -122.6766232, - "relativeDirection" : "CONTINUE", - "stayOn" : false, - "streetName" : "Northwest Station Way", - "walkingBike" : false - }, - { - "absoluteDirection" : "WEST", - "area" : false, - "bogusName" : false, - "distance" : 709.95, - "elevation" : "", - "lat" : 45.5315452, - "lon" : -122.679511, - "relativeDirection" : "LEFT", - "stayOn" : false, - "streetName" : "Northwest Northrup Street", - "walkingBike" : false - } - ], - "to" : { - "arrival" : "2009-11-17T18:24:16.000+00:00", - "departure" : "2009-11-17T18:24:16.000+00:00", - "lat" : 45.5313992, - "lon" : -122.6886162, - "name" : "corner of Northwest Northrup Street and path", - "vertexType" : "NORMAL" - }, - "transitLeg" : false, - "walkingBike" : false - }, - { - "agencyTimeZoneOffset" : -28800000, - "arrivalDelay" : 0, - "departureDelay" : 0, - "distance" : 70.46, - "endTime" : "2009-11-17T18:26:18.000+00:00", - "from" : { - "arrival" : "2009-11-17T18:24:16.000+00:00", - "departure" : "2009-11-17T18:24:16.000+00:00", - "lat" : 45.5313992, - "lon" : -122.6886162, - "name" : "corner of Northwest Northrup Street and path", - "vertexType" : "NORMAL" - }, - "generalizedCost" : 233, - "interlineWithPreviousLeg" : false, - "legGeometry" : { - "length" : 7, - "points" : "ez{tGzrykVC?I?@nBBH?d@??" - }, - "mode" : "WALK", - "pathway" : false, - "realTime" : false, - "rentedBike" : false, - "route" : "", - "startTime" : "2009-11-17T18:24:16.000+00:00", - "steps" : [ - { - "absoluteDirection" : "NORTH", - "area" : false, - "bogusName" : true, - "distance" : 7.61, - "elevation" : "", - "lat" : 45.5313992, - "lon" : -122.6886162, - "relativeDirection" : "RIGHT", - "stayOn" : false, - "streetName" : "path", - "walkingBike" : false - }, - { - "absoluteDirection" : "WEST", - "area" : false, - "bogusName" : false, - "distance" : 62.85, - "elevation" : "", - "lat" : 45.5314676, - "lon" : -122.6886182, - "relativeDirection" : "LEFT", - "stayOn" : false, - "streetName" : "Northwest Northrup Street", - "walkingBike" : false - } - ], - "to" : { - "arrival" : "2009-11-17T18:26:18.000+00:00", - "departure" : "2009-11-17T18:31:26.000+00:00", - "lat" : 45.531434, - "lon" : -122.689417, - "name" : "NW Northrup & 18th", - "stopCode" : "10776", - "stopId" : "prt:10776", - "vertexType" : "TRANSIT", - "zoneId" : "1" - }, - "transitLeg" : false, - "walkingBike" : false - }, - { - "agencyId" : "prt:prt", - "agencyName" : "TriMet", - "agencyTimeZoneOffset" : -28800000, - "agencyUrl" : "http://trimet.org", - "arrivalDelay" : 0, - "departureDelay" : 0, - "distance" : 547.79, - "endTime" : "2009-11-17T18:33:55.000+00:00", - "from" : { - "arrival" : "2009-11-17T18:26:18.000+00:00", - "departure" : "2009-11-17T18:31:26.000+00:00", - "lat" : 45.531434, - "lon" : -122.689417, - "name" : "NW Northrup & 18th", - "stopCode" : "10776", - "stopId" : "prt:10776", - "stopIndex" : 20, - "stopSequence" : 21, - "vertexType" : "TRANSIT", - "zoneId" : "1" - }, - "generalizedCost" : 1057, - "headsign" : "NW 23rd Ave", - "interlineWithPreviousLeg" : false, - "intermediateStops" : [ - { - "arrival" : "2009-11-17T18:33:13.000+00:00", - "departure" : "2009-11-17T18:33:13.000+00:00", - "lat" : 45.531346, - "lon" : -122.694455, - "name" : "NW Northrup & 21st", - "stopCode" : "10777", - "stopId" : "prt:10777", - "stopIndex" : 21, - "stopSequence" : 22, - "vertexType" : "TRANSIT", - "zoneId" : "1" - } - ], - "legGeometry" : { - "length" : 8, - "points" : "cz{tGzwykV?VBhEFtKDvJ??@\\DnJ" - }, - "mode" : "TRAM", - "pathway" : false, - "realTime" : false, - "route" : "Portland Streetcar", - "routeId" : "prt:193", - "routeLongName" : "Portland Streetcar", - "routeType" : 0, - "serviceDate" : "2009-11-17", - "startTime" : "2009-11-17T18:31:26.000+00:00", - "steps" : [ ], - "to" : { - "arrival" : "2009-11-17T18:33:55.000+00:00", - "departure" : "2009-11-17T18:33:55.000+00:00", - "lat" : 45.531308, - "lon" : -122.696445, - "name" : "NW Northrup & 22nd", - "stopCode" : "10778", - "stopId" : "prt:10778", - "stopIndex" : 22, - "stopSequence" : 23, - "vertexType" : "TRANSIT", - "zoneId" : "1" - }, - "transitLeg" : true, - "tripBlockId" : "9384", - "tripId" : "prt:1930W1210" - }, - { - "agencyTimeZoneOffset" : -28800000, - "arrivalDelay" : 0, - "departureDelay" : 0, - "distance" : 18.81, - "endTime" : "2009-11-17T18:34:19.000+00:00", - "from" : { - "arrival" : "2009-11-17T18:33:55.000+00:00", - "departure" : "2009-11-17T18:33:55.000+00:00", - "lat" : 45.531308, - "lon" : -122.696445, - "name" : "NW Northrup & 22nd", - "stopCode" : "10778", - "stopId" : "prt:10778", - "vertexType" : "TRANSIT", - "zoneId" : "1" - }, - "generalizedCost" : 37, - "interlineWithPreviousLeg" : false, - "legGeometry" : { - "length" : 7, - "points" : "sy{tGxc{kV???LABF?B??J" - }, - "mode" : "WALK", - "pathway" : false, - "realTime" : false, - "rentedBike" : false, - "route" : "", - "startTime" : "2009-11-17T18:33:55.000+00:00", - "steps" : [ - { - "absoluteDirection" : "WEST", - "area" : false, - "bogusName" : false, - "distance" : 18.81, - "elevation" : "", - "lat" : 45.5313019, - "lon" : -122.6964448, - "relativeDirection" : "DEPART", - "stayOn" : false, - "streetName" : "Northwest Northrup Street", - "walkingBike" : false - } - ], - "to" : { - "arrival" : "2009-11-17T18:34:19.000+00:00", - "lat" : 45.53122, - "lon" : -122.69659, - "name" : "NW Northrup St. & NW 22nd Ave. (P2)", - "vertexType" : "NORMAL" - }, - "transitLeg" : false, - "walkingBike" : false - } - ], - "startTime" : "2009-11-17T18:04:04.000+00:00", - "tooSloped" : false, - "transfers" : 1, - "transitTime" : 511, - "waitingTime" : 308, - "walkDistance" : 2530.76, - "walkLimitExceeded" : false, - "walkTime" : 996 - }, - { - "arrivedAtDestinationWithRentedBicycle" : false, - "duration" : 1598, - "elevationGained" : 0.0, - "elevationLost" : 0.0, - "endTime" : "2009-11-17T18:35:19.000+00:00", - "fare" : { - "details" : { }, - "fare" : { }, - "legProducts" : [ - { - "legIndices" : [ - 1 - ], - "products" : [ - { - "amount" : { - "cents" : 200, - "currency" : { - "currency" : "USD", - "currencyCode" : "USD", - "defaultFractionDigits" : 2, - "symbol" : "$" - } - }, - "id" : "prt:8", - "name" : "regular" - } - ] - }, - { - "legIndices" : [ - 5 - ], - "products" : [ - { - "amount" : { - "cents" : 200, - "currency" : { - "currency" : "USD", - "currencyCode" : "USD", - "defaultFractionDigits" : 2, - "symbol" : "$" - } - }, - "id" : "prt:8", - "name" : "regular" - } - ] - } - ] - }, - "generalizedCost" : 3378, - "legs" : [ - { - "agencyTimeZoneOffset" : -28800000, - "arrivalDelay" : 0, - "departureDelay" : 0, - "distance" : 408.65, - "endTime" : "2009-11-17T18:14:00.000+00:00", - "from" : { - "departure" : "2009-11-17T18:08:41.000+00:00", - "lat" : 45.51932, - "lon" : -122.648567, - "name" : "SE Stark St. & SE 17th Ave. (P0)", - "vertexType" : "NORMAL" - }, - "generalizedCost" : 623, - "interlineWithPreviousLeg" : false, - "legGeometry" : { - "length" : 16, - "points" : "unytGpxqkVA??dACpB@P?f@?p@?j@?dAAhE?jE?vD?PJ?J@?S" - }, - "mode" : "WALK", - "pathway" : false, - "realTime" : false, - "rentedBike" : false, - "route" : "", - "startTime" : "2009-11-17T18:08:41.000+00:00", - "steps" : [ - { - "absoluteDirection" : "NORTH", - "area" : false, - "bogusName" : false, - "distance" : 0.69, - "elevation" : "", - "lat" : 45.51932, - "lon" : -122.6485648, - "relativeDirection" : "DEPART", - "stayOn" : false, - "streetName" : "Southeast 17th Avenue", - "walkingBike" : false - }, - { - "absoluteDirection" : "WEST", - "area" : false, - "bogusName" : false, - "distance" : 395.42, - "elevation" : "", - "lat" : 45.5193262, - "lon" : -122.6485648, - "relativeDirection" : "LEFT", - "stayOn" : false, - "streetName" : "Southeast Stark Street", - "walkingBike" : false - }, - { - "absoluteDirection" : "SOUTH", - "area" : false, - "bogusName" : false, - "distance" : 12.54, - "elevation" : "", - "lat" : 45.5193421, - "lon" : -122.6536397, - "relativeDirection" : "LEFT", - "stayOn" : false, - "streetName" : "Southeast 12th Avenue", - "walkingBike" : false - } - ], - "to" : { - "arrival" : "2009-11-17T18:14:00.000+00:00", - "departure" : "2009-11-17T18:14:00.000+00:00", - "lat" : 45.519229, - "lon" : -122.653546, - "name" : "SE 12th & Stark", - "stopCode" : "6594", - "stopId" : "prt:6594", - "vertexType" : "TRANSIT", - "zoneId" : "1" - }, - "transitLeg" : false, - "walkingBike" : false - }, - { - "agencyId" : "prt:prt", - "agencyName" : "TriMet", - "agencyTimeZoneOffset" : -28800000, - "agencyUrl" : "http://trimet.org", - "arrivalDelay" : 0, - "departureDelay" : 0, - "distance" : 439.45, - "endTime" : "2009-11-17T18:16:00.000+00:00", - "from" : { - "arrival" : "2009-11-17T18:14:00.000+00:00", - "departure" : "2009-11-17T18:14:00.000+00:00", - "lat" : 45.519229, - "lon" : -122.653546, - "name" : "SE 12th & Stark", - "stopCode" : "6594", - "stopId" : "prt:6594", - "stopIndex" : 32, - "stopSequence" : 33, - "vertexType" : "TRANSIT", - "zoneId" : "1" - }, - "generalizedCost" : 720, - "headsign" : "Rose Qtr TC", - "interlineWithPreviousLeg" : false, - "intermediateStops" : [ - { - "arrival" : "2009-11-17T18:14:44.000+00:00", - "departure" : "2009-11-17T18:14:44.000+00:00", - "lat" : 45.520674, - "lon" : -122.653544, - "name" : "SE 12th & Pine", - "stopCode" : "6589", - "stopId" : "prt:6589", - "stopIndex" : 33, - "stopSequence" : 34, - "vertexType" : "TRANSIT", - "zoneId" : "1" - } - ], - "legGeometry" : { - "length" : 11, - "points" : "cnytGdxrkVW?mC?{BA??Q?oC?mC?kBAa@?w@?" - }, - "mode" : "BUS", - "pathway" : false, - "realTime" : false, - "route" : "12th Ave", - "routeId" : "prt:70", - "routeLongName" : "12th Ave", - "routeShortName" : "70", - "routeType" : 3, - "serviceDate" : "2009-11-17", - "startTime" : "2009-11-17T18:14:00.000+00:00", - "steps" : [ ], - "to" : { - "arrival" : "2009-11-17T18:16:00.000+00:00", - "departure" : "2009-11-17T18:16:00.000+00:00", - "lat" : 45.52318, - "lon" : -122.653507, - "name" : "NE 12th & Sandy", - "stopCode" : "6592", - "stopId" : "prt:6592", - "stopIndex" : 34, - "stopSequence" : 35, - "vertexType" : "TRANSIT", - "zoneId" : "1" - }, - "transitLeg" : true, - "tripBlockId" : "7004", - "tripId" : "prt:700W1150" - }, - { - "agencyTimeZoneOffset" : -28800000, - "arrivalDelay" : 0, - "departureDelay" : 0, - "distance" : 0.0, - "endTime" : "2009-11-17T18:16:00.000+00:00", - "from" : { - "arrival" : "2009-11-17T18:16:00.000+00:00", - "departure" : "2009-11-17T18:16:00.000+00:00", - "lat" : 45.52318, - "lon" : -122.653507, - "name" : "NE 12th & Sandy", - "stopCode" : "6592", - "stopId" : "prt:6592", - "vertexType" : "TRANSIT", - "zoneId" : "1" - }, - "generalizedCost" : 1, - "interlineWithPreviousLeg" : false, - "legElevation" : "", - "legGeometry" : { - "length" : 2, - "points" : "{fztGlwrkV?V" - }, - "mode" : "WALK", - "pathway" : false, - "realTime" : false, - "rentedBike" : false, - "route" : "", - "startTime" : "2009-11-17T18:16:00.000+00:00", - "steps" : [ ], - "to" : { - "arrival" : "2009-11-17T18:16:00.000+00:00", - "departure" : "2009-11-17T18:16:00.000+00:00", - "lat" : 45.5231819, - "lon" : -122.6536285, - "name" : "Northeast 12th Avenue", - "vertexType" : "NORMAL" - }, - "transitLeg" : false, - "walkingBike" : false - }, - { - "agencyTimeZoneOffset" : -28800000, - "arrivalDelay" : 0, - "departureDelay" : 0, - "distance" : 1607.0, - "endTime" : "2009-11-17T18:21:03.000+00:00", - "from" : { - "arrival" : "2009-11-17T18:16:00.000+00:00", - "departure" : "2009-11-17T18:16:00.000+00:00", - "lat" : 45.5231819, - "lon" : -122.6536285, - "name" : "Northeast 12th Avenue", - "vertexType" : "NORMAL" - }, - "generalizedCost" : 473, - "interlineWithPreviousLeg" : false, - "legGeometry" : { - "length" : 81, - "points" : "{fztGdxrkVc@?C?_@AM?O?oBAO??jE?hEAhE?jE?hEAjE?lD?R?FO?]?qA?O?UBmE?k@EU??X?tC?X?P?HAjG?j@ARANCRG\\KFM\\IXCPKXELCJAHMd@?HM\\O`@KPKNKHMLKFIFYJk@P]JIBM@M@O@O?W@O?O?O?q@?Q@K@IBKDIFGFEFGLSFGHEHKZELGP" - }, - "mode" : "CAR", - "pathway" : false, - "realTime" : false, - "rentedBike" : false, - "route" : "", - "startTime" : "2009-11-17T18:16:00.000+00:00", - "steps" : [ - { - "absoluteDirection" : "NORTH", - "area" : false, - "bogusName" : false, - "distance" : 128.28, - "elevation" : "", - "lat" : 45.5231819, - "lon" : -122.6536285, - "relativeDirection" : "DEPART", - "stayOn" : false, - "streetName" : "Northeast 12th Avenue", - "walkingBike" : false - }, - { - "absoluteDirection" : "WEST", - "area" : false, - "bogusName" : false, - "distance" : 553.03, - "elevation" : "", - "lat" : 45.5243354, - "lon" : -122.6536083, - "relativeDirection" : "LEFT", - "stayOn" : false, - "streetName" : "Northeast Davis Street", - "walkingBike" : false - }, - { - "absoluteDirection" : "NORTH", - "area" : false, - "bogusName" : false, - "distance" : 243.39, - "elevation" : "", - "lat" : 45.5243542, - "lon" : -122.6607071, - "relativeDirection" : "RIGHT", - "stayOn" : false, - "streetName" : "Northeast Grand Avenue", - "walkingBike" : false - }, - { - "absoluteDirection" : "WEST", - "area" : false, - "bogusName" : false, - "distance" : 542.09, - "elevation" : "", - "lat" : 45.5265408, - "lon" : -122.6606919, - "relativeDirection" : "LEFT", - "stayOn" : false, - "streetName" : "Northeast Lloyd Boulevard", - "walkingBike" : false - }, - { - "absoluteDirection" : "NORTH", - "area" : false, - "bogusName" : false, - "distance" : 140.22, - "elevation" : "", - "lat" : 45.5286604, - "lon" : -122.6657552, - "relativeDirection" : "CONTINUE", - "stayOn" : false, - "streetName" : "North Interstate Avenue", - "walkingBike" : false - } - ], - "to" : { - "arrival" : "2009-11-17T18:21:03.000+00:00", - "departure" : "2009-11-17T18:21:03.000+00:00", - "lat" : 45.5297183, - "lon" : -122.6664542, - "name" : "corner of North Interstate Avenue and path", - "vertexType" : "NORMAL" - }, - "transitLeg" : false, - "walkingBike" : false - }, - { - "agencyTimeZoneOffset" : -28800000, - "arrivalDelay" : 0, - "departureDelay" : 0, - "distance" : 43.34, - "endTime" : "2009-11-17T18:22:49.000+00:00", - "from" : { - "arrival" : "2009-11-17T18:21:03.000+00:00", - "departure" : "2009-11-17T18:21:03.000+00:00", - "lat" : 45.5297183, - "lon" : -122.6664542, - "name" : "corner of North Interstate Avenue and path", - "vertexType" : "NORMAL" - }, - "generalizedCost" : 196, - "interlineWithPreviousLeg" : false, - "legGeometry" : { - "length" : 13, - "points" : "uo{tGjhukVKIC?CDABCDABEFCHGCEEGK@A" - }, - "mode" : "WALK", - "pathway" : false, - "realTime" : false, - "rentedBike" : false, - "route" : "", - "startTime" : "2009-11-17T18:21:03.000+00:00", - "steps" : [ - { - "absoluteDirection" : "NORTHEAST", - "area" : false, - "bogusName" : true, - "distance" : 28.77, - "elevation" : "", - "lat" : 45.5297183, - "lon" : -122.6664542, - "relativeDirection" : "SLIGHTLY_RIGHT", - "stayOn" : false, - "streetName" : "path", - "walkingBike" : false - }, - { - "absoluteDirection" : "NORTHEAST", - "area" : false, - "bogusName" : false, - "distance" : 14.56, - "elevation" : "", - "lat" : 45.5299086, - "lon" : -122.6665929, - "relativeDirection" : "RIGHT", - "stayOn" : false, - "streetName" : "Rose Quarter Transit Center", - "walkingBike" : false - } - ], - "to" : { - "arrival" : "2009-11-17T18:22:49.000+00:00", - "departure" : "2009-11-17T18:25:00.000+00:00", - "lat" : 45.530005, - "lon" : -122.666476, - "name" : "Rose Quarter Transit Center", - "stopCode" : "2592", - "stopId" : "prt:2592", - "vertexType" : "TRANSIT", - "zoneId" : "0" - }, - "transitLeg" : false, - "walkingBike" : false - }, - { - "agencyId" : "prt:prt", - "agencyName" : "TriMet", - "agencyTimeZoneOffset" : -28800000, - "agencyUrl" : "http://trimet.org", - "arrivalDelay" : 0, - "departureDelay" : 0, - "distance" : 2905.12, - "endTime" : "2009-11-17T18:34:55.000+00:00", - "from" : { - "arrival" : "2009-11-17T18:22:49.000+00:00", - "departure" : "2009-11-17T18:25:00.000+00:00", - "lat" : 45.530005, - "lon" : -122.666476, - "name" : "Rose Quarter Transit Center", - "stopCode" : "2592", - "stopId" : "prt:2592", - "stopIndex" : 84, - "stopSequence" : 85, - "vertexType" : "TRANSIT", - "zoneId" : "0" - }, - "generalizedCost" : 1326, - "headsign" : "Montgomery Park", - "interlineWithPreviousLeg" : false, - "intermediateStops" : [ - { - "arrival" : "2009-11-17T18:28:20.000+00:00", - "departure" : "2009-11-17T18:28:20.000+00:00", - "lat" : 45.526655, - "lon" : -122.676462, - "name" : "NW Glisan & 6th", - "stopCode" : "10803", - "stopId" : "prt:10803", - "stopIndex" : 85, - "stopSequence" : 86, - "vertexType" : "TRANSIT", - "zoneId" : "0" - }, - { - "arrival" : "2009-11-17T18:29:15.000+00:00", - "departure" : "2009-11-17T18:29:15.000+00:00", - "lat" : 45.528799, - "lon" : -122.677238, - "name" : "NW Station Way & Union Station", - "stopCode" : "12801", - "stopId" : "prt:12801", - "stopIndex" : 86, - "stopSequence" : 87, - "vertexType" : "TRANSIT", - "zoneId" : "0" - }, - { - "arrival" : "2009-11-17T18:31:00.000+00:00", - "departure" : "2009-11-17T18:31:00.000+00:00", - "lat" : 45.531582, - "lon" : -122.681193, - "name" : "NW Northrup & 10th", - "stopCode" : "12802", - "stopId" : "prt:12802", - "stopIndex" : 87, - "stopSequence" : 88, - "vertexType" : "TRANSIT", - "zoneId" : "1" - }, - { - "arrival" : "2009-11-17T18:31:33.000+00:00", - "departure" : "2009-11-17T18:31:33.000+00:00", - "lat" : 45.531534, - "lon" : -122.683319, - "name" : "NW 12th & Northrup", - "stopCode" : "12796", - "stopId" : "prt:12796", - "stopIndex" : 88, - "stopSequence" : 89, - "vertexType" : "TRANSIT", - "zoneId" : "1" - }, - { - "arrival" : "2009-11-17T18:32:04.000+00:00", - "departure" : "2009-11-17T18:32:04.000+00:00", - "lat" : 45.531503, - "lon" : -122.685357, - "name" : "NW Northrup & 14th", - "stopCode" : "10775", - "stopId" : "prt:10775", - "stopIndex" : 89, - "stopSequence" : 90, - "vertexType" : "TRANSIT", - "zoneId" : "1" - }, - { - "arrival" : "2009-11-17T18:33:07.000+00:00", - "departure" : "2009-11-17T18:33:07.000+00:00", - "lat" : 45.531434, - "lon" : -122.689417, - "name" : "NW Northrup & 18th", - "stopCode" : "10776", - "stopId" : "prt:10776", - "stopIndex" : 90, - "stopSequence" : 91, - "vertexType" : "TRANSIT", - "zoneId" : "1" - }, - { - "arrival" : "2009-11-17T18:34:24.000+00:00", - "departure" : "2009-11-17T18:34:24.000+00:00", - "lat" : 45.531346, - "lon" : -122.694455, - "name" : "NW Northrup & 21st", - "stopCode" : "10777", - "stopId" : "prt:10777", - "stopIndex" : 91, - "stopSequence" : 92, - "vertexType" : "TRANSIT", - "zoneId" : "1" - } - ], - "legGeometry" : { - "length" : 76, - "points" : "eq{tG`hukVNXJPPVJFf@Vf@Pp@Nd@NRLB@RNXZR\\vAhC@BhAhD`AhClAbDBrDCnG@n@@^@d@HdAP`CBjEDvD???LqCFmCDYBGDEBGJkAzAQR??KNa@b@MJuBBY?OHW@u@~@aD`EcBhBBrD@xC??@l@BlE@lD???XBjEBpD???VBlE?dA@t@?b@?h@BfEBrD???VBhEFtKDvJ??@\\DnJ" - }, - "mode" : "BUS", - "pathway" : false, - "realTime" : false, - "route" : "Broadway/Halsey", - "routeId" : "prt:77", - "routeLongName" : "Broadway/Halsey", - "routeShortName" : "77", - "routeType" : 3, - "serviceDate" : "2009-11-17", - "startTime" : "2009-11-17T18:25:00.000+00:00", - "steps" : [ ], - "to" : { - "arrival" : "2009-11-17T18:34:55.000+00:00", - "departure" : "2009-11-17T18:34:55.000+00:00", - "lat" : 45.531308, - "lon" : -122.696445, - "name" : "NW Northrup & 22nd", - "stopCode" : "10778", - "stopId" : "prt:10778", - "stopIndex" : 92, - "stopSequence" : 93, - "vertexType" : "TRANSIT", - "zoneId" : "1" - }, - "transitLeg" : true, - "tripBlockId" : "7736", - "tripId" : "prt:771W1160" - }, - { - "agencyTimeZoneOffset" : -28800000, - "arrivalDelay" : 0, - "departureDelay" : 0, - "distance" : 18.81, - "endTime" : "2009-11-17T18:35:19.000+00:00", - "from" : { - "arrival" : "2009-11-17T18:34:55.000+00:00", - "departure" : "2009-11-17T18:34:55.000+00:00", - "lat" : 45.531308, - "lon" : -122.696445, - "name" : "NW Northrup & 22nd", - "stopCode" : "10778", - "stopId" : "prt:10778", - "vertexType" : "TRANSIT", - "zoneId" : "1" - }, - "generalizedCost" : 37, - "interlineWithPreviousLeg" : false, - "legGeometry" : { - "length" : 7, - "points" : "sy{tGxc{kV???LABF?B??J" - }, - "mode" : "WALK", - "pathway" : false, - "realTime" : false, - "rentedBike" : false, - "route" : "", - "startTime" : "2009-11-17T18:34:55.000+00:00", - "steps" : [ - { - "absoluteDirection" : "WEST", - "area" : false, - "bogusName" : false, - "distance" : 18.81, - "elevation" : "", - "lat" : 45.5313019, - "lon" : -122.6964448, - "relativeDirection" : "DEPART", - "stayOn" : false, - "streetName" : "Northwest Northrup Street", - "walkingBike" : false - } - ], - "to" : { - "arrival" : "2009-11-17T18:35:19.000+00:00", - "lat" : 45.53122, - "lon" : -122.69659, - "name" : "NW Northrup St. & NW 22nd Ave. (P2)", - "vertexType" : "NORMAL" - }, - "transitLeg" : false, - "walkingBike" : false - } - ], - "startTime" : "2009-11-17T18:08:41.000+00:00", - "tooSloped" : false, - "transfers" : 1, - "transitTime" : 715, - "waitingTime" : 131, - "walkDistance" : 2077.8, - "walkLimitExceeded" : false, - "walkTime" : 752 - }, - { - "arrivedAtDestinationWithRentedBicycle" : false, - "duration" : 2077, - "elevationGained" : 0.0, - "elevationLost" : 0.0, - "endTime" : "2009-11-17T18:38:41.000+00:00", - "fare" : { - "details" : { }, - "fare" : { }, - "legProducts" : [ - { - "legIndices" : [ - 1 - ], - "products" : [ - { - "amount" : { - "cents" : 200, - "currency" : { - "currency" : "USD", - "currencyCode" : "USD", - "defaultFractionDigits" : 2, - "symbol" : "$" - } - }, - "id" : "prt:8", - "name" : "regular" - } - ] - } - ] - }, - "generalizedCost" : 3914, - "legs" : [ - { - "agencyTimeZoneOffset" : -28800000, - "arrivalDelay" : 0, - "departureDelay" : 0, - "distance" : 673.56, - "endTime" : "2009-11-17T18:12:58.000+00:00", - "from" : { - "departure" : "2009-11-17T18:04:04.000+00:00", - "lat" : 45.51932, - "lon" : -122.648567, - "name" : "SE Stark St. & SE 17th Ave. (P0)", - "vertexType" : "NORMAL" - }, - "generalizedCost" : 1031, - "interlineWithPreviousLeg" : false, - "legGeometry" : { - "length" : 42, - "points" : "unytGpxqkVA??dACpB@PoC?_CAM?aC??A?A?A?A??AA?AAA??AAA???A?A?A???A@A??@A@?@??A@?@?BcC?mCAmCAmC?QBIYIWOH" - }, - "mode" : "WALK", - "pathway" : false, - "realTime" : false, - "rentedBike" : false, - "route" : "", - "startTime" : "2009-11-17T18:04:04.000+00:00", - "steps" : [ - { - "absoluteDirection" : "NORTH", - "area" : false, - "bogusName" : false, - "distance" : 0.69, - "elevation" : "", - "lat" : 45.51932, - "lon" : -122.6485648, - "relativeDirection" : "DEPART", - "stayOn" : false, - "streetName" : "Southeast 17th Avenue", - "walkingBike" : false - }, - { - "absoluteDirection" : "WEST", - "area" : false, - "bogusName" : false, - "distance" : 79.12, - "elevation" : "", - "lat" : 45.5193262, - "lon" : -122.6485648, - "relativeDirection" : "LEFT", - "stayOn" : false, - "streetName" : "Southeast Stark Street", - "walkingBike" : false - }, - { - "absoluteDirection" : "NORTH", - "area" : false, - "bogusName" : false, - "distance" : 402.13, - "elevation" : "", - "lat" : 45.5193388, - "lon" : -122.6495798, - "relativeDirection" : "RIGHT", - "stayOn" : false, - "streetName" : "Southeast 16th Avenue", - "walkingBike" : false - }, - { - "absoluteDirection" : "NORTH", - "area" : false, - "bogusName" : false, - "distance" : 168.89, - "elevation" : "", - "lat" : 45.5228912, - "lon" : -122.6495528, - "relativeDirection" : "CONTINUE", - "stayOn" : false, - "streetName" : "Northeast 16th Avenue", - "walkingBike" : false - }, - { - "absoluteDirection" : "NORTHEAST", - "area" : false, - "bogusName" : false, - "distance" : 22.74, - "elevation" : "", - "lat" : 45.524409, - "lon" : -122.6495675, - "relativeDirection" : "RIGHT", - "stayOn" : false, - "streetName" : "Northeast Sandy Boulevard", - "walkingBike" : false - } - ], - "to" : { - "arrival" : "2009-11-17T18:12:58.000+00:00", - "departure" : "2009-11-17T18:12:58.000+00:00", - "lat" : 45.524581, - "lon" : -122.649367, - "name" : "NE Sandy & 16th", - "stopCode" : "5060", - "stopId" : "prt:5060", - "vertexType" : "TRANSIT", - "zoneId" : "1" - }, - "transitLeg" : false, - "walkingBike" : false - }, - { - "agencyId" : "prt:prt", - "agencyName" : "TriMet", - "agencyTimeZoneOffset" : -28800000, - "agencyUrl" : "http://trimet.org", - "arrivalDelay" : 0, - "departureDelay" : 0, - "distance" : 3602.73, - "endTime" : "2009-11-17T18:25:49.000+00:00", - "from" : { - "arrival" : "2009-11-17T18:12:58.000+00:00", - "departure" : "2009-11-17T18:12:58.000+00:00", - "lat" : 45.524581, - "lon" : -122.649367, - "name" : "NE Sandy & 16th", - "stopCode" : "5060", - "stopId" : "prt:5060", - "stopIndex" : 92, - "stopSequence" : 93, - "vertexType" : "TRANSIT", - "zoneId" : "1" - }, - "generalizedCost" : 1371, - "headsign" : "Beaverton TC", - "interlineWithPreviousLeg" : false, - "intermediateStops" : [ - { - "arrival" : "2009-11-17T18:13:32.000+00:00", - "departure" : "2009-11-17T18:13:32.000+00:00", - "lat" : 45.523767, - "lon" : -122.651428, - "name" : "NE Sandy & 14th", - "stopCode" : "5058", - "stopId" : "prt:5058", - "stopIndex" : 93, - "stopSequence" : 94, - "vertexType" : "TRANSIT", - "zoneId" : "1" - }, - { - "arrival" : "2009-11-17T18:14:00.000+00:00", - "departure" : "2009-11-17T18:14:00.000+00:00", - "lat" : 45.523103, - "lon" : -122.653064, - "name" : "NE Sandy & 12th", - "stopCode" : "5055", - "stopId" : "prt:5055", - "stopIndex" : 94, - "stopSequence" : 95, - "vertexType" : "TRANSIT", - "zoneId" : "1" - }, - { - "arrival" : "2009-11-17T18:14:47.000+00:00", - "departure" : "2009-11-17T18:14:47.000+00:00", - "lat" : 45.523024, - "lon" : -122.656526, - "name" : "E Burnside & NE 9th", - "stopCode" : "819", - "stopId" : "prt:819", - "stopIndex" : 95, - "stopSequence" : 96, - "vertexType" : "TRANSIT", - "zoneId" : "1" - }, - { - "arrival" : "2009-11-17T18:15:24.000+00:00", - "departure" : "2009-11-17T18:15:24.000+00:00", - "lat" : 45.523012, - "lon" : -122.659365, - "name" : "E Burnside & NE 6th", - "stopCode" : "805", - "stopId" : "prt:805", - "stopIndex" : 96, - "stopSequence" : 97, - "vertexType" : "TRANSIT", - "zoneId" : "1" - }, - { - "arrival" : "2009-11-17T18:15:52.000+00:00", - "departure" : "2009-11-17T18:15:52.000+00:00", - "lat" : 45.523015, - "lon" : -122.661534, - "name" : "E Burnside & NE M L King", - "stopCode" : "705", - "stopId" : "prt:705", - "stopIndex" : 97, - "stopSequence" : 98, - "vertexType" : "TRANSIT", - "zoneId" : "1" - }, - { - "arrival" : "2009-11-17T18:18:00.000+00:00", - "departure" : "2009-11-17T18:18:00.000+00:00", - "lat" : 45.523249, - "lon" : -122.671269, - "name" : "W Burnside & Burnside Bridge", - "stopCode" : "689", - "stopId" : "prt:689", - "stopIndex" : 98, - "stopSequence" : 99, - "vertexType" : "TRANSIT", - "zoneId" : "0" - }, - { - "arrival" : "2009-11-17T18:19:00.000+00:00", - "departure" : "2009-11-17T18:19:00.000+00:00", - "lat" : 45.523169, - "lon" : -122.675893, - "name" : "W Burnside & NW 5th", - "stopCode" : "782", - "stopId" : "prt:782", - "stopIndex" : 99, - "stopSequence" : 100, - "vertexType" : "TRANSIT", - "zoneId" : "0" - }, - { - "arrival" : "2009-11-17T18:20:17.000+00:00", - "departure" : "2009-11-17T18:20:17.000+00:00", - "lat" : 45.523115, - "lon" : -122.678939, - "name" : "W Burnside & NW Park", - "stopCode" : "716", - "stopId" : "prt:716", - "stopIndex" : 100, - "stopSequence" : 101, - "vertexType" : "TRANSIT", - "zoneId" : "0" - }, - { - "arrival" : "2009-11-17T18:21:25.000+00:00", - "departure" : "2009-11-17T18:21:25.000+00:00", - "lat" : 45.523048, - "lon" : -122.681606, - "name" : "W Burnside & NW 10th", - "stopCode" : "10791", - "stopId" : "prt:10791", - "stopIndex" : 101, - "stopSequence" : 102, - "vertexType" : "TRANSIT", - "zoneId" : "0" - }, - { - "arrival" : "2009-11-17T18:22:14.000+00:00", - "departure" : "2009-11-17T18:22:14.000+00:00", - "lat" : 45.523, - "lon" : -122.683535, - "name" : "W Burnside & NW 12th", - "stopCode" : "11032", - "stopId" : "prt:11032", - "stopIndex" : 102, - "stopSequence" : 103, - "vertexType" : "TRANSIT", - "zoneId" : "0" - }, - { - "arrival" : "2009-11-17T18:24:09.000+00:00", - "departure" : "2009-11-17T18:24:09.000+00:00", - "lat" : 45.522985, - "lon" : -122.688091, - "name" : "W Burnside & NW 17th", - "stopCode" : "10809", - "stopId" : "prt:10809", - "stopIndex" : 103, - "stopSequence" : 104, - "vertexType" : "TRANSIT", - "zoneId" : "1" - }, - { - "arrival" : "2009-11-17T18:25:00.000+00:00", - "departure" : "2009-11-17T18:25:00.000+00:00", - "lat" : 45.523097, - "lon" : -122.690083, - "name" : "W Burnside & NW 19th", - "stopCode" : "735", - "stopId" : "prt:735", - "stopIndex" : 104, - "stopSequence" : 105, - "vertexType" : "TRANSIT", - "zoneId" : "1" - }, - { - "arrival" : "2009-11-17T18:25:21.000+00:00", - "departure" : "2009-11-17T18:25:21.000+00:00", - "lat" : 45.523176, - "lon" : -122.692139, - "name" : "W Burnside & NW 20th", - "stopCode" : "741", - "stopId" : "prt:741", - "stopIndex" : 105, - "stopSequence" : 106, - "vertexType" : "TRANSIT", - "zoneId" : "1" - }, - { - "arrival" : "2009-11-17T18:25:31.000+00:00", - "departure" : "2009-11-17T18:25:31.000+00:00", - "lat" : 45.52322, - "lon" : -122.69313, - "name" : "W Burnside & NW 20th Pl", - "stopCode" : "742", - "stopId" : "prt:742", - "stopIndex" : 106, - "stopSequence" : 107, - "vertexType" : "TRANSIT", - "zoneId" : "1" - } - ], - "legGeometry" : { - "length" : 94, - "points" : "coztGd}qkVNl@r@`CZhA`A`D??Ph@l@tBb@rARh@Pd@???BPj@@jA?jEAhE?pD???VAjE?hE?dB?b@???`AAhE?dD???l@C`EAhEEhE?bAA|@?XAZ@\\AzACnGKbKAjC?bE???JEnE@fEDlE@hE@~A??@rBBzDBpE@~A???Z@tD@RBnEB|A???@BdB?lEBjA??BnBApF@dB?X?^@r@?f@@bCAx@EtB???VChAE|BGnD??AXKnEGnD???XGjD??AZEfCC`AEzB" - }, - "mode" : "BUS", - "pathway" : false, - "realTime" : false, - "route" : "Burnside/Stark", - "routeId" : "prt:20", - "routeLongName" : "Burnside/Stark", - "routeShortName" : "20", - "routeType" : 3, - "serviceDate" : "2009-11-17", - "startTime" : "2009-11-17T18:12:58.000+00:00", - "steps" : [ ], - "to" : { - "arrival" : "2009-11-17T18:25:49.000+00:00", - "departure" : "2009-11-17T18:25:49.000+00:00", - "lat" : 45.523312, - "lon" : -122.694901, - "name" : "W Burnside & NW King", - "stopCode" : "747", - "stopId" : "prt:747", - "stopIndex" : 107, - "stopSequence" : 108, - "vertexType" : "TRANSIT", - "zoneId" : "1" - }, - "transitLeg" : true, - "tripBlockId" : "2002", - "tripId" : "prt:200W1200" - }, - { - "agencyTimeZoneOffset" : -28800000, - "arrivalDelay" : 0, - "departureDelay" : 0, - "distance" : 999.1, - "endTime" : "2009-11-17T18:38:41.000+00:00", - "from" : { - "arrival" : "2009-11-17T18:25:49.000+00:00", - "departure" : "2009-11-17T18:25:49.000+00:00", - "lat" : 45.523312, - "lon" : -122.694901, - "name" : "W Burnside & NW King", - "stopCode" : "747", - "stopId" : "prt:747", - "vertexType" : "TRANSIT", - "zoneId" : "1" - }, - "generalizedCost" : 1511, - "interlineWithPreviousLeg" : false, - "legGeometry" : { - "length" : 29, - "points" : "ugztGdzzkVL?ATClAI|DK?G?mCBkCDoCDmCBoCDkCBoCB[?sBD]?Y@eA@K?C?K?W@{A@M@C@I?_CB?G" - }, - "mode" : "WALK", - "pathway" : false, - "realTime" : false, - "rentedBike" : false, - "route" : "", - "startTime" : "2009-11-17T18:25:49.000+00:00", - "steps" : [ - { - "absoluteDirection" : "WEST", - "area" : false, - "bogusName" : false, - "distance" : 113.27, - "elevation" : "", - "lat" : 45.5232491, - "lon" : -122.6949067, - "relativeDirection" : "DEPART", - "stayOn" : false, - "streetName" : "West Burnside Street", - "walkingBike" : false - }, - { - "absoluteDirection" : "NORTH", - "area" : false, - "bogusName" : false, - "distance" : 882.16, - "elevation" : "", - "lat" : 45.5233204, - "lon" : -122.696357, - "relativeDirection" : "RIGHT", - "stayOn" : false, - "streetName" : "Northwest 22nd Avenue", - "walkingBike" : false - }, - { - "absoluteDirection" : "EAST", - "area" : false, - "bogusName" : false, - "distance" : 3.68, - "elevation" : "", - "lat" : 45.5312508, - "lon" : -122.6966386, - "relativeDirection" : "RIGHT", - "stayOn" : false, - "streetName" : "Northwest Northrup Street", - "walkingBike" : false - } - ], - "to" : { - "arrival" : "2009-11-17T18:38:41.000+00:00", - "lat" : 45.53122, - "lon" : -122.69659, - "name" : "NW Northrup St. & NW 22nd Ave. (P2)", - "vertexType" : "NORMAL" - }, - "transitLeg" : false, - "walkingBike" : false - } - ], - "startTime" : "2009-11-17T18:04:04.000+00:00", - "tooSloped" : false, - "transfers" : 0, - "transitTime" : 771, - "waitingTime" : 0, - "walkDistance" : 1672.66, - "walkLimitExceeded" : false, - "walkTime" : 1306 - }, - { - "arrivedAtDestinationWithRentedBicycle" : false, - "duration" : 1646, - "elevationGained" : 0.0, - "elevationLost" : 0.0, - "endTime" : "2009-11-17T18:39:22.000+00:00", - "fare" : { - "details" : { }, - "fare" : { }, - "legProducts" : [ - { - "legIndices" : [ - 1 - ], - "products" : [ - { - "amount" : { - "cents" : 200, - "currency" : { - "currency" : "USD", - "currencyCode" : "USD", - "defaultFractionDigits" : 2, - "symbol" : "$" - } - }, - "id" : "prt:8", - "name" : "regular" - } - ] - } - ] - }, - "generalizedCost" : 2662, - "legs" : [ - { - "agencyTimeZoneOffset" : -28800000, - "arrivalDelay" : 0, - "departureDelay" : 0, - "distance" : 290.72, - "endTime" : "2009-11-17T18:15:40.000+00:00", - "from" : { - "departure" : "2009-11-17T18:11:56.000+00:00", - "lat" : 45.51932, - "lon" : -122.648567, - "name" : "SE Stark St. & SE 17th Ave. (P0)", - "vertexType" : "NORMAL" - }, - "generalizedCost" : 442, - "interlineWithPreviousLeg" : false, - "legGeometry" : { - "length" : 6, - "points" : "unytGpxqkVjC?lC@nC@?fCG?" - }, - "mode" : "WALK", - "pathway" : false, - "realTime" : false, - "rentedBike" : false, - "route" : "", - "startTime" : "2009-11-17T18:11:56.000+00:00", - "steps" : [ - { - "absoluteDirection" : "SOUTH", - "area" : false, - "bogusName" : false, - "distance" : 237.26, - "elevation" : "", - "lat" : 45.51932, - "lon" : -122.6485648, - "relativeDirection" : "DEPART", - "stayOn" : false, - "streetName" : "Southeast 17th Avenue", - "walkingBike" : false - }, - { - "absoluteDirection" : "WEST", - "area" : false, - "bogusName" : false, - "distance" : 53.47, - "elevation" : "", - "lat" : 45.5171863, - "lon" : -122.6485801, - "relativeDirection" : "RIGHT", - "stayOn" : false, - "streetName" : "Southeast Morrison Street", - "walkingBike" : false - } - ], - "to" : { - "arrival" : "2009-11-17T18:15:40.000+00:00", - "departure" : "2009-11-17T18:15:40.000+00:00", - "lat" : 45.517226, - "lon" : -122.649266, - "name" : "SE Morrison & 16th", - "stopCode" : "4019", - "stopId" : "prt:4019", - "vertexType" : "TRANSIT", - "zoneId" : "1" - }, - "transitLeg" : false, - "walkingBike" : false - }, - { - "agencyId" : "prt:prt", - "agencyName" : "TriMet", - "agencyTimeZoneOffset" : -28800000, - "agencyUrl" : "http://trimet.org", - "arrivalDelay" : 0, - "departureDelay" : 0, - "distance" : 5218.86, - "endTime" : "2009-11-17T18:35:54.000+00:00", - "from" : { - "arrival" : "2009-11-17T18:15:40.000+00:00", - "departure" : "2009-11-17T18:15:40.000+00:00", - "lat" : 45.517226, - "lon" : -122.649266, - "name" : "SE Morrison & 16th", - "stopCode" : "4019", - "stopId" : "prt:4019", - "stopIndex" : 50, - "stopSequence" : 51, - "vertexType" : "TRANSIT", - "zoneId" : "1" - }, - "generalizedCost" : 1814, - "headsign" : "Montgomery Park", - "interlineWithPreviousLeg" : false, - "intermediateStops" : [ - { - "arrival" : "2009-11-17T18:16:15.000+00:00", - "departure" : "2009-11-17T18:16:15.000+00:00", - "lat" : 45.517253, - "lon" : -122.651354, - "name" : "SE Morrison & 14th", - "stopCode" : "4016", - "stopId" : "prt:4016", - "stopIndex" : 51, - "stopSequence" : 52, - "vertexType" : "TRANSIT", - "zoneId" : "1" - }, - { - "arrival" : "2009-11-17T18:17:00.000+00:00", - "departure" : "2009-11-17T18:17:00.000+00:00", - "lat" : 45.517299, - "lon" : -122.654067, - "name" : "SE Morrison & 12th", - "stopCode" : "4014", - "stopId" : "prt:4014", - "stopIndex" : 52, - "stopSequence" : 53, - "vertexType" : "TRANSIT", - "zoneId" : "1" - }, - { - "arrival" : "2009-11-17T18:17:38.000+00:00", - "departure" : "2009-11-17T18:17:38.000+00:00", - "lat" : 45.517292, - "lon" : -122.656563, - "name" : "SE Morrison & 9th", - "stopCode" : "4026", - "stopId" : "prt:4026", - "stopIndex" : 53, - "stopSequence" : 54, - "vertexType" : "TRANSIT", - "zoneId" : "1" - }, - { - "arrival" : "2009-11-17T18:18:08.000+00:00", - "departure" : "2009-11-17T18:18:08.000+00:00", - "lat" : 45.517322, - "lon" : -122.65847, - "name" : "SE Morrison & 7th", - "stopCode" : "4025", - "stopId" : "prt:4025", - "stopIndex" : 54, - "stopSequence" : 55, - "vertexType" : "TRANSIT", - "zoneId" : "1" - }, - { - "arrival" : "2009-11-17T18:18:39.000+00:00", - "departure" : "2009-11-17T18:18:39.000+00:00", - "lat" : 45.517298, - "lon" : -122.660523, - "name" : "SE Morrison & Grand", - "stopCode" : "4013", - "stopId" : "prt:4013", - "stopIndex" : 55, - "stopSequence" : 56, - "vertexType" : "TRANSIT", - "zoneId" : "1" - }, - { - "arrival" : "2009-11-17T18:20:03.000+00:00", - "departure" : "2009-11-17T18:20:03.000+00:00", - "lat" : 45.517351, - "lon" : -122.66601, - "name" : "Morrison Bridge", - "stopCode" : "4029", - "stopId" : "prt:4029", - "stopIndex" : 56, - "stopSequence" : 57, - "vertexType" : "TRANSIT", - "zoneId" : "1" - }, - { - "arrival" : "2009-11-17T18:22:27.000+00:00", - "departure" : "2009-11-17T18:22:27.000+00:00", - "lat" : 45.51959, - "lon" : -122.674599, - "name" : "SW Washington & 3rd", - "stopCode" : "6158", - "stopId" : "prt:6158", - "stopIndex" : 57, - "stopSequence" : 58, - "vertexType" : "TRANSIT", - "zoneId" : "0" - }, - { - "arrival" : "2009-11-17T18:23:00.000+00:00", - "departure" : "2009-11-17T18:23:00.000+00:00", - "lat" : 45.520129, - "lon" : -122.676635, - "name" : "SW Washington & 5th", - "stopCode" : "6160", - "stopId" : "prt:6160", - "stopIndex" : 58, - "stopSequence" : 59, - "vertexType" : "TRANSIT", - "zoneId" : "0" - }, - { - "arrival" : "2009-11-17T18:23:52.000+00:00", - "departure" : "2009-11-17T18:23:52.000+00:00", - "lat" : 45.520695, - "lon" : -122.678657, - "name" : "SW Washington & Broadway", - "stopCode" : "6137", - "stopId" : "prt:6137", - "stopIndex" : 59, - "stopSequence" : 60, - "vertexType" : "TRANSIT", - "zoneId" : "0" - }, - { - "arrival" : "2009-11-17T18:24:34.000+00:00", - "departure" : "2009-11-17T18:24:34.000+00:00", - "lat" : 45.521124, - "lon" : -122.6803, - "name" : "SW Washington & 9th", - "stopCode" : "6169", - "stopId" : "prt:6169", - "stopIndex" : 60, - "stopSequence" : 61, - "vertexType" : "TRANSIT", - "zoneId" : "0" - }, - { - "arrival" : "2009-11-17T18:25:47.000+00:00", - "departure" : "2009-11-17T18:25:47.000+00:00", - "lat" : 45.521094, - "lon" : -122.682819, - "name" : "SW 11th & Alder", - "stopCode" : "9600", - "stopId" : "prt:9600", - "stopIndex" : 61, - "stopSequence" : 62, - "vertexType" : "TRANSIT", - "zoneId" : "0" - }, - { - "arrival" : "2009-11-17T18:26:36.000+00:00", - "departure" : "2009-11-17T18:26:36.000+00:00", - "lat" : 45.52055, - "lon" : -122.683933, - "name" : "SW Morrison & 12th", - "stopCode" : "9598", - "stopId" : "prt:9598", - "stopIndex" : 62, - "stopSequence" : 63, - "vertexType" : "TRANSIT", - "zoneId" : "0" - }, - { - "arrival" : "2009-11-17T18:27:25.000+00:00", - "departure" : "2009-11-17T18:27:25.000+00:00", - "lat" : 45.521063, - "lon" : -122.685848, - "name" : "SW Morrison & 14th", - "stopCode" : "9708", - "stopId" : "prt:9708", - "stopIndex" : 63, - "stopSequence" : 64, - "vertexType" : "TRANSIT", - "zoneId" : "1" - }, - { - "arrival" : "2009-11-17T18:28:18.000+00:00", - "departure" : "2009-11-17T18:28:18.000+00:00", - "lat" : 45.521641, - "lon" : -122.687932, - "name" : "SW Morrison & 16th", - "stopCode" : "9613", - "stopId" : "prt:9613", - "stopIndex" : 64, - "stopSequence" : 65, - "vertexType" : "TRANSIT", - "zoneId" : "1" - }, - { - "arrival" : "2009-11-17T18:29:00.000+00:00", - "departure" : "2009-11-17T18:29:00.000+00:00", - "lat" : 45.52206, - "lon" : -122.689577, - "name" : "SW Morrison & 17th", - "stopCode" : "9599", - "stopId" : "prt:9599", - "stopIndex" : 65, - "stopSequence" : 66, - "vertexType" : "TRANSIT", - "zoneId" : "1" - }, - { - "arrival" : "2009-11-17T18:29:54.000+00:00", - "departure" : "2009-11-17T18:29:54.000+00:00", - "lat" : 45.523097, - "lon" : -122.690083, - "name" : "W Burnside & NW 19th", - "stopCode" : "735", - "stopId" : "prt:735", - "stopIndex" : 66, - "stopSequence" : 67, - "vertexType" : "TRANSIT", - "zoneId" : "1" - }, - { - "arrival" : "2009-11-17T18:30:31.000+00:00", - "departure" : "2009-11-17T18:30:31.000+00:00", - "lat" : 45.523176, - "lon" : -122.692139, - "name" : "W Burnside & NW 20th", - "stopCode" : "741", - "stopId" : "prt:741", - "stopIndex" : 67, - "stopSequence" : 68, - "vertexType" : "TRANSIT", - "zoneId" : "1" - }, - { - "arrival" : "2009-11-17T18:30:48.000+00:00", - "departure" : "2009-11-17T18:30:48.000+00:00", - "lat" : 45.52322, - "lon" : -122.69313, - "name" : "W Burnside & NW 20th Pl", - "stopCode" : "742", - "stopId" : "prt:742", - "stopIndex" : 68, - "stopSequence" : 69, - "vertexType" : "TRANSIT", - "zoneId" : "1" - }, - { - "arrival" : "2009-11-17T18:31:20.000+00:00", - "departure" : "2009-11-17T18:31:20.000+00:00", - "lat" : 45.523312, - "lon" : -122.694901, - "name" : "W Burnside & NW King", - "stopCode" : "747", - "stopId" : "prt:747", - "stopIndex" : 69, - "stopSequence" : 70, - "vertexType" : "TRANSIT", - "zoneId" : "1" - }, - { - "arrival" : "2009-11-17T18:32:18.000+00:00", - "departure" : "2009-11-17T18:32:18.000+00:00", - "lat" : 45.523512, - "lon" : -122.698081, - "name" : "W Burnside & NW 23rd", - "stopCode" : "755", - "stopId" : "prt:755", - "stopIndex" : 70, - "stopSequence" : 71, - "vertexType" : "TRANSIT", - "zoneId" : "1" - }, - { - "arrival" : "2009-11-17T18:33:11.000+00:00", - "departure" : "2009-11-17T18:33:11.000+00:00", - "lat" : 45.525416, - "lon" : -122.698381, - "name" : "NW 23rd & Flanders", - "stopCode" : "7157", - "stopId" : "prt:7157", - "stopIndex" : 71, - "stopSequence" : 72, - "vertexType" : "TRANSIT", - "zoneId" : "1" - }, - { - "arrival" : "2009-11-17T18:34:05.000+00:00", - "departure" : "2009-11-17T18:34:05.000+00:00", - "lat" : 45.527543, - "lon" : -122.698473, - "name" : "NW 23rd & Irving", - "stopCode" : "7161", - "stopId" : "prt:7161", - "stopIndex" : 72, - "stopSequence" : 73, - "vertexType" : "TRANSIT", - "zoneId" : "1" - }, - { - "arrival" : "2009-11-17T18:35:00.000+00:00", - "departure" : "2009-11-17T18:35:00.000+00:00", - "lat" : 45.529681, - "lon" : -122.698529, - "name" : "NW 23rd & Lovejoy", - "stopCode" : "7163", - "stopId" : "prt:7163", - "stopIndex" : 73, - "stopSequence" : 74, - "vertexType" : "TRANSIT", - "zoneId" : "1" - } - ], - "legGeometry" : { - "length" : 135, - "points" : "kaytG||qkVA~@?jE?tC???r@AhE?jE?rA???tBAjE?nD???X?hE?xC??Ah@?pE?~C???J?`@?vAAvBEbE?jEAlE?`BAbB@d@??@tAAj@Cx@Cb@Cp@_@dEcAtFoA`IS~@i@`BmAzDi@zAc@pAi@~C??Id@u@jEm@bD??If@u@jEk@bD??If@u@|DW`B??CPs@|Du@lElBz@??VJbCfAk@dD??Id@w@rEWvAId@AF??Q~@s@`Ei@~C??Ib@u@dEWzA??]jB]MQSe@WOKOKIIQe@GWE]GnD??AXKnEGnD???XGjD??AZEfCC`AEzB??AXCfAGxDE|AEtBIlC??APkAh@o@?sCB{BD??S?mCDmCDyBB??U?mCDmCDyBB??S?oCDmCDmCBo@@" - }, - "mode" : "BUS", - "pathway" : false, - "realTime" : false, - "route" : "Belmont/NW 23rd", - "routeId" : "prt:15", - "routeLongName" : "Belmont/NW 23rd", - "routeShortName" : "15", - "routeType" : 3, - "serviceDate" : "2009-11-17", - "startTime" : "2009-11-17T18:15:40.000+00:00", - "steps" : [ ], - "to" : { - "arrival" : "2009-11-17T18:35:54.000+00:00", - "departure" : "2009-11-17T18:35:54.000+00:00", - "lat" : 45.532159, - "lon" : -122.698634, - "name" : "NW 23rd & Overton", - "stopCode" : "8981", - "stopId" : "prt:8981", - "stopIndex" : 74, - "stopSequence" : 75, - "vertexType" : "TRANSIT", - "zoneId" : "1" - }, - "transitLeg" : true, - "tripBlockId" : "1549", - "tripId" : "prt:150W1400" - }, - { - "agencyTimeZoneOffset" : -28800000, - "arrivalDelay" : 0, - "departureDelay" : 0, - "distance" : 266.21, - "endTime" : "2009-11-17T18:39:22.000+00:00", - "from" : { - "arrival" : "2009-11-17T18:35:54.000+00:00", - "departure" : "2009-11-17T18:35:54.000+00:00", - "lat" : 45.532159, - "lon" : -122.698634, - "name" : "NW 23rd & Overton", - "stopCode" : "8981", - "stopId" : "prt:8981", - "vertexType" : "TRANSIT", - "zoneId" : "1" - }, - "generalizedCost" : 405, - "interlineWithPreviousLeg" : false, - "legGeometry" : { - "length" : 13, - "points" : "}~{tGnq{kV?LVAF?J?L?rBCLA?Q?EAyAEcH?G" - }, - "mode" : "WALK", - "pathway" : false, - "realTime" : false, - "rentedBike" : false, - "route" : "", - "startTime" : "2009-11-17T18:35:54.000+00:00", - "steps" : [ - { - "absoluteDirection" : "SOUTH", - "area" : false, - "bogusName" : false, - "distance" : 104.46, - "elevation" : "", - "lat" : 45.5321578, - "lon" : -122.6987026, - "relativeDirection" : "DEPART", - "stayOn" : false, - "streetName" : "Northwest 23rd Avenue", - "walkingBike" : false - }, - { - "absoluteDirection" : "EAST", - "area" : false, - "bogusName" : false, - "distance" : 161.77, - "elevation" : "", - "lat" : 45.5312188, - "lon" : -122.6986675, - "relativeDirection" : "LEFT", - "stayOn" : false, - "streetName" : "Northwest Northrup Street", - "walkingBike" : false - } - ], - "to" : { - "arrival" : "2009-11-17T18:39:22.000+00:00", - "lat" : 45.53122, - "lon" : -122.69659, - "name" : "NW Northrup St. & NW 22nd Ave. (P2)", - "vertexType" : "NORMAL" - }, - "transitLeg" : false, - "walkingBike" : false - } - ], - "startTime" : "2009-11-17T18:11:56.000+00:00", - "tooSloped" : false, - "transfers" : 0, - "transitTime" : 1214, - "waitingTime" : 0, - "walkDistance" : 556.93, - "walkLimitExceeded" : false, - "walkTime" : 432 - }, - { - "arrivedAtDestinationWithRentedBicycle" : false, - "duration" : 1635, - "elevationGained" : 0.0, - "elevationLost" : 0.0, - "endTime" : "2009-11-17T18:46:19.000+00:00", - "fare" : { - "details" : { }, - "fare" : { }, - "legProducts" : [ - { - "legIndices" : [ - 1 - ], - "products" : [ - { - "amount" : { - "cents" : 200, - "currency" : { - "currency" : "USD", - "currencyCode" : "USD", - "defaultFractionDigits" : 2, - "symbol" : "$" - } - }, - "id" : "prt:8", - "name" : "regular" - } - ] - }, - { - "legIndices" : [ - 5 - ], - "products" : [ - { - "amount" : { - "cents" : 200, - "currency" : { - "currency" : "USD", - "currencyCode" : "USD", - "defaultFractionDigits" : 2, - "symbol" : "$" - } - }, - "id" : "prt:8", - "name" : "regular" - } - ] - } - ] - }, - "generalizedCost" : 3652, - "legs" : [ - { - "agencyTimeZoneOffset" : -28800000, - "arrivalDelay" : 0, - "departureDelay" : 0, - "distance" : 673.56, - "endTime" : "2009-11-17T18:27:58.000+00:00", - "from" : { - "departure" : "2009-11-17T18:19:04.000+00:00", - "lat" : 45.51932, - "lon" : -122.648567, - "name" : "SE Stark St. & SE 17th Ave. (P0)", - "vertexType" : "NORMAL" - }, - "generalizedCost" : 1031, - "interlineWithPreviousLeg" : false, - "legGeometry" : { - "length" : 42, - "points" : "unytGpxqkVA??dACpB@PoC?_CAM?aC??A?A?A?A??AA?AAA??AAA???A?A?A???A@A??@A@?@??A@?@?BcC?mCAmCAmC?QBIYIWOH" - }, - "mode" : "WALK", - "pathway" : false, - "realTime" : false, - "rentedBike" : false, - "route" : "", - "startTime" : "2009-11-17T18:19:04.000+00:00", - "steps" : [ - { - "absoluteDirection" : "NORTH", - "area" : false, - "bogusName" : false, - "distance" : 0.69, - "elevation" : "", - "lat" : 45.51932, - "lon" : -122.6485648, - "relativeDirection" : "DEPART", - "stayOn" : false, - "streetName" : "Southeast 17th Avenue", - "walkingBike" : false - }, - { - "absoluteDirection" : "WEST", - "area" : false, - "bogusName" : false, - "distance" : 79.12, - "elevation" : "", - "lat" : 45.5193262, - "lon" : -122.6485648, - "relativeDirection" : "LEFT", - "stayOn" : false, - "streetName" : "Southeast Stark Street", - "walkingBike" : false - }, - { - "absoluteDirection" : "NORTH", - "area" : false, - "bogusName" : false, - "distance" : 402.13, - "elevation" : "", - "lat" : 45.5193388, - "lon" : -122.6495798, - "relativeDirection" : "RIGHT", - "stayOn" : false, - "streetName" : "Southeast 16th Avenue", - "walkingBike" : false - }, - { - "absoluteDirection" : "NORTH", - "area" : false, - "bogusName" : false, - "distance" : 168.89, - "elevation" : "", - "lat" : 45.5228912, - "lon" : -122.6495528, - "relativeDirection" : "CONTINUE", - "stayOn" : false, - "streetName" : "Northeast 16th Avenue", - "walkingBike" : false - }, - { - "absoluteDirection" : "NORTHEAST", - "area" : false, - "bogusName" : false, - "distance" : 22.74, - "elevation" : "", - "lat" : 45.524409, - "lon" : -122.6495675, - "relativeDirection" : "RIGHT", - "stayOn" : false, - "streetName" : "Northeast Sandy Boulevard", - "walkingBike" : false - } - ], - "to" : { - "arrival" : "2009-11-17T18:27:58.000+00:00", - "departure" : "2009-11-17T18:27:58.000+00:00", - "lat" : 45.524581, - "lon" : -122.649367, - "name" : "NE Sandy & 16th", - "stopCode" : "5060", - "stopId" : "prt:5060", - "vertexType" : "TRANSIT", - "zoneId" : "1" - }, - "transitLeg" : false, - "walkingBike" : false - }, - { - "agencyId" : "prt:prt", - "agencyName" : "TriMet", - "agencyTimeZoneOffset" : -28800000, - "agencyUrl" : "http://trimet.org", - "arrivalDelay" : 0, - "departureDelay" : 0, - "distance" : 2119.06, - "endTime" : "2009-11-17T18:34:00.000+00:00", - "from" : { - "arrival" : "2009-11-17T18:27:58.000+00:00", - "departure" : "2009-11-17T18:27:58.000+00:00", - "lat" : 45.524581, - "lon" : -122.649367, - "name" : "NE Sandy & 16th", - "stopCode" : "5060", - "stopId" : "prt:5060", - "stopIndex" : 92, - "stopSequence" : 93, - "vertexType" : "TRANSIT", - "zoneId" : "1" - }, - "generalizedCost" : 962, - "headsign" : "23rd Ave to Tichner", - "interlineWithPreviousLeg" : false, - "intermediateStops" : [ - { - "arrival" : "2009-11-17T18:28:32.000+00:00", - "departure" : "2009-11-17T18:28:32.000+00:00", - "lat" : 45.523767, - "lon" : -122.651428, - "name" : "NE Sandy & 14th", - "stopCode" : "5058", - "stopId" : "prt:5058", - "stopIndex" : 93, - "stopSequence" : 94, - "vertexType" : "TRANSIT", - "zoneId" : "1" - }, - { - "arrival" : "2009-11-17T18:29:00.000+00:00", - "departure" : "2009-11-17T18:29:00.000+00:00", - "lat" : 45.523103, - "lon" : -122.653064, - "name" : "NE Sandy & 12th", - "stopCode" : "5055", - "stopId" : "prt:5055", - "stopIndex" : 94, - "stopSequence" : 95, - "vertexType" : "TRANSIT", - "zoneId" : "1" - }, - { - "arrival" : "2009-11-17T18:29:47.000+00:00", - "departure" : "2009-11-17T18:29:47.000+00:00", - "lat" : 45.523024, - "lon" : -122.656526, - "name" : "E Burnside & NE 9th", - "stopCode" : "819", - "stopId" : "prt:819", - "stopIndex" : 95, - "stopSequence" : 96, - "vertexType" : "TRANSIT", - "zoneId" : "1" - }, - { - "arrival" : "2009-11-17T18:30:24.000+00:00", - "departure" : "2009-11-17T18:30:24.000+00:00", - "lat" : 45.523012, - "lon" : -122.659365, - "name" : "E Burnside & NE 6th", - "stopCode" : "805", - "stopId" : "prt:805", - "stopIndex" : 96, - "stopSequence" : 97, - "vertexType" : "TRANSIT", - "zoneId" : "1" - }, - { - "arrival" : "2009-11-17T18:30:52.000+00:00", - "departure" : "2009-11-17T18:30:52.000+00:00", - "lat" : 45.523015, - "lon" : -122.661534, - "name" : "E Burnside & NE M L King", - "stopCode" : "705", - "stopId" : "prt:705", - "stopIndex" : 97, - "stopSequence" : 98, - "vertexType" : "TRANSIT", - "zoneId" : "1" - }, - { - "arrival" : "2009-11-17T18:33:00.000+00:00", - "departure" : "2009-11-17T18:33:00.000+00:00", - "lat" : 45.523249, - "lon" : -122.671269, - "name" : "W Burnside & Burnside Bridge", - "stopCode" : "689", - "stopId" : "prt:689", - "stopIndex" : 98, - "stopSequence" : 99, - "vertexType" : "TRANSIT", - "zoneId" : "0" - } - ], - "legGeometry" : { - "length" : 50, - "points" : "coztGd}qkVNl@r@`CZhA`A`D??Ph@l@tBb@rARh@Pd@???BPj@@jA?jEAhE?pD???VAjE?hE?dB?b@???`AAhE?dD???l@C`EAhEEhE?bAA|@?XAZ@\\AzACnGKbKAjC?bE???JEnE@fEDlE@hE@~A" - }, - "mode" : "BUS", - "pathway" : false, - "realTime" : false, - "route" : "Burnside/Stark", - "routeId" : "prt:20", - "routeLongName" : "Burnside/Stark", - "routeShortName" : "20", - "routeType" : 3, - "serviceDate" : "2009-11-17", - "startTime" : "2009-11-17T18:27:58.000+00:00", - "steps" : [ ], - "to" : { - "arrival" : "2009-11-17T18:34:00.000+00:00", - "departure" : "2009-11-17T18:34:00.000+00:00", - "lat" : 45.523169, - "lon" : -122.675893, - "name" : "W Burnside & NW 5th", - "stopCode" : "782", - "stopId" : "prt:782", - "stopIndex" : 99, - "stopSequence" : 100, - "vertexType" : "TRANSIT", - "zoneId" : "0" - }, - "transitLeg" : true, - "tripBlockId" : "2071", - "tripId" : "prt:200W1210" - }, - { - "agencyTimeZoneOffset" : -28800000, - "arrivalDelay" : 0, - "departureDelay" : 0, - "distance" : 0.0, - "endTime" : "2009-11-17T18:34:00.000+00:00", - "from" : { - "arrival" : "2009-11-17T18:34:00.000+00:00", - "departure" : "2009-11-17T18:34:00.000+00:00", - "lat" : 45.523169, - "lon" : -122.675893, - "name" : "W Burnside & NW 5th", - "stopCode" : "782", - "stopId" : "prt:782", - "vertexType" : "TRANSIT", - "zoneId" : "0" - }, - "generalizedCost" : 1, - "interlineWithPreviousLeg" : false, - "legElevation" : "", - "legGeometry" : { - "length" : 2, - "points" : "wfztGjcwkVD?" - }, - "mode" : "WALK", - "pathway" : false, - "realTime" : false, - "rentedBike" : false, - "route" : "", - "startTime" : "2009-11-17T18:34:00.000+00:00", - "steps" : [ ], - "to" : { - "arrival" : "2009-11-17T18:34:00.000+00:00", - "departure" : "2009-11-17T18:34:00.000+00:00", - "lat" : 45.5231324, - "lon" : -122.6758917, - "name" : "West Burnside Street", - "vertexType" : "NORMAL" - }, - "transitLeg" : false, - "walkingBike" : false - }, - { - "agencyTimeZoneOffset" : -28800000, - "arrivalDelay" : 0, - "departureDelay" : 0, - "distance" : 1767.93, - "endTime" : "2009-11-17T18:39:16.000+00:00", - "from" : { - "arrival" : "2009-11-17T18:34:00.000+00:00", - "departure" : "2009-11-17T18:34:00.000+00:00", - "lat" : 45.5231324, - "lon" : -122.6758917, - "name" : "West Burnside Street", - "vertexType" : "NORMAL" - }, - "generalizedCost" : 510, - "interlineWithPreviousLeg" : false, - "legGeometry" : { - "length" : 97, - "points" : "qfztGjcwkV@`B?H?BM?iBBI?K?wBBK?K?sBDM@M@sB@K?K?uBBM?K?uBBI@K?aBBSAM@M@K?GBEDEHIJUX_@f@KNQRSVGFCBQPIHGDGBIBK@W@a@?mA@E?C@C@A?CBQTKJEHIJeC~CYZo@v@g@d@IJAFAD?L@vC@hB@p@?X?T@P?N@P@nA?j@AX?L@`B@dA?R?RBbD?T?NBbD?R?P@|D@jB?x@@J?N?B?P?LBjD@N" - }, - "mode" : "CAR", - "pathway" : false, - "realTime" : false, - "rentedBike" : false, - "route" : "", - "startTime" : "2009-11-17T18:34:00.000+00:00", - "steps" : [ - { - "absoluteDirection" : "WEST", - "area" : false, - "bogusName" : false, - "distance" : 44.21, - "elevation" : "", - "lat" : 45.5231324, - "lon" : -122.6758917, - "relativeDirection" : "DEPART", - "stayOn" : false, - "streetName" : "West Burnside Street", - "walkingBike" : false - }, - { - "absoluteDirection" : "NORTH", - "area" : false, - "bogusName" : false, - "distance" : 548.38, - "elevation" : "", - "lat" : 45.5231221, - "lon" : -122.676459, - "relativeDirection" : "RIGHT", - "stayOn" : false, - "streetName" : "Northwest 6th Avenue", - "walkingBike" : false - }, - { - "absoluteDirection" : "NORTH", - "area" : false, - "bogusName" : false, - "distance" : 465.44, - "elevation" : "", - "lat" : 45.5280515, - "lon" : -122.6766232, - "relativeDirection" : "CONTINUE", - "stayOn" : false, - "streetName" : "Northwest Station Way", - "walkingBike" : false - }, - { - "absoluteDirection" : "WEST", - "area" : false, - "bogusName" : false, - "distance" : 709.95, - "elevation" : "", - "lat" : 45.5315452, - "lon" : -122.679511, - "relativeDirection" : "LEFT", - "stayOn" : false, - "streetName" : "Northwest Northrup Street", - "walkingBike" : false - } - ], - "to" : { - "arrival" : "2009-11-17T18:39:16.000+00:00", - "departure" : "2009-11-17T18:39:16.000+00:00", - "lat" : 45.5313992, - "lon" : -122.6886162, - "name" : "corner of Northwest Northrup Street and path", - "vertexType" : "NORMAL" - }, - "transitLeg" : false, - "walkingBike" : false - }, - { - "agencyTimeZoneOffset" : -28800000, - "arrivalDelay" : 0, - "departureDelay" : 0, - "distance" : 70.46, - "endTime" : "2009-11-17T18:41:18.000+00:00", - "from" : { - "arrival" : "2009-11-17T18:39:16.000+00:00", - "departure" : "2009-11-17T18:39:16.000+00:00", - "lat" : 45.5313992, - "lon" : -122.6886162, - "name" : "corner of Northwest Northrup Street and path", - "vertexType" : "NORMAL" - }, - "generalizedCost" : 233, - "interlineWithPreviousLeg" : false, - "legGeometry" : { - "length" : 7, - "points" : "ez{tGzrykVC?I?@nBBH?d@??" - }, - "mode" : "WALK", - "pathway" : false, - "realTime" : false, - "rentedBike" : false, - "route" : "", - "startTime" : "2009-11-17T18:39:16.000+00:00", - "steps" : [ - { - "absoluteDirection" : "NORTH", - "area" : false, - "bogusName" : true, - "distance" : 7.61, - "elevation" : "", - "lat" : 45.5313992, - "lon" : -122.6886162, - "relativeDirection" : "RIGHT", - "stayOn" : false, - "streetName" : "path", - "walkingBike" : false - }, - { - "absoluteDirection" : "WEST", - "area" : false, - "bogusName" : false, - "distance" : 62.85, - "elevation" : "", - "lat" : 45.5314676, - "lon" : -122.6886182, - "relativeDirection" : "LEFT", - "stayOn" : false, - "streetName" : "Northwest Northrup Street", - "walkingBike" : false - } - ], - "to" : { - "arrival" : "2009-11-17T18:41:18.000+00:00", - "departure" : "2009-11-17T18:43:26.000+00:00", - "lat" : 45.531434, - "lon" : -122.689417, - "name" : "NW Northrup & 18th", - "stopCode" : "10776", - "stopId" : "prt:10776", - "vertexType" : "TRANSIT", - "zoneId" : "1" - }, - "transitLeg" : false, - "walkingBike" : false - }, - { - "agencyId" : "prt:prt", - "agencyName" : "TriMet", - "agencyTimeZoneOffset" : -28800000, - "agencyUrl" : "http://trimet.org", - "arrivalDelay" : 0, - "departureDelay" : 0, - "distance" : 547.79, - "endTime" : "2009-11-17T18:45:55.000+00:00", - "from" : { - "arrival" : "2009-11-17T18:41:18.000+00:00", - "departure" : "2009-11-17T18:43:26.000+00:00", - "lat" : 45.531434, - "lon" : -122.689417, - "name" : "NW Northrup & 18th", - "stopCode" : "10776", - "stopId" : "prt:10776", - "stopIndex" : 20, - "stopSequence" : 21, - "vertexType" : "TRANSIT", - "zoneId" : "1" - }, - "generalizedCost" : 877, - "headsign" : "NW 23rd Ave", - "interlineWithPreviousLeg" : false, - "intermediateStops" : [ - { - "arrival" : "2009-11-17T18:45:13.000+00:00", - "departure" : "2009-11-17T18:45:13.000+00:00", - "lat" : 45.531346, - "lon" : -122.694455, - "name" : "NW Northrup & 21st", - "stopCode" : "10777", - "stopId" : "prt:10777", - "stopIndex" : 21, - "stopSequence" : 22, - "vertexType" : "TRANSIT", - "zoneId" : "1" - } - ], - "legGeometry" : { - "length" : 8, - "points" : "cz{tGzwykV?VBhEFtKDvJ??@\\DnJ" - }, - "mode" : "TRAM", - "pathway" : false, - "realTime" : false, - "route" : "Portland Streetcar", - "routeId" : "prt:193", - "routeLongName" : "Portland Streetcar", - "routeType" : 0, - "serviceDate" : "2009-11-17", - "startTime" : "2009-11-17T18:43:26.000+00:00", - "steps" : [ ], - "to" : { - "arrival" : "2009-11-17T18:45:55.000+00:00", - "departure" : "2009-11-17T18:45:55.000+00:00", - "lat" : 45.531308, - "lon" : -122.696445, - "name" : "NW Northrup & 22nd", - "stopCode" : "10778", - "stopId" : "prt:10778", - "stopIndex" : 22, - "stopSequence" : 23, - "vertexType" : "TRANSIT", - "zoneId" : "1" - }, - "transitLeg" : true, - "tripBlockId" : "9385", - "tripId" : "prt:1930W1220" - }, - { - "agencyTimeZoneOffset" : -28800000, - "arrivalDelay" : 0, - "departureDelay" : 0, - "distance" : 18.81, - "endTime" : "2009-11-17T18:46:19.000+00:00", - "from" : { - "arrival" : "2009-11-17T18:45:55.000+00:00", - "departure" : "2009-11-17T18:45:55.000+00:00", - "lat" : 45.531308, - "lon" : -122.696445, - "name" : "NW Northrup & 22nd", - "stopCode" : "10778", - "stopId" : "prt:10778", - "vertexType" : "TRANSIT", - "zoneId" : "1" - }, - "generalizedCost" : 37, - "interlineWithPreviousLeg" : false, - "legGeometry" : { - "length" : 7, - "points" : "sy{tGxc{kV???LABF?B??J" - }, - "mode" : "WALK", - "pathway" : false, - "realTime" : false, - "rentedBike" : false, - "route" : "", - "startTime" : "2009-11-17T18:45:55.000+00:00", - "steps" : [ - { - "absoluteDirection" : "WEST", - "area" : false, - "bogusName" : false, - "distance" : 18.81, - "elevation" : "", - "lat" : 45.5313019, - "lon" : -122.6964448, - "relativeDirection" : "DEPART", - "stayOn" : false, - "streetName" : "Northwest Northrup Street", - "walkingBike" : false - } - ], - "to" : { - "arrival" : "2009-11-17T18:46:19.000+00:00", - "lat" : 45.53122, - "lon" : -122.69659, - "name" : "NW Northrup St. & NW 22nd Ave. (P2)", - "vertexType" : "NORMAL" - }, - "transitLeg" : false, - "walkingBike" : false - } - ], - "startTime" : "2009-11-17T18:19:04.000+00:00", - "tooSloped" : false, - "transfers" : 1, - "transitTime" : 511, - "waitingTime" : 128, - "walkDistance" : 2530.76, - "walkLimitExceeded" : false, - "walkTime" : 996 - } - ] -] \ No newline at end of file From 7aea107162e71b32c672bf1563a78bf378c51c2c Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Tue, 3 Dec 2024 08:21:07 +0100 Subject: [PATCH 43/80] Switch GTFS flex durations back to seconds --- .../java/org/opentripplanner/gtfs/mapping/TripMapper.java | 2 +- .../java/org/opentripplanner/gtfs/mapping/TripMapperTest.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/application/src/main/java/org/opentripplanner/gtfs/mapping/TripMapper.java b/application/src/main/java/org/opentripplanner/gtfs/mapping/TripMapper.java index daf20445767..7b1614aa4d5 100644 --- a/application/src/main/java/org/opentripplanner/gtfs/mapping/TripMapper.java +++ b/application/src/main/java/org/opentripplanner/gtfs/mapping/TripMapper.java @@ -84,7 +84,7 @@ private Optional mapSafeTimePenalty(org.onebusaway.gtfs.model.Trip } else { var offset = rhs.getSafeDurationOffset() == null ? Duration.ZERO - : Duration.ofMinutes(rhs.getSafeDurationOffset().longValue()); + : Duration.ofSeconds(rhs.getSafeDurationOffset().longValue()); var factor = rhs.getSafeDurationFactor() == null ? 1d : rhs.getSafeDurationFactor().doubleValue(); diff --git a/application/src/test/java/org/opentripplanner/gtfs/mapping/TripMapperTest.java b/application/src/test/java/org/opentripplanner/gtfs/mapping/TripMapperTest.java index 4132b73826c..12df141eaf4 100644 --- a/application/src/test/java/org/opentripplanner/gtfs/mapping/TripMapperTest.java +++ b/application/src/test/java/org/opentripplanner/gtfs/mapping/TripMapperTest.java @@ -150,8 +150,8 @@ void testFlexFactorAndOffset( private static Stream provideOffsetAndFactor() { return Stream.of( - Arguments.of(1.5d, 60d, 1.5d, Duration.ofHours(1)), - Arguments.of(null, 120d, 1d, Duration.ofHours(2)), + Arguments.of(1.5d, 60d, 1.5d, Duration.ofMinutes(1)), + Arguments.of(null, 120d, 1d, Duration.ofMinutes(2)), Arguments.of(1.5d, null, 1.5d, Duration.ZERO) ); } From 2aefc16ccb38fc241965faa8fe70e8570c0b6d77 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Tue, 3 Dec 2024 14:46:02 +0100 Subject: [PATCH 44/80] Add English word as well --- .../java/org/opentripplanner/osm/tagmapping/OsmTagMapper.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/application/src/main/java/org/opentripplanner/osm/tagmapping/OsmTagMapper.java b/application/src/main/java/org/opentripplanner/osm/tagmapping/OsmTagMapper.java index 60cd8d0ac74..55bc87f5cad 100644 --- a/application/src/main/java/org/opentripplanner/osm/tagmapping/OsmTagMapper.java +++ b/application/src/main/java/org/opentripplanner/osm/tagmapping/OsmTagMapper.java @@ -103,7 +103,8 @@ public void populateProperties(WayPropertySet props) { props.setProperties("highway=trunk", withModes(CAR).bicycleSafety(7.47)); props.setProperties("highway=motorway", withModes(CAR).bicycleSafety(8)); - // Do not walk on "moottoriliikennetie"/"Kraftfahrstrasse" + // Do not walk on "moottoriliikennetie"/"Kraftfahrstrasse"/"Limited access road" + // https://en.wikipedia.org/wiki/Limited-access_road props.setProperties(new ExactMatchSpecifier("motorroad=yes"), withModes(CAR)); /* cycleway=lane */ From 3c4f03a93e45320a712ad37f315d0323816eaf7a Mon Sep 17 00:00:00 2001 From: OTP Changelog Bot Date: Tue, 3 Dec 2024 13:54:26 +0000 Subject: [PATCH 45/80] Add changelog entry for #6288 [ci skip] --- doc/user/Changelog.md | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/user/Changelog.md b/doc/user/Changelog.md index 17a54ede4ae..c1fb8d42d13 100644 --- a/doc/user/Changelog.md +++ b/doc/user/Changelog.md @@ -54,6 +54,7 @@ based on merged pull requests. Search GitHub issues and pull requests for smalle - Fix problem with relaxed-generalized-cost-at-destination [#6255](https://github.com/opentripplanner/OpenTripPlanner/pull/6255) - Reject SIRI-ET updates with empty StopPointRefs [#6266](https://github.com/opentripplanner/OpenTripPlanner/pull/6266) - Allow GTFS fuzzy trip matching even when trip descriptor has an id [#6250](https://github.com/opentripplanner/OpenTripPlanner/pull/6250) +- Make `motorroad=yes` car-only [#6288](https://github.com/opentripplanner/OpenTripPlanner/pull/6288) [](AUTOMATIC_CHANGELOG_PLACEHOLDER_DO_NOT_REMOVE) ## 2.6.0 (2024-09-18) From 69e6f64f2566a58a81fa7d67c128bfd66041fdb7 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 3 Dec 2024 17:42:32 +0000 Subject: [PATCH 46/80] chore(deps): update debug ui dependencies (non-major) --- client/package-lock.json | 263 ++++++++++++++++++++++----------------- client/package.json | 16 +-- 2 files changed, 159 insertions(+), 120 deletions(-) diff --git a/client/package-lock.json b/client/package-lock.json index 36c05bdf4f1..bbed0b8e4fa 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -15,13 +15,13 @@ "graphql-request": "7.1.2", "maplibre-gl": "4.7.1", "react": "18.3.1", - "react-bootstrap": "2.10.5", + "react-bootstrap": "2.10.6", "react-dom": "18.3.1", "react-map-gl": "7.1.7" }, "devDependencies": { "@graphql-codegen/cli": "5.0.3", - "@graphql-codegen/client-preset": "4.5.0", + "@graphql-codegen/client-preset": "4.5.1", "@graphql-codegen/introspection": "4.0.3", "@parcel/watcher": "2.5.0", "@testing-library/react": "16.0.1", @@ -30,19 +30,19 @@ "@typescript-eslint/eslint-plugin": "7.18.0", "@typescript-eslint/parser": "7.18.0", "@vitejs/plugin-react": "4.3.4", - "@vitest/coverage-v8": "2.1.5", + "@vitest/coverage-v8": "2.1.8", "eslint": "8.57.1", "eslint-config-prettier": "9.1.0", "eslint-plugin-import": "2.31.0", "eslint-plugin-jsx-a11y": "6.10.2", "eslint-plugin-react": "7.37.2", "eslint-plugin-react-hooks": "5.0.0", - "eslint-plugin-react-refresh": "0.4.14", + "eslint-plugin-react-refresh": "0.4.16", "jsdom": "25.0.1", - "prettier": "3.3.3", - "typescript": "5.6.3", - "vite": "6.0.1", - "vitest": "2.1.5" + "prettier": "3.4.1", + "typescript": "5.7.2", + "vite": "6.0.2", + "vitest": "2.1.8" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -989,9 +989,9 @@ } }, "node_modules/@babel/runtime": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.7.tgz", - "integrity": "sha512-UwgBRMjJP+xv857DCngvqXI3Iq6J4v0wXmwc6sapg+zyhbwmQX67LUEFrkK5tbyJ30jGuG3ZvWpBiB9LCy1kWw==", + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.0.tgz", + "integrity": "sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw==", "license": "MIT", "dependencies": { "regenerator-runtime": "^0.14.0" @@ -1623,21 +1623,21 @@ } }, "node_modules/@graphql-codegen/client-preset": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/@graphql-codegen/client-preset/-/client-preset-4.5.0.tgz", - "integrity": "sha512-0fFGSjpDhB7Jp6v+FQWDIeNJhL8VEiy3zeazyus3mGUELPaRQsoos2NczkDWnyMjSB1NHn4GrI53DB4TXkTAog==", + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/@graphql-codegen/client-preset/-/client-preset-4.5.1.tgz", + "integrity": "sha512-UE2/Kz2eaxv35HIXFwlm2QwoUH77am6+qp54aeEWYq+T+WPwmIc6+YzqtGiT/VcaXgoOUSgidREGm9R6jKcf9g==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.20.2", "@babel/template": "^7.20.7", "@graphql-codegen/add": "^5.0.3", - "@graphql-codegen/gql-tag-operations": "4.0.11", + "@graphql-codegen/gql-tag-operations": "4.0.12", "@graphql-codegen/plugin-helpers": "^5.1.0", - "@graphql-codegen/typed-document-node": "^5.0.11", - "@graphql-codegen/typescript": "^4.1.1", - "@graphql-codegen/typescript-operations": "^4.3.1", - "@graphql-codegen/visitor-plugin-common": "^5.5.0", + "@graphql-codegen/typed-document-node": "^5.0.12", + "@graphql-codegen/typescript": "^4.1.2", + "@graphql-codegen/typescript-operations": "^4.4.0", + "@graphql-codegen/visitor-plugin-common": "^5.6.0", "@graphql-tools/documents": "^1.0.0", "@graphql-tools/utils": "^10.0.0", "@graphql-typed-document-node/core": "3.2.0", @@ -1666,14 +1666,14 @@ } }, "node_modules/@graphql-codegen/gql-tag-operations": { - "version": "4.0.11", - "resolved": "https://registry.npmjs.org/@graphql-codegen/gql-tag-operations/-/gql-tag-operations-4.0.11.tgz", - "integrity": "sha512-EUQuBsYB5RtNlzBb/O0nJvbWC8HvPRWwVTHRf0ElOoQlJfRgfDom2GWmEM5hXa2afzMqB7AWxOH24ibOqiYnMQ==", + "version": "4.0.12", + "resolved": "https://registry.npmjs.org/@graphql-codegen/gql-tag-operations/-/gql-tag-operations-4.0.12.tgz", + "integrity": "sha512-v279i49FJ5dMmQXIGUgm6FtnnkxtJjVJWDNYh9JK4ppvOixdHp+PmEzW227DkLN6avhVxNnYdp/1gdRBwdWypw==", "dev": true, "license": "MIT", "dependencies": { "@graphql-codegen/plugin-helpers": "^5.1.0", - "@graphql-codegen/visitor-plugin-common": "5.5.0", + "@graphql-codegen/visitor-plugin-common": "5.6.0", "@graphql-tools/utils": "^10.0.0", "auto-bind": "~4.0.0", "tslib": "~2.6.0" @@ -1736,14 +1736,14 @@ } }, "node_modules/@graphql-codegen/typed-document-node": { - "version": "5.0.11", - "resolved": "https://registry.npmjs.org/@graphql-codegen/typed-document-node/-/typed-document-node-5.0.11.tgz", - "integrity": "sha512-btENKrSIUZ5UllS8sFhVZ+Y91VL0knK9gHxW/6/WzaCTxBQ+wOk07vQNeoWlvMrkl0QeUsGt6YvSo0SoPtsKdA==", + "version": "5.0.12", + "resolved": "https://registry.npmjs.org/@graphql-codegen/typed-document-node/-/typed-document-node-5.0.12.tgz", + "integrity": "sha512-Wsbc1AqC+MFp3maWPzrmmyHLuWCPB63qBBFLTKtO6KSsnn0KnLocBp475wkfBZnFISFvzwpJ0e6LV71gKfTofQ==", "dev": true, "license": "MIT", "dependencies": { "@graphql-codegen/plugin-helpers": "^5.1.0", - "@graphql-codegen/visitor-plugin-common": "5.5.0", + "@graphql-codegen/visitor-plugin-common": "5.6.0", "auto-bind": "~4.0.0", "change-case-all": "1.0.15", "tslib": "~2.6.0" @@ -1756,15 +1756,15 @@ } }, "node_modules/@graphql-codegen/typescript": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/@graphql-codegen/typescript/-/typescript-4.1.1.tgz", - "integrity": "sha512-+o5LOT71K9hdO4lDVnRGkkET5RdlKvxlQGug8dZgRGrhE2/xoPBsKfLhg9AoJGYMauNZxKj3blABQxHOKEku6Q==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/@graphql-codegen/typescript/-/typescript-4.1.2.tgz", + "integrity": "sha512-GhPgfxgWEkBrvKR2y77OThus3K8B6U3ESo68l7+sHH1XiL2WapK5DdClViblJWKQerJRjfJu8tcaxQ8Wpk6Ogw==", "dev": true, "license": "MIT", "dependencies": { "@graphql-codegen/plugin-helpers": "^5.1.0", "@graphql-codegen/schema-ast": "^4.0.2", - "@graphql-codegen/visitor-plugin-common": "5.5.0", + "@graphql-codegen/visitor-plugin-common": "5.6.0", "auto-bind": "~4.0.0", "tslib": "~2.6.0" }, @@ -1776,15 +1776,15 @@ } }, "node_modules/@graphql-codegen/typescript-operations": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@graphql-codegen/typescript-operations/-/typescript-operations-4.3.1.tgz", - "integrity": "sha512-yW5Iia6IK1VKiPm3oeukYMQN5pEBLwRlG8ZzQA9beeLQ8PskKyz6mjar6U7dJ2hc8pv/qT4R8kcJOQ2RloniAQ==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@graphql-codegen/typescript-operations/-/typescript-operations-4.4.0.tgz", + "integrity": "sha512-oVlos2ySx8xIbbe8r5ZI6mOpI+OTeP14RmS2MchBJ6DL+S9G16O6+9V3Y8V22fTnmBTZkTfAAaBv4HYhhDGWVA==", "dev": true, "license": "MIT", "dependencies": { "@graphql-codegen/plugin-helpers": "^5.1.0", - "@graphql-codegen/typescript": "^4.1.1", - "@graphql-codegen/visitor-plugin-common": "5.5.0", + "@graphql-codegen/typescript": "^4.1.2", + "@graphql-codegen/visitor-plugin-common": "5.6.0", "auto-bind": "~4.0.0", "tslib": "~2.6.0" }, @@ -1796,9 +1796,9 @@ } }, "node_modules/@graphql-codegen/visitor-plugin-common": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@graphql-codegen/visitor-plugin-common/-/visitor-plugin-common-5.5.0.tgz", - "integrity": "sha512-FSkxe/o4qKbpK+ipIT/jxZLYH0+3+XdIrJWsKlCW9wwJMF9mEJLJtzZNcxHSjz7+Eny6SUElAT2dqZ5XByxkog==", + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@graphql-codegen/visitor-plugin-common/-/visitor-plugin-common-5.6.0.tgz", + "integrity": "sha512-PowcVPJbUqMC9xTJ/ZRX1p/fsdMZREc+69CM1YY+AlFng2lL0zsdBskFJSRoviQk2Ch9IPhKGyHxlJCy9X22tg==", "dev": true, "license": "MIT", "dependencies": { @@ -3008,19 +3008,19 @@ } }, "node_modules/@restart/ui": { - "version": "1.6.9", - "resolved": "https://registry.npmjs.org/@restart/ui/-/ui-1.6.9.tgz", - "integrity": "sha512-mUbygUsJcRurjZCt1f77gg4DpheD1D+Sc7J3JjAkysUj7t8m4EBJVOqWC9788Qtbc69cJ+HlJc6jBguKwS8Mcw==", + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@restart/ui/-/ui-1.9.1.tgz", + "integrity": "sha512-qghR21ynHiUrpcIkKCoKYB+3rJtezY5Y7ikrwradCL+7hZHdQ2Ozc5ffxtpmpahoAGgc31gyXaSx2sXXaThmqA==", "license": "MIT", "dependencies": { - "@babel/runtime": "^7.21.0", - "@popperjs/core": "^2.11.6", + "@babel/runtime": "^7.26.0", + "@popperjs/core": "^2.11.8", "@react-aria/ssr": "^3.5.0", - "@restart/hooks": "^0.4.9", - "@types/warning": "^3.0.0", + "@restart/hooks": "^0.5.0", + "@types/warning": "^3.0.3", "dequal": "^2.0.3", "dom-helpers": "^5.2.0", - "uncontrollable": "^8.0.1", + "uncontrollable": "^8.0.4", "warning": "^4.0.3" }, "peerDependencies": { @@ -3028,6 +3028,18 @@ "react-dom": ">=16.14.0" } }, + "node_modules/@restart/ui/node_modules/@restart/hooks": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@restart/hooks/-/hooks-0.5.0.tgz", + "integrity": "sha512-wS+h6IusJCPjTkmOOrRZxIPICD/mtFA3PRZviutoM23/b7akyDGfZF/WS+nIFk27u7JDhPE2+0GBdZxjSqHZkg==", + "license": "MIT", + "dependencies": { + "dequal": "^2.0.3" + }, + "peerDependencies": { + "react": ">=16.8.0" + } + }, "node_modules/@restart/ui/node_modules/uncontrollable": { "version": "8.0.4", "resolved": "https://registry.npmjs.org/uncontrollable/-/uncontrollable-8.0.4.tgz", @@ -3742,9 +3754,9 @@ } }, "node_modules/@vitest/coverage-v8": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-2.1.5.tgz", - "integrity": "sha512-/RoopB7XGW7UEkUndRXF87A9CwkoZAJW01pj8/3pgmDVsjMH2IKy6H1A38po9tmUlwhSyYs0az82rbKd9Yaynw==", + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-2.1.8.tgz", + "integrity": "sha512-2Y7BPlKH18mAZYAW1tYByudlCYrQyl5RGvnnDYJKW5tCiO5qg3KSAy3XAxcxKz900a0ZXxWtKrMuZLe3lKBpJw==", "dev": true, "license": "MIT", "dependencies": { @@ -3765,8 +3777,8 @@ "url": "https://opencollective.com/vitest" }, "peerDependencies": { - "@vitest/browser": "2.1.5", - "vitest": "2.1.5" + "@vitest/browser": "2.1.8", + "vitest": "2.1.8" }, "peerDependenciesMeta": { "@vitest/browser": { @@ -3775,14 +3787,14 @@ } }, "node_modules/@vitest/expect": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-2.1.5.tgz", - "integrity": "sha512-nZSBTW1XIdpZvEJyoP/Sy8fUg0b8od7ZpGDkTUcfJ7wz/VoZAFzFfLyxVxGFhUjJzhYqSbIpfMtl/+k/dpWa3Q==", + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-2.1.8.tgz", + "integrity": "sha512-8ytZ/fFHq2g4PJVAtDX57mayemKgDR6X3Oa2Foro+EygiOJHUXhCqBAAKQYYajZpFoIfvBCF1j6R6IYRSIUFuw==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/spy": "2.1.5", - "@vitest/utils": "2.1.5", + "@vitest/spy": "2.1.8", + "@vitest/utils": "2.1.8", "chai": "^5.1.2", "tinyrainbow": "^1.2.0" }, @@ -3791,9 +3803,9 @@ } }, "node_modules/@vitest/pretty-format": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-2.1.5.tgz", - "integrity": "sha512-4ZOwtk2bqG5Y6xRGHcveZVr+6txkH7M2e+nPFd6guSoN638v/1XQ0K06eOpi0ptVU/2tW/pIU4IoPotY/GZ9fw==", + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-2.1.8.tgz", + "integrity": "sha512-9HiSZ9zpqNLKlbIDRWOnAWqgcA7xu+8YxXSekhr0Ykab7PAYFkhkwoqVArPOtJhPmYeE2YHgKZlj3CP36z2AJQ==", "dev": true, "license": "MIT", "dependencies": { @@ -3804,13 +3816,13 @@ } }, "node_modules/@vitest/runner": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-2.1.5.tgz", - "integrity": "sha512-pKHKy3uaUdh7X6p1pxOkgkVAFW7r2I818vHDthYLvUyjRfkKOU6P45PztOch4DZarWQne+VOaIMwA/erSSpB9g==", + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-2.1.8.tgz", + "integrity": "sha512-17ub8vQstRnRlIU5k50bG+QOMLHRhYPAna5tw8tYbj+jzjcspnwnwtPtiOlkuKC4+ixDPTuLZiqiWWQ2PSXHVg==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/utils": "2.1.5", + "@vitest/utils": "2.1.8", "pathe": "^1.1.2" }, "funding": { @@ -3818,13 +3830,13 @@ } }, "node_modules/@vitest/snapshot": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-2.1.5.tgz", - "integrity": "sha512-zmYw47mhfdfnYbuhkQvkkzYroXUumrwWDGlMjpdUr4jBd3HZiV2w7CQHj+z7AAS4VOtWxI4Zt4bWt4/sKcoIjg==", + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-2.1.8.tgz", + "integrity": "sha512-20T7xRFbmnkfcmgVEz+z3AU/3b0cEzZOt/zmnvZEctg64/QZbSDJEVm9fLnnlSi74KibmRsO9/Qabi+t0vCRPg==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "2.1.5", + "@vitest/pretty-format": "2.1.8", "magic-string": "^0.30.12", "pathe": "^1.1.2" }, @@ -3833,9 +3845,9 @@ } }, "node_modules/@vitest/spy": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-2.1.5.tgz", - "integrity": "sha512-aWZF3P0r3w6DiYTVskOYuhBc7EMc3jvn1TkBg8ttylFFRqNN2XGD7V5a4aQdk6QiUzZQ4klNBSpCLJgWNdIiNw==", + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-2.1.8.tgz", + "integrity": "sha512-5swjf2q95gXeYPevtW0BLk6H8+bPlMb4Vw/9Em4hFxDcaOxS+e0LOX4yqNxoHzMR2akEB2xfpnWUzkZokmgWDg==", "dev": true, "license": "MIT", "dependencies": { @@ -3846,13 +3858,13 @@ } }, "node_modules/@vitest/utils": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-2.1.5.tgz", - "integrity": "sha512-yfj6Yrp0Vesw2cwJbP+cl04OC+IHFsuQsrsJBL9pyGeQXE56v1UAOQco+SR55Vf1nQzfV0QJg1Qum7AaWUwwYg==", + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-2.1.8.tgz", + "integrity": "sha512-dwSoui6djdwbfFmIgbIjX2ZhIoG7Ex/+xpxyiEgIGzjliY8xGkcpITKTlp6B4MgtGkF2ilvm97cPM96XZaAgcA==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "2.1.5", + "@vitest/pretty-format": "2.1.8", "loupe": "^3.1.2", "tinyrainbow": "^1.2.0" }, @@ -5792,13 +5804,13 @@ } }, "node_modules/eslint-plugin-react-refresh": { - "version": "0.4.14", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.14.tgz", - "integrity": "sha512-aXvzCTK7ZBv1e7fahFuR3Z/fyQQSIQ711yPgYRj+Oj64tyTgO4iQIDmYXDBqvSWQ/FA4OSCsXOStlF+noU0/NA==", + "version": "0.4.16", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.16.tgz", + "integrity": "sha512-slterMlxAhov/DZO8NScf6mEeMBBXodFUolijDvrtTxyezyLoTQaa73FyYus/VbTdftd8wBgBxPMRk3poleXNQ==", "dev": true, "license": "MIT", "peerDependencies": { - "eslint": ">=7" + "eslint": ">=8.40" } }, "node_modules/eslint-plugin-react/node_modules/brace-expansion": { @@ -8896,9 +8908,9 @@ } }, "node_modules/prettier": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.3.tgz", - "integrity": "sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==", + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.4.1.tgz", + "integrity": "sha512-G+YdqtITVZmOJje6QkXQWzl3fSfMxFwm1tjTyo9exhkmWSqC4Yhd1+lug++IlR2mvRVAxEDDWYkQdeSztajqgg==", "dev": true, "license": "MIT", "bin": { @@ -9022,14 +9034,14 @@ } }, "node_modules/react-bootstrap": { - "version": "2.10.5", - "resolved": "https://registry.npmjs.org/react-bootstrap/-/react-bootstrap-2.10.5.tgz", - "integrity": "sha512-XueAOEn64RRkZ0s6yzUTdpFtdUXs5L5491QU//8ZcODKJNDLt/r01tNyriZccjgRImH1REynUc9pqjiRMpDLWQ==", + "version": "2.10.6", + "resolved": "https://registry.npmjs.org/react-bootstrap/-/react-bootstrap-2.10.6.tgz", + "integrity": "sha512-fNvKytSp0nHts1WRnRBJeBEt+I9/ZdrnhIjWOucEduRNvFRU1IXjZueDdWnBiqsTSJ7MckQJi9i/hxGolaRq+g==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.24.7", "@restart/hooks": "^0.4.9", - "@restart/ui": "^1.6.9", + "@restart/ui": "^1.9.0", "@types/react-transition-group": "^4.4.6", "classnames": "^2.3.2", "dom-helpers": "^5.2.1", @@ -10374,9 +10386,9 @@ } }, "node_modules/typescript": { - "version": "5.6.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz", - "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==", + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.2.tgz", + "integrity": "sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==", "dev": true, "license": "Apache-2.0", "bin": { @@ -10583,10 +10595,11 @@ } }, "node_modules/vite": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/vite/-/vite-6.0.1.tgz", - "integrity": "sha512-Ldn6gorLGr4mCdFnmeAOLweJxZ34HjKnDm4HGo6P66IEqTxQb36VEdFJQENKxWjupNfoIjvRUnswjn1hpYEpjQ==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/vite/-/vite-6.0.2.tgz", + "integrity": "sha512-XdQ+VsY2tJpBsKGs0wf3U/+azx8BBpYRHFAyKm5VeEZNOJZRB63q7Sc8Iup3k0TrN3KO6QgyzFf+opSbfY1y0g==", "dev": true, + "license": "MIT", "dependencies": { "esbuild": "^0.24.0", "postcss": "^8.4.49", @@ -10654,9 +10667,9 @@ } }, "node_modules/vite-node": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-2.1.5.tgz", - "integrity": "sha512-rd0QIgx74q4S1Rd56XIiL2cYEdyWn13cunYBIuqh9mpmQr7gGS0IxXoP8R6OaZtNQQLyXSWbd4rXKYUbhFpK5w==", + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-2.1.8.tgz", + "integrity": "sha512-uPAwSr57kYjAUux+8E2j0q0Fxpn8M9VoyfGiRI8Kfktz9NcYMCenwY5RnZxnF1WTu3TGiYipirIzacLL3VVGFg==", "dev": true, "license": "MIT", "dependencies": { @@ -11142,19 +11155,19 @@ } }, "node_modules/vitest": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-2.1.5.tgz", - "integrity": "sha512-P4ljsdpuzRTPI/kbND2sDZ4VmieerR2c9szEZpjc+98Z9ebvnXmM5+0tHEKqYZumXqlvnmfWsjeFOjXVriDG7A==", + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-2.1.8.tgz", + "integrity": "sha512-1vBKTZskHw/aosXqQUlVWWlGUxSJR8YtiyZDJAFeW2kPAeX6S3Sool0mjspO+kXLuxVWlEDDowBAeqeAQefqLQ==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/expect": "2.1.5", - "@vitest/mocker": "2.1.5", - "@vitest/pretty-format": "^2.1.5", - "@vitest/runner": "2.1.5", - "@vitest/snapshot": "2.1.5", - "@vitest/spy": "2.1.5", - "@vitest/utils": "2.1.5", + "@vitest/expect": "2.1.8", + "@vitest/mocker": "2.1.8", + "@vitest/pretty-format": "^2.1.8", + "@vitest/runner": "2.1.8", + "@vitest/snapshot": "2.1.8", + "@vitest/spy": "2.1.8", + "@vitest/utils": "2.1.8", "chai": "^5.1.2", "debug": "^4.3.7", "expect-type": "^1.1.0", @@ -11166,7 +11179,7 @@ "tinypool": "^1.0.1", "tinyrainbow": "^1.2.0", "vite": "^5.0.0", - "vite-node": "2.1.5", + "vite-node": "2.1.8", "why-is-node-running": "^2.3.0" }, "bin": { @@ -11181,8 +11194,8 @@ "peerDependencies": { "@edge-runtime/vm": "*", "@types/node": "^18.0.0 || >=20.0.0", - "@vitest/browser": "2.1.5", - "@vitest/ui": "2.1.5", + "@vitest/browser": "2.1.8", + "@vitest/ui": "2.1.8", "happy-dom": "*", "jsdom": "*" }, @@ -11215,6 +11228,7 @@ "ppc64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "aix" @@ -11231,6 +11245,7 @@ "arm" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "android" @@ -11247,6 +11262,7 @@ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "android" @@ -11263,6 +11279,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "android" @@ -11279,6 +11296,7 @@ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" @@ -11295,6 +11313,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" @@ -11311,6 +11330,7 @@ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "freebsd" @@ -11327,6 +11347,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "freebsd" @@ -11343,6 +11364,7 @@ "arm" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -11359,6 +11381,7 @@ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -11375,6 +11398,7 @@ "ia32" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -11391,6 +11415,7 @@ "loong64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -11407,6 +11432,7 @@ "mips64el" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -11423,6 +11449,7 @@ "ppc64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -11439,6 +11466,7 @@ "riscv64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -11455,6 +11483,7 @@ "s390x" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -11471,6 +11500,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -11487,6 +11517,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "netbsd" @@ -11503,6 +11534,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "openbsd" @@ -11519,6 +11551,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "sunos" @@ -11535,6 +11568,7 @@ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" @@ -11551,6 +11585,7 @@ "ia32" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" @@ -11567,6 +11602,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" @@ -11576,12 +11612,13 @@ } }, "node_modules/vitest/node_modules/@vitest/mocker": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-2.1.5.tgz", - "integrity": "sha512-XYW6l3UuBmitWqSUXTNXcVBUCRytDogBsWuNXQijc00dtnU/9OqpXWp4OJroVrad/gLIomAq9aW8yWDBtMthhQ==", + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-2.1.8.tgz", + "integrity": "sha512-7guJ/47I6uqfttp33mgo6ga5Gr1VnL58rcqYKyShoRK9ebu8T5Rs6HN3s1NABiBeVTdWNrwUMcHH54uXZBN4zA==", "dev": true, + "license": "MIT", "dependencies": { - "@vitest/spy": "2.1.5", + "@vitest/spy": "2.1.8", "estree-walker": "^3.0.3", "magic-string": "^0.30.12" }, @@ -11607,6 +11644,7 @@ "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", "dev": true, "hasInstallScript": true, + "license": "MIT", "bin": { "esbuild": "bin/esbuild" }, @@ -11644,6 +11682,7 @@ "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.11.tgz", "integrity": "sha512-c7jFQRklXua0mTzneGW9QVyxFjUgwcihC4bXEtujIo2ouWCe1Ajt/amn2PCxYnhYfd5k09JX3SB7OYWFKYqj8Q==", "dev": true, + "license": "MIT", "dependencies": { "esbuild": "^0.21.3", "postcss": "^8.4.43", diff --git a/client/package.json b/client/package.json index 57320f35540..f930bcd67d5 100644 --- a/client/package.json +++ b/client/package.json @@ -24,13 +24,13 @@ "graphql-request": "7.1.2", "maplibre-gl": "4.7.1", "react": "18.3.1", - "react-bootstrap": "2.10.5", + "react-bootstrap": "2.10.6", "react-dom": "18.3.1", "react-map-gl": "7.1.7" }, "devDependencies": { "@graphql-codegen/cli": "5.0.3", - "@graphql-codegen/client-preset": "4.5.0", + "@graphql-codegen/client-preset": "4.5.1", "@graphql-codegen/introspection": "4.0.3", "@parcel/watcher": "2.5.0", "@testing-library/react": "16.0.1", @@ -39,18 +39,18 @@ "@typescript-eslint/eslint-plugin": "7.18.0", "@typescript-eslint/parser": "7.18.0", "@vitejs/plugin-react": "4.3.4", - "@vitest/coverage-v8": "2.1.5", + "@vitest/coverage-v8": "2.1.8", "eslint": "8.57.1", "eslint-config-prettier": "9.1.0", "eslint-plugin-import": "2.31.0", "eslint-plugin-jsx-a11y": "6.10.2", "eslint-plugin-react": "7.37.2", "eslint-plugin-react-hooks": "5.0.0", - "eslint-plugin-react-refresh": "0.4.14", + "eslint-plugin-react-refresh": "0.4.16", "jsdom": "25.0.1", - "prettier": "3.3.3", - "typescript": "5.6.3", - "vite": "6.0.1", - "vitest": "2.1.5" + "prettier": "3.4.1", + "typescript": "5.7.2", + "vite": "6.0.2", + "vitest": "2.1.8" } } From 4a61e111ed779810462623437c742228b7cb1288 Mon Sep 17 00:00:00 2001 From: OTP Changelog Bot Date: Wed, 4 Dec 2024 00:34:22 +0000 Subject: [PATCH 47/80] Add changelog entry for #6281 [ci skip] --- doc/user/Changelog.md | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/user/Changelog.md b/doc/user/Changelog.md index c1fb8d42d13..e216ef85fe0 100644 --- a/doc/user/Changelog.md +++ b/doc/user/Changelog.md @@ -55,6 +55,7 @@ based on merged pull requests. Search GitHub issues and pull requests for smalle - Reject SIRI-ET updates with empty StopPointRefs [#6266](https://github.com/opentripplanner/OpenTripPlanner/pull/6266) - Allow GTFS fuzzy trip matching even when trip descriptor has an id [#6250](https://github.com/opentripplanner/OpenTripPlanner/pull/6250) - Make `motorroad=yes` car-only [#6288](https://github.com/opentripplanner/OpenTripPlanner/pull/6288) +- Add decision record for analysis and design documentation [#6281](https://github.com/opentripplanner/OpenTripPlanner/pull/6281) [](AUTOMATIC_CHANGELOG_PLACEHOLDER_DO_NOT_REMOVE) ## 2.6.0 (2024-09-18) From 2de435c42ec9b82fd11b908f2c232d8e072dc9cb Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Wed, 4 Dec 2024 08:14:18 +0100 Subject: [PATCH 48/80] Apply new format --- .../src/components/ItineraryList/ItineraryLegDetails.tsx | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/client/src/components/ItineraryList/ItineraryLegDetails.tsx b/client/src/components/ItineraryList/ItineraryLegDetails.tsx index d23563331b5..65d790902a8 100644 --- a/client/src/components/ItineraryList/ItineraryLegDetails.tsx +++ b/client/src/components/ItineraryList/ItineraryLegDetails.tsx @@ -24,8 +24,11 @@ export function ItineraryLegDetails({ leg, isLast }: { leg: Leg; isLast: boolean {formatDistance(leg.distance)}, {formatDuration(leg.duration)} - -{' '} - + -
{leg.mode}{' '} {leg.line && ( From 8395345b2483909862baf459c5fce0ae934f8bc8 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Wed, 4 Dec 2024 08:15:09 +0100 Subject: [PATCH 49/80] DebugUiConfig doesn't need to be Serializable --- .../org/opentripplanner/standalone/config/DebugUiConfig.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/application/src/main/java/org/opentripplanner/standalone/config/DebugUiConfig.java b/application/src/main/java/org/opentripplanner/standalone/config/DebugUiConfig.java index 165bcfe28f4..00f59cd342b 100644 --- a/application/src/main/java/org/opentripplanner/standalone/config/DebugUiConfig.java +++ b/application/src/main/java/org/opentripplanner/standalone/config/DebugUiConfig.java @@ -4,7 +4,6 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.MissingNode; -import java.io.Serializable; import java.util.List; import org.opentripplanner.standalone.config.debuguiconfig.BackgroundTileLayer; import org.opentripplanner.standalone.config.framework.json.NodeAdapter; @@ -14,7 +13,7 @@ /** * This class is an object representation of the 'debug-ui-config.json'. */ -public class DebugUiConfig implements Serializable { +public class DebugUiConfig { private static final Logger LOG = LoggerFactory.getLogger(DebugUiConfig.class); From d831ec4943c8888d308064e85188ddf5d5e369d5 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Wed, 4 Dec 2024 08:15:30 +0100 Subject: [PATCH 50/80] Update application/src/main/java/org/opentripplanner/standalone/config/DebugUiConfig.java Co-authored-by: Joel Lappalainen --- .../org/opentripplanner/standalone/config/DebugUiConfig.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/src/main/java/org/opentripplanner/standalone/config/DebugUiConfig.java b/application/src/main/java/org/opentripplanner/standalone/config/DebugUiConfig.java index 00f59cd342b..079ba8ea84c 100644 --- a/application/src/main/java/org/opentripplanner/standalone/config/DebugUiConfig.java +++ b/application/src/main/java/org/opentripplanner/standalone/config/DebugUiConfig.java @@ -46,7 +46,7 @@ public DebugUiConfig(JsonNode node, String source, boolean logUnusedParams) { """ Add additional background layers that will appear in the Debug UI as one of the choices. - Current only raster tile layers are supported. + Currently only raster tile layers are supported. """ ) .asObjects( From 2ac997f8e3cefe497761361af41b4e4372418809 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Wed, 4 Dec 2024 08:20:26 +0100 Subject: [PATCH 51/80] Update docs --- doc/user/DebugUiConfiguration.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/user/DebugUiConfiguration.md b/doc/user/DebugUiConfiguration.md index 5719a606d4a..a1657796fe0 100644 --- a/doc/user/DebugUiConfiguration.md +++ b/doc/user/DebugUiConfiguration.md @@ -39,7 +39,7 @@ Additional background raster map layers. Add additional background layers that will appear in the Debug UI as one of the choices. -Current only raster tile layers are supported. +Currently only raster tile layers are supported. From a83afac6bbd88958562e35d8858c0bff717ed7f5 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Wed, 4 Dec 2024 08:21:34 +0100 Subject: [PATCH 52/80] Remove check for LOG.isWarnEnabled() --- .../org/opentripplanner/standalone/config/DebugUiConfig.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/src/main/java/org/opentripplanner/standalone/config/DebugUiConfig.java b/application/src/main/java/org/opentripplanner/standalone/config/DebugUiConfig.java index 079ba8ea84c..cca6d2359be 100644 --- a/application/src/main/java/org/opentripplanner/standalone/config/DebugUiConfig.java +++ b/application/src/main/java/org/opentripplanner/standalone/config/DebugUiConfig.java @@ -77,7 +77,7 @@ public DebugUiConfig(JsonNode node, String source, boolean logUnusedParams) { ) ); - if (logUnusedParams && LOG.isWarnEnabled()) { + if (logUnusedParams) { root.logAllWarnings(LOG::warn); } } From 27b18bd07ee13dc848eb84e3b3354c9f668b9682 Mon Sep 17 00:00:00 2001 From: OTP Bot Date: Wed, 4 Dec 2024 08:22:57 +0000 Subject: [PATCH 53/80] Upgrade debug client to version 2024/12/2024-12-04T08:22 --- application/src/client/index.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/application/src/client/index.html b/application/src/client/index.html index 19ee598b816..391458fba41 100644 --- a/application/src/client/index.html +++ b/application/src/client/index.html @@ -5,8 +5,8 @@ OTP Debug Client - - + +
From 20696c1d6e78902f8dd9d1e6ba31de993caf7789 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Wed, 4 Dec 2024 09:56:39 +0100 Subject: [PATCH 54/80] Use 'OTP Debug' in the UI --- client/index.html | 2 +- client/src/components/SearchBar/SearchBar.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/client/index.html b/client/index.html index 77eb289e595..f09832636f0 100644 --- a/client/index.html +++ b/client/index.html @@ -4,7 +4,7 @@ - OTP Debug Client + OTP Debug
diff --git a/client/src/components/SearchBar/SearchBar.tsx b/client/src/components/SearchBar/SearchBar.tsx index 47781532179..e90a54eab80 100644 --- a/client/src/components/SearchBar/SearchBar.tsx +++ b/client/src/components/SearchBar/SearchBar.tsx @@ -34,7 +34,7 @@ export function SearchBar({ onRoute, tripQueryVariables, setTripQueryVariables,
setShowServerInfo((v) => !v)}>
- OTP Debug Client + OTP Debug {showServerInfo && }
From 20502170aa7a195ce4f557c59c463414d05fd702 Mon Sep 17 00:00:00 2001 From: OTP Changelog Bot Date: Wed, 4 Dec 2024 13:42:31 +0000 Subject: [PATCH 55/80] Add changelog entry for #6298 [ci skip] --- doc/user/Changelog.md | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/user/Changelog.md b/doc/user/Changelog.md index e216ef85fe0..f6f9a55fb77 100644 --- a/doc/user/Changelog.md +++ b/doc/user/Changelog.md @@ -56,6 +56,7 @@ based on merged pull requests. Search GitHub issues and pull requests for smalle - Allow GTFS fuzzy trip matching even when trip descriptor has an id [#6250](https://github.com/opentripplanner/OpenTripPlanner/pull/6250) - Make `motorroad=yes` car-only [#6288](https://github.com/opentripplanner/OpenTripPlanner/pull/6288) - Add decision record for analysis and design documentation [#6281](https://github.com/opentripplanner/OpenTripPlanner/pull/6281) +- Switch GTFS flex `safe_duration_offset` back to seconds [#6298](https://github.com/opentripplanner/OpenTripPlanner/pull/6298) [](AUTOMATIC_CHANGELOG_PLACEHOLDER_DO_NOT_REMOVE) ## 2.6.0 (2024-09-18) From 0fe4bdd3d16298cee75b8e8366db7388ca7ee86f Mon Sep 17 00:00:00 2001 From: OTP Changelog Bot Date: Thu, 5 Dec 2024 14:01:41 +0000 Subject: [PATCH 56/80] Add changelog entry for #6282 [ci skip] --- doc/user/Changelog.md | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/user/Changelog.md b/doc/user/Changelog.md index f6f9a55fb77..f9f766bbaa7 100644 --- a/doc/user/Changelog.md +++ b/doc/user/Changelog.md @@ -57,6 +57,7 @@ based on merged pull requests. Search GitHub issues and pull requests for smalle - Make `motorroad=yes` car-only [#6288](https://github.com/opentripplanner/OpenTripPlanner/pull/6288) - Add decision record for analysis and design documentation [#6281](https://github.com/opentripplanner/OpenTripPlanner/pull/6281) - Switch GTFS flex `safe_duration_offset` back to seconds [#6298](https://github.com/opentripplanner/OpenTripPlanner/pull/6298) +- Remove unused GtfsGraphQlApiRentalStationFuzzyMatching feature [#6282](https://github.com/opentripplanner/OpenTripPlanner/pull/6282) [](AUTOMATIC_CHANGELOG_PLACEHOLDER_DO_NOT_REMOVE) ## 2.6.0 (2024-09-18) From 3952cfcd8401b2bf29169e32ce870b3eaf4f933a Mon Sep 17 00:00:00 2001 From: Thomas Gran Date: Fri, 6 Dec 2024 10:06:02 +0100 Subject: [PATCH 57/80] fix: Fix references to the shaded jar for performance tests and in doc --- .github/workflows/performance-test.yml | 2 +- README.md | 2 +- doc/user/Getting-OTP.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/performance-test.yml b/.github/workflows/performance-test.yml index ad3b843dd12..1ec537a0b4f 100644 --- a/.github/workflows/performance-test.yml +++ b/.github/workflows/performance-test.yml @@ -88,7 +88,7 @@ jobs: - name: Build graph if: matrix.profile == 'core' || github.ref == 'refs/heads/dev-2.x' run: | - cp application/target/otp-*-SNAPSHOT-shaded.jar otp.jar + cp shaded-jar/target/otp-*-SNAPSHOT-shaded.jar otp.jar java -Xmx32G -jar otp.jar --build --save test/performance/${{ matrix.location }}/ - name: Run speed test diff --git a/README.md b/README.md index 41d889cf15b..ec66e694e8c 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ We run a speed test (included in the code) to measure the performance for every The main Java server code is in `application/src/main/`. OTP also includes a Javascript client based on the MapLibre mapping library in `client/src/`. This client is now used for testing, with most major deployments building custom clients from reusable components. The Maven build produces a unified ("shaded") -JAR file at `application/target/otp-VERSION.jar` containing all necessary code and dependencies to run OpenTripPlanner. +JAR file at `shaded-jar/target/otp-VERSION.jar` containing all necessary code and dependencies to run OpenTripPlanner. Additional information and instructions are available in the [main documentation](http://docs.opentripplanner.org/en/dev-2.x/), including a diff --git a/doc/user/Getting-OTP.md b/doc/user/Getting-OTP.md index 92f1e7298fc..ea0bac0df90 100644 --- a/doc/user/Getting-OTP.md +++ b/doc/user/Getting-OTP.md @@ -65,7 +65,7 @@ OTP. If all goes well you should see a success message like the following: ``` This build process should produce a JAR file called `otp-x.y.z-shaded.jar` in the -`application/target/` directory which contains all the compiled OTP classes and their dependencies +`shaded-jar/target/` directory which contains all the compiled OTP classes and their dependencies (the external libraries they use). The shell script called 'otp' in the root of the cloned repository will start the main class of that JAR file under a Java virtual machine, so after the Maven build completes you should be able to run `./otp --help` and see an OTP help message including command line From 4a63ca10ff08b6be1566a4ee9f2d85b20807dd31 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Fri, 6 Dec 2024 11:53:39 +0100 Subject: [PATCH 58/80] Convert booking notice to durations --- .../gtfs/datafetchers/BookingInfoImpl.java | 10 ++++++ .../gtfs/generated/GraphQLDataFetchers.java | 4 +++ .../opentripplanner/apis/gtfs/schema.graphqls | 8 +++-- .../datafetchers/BookingInfoImplTest.java | 31 +++++++++++++------ 4 files changed, 42 insertions(+), 11 deletions(-) diff --git a/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/BookingInfoImpl.java b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/BookingInfoImpl.java index 0060e6ad7e1..f6633818b3d 100644 --- a/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/BookingInfoImpl.java +++ b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/BookingInfoImpl.java @@ -30,6 +30,11 @@ public DataFetcher latestBookingTime() { return environment -> getSource(environment).getLatestBookingTime(); } + @Override + public DataFetcher maximumBookingNotice() { + return env -> getSource(env).getMaximumBookingNotice().orElse(null); + } + @Override public DataFetcher maximumBookingNoticeSeconds() { return environment -> @@ -41,6 +46,11 @@ public DataFetcher message() { return environment -> getSource(environment).getMessage(); } + @Override + public DataFetcher minimumBookingNotice() { + return env -> getSource(env).getMinimumBookingNotice().orElse(null); + } + @Override public DataFetcher minimumBookingNoticeSeconds() { return environment -> diff --git a/application/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java b/application/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java index dd74347b928..6528d8ee286 100644 --- a/application/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java +++ b/application/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java @@ -221,10 +221,14 @@ public interface GraphQLBookingInfo { public DataFetcher latestBookingTime(); + public DataFetcher maximumBookingNotice(); + public DataFetcher maximumBookingNoticeSeconds(); public DataFetcher message(); + public DataFetcher minimumBookingNotice(); + public DataFetcher minimumBookingNoticeSeconds(); public DataFetcher pickupMessage(); diff --git a/application/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls b/application/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls index a131b95fc8e..f92a8191018 100644 --- a/application/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls +++ b/application/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls @@ -279,12 +279,16 @@ type BookingInfo { earliestBookingTime: BookingTime "When is the latest time the service can be booked" latestBookingTime: BookingTime + "Maximum duration before travel to make the request." + maximumBookingNotice: Duration "Maximum number of seconds before travel to make the request" - maximumBookingNoticeSeconds: Long + maximumBookingNoticeSeconds: Long @deprecated(reason : "Use `maximumBookingNotice`") "A general message for those booking the service" message: String + "Minimum duration before travel to make the request" + minimumBookingNotice: Duration "Minimum number of seconds before travel to make the request" - minimumBookingNoticeSeconds: Long + minimumBookingNoticeSeconds: Long @deprecated(reason : "Use `minimumBookingNotice`") "A message specific to the pick up" pickupMessage: String } diff --git a/application/src/test/java/org/opentripplanner/apis/gtfs/datafetchers/BookingInfoImplTest.java b/application/src/test/java/org/opentripplanner/apis/gtfs/datafetchers/BookingInfoImplTest.java index 1103024aa61..d721a73939b 100644 --- a/application/src/test/java/org/opentripplanner/apis/gtfs/datafetchers/BookingInfoImplTest.java +++ b/application/src/test/java/org/opentripplanner/apis/gtfs/datafetchers/BookingInfoImplTest.java @@ -15,27 +15,40 @@ class BookingInfoImplTest { private static final BookingInfoImpl SUBJECT = new BookingInfoImpl(); private static final Duration TEN_MINUTES = Duration.ofMinutes(10); + private static final BookingInfo WITH_NOTICE_DURATIONS = BookingInfo + .of() + .withMinimumBookingNotice(TEN_MINUTES) + .withMaximumBookingNotice(TEN_MINUTES) + .build(); @Test - void emptyDurations() throws Exception { + void emptyNoticeSeconds() throws Exception { var env = dataFetchingEnvironment(BookingInfo.of().build()); assertNull(SUBJECT.minimumBookingNoticeSeconds().get(env)); assertNull(SUBJECT.maximumBookingNoticeSeconds().get(env)); } @Test - void durations() throws Exception { - var env = dataFetchingEnvironment( - BookingInfo - .of() - .withMinimumBookingNotice(TEN_MINUTES) - .withMaximumBookingNotice(TEN_MINUTES) - .build() - ); + void emptyNoticeDurations() throws Exception { + var env = dataFetchingEnvironment(BookingInfo.of().build()); + assertNull(SUBJECT.minimumBookingNotice().get(env)); + assertNull(SUBJECT.maximumBookingNotice().get(env)); + } + + @Test + void seconds() throws Exception { + var env = dataFetchingEnvironment(WITH_NOTICE_DURATIONS); assertEquals(600, SUBJECT.minimumBookingNoticeSeconds().get(env)); assertEquals(600, SUBJECT.maximumBookingNoticeSeconds().get(env)); } + @Test + void durations() throws Exception { + var env = dataFetchingEnvironment(WITH_NOTICE_DURATIONS); + assertEquals(TEN_MINUTES, SUBJECT.minimumBookingNotice().get(env)); + assertEquals(TEN_MINUTES, SUBJECT.maximumBookingNotice().get(env)); + } + private DataFetchingEnvironment dataFetchingEnvironment(BookingInfo bookingInfo) { var executionContext = newExecutionContextBuilder() .executionId(ExecutionId.from(this.getClass().getName())) From 42b23c0a6d1cd429b423969a2d33d7c58b197c43 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 7 Dec 2024 05:48:09 +0000 Subject: [PATCH 59/80] chore(deps): update micrometer.version to v1.14.1 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index edc1ab5efd7..a502f3d57bc 100644 --- a/pom.xml +++ b/pom.xml @@ -65,7 +65,7 @@ 2.18.2 3.1.9 5.11.3 - 1.13.7 + 1.14.1 5.6.0 1.5.12 9.12.0 From 540cbbd343ab19e2fe35132cde8ad520f2409ebf Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 8 Dec 2024 18:37:44 +0000 Subject: [PATCH 60/80] fix(deps): update dependency org.onebusaway:onebusaway-gtfs to v4 --- application/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/pom.xml b/application/pom.xml index 4b11f1f6527..50ecf5e2549 100644 --- a/application/pom.xml +++ b/application/pom.xml @@ -296,7 +296,7 @@ org.onebusaway onebusaway-gtfs - 3.2.4 + 4.3.0 From 4cdde4bc42f9b77da11909e7755a1569b2e431b5 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 9 Dec 2024 06:44:44 +0100 Subject: [PATCH 61/80] fix(deps): update dependency org.mobilitydata:gbfs-java-model to v1.0.9 (#6319) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- application/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/pom.xml b/application/pom.xml index 4b11f1f6527..84d92f2b4d4 100644 --- a/application/pom.xml +++ b/application/pom.xml @@ -148,7 +148,7 @@ org.mobilitydata gbfs-java-model - 1.0.7 + 1.0.9 From 6683aed6399725b0c6b55dfbd114ceda9f81cee0 Mon Sep 17 00:00:00 2001 From: OTP Bot Date: Mon, 9 Dec 2024 09:18:30 +0000 Subject: [PATCH 62/80] Upgrade debug client to version 2024/12/2024-12-09T09:17 --- application/src/client/index.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/application/src/client/index.html b/application/src/client/index.html index 391458fba41..b34591918d8 100644 --- a/application/src/client/index.html +++ b/application/src/client/index.html @@ -4,9 +4,9 @@ - OTP Debug Client - - + OTP Debug + +
From ff031693965e09c156e117ee3422c7b377d0a983 Mon Sep 17 00:00:00 2001 From: OTP Changelog Bot Date: Mon, 9 Dec 2024 09:18:46 +0000 Subject: [PATCH 63/80] Add changelog entry for #6295 [ci skip] --- doc/user/Changelog.md | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/user/Changelog.md b/doc/user/Changelog.md index f9f766bbaa7..7d96b53885c 100644 --- a/doc/user/Changelog.md +++ b/doc/user/Changelog.md @@ -58,6 +58,7 @@ based on merged pull requests. Search GitHub issues and pull requests for smalle - Add decision record for analysis and design documentation [#6281](https://github.com/opentripplanner/OpenTripPlanner/pull/6281) - Switch GTFS flex `safe_duration_offset` back to seconds [#6298](https://github.com/opentripplanner/OpenTripPlanner/pull/6298) - Remove unused GtfsGraphQlApiRentalStationFuzzyMatching feature [#6282](https://github.com/opentripplanner/OpenTripPlanner/pull/6282) +- Make debug UI background layers configurable with new file `debug-ui-config.json` [#6295](https://github.com/opentripplanner/OpenTripPlanner/pull/6295) [](AUTOMATIC_CHANGELOG_PLACEHOLDER_DO_NOT_REMOVE) ## 2.6.0 (2024-09-18) From 0079a16a6ef3fa9bef7610df598244a8dd9795fd Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Mon, 9 Dec 2024 10:19:33 +0100 Subject: [PATCH 64/80] Remove console.log [ci skip] --- client/src/components/MapView/LayerControl.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/client/src/components/MapView/LayerControl.tsx b/client/src/components/MapView/LayerControl.tsx index a41e7f133a4..43b0258662d 100644 --- a/client/src/components/MapView/LayerControl.tsx +++ b/client/src/components/MapView/LayerControl.tsx @@ -65,7 +65,6 @@ class LayerControl implements IControl { }); select.onchange = () => { const layerId = select.value; - console.log(select.value); const layer = map.getLayer(layerId); if (layer) { rasterLayers.forEach((l) => { From da622619c0c8dcfd81e25091e1f55d57360eed32 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 9 Dec 2024 09:23:18 +0000 Subject: [PATCH 65/80] chore(deps): update react monorepo to v19 --- client/package.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/client/package.json b/client/package.json index f930bcd67d5..5aa6681a44b 100644 --- a/client/package.json +++ b/client/package.json @@ -23,9 +23,9 @@ "graphql": "16.9.0", "graphql-request": "7.1.2", "maplibre-gl": "4.7.1", - "react": "18.3.1", + "react": "19.0.0", "react-bootstrap": "2.10.6", - "react-dom": "18.3.1", + "react-dom": "19.0.0", "react-map-gl": "7.1.7" }, "devDependencies": { @@ -34,8 +34,8 @@ "@graphql-codegen/introspection": "4.0.3", "@parcel/watcher": "2.5.0", "@testing-library/react": "16.0.1", - "@types/react": "18.3.12", - "@types/react-dom": "18.3.1", + "@types/react": "19.0.1", + "@types/react-dom": "19.0.1", "@typescript-eslint/eslint-plugin": "7.18.0", "@typescript-eslint/parser": "7.18.0", "@vitejs/plugin-react": "4.3.4", From f2db3f45d3e239f145b31183c9b82b8842ddd066 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=20Erik=20St=C3=B8wer?= Date: Mon, 9 Dec 2024 11:00:15 +0100 Subject: [PATCH 66/80] Update @testing-library/react to react19 compatible version --- client/package-lock.json | 2190 +++++++++++++++++++------------------- client/package.json | 2 +- 2 files changed, 1072 insertions(+), 1120 deletions(-) diff --git a/client/package-lock.json b/client/package-lock.json index bbed0b8e4fa..52d93d9d4cf 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -14,9 +14,9 @@ "graphql": "16.9.0", "graphql-request": "7.1.2", "maplibre-gl": "4.7.1", - "react": "18.3.1", + "react": "19.0.0", "react-bootstrap": "2.10.6", - "react-dom": "18.3.1", + "react-dom": "19.0.0", "react-map-gl": "7.1.7" }, "devDependencies": { @@ -24,9 +24,9 @@ "@graphql-codegen/client-preset": "4.5.1", "@graphql-codegen/introspection": "4.0.3", "@parcel/watcher": "2.5.0", - "@testing-library/react": "16.0.1", - "@types/react": "18.3.12", - "@types/react-dom": "18.3.1", + "@testing-library/react": "16.1.0", + "@types/react": "19.0.1", + "@types/react-dom": "19.0.1", "@typescript-eslint/eslint-plugin": "7.18.0", "@typescript-eslint/parser": "7.18.0", "@vitejs/plugin-react": "4.3.4", @@ -45,15 +45,6 @@ "vitest": "2.1.8" } }, - "node_modules/@aashutoshrathi/word-wrap": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", - "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/@ampproject/remapping": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", @@ -229,9 +220,9 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.26.2", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.26.2.tgz", - "integrity": "sha512-Z0WgzSEa+aUcdiJuCIqgujCshpMWgUpgOxXotrYPSA53hA3qopNaqcJpyr0hVb1FeWdnqFA35/fUtXgBK8srQg==", + "version": "7.26.3", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.26.3.tgz", + "integrity": "sha512-nHIxvKPniQXpmQLb0vhY3VaFb3S0YrTAwpOWJZh1wn3oJPjJk9Asva204PsBdmAE8vpzfHudT8DB0scYvy9q0g==", "dev": true, "engines": { "node": ">=6.9.0" @@ -268,13 +259,13 @@ } }, "node_modules/@babel/generator": { - "version": "7.26.2", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.2.tgz", - "integrity": "sha512-zevQbhbau95nkoxSq3f/DC/SC+EEOUZd3DYqfSkMhY2/wfSeaHV1Ew4vk8e+x8lja31IbyuUa2uQ3JONqKbysw==", + "version": "7.26.3", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.3.tgz", + "integrity": "sha512-6FF/urZvD0sTeO7k6/B15pMLC4CHUv1426lzr3N01aHJTl046uCAh9LXW/fzeXXjPNCJ6iABW5XaWOsIZB93aQ==", "dev": true, "dependencies": { - "@babel/parser": "^7.26.2", - "@babel/types": "^7.26.0", + "@babel/parser": "^7.26.3", + "@babel/types": "^7.26.3", "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25", "jsesc": "^3.0.2" @@ -284,12 +275,12 @@ } }, "node_modules/@babel/helper-annotate-as-pure": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz", - "integrity": "sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.25.9.tgz", + "integrity": "sha512-gv7320KBUFJz1RnylIg5WWYPRXKZ884AGkYpgpWW02TH66Dl+HaC1t1CKd0z3R4b6hdYEcmrNZHUmfCP+1u3/g==", "dev": true, "dependencies": { - "@babel/types": "^7.22.5" + "@babel/types": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -312,19 +303,17 @@ } }, "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.24.1.tgz", - "integrity": "sha512-1yJa9dX9g//V6fDebXoEfEsxkZHk3Hcbm+zLhyu6qVgYFLvmTALTeV+jNU9e5RnYtioBrGEOdoI2joMSNQ/+aA==", - "dev": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.22.5", - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-function-name": "^7.23.0", - "@babel/helper-member-expression-to-functions": "^7.23.0", - "@babel/helper-optimise-call-expression": "^7.22.5", - "@babel/helper-replace-supers": "^7.24.1", - "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.25.9.tgz", + "integrity": "sha512-UTZQMvt0d/rSz6KI+qdu7GQze5TIajwTS++GUozlw8VBJDEOAqSXwm1WvmYEZwqdqSGQshRocPDqrt4HBZB3fQ==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.25.9", + "@babel/helper-member-expression-to-functions": "^7.25.9", + "@babel/helper-optimise-call-expression": "^7.25.9", + "@babel/helper-replace-supers": "^7.25.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9", + "@babel/traverse": "^7.25.9", "semver": "^6.3.1" }, "engines": { @@ -334,37 +323,14 @@ "@babel/core": "^7.0.0" } }, - "node_modules/@babel/helper-environment-visitor": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.24.6.tgz", - "integrity": "sha512-Y50Cg3k0LKLMjxdPjIl40SdJgMB85iXn27Vk/qbHZCFx/o5XO3PSnpi675h1KEmmDb6OFArfd5SCQEQ5Q4H88g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-function-name": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.24.6.tgz", - "integrity": "sha512-xpeLqeeRkbxhnYimfr2PC+iA0Q7ljX/d1eZ9/inYbmfG2jpl8Lu3DyXvpOAnrS5kxkfOWJjioIMQsaMBXFI05w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/template": "^7.24.6", - "@babel/types": "^7.24.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.23.0.tgz", - "integrity": "sha512-6gfrPwh7OuT6gZyJZvd6WbTfrqAo7vm4xCzAXOusKqq/vWdKXphTpj5klHKNmRUU6/QRGlBsyU9mAIPaWHlqJA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.25.9.tgz", + "integrity": "sha512-wbfdZ9w5vk0C0oyHqAJbc62+vet5prjj01jjJ8sKn3j9h3MQQlflEdXYvuqRWjHnM12coDEqiC1IRCi0U/EKwQ==", "dev": true, "dependencies": { - "@babel/types": "^7.23.0" + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -401,12 +367,12 @@ } }, "node_modules/@babel/helper-optimise-call-expression": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.22.5.tgz", - "integrity": "sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.25.9.tgz", + "integrity": "sha512-FIpuNaz5ow8VyrYcnXQTDRGvV6tTjkNtCK/RYNDXGSLlUD6cBuQTSw43CShGxjvfBTfcUA/r6UhUCbtYqkhcuQ==", "dev": true, "dependencies": { - "@babel/types": "^7.22.5" + "@babel/types": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -422,14 +388,14 @@ } }, "node_modules/@babel/helper-replace-supers": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.24.1.tgz", - "integrity": "sha512-QCR1UqC9BzG5vZl8BMicmZ28RuUBnHhAMddD8yHFHDRH9lLTZ9uUPehX8ctVPT8l0TKblJidqcgUUKGVrePleQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.25.9.tgz", + "integrity": "sha512-IiDqTOTBQy0sWyeXyGSC5TBJpGFXBkRynjBeXsvbhQFKj2viwJC76Epz35YLU1fpe/Am6Vppb7W7zM4fPQzLsQ==", "dev": true, "dependencies": { - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-member-expression-to-functions": "^7.23.0", - "@babel/helper-optimise-call-expression": "^7.22.5" + "@babel/helper-member-expression-to-functions": "^7.25.9", + "@babel/helper-optimise-call-expression": "^7.25.9", + "@babel/traverse": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -438,40 +404,14 @@ "@babel/core": "^7.0.0" } }, - "node_modules/@babel/helper-simple-access": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.25.7.tgz", - "integrity": "sha512-FPGAkJmyoChQeM+ruBGIDyrT2tKfZJO8NcxdC+CWNJi7N8/rZpSxK7yvBJ5O/nF1gfu5KzN7VKG3YVSLFfRSxQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/traverse": "^7.25.7", - "@babel/types": "^7.25.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.22.5.tgz", - "integrity": "sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q==", - "dev": true, - "dependencies": { - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-split-export-declaration": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.6.tgz", - "integrity": "sha512-CvLSkwXGWnYlF9+J3iZUvwgAxKiYzK3BWuo+mLzD/MDGOZDj7Gq8+hqaOkMxmJwmlv0iu86uH5fdADd9Hxkymw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.25.9.tgz", + "integrity": "sha512-K4Du3BFa3gvyhzgPcntrkDgZzQaq6uozzcpGbOO1OEJaI+EJdqWIMTLgFgQf6lrfiDFo5FU+BxKepI9RmZqahA==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/types": "^7.24.6" + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -518,12 +458,12 @@ } }, "node_modules/@babel/parser": { - "version": "7.26.2", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.2.tgz", - "integrity": "sha512-DWMCZH9WA4Maitz2q21SRKHo9QXZxkDsbNZoVD62gusNtNBBqDg9i7uOhASfTfIGNzW+O+r7+jAlM8dwphcJKQ==", + "version": "7.26.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.3.tgz", + "integrity": "sha512-WJ/CvmY8Mea8iDXo6a7RK2wbmJITT5fN3BEkRuFlxVyNx8jOKIIhmC4fSkTcPcf8JyavbBwIe6OpiCOBXt/IcA==", "dev": true, "dependencies": { - "@babel/types": "^7.26.0" + "@babel/types": "^7.26.3" }, "bin": { "parser": "bin/babel-parser.js" @@ -582,12 +522,12 @@ } }, "node_modules/@babel/plugin-syntax-flow": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.24.1.tgz", - "integrity": "sha512-sxi2kLTI5DeW5vDtMUsk4mTPwvlUDbjOnoWayhynCwrw4QXRld4QEYwqzY8JmQXaJUtgUuCIurtSRH5sn4c7mA==", + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.26.0.tgz", + "integrity": "sha512-B+O2DnPc0iG+YXFqOxv2WNuNU97ToWjOomUQ78DouOENWUaM5sVrmet9mcomUGQFwpJd//gvUagXBSdzO1fRKg==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -597,12 +537,12 @@ } }, "node_modules/@babel/plugin-syntax-import-assertions": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.24.1.tgz", - "integrity": "sha512-IuwnI5XnuF189t91XbxmXeCDz3qs6iDRO7GJ++wcfgeXNs/8FmIlKcpDSXNVyuLQxlwvskmI3Ct73wUODkJBlQ==", + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.26.0.tgz", + "integrity": "sha512-QCWT5Hh830hK5EQa7XzuqIkQU9tT/whqbDz7kuaZMHFl1inRRg7JnuAEOQ0Ur0QUl0NufCk1msK2BeY79Aj/eg==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -612,12 +552,12 @@ } }, "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.1.tgz", - "integrity": "sha512-2eCtxZXf+kbkMIsXS4poTvT4Yu5rXiRa+9xGVT56raghjmBTKMpFNc9R4IDiB4emao9eO22Ox7CxuJG7BgExqA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.25.9.tgz", + "integrity": "sha512-ld6oezHQMZsZfp6pWtbjaNDF2tiiCYYDqQszHt5VV437lewP9aSi2Of99CK0D0XB21k7FLgnLcmQKyKzynfeAA==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -639,12 +579,12 @@ } }, "node_modules/@babel/plugin-transform-arrow-functions": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.24.1.tgz", - "integrity": "sha512-ngT/3NkRhsaep9ck9uj2Xhv9+xB1zShY3tM3g6om4xxCELwCDN4g4Aq5dRn48+0hasAql7s2hdBOysCfNpr4fw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.25.9.tgz", + "integrity": "sha512-6jmooXYIwn9ca5/RylZADJ+EnSxVUS5sjeJ9UPk6RWRzXCmOJCy6dqItPJFpw2cuCangPK4OYr5uhGKcmrm5Qg==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -654,12 +594,12 @@ } }, "node_modules/@babel/plugin-transform-block-scoped-functions": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.24.1.tgz", - "integrity": "sha512-TWWC18OShZutrv9C6mye1xwtam+uNi2bnTOCBUd5sZxyHOiWbU6ztSROofIMrK84uweEZC219POICK/sTYwfgg==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.25.9.tgz", + "integrity": "sha512-toHc9fzab0ZfenFpsyYinOX0J/5dgJVA2fm64xPewu7CoYHWEivIWKxkK2rMi4r3yQqLnVmheMXRdG+k239CgA==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -669,12 +609,12 @@ } }, "node_modules/@babel/plugin-transform-block-scoping": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.24.1.tgz", - "integrity": "sha512-h71T2QQvDgM2SmT29UYU6ozjMlAt7s7CSs5Hvy8f8cf/GM/Z4a2zMfN+fjVGaieeCrXR3EdQl6C4gQG+OgmbKw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.25.9.tgz", + "integrity": "sha512-1F05O7AYjymAtqbsFETboN1NvBdcnzMerO+zlMyJBEz6WkMdejvGWw9p05iTSjC85RLlBseHHQpYaM4gzJkBGg==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -684,18 +624,16 @@ } }, "node_modules/@babel/plugin-transform-classes": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.24.1.tgz", - "integrity": "sha512-ZTIe3W7UejJd3/3R4p7ScyyOoafetUShSf4kCqV0O7F/RiHxVj/wRaRnQlrGwflvcehNA8M42HkAiEDYZu2F1Q==", - "dev": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.22.5", - "@babel/helper-compilation-targets": "^7.23.6", - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-function-name": "^7.23.0", - "@babel/helper-plugin-utils": "^7.24.0", - "@babel/helper-replace-supers": "^7.24.1", - "@babel/helper-split-export-declaration": "^7.22.6", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.25.9.tgz", + "integrity": "sha512-mD8APIXmseE7oZvZgGABDyM34GUmK45Um2TXiBUt7PnuAxrgoSVf123qUzPxEr/+/BHrRn5NMZCdE2m/1F8DGg==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.25.9", + "@babel/helper-compilation-targets": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-replace-supers": "^7.25.9", + "@babel/traverse": "^7.25.9", "globals": "^11.1.0" }, "engines": { @@ -706,13 +644,13 @@ } }, "node_modules/@babel/plugin-transform-computed-properties": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.24.1.tgz", - "integrity": "sha512-5pJGVIUfJpOS+pAqBQd+QMaTD2vCL/HcePooON6pDpHgRp4gNRmzyHTPIkXntwKsq3ayUFVfJaIKPw2pOkOcTw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.25.9.tgz", + "integrity": "sha512-HnBegGqXZR12xbcTHlJ9HGxw1OniltT26J5YpfruGqtUHlz/xKf/G2ak9e+t0rVqrjXa9WOhvYPz1ERfMj23AA==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0", - "@babel/template": "^7.24.0" + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/template": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -722,12 +660,12 @@ } }, "node_modules/@babel/plugin-transform-destructuring": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.24.1.tgz", - "integrity": "sha512-ow8jciWqNxR3RYbSNVuF4U2Jx130nwnBnhRw6N6h1bOejNkABmcI5X5oz29K4alWX7vf1C+o6gtKXikzRKkVdw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.25.9.tgz", + "integrity": "sha512-WkCGb/3ZxXepmMiX101nnGiU+1CAdut8oHyEOHxkKuS1qKpU2SMXE2uSvfz8PBuLd49V6LEsbtyPhWC7fnkgvQ==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -737,13 +675,13 @@ } }, "node_modules/@babel/plugin-transform-flow-strip-types": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.24.1.tgz", - "integrity": "sha512-iIYPIWt3dUmUKKE10s3W+jsQ3icFkw0JyRVyY1B7G4yK/nngAOHLVx8xlhA6b/Jzl/Y0nis8gjqhqKtRDQqHWQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.25.9.tgz", + "integrity": "sha512-/VVukELzPDdci7UUsWQaSkhgnjIWXnIyRpM02ldxaVoFK96c41So8JcKT3m0gYjyv7j5FNPGS5vfELrWalkbDA==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0", - "@babel/plugin-syntax-flow": "^7.24.1" + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/plugin-syntax-flow": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -753,13 +691,13 @@ } }, "node_modules/@babel/plugin-transform-for-of": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.24.1.tgz", - "integrity": "sha512-OxBdcnF04bpdQdR3i4giHZNZQn7cm8RQKcSwA17wAAqEELo1ZOwp5FFgeptWUQXFyT9kwHo10aqqauYkRZPCAg==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.25.9.tgz", + "integrity": "sha512-LqHxduHoaGELJl2uhImHwRQudhCM50pT46rIBNvtT/Oql3nqiS3wOwP+5ten7NpYSXrrVLgtZU3DZmPtWZo16A==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0", - "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5" + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -769,14 +707,14 @@ } }, "node_modules/@babel/plugin-transform-function-name": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.24.1.tgz", - "integrity": "sha512-BXmDZpPlh7jwicKArQASrj8n22/w6iymRnvHYYd2zO30DbE277JO20/7yXJT3QxDPtiQiOxQBbZH4TpivNXIxA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.25.9.tgz", + "integrity": "sha512-8lP+Yxjv14Vc5MuWBpJsoUCd3hD6V9DgBon2FVYL4jJgbnVQ9fTgYmonchzZJOVNgzEgbxp4OwAf6xz6M/14XA==", "dev": true, "dependencies": { - "@babel/helper-compilation-targets": "^7.23.6", - "@babel/helper-function-name": "^7.23.0", - "@babel/helper-plugin-utils": "^7.24.0" + "@babel/helper-compilation-targets": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/traverse": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -786,12 +724,12 @@ } }, "node_modules/@babel/plugin-transform-literals": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.24.1.tgz", - "integrity": "sha512-zn9pwz8U7nCqOYIiBaOxoQOtYmMODXTJnkxG4AtX8fPmnCRYWBOHD0qcpwS9e2VDSp1zNJYpdnFMIKb8jmwu6g==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.25.9.tgz", + "integrity": "sha512-9N7+2lFziW8W9pBl2TzaNht3+pgMIRP74zizeCSrtnSKVdUl8mAjjOP2OOVQAfZ881P2cNjDj1uAMEdeD50nuQ==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -801,12 +739,12 @@ } }, "node_modules/@babel/plugin-transform-member-expression-literals": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.24.1.tgz", - "integrity": "sha512-4ojai0KysTWXzHseJKa1XPNXKRbuUrhkOPY4rEGeR+7ChlJVKxFa3H3Bz+7tWaGKgJAXUWKOGmltN+u9B3+CVg==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.25.9.tgz", + "integrity": "sha512-PYazBVfofCQkkMzh2P6IdIUaCEWni3iYEerAsRWuVd8+jlM1S9S9cz1dF9hIzyoZ8IA3+OwVYIp9v9e+GbgZhA==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -816,14 +754,13 @@ } }, "node_modules/@babel/plugin-transform-modules-commonjs": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.24.1.tgz", - "integrity": "sha512-szog8fFTUxBfw0b98gEWPaEqF42ZUD/T3bkynW/wtgx2p/XCP55WEsb+VosKceRSd6njipdZvNogqdtI4Q0chw==", + "version": "7.26.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.26.3.tgz", + "integrity": "sha512-MgR55l4q9KddUDITEzEFYn5ZsGDXMSsU9E+kh7fjRXTIC3RHqfCo8RPRbyReYJh44HQ/yomFkqbOFohXvDCiIQ==", "dev": true, "dependencies": { - "@babel/helper-module-transforms": "^7.23.3", - "@babel/helper-plugin-utils": "^7.24.0", - "@babel/helper-simple-access": "^7.22.5" + "@babel/helper-module-transforms": "^7.26.0", + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -833,13 +770,13 @@ } }, "node_modules/@babel/plugin-transform-object-super": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.24.1.tgz", - "integrity": "sha512-oKJqR3TeI5hSLRxudMjFQ9re9fBVUU0GICqM3J1mi8MqlhVr6hC/ZN4ttAyMuQR6EZZIY6h/exe5swqGNNIkWQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.25.9.tgz", + "integrity": "sha512-Kj/Gh+Rw2RNLbCK1VAWj2U48yxxqL2x0k10nPtSdRa0O2xnHXalD0s+o1A6a0W43gJ00ANo38jxkQreckOzv5A==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0", - "@babel/helper-replace-supers": "^7.24.1" + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-replace-supers": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -849,12 +786,12 @@ } }, "node_modules/@babel/plugin-transform-parameters": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.24.1.tgz", - "integrity": "sha512-8Jl6V24g+Uw5OGPeWNKrKqXPDw2YDjLc53ojwfMcKwlEoETKU9rU0mHUtcg9JntWI/QYzGAXNWEcVHZ+fR+XXg==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.25.9.tgz", + "integrity": "sha512-wzz6MKwpnshBAiRmn4jR8LYz/g8Ksg0o80XmwZDlordjwEk9SxBzTWC7F5ef1jhbrbOW2DJ5J6ayRukrJmnr0g==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -864,12 +801,12 @@ } }, "node_modules/@babel/plugin-transform-property-literals": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.24.1.tgz", - "integrity": "sha512-LetvD7CrHmEx0G442gOomRr66d7q8HzzGGr4PMHGr+5YIm6++Yke+jxj246rpvsbyhJwCLxcTn6zW1P1BSenqA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.25.9.tgz", + "integrity": "sha512-IvIUeV5KrS/VPavfSM/Iu+RE6llrHrYIKY1yfCzyO/lMXHQ+p7uGhonmGVisv6tSBSVgWzMBohTcvkC9vQcQFA==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -879,12 +816,12 @@ } }, "node_modules/@babel/plugin-transform-react-display-name": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.24.1.tgz", - "integrity": "sha512-mvoQg2f9p2qlpDQRBC7M3c3XTr0k7cp/0+kFKKO/7Gtu0LSw16eKB+Fabe2bDT/UpsyasTBBkAnbdsLrkD5XMw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.25.9.tgz", + "integrity": "sha512-KJfMlYIUxQB1CJfO3e0+h0ZHWOTLCPP115Awhaz8U0Zpq36Gl/cXlpoyMRnUWlhNUBAzldnCiAZNvCDj7CrKxQ==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -894,16 +831,16 @@ } }, "node_modules/@babel/plugin-transform-react-jsx": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.23.4.tgz", - "integrity": "sha512-5xOpoPguCZCRbo/JeHlloSkTA8Bld1J/E1/kLfD1nsuiW1m8tduTA1ERCgIZokDflX/IBzKcqR3l7VlRgiIfHA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.25.9.tgz", + "integrity": "sha512-s5XwpQYCqGerXl+Pu6VDL3x0j2d82eiV77UJ8a2mDHAW7j9SWRqQ2y1fNo1Z74CdcYipl5Z41zvjj4Nfzq36rw==", "dev": true, "dependencies": { - "@babel/helper-annotate-as-pure": "^7.22.5", - "@babel/helper-module-imports": "^7.22.15", - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/plugin-syntax-jsx": "^7.23.3", - "@babel/types": "^7.23.4" + "@babel/helper-annotate-as-pure": "^7.25.9", + "@babel/helper-module-imports": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/plugin-syntax-jsx": "^7.25.9", + "@babel/types": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -943,12 +880,12 @@ } }, "node_modules/@babel/plugin-transform-shorthand-properties": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.24.1.tgz", - "integrity": "sha512-LyjVB1nsJ6gTTUKRjRWx9C1s9hE7dLfP/knKdrfeH9UPtAGjYGgxIbFfx7xyLIEWs7Xe1Gnf8EWiUqfjLhInZA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.25.9.tgz", + "integrity": "sha512-MUv6t0FhO5qHnS/W8XCbHmiRWOphNufpE1IVxhK5kuN3Td9FT1x4rx4K42s3RYdMXCXpfWkGSbCSd0Z64xA7Ng==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -958,13 +895,13 @@ } }, "node_modules/@babel/plugin-transform-spread": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.24.1.tgz", - "integrity": "sha512-KjmcIM+fxgY+KxPVbjelJC6hrH1CgtPmTvdXAfn3/a9CnWGSTY7nH4zm5+cjmWJybdcPSsD0++QssDsjcpe47g==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.25.9.tgz", + "integrity": "sha512-oNknIB0TbURU5pqJFVbOOFspVlrpVwo2H1+HUIsVDvp5VauGGDP1ZEvO8Nn5xyMEs3dakajOxlmkNW7kNgSm6A==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0", - "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5" + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -974,12 +911,12 @@ } }, "node_modules/@babel/plugin-transform-template-literals": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.24.1.tgz", - "integrity": "sha512-WRkhROsNzriarqECASCNu/nojeXCDTE/F2HmRgOzi7NGvyfYGq1NEjKBK3ckLfRgGc6/lPAqP0vDOSw3YtG34g==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.25.9.tgz", + "integrity": "sha512-o97AE4syN71M/lxrCtQByzphAdlYluKPDBzDVzMmfCobUjjhAryZV0AIpRPrxN0eAkxXO6ZLEScmt+PNhj2OTw==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -992,7 +929,6 @@ "version": "7.26.0", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.0.tgz", "integrity": "sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw==", - "license": "MIT", "dependencies": { "regenerator-runtime": "^0.14.0" }, @@ -1015,16 +951,16 @@ } }, "node_modules/@babel/traverse": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.9.tgz", - "integrity": "sha512-ZCuvfwOwlz/bawvAuvcj8rrithP2/N55Tzz342AkTvq4qaWbGfmCk/tKhNaV2cthijKrPAA8SRJV5WWe7IBMJw==", + "version": "7.26.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.26.4.tgz", + "integrity": "sha512-fH+b7Y4p3yqvApJALCPJcwb0/XaOSgtK4pzV6WVjPR5GLFQBRI7pfoX2V2iM48NXvX07NUxxm1Vw98YjqTcU5w==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.25.9", - "@babel/generator": "^7.25.9", - "@babel/parser": "^7.25.9", + "@babel/code-frame": "^7.26.2", + "@babel/generator": "^7.26.3", + "@babel/parser": "^7.26.3", "@babel/template": "^7.25.9", - "@babel/types": "^7.25.9", + "@babel/types": "^7.26.3", "debug": "^4.3.1", "globals": "^11.1.0" }, @@ -1033,9 +969,9 @@ } }, "node_modules/@babel/types": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.0.tgz", - "integrity": "sha512-Z/yiTPj+lDVnF7lWeKCIJzaIkI0vYO87dMpZ4bg4TDrFe4XXLFWL1TbXU27gBP3QccxV9mZICCrnjnYlJjXHOA==", + "version": "7.26.3", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.3.tgz", + "integrity": "sha512-vN5p+1kl59GVKMvTHt55NzzmYVxprfJD+ql7U9NFIfKCBkYE55LYtS+WtPlaYOyzydrKI8Nezd+aZextrd+FMA==", "dev": true, "dependencies": { "@babel/helper-string-parser": "^7.25.9", @@ -1436,24 +1372,27 @@ } }, "node_modules/@eslint-community/eslint-utils": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", - "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.1.tgz", + "integrity": "sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==", "dev": true, "dependencies": { - "eslint-visitor-keys": "^3.3.0" + "eslint-visitor-keys": "^3.4.3" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, + "funding": { + "url": "https://opencollective.com/eslint" + }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, "node_modules/@eslint-community/regexpp": { - "version": "4.10.0", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", - "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", + "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", "dev": true, "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" @@ -1536,7 +1475,6 @@ "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz", "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==", "dev": true, - "license": "MIT", "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } @@ -1551,7 +1489,6 @@ "resolved": "https://registry.npmjs.org/@graphql-codegen/add/-/add-5.0.3.tgz", "integrity": "sha512-SxXPmramkth8XtBlAHu4H4jYcYXM/o3p01+psU+0NADQowA8jtYkK6MW5rV6T+CxkEaNZItfSmZRPgIuypcqnA==", "dev": true, - "license": "MIT", "dependencies": { "@graphql-codegen/plugin-helpers": "^5.0.3", "tslib": "~2.6.0" @@ -1560,12 +1497,17 @@ "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0" } }, + "node_modules/@graphql-codegen/add/node_modules/tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", + "dev": true + }, "node_modules/@graphql-codegen/cli": { "version": "5.0.3", "resolved": "https://registry.npmjs.org/@graphql-codegen/cli/-/cli-5.0.3.tgz", "integrity": "sha512-ULpF6Sbu2d7vNEOgBtE9avQp2oMgcPY/QBYcCqk0Xru5fz+ISjcovQX29V7CS7y5wWBRzNLoXwJQGeEyWbl05g==", "dev": true, - "license": "MIT", "dependencies": { "@babel/generator": "^7.18.13", "@babel/template": "^7.18.10", @@ -1627,7 +1569,6 @@ "resolved": "https://registry.npmjs.org/@graphql-codegen/client-preset/-/client-preset-4.5.1.tgz", "integrity": "sha512-UE2/Kz2eaxv35HIXFwlm2QwoUH77am6+qp54aeEWYq+T+WPwmIc6+YzqtGiT/VcaXgoOUSgidREGm9R6jKcf9g==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.20.2", "@babel/template": "^7.20.7", @@ -1650,6 +1591,12 @@ "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0" } }, + "node_modules/@graphql-codegen/client-preset/node_modules/tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", + "dev": true + }, "node_modules/@graphql-codegen/core": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/@graphql-codegen/core/-/core-4.0.2.tgz", @@ -1665,12 +1612,17 @@ "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0" } }, + "node_modules/@graphql-codegen/core/node_modules/tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", + "dev": true + }, "node_modules/@graphql-codegen/gql-tag-operations": { "version": "4.0.12", "resolved": "https://registry.npmjs.org/@graphql-codegen/gql-tag-operations/-/gql-tag-operations-4.0.12.tgz", "integrity": "sha512-v279i49FJ5dMmQXIGUgm6FtnnkxtJjVJWDNYh9JK4ppvOixdHp+PmEzW227DkLN6avhVxNnYdp/1gdRBwdWypw==", "dev": true, - "license": "MIT", "dependencies": { "@graphql-codegen/plugin-helpers": "^5.1.0", "@graphql-codegen/visitor-plugin-common": "5.6.0", @@ -1685,6 +1637,12 @@ "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0" } }, + "node_modules/@graphql-codegen/gql-tag-operations/node_modules/tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", + "dev": true + }, "node_modules/@graphql-codegen/introspection": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/@graphql-codegen/introspection/-/introspection-4.0.3.tgz", @@ -1699,12 +1657,17 @@ "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0" } }, + "node_modules/@graphql-codegen/introspection/node_modules/tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", + "dev": true + }, "node_modules/@graphql-codegen/plugin-helpers": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/@graphql-codegen/plugin-helpers/-/plugin-helpers-5.1.0.tgz", "integrity": "sha512-Y7cwEAkprbTKzVIe436TIw4w03jorsMruvCvu0HJkavaKMQbWY+lQ1RIuROgszDbxAyM35twB5/sUvYG5oW+yg==", "dev": true, - "license": "MIT", "dependencies": { "@graphql-tools/utils": "^10.0.0", "change-case-all": "1.0.15", @@ -1720,12 +1683,17 @@ "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0" } }, + "node_modules/@graphql-codegen/plugin-helpers/node_modules/tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", + "dev": true + }, "node_modules/@graphql-codegen/schema-ast": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/@graphql-codegen/schema-ast/-/schema-ast-4.1.0.tgz", "integrity": "sha512-kZVn0z+th9SvqxfKYgztA6PM7mhnSZaj4fiuBWvMTqA+QqQ9BBed6Pz41KuD/jr0gJtnlr2A4++/0VlpVbCTmQ==", "dev": true, - "license": "MIT", "dependencies": { "@graphql-codegen/plugin-helpers": "^5.0.3", "@graphql-tools/utils": "^10.0.0", @@ -1735,12 +1703,17 @@ "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0" } }, + "node_modules/@graphql-codegen/schema-ast/node_modules/tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", + "dev": true + }, "node_modules/@graphql-codegen/typed-document-node": { "version": "5.0.12", "resolved": "https://registry.npmjs.org/@graphql-codegen/typed-document-node/-/typed-document-node-5.0.12.tgz", "integrity": "sha512-Wsbc1AqC+MFp3maWPzrmmyHLuWCPB63qBBFLTKtO6KSsnn0KnLocBp475wkfBZnFISFvzwpJ0e6LV71gKfTofQ==", "dev": true, - "license": "MIT", "dependencies": { "@graphql-codegen/plugin-helpers": "^5.1.0", "@graphql-codegen/visitor-plugin-common": "5.6.0", @@ -1755,12 +1728,17 @@ "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0" } }, + "node_modules/@graphql-codegen/typed-document-node/node_modules/tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", + "dev": true + }, "node_modules/@graphql-codegen/typescript": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/@graphql-codegen/typescript/-/typescript-4.1.2.tgz", "integrity": "sha512-GhPgfxgWEkBrvKR2y77OThus3K8B6U3ESo68l7+sHH1XiL2WapK5DdClViblJWKQerJRjfJu8tcaxQ8Wpk6Ogw==", "dev": true, - "license": "MIT", "dependencies": { "@graphql-codegen/plugin-helpers": "^5.1.0", "@graphql-codegen/schema-ast": "^4.0.2", @@ -1780,7 +1758,6 @@ "resolved": "https://registry.npmjs.org/@graphql-codegen/typescript-operations/-/typescript-operations-4.4.0.tgz", "integrity": "sha512-oVlos2ySx8xIbbe8r5ZI6mOpI+OTeP14RmS2MchBJ6DL+S9G16O6+9V3Y8V22fTnmBTZkTfAAaBv4HYhhDGWVA==", "dev": true, - "license": "MIT", "dependencies": { "@graphql-codegen/plugin-helpers": "^5.1.0", "@graphql-codegen/typescript": "^4.1.2", @@ -1795,12 +1772,23 @@ "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0" } }, + "node_modules/@graphql-codegen/typescript-operations/node_modules/tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", + "dev": true + }, + "node_modules/@graphql-codegen/typescript/node_modules/tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", + "dev": true + }, "node_modules/@graphql-codegen/visitor-plugin-common": { "version": "5.6.0", "resolved": "https://registry.npmjs.org/@graphql-codegen/visitor-plugin-common/-/visitor-plugin-common-5.6.0.tgz", "integrity": "sha512-PowcVPJbUqMC9xTJ/ZRX1p/fsdMZREc+69CM1YY+AlFng2lL0zsdBskFJSRoviQk2Ch9IPhKGyHxlJCy9X22tg==", "dev": true, - "license": "MIT", "dependencies": { "@graphql-codegen/plugin-helpers": "^5.1.0", "@graphql-tools/optimize": "^2.0.0", @@ -1820,15 +1808,21 @@ "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0" } }, + "node_modules/@graphql-codegen/visitor-plugin-common/node_modules/tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", + "dev": true + }, "node_modules/@graphql-tools/apollo-engine-loader": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/@graphql-tools/apollo-engine-loader/-/apollo-engine-loader-8.0.1.tgz", - "integrity": "sha512-NaPeVjtrfbPXcl+MLQCJLWtqe2/E4bbAqcauEOQ+3sizw1Fc2CNmhHRF8a6W4D0ekvTRRXAMptXYgA2uConbrA==", + "version": "8.0.7", + "resolved": "https://registry.npmjs.org/@graphql-tools/apollo-engine-loader/-/apollo-engine-loader-8.0.7.tgz", + "integrity": "sha512-jyQU4ZhbkUM7C3V+m15K3ch7BSCTdWw/bthjhYhMkiMoFGL/ClNL5+fCIFMcQi5xSxPPmwkBkxzQ8u8UoNPMAg==", "dev": true, "dependencies": { "@ardatan/sync-fetch": "^0.0.1", - "@graphql-tools/utils": "^10.0.13", - "@whatwg-node/fetch": "^0.9.0", + "@graphql-tools/utils": "^10.6.2", + "@whatwg-node/fetch": "^0.10.0", "tslib": "^2.4.0" }, "engines": { @@ -1838,32 +1832,60 @@ "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" } }, + "node_modules/@graphql-tools/apollo-engine-loader/node_modules/@whatwg-node/fetch": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/@whatwg-node/fetch/-/fetch-0.10.1.tgz", + "integrity": "sha512-gmPOLrsjSZWEZlr9Oe5+wWFBq3CG6fN13rGlM91Jsj/vZ95G9CCvrORGBAxMXy0AJGiC83aYiHXn3JzTzXQmbA==", + "dev": true, + "dependencies": { + "@whatwg-node/node-fetch": "^0.7.1", + "urlpattern-polyfill": "^10.0.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@graphql-tools/apollo-engine-loader/node_modules/@whatwg-node/node-fetch": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/@whatwg-node/node-fetch/-/node-fetch-0.7.4.tgz", + "integrity": "sha512-rvUtU/xKKl/av5EIwyqfw7w0R+hx+tQrlhpIyFr27MwJRlUb+xcYv97kOmp7FE/WmQ8s+Tb6bcD6W8o/s2pGWw==", + "dev": true, + "dependencies": { + "@kamilkisiela/fast-url-parser": "^1.1.4", + "@whatwg-node/disposablestack": "^0.0.5", + "busboy": "^1.6.0", + "fast-querystring": "^1.1.1", + "tslib": "^2.6.3" + }, + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/@graphql-tools/batch-execute": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/@graphql-tools/batch-execute/-/batch-execute-9.0.4.tgz", - "integrity": "sha512-kkebDLXgDrep5Y0gK1RN3DMUlLqNhg60OAz0lTCqrYeja6DshxLtLkj+zV4mVbBA4mQOEoBmw6g1LZs3dA84/w==", + "version": "9.0.10", + "resolved": "https://registry.npmjs.org/@graphql-tools/batch-execute/-/batch-execute-9.0.10.tgz", + "integrity": "sha512-nCRNFq2eqy+ONDknd8DfqidY/Ljgyq67Q0Hb9SMJ3FOWpKrApqmNT9J1BA3JW4r+/zIGtM1VKi+P9FYu3zMHHA==", "dev": true, "dependencies": { - "@graphql-tools/utils": "^10.0.13", - "dataloader": "^2.2.2", - "tslib": "^2.4.0", - "value-or-promise": "^1.0.12" + "@graphql-tools/utils": "^10.6.2", + "dataloader": "^2.2.3", + "tslib": "^2.8.1" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" }, "peerDependencies": { "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" } }, "node_modules/@graphql-tools/code-file-loader": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/@graphql-tools/code-file-loader/-/code-file-loader-8.1.1.tgz", - "integrity": "sha512-q4KN25EPSUztc8rA8YUU3ufh721Yk12xXDbtUA+YstczWS7a1RJlghYMFEfR1HsHSYbF7cUqkbnTKSGM3o52bQ==", + "version": "8.1.8", + "resolved": "https://registry.npmjs.org/@graphql-tools/code-file-loader/-/code-file-loader-8.1.8.tgz", + "integrity": "sha512-b8BTP0cVTgWgc60H7LNfY7dZcEJVsgyCm52BsWOggwWapKAdli1T7ZaLJvnTAbVd8EY8+k4OAO1Z/ti1iirVOA==", "dev": true, "dependencies": { - "@graphql-tools/graphql-tag-pluck": "8.3.0", - "@graphql-tools/utils": "^10.0.13", + "@graphql-tools/graphql-tag-pluck": "8.3.7", + "@graphql-tools/utils": "^10.6.2", "globby": "^11.0.3", "tslib": "^2.4.0", "unixify": "^1.0.0" @@ -1876,29 +1898,31 @@ } }, "node_modules/@graphql-tools/delegate": { - "version": "10.0.4", - "resolved": "https://registry.npmjs.org/@graphql-tools/delegate/-/delegate-10.0.4.tgz", - "integrity": "sha512-WswZRbQZMh/ebhc8zSomK9DIh6Pd5KbuiMsyiKkKz37TWTrlCOe+4C/fyrBFez30ksq6oFyCeSKMwfrCbeGo0Q==", + "version": "10.2.7", + "resolved": "https://registry.npmjs.org/@graphql-tools/delegate/-/delegate-10.2.7.tgz", + "integrity": "sha512-cHNRguTi/RGxLttmDR5F4698kVtoPnYCFjgEZh/sg8MGrejTiCpQeg+aXUqcj0efWmnKIkeia5JaqqbTGpc0xA==", "dev": true, "dependencies": { - "@graphql-tools/batch-execute": "^9.0.4", - "@graphql-tools/executor": "^1.2.1", - "@graphql-tools/schema": "^10.0.3", - "@graphql-tools/utils": "^10.0.13", - "dataloader": "^2.2.2", - "tslib": "^2.5.0" + "@graphql-tools/batch-execute": "^9.0.10", + "@graphql-tools/executor": "^1.3.6", + "@graphql-tools/schema": "^10.0.11", + "@graphql-tools/utils": "^10.6.2", + "@repeaterjs/repeater": "^3.0.6", + "dataloader": "^2.2.3", + "dset": "^3.1.2", + "tslib": "^2.8.1" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" }, "peerDependencies": { "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" } }, "node_modules/@graphql-tools/documents": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@graphql-tools/documents/-/documents-1.0.0.tgz", - "integrity": "sha512-rHGjX1vg/nZ2DKqRGfDPNC55CWZBMldEVcH+91BThRa6JeT80NqXknffLLEZLRUxyikCfkwMsk6xR3UNMqG0Rg==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@graphql-tools/documents/-/documents-1.0.1.tgz", + "integrity": "sha512-aweoMH15wNJ8g7b2r4C4WRuJxZ0ca8HtNO54rkye/3duxTkW4fGBEutCx03jCIr5+a1l+4vFJNP859QnAVBVCA==", "dev": true, "dependencies": { "lodash.sortby": "^4.7.0", @@ -1912,12 +1936,12 @@ } }, "node_modules/@graphql-tools/executor": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@graphql-tools/executor/-/executor-1.2.4.tgz", - "integrity": "sha512-aCO/5LEAwyTWObAAfpLlwAjaOjTxRX6YNXcGW62mglQhPBy+j0fTc4desci/4nJ49l8FWETaTG0MZ1G/PqQslg==", + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/@graphql-tools/executor/-/executor-1.3.6.tgz", + "integrity": "sha512-ZmWsWdUhTez2b4w9NkmL4wpPb8n8WZmLOMIPTXH2A2yEe2nHrK/tk653JZXvZFtx2HrBIcoZD4Fe/STYWIR74Q==", "dev": true, "dependencies": { - "@graphql-tools/utils": "^10.1.1", + "@graphql-tools/utils": "^10.6.2", "@graphql-typed-document-node/core": "3.2.0", "@repeaterjs/repeater": "^3.0.4", "tslib": "^2.4.0", @@ -1931,57 +1955,87 @@ } }, "node_modules/@graphql-tools/executor-graphql-ws": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@graphql-tools/executor-graphql-ws/-/executor-graphql-ws-1.1.2.tgz", - "integrity": "sha512-+9ZK0rychTH1LUv4iZqJ4ESbmULJMTsv3XlFooPUngpxZkk00q6LqHKJRrsLErmQrVaC7cwQCaRBJa0teK17Lg==", + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@graphql-tools/executor-graphql-ws/-/executor-graphql-ws-1.3.5.tgz", + "integrity": "sha512-8BZf9a9SkaJAkF5Byb4ZdiwzCNoTrfl515m206XvCkCHM7dM1AwvX1rYZTrnJWgXgQUxhPjvll5vgciOe1APaA==", "dev": true, "dependencies": { - "@graphql-tools/utils": "^10.0.13", - "@types/ws": "^8.0.0", + "@graphql-tools/utils": "^10.6.2", + "@whatwg-node/disposablestack": "^0.0.5", "graphql-ws": "^5.14.0", "isomorphic-ws": "^5.0.0", - "tslib": "^2.4.0", - "ws": "^8.13.0" + "tslib": "^2.8.1", + "ws": "^8.17.1" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" }, "peerDependencies": { "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" } }, "node_modules/@graphql-tools/executor-http": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@graphql-tools/executor-http/-/executor-http-1.0.9.tgz", - "integrity": "sha512-+NXaZd2MWbbrWHqU4EhXcrDbogeiCDmEbrAN+rMn4Nu2okDjn2MTFDbTIab87oEubQCH4Te1wDkWPKrzXup7+Q==", + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/@graphql-tools/executor-http/-/executor-http-1.1.14.tgz", + "integrity": "sha512-y/j+fOTgkYSEDzLQ7xMErSfg6kgejVhG4yieKy1PXBaiDNN8t9MOUxEJDDtRDr/pFnvjTtm78UFo04I7S+m7BA==", "dev": true, "dependencies": { - "@graphql-tools/utils": "^10.0.13", + "@graphql-tools/utils": "^10.6.2", "@repeaterjs/repeater": "^3.0.4", - "@whatwg-node/fetch": "^0.9.0", + "@whatwg-node/disposablestack": "^0.0.5", + "@whatwg-node/fetch": "^0.10.1", "extract-files": "^11.0.0", "meros": "^1.2.1", - "tslib": "^2.4.0", + "tslib": "^2.8.1", "value-or-promise": "^1.0.12" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" }, "peerDependencies": { "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" } }, + "node_modules/@graphql-tools/executor-http/node_modules/@whatwg-node/fetch": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/@whatwg-node/fetch/-/fetch-0.10.1.tgz", + "integrity": "sha512-gmPOLrsjSZWEZlr9Oe5+wWFBq3CG6fN13rGlM91Jsj/vZ95G9CCvrORGBAxMXy0AJGiC83aYiHXn3JzTzXQmbA==", + "dev": true, + "dependencies": { + "@whatwg-node/node-fetch": "^0.7.1", + "urlpattern-polyfill": "^10.0.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@graphql-tools/executor-http/node_modules/@whatwg-node/node-fetch": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/@whatwg-node/node-fetch/-/node-fetch-0.7.4.tgz", + "integrity": "sha512-rvUtU/xKKl/av5EIwyqfw7w0R+hx+tQrlhpIyFr27MwJRlUb+xcYv97kOmp7FE/WmQ8s+Tb6bcD6W8o/s2pGWw==", + "dev": true, + "dependencies": { + "@kamilkisiela/fast-url-parser": "^1.1.4", + "@whatwg-node/disposablestack": "^0.0.5", + "busboy": "^1.6.0", + "fast-querystring": "^1.1.1", + "tslib": "^2.6.3" + }, + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/@graphql-tools/executor-legacy-ws": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/@graphql-tools/executor-legacy-ws/-/executor-legacy-ws-1.0.6.tgz", - "integrity": "sha512-lDSxz9VyyquOrvSuCCnld3256Hmd+QI2lkmkEv7d4mdzkxkK4ddAWW1geQiWrQvWmdsmcnGGlZ7gDGbhEExwqg==", + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@graphql-tools/executor-legacy-ws/-/executor-legacy-ws-1.1.5.tgz", + "integrity": "sha512-iqN3NYpv4mGTOUUkhNOL0v9kskVHXl1BrzueRtDFaWznjO7qpwAUwCAih3AMHDNadLQdppkjIhOJB+YU8KCfsQ==", "dev": true, "dependencies": { - "@graphql-tools/utils": "^10.0.13", + "@graphql-tools/utils": "^10.6.2", "@types/ws": "^8.0.0", "isomorphic-ws": "^5.0.0", "tslib": "^2.4.0", - "ws": "^8.15.0" + "ws": "^8.17.1" }, "engines": { "node": ">=16.0.0" @@ -1991,15 +2045,15 @@ } }, "node_modules/@graphql-tools/git-loader": { - "version": "8.0.5", - "resolved": "https://registry.npmjs.org/@graphql-tools/git-loader/-/git-loader-8.0.5.tgz", - "integrity": "sha512-P97/1mhruDiA6D5WUmx3n/aeGPLWj2+4dpzDOxFGGU+z9NcI/JdygMkeFpGZNHeJfw+kHfxgPcMPnxHcyhAoVA==", + "version": "8.0.12", + "resolved": "https://registry.npmjs.org/@graphql-tools/git-loader/-/git-loader-8.0.12.tgz", + "integrity": "sha512-B65UbwMeR6TWwTzz5OS6iGuqSa1za/lbLO3buSwDs8+zxTpqrJljeKllG2EFk7g7D2OtTt3Tu9+itWkuIbqOUw==", "dev": true, "dependencies": { - "@graphql-tools/graphql-tag-pluck": "8.3.0", - "@graphql-tools/utils": "^10.0.13", + "@graphql-tools/graphql-tag-pluck": "8.3.7", + "@graphql-tools/utils": "^10.6.2", "is-glob": "4.0.3", - "micromatch": "^4.0.4", + "micromatch": "^4.0.8", "tslib": "^2.4.0", "unixify": "^1.0.0" }, @@ -2011,16 +2065,16 @@ } }, "node_modules/@graphql-tools/github-loader": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/@graphql-tools/github-loader/-/github-loader-8.0.1.tgz", - "integrity": "sha512-W4dFLQJ5GtKGltvh/u1apWRFKBQOsDzFxO9cJkOYZj1VzHCpRF43uLST4VbCfWve+AwBqOuKr7YgkHoxpRMkcg==", + "version": "8.0.7", + "resolved": "https://registry.npmjs.org/@graphql-tools/github-loader/-/github-loader-8.0.7.tgz", + "integrity": "sha512-p7aGLbOkwLTCKk/hSEJJgrSIhbwNS7SBhtYFPMa1uoga4I10xDJuGrUl8l9Jq2y953rtJA6/aGyVJs87Yn2hwA==", "dev": true, "dependencies": { "@ardatan/sync-fetch": "^0.0.1", - "@graphql-tools/executor-http": "^1.0.9", - "@graphql-tools/graphql-tag-pluck": "^8.0.0", - "@graphql-tools/utils": "^10.0.13", - "@whatwg-node/fetch": "^0.9.0", + "@graphql-tools/executor-http": "^1.1.9", + "@graphql-tools/graphql-tag-pluck": "^8.3.7", + "@graphql-tools/utils": "^10.6.2", + "@whatwg-node/fetch": "^0.10.0", "tslib": "^2.4.0", "value-or-promise": "^1.0.12" }, @@ -2031,14 +2085,43 @@ "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" } }, + "node_modules/@graphql-tools/github-loader/node_modules/@whatwg-node/fetch": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/@whatwg-node/fetch/-/fetch-0.10.1.tgz", + "integrity": "sha512-gmPOLrsjSZWEZlr9Oe5+wWFBq3CG6fN13rGlM91Jsj/vZ95G9CCvrORGBAxMXy0AJGiC83aYiHXn3JzTzXQmbA==", + "dev": true, + "dependencies": { + "@whatwg-node/node-fetch": "^0.7.1", + "urlpattern-polyfill": "^10.0.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@graphql-tools/github-loader/node_modules/@whatwg-node/node-fetch": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/@whatwg-node/node-fetch/-/node-fetch-0.7.4.tgz", + "integrity": "sha512-rvUtU/xKKl/av5EIwyqfw7w0R+hx+tQrlhpIyFr27MwJRlUb+xcYv97kOmp7FE/WmQ8s+Tb6bcD6W8o/s2pGWw==", + "dev": true, + "dependencies": { + "@kamilkisiela/fast-url-parser": "^1.1.4", + "@whatwg-node/disposablestack": "^0.0.5", + "busboy": "^1.6.0", + "fast-querystring": "^1.1.1", + "tslib": "^2.6.3" + }, + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/@graphql-tools/graphql-file-loader": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/@graphql-tools/graphql-file-loader/-/graphql-file-loader-8.0.1.tgz", - "integrity": "sha512-7gswMqWBabTSmqbaNyWSmRRpStWlcCkBc73E6NZNlh4YNuiyKOwbvSkOUYFOqFMfEL+cFsXgAvr87Vz4XrYSbA==", + "version": "8.0.6", + "resolved": "https://registry.npmjs.org/@graphql-tools/graphql-file-loader/-/graphql-file-loader-8.0.6.tgz", + "integrity": "sha512-nLOvotKcvZLXQWryYl34vHI4Fr+VTA/y6WHcZ73gXBQ//8oGKgnuDNoAdi4rXgk4iGyIMvRxZpYU27k6Z4acBw==", "dev": true, "dependencies": { - "@graphql-tools/import": "7.0.1", - "@graphql-tools/utils": "^10.0.13", + "@graphql-tools/import": "7.0.6", + "@graphql-tools/utils": "^10.6.2", "globby": "^11.0.3", "tslib": "^2.4.0", "unixify": "^1.0.0" @@ -2051,9 +2134,9 @@ } }, "node_modules/@graphql-tools/graphql-tag-pluck": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/@graphql-tools/graphql-tag-pluck/-/graphql-tag-pluck-8.3.0.tgz", - "integrity": "sha512-gNqukC+s7iHC7vQZmx1SEJQmLnOguBq+aqE2zV2+o1hxkExvKqyFli1SY/9gmukFIKpKutCIj+8yLOM+jARutw==", + "version": "8.3.7", + "resolved": "https://registry.npmjs.org/@graphql-tools/graphql-tag-pluck/-/graphql-tag-pluck-8.3.7.tgz", + "integrity": "sha512-QoGf/8oVzhMZW+EbgpkM7zUxlNyv60Twb254R0D8TxS19OznoMMZMiDJdoID/k42QRoJ7o1V/yEOHgJFcqYHVw==", "dev": true, "dependencies": { "@babel/core": "^7.22.9", @@ -2061,7 +2144,7 @@ "@babel/plugin-syntax-import-assertions": "^7.20.0", "@babel/traverse": "^7.16.8", "@babel/types": "^7.16.8", - "@graphql-tools/utils": "^10.0.13", + "@graphql-tools/utils": "^10.6.2", "tslib": "^2.4.0" }, "engines": { @@ -2072,12 +2155,12 @@ } }, "node_modules/@graphql-tools/import": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/@graphql-tools/import/-/import-7.0.1.tgz", - "integrity": "sha512-935uAjAS8UAeXThqHfYVr4HEAp6nHJ2sximZKO1RzUTq5WoALMAhhGARl0+ecm6X+cqNUwIChJbjtaa6P/ML0w==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/@graphql-tools/import/-/import-7.0.6.tgz", + "integrity": "sha512-F28lG9w3gckZ+ubnq3jM2s2OiyH+cVZZXvOZ8RO/EJQ0dS+BE/S9zzvpCTuOWyuZvcLvbYBDjliZTOmeSQUhMg==", "dev": true, "dependencies": { - "@graphql-tools/utils": "^10.0.13", + "@graphql-tools/utils": "^10.6.2", "resolve-from": "5.0.0", "tslib": "^2.4.0" }, @@ -2089,12 +2172,12 @@ } }, "node_modules/@graphql-tools/json-file-loader": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/@graphql-tools/json-file-loader/-/json-file-loader-8.0.1.tgz", - "integrity": "sha512-lAy2VqxDAHjVyqeJonCP6TUemrpYdDuKt25a10X6zY2Yn3iFYGnuIDQ64cv3ytyGY6KPyPB+Kp+ZfOkNDG3FQA==", + "version": "8.0.6", + "resolved": "https://registry.npmjs.org/@graphql-tools/json-file-loader/-/json-file-loader-8.0.6.tgz", + "integrity": "sha512-mjZFVMtBL9fcvovwCoXKjZxXqr92/dcPZmHlQsW9jUC9WW6KfmolwtyvRxy9CcOjjh1HDTPcNoDgW05iI1CFYQ==", "dev": true, "dependencies": { - "@graphql-tools/utils": "^10.0.13", + "@graphql-tools/utils": "^10.6.2", "globby": "^11.0.3", "tslib": "^2.4.0", "unixify": "^1.0.0" @@ -2107,13 +2190,13 @@ } }, "node_modules/@graphql-tools/load": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@graphql-tools/load/-/load-8.0.2.tgz", - "integrity": "sha512-S+E/cmyVmJ3CuCNfDuNF2EyovTwdWfQScXv/2gmvJOti2rGD8jTt9GYVzXaxhblLivQR9sBUCNZu/w7j7aXUCA==", + "version": "8.0.7", + "resolved": "https://registry.npmjs.org/@graphql-tools/load/-/load-8.0.7.tgz", + "integrity": "sha512-1JmZaMxs9LOyyq7XF/knBxY+Uejnc68+nILCFYwsts9KTUOZHpJqjleIIDf7Il1yHDaujjThX4Xqg2Dwhdb/bw==", "dev": true, "dependencies": { - "@graphql-tools/schema": "^10.0.3", - "@graphql-tools/utils": "^10.0.13", + "@graphql-tools/schema": "^10.0.11", + "@graphql-tools/utils": "^10.6.2", "p-limit": "3.1.0", "tslib": "^2.4.0" }, @@ -2125,12 +2208,12 @@ } }, "node_modules/@graphql-tools/merge": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/@graphql-tools/merge/-/merge-9.0.3.tgz", - "integrity": "sha512-FeKv9lKLMwqDu0pQjPpF59GY3HReUkWXKsMIuMuJQOKh9BETu7zPEFUELvcw8w+lwZkl4ileJsHXC9+AnsT2Lw==", + "version": "9.0.12", + "resolved": "https://registry.npmjs.org/@graphql-tools/merge/-/merge-9.0.12.tgz", + "integrity": "sha512-ECkUdgWkizhzQ6JJg16MCYnIN2r2+q/vP5smzi3YeeJkZ/3f9ynFDkaqoMg0Ddg9MugR03hMiQQrssk5f0389Q==", "dev": true, "dependencies": { - "@graphql-tools/utils": "^10.0.13", + "@graphql-tools/utils": "^10.6.2", "tslib": "^2.4.0" }, "engines": { @@ -2156,16 +2239,15 @@ } }, "node_modules/@graphql-tools/prisma-loader": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/@graphql-tools/prisma-loader/-/prisma-loader-8.0.3.tgz", - "integrity": "sha512-oZhxnMr3Jw2WAW1h9FIhF27xWzIB7bXWM8olz4W12oII4NiZl7VRkFw9IT50zME2Bqi9LGh9pkmMWkjvbOpl+Q==", + "version": "8.0.17", + "resolved": "https://registry.npmjs.org/@graphql-tools/prisma-loader/-/prisma-loader-8.0.17.tgz", + "integrity": "sha512-fnuTLeQhqRbA156pAyzJYN0KxCjKYRU5bz1q/SKOwElSnAU4k7/G1kyVsWLh7fneY78LoMNH5n+KlFV8iQlnyg==", "dev": true, "dependencies": { - "@graphql-tools/url-loader": "^8.0.2", - "@graphql-tools/utils": "^10.0.13", + "@graphql-tools/url-loader": "^8.0.15", + "@graphql-tools/utils": "^10.5.6", "@types/js-yaml": "^4.0.0", - "@types/json-stable-stringify": "^1.0.32", - "@whatwg-node/fetch": "^0.9.0", + "@whatwg-node/fetch": "^0.10.0", "chalk": "^4.1.0", "debug": "^4.3.1", "dotenv": "^16.0.0", @@ -2174,7 +2256,6 @@ "https-proxy-agent": "^7.0.0", "jose": "^5.0.0", "js-yaml": "^4.0.0", - "json-stable-stringify": "^1.0.1", "lodash": "^4.17.20", "scuid": "^1.1.0", "tslib": "^2.4.0", @@ -2187,12 +2268,40 @@ "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" } }, + "node_modules/@graphql-tools/prisma-loader/node_modules/@whatwg-node/fetch": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/@whatwg-node/fetch/-/fetch-0.10.1.tgz", + "integrity": "sha512-gmPOLrsjSZWEZlr9Oe5+wWFBq3CG6fN13rGlM91Jsj/vZ95G9CCvrORGBAxMXy0AJGiC83aYiHXn3JzTzXQmbA==", + "dev": true, + "dependencies": { + "@whatwg-node/node-fetch": "^0.7.1", + "urlpattern-polyfill": "^10.0.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@graphql-tools/prisma-loader/node_modules/@whatwg-node/node-fetch": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/@whatwg-node/node-fetch/-/node-fetch-0.7.4.tgz", + "integrity": "sha512-rvUtU/xKKl/av5EIwyqfw7w0R+hx+tQrlhpIyFr27MwJRlUb+xcYv97kOmp7FE/WmQ8s+Tb6bcD6W8o/s2pGWw==", + "dev": true, + "dependencies": { + "@kamilkisiela/fast-url-parser": "^1.1.4", + "@whatwg-node/disposablestack": "^0.0.5", + "busboy": "^1.6.0", + "fast-querystring": "^1.1.1", + "tslib": "^2.6.3" + }, + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/@graphql-tools/prisma-loader/node_modules/graphql-request": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/graphql-request/-/graphql-request-6.1.0.tgz", "integrity": "sha512-p+XPfS4q7aIpKVcgmnZKhMNqhltk20hfXtkaIkTfjjmiKMJ5xrt5c743cL03y/K7y1rg3WrIC49xGiEQ4mxdNw==", "dev": true, - "license": "MIT", "dependencies": { "@graphql-typed-document-node/core": "^3.2.0", "cross-fetch": "^3.1.5" @@ -2202,13 +2311,13 @@ } }, "node_modules/@graphql-tools/relay-operation-optimizer": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/@graphql-tools/relay-operation-optimizer/-/relay-operation-optimizer-7.0.1.tgz", - "integrity": "sha512-y0ZrQ/iyqWZlsS/xrJfSir3TbVYJTYmMOu4TaSz6F4FRDTQ3ie43BlKkhf04rC28pnUOS4BO9pDcAo1D30l5+A==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/@graphql-tools/relay-operation-optimizer/-/relay-operation-optimizer-7.0.6.tgz", + "integrity": "sha512-hzzH1flmvL0o7tczQbnGVmsaLruhl8rxoqszo6uBjjjPxppoT0vwqIvU5X+lGJi2U+/fv3Q2FV3XALQB5Pmeaw==", "dev": true, "dependencies": { "@ardatan/relay-compiler": "12.0.0", - "@graphql-tools/utils": "^10.0.13", + "@graphql-tools/utils": "^10.6.2", "tslib": "^2.4.0" }, "engines": { @@ -2219,13 +2328,13 @@ } }, "node_modules/@graphql-tools/schema": { - "version": "10.0.3", - "resolved": "https://registry.npmjs.org/@graphql-tools/schema/-/schema-10.0.3.tgz", - "integrity": "sha512-p28Oh9EcOna6i0yLaCFOnkcBDQECVf3SCexT6ktb86QNj9idnkhI+tCxnwZDh58Qvjd2nURdkbevvoZkvxzCog==", + "version": "10.0.11", + "resolved": "https://registry.npmjs.org/@graphql-tools/schema/-/schema-10.0.11.tgz", + "integrity": "sha512-cYr/7SJSKtdwPByTKHlBr0tYGf7/sYNyzKlPhPMHWoYyGxtn8ytbfF6wEUcxuaOoqksIFxOGr+WOJh1WvShb6A==", "dev": true, "dependencies": { - "@graphql-tools/merge": "^9.0.3", - "@graphql-tools/utils": "^10.0.13", + "@graphql-tools/merge": "^9.0.12", + "@graphql-tools/utils": "^10.6.2", "tslib": "^2.4.0", "value-or-promise": "^1.0.12" }, @@ -2237,24 +2346,23 @@ } }, "node_modules/@graphql-tools/url-loader": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@graphql-tools/url-loader/-/url-loader-8.0.2.tgz", - "integrity": "sha512-1dKp2K8UuFn7DFo1qX5c1cyazQv2h2ICwA9esHblEqCYrgf69Nk8N7SODmsfWg94OEaI74IqMoM12t7eIGwFzQ==", + "version": "8.0.18", + "resolved": "https://registry.npmjs.org/@graphql-tools/url-loader/-/url-loader-8.0.18.tgz", + "integrity": "sha512-gz6oRoZzUJyBDIVMBKFa35InRqzq3FOb/kEb+8T3/DrDZCIxFlmLBZzy9ANjKmF3ctLn0WQXopRSaG/Wq7NEwA==", "dev": true, "dependencies": { "@ardatan/sync-fetch": "^0.0.1", - "@graphql-tools/delegate": "^10.0.4", - "@graphql-tools/executor-graphql-ws": "^1.1.2", - "@graphql-tools/executor-http": "^1.0.9", - "@graphql-tools/executor-legacy-ws": "^1.0.6", - "@graphql-tools/utils": "^10.0.13", - "@graphql-tools/wrap": "^10.0.2", + "@graphql-tools/executor-graphql-ws": "^1.3.2", + "@graphql-tools/executor-http": "^1.1.9", + "@graphql-tools/executor-legacy-ws": "^1.1.5", + "@graphql-tools/utils": "^10.6.2", + "@graphql-tools/wrap": "^10.0.16", "@types/ws": "^8.0.0", - "@whatwg-node/fetch": "^0.9.0", + "@whatwg-node/fetch": "^0.10.0", "isomorphic-ws": "^5.0.0", "tslib": "^2.4.0", "value-or-promise": "^1.0.11", - "ws": "^8.12.0" + "ws": "^8.17.1" }, "engines": { "node": ">=16.0.0" @@ -2263,14 +2371,43 @@ "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" } }, + "node_modules/@graphql-tools/url-loader/node_modules/@whatwg-node/fetch": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/@whatwg-node/fetch/-/fetch-0.10.1.tgz", + "integrity": "sha512-gmPOLrsjSZWEZlr9Oe5+wWFBq3CG6fN13rGlM91Jsj/vZ95G9CCvrORGBAxMXy0AJGiC83aYiHXn3JzTzXQmbA==", + "dev": true, + "dependencies": { + "@whatwg-node/node-fetch": "^0.7.1", + "urlpattern-polyfill": "^10.0.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@graphql-tools/url-loader/node_modules/@whatwg-node/node-fetch": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/@whatwg-node/node-fetch/-/node-fetch-0.7.4.tgz", + "integrity": "sha512-rvUtU/xKKl/av5EIwyqfw7w0R+hx+tQrlhpIyFr27MwJRlUb+xcYv97kOmp7FE/WmQ8s+Tb6bcD6W8o/s2pGWw==", + "dev": true, + "dependencies": { + "@kamilkisiela/fast-url-parser": "^1.1.4", + "@whatwg-node/disposablestack": "^0.0.5", + "busboy": "^1.6.0", + "fast-querystring": "^1.1.1", + "tslib": "^2.6.3" + }, + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/@graphql-tools/utils": { - "version": "10.1.2", - "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-10.1.2.tgz", - "integrity": "sha512-fX13CYsDnX4yifIyNdiN0cVygz/muvkreWWem6BBw130+ODbRRgfiVveL0NizCEnKXkpvdeTy9Bxvo9LIKlhrw==", + "version": "10.6.2", + "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-10.6.2.tgz", + "integrity": "sha512-ABZHTpwiVR8oE2//NI/nnU3nNhbBpqMlMYyCF5cnqjLfhlyOdFfoRuhYEATEsmMfDg0ijGreULywK/SmepVGfw==", "dev": true, "dependencies": { "@graphql-typed-document-node/core": "^3.1.1", - "cross-inspect": "1.0.0", + "cross-inspect": "1.0.1", "dset": "^3.1.2", "tslib": "^2.4.0" }, @@ -2282,19 +2419,18 @@ } }, "node_modules/@graphql-tools/wrap": { - "version": "10.0.5", - "resolved": "https://registry.npmjs.org/@graphql-tools/wrap/-/wrap-10.0.5.tgz", - "integrity": "sha512-Cbr5aYjr3HkwdPvetZp1cpDWTGdD1Owgsb3z/ClzhmrboiK86EnQDxDvOJiQkDCPWE9lNBwj8Y4HfxroY0D9DQ==", + "version": "10.0.25", + "resolved": "https://registry.npmjs.org/@graphql-tools/wrap/-/wrap-10.0.25.tgz", + "integrity": "sha512-51Koxi6IZHF4Ns7c6jvLU2x7GJyGGDL7V6e0u4J6ci/0vSCqLBwT3YYutDlZ7uJTpbLjEbjl0R0+1fOerdIkOQ==", "dev": true, "dependencies": { - "@graphql-tools/delegate": "^10.0.4", - "@graphql-tools/schema": "^10.0.3", - "@graphql-tools/utils": "^10.1.1", - "tslib": "^2.4.0", - "value-or-promise": "^1.0.12" + "@graphql-tools/delegate": "^10.2.7", + "@graphql-tools/schema": "^10.0.11", + "@graphql-tools/utils": "^10.6.2", + "tslib": "^2.8.1" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" }, "peerDependencies": { "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" @@ -2314,7 +2450,6 @@ "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==", "deprecated": "Use @eslint/config-array instead", "dev": true, - "license": "Apache-2.0", "dependencies": { "@humanwhocodes/object-schema": "^2.0.3", "debug": "^4.3.1", @@ -2364,15 +2499,13 @@ "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", "deprecated": "Use @eslint/object-schema instead", - "dev": true, - "license": "BSD-3-Clause" + "dev": true }, "node_modules/@isaacs/cliui": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", "dev": true, - "license": "ISC", "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", @@ -2386,11 +2519,10 @@ } }, "node_modules/@isaacs/cliui/node_modules/ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", "dev": true, - "license": "MIT", "engines": { "node": ">=12" }, @@ -2403,7 +2535,6 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", "dev": true, - "license": "MIT", "engines": { "node": ">=12" }, @@ -2416,7 +2547,6 @@ "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", "dev": true, - "license": "MIT", "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", @@ -2434,7 +2564,6 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", "dev": true, - "license": "MIT", "dependencies": { "ansi-regex": "^6.0.1" }, @@ -2450,7 +2579,6 @@ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", "dev": true, - "license": "MIT", "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", @@ -2508,8 +2636,7 @@ "version": "1.5.0", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.25", @@ -2537,8 +2664,7 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/@kamilkisiela/fast-url-parser/-/fast-url-parser-1.1.4.tgz", "integrity": "sha512-gbkePEBupNydxCelHCESvFSFM8XPh1Zs/OAVRW/rKpEqPAl5PbOM90Si8mv9bvnR53uPD2s/FiRxdvSejpRJew==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/@mapbox/geojson-rewind": { "version": "0.5.2", @@ -2592,10 +2718,9 @@ } }, "node_modules/@maplibre/maplibre-gl-style-spec": { - "version": "20.3.1", - "resolved": "https://registry.npmjs.org/@maplibre/maplibre-gl-style-spec/-/maplibre-gl-style-spec-20.3.1.tgz", - "integrity": "sha512-5ueL4UDitzVtceQ8J4kY+Px3WK+eZTsmGwha3MBKHKqiHvKrjWWwBCIl1K8BuJSc5OFh83uI8IFNoFvQxX2uUw==", - "license": "ISC", + "version": "20.4.0", + "resolved": "https://registry.npmjs.org/@maplibre/maplibre-gl-style-spec/-/maplibre-gl-style-spec-20.4.0.tgz", + "integrity": "sha512-AzBy3095fTFPjDjmWpR2w6HVRAZJ6hQZUCwk5Plz6EyfnfuQW1odeW5i2Ai47Y6TBA2hQnC+azscjBSALpaWgw==", "dependencies": { "@mapbox/jsonlint-lines-primitives": "~2.0.2", "@mapbox/unitbezier": "^0.0.1", @@ -2603,7 +2728,6 @@ "minimist": "^1.2.8", "quickselect": "^2.0.0", "rw": "^1.3.3", - "sort-object": "^3.0.3", "tinyqueue": "^3.0.0" }, "bin": { @@ -2612,6 +2736,11 @@ "gl-style-validate": "dist/gl-style-validate.mjs" } }, + "node_modules/@maplibre/maplibre-gl-style-spec/node_modules/quickselect": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/quickselect/-/quickselect-2.0.0.tgz", + "integrity": "sha512-RKJ22hX8mHe3Y6wH/N3wCM6BWtjaxIyyUIkpHOvfFnxdI4yD4tBXEBKSbriGujF6jnSVkJrffuo6vxACiSSxIw==" + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -2653,7 +2782,6 @@ "integrity": "sha512-i0GV1yJnm2n3Yq1qw6QrUrd/LI9bE8WEBOTtOkpCXHHdyN3TAGgqAK/DAT05z4fq2x04cARXt2pDmjWjL92iTQ==", "dev": true, "hasInstallScript": true, - "license": "MIT", "dependencies": { "detect-libc": "^1.0.3", "is-glob": "^4.0.3", @@ -2691,7 +2819,6 @@ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "android" @@ -2712,7 +2839,6 @@ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "darwin" @@ -2733,7 +2859,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "darwin" @@ -2754,7 +2879,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "freebsd" @@ -2775,7 +2899,6 @@ "arm" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -2796,7 +2919,6 @@ "arm" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -2817,7 +2939,6 @@ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -2838,7 +2959,6 @@ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -2859,7 +2979,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -2880,7 +2999,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -2901,7 +3019,6 @@ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "win32" @@ -2922,7 +3039,6 @@ "ia32" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "win32" @@ -2943,7 +3059,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "win32" @@ -2961,7 +3076,6 @@ "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", "dev": true, - "license": "MIT", "optional": true, "engines": { "node": ">=14" @@ -2977,9 +3091,9 @@ } }, "node_modules/@react-aria/ssr": { - "version": "3.9.2", - "resolved": "https://registry.npmjs.org/@react-aria/ssr/-/ssr-3.9.2.tgz", - "integrity": "sha512-0gKkgDYdnq1w+ey8KzG9l+H5Z821qh9vVjztk55rUg71vTk/Eaebeir+WtzcLLwTjw3m/asIjx8Y59y1lJZhBw==", + "version": "3.9.7", + "resolved": "https://registry.npmjs.org/@react-aria/ssr/-/ssr-3.9.7.tgz", + "integrity": "sha512-GQygZaGlmYjmYM+tiNBA5C6acmiDWF52Nqd40bBp0Znk4M4hP+LTmI0lpI1BuKMw45T8RIhrAsICIfKwZvi2Gg==", "dependencies": { "@swc/helpers": "^0.5.0" }, @@ -2987,13 +3101,13 @@ "node": ">= 12" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0" + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" } }, "node_modules/@repeaterjs/repeater": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@repeaterjs/repeater/-/repeater-3.0.5.tgz", - "integrity": "sha512-l3YHBLAol6d/IKnB9LhpD0cEZWAoe3eFKUyTYWmFmCO2Q/WOckxLQAUyMZWwZV2M/m3+4vgRoaolFqaII82/TA==", + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@repeaterjs/repeater/-/repeater-3.0.6.tgz", + "integrity": "sha512-Javneu5lsuhwNCryN+pXH93VPQ8g0dBX7wItHFgYiwQmzE1sVdg5tWHiOgHywzL2W21XQopa7IwIEnNbmeUJYA==", "dev": true }, "node_modules/@restart/hooks": { @@ -3011,7 +3125,6 @@ "version": "1.9.1", "resolved": "https://registry.npmjs.org/@restart/ui/-/ui-1.9.1.tgz", "integrity": "sha512-qghR21ynHiUrpcIkKCoKYB+3rJtezY5Y7ikrwradCL+7hZHdQ2Ozc5ffxtpmpahoAGgc31gyXaSx2sXXaThmqA==", - "license": "MIT", "dependencies": { "@babel/runtime": "^7.26.0", "@popperjs/core": "^2.11.8", @@ -3032,7 +3145,6 @@ "version": "0.5.0", "resolved": "https://registry.npmjs.org/@restart/hooks/-/hooks-0.5.0.tgz", "integrity": "sha512-wS+h6IusJCPjTkmOOrRZxIPICD/mtFA3PRZviutoM23/b7akyDGfZF/WS+nIFk27u7JDhPE2+0GBdZxjSqHZkg==", - "license": "MIT", "dependencies": { "dequal": "^2.0.3" }, @@ -3049,9 +3161,9 @@ } }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.27.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.27.4.tgz", - "integrity": "sha512-2Y3JT6f5MrQkICUyRVCw4oa0sutfAsgaSsb0Lmmy1Wi2y7X5vT9Euqw4gOsCyy0YfKURBg35nhUKZS4mDcfULw==", + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.28.1.tgz", + "integrity": "sha512-2aZp8AES04KI2dy3Ss6/MDjXbwBzj+i0GqKtWXgw2/Ma6E4jJvujryO6gJAghIRVz7Vwr9Gtl/8na3nDUKpraQ==", "cpu": [ "arm" ], @@ -3062,9 +3174,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.27.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.27.4.tgz", - "integrity": "sha512-wzKRQXISyi9UdCVRqEd0H4cMpzvHYt1f/C3CoIjES6cG++RHKhrBj2+29nPF0IB5kpy9MS71vs07fvrNGAl/iA==", + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.28.1.tgz", + "integrity": "sha512-EbkK285O+1YMrg57xVA+Dp0tDBRB93/BZKph9XhMjezf6F4TpYjaUSuPt5J0fZXlSag0LmZAsTmdGGqPp4pQFA==", "cpu": [ "arm64" ], @@ -3075,9 +3187,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.27.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.27.4.tgz", - "integrity": "sha512-PlNiRQapift4LNS8DPUHuDX/IdXiLjf8mc5vdEmUR0fF/pyy2qWwzdLjB+iZquGr8LuN4LnUoSEvKRwjSVYz3Q==", + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.28.1.tgz", + "integrity": "sha512-prduvrMKU6NzMq6nxzQw445zXgaDBbMQvmKSJaxpaZ5R1QDM8w+eGxo6Y/jhT/cLoCvnZI42oEqf9KQNYz1fqQ==", "cpu": [ "arm64" ], @@ -3088,9 +3200,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.27.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.27.4.tgz", - "integrity": "sha512-o9bH2dbdgBDJaXWJCDTNDYa171ACUdzpxSZt+u/AAeQ20Nk5x+IhA+zsGmrQtpkLiumRJEYef68gcpn2ooXhSQ==", + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.28.1.tgz", + "integrity": "sha512-WsvbOunsUk0wccO/TV4o7IKgloJ942hVFK1CLatwv6TJspcCZb9umQkPdvB7FihmdxgaKR5JyxDjWpCOp4uZlQ==", "cpu": [ "x64" ], @@ -3101,9 +3213,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.27.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.27.4.tgz", - "integrity": "sha512-NBI2/i2hT9Q+HySSHTBh52da7isru4aAAo6qC3I7QFVsuhxi2gM8t/EI9EVcILiHLj1vfi+VGGPaLOUENn7pmw==", + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.28.1.tgz", + "integrity": "sha512-HTDPdY1caUcU4qK23FeeGxCdJF64cKkqajU0iBnTVxS8F7H/7BewvYoG+va1KPSL63kQ1PGNyiwKOfReavzvNA==", "cpu": [ "arm64" ], @@ -3114,9 +3226,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.27.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.27.4.tgz", - "integrity": "sha512-wYcC5ycW2zvqtDYrE7deary2P2UFmSh85PUpAx+dwTCO9uw3sgzD6Gv9n5X4vLaQKsrfTSZZ7Z7uynQozPVvWA==", + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.28.1.tgz", + "integrity": "sha512-m/uYasxkUevcFTeRSM9TeLyPe2QDuqtjkeoTpP9SW0XxUWfcYrGDMkO/m2tTw+4NMAF9P2fU3Mw4ahNvo7QmsQ==", "cpu": [ "x64" ], @@ -3127,9 +3239,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.27.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.27.4.tgz", - "integrity": "sha512-9OwUnK/xKw6DyRlgx8UizeqRFOfi9mf5TYCw1uolDaJSbUmBxP85DE6T4ouCMoN6pXw8ZoTeZCSEfSaYo+/s1w==", + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.28.1.tgz", + "integrity": "sha512-QAg11ZIt6mcmzpNE6JZBpKfJaKkqTm1A9+y9O+frdZJEuhQxiugM05gnCWiANHj4RmbgeVJpTdmKRmH/a+0QbA==", "cpu": [ "arm" ], @@ -3140,9 +3252,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.27.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.27.4.tgz", - "integrity": "sha512-Vgdo4fpuphS9V24WOV+KwkCVJ72u7idTgQaBoLRD0UxBAWTF9GWurJO9YD9yh00BzbkhpeXtm6na+MvJU7Z73A==", + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.28.1.tgz", + "integrity": "sha512-dRP9PEBfolq1dmMcFqbEPSd9VlRuVWEGSmbxVEfiq2cs2jlZAl0YNxFzAQS2OrQmsLBLAATDMb3Z6MFv5vOcXg==", "cpu": [ "arm" ], @@ -3153,9 +3265,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.27.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.27.4.tgz", - "integrity": "sha512-pleyNgyd1kkBkw2kOqlBx+0atfIIkkExOTiifoODo6qKDSpnc6WzUY5RhHdmTdIJXBdSnh6JknnYTtmQyobrVg==", + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.28.1.tgz", + "integrity": "sha512-uGr8khxO+CKT4XU8ZUH1TTEUtlktK6Kgtv0+6bIFSeiSlnGJHG1tSFSjm41uQ9sAO/5ULx9mWOz70jYLyv1QkA==", "cpu": [ "arm64" ], @@ -3166,9 +3278,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.27.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.27.4.tgz", - "integrity": "sha512-caluiUXvUuVyCHr5DxL8ohaaFFzPGmgmMvwmqAITMpV/Q+tPoaHZ/PWa3t8B2WyoRcIIuu1hkaW5KkeTDNSnMA==", + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.28.1.tgz", + "integrity": "sha512-QF54q8MYGAqMLrX2t7tNpi01nvq5RI59UBNx+3+37zoKX5KViPo/gk2QLhsuqok05sSCRluj0D00LzCwBikb0A==", "cpu": [ "arm64" ], @@ -3178,10 +3290,23 @@ "linux" ] }, + "node_modules/@rollup/rollup-linux-loongarch64-gnu": { + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.28.1.tgz", + "integrity": "sha512-vPul4uodvWvLhRco2w0GcyZcdyBfpfDRgNKU+p35AWEbJ/HPs1tOUrkSueVbBS0RQHAf/A+nNtDpvw95PeVKOA==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.27.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.27.4.tgz", - "integrity": "sha512-FScrpHrO60hARyHh7s1zHE97u0KlT/RECzCKAdmI+LEoC1eDh/RDji9JgFqyO+wPDb86Oa/sXkily1+oi4FzJQ==", + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.28.1.tgz", + "integrity": "sha512-pTnTdBuC2+pt1Rmm2SV7JWRqzhYpEILML4PKODqLz+C7Ou2apEV52h19CR7es+u04KlqplggmN9sqZlekg3R1A==", "cpu": [ "ppc64" ], @@ -3192,9 +3317,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.27.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.27.4.tgz", - "integrity": "sha512-qyyprhyGb7+RBfMPeww9FlHwKkCXdKHeGgSqmIXw9VSUtvyFZ6WZRtnxgbuz76FK7LyoN8t/eINRbPUcvXB5fw==", + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.28.1.tgz", + "integrity": "sha512-vWXy1Nfg7TPBSuAncfInmAI/WZDd5vOklyLJDdIRKABcZWojNDY0NJwruY2AcnCLnRJKSaBgf/GiJfauu8cQZA==", "cpu": [ "riscv64" ], @@ -3205,9 +3330,9 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.27.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.27.4.tgz", - "integrity": "sha512-PFz+y2kb6tbh7m3A7nA9++eInGcDVZUACulf/KzDtovvdTizHpZaJty7Gp0lFwSQcrnebHOqxF1MaKZd7psVRg==", + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.28.1.tgz", + "integrity": "sha512-/yqC2Y53oZjb0yz8PVuGOQQNOTwxcizudunl/tFs1aLvObTclTwZ0JhXF2XcPT/zuaymemCDSuuUPXJJyqeDOg==", "cpu": [ "s390x" ], @@ -3218,9 +3343,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.27.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.27.4.tgz", - "integrity": "sha512-Ni8mMtfo+o/G7DVtweXXV/Ol2TFf63KYjTtoZ5f078AUgJTmaIJnj4JFU7TK/9SVWTaSJGxPi5zMDgK4w+Ez7Q==", + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.28.1.tgz", + "integrity": "sha512-fzgeABz7rrAlKYB0y2kSEiURrI0691CSL0+KXwKwhxvj92VULEDQLpBYLHpF49MSiPG4sq5CK3qHMnb9tlCjBw==", "cpu": [ "x64" ], @@ -3231,9 +3356,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.27.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.27.4.tgz", - "integrity": "sha512-5AeeAF1PB9TUzD+3cROzFTnAJAcVUGLuR8ng0E0WXGkYhp6RD6L+6szYVX+64Rs0r72019KHZS1ka1q+zU/wUw==", + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.28.1.tgz", + "integrity": "sha512-xQTDVzSGiMlSshpJCtudbWyRfLaNiVPXt1WgdWTwWz9n0U12cI2ZVtWe/Jgwyv/6wjL7b66uu61Vg0POWVfz4g==", "cpu": [ "x64" ], @@ -3244,9 +3369,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.27.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.27.4.tgz", - "integrity": "sha512-yOpVsA4K5qVwu2CaS3hHxluWIK5HQTjNV4tWjQXluMiiiu4pJj4BN98CvxohNCpcjMeTXk/ZMJBRbgRg8HBB6A==", + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.28.1.tgz", + "integrity": "sha512-wSXmDRVupJstFP7elGMgv+2HqXelQhuNf+IS4V+nUpNVi/GUiBgDmfwD0UGN3pcAnWsgKG3I52wMOBnk1VHr/A==", "cpu": [ "arm64" ], @@ -3257,9 +3382,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.27.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.27.4.tgz", - "integrity": "sha512-KtwEJOaHAVJlxV92rNYiG9JQwQAdhBlrjNRp7P9L8Cb4Rer3in+0A+IPhJC9y68WAi9H0sX4AiG2NTsVlmqJeQ==", + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.28.1.tgz", + "integrity": "sha512-ZkyTJ/9vkgrE/Rk9vhMXhf8l9D+eAhbAVbsGsXKy2ohmJaWg0LPQLnIxRdRp/bKyr8tXuPlXhIoGlEB5XpJnGA==", "cpu": [ "ia32" ], @@ -3270,9 +3395,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.27.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.27.4.tgz", - "integrity": "sha512-3j4jx1TppORdTAoBJRd+/wJRGCPC0ETWkXOecJ6PPZLj6SptXkrXcNqdj0oclbKML6FkQltdz7bBA3rUSirZug==", + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.28.1.tgz", + "integrity": "sha512-ZvK2jBafvttJjoIdKm/Q/Bh7IJ1Ose9IBOwpOXcOvW3ikGTQGmKDgxTC6oCAzW6PynbkKP8+um1du81XJHZ0JA==", "cpu": [ "x64" ], @@ -3286,21 +3411,20 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz", "integrity": "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/@swc/helpers": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.7.tgz", - "integrity": "sha512-BVvNZhx362+l2tSwSuyEUV4h7+jk9raNdoTSdLfwTshXJSaGmYKluGRJznziCI3KX02Z19DdsQrdfrpXAU3Hfg==", + "version": "0.5.15", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz", + "integrity": "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==", "dependencies": { - "tslib": "^2.4.0" + "tslib": "^2.8.0" } }, "node_modules/@testing-library/dom": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.0.0.tgz", - "integrity": "sha512-PmJPnogldqoVFf+EwbHvbBJ98MmqASV8kLrBYgsDNxQcFMeIS7JFL48sfyXvuMtgmWO/wMhh25odr+8VhDmn4g==", + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.0.tgz", + "integrity": "sha512-pemlzrSESWbdAloYml3bAJMEfNh1Z7EduzqPKprCH5S341frlpYnUEW0H72dLxa6IsYr+mPno20GiSm+h9dEdQ==", "dev": true, "peer": true, "dependencies": { @@ -3318,11 +3442,10 @@ } }, "node_modules/@testing-library/react": { - "version": "16.0.1", - "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-16.0.1.tgz", - "integrity": "sha512-dSmwJVtJXmku+iocRhWOUFbrERC76TX2Mnf0ATODz8brzAZrMBbzLwQixlBSanZxR6LddK3eiwpSFZgDET1URg==", + "version": "16.1.0", + "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-16.1.0.tgz", + "integrity": "sha512-Q2ToPvg0KsVL0ohND9A3zLJWcOXXcO8IDu3fj11KhNt0UlCWyFyvnCIBkd12tidB2lkiVRG8VFqdhcqhqnAQtg==", "dev": true, - "license": "MIT", "dependencies": { "@babel/runtime": "^7.12.5" }, @@ -3331,10 +3454,10 @@ }, "peerDependencies": { "@testing-library/dom": "^10.0.0", - "@types/react": "^18.0.0", - "@types/react-dom": "^18.0.0", - "react": "^18.0.0", - "react-dom": "^18.0.0" + "@types/react": "^18.0.0 || ^19.0.0", + "@types/react-dom": "^18.0.0 || ^19.0.0", + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" }, "peerDependenciesMeta": { "@types/react": { @@ -3385,9 +3508,9 @@ } }, "node_modules/@types/babel__traverse": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.5.tgz", - "integrity": "sha512-WXCyOcRtH37HAUkpXhUduaxdm82b4GSlyTqajXviN4EfiuPgNYR109xMCKvpl6zPIpua0DGlMEDCq+g8EdoheQ==", + "version": "7.20.6", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.6.tgz", + "integrity": "sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg==", "dev": true, "dependencies": { "@babel/types": "^7.20.7" @@ -3400,9 +3523,9 @@ "dev": true }, "node_modules/@types/geojson": { - "version": "7946.0.14", - "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.14.tgz", - "integrity": "sha512-WCfD5Ht3ZesJUsONdhvm84dmzWOiOzOAqOncN0++w0lBw1o8OuDNJF2McvvCef/yBqb/HYRahp1BYtODFQ8bRg==" + "version": "7946.0.15", + "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.15.tgz", + "integrity": "sha512-9oSxFzDCT2Rj6DfcHF8G++jxBKS7mBqXl5xrRW+Kbvjry6Uduya2iiwqHPhVXpasAVMBYKkEPGgKhd3+/HZ6xA==" }, "node_modules/@types/geojson-vt": { "version": "3.2.5", @@ -3418,12 +3541,6 @@ "integrity": "sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg==", "dev": true }, - "node_modules/@types/json-stable-stringify": { - "version": "1.0.36", - "resolved": "https://registry.npmjs.org/@types/json-stable-stringify/-/json-stable-stringify-1.0.36.tgz", - "integrity": "sha512-b7bq23s4fgBB76n34m2b3RBf6M369B0Z9uRR8aHTMd8kZISRkmDEpPD8hhpYvDFzr3bJCPES96cm3Q6qRNDbQw==", - "dev": true - }, "node_modules/@types/json5": { "version": "0.0.29", "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", @@ -3446,20 +3563,20 @@ } }, "node_modules/@types/mapbox-gl": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@types/mapbox-gl/-/mapbox-gl-3.1.0.tgz", - "integrity": "sha512-hI6cQDjw1bkJw7MC/eHMqq5TWUamLwsujnUUeiIX2KDRjxRNSYMjnHz07+LATz9I9XIsKumOtUz4gRYnZOJ/FA==", + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/@types/mapbox-gl/-/mapbox-gl-3.4.1.tgz", + "integrity": "sha512-NsGKKtgW93B+UaLPti6B7NwlxYlES5DpV5Gzj9F75rK5ALKsqSk15CiEHbOnTr09RGbr6ZYiCdI+59NNNcAImg==", "dependencies": { "@types/geojson": "*" } }, "node_modules/@types/node": { - "version": "20.11.30", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.30.tgz", - "integrity": "sha512-dHM6ZxwlmuZaRmUPfv1p+KrdD1Dci04FbdEm/9wEMouFqxYoFl5aMkt0VMAUtYRQDyYvD41WJLukhq/ha3YuTw==", + "version": "22.10.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.1.tgz", + "integrity": "sha512-qKgsUwfHZV2WCWLAnVP1JqnpE6Im6h3Y0+fYgMTasNQ7V++CBX5OT1as0g0f+OyubbFqhf6XVNIsmN4IIhEgGQ==", "dev": true, "dependencies": { - "undici-types": "~5.26.4" + "undici-types": "~6.20.0" } }, "node_modules/@types/pbf": { @@ -3467,35 +3584,27 @@ "resolved": "https://registry.npmjs.org/@types/pbf/-/pbf-3.0.5.tgz", "integrity": "sha512-j3pOPiEcWZ34R6a6mN07mUkM4o4Lwf6hPNt8eilOeZhTFbxFXmKhvXl9Y28jotFPaI1bpPDJsbCprUoNke6OrA==" }, - "node_modules/@types/prop-types": { - "version": "15.7.12", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz", - "integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==" - }, "node_modules/@types/react": { - "version": "18.3.12", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.12.tgz", - "integrity": "sha512-D2wOSq/d6Agt28q7rSI3jhU7G6aiuzljDGZ2hTZHIkrTLUI+AF3WMeKkEZ9nN2fkBAlcktT6vcZjDFiIhMYEQw==", - "license": "MIT", + "version": "19.0.1", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.0.1.tgz", + "integrity": "sha512-YW6614BDhqbpR5KtUYzTA+zlA7nayzJRA9ljz9CQoxthR0sDisYZLuvSMsil36t4EH/uAt8T52Xb4sVw17G+SQ==", "dependencies": { - "@types/prop-types": "*", "csstype": "^3.0.2" } }, "node_modules/@types/react-dom": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.1.tgz", - "integrity": "sha512-qW1Mfv8taImTthu4KoXgDfLuk4bydU6Q/TkADnDWWHwi4NX4BR+LWfTp2sVmTqRrsHvyDDTelgelxJ+SsejKKQ==", + "version": "19.0.1", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.0.1.tgz", + "integrity": "sha512-hljHij7MpWPKF6u5vojuyfV0YA4YURsQG7KT6SzV0Zs2BXAtgdTxG6A229Ub/xiWV4w/7JL8fi6aAyjshH4meA==", "dev": true, - "license": "MIT", "dependencies": { "@types/react": "*" } }, "node_modules/@types/react-transition-group": { - "version": "4.4.10", - "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.10.tgz", - "integrity": "sha512-hT/+s0VQs2ojCX823m60m5f0sL5idt9SO6Tj6Dg+rdphGPIeJbJ6CxvBYkgkGKrYeDjvIpKTR38UzmtHJOGW3Q==", + "version": "4.4.11", + "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.11.tgz", + "integrity": "sha512-RM05tAniPZ5DZPzzNFP+DmrcOdD0efDUxMy3145oljWSl3x9ZV5vhme98gTxFrj2lhXvmGNnUiuDyJgY9IKkNA==", "dependencies": { "@types/react": "*" } @@ -3514,9 +3623,9 @@ "integrity": "sha512-D1XC7WK8K+zZEveUPY+cf4+kgauk8N4eHr/XIHXGlGYkHLud6hK9lYfZk1ry1TNh798cZUCgb6MqGEG8DkJt6Q==" }, "node_modules/@types/ws": { - "version": "8.5.10", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.10.tgz", - "integrity": "sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==", + "version": "8.5.13", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.13.tgz", + "integrity": "sha512-osM/gWBTPKgHV8XkTunnegTRIsvF6owmf5w+JtAfOw472dptdm0dlGv4xCt6GwQRcC2XVOvvRE/0bAoQcL2QkA==", "dev": true, "dependencies": { "@types/node": "*" @@ -3527,7 +3636,6 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.18.0.tgz", "integrity": "sha512-94EQTWZ40mzBc42ATNIBimBEDltSJ9RQHCC8vc/PDbxi4k8dVwUAv4o98dk50M1zB+JGFxp43FP7f8+FP8R6Sw==", "dev": true, - "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.10.0", "@typescript-eslint/scope-manager": "7.18.0", @@ -3561,7 +3669,6 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.18.0.tgz", "integrity": "sha512-4Z+L8I2OqhZV8qA132M4wNL30ypZGYOQVBfMgxDH/K5UX0PNqTu1c6za9ST5r9+tavvHiTWmBnKzpCJ/GlVFtg==", "dev": true, - "license": "BSD-2-Clause", "dependencies": { "@typescript-eslint/scope-manager": "7.18.0", "@typescript-eslint/types": "7.18.0", @@ -3590,7 +3697,6 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.18.0.tgz", "integrity": "sha512-jjhdIE/FPF2B7Z1uzc6i3oWKbGcHb87Qw7AWj6jmEqNOfDFbJWtjt/XfwCpvNkpGWlcJaog5vTR+VV8+w9JflA==", "dev": true, - "license": "MIT", "dependencies": { "@typescript-eslint/types": "7.18.0", "@typescript-eslint/visitor-keys": "7.18.0" @@ -3608,7 +3714,6 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.18.0.tgz", "integrity": "sha512-XL0FJXuCLaDuX2sYqZUUSOJ2sG5/i1AAze+axqmLnSkNEVMVYLF+cbwlB2w8D1tinFuSikHmFta+P+HOofrLeA==", "dev": true, - "license": "MIT", "dependencies": { "@typescript-eslint/typescript-estree": "7.18.0", "@typescript-eslint/utils": "7.18.0", @@ -3636,7 +3741,6 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.18.0.tgz", "integrity": "sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==", "dev": true, - "license": "MIT", "engines": { "node": "^18.18.0 || >=20.0.0" }, @@ -3650,7 +3754,6 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.18.0.tgz", "integrity": "sha512-aP1v/BSPnnyhMHts8cf1qQ6Q1IFwwRvAQGRvBFkWlo3/lH29OXA3Pts+c10nxRxIBrDnoMqzhgdwVe5f2D6OzA==", "dev": true, - "license": "BSD-2-Clause", "dependencies": { "@typescript-eslint/types": "7.18.0", "@typescript-eslint/visitor-keys": "7.18.0", @@ -3679,7 +3782,6 @@ "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", "dev": true, - "license": "ISC", "bin": { "semver": "bin/semver.js" }, @@ -3692,7 +3794,6 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.18.0.tgz", "integrity": "sha512-kK0/rNa2j74XuHVcoCZxdFBMF+aq/vH83CXAOHieC+2Gis4mF8jJXT5eAfyD3K0sAxtPuwxaIOIOvhwzVDt/kw==", "dev": true, - "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@typescript-eslint/scope-manager": "7.18.0", @@ -3715,7 +3816,6 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.18.0.tgz", "integrity": "sha512-cDF0/Gf81QpY3xYyJKDV14Zwdmid5+uuENhjH2EqFaF0ni+yAyq/LzMaIJdhNJXZI7uLzwIlA+V7oWoyn6Curg==", "dev": true, - "license": "MIT", "dependencies": { "@typescript-eslint/types": "7.18.0", "eslint-visitor-keys": "^3.4.3" @@ -3729,9 +3829,9 @@ } }, "node_modules/@ungap/structured-clone": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", - "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.1.tgz", + "integrity": "sha512-fEzPV3hSkSMltkw152tJKNARhOupqbH96MZWyRjNaYZOMIzbrTeQDG+MTc6Mr2pgzFQzFxAfmhGDNP5QK++2ZA==", "dev": true }, "node_modules/@vitejs/plugin-react": { @@ -3758,7 +3858,6 @@ "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-2.1.8.tgz", "integrity": "sha512-2Y7BPlKH18mAZYAW1tYByudlCYrQyl5RGvnnDYJKW5tCiO5qg3KSAy3XAxcxKz900a0ZXxWtKrMuZLe3lKBpJw==", "dev": true, - "license": "MIT", "dependencies": { "@ampproject/remapping": "^2.3.0", "@bcoe/v8-coverage": "^0.2.3", @@ -3791,7 +3890,6 @@ "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-2.1.8.tgz", "integrity": "sha512-8ytZ/fFHq2g4PJVAtDX57mayemKgDR6X3Oa2Foro+EygiOJHUXhCqBAAKQYYajZpFoIfvBCF1j6R6IYRSIUFuw==", "dev": true, - "license": "MIT", "dependencies": { "@vitest/spy": "2.1.8", "@vitest/utils": "2.1.8", @@ -3807,7 +3905,6 @@ "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-2.1.8.tgz", "integrity": "sha512-9HiSZ9zpqNLKlbIDRWOnAWqgcA7xu+8YxXSekhr0Ykab7PAYFkhkwoqVArPOtJhPmYeE2YHgKZlj3CP36z2AJQ==", "dev": true, - "license": "MIT", "dependencies": { "tinyrainbow": "^1.2.0" }, @@ -3820,7 +3917,6 @@ "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-2.1.8.tgz", "integrity": "sha512-17ub8vQstRnRlIU5k50bG+QOMLHRhYPAna5tw8tYbj+jzjcspnwnwtPtiOlkuKC4+ixDPTuLZiqiWWQ2PSXHVg==", "dev": true, - "license": "MIT", "dependencies": { "@vitest/utils": "2.1.8", "pathe": "^1.1.2" @@ -3834,7 +3930,6 @@ "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-2.1.8.tgz", "integrity": "sha512-20T7xRFbmnkfcmgVEz+z3AU/3b0cEzZOt/zmnvZEctg64/QZbSDJEVm9fLnnlSi74KibmRsO9/Qabi+t0vCRPg==", "dev": true, - "license": "MIT", "dependencies": { "@vitest/pretty-format": "2.1.8", "magic-string": "^0.30.12", @@ -3849,7 +3944,6 @@ "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-2.1.8.tgz", "integrity": "sha512-5swjf2q95gXeYPevtW0BLk6H8+bPlMb4Vw/9Em4hFxDcaOxS+e0LOX4yqNxoHzMR2akEB2xfpnWUzkZokmgWDg==", "dev": true, - "license": "MIT", "dependencies": { "tinyspy": "^3.0.2" }, @@ -3862,7 +3956,6 @@ "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-2.1.8.tgz", "integrity": "sha512-dwSoui6djdwbfFmIgbIjX2ZhIoG7Ex/+xpxyiEgIGzjliY8xGkcpITKTlp6B4MgtGkF2ilvm97cPM96XZaAgcA==", "dev": true, - "license": "MIT", "dependencies": { "@vitest/pretty-format": "2.1.8", "loupe": "^3.1.2", @@ -3872,14 +3965,25 @@ "url": "https://opencollective.com/vitest" } }, + "node_modules/@whatwg-node/disposablestack": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/@whatwg-node/disposablestack/-/disposablestack-0.0.5.tgz", + "integrity": "sha512-9lXugdknoIequO4OYvIjhygvfSEgnO8oASLqLelnDhkRjgBZhc39shC3QSlZuyDO9bgYSIVa2cHAiN+St3ty4w==", + "dev": true, + "dependencies": { + "tslib": "^2.6.3" + }, + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/@whatwg-node/fetch": { - "version": "0.9.21", - "resolved": "https://registry.npmjs.org/@whatwg-node/fetch/-/fetch-0.9.21.tgz", - "integrity": "sha512-Wt0jPb+04JjobK0pAAN7mEHxVHcGA9HoP3OyCsZtyAecNQeADXCZ1MihFwVwjsgaRYuGVmNlsCmLxlG6mor8Gw==", + "version": "0.9.23", + "resolved": "https://registry.npmjs.org/@whatwg-node/fetch/-/fetch-0.9.23.tgz", + "integrity": "sha512-7xlqWel9JsmxahJnYVUj/LLxWcnA93DR4c9xlw3U814jWTiYalryiH1qToik1hOxweKKRLi4haXHM5ycRksPBA==", "dev": true, - "license": "MIT", "dependencies": { - "@whatwg-node/node-fetch": "^0.5.23", + "@whatwg-node/node-fetch": "^0.6.0", "urlpattern-polyfill": "^10.0.0" }, "engines": { @@ -3887,11 +3991,10 @@ } }, "node_modules/@whatwg-node/node-fetch": { - "version": "0.5.26", - "resolved": "https://registry.npmjs.org/@whatwg-node/node-fetch/-/node-fetch-0.5.26.tgz", - "integrity": "sha512-4jXDeZ4IH4bylZ6wu14VEx0aDXXhrN4TC279v9rPmn08g4EYekcYf8wdcOOnS9STjDkb6x77/6xBUTqxGgjr8g==", + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@whatwg-node/node-fetch/-/node-fetch-0.6.0.tgz", + "integrity": "sha512-tcZAhrpx6oVlkEsRngeTEEE7I5/QdLjeEz4IlekabGaESP7+Dkm/6a9KcF1KdCBB7mO9PXtBkwCuTCt8+UPg8Q==", "dev": true, - "license": "MIT", "dependencies": { "@kamilkisiela/fast-url-parser": "^1.1.4", "busboy": "^1.6.0", @@ -3902,17 +4005,10 @@ "node": ">=18.0.0" } }, - "node_modules/@whatwg-node/node-fetch/node_modules/tslib": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.0.tgz", - "integrity": "sha512-jWVzBLplnCmoaTr13V9dYbiQ99wvZRd0vNWaDRg+aVYRcjDF3nDksxFDE/+fkXnKhpnUUkmx5pK/v8mCtLVqZA==", - "dev": true, - "license": "0BSD" - }, "node_modules/acorn": { - "version": "8.11.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", - "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", + "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", "dev": true, "bin": { "acorn": "bin/acorn" @@ -3931,13 +4027,10 @@ } }, "node_modules/agent-base": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz", - "integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==", + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz", + "integrity": "sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==", "dev": true, - "dependencies": { - "debug": "^4.3.4" - }, "engines": { "node": ">= 14" } @@ -4160,7 +4253,6 @@ "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.4.tgz", "integrity": "sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==", "dev": true, - "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", @@ -4205,7 +4297,6 @@ "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", "dev": true, - "license": "MIT", "engines": { "node": ">=12" } @@ -4267,11 +4358,10 @@ } }, "node_modules/axe-core": { - "version": "4.10.0", - "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.10.0.tgz", - "integrity": "sha512-Mr2ZakwQ7XUAjp7pAwQWRhhK8mQQ6JAaNWSjmjxil0R8BPioMtQsTLOolGYkji1rcL++3dCqZA3zWqpT+9Ew6g==", + "version": "4.10.2", + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.10.2.tgz", + "integrity": "sha512-RE3mdQ7P3FRSe7eqCWoeQ/Z9QXrtniSjp1wUjt5nRC3WIpz5rSCve6o3fsZ2aCpJtrZjSZgjwXAoTO5k4tEI0w==", "dev": true, - "license": "MPL-2.0", "engines": { "node": ">=4" } @@ -4281,7 +4371,6 @@ "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==", "dev": true, - "license": "Apache-2.0", "engines": { "node": ">= 0.4" } @@ -4390,27 +4479,26 @@ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, - "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" } }, "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, "dependencies": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" }, "engines": { "node": ">=8" } }, "node_modules/browserslist": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.0.tgz", - "integrity": "sha512-Rmb62sR1Zpjql25eSanFGEhAxcFwfA1K0GuQcLoaJBAcENegrQut3hYdhXFF1obQfiDyqIW/cLM5HSJ/9k884A==", + "version": "4.24.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.2.tgz", + "integrity": "sha512-ZIc+Q62revdMcqC6aChtW4jz3My3klmCO1fEmINZY/8J3EpBg5/A/D0AKmBveUh6pgoeycoMkVMko84tuYS+Gg==", "dev": true, "funding": [ { @@ -4426,12 +4514,11 @@ "url": "https://github.com/sponsors/ai" } ], - "license": "MIT", "dependencies": { - "caniuse-lite": "^1.0.30001663", - "electron-to-chromium": "^1.5.28", + "caniuse-lite": "^1.0.30001669", + "electron-to-chromium": "^1.5.41", "node-releases": "^2.0.18", - "update-browserslist-db": "^1.1.0" + "update-browserslist-db": "^1.1.1" }, "bin": { "browserslist": "cli.js" @@ -4512,22 +4599,34 @@ } }, "node_modules/call-bind": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", - "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", + "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", "dev": true, "dependencies": { + "call-bind-apply-helpers": "^1.0.0", "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", "get-intrinsic": "^1.2.4", - "set-function-length": "^1.2.1" + "set-function-length": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.1.tgz", + "integrity": "sha512-BhYE+WDaywFg2TBWYNXAE+8B1ATnThNBqXHP5nQu0jWJdVvY2hvkpyB3qOmtmDePiS5/BDQ8wASEWGMWRG148g==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" }, "engines": { "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" } }, "node_modules/callsites": { @@ -4559,9 +4658,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001669", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001669.tgz", - "integrity": "sha512-DlWzFDJqstqtIVx1zeSpIMLjunf5SmwOw0N2Ck/QSQdS8PLS4+9HrLaYei4w8BIAL7IB/UEDu889d8vhCTPA0w==", + "version": "1.0.30001687", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001687.tgz", + "integrity": "sha512-0S/FDhf4ZiqrTUiQ39dKeUjYRjkv7lOZU1Dgif2rIqrTzX/1wV2hfKu9TOm1IHkdSijfLswxTFzl/cvir+SLSQ==", "dev": true, "funding": [ { @@ -4576,8 +4675,7 @@ "type": "github", "url": "https://github.com/sponsors/ai" } - ], - "license": "CC-BY-4.0" + ] }, "node_modules/capital-case": { "version": "1.0.4", @@ -4595,7 +4693,6 @@ "resolved": "https://registry.npmjs.org/chai/-/chai-5.1.2.tgz", "integrity": "sha512-aGtmf24DW6MLHHG5gCx4zaI3uBq3KRtxeVs0DjFH6Z0rDNbsvTxFASFvdj79pxjxZ8/5u3PIiN3IwEIQkiiuPw==", "dev": true, - "license": "MIT", "dependencies": { "assertion-error": "^2.0.1", "check-error": "^2.1.1", @@ -4672,7 +4769,6 @@ "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.1.tgz", "integrity": "sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==", "dev": true, - "license": "MIT", "engines": { "node": ">= 16" } @@ -4884,9 +4980,9 @@ } }, "node_modules/cross-inspect": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/cross-inspect/-/cross-inspect-1.0.0.tgz", - "integrity": "sha512-4PFfn4b5ZN6FMNGSZlyb7wUhuN8wvj8t/VQHZdM4JsDcruGJ8L2kf9zao98QIrBPFCpdk27qst/AGTl7pL3ypQ==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cross-inspect/-/cross-inspect-1.0.1.tgz", + "integrity": "sha512-Pcw1JTvZLSJH83iiGWt6fRcT+BjZlCDRVwYLbUcHzv/CRpB7r0MlSrGbIyQvVSNyGnbt7G4AXuyCiDR3POvZ1A==", "dev": true, "dependencies": { "tslib": "^2.4.0" @@ -4896,9 +4992,9 @@ } }, "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "dev": true, "dependencies": { "path-key": "^3.1.0", @@ -4914,7 +5010,6 @@ "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-4.1.0.tgz", "integrity": "sha512-h66W1URKpBS5YMI/V8PyXvTMFT8SupJ1IzoIV8IeBC/ji8WVmrO8dGlTi+2dh6whmdk6BiKJLD/ZBkhWbcg6nA==", "dev": true, - "license": "MIT", "dependencies": { "rrweb-cssom": "^0.7.1" }, @@ -4998,9 +5093,9 @@ } }, "node_modules/dataloader": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/dataloader/-/dataloader-2.2.2.tgz", - "integrity": "sha512-8YnDaaf7N3k/q5HnTJVuzSyLETjoZjVmHc4AeKAzOvKHEFQKcn64OKBfzHYtE9zGjctNM7V9I0MfnUVLpi7M5g==", + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/dataloader/-/dataloader-2.2.3.tgz", + "integrity": "sha512-y2krtASINtPFS1rSDjacrFgn1dcUuoREVabwlOGOe4SdxenREqwjwjElAdwvbGM7kgZz9a3KVicWR7vcz8rnzA==", "dev": true }, "node_modules/debounce": { @@ -5010,11 +5105,10 @@ "dev": true }, "node_modules/debug": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", - "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", "dev": true, - "license": "MIT", "dependencies": { "ms": "^2.1.3" }, @@ -5047,7 +5141,6 @@ "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz", "integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==", "dev": true, - "license": "MIT", "engines": { "node": ">=6" } @@ -5202,9 +5295,9 @@ } }, "node_modules/dotenv": { - "version": "16.4.5", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz", - "integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==", + "version": "16.4.7", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz", + "integrity": "sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==", "dev": true, "engines": { "node": ">=12" @@ -5214,33 +5307,44 @@ } }, "node_modules/dset": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/dset/-/dset-3.1.3.tgz", - "integrity": "sha512-20TuZZHCEZ2O71q9/+8BwKwZ0QtD9D8ObhrihJPr+vLLYlSuAU3/zL4cSlgbfeoGHTjCSJBa7NGcrF9/Bx/WJQ==", + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/dset/-/dset-3.1.4.tgz", + "integrity": "sha512-2QF/g9/zTaPDc3BjNcVTGoBbXBgYfMTTceLaYcFJ/W9kggFUkhxD/hMEeuLKbugyef9SqAx8cpgwlIP/jinUTA==", "dev": true, "engines": { "node": ">=4" } }, + "node_modules/dunder-proto": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.0.tgz", + "integrity": "sha512-9+Sj30DIu+4KvHqMfLUGLFYL2PkURSYMVXJyXe92nFRvlYq5hBjLEhblKB+vkd/WVlUYMWigiY07T91Fkk0+4A==", + "dev": true, + "dependencies": { + "call-bind-apply-helpers": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/earcut": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/earcut/-/earcut-3.0.0.tgz", - "integrity": "sha512-41Fs7Q/PLq1SDbqjsgcY7GA42T0jvaCNGXgGtsNdvg+Yv8eIu06bxv4/PoREkZ9nMDNwnUSG9OFB9+yv8eKhDg==", - "license": "ISC" + "integrity": "sha512-41Fs7Q/PLq1SDbqjsgcY7GA42T0jvaCNGXgGtsNdvg+Yv8eIu06bxv4/PoREkZ9nMDNwnUSG9OFB9+yv8eKhDg==" }, "node_modules/eastasianwidth": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/electron-to-chromium": { - "version": "1.5.40", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.40.tgz", - "integrity": "sha512-LYm78o6if4zTasnYclgQzxEcgMoIcybWOhkATWepN95uwVVWV0/IW10v+2sIeHE+bIYWipLneTftVyQm45UY7g==", - "dev": true, - "license": "ISC" + "version": "1.5.71", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.71.tgz", + "integrity": "sha512-dB68l59BI75W1BUGVTAEJy45CEVuEGy9qPVVQ8pnHyHMn36PLPPoE1mjLH+lo9rKulO3HC2OhbACI/8tCqJBcA==", + "dev": true }, "node_modules/emoji-regex": { "version": "9.2.2", @@ -5270,11 +5374,10 @@ } }, "node_modules/es-abstract": { - "version": "1.23.3", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.3.tgz", - "integrity": "sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==", + "version": "1.23.5", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.5.tgz", + "integrity": "sha512-vlmniQ0WNPwXqA0BnmwV3Ng7HxiGlh6r5U6JcTMNx8OilcAGqVJBHJcPjqOMaczU9fRuRK5Px2BdVyPRnKMMVQ==", "dev": true, - "license": "MIT", "dependencies": { "array-buffer-byte-length": "^1.0.1", "arraybuffer.prototype.slice": "^1.0.3", @@ -5291,7 +5394,7 @@ "function.prototype.name": "^1.1.6", "get-intrinsic": "^1.2.4", "get-symbol-description": "^1.0.2", - "globalthis": "^1.0.3", + "globalthis": "^1.0.4", "gopd": "^1.0.1", "has-property-descriptors": "^1.0.2", "has-proto": "^1.0.3", @@ -5307,10 +5410,10 @@ "is-string": "^1.0.7", "is-typed-array": "^1.1.13", "is-weakref": "^1.0.2", - "object-inspect": "^1.13.1", + "object-inspect": "^1.13.3", "object-keys": "^1.1.1", "object.assign": "^4.1.5", - "regexp.prototype.flags": "^1.5.2", + "regexp.prototype.flags": "^1.5.3", "safe-array-concat": "^1.1.2", "safe-regex-test": "^1.0.3", "string.prototype.trim": "^1.2.9", @@ -5331,13 +5434,10 @@ } }, "node_modules/es-define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", - "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", "dev": true, - "dependencies": { - "get-intrinsic": "^1.2.4" - }, "engines": { "node": ">= 0.4" } @@ -5352,11 +5452,10 @@ } }, "node_modules/es-iterator-helpers": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.1.0.tgz", - "integrity": "sha512-/SurEfycdyssORP/E+bj4sEu1CWw4EmLDsHynHwSXQ7utgbrMRWW195pTrCjFgFCddf/UkYm3oqKPRq5i8bJbw==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.2.0.tgz", + "integrity": "sha512-tpxqxncxnpw3c93u8n3VOzACmRFoVmWJqbWXvX/JfKbkhBw1oslgPrUfeSt2psuqyEJFD6N/9lg5i7bsKpoq+Q==", "dev": true, - "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", @@ -5366,6 +5465,7 @@ "function-bind": "^1.1.2", "get-intrinsic": "^1.2.4", "globalthis": "^1.0.4", + "gopd": "^1.0.1", "has-property-descriptors": "^1.0.2", "has-proto": "^1.0.3", "has-symbols": "^1.0.3", @@ -5381,8 +5481,7 @@ "version": "1.5.4", "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.4.tgz", "integrity": "sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/es-object-atoms": { "version": "1.0.0", @@ -5420,14 +5519,14 @@ } }, "node_modules/es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.0.tgz", + "integrity": "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==", "dev": true, "dependencies": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" + "is-callable": "^1.2.7", + "is-date-object": "^1.0.5", + "is-symbol": "^1.0.4" }, "engines": { "node": ">= 0.4" @@ -5480,7 +5579,6 @@ "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", "dev": true, - "license": "MIT", "engines": { "node": ">=6" } @@ -5501,8 +5599,8 @@ "version": "8.57.1", "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz", "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", + "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", "dev": true, - "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", @@ -5590,7 +5688,6 @@ "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.12.0.tgz", "integrity": "sha512-wALZ0HFoytlyh/1+4wuZ9FJCD/leWHQzzrxJ8+rebyReSLk7LApMyd3WJaLVoN+D5+WIdJyDK1c6JnE65V4Zyg==", "dev": true, - "license": "MIT", "dependencies": { "debug": "^3.2.7" }, @@ -5617,7 +5714,6 @@ "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.31.0.tgz", "integrity": "sha512-ixmkI62Rbc2/w8Vfxyh1jQRTdRTF52VxwRVHl/ykPAmqG+Nb7/kNn+byLP0LxPgI7zWA16Jt82SybJInmMia3A==", "dev": true, - "license": "MIT", "dependencies": { "@rtsao/scc": "^1.1.0", "array-includes": "^3.1.8", @@ -5651,7 +5747,6 @@ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, - "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -5662,7 +5757,6 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, - "license": "MIT", "dependencies": { "ms": "^2.1.1" } @@ -5672,7 +5766,6 @@ "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", "dev": true, - "license": "Apache-2.0", "dependencies": { "esutils": "^2.0.2" }, @@ -5685,7 +5778,6 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, - "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" }, @@ -5698,7 +5790,6 @@ "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.10.2.tgz", "integrity": "sha512-scB3nz4WmG75pV8+3eRUQOHZlNSUhFNq37xnpgRkCCELU3XMvXAxLk1eqWWyE22Ki4Q01Fnsw9BA3cJHDPgn2Q==", "dev": true, - "license": "MIT", "dependencies": { "aria-query": "^5.3.2", "array-includes": "^3.1.8", @@ -5728,7 +5819,6 @@ "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz", "integrity": "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==", "dev": true, - "license": "Apache-2.0", "engines": { "node": ">= 0.4" } @@ -5738,7 +5828,6 @@ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, - "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -5749,7 +5838,6 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, - "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" }, @@ -5762,7 +5850,6 @@ "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.2.tgz", "integrity": "sha512-EsTAnj9fLVr/GZleBLFbj/sSuXeWmp1eXIN60ceYnZveqEaUCyW4X+Vh4WTdUhCkW4xutXYqTXCUSyqD4rB75w==", "dev": true, - "license": "MIT", "dependencies": { "array-includes": "^3.1.8", "array.prototype.findlast": "^1.2.5", @@ -5795,7 +5882,6 @@ "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.0.0.tgz", "integrity": "sha512-hIOwI+5hYGpJEc4uPRmz2ulCjAGD/N13Lukkh8cLV0i2IRk/bdZDYjgLVHj+U9Z704kLIdIO6iueGvxNur0sgw==", "dev": true, - "license": "MIT", "engines": { "node": ">=10" }, @@ -5808,7 +5894,6 @@ "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.16.tgz", "integrity": "sha512-slterMlxAhov/DZO8NScf6mEeMBBXodFUolijDvrtTxyezyLoTQaa73FyYus/VbTdftd8wBgBxPMRk3poleXNQ==", "dev": true, - "license": "MIT", "peerDependencies": { "eslint": ">=8.40" } @@ -5818,7 +5903,6 @@ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, - "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -5829,7 +5913,6 @@ "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", "dev": true, - "license": "Apache-2.0", "dependencies": { "esutils": "^2.0.2" }, @@ -5842,7 +5925,6 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, - "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" }, @@ -5855,7 +5937,6 @@ "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz", "integrity": "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==", "dev": true, - "license": "MIT", "dependencies": { "is-core-module": "^2.13.0", "path-parse": "^1.0.7", @@ -5901,7 +5982,6 @@ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, - "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -5912,7 +5992,6 @@ "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", "dev": true, - "license": "MIT", "dependencies": { "type-fest": "^0.20.2" }, @@ -5928,7 +6007,6 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, - "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" }, @@ -5941,7 +6019,6 @@ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", "dev": true, - "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=10" }, @@ -5967,9 +6044,9 @@ } }, "node_modules/esquery": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", - "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", "dev": true, "dependencies": { "estraverse": "^5.1.0" @@ -6022,7 +6099,6 @@ "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.1.0.tgz", "integrity": "sha512-bFi65yM+xZgk+u/KRIpekdSYkTB5W1pEf0Lt8Q8Msh7b+eQ7LXVtIB1Bkm4fvclDEL1b2CZkMhv2mOeF8tMdkA==", "dev": true, - "license": "Apache-2.0", "engines": { "node": ">=12.0.0" } @@ -6068,8 +6144,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/fast-decode-uri-component/-/fast-decode-uri-component-1.0.1.tgz", "integrity": "sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/fast-deep-equal": { "version": "3.1.3", @@ -6122,7 +6197,6 @@ "resolved": "https://registry.npmjs.org/fast-querystring/-/fast-querystring-1.1.2.tgz", "integrity": "sha512-g6KuKWmFXc0fID8WWH0jit4g0AGBoJhCkJMb1RmbsSEUNvQ+ZC8D6CUZ+GtF8nMzSPXnhiePyyqqipzNNEnHjg==", "dev": true, - "license": "MIT", "dependencies": { "fast-decode-uri-component": "^1.0.1" } @@ -6203,9 +6277,9 @@ } }, "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, "dependencies": { "to-regex-range": "^5.0.1" @@ -6245,9 +6319,9 @@ } }, "node_modules/flatted": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", - "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.2.tgz", + "integrity": "sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA==", "dev": true }, "node_modules/for-each": { @@ -6260,11 +6334,10 @@ } }, "node_modules/foreground-child": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.2.1.tgz", - "integrity": "sha512-PXUUyLqrR2XCWICfv6ukppP96sdFwWbNEnfEMt7jNsISjMsvaLNinAHNDYyvkyU+SZG2BTSbT5NjG+vZslfGTA==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", + "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", "dev": true, - "license": "ISC", "dependencies": { "cross-spawn": "^7.0.0", "signal-exit": "^4.0.1" @@ -6281,7 +6354,6 @@ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", "dev": true, - "license": "ISC", "engines": { "node": ">=14" }, @@ -6290,9 +6362,9 @@ } }, "node_modules/form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.1.tgz", + "integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==", "dev": true, "dependencies": { "asynckit": "^0.4.0", @@ -6371,8 +6443,7 @@ "node_modules/geojson-vt": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/geojson-vt/-/geojson-vt-4.0.2.tgz", - "integrity": "sha512-AV9ROqlNqoZEIJGfm1ncNjEXfkz2hdFlZf0qkVfmkwdKa8vj7H16YUOT81rJw1rdFhyEDlN2Tds91p/glzbl5A==", - "license": "ISC" + "integrity": "sha512-AV9ROqlNqoZEIJGfm1ncNjEXfkz2hdFlZf0qkVfmkwdKa8vj7H16YUOT81rJw1rdFhyEDlN2Tds91p/glzbl5A==" }, "node_modules/get-caller-file": { "version": "2.0.5", @@ -6384,16 +6455,19 @@ } }, "node_modules/get-intrinsic": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", - "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.5.tgz", + "integrity": "sha512-Y4+pKa7XeRUPWFNvOOYHkRYrfzW07oraURSvjDmRVOJ748OrVmeXtpE4+GCEHncjCjkTxPNRt8kEbxDhsn6VTg==", "dev": true, "dependencies": { + "call-bind-apply-helpers": "^1.0.0", + "dunder-proto": "^1.0.0", + "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "function-bind": "^1.1.2", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0" + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2" }, "engines": { "node": ">= 0.4" @@ -6447,6 +6521,7 @@ "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", "dev": true, "dependencies": { "fs.realpath": "^1.0.0", @@ -6501,7 +6576,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-4.0.0.tgz", "integrity": "sha512-w0Uf9Y9/nyHinEk5vMJKRie+wa4kR5hmDbEhGGds/kG1PwGLLHKRoNMeJOyCQjjBkANlnScqgzcFwGHgmgLkVA==", - "license": "MIT", "dependencies": { "ini": "^4.1.3", "kind-of": "^6.0.3", @@ -6515,7 +6589,6 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", - "license": "ISC", "engines": { "node": ">=16" } @@ -6524,7 +6597,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", - "license": "ISC", "dependencies": { "isexe": "^3.1.1" }, @@ -6549,7 +6621,6 @@ "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", "dev": true, - "license": "MIT", "dependencies": { "define-properties": "^1.2.1", "gopd": "^1.0.1" @@ -6582,12 +6653,12 @@ } }, "node_modules/gopd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", - "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", "dev": true, - "dependencies": { - "get-intrinsic": "^1.1.3" + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -6603,7 +6674,6 @@ "version": "16.9.0", "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.9.0.tgz", "integrity": "sha512-GGTKBX4SD7Wdb8mqeDLni2oaRGYQWjWHGKPQ24ZMnUtKfcsVoiv4uX8+LJr1K6U5VW2Lu1BwJnj7uiori0YtRw==", - "license": "MIT", "engines": { "node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0" } @@ -6613,7 +6683,6 @@ "resolved": "https://registry.npmjs.org/graphql-config/-/graphql-config-5.1.3.tgz", "integrity": "sha512-RBhejsPjrNSuwtckRlilWzLVt2j8itl74W9Gke1KejDTz7oaA5kVd6wRn9zK9TS5mcmIYGxf7zN7a1ORMdxp1Q==", "dev": true, - "license": "MIT", "dependencies": { "@graphql-tools/graphql-file-loader": "^8.0.0", "@graphql-tools/json-file-loader": "^8.0.0", @@ -6641,11 +6710,10 @@ } }, "node_modules/graphql-config/node_modules/jiti": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.3.3.tgz", - "integrity": "sha512-EX4oNDwcXSivPrw2qKH2LB5PoFxEvgtv2JgwW0bU858HoLQ+kutSvjLMUqBd0PeJYEinLWhoI9Ol0eYMqj/wNQ==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.4.1.tgz", + "integrity": "sha512-yPBThwecp1wS9DmoA4x4KR2h3QoslacnDR8ypuFM962kI4/456Iy1oHx2RAgh4jfZNdn0bctsdadceiBUgpU1g==", "dev": true, - "license": "MIT", "bin": { "jiti": "lib/jiti-cli.mjs" } @@ -6654,7 +6722,6 @@ "version": "7.1.2", "resolved": "https://registry.npmjs.org/graphql-request/-/graphql-request-7.1.2.tgz", "integrity": "sha512-+XE3iuC55C2di5ZUrB4pjgwe+nIQBuXVIK9J98wrVwojzDW3GMdSBZfxUk8l4j9TieIpjpggclxhNEU9ebGF8w==", - "license": "MIT", "dependencies": { "@graphql-typed-document-node/core": "^3.2.0" }, @@ -6678,9 +6745,9 @@ } }, "node_modules/graphql-ws": { - "version": "5.15.0", - "resolved": "https://registry.npmjs.org/graphql-ws/-/graphql-ws-5.15.0.tgz", - "integrity": "sha512-xWGAtm3fig9TIhSaNsg0FaDZ8Pyn/3re3RFlP4rhQcmjRDIPpk1EhRuNB+YSJtLzttyuToaDiNhwT1OMoGnJnw==", + "version": "5.16.0", + "resolved": "https://registry.npmjs.org/graphql-ws/-/graphql-ws-5.16.0.tgz", + "integrity": "sha512-Ju2RCU2dQMgSKtArPbEtsK5gNLnsQyTNIo/T7cZNp96niC1x0KdJNZV0TIoilceBPQwfb5itrGl8pkFeOUMl4A==", "dev": true, "engines": { "node": ">=10" @@ -6720,10 +6787,13 @@ } }, "node_modules/has-proto": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", - "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz", + "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==", "dev": true, + "dependencies": { + "dunder-proto": "^1.0.0" + }, "engines": { "node": ">= 0.4" }, @@ -6732,9 +6802,9 @@ } }, "node_modules/has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", "dev": true, "engines": { "node": ">= 0.4" @@ -6812,13 +6882,12 @@ } }, "node_modules/https-proxy-agent": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz", - "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", "dev": true, - "license": "MIT", "dependencies": { - "agent-base": "^7.0.2", + "agent-base": "^7.1.2", "debug": "4" }, "engines": { @@ -6857,9 +6926,9 @@ ] }, "node_modules/ignore": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", - "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", "dev": true, "engines": { "node": ">= 4" @@ -6933,6 +7002,7 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", "dev": true, "dependencies": { "once": "^1.3.0", @@ -6949,7 +7019,6 @@ "version": "4.1.3", "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.3.tgz", "integrity": "sha512-X7rqawQBvfdjS10YU1y1YVreA3SsLrW9dX2CewP2EbBJM4ypVNLDkO5y04gejPwKIY9lR+7r9gn3rFPt/kmWFg==", - "license": "ISC", "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } @@ -7042,7 +7111,6 @@ "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.0.0.tgz", "integrity": "sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==", "dev": true, - "license": "MIT", "dependencies": { "has-tostringtag": "^1.0.0" }, @@ -7054,25 +7122,28 @@ } }, "node_modules/is-bigint": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz", + "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==", "dev": true, "dependencies": { - "has-bigints": "^1.0.1" + "has-bigints": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/is-boolean-object": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.0.tgz", + "integrity": "sha512-kR5g0+dXf/+kXnqI+lu0URKYPKgICtHGGNCDSB10AaUFj3o/HkB3u7WfpRBJGFopxxY0oH3ux7ZsDjLtK7xqvw==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" + "call-bind": "^1.0.7", + "has-tostringtag": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -7098,7 +7169,6 @@ "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.1.tgz", "integrity": "sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==", "dev": true, - "license": "MIT", "dependencies": { "hasown": "^2.0.2" }, @@ -7157,13 +7227,15 @@ } }, "node_modules/is-finalizationregistry": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.0.2.tgz", - "integrity": "sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.0.tgz", + "integrity": "sha512-qfMdqbAQEwBw78ZyReKnlA8ezmPdb9BemzIIip/JkjaZUhitfXDkkr+3QTboW0JrSXT1QWyYShpvnNHGZ4c4yA==", "dev": true, - "license": "MIT", "dependencies": { - "call-bind": "^1.0.2" + "call-bind": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -7183,7 +7255,6 @@ "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", "dev": true, - "license": "MIT", "dependencies": { "has-tostringtag": "^1.0.0" }, @@ -7258,12 +7329,13 @@ } }, "node_modules/is-number-object": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", - "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.0.tgz", + "integrity": "sha512-KVSZV0Dunv9DTPkhXwcZ3Q+tUc9TsaE1ZwX5J2WMvsSGS6Md8TFPun5uwh0yRdrNerI6vf/tbJxqSx4c1ZI1Lw==", "dev": true, "dependencies": { - "has-tostringtag": "^1.0.0" + "call-bind": "^1.0.7", + "has-tostringtag": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -7299,13 +7371,15 @@ "dev": true }, "node_modules/is-regex": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.0.tgz", + "integrity": "sha512-B6ohK4ZmoftlUe+uvenXSbPJFo6U37BH7oO1B3nQH8f/7h27N56s85MhUtbFJAziz5dcmuR3i8ovUl35zp8pFA==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" + "call-bind": "^1.0.7", + "gopd": "^1.1.0", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" }, "engines": { "node": ">= 0.4" @@ -7354,12 +7428,13 @@ } }, "node_modules/is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.0.tgz", + "integrity": "sha512-PlfzajuF9vSo5wErv3MJAKD/nqf9ngAs1NFQYm16nUYFO2IzxJ2hcm+IOCg+EEopdykNNUhVq5cz35cAUxU8+g==", "dev": true, "dependencies": { - "has-tostringtag": "^1.0.0" + "call-bind": "^1.0.7", + "has-tostringtag": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -7369,12 +7444,14 @@ } }, "node_modules/is-symbol": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.0.tgz", + "integrity": "sha512-qS8KkNNXUZ/I+nX6QT8ZS1/Yx0A444yhzdTKxCzKkNjQ9sHErBxJnJAgh+f5YhusYECEcjo4XcyH87hn6+ks0A==", "dev": true, "dependencies": { - "has-symbols": "^1.0.2" + "call-bind": "^1.0.7", + "has-symbols": "^1.0.3", + "safe-regex-test": "^1.0.3" }, "engines": { "node": ">= 0.4" @@ -7537,7 +7614,6 @@ "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-5.0.6.tgz", "integrity": "sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==", "dev": true, - "license": "BSD-3-Clause", "dependencies": { "@jridgewell/trace-mapping": "^0.3.23", "debug": "^4.1.1", @@ -7565,7 +7641,6 @@ "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.3.tgz", "integrity": "sha512-FW5iMbeQ6rBGm/oKgzq2aW4KvAGpxPzYES8N4g4xNXUKpL1mclMvOe+76AcLDTvD+Ze+sOpVhgdAQEKF4L9iGQ==", "dev": true, - "license": "MIT", "dependencies": { "define-properties": "^1.2.1", "get-intrinsic": "^1.2.1", @@ -7582,7 +7657,6 @@ "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", "dev": true, - "license": "BlueOak-1.0.0", "dependencies": { "@isaacs/cliui": "^8.0.2" }, @@ -7594,18 +7668,18 @@ } }, "node_modules/jiti": { - "version": "1.21.0", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.0.tgz", - "integrity": "sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==", + "version": "1.21.6", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.6.tgz", + "integrity": "sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==", "dev": true, "bin": { "jiti": "bin/jiti.js" } }, "node_modules/jose": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/jose/-/jose-5.2.3.tgz", - "integrity": "sha512-KUXdbctm1uHVL8BYhnyHkgp3zDX5KW8ZhAKVFEfUbU2P8Alpzjb+48hHvjOdQIyPshoblhzsuqOwEEAbtHVirA==", + "version": "5.9.6", + "resolved": "https://registry.npmjs.org/jose/-/jose-5.9.6.tgz", + "integrity": "sha512-AMlnetc9+CV9asI19zHmrgS/WYsWUwCn2R7RzlbJWD7F9eWYUTGyBmU9o6PxngtLGOiDGPRu+Uc4fhKzbpteZQ==", "dev": true, "funding": { "url": "https://github.com/sponsors/panva" @@ -7638,7 +7712,6 @@ "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-25.0.1.tgz", "integrity": "sha512-8i7LzZj7BF8uplX+ZyOlIz86V6TAsSs+np6m1kpW9u0JWi4z/1t+FzcK1aek+ybTnAC4KhBL4uXCNT0wcUIeCw==", "dev": true, - "license": "MIT", "dependencies": { "cssstyle": "^4.1.0", "data-urls": "^5.0.0", @@ -7679,7 +7752,6 @@ "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==", "dev": true, - "license": "MIT", "bin": { "jsesc": "bin/jsesc" }, @@ -7705,24 +7777,6 @@ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true }, - "node_modules/json-stable-stringify": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.1.1.tgz", - "integrity": "sha512-SU/971Kt5qVQfJpyDveVhQ/vya+5hvrjClFOcr8c0Fq5aODJjMwutrOfCU+eCnVD5gpx1Q3fEqkyom77zH1iIg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.5", - "isarray": "^2.0.5", - "jsonify": "^0.0.1", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", @@ -7759,15 +7813,6 @@ "node": ">=6" } }, - "node_modules/jsonify": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.1.tgz", - "integrity": "sha512-2/Ki0GcmuqSrgFyelQq9M05y7PS0mEwuIzrf3f1fPqkVDVRvZrPZtVSMHxdgo8Aq0sxAOb/cr2aqqA3LeWHVPg==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/jsx-ast-utils": { "version": "3.3.5", "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", @@ -7806,9 +7851,9 @@ } }, "node_modules/language-subtag-registry": { - "version": "0.3.22", - "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz", - "integrity": "sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w==", + "version": "0.3.23", + "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.23.tgz", + "integrity": "sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==", "dev": true }, "node_modules/language-tags": { @@ -7985,8 +8030,7 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.1.2.tgz", "integrity": "sha512-23I4pFZHmAemUnz8WZXbYRSKYj801VDaNv9ETuMh7IrMc7VuVVSo+Z9iLE3ni30+U48iDWfi30d3twAXBYmnCg==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/lower-case": { "version": "2.0.2", @@ -8026,11 +8070,10 @@ } }, "node_modules/magic-string": { - "version": "0.30.12", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.12.tgz", - "integrity": "sha512-Ea8I3sQMVXr8JhN4z+H/d8zwo+tYDgHE9+5G4Wnrwhs0gaK9fXTKx0Tw5Xwsd/bCPTTZNRAdpyzvoeORe9LYpw==", + "version": "0.30.14", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.14.tgz", + "integrity": "sha512-5c99P1WKTed11ZC0HMJOj6CDIue6F8ySu+bJL+85q1zBEIY8IklrJ1eiKC2NDRh3Ct3FcvmJPyQHb9erXMTJNw==", "dev": true, - "license": "MIT", "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0" } @@ -8040,7 +8083,6 @@ "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.3.5.tgz", "integrity": "sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ==", "dev": true, - "license": "MIT", "dependencies": { "@babel/parser": "^7.25.4", "@babel/types": "^7.25.4", @@ -8062,26 +8104,11 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/make-dir/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/make-dir/node_modules/semver": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", - "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, "bin": { "semver": "bin/semver.js" }, @@ -8089,12 +8116,6 @@ "node": ">=10" } }, - "node_modules/make-dir/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, "node_modules/map-cache": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", @@ -8108,7 +8129,6 @@ "version": "4.7.1", "resolved": "https://registry.npmjs.org/maplibre-gl/-/maplibre-gl-4.7.1.tgz", "integrity": "sha512-lgL7XpIwsgICiL82ITplfS7IGwrB1OJIw/pCvprDp2dhmSSEBgmPzYRvwYYYvJGJD7fxUv1Tvpih4nZ6VrLuaA==", - "license": "BSD-3-Clause", "dependencies": { "@mapbox/geojson-rewind": "^0.5.2", "@mapbox/jsonlint-lines-primitives": "^2.0.2", @@ -8145,12 +8165,6 @@ "url": "https://github.com/maplibre/maplibre-gl-js?sponsor=1" } }, - "node_modules/maplibre-gl/node_modules/quickselect": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/quickselect/-/quickselect-3.0.0.tgz", - "integrity": "sha512-XdjUArbK4Bm5fLLvlm5KpTFOiOThgfWWI4axAZDWg4E/0mKdZyI9tNEfds27qCi1ze/vwTR16kvmmGhRra3c2g==", - "license": "ISC" - }, "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", @@ -8178,12 +8192,12 @@ } }, "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "dev": true, "dependencies": { - "braces": "^3.0.2", + "braces": "^3.0.3", "picomatch": "^2.3.1" }, "engines": { @@ -8225,7 +8239,6 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, - "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" }, @@ -8249,7 +8262,6 @@ "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", "dev": true, - "license": "ISC", "engines": { "node": ">=16 || 14 >=14.17" } @@ -8258,8 +8270,7 @@ "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/murmurhash-js": { "version": "1.0.0", @@ -8307,13 +8318,10 @@ } }, "node_modules/node-addon-api": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.0.tgz", - "integrity": "sha512-mNcltoe1R8o7STTegSOHdnJNN7s5EUvhoS7ShnTHDyOSd+8H+UdWODq6qSv67PjC8Zc5JRT8+oLAMCr0SIXw7g==", - "dev": true, - "engines": { - "node": "^16 || ^18 || >= 20" - } + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", + "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", + "dev": true }, "node_modules/node-fetch": { "version": "2.7.0", @@ -8367,8 +8375,7 @@ "version": "2.0.18", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/normalize-path": { "version": "2.1.1", @@ -8389,11 +8396,10 @@ "dev": true }, "node_modules/nwsapi": { - "version": "2.2.12", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.12.tgz", - "integrity": "sha512-qXDmcVlZV4XRtKFzddidpfVP4oMSGhga+xdMc25mv8kaLUHtgzCDhUxkrN8exkGdTlLNaXj7CV3GtON7zuGZ+w==", - "dev": true, - "license": "MIT" + "version": "2.2.16", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.16.tgz", + "integrity": "sha512-F1I/bimDpj3ncaNDhfyMWuFqmQDBwDB0Fogc2qpL3BWvkQteFD/8BzWuIRl83rq0DXfm8SGt/HFhLXZyljTXcQ==", + "dev": true }, "node_modules/object-assign": { "version": "4.1.1", @@ -8404,10 +8410,13 @@ } }, "node_modules/object-inspect": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", - "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", + "version": "1.13.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.3.tgz", + "integrity": "sha512-kDCGIbxkDSXE3euJZZXzc6to7fCrKHNI/hSRQnRuQ+BWjFNzZwiFF8fj/6o2t2G9/jTj8PSIYTfCLelLZEeRpA==", "dev": true, + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -8527,17 +8536,17 @@ } }, "node_modules/optionator": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", - "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", "dev": true, "dependencies": { - "@aashutoshrathi/word-wrap": "^1.2.3", "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", - "type-check": "^0.4.0" + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" }, "engines": { "node": ">= 0.8.0" @@ -8630,11 +8639,10 @@ } }, "node_modules/package-json-from-dist": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz", - "integrity": "sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==", - "dev": true, - "license": "BlueOak-1.0.0" + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "dev": true }, "node_modules/param-case": { "version": "3.0.4", @@ -8691,12 +8699,12 @@ } }, "node_modules/parse5": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", - "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.2.1.tgz", + "integrity": "sha512-BuBYQYlv1ckiPdQi/ohiivi9Sagc9JG+Ozs0r7b/0iK3sKmrb0b9FdWdBbOdx6hBCM/F9Ir82ofnBhtZOjCRPQ==", "dev": true, "dependencies": { - "entities": "^4.4.0" + "entities": "^4.5.0" }, "funding": { "url": "https://github.com/inikulin/parse5?sponsor=1" @@ -8781,7 +8789,6 @@ "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", "dev": true, - "license": "BlueOak-1.0.0", "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" @@ -8797,8 +8804,7 @@ "version": "10.4.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", - "dev": true, - "license": "ISC" + "dev": true }, "node_modules/path-type": { "version": "4.0.0", @@ -8820,7 +8826,6 @@ "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.0.tgz", "integrity": "sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==", "dev": true, - "license": "MIT", "engines": { "node": ">= 14.16" } @@ -8829,7 +8834,6 @@ "version": "3.3.0", "resolved": "https://registry.npmjs.org/pbf/-/pbf-3.3.0.tgz", "integrity": "sha512-XDF38WCH3z5OV/OVa8GKUNtLAyneuzbCisx7QUCF8Q6Nutx0WnJrQe5O+kOtBlLfRNUws98Y58Lblp+NJG5T4Q==", - "license": "BSD-3-Clause", "dependencies": { "ieee754": "^1.1.12", "resolve-protobuf-schema": "^2.1.0" @@ -8912,7 +8916,6 @@ "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.4.1.tgz", "integrity": "sha512-G+YdqtITVZmOJje6QkXQWzl3fSfMxFwm1tjTyo9exhkmWSqC4Yhd1+lug++IlR2mvRVAxEDDWYkQdeSztajqgg==", "dev": true, - "license": "MIT", "bin": { "prettier": "bin/prettier.cjs" }, @@ -8997,6 +9000,15 @@ "resolved": "https://registry.npmjs.org/protocol-buffers-schema/-/protocol-buffers-schema-3.6.0.tgz", "integrity": "sha512-TdDRD+/QNdrCGCE7v8340QyuXd4kIWIgapsE2+n/SaGiSSbomYl4TjHlvIoCWRpE7wFt02EpB35VVA2ImcBVqw==" }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -9018,17 +9030,14 @@ ] }, "node_modules/quickselect": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/quickselect/-/quickselect-2.0.0.tgz", - "integrity": "sha512-RKJ22hX8mHe3Y6wH/N3wCM6BWtjaxIyyUIkpHOvfFnxdI4yD4tBXEBKSbriGujF6jnSVkJrffuo6vxACiSSxIw==" + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/quickselect/-/quickselect-3.0.0.tgz", + "integrity": "sha512-XdjUArbK4Bm5fLLvlm5KpTFOiOThgfWWI4axAZDWg4E/0mKdZyI9tNEfds27qCi1ze/vwTR16kvmmGhRra3c2g==" }, "node_modules/react": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", - "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", - "dependencies": { - "loose-envify": "^1.1.0" - }, + "version": "19.0.0", + "resolved": "https://registry.npmjs.org/react/-/react-19.0.0.tgz", + "integrity": "sha512-V8AVnmPIICiWpGfm6GLzCR/W5FXLchHop40W4nXBmdlEceh16rCN8O8LNWm5bh5XUX91fh7KpA+W0TgMKmgTpQ==", "engines": { "node": ">=0.10.0" } @@ -9037,7 +9046,6 @@ "version": "2.10.6", "resolved": "https://registry.npmjs.org/react-bootstrap/-/react-bootstrap-2.10.6.tgz", "integrity": "sha512-fNvKytSp0nHts1WRnRBJeBEt+I9/ZdrnhIjWOucEduRNvFRU1IXjZueDdWnBiqsTSJ7MckQJi9i/hxGolaRq+g==", - "license": "MIT", "dependencies": { "@babel/runtime": "^7.24.7", "@restart/hooks": "^0.4.9", @@ -9064,15 +9072,14 @@ } }, "node_modules/react-dom": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", - "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "version": "19.0.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.0.0.tgz", + "integrity": "sha512-4GV5sHFG0e/0AD4X+ySy6UJd3jVl1iNsNHdpad0qhABJ11twS3TTBnseqsKurKcsNqCEFeGL3uLpVChpIO3QfQ==", "dependencies": { - "loose-envify": "^1.1.0", - "scheduler": "^0.23.2" + "scheduler": "^0.25.0" }, "peerDependencies": { - "react": "^18.3.1" + "react": "^19.0.0" } }, "node_modules/react-is": { @@ -9138,7 +9145,6 @@ "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz", "integrity": "sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==", "dev": true, - "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -9173,19 +9179,19 @@ } }, "node_modules/reflect.getprototypeof": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.6.tgz", - "integrity": "sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg==", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.8.tgz", + "integrity": "sha512-B5dj6usc5dkk8uFliwjwDHM8To5/QwdKz9JcBZ8Ic4G1f0YmeeJTtE/ZTdgRFPAfxZFiUaPhZ1Jcs4qeagItGQ==", "dev": true, - "license": "MIT", "dependencies": { - "call-bind": "^1.0.7", + "call-bind": "^1.0.8", "define-properties": "^1.2.1", - "es-abstract": "^1.23.1", + "dunder-proto": "^1.0.0", + "es-abstract": "^1.23.5", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.4", - "globalthis": "^1.0.3", - "which-builtin-type": "^1.1.3" + "gopd": "^1.2.0", + "which-builtin-type": "^1.2.0" }, "engines": { "node": ">= 0.4" @@ -9200,15 +9206,15 @@ "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" }, "node_modules/regexp.prototype.flags": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz", - "integrity": "sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==", + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.3.tgz", + "integrity": "sha512-vqlC04+RQoFalODCbCumG2xIOvapzVMHwsyIGM/SIE8fRhFFsXeH8/QQ+s0T0kDAhKc4k30s73/0ydkHQz6HlQ==", "dev": true, "dependencies": { - "call-bind": "^1.0.6", + "call-bind": "^1.0.7", "define-properties": "^1.2.1", "es-errors": "^1.3.0", - "set-function-name": "^2.0.1" + "set-function-name": "^2.0.2" }, "engines": { "node": ">= 0.4" @@ -9322,15 +9328,16 @@ } }, "node_modules/rfdc": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.1.tgz", - "integrity": "sha512-r5a3l5HzYlIC68TpmYKlxWjmOP6wiPJ1vWv2HeLhNsRZMrCkxeqxiHlQ21oXmQ4F3SiryXBHhAD7JZqvOJjFmg==", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", + "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", "dev": true }, "node_modules/rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", "dev": true, "dependencies": { "glob": "^7.1.3" @@ -9343,9 +9350,9 @@ } }, "node_modules/rollup": { - "version": "4.27.4", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.27.4.tgz", - "integrity": "sha512-RLKxqHEMjh/RGLsDxAEsaLO3mWgyoU6x9w6n1ikAzet4B3gI2/3yP6PWY2p9QzRTh6MfEIXB3MwsOY0Iv3vNrw==", + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.28.1.tgz", + "integrity": "sha512-61fXYl/qNVinKmGSTHAZ6Yy8I3YIJC/r2m9feHo6SwVAVcLT5MPwOUFe7EuURA/4m0NR8lXG4BBXuo/IZEsjMg==", "dev": true, "dependencies": { "@types/estree": "1.0.6" @@ -9358,24 +9365,25 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.27.4", - "@rollup/rollup-android-arm64": "4.27.4", - "@rollup/rollup-darwin-arm64": "4.27.4", - "@rollup/rollup-darwin-x64": "4.27.4", - "@rollup/rollup-freebsd-arm64": "4.27.4", - "@rollup/rollup-freebsd-x64": "4.27.4", - "@rollup/rollup-linux-arm-gnueabihf": "4.27.4", - "@rollup/rollup-linux-arm-musleabihf": "4.27.4", - "@rollup/rollup-linux-arm64-gnu": "4.27.4", - "@rollup/rollup-linux-arm64-musl": "4.27.4", - "@rollup/rollup-linux-powerpc64le-gnu": "4.27.4", - "@rollup/rollup-linux-riscv64-gnu": "4.27.4", - "@rollup/rollup-linux-s390x-gnu": "4.27.4", - "@rollup/rollup-linux-x64-gnu": "4.27.4", - "@rollup/rollup-linux-x64-musl": "4.27.4", - "@rollup/rollup-win32-arm64-msvc": "4.27.4", - "@rollup/rollup-win32-ia32-msvc": "4.27.4", - "@rollup/rollup-win32-x64-msvc": "4.27.4", + "@rollup/rollup-android-arm-eabi": "4.28.1", + "@rollup/rollup-android-arm64": "4.28.1", + "@rollup/rollup-darwin-arm64": "4.28.1", + "@rollup/rollup-darwin-x64": "4.28.1", + "@rollup/rollup-freebsd-arm64": "4.28.1", + "@rollup/rollup-freebsd-x64": "4.28.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.28.1", + "@rollup/rollup-linux-arm-musleabihf": "4.28.1", + "@rollup/rollup-linux-arm64-gnu": "4.28.1", + "@rollup/rollup-linux-arm64-musl": "4.28.1", + "@rollup/rollup-linux-loongarch64-gnu": "4.28.1", + "@rollup/rollup-linux-powerpc64le-gnu": "4.28.1", + "@rollup/rollup-linux-riscv64-gnu": "4.28.1", + "@rollup/rollup-linux-s390x-gnu": "4.28.1", + "@rollup/rollup-linux-x64-gnu": "4.28.1", + "@rollup/rollup-linux-x64-musl": "4.28.1", + "@rollup/rollup-win32-arm64-msvc": "4.28.1", + "@rollup/rollup-win32-ia32-msvc": "4.28.1", + "@rollup/rollup-win32-x64-msvc": "4.28.1", "fsevents": "~2.3.2" } }, @@ -9383,8 +9391,7 @@ "version": "0.7.1", "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.7.1.tgz", "integrity": "sha512-TrEMa7JGdVm0UThDJSx7ddw5nVm3UJS9o9CCIZ72B1vSyEZoziDqBYP3XIoi/12lKrJR8rE3jeFHMok2F/Mnsg==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/run-async": { "version": "2.4.1", @@ -9506,12 +9513,9 @@ } }, "node_modules/scheduler": { - "version": "0.23.2", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", - "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", - "dependencies": { - "loose-envify": "^1.1.0" - } + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.25.0.tgz", + "integrity": "sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA==" }, "node_modules/scuid": { "version": "1.1.0", @@ -9619,10 +9623,13 @@ } }, "node_modules/shell-quote": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz", - "integrity": "sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==", + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.2.tgz", + "integrity": "sha512-AzqKpGKjrj7EM6rKVQEPpB288oCfnrEIuyoT9cyF4nmGa7V8Zk6f7RRqYisX8X9m+Q7bd632aZW4ky7EhbQztA==", "dev": true, + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -9733,7 +9740,6 @@ "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", "dev": true, - "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } @@ -9791,8 +9797,7 @@ "version": "3.8.0", "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.8.0.tgz", "integrity": "sha512-Bc3YwwCB+OzldMxOXJIIvC6cPRWr/LxOp48CdQTOkPyk/t4JWWJbrilwBd7RJzKV8QW7tJkcgAmeuLLJugl5/w==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/streamsearch": { "version": "1.1.0", @@ -9838,7 +9843,6 @@ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, - "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -9852,8 +9856,7 @@ "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/string-width/node_modules/emoji-regex": { "version": "8.0.0", @@ -9866,7 +9869,6 @@ "resolved": "https://registry.npmjs.org/string.prototype.includes/-/string.prototype.includes-2.0.1.tgz", "integrity": "sha512-o7+c9bW6zpAdJHTtujeePODAhkuicdAryFsfVKwA+wGw89wJ4GTY484WTucM9hLtDEOpOvI+aHnzqnC5lHp4Rg==", "dev": true, - "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", @@ -9907,7 +9909,6 @@ "resolved": "https://registry.npmjs.org/string.prototype.repeat/-/string.prototype.repeat-1.0.0.tgz", "integrity": "sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==", "dev": true, - "license": "MIT", "dependencies": { "define-properties": "^1.1.3", "es-abstract": "^1.17.5" @@ -9980,7 +9981,6 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, - "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" }, @@ -10061,7 +10061,6 @@ "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-7.0.1.tgz", "integrity": "sha512-pFYqmTw68LXVjeWJMST4+borgQP2AyMNbg1BpZh9LbyhUeNkeaPF9gzfPGUAnSMV3qPYdWUwDIjjCLiSDOl7vg==", "dev": true, - "license": "ISC", "dependencies": { "@istanbuljs/schema": "^0.1.2", "glob": "^10.4.1", @@ -10076,7 +10075,6 @@ "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", "dev": true, - "license": "ISC", "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", @@ -10108,22 +10106,19 @@ "version": "2.9.0", "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/tinyexec": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.1.tgz", "integrity": "sha512-WiCJLEECkO18gwqIp6+hJg0//p23HXp4S+gGtAKu3mI2F2/sXC4FvHvXvB0zJVVaTPhx1/tOwdbRsa1sOBIKqQ==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/tinypool": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.0.1.tgz", - "integrity": "sha512-URZYihUbRPcGv95En+sz6MfghfIc2OJ1sv/RmhWZLouPY0/8Vo80viwPvg3dlaS9fuq7fQMEfgRRK7BBZThBEA==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.0.2.tgz", + "integrity": "sha512-al6n+QEANGFOMf/dmUMsuS5/r9B06uwlyNjZZql/zv8J7ybHCgoihBNORZCY2mzUuAnomQa2JdhyHKzZxPCrFA==", "dev": true, - "license": "MIT", "engines": { "node": "^18.0.0 || >=20.0.0" } @@ -10131,15 +10126,13 @@ "node_modules/tinyqueue": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/tinyqueue/-/tinyqueue-3.0.0.tgz", - "integrity": "sha512-gRa9gwYU3ECmQYv3lslts5hxuIa90veaEcxDYuu3QGOIAEM2mOZkVHp48ANJuu1CURtRdHKUBY5Lm1tHV+sD4g==", - "license": "ISC" + "integrity": "sha512-gRa9gwYU3ECmQYv3lslts5hxuIa90veaEcxDYuu3QGOIAEM2mOZkVHp48ANJuu1CURtRdHKUBY5Lm1tHV+sD4g==" }, "node_modules/tinyrainbow": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-1.2.0.tgz", "integrity": "sha512-weEDEq7Z5eTHPDh4xjX789+fHfF+P8boiFB+0vbWzpbnbsEr/GRaohi/uMKxg8RZMXnl1ItAi/IUHWMsjDV7kQ==", "dev": true, - "license": "MIT", "engines": { "node": ">=14.0.0" } @@ -10149,7 +10142,6 @@ "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-3.0.2.tgz", "integrity": "sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==", "dev": true, - "license": "MIT", "engines": { "node": ">=14.0.0" } @@ -10164,24 +10156,22 @@ } }, "node_modules/tldts": { - "version": "6.1.52", - "resolved": "https://registry.npmjs.org/tldts/-/tldts-6.1.52.tgz", - "integrity": "sha512-fgrDJXDjbAverY6XnIt0lNfv8A0cf7maTEaZxNykLGsLG7XP+5xhjBTrt/ieAsFjAlZ+G5nmXomLcZDkxXnDzw==", + "version": "6.1.66", + "resolved": "https://registry.npmjs.org/tldts/-/tldts-6.1.66.tgz", + "integrity": "sha512-l3ciXsYFel/jSRfESbyKYud1nOw7WfhrBEF9I3UiarYk/qEaOOwu3qXNECHw4fHGHGTEOuhf/VdKgoDX5M/dhQ==", "dev": true, - "license": "MIT", "dependencies": { - "tldts-core": "^6.1.52" + "tldts-core": "^6.1.66" }, "bin": { "tldts": "bin/cli.js" } }, "node_modules/tldts-core": { - "version": "6.1.52", - "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-6.1.52.tgz", - "integrity": "sha512-j4OxQI5rc1Ve/4m/9o2WhWSC4jGc4uVbCINdOEJRAraCi0YqTqgMcxUx7DbmuP0G3PCixoof/RZB0Q5Kh9tagw==", - "dev": true, - "license": "MIT" + "version": "6.1.66", + "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-6.1.66.tgz", + "integrity": "sha512-s07jJruSwndD2X8bVjwioPfqpIc1pDTzszPe9pL1Skbh4bjytL85KNQ3tolqLbCvpQHawIsGfFi9dgerWjqW4g==", + "dev": true }, "node_modules/tmp": { "version": "0.0.33", @@ -10212,7 +10202,6 @@ "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-5.0.0.tgz", "integrity": "sha512-FRKsF7cz96xIIeMZ82ehjC3xW2E+O2+v11udrDYewUbszngYhsGa8z6YUMMzO9QJZzzyd0nGGXnML/TReX6W8Q==", "dev": true, - "license": "BSD-3-Clause", "dependencies": { "tldts": "^6.1.32" }, @@ -10232,19 +10221,10 @@ "node": ">=18" } }, - "node_modules/tr46/node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, "node_modules/ts-api-utils": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", - "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.4.3.tgz", + "integrity": "sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw==", "dev": true, "engines": { "node": ">=16" @@ -10254,9 +10234,9 @@ } }, "node_modules/ts-log": { - "version": "2.2.5", - "resolved": "https://registry.npmjs.org/ts-log/-/ts-log-2.2.5.tgz", - "integrity": "sha512-PGcnJoTBnVGy6yYNFxWVNkdcAuAMstvutN9MgDJIV6L0oG8fB+ZNNy1T+wJzah8RPGor1mZuPQkVfXNDpy9eHA==", + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/ts-log/-/ts-log-2.2.7.tgz", + "integrity": "sha512-320x5Ggei84AxzlXp91QkIGSw5wgaLT6GeAH0KsqDmRZdVWW2OiSeVvElVoatk3f7nicwXlElXsoFkARiGE2yg==", "dev": true }, "node_modules/tsconfig-paths": { @@ -10284,9 +10264,9 @@ } }, "node_modules/tslib": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==" }, "node_modules/type-check": { "version": "0.4.0", @@ -10346,9 +10326,9 @@ } }, "node_modules/typed-array-byte-offset": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz", - "integrity": "sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.3.tgz", + "integrity": "sha512-GsvTyUHTriq6o/bHcTd0vM7OQ9JEdlvluu9YISaA7+KzDzPaIzEeDFNkTfhdE3MYcNhNi0vq/LlegYgIs5yPAw==", "dev": true, "dependencies": { "available-typed-arrays": "^1.0.7", @@ -10356,7 +10336,8 @@ "for-each": "^0.3.3", "gopd": "^1.0.1", "has-proto": "^1.0.3", - "is-typed-array": "^1.1.13" + "is-typed-array": "^1.1.13", + "reflect.getprototypeof": "^1.0.6" }, "engines": { "node": ">= 0.4" @@ -10366,17 +10347,17 @@ } }, "node_modules/typed-array-length": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.6.tgz", - "integrity": "sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.7.tgz", + "integrity": "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==", "dev": true, "dependencies": { "call-bind": "^1.0.7", "for-each": "^0.3.3", "gopd": "^1.0.1", - "has-proto": "^1.0.3", "is-typed-array": "^1.1.13", - "possible-typed-array-names": "^1.0.0" + "possible-typed-array-names": "^1.0.0", + "reflect.getprototypeof": "^1.0.6" }, "engines": { "node": ">= 0.4" @@ -10390,7 +10371,6 @@ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.2.tgz", "integrity": "sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==", "dev": true, - "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -10413,9 +10393,9 @@ "integrity": "sha512-2SCC/WLzj2SbUwzFOzqMCkz5amXLlxtJqDKTICqg30x+2DZxcfZN2MvQZmGfXWKNWaKK9pBPsvkcwv8bF/gxKg==" }, "node_modules/ua-parser-js": { - "version": "1.0.37", - "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.37.tgz", - "integrity": "sha512-bhTyI94tZofjo+Dn8SN6Zv8nBDvyXTymAdM3LDI/0IboIUwTu1rEhW7v2TfiVsoYWgkQ4kOVqnI8APUFbIQIFQ==", + "version": "1.0.39", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.39.tgz", + "integrity": "sha512-k24RCVWlEcjkdOxYmVJgeD/0a1TiSpqLg+ZalVGV9lsnr4yqu0w7tX/x2xX6G4zpkgQnRf89lxuZ1wsbjXM8lw==", "dev": true, "funding": [ { @@ -10431,6 +10411,9 @@ "url": "https://github.com/sponsors/faisalman" } ], + "bin": { + "ua-parser-js": "script/cli.js" + }, "engines": { "node": "*" } @@ -10474,9 +10457,9 @@ } }, "node_modules/undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", + "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", "dev": true }, "node_modules/union-value": { @@ -10524,7 +10507,6 @@ "url": "https://github.com/sponsors/ai" } ], - "license": "MIT", "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.0" @@ -10563,21 +10545,11 @@ "punycode": "^2.1.0" } }, - "node_modules/uri-js/node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, "node_modules/urlpattern-polyfill": { "version": "10.0.0", "resolved": "https://registry.npmjs.org/urlpattern-polyfill/-/urlpattern-polyfill-10.0.0.tgz", "integrity": "sha512-H/A06tKD7sS1O1X2SshBVeA5FLycRpjqiBeqGKmBwBDBy28EnRjORxTNe269KSSr5un5qyWi1iL61wLxpd+ZOg==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/util-deprecate": { "version": "1.0.2", @@ -10599,7 +10571,6 @@ "resolved": "https://registry.npmjs.org/vite/-/vite-6.0.2.tgz", "integrity": "sha512-XdQ+VsY2tJpBsKGs0wf3U/+azx8BBpYRHFAyKm5VeEZNOJZRB63q7Sc8Iup3k0TrN3KO6QgyzFf+opSbfY1y0g==", "dev": true, - "license": "MIT", "dependencies": { "esbuild": "^0.24.0", "postcss": "^8.4.49", @@ -10671,7 +10642,6 @@ "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-2.1.8.tgz", "integrity": "sha512-uPAwSr57kYjAUux+8E2j0q0Fxpn8M9VoyfGiRI8Kfktz9NcYMCenwY5RnZxnF1WTu3TGiYipirIzacLL3VVGFg==", "dev": true, - "license": "MIT", "dependencies": { "cac": "^6.7.14", "debug": "^4.3.7", @@ -11159,7 +11129,6 @@ "resolved": "https://registry.npmjs.org/vitest/-/vitest-2.1.8.tgz", "integrity": "sha512-1vBKTZskHw/aosXqQUlVWWlGUxSJR8YtiyZDJAFeW2kPAeX6S3Sool0mjspO+kXLuxVWlEDDowBAeqeAQefqLQ==", "dev": true, - "license": "MIT", "dependencies": { "@vitest/expect": "2.1.8", "@vitest/mocker": "2.1.8", @@ -11228,7 +11197,6 @@ "ppc64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "aix" @@ -11245,7 +11213,6 @@ "arm" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "android" @@ -11262,7 +11229,6 @@ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "android" @@ -11279,7 +11245,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "android" @@ -11296,7 +11261,6 @@ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "darwin" @@ -11313,7 +11277,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "darwin" @@ -11330,7 +11293,6 @@ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "freebsd" @@ -11347,7 +11309,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "freebsd" @@ -11364,7 +11325,6 @@ "arm" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -11381,7 +11341,6 @@ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -11398,7 +11357,6 @@ "ia32" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -11415,7 +11373,6 @@ "loong64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -11432,7 +11389,6 @@ "mips64el" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -11449,7 +11405,6 @@ "ppc64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -11466,7 +11421,6 @@ "riscv64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -11483,7 +11437,6 @@ "s390x" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -11500,7 +11453,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -11517,7 +11469,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "netbsd" @@ -11534,7 +11485,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "openbsd" @@ -11551,7 +11501,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "sunos" @@ -11568,7 +11517,6 @@ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "win32" @@ -11585,7 +11533,6 @@ "ia32" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "win32" @@ -11602,7 +11549,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "win32" @@ -11616,7 +11562,6 @@ "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-2.1.8.tgz", "integrity": "sha512-7guJ/47I6uqfttp33mgo6ga5Gr1VnL58rcqYKyShoRK9ebu8T5Rs6HN3s1NABiBeVTdWNrwUMcHH54uXZBN4zA==", "dev": true, - "license": "MIT", "dependencies": { "@vitest/spy": "2.1.8", "estree-walker": "^3.0.3", @@ -11644,7 +11589,6 @@ "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", "dev": true, "hasInstallScript": true, - "license": "MIT", "bin": { "esbuild": "bin/esbuild" }, @@ -11682,7 +11626,6 @@ "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.11.tgz", "integrity": "sha512-c7jFQRklXua0mTzneGW9QVyxFjUgwcihC4bXEtujIo2ouWCe1Ajt/amn2PCxYnhYfd5k09JX3SB7OYWFKYqj8Q==", "dev": true, - "license": "MIT", "dependencies": { "esbuild": "^0.21.3", "postcss": "^8.4.43", @@ -11819,9 +11762,9 @@ } }, "node_modules/whatwg-url": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.0.0.tgz", - "integrity": "sha512-1lfMEm2IEr7RIV+f4lUNPOqfFL+pO+Xw3fJSqmjX9AbXcXcYOkCe1P6+9VBZB6n94af16NfZf+sSk0JCBZC9aw==", + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.1.0.tgz", + "integrity": "sha512-jlf/foYIKywAt3x/XWKZ/3rz8OSJPiWktjmk891alJUEjiVxKX9LEO92qH3hv4aJ0mN3MWPvGMCy8jQi95xK4w==", "dev": true, "dependencies": { "tr46": "^5.0.0", @@ -11847,33 +11790,36 @@ } }, "node_modules/which-boxed-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.1.0.tgz", + "integrity": "sha512-Ei7Miu/AXe2JJ4iNF5j/UphAgRoma4trE6PtisM09bPygb3egMH3YLW/befsWb1A1AxvNSFidOFTB18XtnIIng==", "dev": true, "dependencies": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" + "is-bigint": "^1.1.0", + "is-boolean-object": "^1.2.0", + "is-number-object": "^1.1.0", + "is-string": "^1.1.0", + "is-symbol": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/which-builtin-type": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.1.4.tgz", - "integrity": "sha512-bppkmBSsHFmIMSl8BO9TbsyzsvGjVoppt8xUiGzwiu/bhDCGxnpOKCxgqj6GuyHE0mINMDecBFPlOm2hzY084w==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.2.0.tgz", + "integrity": "sha512-I+qLGQ/vucCby4tf5HsLmGueEla4ZhwTBSqaooS+Y0BuxN4Cp+okmGuV+8mXZ84KDI9BA+oklo+RzKg0ONdSUA==", "dev": true, - "license": "MIT", "dependencies": { + "call-bind": "^1.0.7", "function.prototype.name": "^1.1.6", "has-tostringtag": "^1.0.2", "is-async-function": "^2.0.0", "is-date-object": "^1.0.5", - "is-finalizationregistry": "^1.0.2", + "is-finalizationregistry": "^1.1.0", "is-generator-function": "^1.0.10", "is-regex": "^1.1.4", "is-weakref": "^1.0.2", @@ -11914,9 +11860,9 @@ "dev": true }, "node_modules/which-typed-array": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz", - "integrity": "sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==", + "version": "1.1.16", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.16.tgz", + "integrity": "sha512-g+N+GAWiRj66DngFwHvISJd+ITsyphZvD1vChfVg6cEdnzy53GzB3oy0fUNlvhz7H7+MiqhYr26qxQShCpKTTQ==", "dev": true, "dependencies": { "available-typed-arrays": "^1.0.7", @@ -11937,7 +11883,6 @@ "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", "dev": true, - "license": "MIT", "dependencies": { "siginfo": "^2.0.0", "stackback": "0.0.2" @@ -11949,6 +11894,15 @@ "node": ">=8" } }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/wrap-ansi": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", @@ -11969,7 +11923,6 @@ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, - "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -11993,7 +11946,6 @@ "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", "dev": true, - "license": "MIT", "engines": { "node": ">=10.0.0" }, diff --git a/client/package.json b/client/package.json index 5aa6681a44b..92747c2fbb7 100644 --- a/client/package.json +++ b/client/package.json @@ -33,7 +33,7 @@ "@graphql-codegen/client-preset": "4.5.1", "@graphql-codegen/introspection": "4.0.3", "@parcel/watcher": "2.5.0", - "@testing-library/react": "16.0.1", + "@testing-library/react": "16.1.0", "@types/react": "19.0.1", "@types/react-dom": "19.0.1", "@typescript-eslint/eslint-plugin": "7.18.0", From e0422cd145c1a021279774e3d7a68102510f0945 Mon Sep 17 00:00:00 2001 From: OTP Bot Date: Mon, 9 Dec 2024 10:12:38 +0000 Subject: [PATCH 67/80] Upgrade debug client to version 2024/12/2024-12-09T10:11 --- application/src/client/index.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/application/src/client/index.html b/application/src/client/index.html index b34591918d8..23748ea08a7 100644 --- a/application/src/client/index.html +++ b/application/src/client/index.html @@ -5,8 +5,8 @@ OTP Debug - - + +
From 6f5b5df790faef7e95c33677b8dac3501969767d Mon Sep 17 00:00:00 2001 From: Teemu Kalvas Date: Mon, 9 Dec 2024 12:45:54 +0200 Subject: [PATCH 68/80] put escalator preferences in a sub object in walk preferences --- .../module/osm/EscalatorProcessor.java | 6 +- .../org/opentripplanner/osm/model/OsmWay.java | 4 +- .../osm/model/OsmWithTags.java | 54 +++++---- .../preference/EscalatorPreferences.java | 109 ++++++++++++++++++ .../request/preference/WalkPreferences.java | 50 +++----- .../routerequest/RouteRequestConfig.java | 45 +++++--- .../street/model/edge/EscalatorEdge.java | 4 +- .../opentripplanner/osm/model/OsmWayTest.java | 5 - .../osm/model/OsmWithTagsTest.java | 2 +- .../preference/WalkPreferencesTest.java | 16 +-- .../street/model/edge/EscalatorEdgeTest.java | 4 +- .../standalone/config/router-config.json | 6 +- doc/user/RouteRequest.md | 29 ++--- doc/user/RouterConfiguration.md | 6 +- 14 files changed, 228 insertions(+), 112 deletions(-) create mode 100644 application/src/main/java/org/opentripplanner/routing/api/request/preference/EscalatorPreferences.java diff --git a/application/src/main/java/org/opentripplanner/graph_builder/module/osm/EscalatorProcessor.java b/application/src/main/java/org/opentripplanner/graph_builder/module/osm/EscalatorProcessor.java index c8f4e0e0042..40695e7c67c 100644 --- a/application/src/main/java/org/opentripplanner/graph_builder/module/osm/EscalatorProcessor.java +++ b/application/src/main/java/org/opentripplanner/graph_builder/module/osm/EscalatorProcessor.java @@ -45,8 +45,8 @@ public void buildEscalatorEdge(OsmWay escalatorWay, double length) { issueStore.add( Issue.issue( "InvalidDuration", - "Duration for osm node %d is not a valid duration: '%s'; it's replaced with 'Optional.empty()' (unknown).", - escalatorWay.getId(), + "Duration for osm node {} is not a valid duration: '{}'; the value is ignored.", + escalatorWay.url(), v ) ) @@ -59,7 +59,7 @@ public void buildEscalatorEdge(OsmWay escalatorWay, double length) { Issue.issue( "InvalidDuration", "Duration for osm node {} makes implied speed {} be outside acceptable range.", - escalatorWay.getId(), + escalatorWay.url(), speed ) ); diff --git a/application/src/main/java/org/opentripplanner/osm/model/OsmWay.java b/application/src/main/java/org/opentripplanner/osm/model/OsmWay.java index 0cc19363a0a..a620545f521 100644 --- a/application/src/main/java/org/opentripplanner/osm/model/OsmWay.java +++ b/application/src/main/java/org/opentripplanner/osm/model/OsmWay.java @@ -3,13 +3,11 @@ import gnu.trove.list.TLongList; import gnu.trove.list.array.TLongArrayList; import java.time.Duration; -import java.time.format.DateTimeParseException; import java.util.Optional; import java.util.Set; import java.util.function.Consumer; import org.opentripplanner.graph_builder.module.osm.StreetTraversalPermissionPair; import org.opentripplanner.street.model.StreetTraversalPermission; -import org.opentripplanner.utils.time.DurationUtils; public class OsmWay extends OsmWithTags { @@ -136,7 +134,7 @@ public boolean isEscalator() { } public Optional getDuration(Consumer errorHandler) { - return getTagAsDuration("duration", errorHandler); + return getTagValueAsDuration("duration", errorHandler); } public boolean isForwardEscalator() { diff --git a/application/src/main/java/org/opentripplanner/osm/model/OsmWithTags.java b/application/src/main/java/org/opentripplanner/osm/model/OsmWithTags.java index 74d1ffd25f5..ab50fb0ec1b 100644 --- a/application/src/main/java/org/opentripplanner/osm/model/OsmWithTags.java +++ b/application/src/main/java/org/opentripplanner/osm/model/OsmWithTags.java @@ -229,36 +229,43 @@ public OptionalInt getTagAsInt(String tag, Consumer errorHandler) { * hh:mm * hh:mm:ss * and where the leading value is not limited to any maximum. + * See OSM wiki definition + * of duration. + * * @param duration string in format mm, hh:mm, or hh:mm:ss * @return Duration * @throws DateTimeParseException on bad input */ public static Duration parseOsmDuration(String duration) { - // Unfortunately DateFormatParserBuilder doesn't quite do enough for this case. - // It has the capability for expressing optional parts, so it could express hh(:mm(:ss)?)? - // but it cannot express (hh:)?mm(:ss)? where the existence of (:ss) implies the existence - // of (hh:). Even if it did, it would not be able to handle the cases where hours are - // greater than 23 or (if there is no hours part at all) minutes are greater than 59, which - // are both allowed by the spec and exist in OSM data. Durations are not LocalTimes after - // all, in parsing a LocalTime it makes sense and is correct that hours cannot be more than - // 23 or minutes more than 59, but in durations if you have capped the largest unit, it is - // reasonable for the amount of the largest unit to be as large as it needs to be. + /* + * Unfortunately DateFormatParserBuilder doesn't quite do enough for this case. + * It has the capability for expressing optional parts, so it could express hh(:mm(:ss)?)? + * but it cannot express (hh:)?mm(:ss)? where the existence of (:ss) implies the existence + * of (hh:). Even if it did, it would not be able to handle the cases where hours are + * greater than 23 or (if there is no hours part at all) minutes are greater than 59, which + * are both allowed by the spec and exist in OSM data. Durations are not LocalTimes after + * all, in parsing a LocalTime it makes sense and is correct that hours cannot be more than + * 23 or minutes more than 59, but in durations if you have capped the largest unit, it is + * reasonable for the amount of the largest unit to be as large as it needs to be. + */ int colonCount = (int) duration.chars().filter(ch -> ch == ':').count(); if (colonCount <= 2) { try { int i, j; long hours, minutes, seconds; - // The first :-separated element can be any width, and has no maximum. It still has - // to be non-negative. The following elements must be 2 characters wide, non-negative, - // and less than 60. + /* + * The first :-separated element can be any width, and has no maximum. It still has + * to be non-negative. The following elements must be 2 characters wide, non-negative, + * and less than 60. + */ switch (colonCount) { - case 0: // case "m" + case 0: /* case "m" */ minutes = Long.parseLong(duration); if (minutes >= 0) { return Duration.ofMinutes(minutes); } break; - case 1: // case "h:mm" + case 1: /* case "h:mm" */ i = duration.indexOf(':'); hours = Long.parseLong(duration.substring(0, i)); minutes = Long.parseLong(duration.substring(i + 1)); @@ -266,8 +273,7 @@ public static Duration parseOsmDuration(String duration) { return Duration.ofHours(hours).plusMinutes(minutes); } break; - default: // case "h:mm:ss" - //case 2: + default: /* case "h:mm:ss" */ i = duration.indexOf(':'); j = duration.indexOf(':', i + 1); hours = Long.parseLong(duration.substring(0, i)); @@ -287,14 +293,22 @@ public static Duration parseOsmDuration(String duration) { break; } } catch (NumberFormatException e) { - // fallthrough + /* fallthrough */ } } - throw new DateTimeParseException("bad clock duration", duration, 0); + throw new DateTimeParseException("Bad OSM duration", duration, 0); } - public Optional getTagAsDuration(String tag, Consumer errorHandler) { - String value = getTag(tag); + /** + * Gets a tag's value, assumes it is an OSM wiki spesified duration, parses and returns it. + * If parsing fails, calls the error handler. + * + * @param key + * @param errorHandler + * @return parsed Duration, or empty + */ + public Optional getTagValueAsDuration(String key, Consumer errorHandler) { + String value = getTag(key); if (value != null) { try { return Optional.of(parseOsmDuration(value)); diff --git a/application/src/main/java/org/opentripplanner/routing/api/request/preference/EscalatorPreferences.java b/application/src/main/java/org/opentripplanner/routing/api/request/preference/EscalatorPreferences.java new file mode 100644 index 00000000000..9a770d99fda --- /dev/null +++ b/application/src/main/java/org/opentripplanner/routing/api/request/preference/EscalatorPreferences.java @@ -0,0 +1,109 @@ +package org.opentripplanner.routing.api.request.preference; + +import static org.opentripplanner.utils.lang.DoubleUtils.doubleEquals; + +import java.io.Serializable; +import java.util.Objects; +import java.util.function.Consumer; +import org.opentripplanner.utils.tostring.ToStringBuilder; + +public class EscalatorPreferences implements Serializable { + + public static final EscalatorPreferences DEFAULT = new EscalatorPreferences(); + + private final double reluctance; + private final double speed; + + private EscalatorPreferences() { + this.reluctance = 1.5; + this.speed = 0.45; + } + + private EscalatorPreferences(Builder builder) { + reluctance = builder.reluctance; + speed = builder.speed; + } + + public static Builder of() { + return new Builder(DEFAULT); + } + + public Builder copyOf() { + return new Builder(this); + } + + public double reluctance() { + return reluctance; + } + + public double speed() { + return speed; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + EscalatorPreferences that = (EscalatorPreferences) o; + return (doubleEquals(that.reluctance, reluctance) && doubleEquals(that.speed, speed)); + } + + @Override + public int hashCode() { + return Objects.hash(speed, reluctance); + } + + @Override + public String toString() { + return ToStringBuilder + .of(EscalatorPreferences.class) + .addNum("speed", speed, DEFAULT.speed) + .addNum("reluctance", reluctance, DEFAULT.reluctance) + .toString(); + } + + public static class Builder { + + private final EscalatorPreferences original; + private double reluctance; + private double speed; + + public Builder(EscalatorPreferences original) { + this.original = original; + this.reluctance = original.reluctance; + this.speed = original.speed; + } + + public EscalatorPreferences original() { + return original; + } + + public double speed() { + return speed; + } + + public Builder withSpeed(double speed) { + this.speed = speed; + return this; + } + + public double reluctance() { + return reluctance; + } + + public Builder withReluctance(double reluctance) { + this.reluctance = reluctance; + return this; + } + + public Builder apply(Consumer body) { + body.accept(this); + return this; + } + + public EscalatorPreferences build() { + var newObj = new EscalatorPreferences(this); + return original.equals(newObj) ? original : newObj; + } + } +} diff --git a/application/src/main/java/org/opentripplanner/routing/api/request/preference/WalkPreferences.java b/application/src/main/java/org/opentripplanner/routing/api/request/preference/WalkPreferences.java index 87dcc320c83..5bc0a120d32 100644 --- a/application/src/main/java/org/opentripplanner/routing/api/request/preference/WalkPreferences.java +++ b/application/src/main/java/org/opentripplanner/routing/api/request/preference/WalkPreferences.java @@ -1,6 +1,7 @@ package org.opentripplanner.routing.api.request.preference; import static org.opentripplanner.utils.lang.DoubleUtils.doubleEquals; +import static org.opentripplanner.utils.lang.ObjectUtils.ifNotNull; import java.io.Serializable; import java.util.Objects; @@ -29,8 +30,7 @@ public final class WalkPreferences implements Serializable { private final double stairsTimeFactor; private final double safetyFactor; - private final double escalatorReluctance; - private final double escalatorSpeed; + private final EscalatorPreferences escalator; private WalkPreferences() { this.speed = 1.33; @@ -39,8 +39,7 @@ private WalkPreferences() { this.stairsReluctance = 2.0; this.stairsTimeFactor = 3.0; this.safetyFactor = 1.0; - this.escalatorReluctance = 1.5; - this.escalatorSpeed = 0.45; + this.escalator = EscalatorPreferences.DEFAULT; } private WalkPreferences(Builder builder) { @@ -50,8 +49,7 @@ private WalkPreferences(Builder builder) { this.stairsReluctance = Units.reluctance(builder.stairsReluctance); this.stairsTimeFactor = Units.reluctance(builder.stairsTimeFactor); this.safetyFactor = Units.reluctance(builder.safetyFactor); - this.escalatorReluctance = Units.reluctance(builder.escalatorReluctance); - this.escalatorSpeed = Units.speed(builder.escalatorSpeed); + this.escalator = builder.escalator; } public static Builder of() { @@ -111,12 +109,8 @@ public double safetyFactor() { return safetyFactor; } - public double escalatorReluctance() { - return escalatorReluctance; - } - - public double escalatorSpeed() { - return escalatorSpeed; + public EscalatorPreferences escalator() { + return escalator; } @Override @@ -131,8 +125,7 @@ public boolean equals(Object o) { doubleEquals(that.stairsReluctance, stairsReluctance) && doubleEquals(that.stairsTimeFactor, stairsTimeFactor) && doubleEquals(that.safetyFactor, safetyFactor) && - doubleEquals(that.escalatorReluctance, escalatorReluctance) && - doubleEquals(that.escalatorSpeed, escalatorSpeed) + escalator.equals(that.escalator) ); } @@ -145,8 +138,7 @@ public int hashCode() { stairsReluctance, stairsTimeFactor, safetyFactor, - escalatorReluctance, - escalatorSpeed + escalator ); } @@ -160,8 +152,7 @@ public String toString() { .addNum("stairsReluctance", stairsReluctance, DEFAULT.stairsReluctance) .addNum("stairsTimeFactor", stairsTimeFactor, DEFAULT.stairsTimeFactor) .addNum("safetyFactor", safetyFactor, DEFAULT.safetyFactor) - .addNum("escalatorReluctance", escalatorReluctance, DEFAULT.escalatorReluctance) - .addNum("escalatorSpeed", escalatorSpeed, DEFAULT.escalatorSpeed) + .addObj("escalator", escalator, DEFAULT.escalator) .toString(); } @@ -175,8 +166,7 @@ public static class Builder { private double stairsTimeFactor; private double safetyFactor; - private double escalatorReluctance; - private double escalatorSpeed; + private EscalatorPreferences escalator; public Builder(WalkPreferences original) { this.original = original; @@ -186,8 +176,7 @@ public Builder(WalkPreferences original) { this.stairsReluctance = original.stairsReluctance; this.stairsTimeFactor = original.stairsTimeFactor; this.safetyFactor = original.safetyFactor; - this.escalatorReluctance = original.escalatorReluctance; - this.escalatorSpeed = original.escalatorSpeed; + this.escalator = original.escalator; } public WalkPreferences original() { @@ -254,21 +243,12 @@ public Builder withSafetyFactor(double safetyFactor) { return this; } - public double escalatorReluctance() { - return escalatorReluctance; - } - - public Builder withEscalatorReluctance(double escalatorReluctance) { - this.escalatorReluctance = escalatorReluctance; - return this; - } - - public double escalatorSpeed() { - return escalatorSpeed; + public EscalatorPreferences escalator() { + return escalator; } - public Builder withEscalatorSpeed(double escalatorSpeed) { - this.escalatorSpeed = escalatorSpeed; + public Builder withEscalator(Consumer body) { + this.escalator = ifNotNull(this.escalator, original.escalator).copyOf().apply(body).build(); return this; } diff --git a/application/src/main/java/org/opentripplanner/standalone/config/routerequest/RouteRequestConfig.java b/application/src/main/java/org/opentripplanner/standalone/config/routerequest/RouteRequestConfig.java index 9f0e0ba17b4..454ab29a68c 100644 --- a/application/src/main/java/org/opentripplanner/standalone/config/routerequest/RouteRequestConfig.java +++ b/application/src/main/java/org/opentripplanner/standalone/config/routerequest/RouteRequestConfig.java @@ -26,6 +26,7 @@ import org.opentripplanner.routing.api.request.preference.AccessEgressPreferences; import org.opentripplanner.routing.api.request.preference.BikePreferences; import org.opentripplanner.routing.api.request.preference.CarPreferences; +import org.opentripplanner.routing.api.request.preference.EscalatorPreferences; import org.opentripplanner.routing.api.request.preference.RoutingPreferences; import org.opentripplanner.routing.api.request.preference.ScooterPreferences; import org.opentripplanner.routing.api.request.preference.StreetPreferences; @@ -737,6 +738,32 @@ private static void mapSystemPreferences(NodeAdapter c, SystemPreferences.Builde } } + private static void mapEscalatorPreferences( + NodeAdapter root, + EscalatorPreferences.Builder escalator + ) { + var dft = escalator.original(); + NodeAdapter c = root.of("escalator").since(V2_7).summary("Escalator preferences.").asObject(); + escalator + .withReluctance( + c + .of("reluctance") + .since(V2_4) + .summary( + "A multiplier for how bad being in an escalator is compared to being in transit for equal lengths of time" + ) + .asDouble(dft.reluctance()) + ) + .withSpeed( + c + .of("speed") + .since(V2_7) + .summary("How fast does an escalator move horizontally?") + .description("Horizontal speed of escalator in m/s.") + .asDouble(dft.speed()) + ); + } + private static void mapWalkPreferences(NodeAdapter root, WalkPreferences.Builder walk) { var dft = walk.original(); NodeAdapter c = root.of("walk").since(V2_5).summary("Walking preferences.").asObject(); @@ -810,22 +837,6 @@ private static void mapWalkPreferences(NodeAdapter root, WalkPreferences.Builder ) .asDouble(dft.safetyFactor()) ) - .withEscalatorReluctance( - c - .of("escalatorReluctance") - .since(V2_4) - .summary( - "A multiplier for how bad being in an escalator is compared to being in transit for equal lengths of time" - ) - .asDouble(dft.escalatorReluctance()) - ) - .withEscalatorSpeed( - c - .of("escalatorSpeed") - .since(V2_7) - .summary("How fast does an escalator move horizontally?") - .description("Horizontal speed of escalator in m/s.") - .asDouble(dft.escalatorSpeed()) - ); + .withEscalator(escalator -> mapEscalatorPreferences(c, escalator)); } } diff --git a/application/src/main/java/org/opentripplanner/street/model/edge/EscalatorEdge.java b/application/src/main/java/org/opentripplanner/street/model/edge/EscalatorEdge.java index fdfd4ee44b4..d44b67568d6 100644 --- a/application/src/main/java/org/opentripplanner/street/model/edge/EscalatorEdge.java +++ b/application/src/main/java/org/opentripplanner/street/model/edge/EscalatorEdge.java @@ -31,11 +31,11 @@ public State[] traverse(State s0) { var s1 = s0.edit(this); double time; if (duration == null) { - time = getDistanceMeters() / s0.getPreferences().walk().escalatorSpeed(); + time = getDistanceMeters() / s0.getPreferences().walk().escalator().speed(); } else { time = duration.toSeconds(); } - s1.incrementWeight(s0.getPreferences().walk().escalatorReluctance() * time); + s1.incrementWeight(s0.getPreferences().walk().escalator().reluctance() * time); s1.incrementTimeInSeconds((int) Math.round(time)); s1.incrementWalkDistance(getDistanceMeters()); return s1.makeStateArray(); diff --git a/application/src/test/java/org/opentripplanner/osm/model/OsmWayTest.java b/application/src/test/java/org/opentripplanner/osm/model/OsmWayTest.java index 277cda7ac9b..9ac9457a9ec 100644 --- a/application/src/test/java/org/opentripplanner/osm/model/OsmWayTest.java +++ b/application/src/test/java/org/opentripplanner/osm/model/OsmWayTest.java @@ -1,13 +1,8 @@ package org.opentripplanner.osm.model; -import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; -import java.time.Duration; -import java.util.Optional; -import java.util.function.Consumer; import org.junit.jupiter.api.Test; import org.opentripplanner.osm.wayproperty.specifier.WayTestData; diff --git a/application/src/test/java/org/opentripplanner/osm/model/OsmWithTagsTest.java b/application/src/test/java/org/opentripplanner/osm/model/OsmWithTagsTest.java index 3fe49ded403..84b74b8f655 100644 --- a/application/src/test/java/org/opentripplanner/osm/model/OsmWithTagsTest.java +++ b/application/src/test/java/org/opentripplanner/osm/model/OsmWithTagsTest.java @@ -325,7 +325,7 @@ void parseTagAsDuration(String value, Optional expected) { var way = new OsmWithTags(); var key = "duration"; way.addTag(key, value); - var duration = way.getTagAsDuration(key, i -> {}); + var duration = way.getTagValueAsDuration(key, i -> {}); assertEquals(expected, duration); } } diff --git a/application/src/test/java/org/opentripplanner/routing/api/request/preference/WalkPreferencesTest.java b/application/src/test/java/org/opentripplanner/routing/api/request/preference/WalkPreferencesTest.java index a61a0558bb1..785b130ca7a 100644 --- a/application/src/test/java/org/opentripplanner/routing/api/request/preference/WalkPreferencesTest.java +++ b/application/src/test/java/org/opentripplanner/routing/api/request/preference/WalkPreferencesTest.java @@ -88,7 +88,7 @@ void testEqualsAndHashCodeWithNewlyConstructedPreferences() { .withReluctance(sameReluctance) .withStairsReluctance(sameStairsReluctance) .withSafetyFactor(sameSafetyFactor) - .withEscalatorReluctance(sameEscalatorReluctance) + .withEscalator(escalator -> escalator.withReluctance(sameEscalatorReluctance)) .withBoardCost(sameBoardCost) .build(); var secondEqual = WalkPreferences @@ -97,7 +97,7 @@ void testEqualsAndHashCodeWithNewlyConstructedPreferences() { .withReluctance(sameReluctance) .withStairsReluctance(sameStairsReluctance) .withSafetyFactor(sameSafetyFactor) - .withEscalatorReluctance(sameEscalatorReluctance) + .withEscalator(escalator -> escalator.withReluctance(sameEscalatorReluctance)) .withBoardCost(sameBoardCost) .build(); assertEqualsAndHashCode(firstEqual, secondEqual); @@ -110,7 +110,7 @@ void testEqualsAndHashCodeWithNewlyConstructedPreferences() { .withReluctance(sameReluctance) .withStairsReluctance(sameStairsReluctance) .withSafetyFactor(sameSafetyFactor) - .withEscalatorReluctance(sameEscalatorReluctance) + .withEscalator(escalator -> escalator.withReluctance(sameEscalatorReluctance)) .withBoardCost(sameBoardCost) .build(); assertNotEqualsAndHashCode(firstEqual, differentSpeedPreferences); @@ -123,7 +123,7 @@ void testEqualsAndHashCodeWithNewlyConstructedPreferences() { .withReluctance(notSameReluctance) .withStairsReluctance(sameStairsReluctance) .withSafetyFactor(sameSafetyFactor) - .withEscalatorReluctance(sameEscalatorReluctance) + .withEscalator(escalator -> escalator.withReluctance(sameEscalatorReluctance)) .withBoardCost(sameBoardCost) .build(); assertNotEqualsAndHashCode(firstEqual, differentReluctancePreferences); @@ -136,7 +136,7 @@ void testEqualsAndHashCodeWithNewlyConstructedPreferences() { .withReluctance(sameReluctance) .withStairsReluctance(notSameStairsReluctance) .withSafetyFactor(sameSafetyFactor) - .withEscalatorReluctance(sameEscalatorReluctance) + .withEscalator(escalator -> escalator.withReluctance(sameEscalatorReluctance)) .withBoardCost(sameBoardCost) .build(); assertNotEqualsAndHashCode(firstEqual, differentStairsReluctancePreferences); @@ -149,7 +149,7 @@ void testEqualsAndHashCodeWithNewlyConstructedPreferences() { .withReluctance(sameReluctance) .withStairsReluctance(sameStairsReluctance) .withSafetyFactor(notSameSafetyFactor) - .withEscalatorReluctance(sameEscalatorReluctance) + .withEscalator(escalator -> escalator.withReluctance(sameEscalatorReluctance)) .withBoardCost(sameBoardCost) .build(); assertNotEqualsAndHashCode(firstEqual, differentSafetyFactorPreferences); @@ -162,7 +162,7 @@ void testEqualsAndHashCodeWithNewlyConstructedPreferences() { .withReluctance(sameReluctance) .withStairsReluctance(sameStairsReluctance) .withSafetyFactor(sameSafetyFactor) - .withEscalatorReluctance(notSameEscalatorReluctance) + .withEscalator(escalator -> escalator.withReluctance(notSameEscalatorReluctance)) .withBoardCost(sameBoardCost) .build(); assertNotEqualsAndHashCode(firstEqual, differentEscalatorReluctancePreferences); @@ -175,7 +175,7 @@ void testEqualsAndHashCodeWithNewlyConstructedPreferences() { .withReluctance(sameReluctance) .withStairsReluctance(sameStairsReluctance) .withSafetyFactor(sameSafetyFactor) - .withEscalatorReluctance(sameEscalatorReluctance) + .withEscalator(escalator -> escalator.withReluctance(sameEscalatorReluctance)) .withBoardCost(notSameBoardCost) .build(); assertNotEqualsAndHashCode(firstEqual, differentBoardCostPreferences); diff --git a/application/src/test/java/org/opentripplanner/street/model/edge/EscalatorEdgeTest.java b/application/src/test/java/org/opentripplanner/street/model/edge/EscalatorEdgeTest.java index 25199e373a0..23ae7a567f8 100644 --- a/application/src/test/java/org/opentripplanner/street/model/edge/EscalatorEdgeTest.java +++ b/application/src/test/java/org/opentripplanner/street/model/edge/EscalatorEdgeTest.java @@ -31,7 +31,9 @@ void testWalking(double escalatorReluctance, double expectedWeight) { var edge = EscalatorEdge.createEscalatorEdge(from, to, 45, null); var req = StreetSearchRequest .of() - .withPreferences(p -> p.withWalk(w -> w.withEscalatorReluctance(escalatorReluctance))) + .withPreferences(p -> + p.withWalk(w -> w.withEscalator(escalator -> escalator.withReluctance(escalatorReluctance))) + ) .withMode(StreetMode.WALK); var res = edge.traverse(new State(from, req.build()))[0]; diff --git a/application/src/test/resources/standalone/config/router-config.json b/application/src/test/resources/standalone/config/router-config.json index 5539ec4de65..e3f5b0caad2 100644 --- a/application/src/test/resources/standalone/config/router-config.json +++ b/application/src/test/resources/standalone/config/router-config.json @@ -75,8 +75,10 @@ "reluctance": 4.0, "stairsReluctance": 1.65, "boardCost": 600, - "escalatorReluctance": 1.5, - "escalatorSpeed": 0.45 + "escalator": { + "reluctance": 1.5, + "speed": 0.45 + } }, "waitReluctance": 1.0, "otherThanPreferredRoutesPenalty": 300, diff --git a/doc/user/RouteRequest.md b/doc/user/RouteRequest.md index c6cdef82c25..5b428ff9175 100644 --- a/doc/user/RouteRequest.md +++ b/doc/user/RouteRequest.md @@ -155,13 +155,14 @@ and in the [transferRequests in build-config.json](BuildConfiguration.md#transfe |    [routes](#rd_unpreferred_routes) | `feed-scoped-id[]` | The ids of the routes that incur an extra cost when being used. Format: `FeedId:RouteId` | *Optional* | | 2.2 | | walk | `object` | Walking preferences. | *Optional* | | 2.5 | |    boardCost | `integer` | Prevents unnecessary transfers by adding a cost for boarding a vehicle. This is the cost that is used when boarding while walking. | *Optional* | `600` | 2.0 | -|    escalatorReluctance | `double` | A multiplier for how bad being in an escalator is compared to being in transit for equal lengths of time | *Optional* | `1.5` | 2.4 | -|    [escalatorSpeed](#rd_walk_escalatorSpeed) | `double` | How fast does an escalator move horizontally? | *Optional* | `0.45` | 2.7 | |    [reluctance](#rd_walk_reluctance) | `double` | A multiplier for how bad walking is, compared to being in transit for equal lengths of time. | *Optional* | `2.0` | 2.0 | |    [safetyFactor](#rd_walk_safetyFactor) | `double` | Factor for how much the walk safety is considered in routing. | *Optional* | `1.0` | 2.2 | |    speed | `double` | The user's walking speed in meters/second. | *Optional* | `1.33` | 2.0 | |    stairsReluctance | `double` | Used instead of walkReluctance for stairs. | *Optional* | `2.0` | 2.0 | |    [stairsTimeFactor](#rd_walk_stairsTimeFactor) | `double` | How much more time does it take to walk a flight of stairs compared to walking a similar horizontal length. | *Optional* | `3.0` | 2.1 | +|    escalator | `object` | Escalator preferences. | *Optional* | | 2.7 | +|       reluctance | `double` | A multiplier for how bad being in an escalator is compared to being in transit for equal lengths of time | *Optional* | `1.5` | 2.4 | +|       [speed](#rd_walk_escalator_speed) | `double` | How fast does an escalator move horizontally? | *Optional* | `0.45` | 2.7 | | wheelchairAccessibility | `object` | See [Wheelchair Accessibility](Accessibility.md) | *Optional* | | 2.2 | |    enabled | `boolean` | Enable wheelchair accessibility. | *Optional* | `false` | 2.0 | |    inaccessibleStreetReluctance | `double` | The factor to multiply the cost of traversing a street edge that is not wheelchair-accessible. | *Optional* | `25.0` | 2.2 | @@ -1072,15 +1073,6 @@ The ids of the routes that incur an extra cost when being used. Format: `FeedId: How much cost is added is configured in `unpreferredCost`. -

escalatorSpeed

- -**Since version:** `2.7` ∙ **Type:** `double` ∙ **Cardinality:** `Optional` ∙ **Default value:** `0.45` -**Path:** /routingDefaults/walk - -How fast does an escalator move horizontally? - -Horizontal speed of escalator in m/s. -

reluctance

**Since version:** `2.0` ∙ **Type:** `double` ∙ **Cardinality:** `Optional` ∙ **Default value:** `2.0` @@ -1115,6 +1107,15 @@ Default value is based on: Fujiyama, T., & Tyler, N. (2010). Predicting the walk speed of pedestrians on stairs. Transportation Planning and Technology, 33(2), 177–202. +

speed

+ +**Since version:** `2.7` ∙ **Type:** `double` ∙ **Cardinality:** `Optional` ∙ **Default value:** `0.45` +**Path:** /routingDefaults/walk/escalator + +How fast does an escalator move horizontally? + +Horizontal speed of escalator in m/s. +

maxSlope

**Since version:** `2.0` ∙ **Type:** `double` ∙ **Cardinality:** `Optional` ∙ **Default value:** `0.083` @@ -1224,8 +1225,10 @@ include stairs as a last result. "reluctance" : 4.0, "stairsReluctance" : 1.65, "boardCost" : 600, - "escalatorReluctance" : 1.5, - "escalatorSpeed" : 0.45 + "escalator" : { + "reluctance" : 1.5, + "speed" : 0.45 + } }, "waitReluctance" : 1.0, "otherThanPreferredRoutesPenalty" : 300, diff --git a/doc/user/RouterConfiguration.md b/doc/user/RouterConfiguration.md index 043e4f2f485..7dae97fd74c 100644 --- a/doc/user/RouterConfiguration.md +++ b/doc/user/RouterConfiguration.md @@ -528,8 +528,10 @@ Used to group requests when monitoring OTP. "reluctance" : 4.0, "stairsReluctance" : 1.65, "boardCost" : 600, - "escalatorReluctance" : 1.5, - "escalatorSpeed" : 0.45 + "escalator" : { + "reluctance" : 1.5, + "speed" : 0.45 + } }, "waitReluctance" : 1.0, "otherThanPreferredRoutesPenalty" : 300, From 1e64a995b777320e15a22e044eded8d50645fe12 Mon Sep 17 00:00:00 2001 From: Teemu Kalvas Date: Mon, 9 Dec 2024 13:19:02 +0200 Subject: [PATCH 69/80] prettier wanted less spaces --- .../java/org/opentripplanner/osm/model/OsmWithTags.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/application/src/main/java/org/opentripplanner/osm/model/OsmWithTags.java b/application/src/main/java/org/opentripplanner/osm/model/OsmWithTags.java index ab50fb0ec1b..0c44d892524 100644 --- a/application/src/main/java/org/opentripplanner/osm/model/OsmWithTags.java +++ b/application/src/main/java/org/opentripplanner/osm/model/OsmWithTags.java @@ -259,13 +259,13 @@ public static Duration parseOsmDuration(String duration) { * and less than 60. */ switch (colonCount) { - case 0: /* case "m" */ + case 0:/* case "m" */ minutes = Long.parseLong(duration); if (minutes >= 0) { return Duration.ofMinutes(minutes); } break; - case 1: /* case "h:mm" */ + case 1:/* case "h:mm" */ i = duration.indexOf(':'); hours = Long.parseLong(duration.substring(0, i)); minutes = Long.parseLong(duration.substring(i + 1)); @@ -273,7 +273,7 @@ public static Duration parseOsmDuration(String duration) { return Duration.ofHours(hours).plusMinutes(minutes); } break; - default: /* case "h:mm:ss" */ + default:/* case "h:mm:ss" */ i = duration.indexOf(':'); j = duration.indexOf(':', i + 1); hours = Long.parseLong(duration.substring(0, i)); From 9c8e928399d3e82c58816d71760df9b1640b154f Mon Sep 17 00:00:00 2001 From: Teemu Kalvas Date: Mon, 9 Dec 2024 13:43:30 +0200 Subject: [PATCH 70/80] comment formatting --- .../osm/model/OsmWithTags.java | 39 +++++++++---------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/application/src/main/java/org/opentripplanner/osm/model/OsmWithTags.java b/application/src/main/java/org/opentripplanner/osm/model/OsmWithTags.java index 0c44d892524..d6ed30be092 100644 --- a/application/src/main/java/org/opentripplanner/osm/model/OsmWithTags.java +++ b/application/src/main/java/org/opentripplanner/osm/model/OsmWithTags.java @@ -237,35 +237,33 @@ public OptionalInt getTagAsInt(String tag, Consumer errorHandler) { * @throws DateTimeParseException on bad input */ public static Duration parseOsmDuration(String duration) { - /* - * Unfortunately DateFormatParserBuilder doesn't quite do enough for this case. - * It has the capability for expressing optional parts, so it could express hh(:mm(:ss)?)? - * but it cannot express (hh:)?mm(:ss)? where the existence of (:ss) implies the existence - * of (hh:). Even if it did, it would not be able to handle the cases where hours are - * greater than 23 or (if there is no hours part at all) minutes are greater than 59, which - * are both allowed by the spec and exist in OSM data. Durations are not LocalTimes after - * all, in parsing a LocalTime it makes sense and is correct that hours cannot be more than - * 23 or minutes more than 59, but in durations if you have capped the largest unit, it is - * reasonable for the amount of the largest unit to be as large as it needs to be. - */ + // Unfortunately DateFormatParserBuilder doesn't quite do enough for this case. + // It has the capability for expressing optional parts, so it could express hh(:mm(:ss)?)? + // but it cannot express (hh:)?mm(:ss)? where the existence of (:ss) implies the existence + // of (hh:). Even if it did, it would not be able to handle the cases where hours are + // greater than 23 or (if there is no hours part at all) minutes are greater than 59, which + // are both allowed by the spec and exist in OSM data. Durations are not LocalTimes after + // all, in parsing a LocalTime it makes sense and is correct that hours cannot be more than + // 23 or minutes more than 59, but in durations if you have capped the largest unit, it is + // reasonable for the amount of the largest unit to be as large as it needs to be. int colonCount = (int) duration.chars().filter(ch -> ch == ':').count(); if (colonCount <= 2) { try { int i, j; long hours, minutes, seconds; - /* - * The first :-separated element can be any width, and has no maximum. It still has - * to be non-negative. The following elements must be 2 characters wide, non-negative, - * and less than 60. - */ + // The first :-separated element can be any width, and has no maximum. It still has + // to be non-negative. The following elements must be 2 characters wide, non-negative, + // and less than 60. switch (colonCount) { - case 0:/* case "m" */ + // case "m" + case 0: minutes = Long.parseLong(duration); if (minutes >= 0) { return Duration.ofMinutes(minutes); } break; - case 1:/* case "h:mm" */ + // case "h:mm" + case 1: i = duration.indexOf(':'); hours = Long.parseLong(duration.substring(0, i)); minutes = Long.parseLong(duration.substring(i + 1)); @@ -273,7 +271,8 @@ public static Duration parseOsmDuration(String duration) { return Duration.ofHours(hours).plusMinutes(minutes); } break; - default:/* case "h:mm:ss" */ + // case "h:mm:ss" + default: i = duration.indexOf(':'); j = duration.indexOf(':', i + 1); hours = Long.parseLong(duration.substring(0, i)); @@ -293,7 +292,7 @@ public static Duration parseOsmDuration(String duration) { break; } } catch (NumberFormatException e) { - /* fallthrough */ + // fallthrough } } throw new DateTimeParseException("Bad OSM duration", duration, 0); From 68b9c61ac442e449bda595d11e36f259834e306a Mon Sep 17 00:00:00 2001 From: Teemu Kalvas Date: Mon, 9 Dec 2024 13:50:08 +0200 Subject: [PATCH 71/80] revert explanation of default escalator speed --- .../api/request/preference/EscalatorPreferences.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/application/src/main/java/org/opentripplanner/routing/api/request/preference/EscalatorPreferences.java b/application/src/main/java/org/opentripplanner/routing/api/request/preference/EscalatorPreferences.java index 9a770d99fda..3c150b43417 100644 --- a/application/src/main/java/org/opentripplanner/routing/api/request/preference/EscalatorPreferences.java +++ b/application/src/main/java/org/opentripplanner/routing/api/request/preference/EscalatorPreferences.java @@ -14,9 +14,14 @@ public class EscalatorPreferences implements Serializable { private final double reluctance; private final double speed; + /* Using the angle of 30 degrees and a speed of 0.5 m/s gives a horizontal component + * of approx. 0.43 m/s. This is typical of short escalators like those in shopping + * malls. */ + private static final double HORIZONTAL_SPEED = 0.45; + private EscalatorPreferences() { this.reluctance = 1.5; - this.speed = 0.45; + this.speed = HORIZONTAL_SPEED; } private EscalatorPreferences(Builder builder) { From ffffb13b54cc7785d7563f79698af84100d6deb6 Mon Sep 17 00:00:00 2001 From: Joel Lappalainen Date: Mon, 9 Dec 2024 14:04:15 +0200 Subject: [PATCH 72/80] Update application/src/main/java/org/opentripplanner/osm/model/OsmWithTags.java Co-authored-by: Leonard Ehrenfried --- .../main/java/org/opentripplanner/osm/model/OsmWithTags.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/src/main/java/org/opentripplanner/osm/model/OsmWithTags.java b/application/src/main/java/org/opentripplanner/osm/model/OsmWithTags.java index d6ed30be092..3f47d4454bd 100644 --- a/application/src/main/java/org/opentripplanner/osm/model/OsmWithTags.java +++ b/application/src/main/java/org/opentripplanner/osm/model/OsmWithTags.java @@ -299,7 +299,7 @@ public static Duration parseOsmDuration(String duration) { } /** - * Gets a tag's value, assumes it is an OSM wiki spesified duration, parses and returns it. + * Gets a tag's value, assumes it is an OSM wiki specified duration, parses and returns it. * If parsing fails, calls the error handler. * * @param key From 7b38d5cdbcd12c7ff5575f9cb412496c6cc6e4e0 Mon Sep 17 00:00:00 2001 From: OTP Changelog Bot Date: Mon, 9 Dec 2024 12:04:53 +0000 Subject: [PATCH 73/80] Add changelog entry for #6268 [ci skip] --- doc/user/Changelog.md | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/user/Changelog.md b/doc/user/Changelog.md index 7d96b53885c..56a58be86b2 100644 --- a/doc/user/Changelog.md +++ b/doc/user/Changelog.md @@ -59,6 +59,7 @@ based on merged pull requests. Search GitHub issues and pull requests for smalle - Switch GTFS flex `safe_duration_offset` back to seconds [#6298](https://github.com/opentripplanner/OpenTripPlanner/pull/6298) - Remove unused GtfsGraphQlApiRentalStationFuzzyMatching feature [#6282](https://github.com/opentripplanner/OpenTripPlanner/pull/6282) - Make debug UI background layers configurable with new file `debug-ui-config.json` [#6295](https://github.com/opentripplanner/OpenTripPlanner/pull/6295) +- Better escalator duration control: specific duration from OSM duration tag, default speed from build-config.json [#6268](https://github.com/opentripplanner/OpenTripPlanner/pull/6268) [](AUTOMATIC_CHANGELOG_PLACEHOLDER_DO_NOT_REMOVE) ## 2.6.0 (2024-09-18) From a866234deb1d4691a6e2a6dc7ca681ff8ca944d7 Mon Sep 17 00:00:00 2001 From: OTP Serialization Version Bot Date: Mon, 9 Dec 2024 12:05:14 +0000 Subject: [PATCH 74/80] Bump serialization version id for #6268 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index a502f3d57bc..c3f29ad1cee 100644 --- a/pom.xml +++ b/pom.xml @@ -58,7 +58,7 @@ - 174 + 175 32.1 2.52 From a1d44ba8b438a21d83db598b116f8df0e6f54dec Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Mon, 9 Dec 2024 16:23:49 +0100 Subject: [PATCH 75/80] Reduce geocode cluster radius --- .../org/opentripplanner/ext/geocoder/StopClusterMapper.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/src/ext/java/org/opentripplanner/ext/geocoder/StopClusterMapper.java b/application/src/ext/java/org/opentripplanner/ext/geocoder/StopClusterMapper.java index daecb7f6a4e..d420d0e8784 100644 --- a/application/src/ext/java/org/opentripplanner/ext/geocoder/StopClusterMapper.java +++ b/application/src/ext/java/org/opentripplanner/ext/geocoder/StopClusterMapper.java @@ -121,7 +121,7 @@ private List buildStopClusters(Collection stopL .stream() .collect( Collectors.groupingBy(sl -> - new DeduplicationKey(sl.getName(), sl.getCoordinate().roundToApproximate100m()) + new DeduplicationKey(sl.getName(), sl.getCoordinate().roundToApproximate10m()) ) ) .values() From e70d2eb2e24e8d08b05f13209e4f968a5a19bde0 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 9 Dec 2024 22:46:14 +0000 Subject: [PATCH 76/80] chore(deps): update google.dagger.version to v2.53 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index c3f29ad1cee..545d558b210 100644 --- a/pom.xml +++ b/pom.xml @@ -61,7 +61,7 @@ 175 32.1 - 2.52 + 2.53 2.18.2 3.1.9 5.11.3 From 9e8f2f6558e8f5b824dbf1ef5bea6fc318c0deab Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Tue, 10 Dec 2024 08:10:39 +0100 Subject: [PATCH 77/80] Fix nullability --- .../configure/StopConsolidationRepositoryModule.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/application/src/ext/java/org/opentripplanner/ext/stopconsolidation/configure/StopConsolidationRepositoryModule.java b/application/src/ext/java/org/opentripplanner/ext/stopconsolidation/configure/StopConsolidationRepositoryModule.java index 75cd6cb868f..cb774af1619 100644 --- a/application/src/ext/java/org/opentripplanner/ext/stopconsolidation/configure/StopConsolidationRepositoryModule.java +++ b/application/src/ext/java/org/opentripplanner/ext/stopconsolidation/configure/StopConsolidationRepositoryModule.java @@ -2,7 +2,6 @@ import dagger.Binds; import dagger.Module; -import javax.annotation.Nullable; import org.opentripplanner.ext.stopconsolidation.StopConsolidationRepository; import org.opentripplanner.ext.stopconsolidation.internal.DefaultStopConsolidationRepository; @@ -13,6 +12,5 @@ @Module public interface StopConsolidationRepositoryModule { @Binds - @Nullable - StopConsolidationRepository bindRepository(@Nullable DefaultStopConsolidationRepository repo); + StopConsolidationRepository bindRepository(DefaultStopConsolidationRepository repo); } From b476098db4f4c9a5dee42ba0d93b5c44bf8b7db4 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Tue, 10 Dec 2024 08:25:17 +0100 Subject: [PATCH 78/80] Update magidoc --- .github/workflows/cibuild.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/cibuild.yml b/.github/workflows/cibuild.yml index 212c3934dc2..0368fc5c34a 100644 --- a/.github/workflows/cibuild.yml +++ b/.github/workflows/cibuild.yml @@ -134,7 +134,7 @@ jobs: - name: Build GTFS GraphQL API documentation run: | - npm install -g @magidoc/cli@6.1.0 + npm install -g @magidoc/cli@6.2.0 magidoc generate --stacktrace - name: Deploy compiled HTML to Github pages From 7266bdf3078105d083798581a547018982236c8e Mon Sep 17 00:00:00 2001 From: Thomas Gran Date: Tue, 10 Dec 2024 13:05:50 +0100 Subject: [PATCH 79/80] Add endpoint to download Transmodel GraphQL Schema --- .../opentripplanner/apis/transmodel/TransmodelAPI.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/application/src/main/java/org/opentripplanner/apis/transmodel/TransmodelAPI.java b/application/src/main/java/org/opentripplanner/apis/transmodel/TransmodelAPI.java index fe73e8b9887..d2d6379d19b 100644 --- a/application/src/main/java/org/opentripplanner/apis/transmodel/TransmodelAPI.java +++ b/application/src/main/java/org/opentripplanner/apis/transmodel/TransmodelAPI.java @@ -2,9 +2,11 @@ import com.fasterxml.jackson.databind.ObjectMapper; import graphql.schema.GraphQLSchema; +import graphql.schema.idl.SchemaPrinter; import io.micrometer.core.instrument.Tag; import jakarta.ws.rs.BadRequestException; import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.GET; import jakarta.ws.rs.POST; import jakarta.ws.rs.Path; import jakarta.ws.rs.PathParam; @@ -138,6 +140,12 @@ public Response getGraphQL(String query, @Context HttpHeaders headers) { ); } + @GET + @Path("schema.graphql") + public Response getGraphQLSchema() { + return Response.ok().encoding("UTF-8").entity(new SchemaPrinter().print(schema)).build(); + } + private static Iterable getTagsFromHeaders(HttpHeaders headers) { return tracingHeaderTags .stream() From f765199bb730ced20212d4cc7f7e2baa574ef14d Mon Sep 17 00:00:00 2001 From: Thomas Gran Date: Tue, 10 Dec 2024 14:49:14 +0100 Subject: [PATCH 80/80] doc: Add a disclaimer to the top of the Transmodel Schema served at runtime. --- .../apis/transmodel/TransmodelAPI.java | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/application/src/main/java/org/opentripplanner/apis/transmodel/TransmodelAPI.java b/application/src/main/java/org/opentripplanner/apis/transmodel/TransmodelAPI.java index d2d6379d19b..66377a56390 100644 --- a/application/src/main/java/org/opentripplanner/apis/transmodel/TransmodelAPI.java +++ b/application/src/main/java/org/opentripplanner/apis/transmodel/TransmodelAPI.java @@ -33,6 +33,15 @@ @Produces(MediaType.APPLICATION_JSON) public class TransmodelAPI { + // Note, the blank line at the end is intended + private static final String SCHEMA_DOC_HEADER = + """ +# THIS IS NOT INTENDED FOR PRODUCTION USE. We recommend using the GraphQL introspection instead. +# This is intended for the OTP Debug UI and can also be used by humans to get the schema with the +# OTP configured default-values injected. + +"""; + private static final Logger LOG = LoggerFactory.getLogger(TransmodelAPI.class); private static GraphQLSchema schema; @@ -143,7 +152,8 @@ public Response getGraphQL(String query, @Context HttpHeaders headers) { @GET @Path("schema.graphql") public Response getGraphQLSchema() { - return Response.ok().encoding("UTF-8").entity(new SchemaPrinter().print(schema)).build(); + var text = SCHEMA_DOC_HEADER + new SchemaPrinter().print(schema); + return Response.ok().encoding("UTF-8").entity(text).build(); } private static Iterable getTagsFromHeaders(HttpHeaders headers) {