diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000..273fff0a --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,11 @@ +# To get started with Dependabot version updates, you'll need to specify which +# package ecosystems to update and where the package manifests are located. +# Please see the documentation for all configuration options: +# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file + +version: 2 +updates: + - package-ecosystem: "maven" # See documentation for possible values + directory: "/" # Location of package manifests + schedule: + interval: "weekly" diff --git a/.github/workflows/maven-release.yml b/.github/workflows/maven-release.yml index be71f3ee..7af50c61 100644 --- a/.github/workflows/maven-release.yml +++ b/.github/workflows/maven-release.yml @@ -2,8 +2,7 @@ name: Maven Deploy on: release: - types: - - created + types: [created] jobs: deploy-release: @@ -24,7 +23,7 @@ jobs: - name: Setup Java uses: actions/setup-java@v2 with: - java-version: 11 + java-version: 17 distribution: 'adopt' server-id: pt2matsim-releases server-username: MAVEN_USERNAME diff --git a/.github/workflows/maven-test.yml b/.github/workflows/maven-test.yml index e71cf1d1..7468c447 100644 --- a/.github/workflows/maven-test.yml +++ b/.github/workflows/maven-test.yml @@ -13,9 +13,9 @@ jobs: steps: - uses: actions/checkout@v2 - - name: Set up JDK 11 + - name: Set up JDK 17 uses: actions/setup-java@v1 with: - java-version: 1.11 + java-version: 1.17 - name: Build with Maven run: mvn test -B -Dmatsim.preferLocalDtds=true diff --git a/README.md b/README.md index 6c7f573b..4a7462c5 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # PT2MATSim -[![Build Status](https://travis-ci.org/matsim-org/pt2matsim.svg?branch=master)](https://travis-ci.org/matsim-org/pt2matsim) +[![Status Maven Test](https://github.com/matsim-org/pt2matsim/actions/workflows/maven-test.yml/badge.svg)](https://github.com/matsim-org/pt2matsim/actions/workflows/maven-test.yml) PT2MATSim is a package to convert public transit data from GTFS, HAFAS or OSM to a completely mapped MATSim schedule. @@ -45,8 +45,8 @@ To include pt2matsim in your own maven project, add this snippet to your pom.xml org.matsim pt2matsim - 22.3 + 24.4 -The master branch contains the snapshot version with the latest changes. Clone the git repository to use it. \ No newline at end of file +The master branch contains the snapshot version with the latest changes. Clone the git repository to use it. diff --git a/doc/defaultOsmConfig.xml b/doc/defaultOsmConfig.xml index 84af330d..bf37dc9a 100644 --- a/doc/defaultOsmConfig.xml +++ b/doc/defaultOsmConfig.xml @@ -24,6 +24,8 @@ This file can be used for visualization purposes in Simunto Via or GIS software. --> + + diff --git a/pom.xml b/pom.xml index f5df9da7..609e71d4 100644 --- a/pom.xml +++ b/pom.xml @@ -4,17 +4,17 @@ 4.0.0 org.matsim pt2matsim - 22.3 + 24.5-SNAPSHOT PT2MATSim Public Transport to MATSim - pt2matsim-releases - pt2matsim Releases Maven Repository - https://repo.matsim.org/repository/matsim-releases/ - + pt2matsim-releases + pt2matsim Releases Maven Repository + https://repo.matsim.org/repository/matsim-releases/ + @@ -23,70 +23,118 @@ https://repo.matsim.org/repository/matsim - osgeo - https://repo.osgeo.org/repository/release + osgeo + https://repo.osgeo.org/repository/release - - 24.2 - + + 29.6 + 2.18.2 + 1.19.0 + 2.23.1 + 5.10.3 + org.matsim matsim - 13.0 + 2024.0 - junit - junit - 4.13.1 + org.junit.jupiter + junit-jupiter-api + ${junit.version} test com.opencsv opencsv - 3.7 + 5.9 - commons-io - commons-io - 2.7 - + commons-io + commons-io + 2.16.1 + de.grundid.opendatalab geojson-jackson - 1.5 + 1.14 net.lingala.zip4j zip4j - 2.9.1 + 2.11.5 - org.geotools - gt-referencing - ${geotools.version} + com.google.guava + guava + 33.3.1-jre + + + org.apache.logging.log4j + log4j-api + ${log4j.version} + + + org.apache.logging.log4j + log4j-core + ${log4j.version} + + + com.fasterxml.jackson.core + jackson-databind + + + + com.fasterxml.jackson.core + jackson-annotations + + + org.locationtech.jts + jts-core + ${jts.version} org.geotools - gt-epsg-hsql + gt-opengis ${geotools.version} + + + + com.fasterxml.jackson + jackson-bom + ${jackson.version} + import + pom + + + + + + + + org.apache.maven.plugins + maven-dependency-plugin + 3.8.0 + + + org.apache.maven.plugins maven-compiler-plugin - 2.3.2 + 3.13.0 - 1.8 - 1.8 - false - false + 17 + true + true UTF-8 true @@ -101,7 +149,7 @@ org.apache.maven.plugins maven-shade-plugin - 3.1.0 + 3.6.0 @@ -109,6 +157,7 @@ true + false @@ -117,16 +166,16 @@ - - - *:* - - META-INF/*.SF - META-INF/*.DSA - META-INF/*.RSA - - - + + + *:* + + META-INF/*.SF + META-INF/*.DSA + META-INF/*.RSA + + + @@ -134,7 +183,7 @@ org.apache.maven.plugins maven-source-plugin - 3.0.1 + 3.3.1 attach-sources diff --git a/src/main/java/org/matsim/pt2matsim/config/OsmConverterConfigGroup.java b/src/main/java/org/matsim/pt2matsim/config/OsmConverterConfigGroup.java index 6ef16f54..c4f50732 100644 --- a/src/main/java/org/matsim/pt2matsim/config/OsmConverterConfigGroup.java +++ b/src/main/java/org/matsim/pt2matsim/config/OsmConverterConfigGroup.java @@ -21,6 +21,8 @@ import org.matsim.core.api.internal.MatsimParameters; import org.matsim.core.config.*; +import org.matsim.core.config.ReflectiveConfigGroup.Comment; +import org.matsim.core.config.ReflectiveConfigGroup.Parameter; import org.matsim.core.utils.collections.CollectionUtils; import org.matsim.pt2matsim.osm.lib.Osm; @@ -65,6 +67,9 @@ public class OsmConverterConfigGroup extends ReflectiveConfigGroup { private boolean keepTagsAsAttributes = true; private boolean keepWaysWithPublicTransit = true; + @Parameter + @Comment("If true: OSM turn restrictions are parsed and written as disallowedNextLinks attribute to the first link.") + public boolean parseTurnRestrictions = false; public OsmConverterConfigGroup() { super(GROUP_NAME); @@ -254,7 +259,7 @@ public ConfigGroup createParameterSet(final String type) { */ public static class OsmWayParams extends ReflectiveConfigGroup implements MatsimParameters { - public final static String SET_NAME = "wayDefaultParams"; + public static final String SET_NAME = "wayDefaultParams"; private String osmKey; private String osmValue; @@ -385,7 +390,7 @@ private void setAllowedTransportModesString(String allowedTransportModesString) */ public static class RoutableSubnetworkParams extends ReflectiveConfigGroup implements MatsimParameters { - public final static String SET_NAME = "routableSubnetwork"; + public static final String SET_NAME = "routableSubnetwork"; /** Network mode, for which a consistent routable network is created **/ private String subnetworkMode; diff --git a/src/main/java/org/matsim/pt2matsim/config/PublicTransitMappingConfigGroup.java b/src/main/java/org/matsim/pt2matsim/config/PublicTransitMappingConfigGroup.java index 2eb638ce..fc41e3d4 100644 --- a/src/main/java/org/matsim/pt2matsim/config/PublicTransitMappingConfigGroup.java +++ b/src/main/java/org/matsim/pt2matsim/config/PublicTransitMappingConfigGroup.java @@ -479,7 +479,7 @@ public void setCandidateDistanceMultiplier(double multiplier) { */ public static class TransportModeAssignment extends ReflectiveConfigGroup implements MatsimParameters { - public final static String SET_NAME = "transportModeAssignment"; + public static final String SET_NAME = "transportModeAssignment"; private static final String SCHEDULE_MODE = "scheduleMode"; private static final String NETWORK_MODES = "networkModes"; diff --git a/src/main/java/org/matsim/pt2matsim/editor/BasicScheduleEditor.java b/src/main/java/org/matsim/pt2matsim/editor/BasicScheduleEditor.java index adcc6805..3cb9fc0f 100644 --- a/src/main/java/org/matsim/pt2matsim/editor/BasicScheduleEditor.java +++ b/src/main/java/org/matsim/pt2matsim/editor/BasicScheduleEditor.java @@ -18,8 +18,13 @@ package org.matsim.pt2matsim.editor; +import com.opencsv.CSVParserBuilder; import com.opencsv.CSVReader; -import org.apache.log4j.Logger; +import com.opencsv.CSVReaderBuilder; +import com.opencsv.exceptions.CsvValidationException; + +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.LogManager; import org.matsim.api.core.v01.Coord; import org.matsim.api.core.v01.Id; import org.matsim.api.core.v01.network.Link; @@ -50,7 +55,7 @@ */ public class BasicScheduleEditor implements ScheduleEditor { - protected static Logger log = Logger.getLogger(RunScheduleEditor.class); + protected static Logger log = LogManager.getLogger(RunScheduleEditor.class); // fields private final Network network; private final TransitSchedule schedule; @@ -93,15 +98,20 @@ public TransitSchedule getSchedule() { */ @Override public void parseCommandCsv(String filePath) throws IOException { - CSVReader reader = new CSVReader(new FileReader(filePath), ';'); - - String[] line = reader.readNext(); - while(line != null) { - log.info(CollectionUtils.arrayToString(line)); - executeCmdLine(line); - line = reader.readNext(); + try (CSVReader reader = new CSVReaderBuilder(new FileReader(filePath)) + .withCSVParser(new CSVParserBuilder() + .withSeparator(';') + .build()) + .build()) { + String[] line = reader.readNext(); + while (line != null) { + log.info(CollectionUtils.arrayToString(line)); + executeCmdLine(line); + line = reader.readNext(); + } + } catch (CsvValidationException e) { + throw new RuntimeException(e); } - reader.close(); } /** diff --git a/src/main/java/org/matsim/pt2matsim/editor/RunScheduleEditor.java b/src/main/java/org/matsim/pt2matsim/editor/RunScheduleEditor.java index 057f7553..ead6e9d3 100644 --- a/src/main/java/org/matsim/pt2matsim/editor/RunScheduleEditor.java +++ b/src/main/java/org/matsim/pt2matsim/editor/RunScheduleEditor.java @@ -18,8 +18,10 @@ package org.matsim.pt2matsim.editor; -import org.apache.log4j.Level; -import org.apache.log4j.Logger; +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.core.config.Configurator; +import org.apache.logging.log4j.LogManager; import org.matsim.api.core.v01.network.Network; import org.matsim.core.network.io.NetworkWriter; import org.matsim.pt.transitSchedule.api.TransitSchedule; @@ -37,7 +39,7 @@ */ public class RunScheduleEditor { - protected static Logger log = Logger.getLogger(RunScheduleEditor.class); + protected static Logger log = LogManager.getLogger(RunScheduleEditor.class); /** * Loads the schedule and network, then executes all commands in the commands csv file. @@ -99,17 +101,17 @@ public static void run(String scheduleFile, String networkFile, String commandFi } private static void setLogLevels() { - Logger.getLogger(org.matsim.core.router.Dijkstra.class).setLevel(Level.ERROR); // suppress no route found warnings - Logger.getLogger(Network.class).setLevel(Level.WARN); - Logger.getLogger(org.matsim.api.core.v01.network.Node.class).setLevel(Level.WARN); - Logger.getLogger(org.matsim.api.core.v01.network.Link.class).setLevel(Level.WARN); - Logger.getLogger(org.matsim.core.utils.io.MatsimXmlParser.class).setLevel(Level.WARN); - Logger.getLogger(org.matsim.core.utils.io.MatsimFileTypeGuesser.class).setLevel(Level.WARN); - Logger.getLogger(org.matsim.core.network.filter.NetworkFilterManager.class).setLevel(Level.WARN); - Logger.getLogger(org.matsim.core.router.util.PreProcessDijkstra.class).setLevel(Level.WARN); - Logger.getLogger(org.matsim.core.router.util.PreProcessDijkstra.class).setLevel(Level.WARN); - Logger.getLogger(org.matsim.core.router.util.PreProcessEuclidean.class).setLevel(Level.WARN); - Logger.getLogger(org.matsim.core.router.util.PreProcessLandmarks.class).setLevel(Level.WARN); + Configurator.setLevel(LogManager.getLogger(org.matsim.core.router.Dijkstra.class).getName(), Level.ERROR); // suppress no route found warnings + Configurator.setLevel(LogManager.getLogger(Network.class).getName(), Level.WARN); + Configurator.setLevel(LogManager.getLogger(org.matsim.api.core.v01.network.Node.class).getName(), Level.WARN); + Configurator.setLevel(LogManager.getLogger(org.matsim.api.core.v01.network.Link.class).getName(), Level.WARN); + Configurator.setLevel(LogManager.getLogger(org.matsim.core.utils.io.MatsimXmlParser.class).getName(), Level.WARN); + Configurator.setLevel(LogManager.getLogger(org.matsim.core.utils.io.MatsimFileTypeGuesser.class).getName(), Level.WARN); + Configurator.setLevel(LogManager.getLogger(org.matsim.core.network.filter.NetworkFilterManager.class).getName(), Level.WARN); + Configurator.setLevel(LogManager.getLogger(org.matsim.core.router.util.PreProcessDijkstra.class).getName(), Level.WARN); + Configurator.setLevel(LogManager.getLogger(org.matsim.core.router.util.PreProcessDijkstra.class).getName(), Level.WARN); + Configurator.setLevel(LogManager.getLogger(org.matsim.core.router.util.PreProcessEuclidean.class).getName(), Level.WARN); + Configurator.setLevel(LogManager.getLogger(org.matsim.core.router.util.PreProcessLandmarks.class).getName(), Level.WARN); } } \ No newline at end of file diff --git a/src/main/java/org/matsim/pt2matsim/gtfs/GtfsConverter.java b/src/main/java/org/matsim/pt2matsim/gtfs/GtfsConverter.java index 5affd810..815153da 100644 --- a/src/main/java/org/matsim/pt2matsim/gtfs/GtfsConverter.java +++ b/src/main/java/org/matsim/pt2matsim/gtfs/GtfsConverter.java @@ -18,7 +18,8 @@ package org.matsim.pt2matsim.gtfs; -import org.apache.log4j.Logger; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.LogManager; import org.matsim.api.core.v01.Id; import org.matsim.core.utils.misc.Time; import org.matsim.pt.transitSchedule.api.*; @@ -50,7 +51,7 @@ public class GtfsConverter { public static final String DAY_WITH_MOST_TRIPS = "dayWithMostTrips"; public static final String DAY_WITH_MOST_SERVICES = "dayWithMostServices"; - protected static Logger log = Logger.getLogger(GtfsConverter.class); + protected static Logger log = LogManager.getLogger(GtfsConverter.class); protected final GtfsFeed feed; protected final TransitScheduleFactory scheduleFactory = ScheduleTools.createSchedule().getFactory(); diff --git a/src/main/java/org/matsim/pt2matsim/gtfs/GtfsFeedImpl.java b/src/main/java/org/matsim/pt2matsim/gtfs/GtfsFeedImpl.java index 206394da..b93eacfd 100755 --- a/src/main/java/org/matsim/pt2matsim/gtfs/GtfsFeedImpl.java +++ b/src/main/java/org/matsim/pt2matsim/gtfs/GtfsFeedImpl.java @@ -19,10 +19,13 @@ package org.matsim.pt2matsim.gtfs; import com.opencsv.CSVReader; +import com.opencsv.exceptions.CsvValidationException; + import net.lingala.zip4j.ZipFile; import net.lingala.zip4j.exception.ZipException; import org.apache.commons.io.input.BOMInputStream; -import org.apache.log4j.Logger; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.LogManager; import org.matsim.api.core.v01.Coord; import org.matsim.api.core.v01.Id; import org.matsim.core.utils.geometry.CoordinateTransformation; @@ -47,7 +50,7 @@ */ public class GtfsFeedImpl implements GtfsFeed { - protected static final Logger log = Logger.getLogger(GtfsFeedImpl.class); + protected static final Logger log = LogManager.getLogger(GtfsFeedImpl.class); /** * Path to the folder where the gtfs files are located @@ -217,6 +220,8 @@ protected void loadAgencies() throws IOException { reader.close(); } catch (ArrayIndexOutOfBoundsException e) { throw new RuntimeException("Line " + l + " in agency.txt is empty or malformed."); + } catch (CsvValidationException e) { + throw new RuntimeException(e); } log.info("... agency.txt loaded"); } @@ -267,6 +272,8 @@ protected void loadStops() throws IOException { reader.close(); } catch (ArrayIndexOutOfBoundsException e) { throw new RuntimeException("Line " + l + " in stops.txt is empty or malformed."); + } catch (CsvValidationException e) { + throw new RuntimeException(e); } log.info("... stops.txt loaded"); } @@ -313,6 +320,8 @@ protected boolean loadCalendar() { return false; } catch (ArrayIndexOutOfBoundsException i) { throw new RuntimeException("Line " + l + " in calendar.txt is empty or malformed."); + } catch (CsvValidationException e) { + throw new RuntimeException(e); } log.info("... calendar.txt loaded"); return true; @@ -366,6 +375,8 @@ protected boolean loadCalendarDates() { return false; } catch (ArrayIndexOutOfBoundsException i) { throw new RuntimeException("Line " + l + " in calendar_dates.txt is empty or malformed."); + } catch (CsvValidationException e) { + throw new RuntimeException(e); } return true; } @@ -409,6 +420,8 @@ protected void loadShapes() { log.info("... no shapes file found."); } catch (ArrayIndexOutOfBoundsException i) { throw new RuntimeException("Line " + l + " in shapes.txt is empty or malformed."); + } catch (CsvValidationException e) { + throw new RuntimeException(e); } } @@ -457,6 +470,8 @@ protected void loadRoutes() throws IOException { reader.close(); } catch (ArrayIndexOutOfBoundsException i) { throw new RuntimeException("Line " + l + " in routes.txt is empty or malformed."); + } catch (CsvValidationException e) { + throw new RuntimeException(e); } log.info("... routes.txt loaded"); } @@ -517,6 +532,8 @@ protected void loadTrips() throws IOException { reader.close(); } catch (ArrayIndexOutOfBoundsException i) { throw new RuntimeException("Line " + l + " in trips.txt is empty or malformed."); + } catch (CsvValidationException e) { + throw new RuntimeException(e); } log.info("... trips.txt loaded"); } @@ -602,6 +619,8 @@ protected void loadStopTimes() throws IOException { reader.close(); } catch (ArrayIndexOutOfBoundsException i) { throw new RuntimeException("Line " + l + " in stop_times.txt is empty or malformed."); + } catch (CsvValidationException e) { + throw new RuntimeException(e); } log.info("... stop_times.txt loaded"); } @@ -656,6 +675,8 @@ protected void loadFrequencies() { throw new RuntimeException("Line " + l + " in frequencies.txt is empty or malformed."); } catch (IOException e) { e.printStackTrace(); + } catch (CsvValidationException e) { + throw new RuntimeException(e); } } @@ -699,6 +720,8 @@ protected void loadTransfers() { transfersFileFound = false; } catch (IOException e) { e.printStackTrace(); + } catch (CsvValidationException e) { + throw new RuntimeException(e); } if(transfersFileFound) { log.info("... transfers.txt loaded"); @@ -709,14 +732,15 @@ protected String unzip(String compressedZip) { String unzippedFolder = compressedZip.substring(0, compressedZip.length() - 4) + "/"; log.info("Unzipping " + compressedZip + " to " + unzippedFolder); - try { - ZipFile zipFile = new ZipFile(compressedZip); + try (ZipFile zipFile = new ZipFile(compressedZip)) { if(zipFile.isEncrypted()) { throw new RuntimeException("Zip file is encrypted"); } zipFile.extractAll(unzippedFolder); } catch (ZipException e) { e.printStackTrace(); + } catch(IOException e) { + throw new RuntimeException(e); } return unzippedFolder; } diff --git a/src/main/java/org/matsim/pt2matsim/hafas/HafasConverter.java b/src/main/java/org/matsim/pt2matsim/hafas/HafasConverter.java index 9a821197..962e7b9d 100644 --- a/src/main/java/org/matsim/pt2matsim/hafas/HafasConverter.java +++ b/src/main/java/org/matsim/pt2matsim/hafas/HafasConverter.java @@ -21,7 +21,8 @@ package org.matsim.pt2matsim.hafas; -import org.apache.log4j.Logger; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.LogManager; import org.matsim.api.core.v01.Id; import org.matsim.core.utils.collections.MapUtils; import org.matsim.core.utils.geometry.CoordinateTransformation; @@ -32,6 +33,7 @@ import org.matsim.pt2matsim.tools.debug.ScheduleCleaner; import org.matsim.vehicles.VehicleCapacity; import org.matsim.vehicles.VehicleType; +import org.matsim.vehicles.VehicleUtils; import org.matsim.vehicles.Vehicles; import org.matsim.vehicles.VehiclesFactory; @@ -51,7 +53,7 @@ */ public class HafasConverter { - protected static Logger log = Logger.getLogger(HafasConverter.class); + protected static Logger log = LogManager.getLogger(HafasConverter.class); public static void run(String hafasFolder, TransitSchedule schedule, CoordinateTransformation transformation, Vehicles vehicles) throws IOException { run(hafasFolder, schedule, transformation, vehicles, -1); @@ -89,7 +91,7 @@ public static void run(String hafasFolder, TransitSchedule schedule, CoordinateT // 1. Read and create stop facilities log.info(" Read transit stops..."); - StopReader.run(schedule, transformation, hafasFolder + "BFKOORD_GEO"); + StopReader.run(schedule, transformation, hafasFolder + "BFKOORD_WGS"); log.info(" Read transit stops... done."); // 1.a Read minimal transfer times @@ -181,9 +183,9 @@ private static void createTransitRoutesFromFPLAN(List routes, Transi // using default values for vehicle type vehicleType.setLength(defaultVehicleType.length); vehicleType.setWidth(defaultVehicleType.width); - vehicleType.setAccessTime(defaultVehicleType.accessTime); - vehicleType.setEgressTime(defaultVehicleType.egressTime); - vehicleType.setDoorOperationMode(defaultVehicleType.doorOperation); + VehicleUtils.setAccessTime(vehicleType, defaultVehicleType.accessTime); + VehicleUtils.setEgressTime(vehicleType, defaultVehicleType.egressTime); + VehicleUtils.setDoorOperationMode(vehicleType, defaultVehicleType.doorOperation); vehicleType.setPcuEquivalents(defaultVehicleType.pcuEquivalents); VehicleCapacity vehicleCapacity = vehicleType.getCapacity(); diff --git a/src/main/java/org/matsim/pt2matsim/hafas/lib/BitfeldAnalyzer.java b/src/main/java/org/matsim/pt2matsim/hafas/lib/BitfeldAnalyzer.java index 391eff0f..e2a731cf 100644 --- a/src/main/java/org/matsim/pt2matsim/hafas/lib/BitfeldAnalyzer.java +++ b/src/main/java/org/matsim/pt2matsim/hafas/lib/BitfeldAnalyzer.java @@ -21,7 +21,8 @@ package org.matsim.pt2matsim.hafas.lib; -import org.apache.log4j.Logger; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.LogManager; import java.io.BufferedReader; import java.io.FileInputStream; @@ -40,14 +41,17 @@ * @author boescpa */ public class BitfeldAnalyzer { - protected static Logger log = Logger.getLogger(BitfeldAnalyzer.class); + protected static Logger log = LogManager.getLogger(BitfeldAnalyzer.class); public static Set findBitfeldnumbersOfBusiestDay(String FPLAN, String BITFELD) throws IOException { final Set bitfeldNummern = new HashSet<>(); final int posMaxFVals = find4DayBlockWithMostFVals(FPLAN, BITFELD); BufferedReader readsLines = new BufferedReader(new InputStreamReader(new FileInputStream(BITFELD), "latin1")); - String newLine = readsLines.readLine(); - while (newLine != null) { + String newLine; + while ((newLine = readsLines.readLine()) != null) { + if (newLine.startsWith("*")) { + continue; + } /*Spalte Typ Bedeutung 1−6 INT32 Bitfeldnummer 8−103 CHAR Bitfeld (Binärkodierung der Tage, an welchen Fahrt, in Hexadezimalzahlen notiert.)*/ @@ -68,7 +72,6 @@ public static Set findBitfeldnumbersOfBusiestDay(String FPLAN, String B if (matches >= 1) { bitfeldNummern.add(bitfeldnummer); } - newLine = readsLines.readLine(); } readsLines.close(); bitfeldNummern.add(0); @@ -116,8 +119,11 @@ private static int find4DayBlockWithMostFVals(String FPLAN, String BITFELD) { int[] bitfeldStats = new int[96]; try { BufferedReader readsLines = new BufferedReader(new InputStreamReader(new FileInputStream(BITFELD), "latin1")); - String newLine = readsLines.readLine(); - while (newLine != null) { + String newLine; + while ((newLine = readsLines.readLine()) != null) { + if (newLine.startsWith("*")) { + continue; + } /*Spalte Typ Bedeutung 1−6 INT32 Bitfeldnummer 8−103 CHAR Bitfeld (Binärkodierung der Tage, an welchen Fahrt, in Hexadezimalzahlen notiert.)*/ @@ -131,7 +137,6 @@ private static int find4DayBlockWithMostFVals(String FPLAN, String BITFELD) { bitfeldStats[i] += bitFeldValue; } } - newLine = readsLines.readLine(); } readsLines.close(); } catch (IOException e) { @@ -162,12 +167,14 @@ public static Set getBitfieldsAtValidDay(final int dayNr, final String Set validBitfields = new HashSet<>(); BufferedReader readsLines = new BufferedReader(new InputStreamReader(new FileInputStream(pathFile), "utf-8")); - String newLine = readsLines.readLine(); - while (newLine != null) { + String newLine; + while ((newLine = readsLines.readLine()) != null) { + if (newLine.startsWith("*")) { + continue; + } int id = Integer.parseInt(newLine.substring(0, 6)); String bitfield = new BigInteger(newLine.substring(7), 16).toString(2).substring(offset_bitstring); if (bitfield.charAt(dayNr)== '1') validBitfields.add(id); - newLine = readsLines.readLine(); } readsLines.close(); // TODO this error-prone and should be removed by a stable solution diff --git a/src/main/java/org/matsim/pt2matsim/hafas/lib/ECKDATENReader.java b/src/main/java/org/matsim/pt2matsim/hafas/lib/ECKDATENReader.java index 9d866fcc..bcf20865 100644 --- a/src/main/java/org/matsim/pt2matsim/hafas/lib/ECKDATENReader.java +++ b/src/main/java/org/matsim/pt2matsim/hafas/lib/ECKDATENReader.java @@ -1,6 +1,7 @@ package org.matsim.pt2matsim.hafas.lib; -import org.apache.log4j.Logger; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.LogManager; import java.io.*; import java.time.LocalDate; @@ -9,7 +10,7 @@ public class ECKDATENReader { - protected static Logger log = Logger.getLogger(ECKDATENReader.class); + protected static Logger log = LogManager.getLogger(ECKDATENReader.class); private static final String ECKDATEN = "ECKDATEN"; /* 1 1−10 CHAR Fahrplanstart im Format TT.MM.JJJJ @@ -19,7 +20,17 @@ public class ECKDATENReader { public static LocalDate getFahrPlanStart(String pathToHafasFolder) throws IOException { if (new File(pathToHafasFolder, ECKDATEN).exists()) { BufferedReader readsLines = new BufferedReader(new InputStreamReader(new FileInputStream(pathToHafasFolder + ECKDATEN), "utf-8")); - LocalDate startDate = getDate(readsLines.readLine()); + String line; + String firstLineAfterComments = null; + + while ((line = readsLines.readLine()) != null) { + if (line.startsWith("*")) { + continue; + } + firstLineAfterComments = line; + break; + } + LocalDate startDate = getDate(firstLineAfterComments); readsLines.close(); return startDate; } else { @@ -31,8 +42,17 @@ public static LocalDate getFahrPlanStart(String pathToHafasFolder) throws IOExce public static LocalDate getFahrPlanEnd(String pathToHafasFolder) throws IOException { if (new File(pathToHafasFolder, ECKDATEN).exists()) { BufferedReader readsLines = new BufferedReader(new InputStreamReader(new FileInputStream(pathToHafasFolder + ECKDATEN), "utf-8")); - readsLines.readLine(); - LocalDate endDate = getDate(readsLines.readLine()); + String line; + String secondLineAfterComments = null; + + while ((line = readsLines.readLine()) != null) { + if (line.startsWith("*")) { + continue; + } + secondLineAfterComments = readsLines.readLine(); + break; + } + LocalDate endDate = getDate(secondLineAfterComments); readsLines.close(); return endDate; diff --git a/src/main/java/org/matsim/pt2matsim/hafas/lib/FPLANReader.java b/src/main/java/org/matsim/pt2matsim/hafas/lib/FPLANReader.java index 8016ef49..b24c3ca3 100644 --- a/src/main/java/org/matsim/pt2matsim/hafas/lib/FPLANReader.java +++ b/src/main/java/org/matsim/pt2matsim/hafas/lib/FPLANReader.java @@ -21,7 +21,8 @@ package org.matsim.pt2matsim.hafas.lib; -import org.apache.log4j.Logger; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.LogManager; import org.matsim.api.core.v01.Id; import org.matsim.core.utils.misc.Counter; import org.matsim.vehicles.VehicleType; @@ -41,7 +42,7 @@ * @author polettif */ public class FPLANReader { - protected static Logger log = Logger.getLogger(FPLANReader.class); + protected static Logger log = LogManager.getLogger(FPLANReader.class); /** * Only reads the PtRoutes and leaves line/route @@ -64,24 +65,25 @@ public static List parseFPLAN(Set bitfeldNummern, Map stopId = Id.create(newLine.substring(0, 7), TransitStopFacility.class); double transferTime = Integer.parseInt(newLine.substring(11, 13)) * 60; minimalTransferTimes.set(stopId, stopId, transferTime); - newLine = readsLines.readLine(); } readsLines.close(); } else { diff --git a/src/main/java/org/matsim/pt2matsim/hafas/lib/OperatorReader.java b/src/main/java/org/matsim/pt2matsim/hafas/lib/OperatorReader.java index b0e924ad..df8ec56d 100644 --- a/src/main/java/org/matsim/pt2matsim/hafas/lib/OperatorReader.java +++ b/src/main/java/org/matsim/pt2matsim/hafas/lib/OperatorReader.java @@ -37,16 +37,20 @@ public class OperatorReader { public static Map readOperators(String BETRIEB_DE) throws IOException { Map operators = new HashMap<>(); - BufferedReader readsLines = new BufferedReader(new InputStreamReader(new FileInputStream(BETRIEB_DE), "utf-8")); - String newLine = readsLines.readLine(); - while (newLine != null) { - String abbrevationOperator = newLine.split("\"")[1].replace(" ",""); - newLine = readsLines.readLine(); - if (newLine == null) break; - String operatorId = newLine.substring(8, 14).trim(); - operators.put(operatorId, abbrevationOperator); - // read the next operator: - newLine = readsLines.readLine(); + try(BufferedReader readsLines = new BufferedReader(new InputStreamReader(new FileInputStream(BETRIEB_DE), "utf-8"))) { + String newLine; + while ((newLine = readsLines.readLine()) != null) { + if (newLine.startsWith("*")) { + continue; + } + String abbrevationOperator = newLine.split("\"")[1].replace(" ",""); + newLine = readsLines.readLine(); + if (newLine == null) break; + String[] operatorIds = newLine.substring(8).trim().split("\\s+"); + for (String operatorId : operatorIds) { + operators.put(operatorId.trim(), abbrevationOperator); + } + } } return operators; } diff --git a/src/main/java/org/matsim/pt2matsim/hafas/lib/StopReader.java b/src/main/java/org/matsim/pt2matsim/hafas/lib/StopReader.java index 67b291ba..6240b12e 100644 --- a/src/main/java/org/matsim/pt2matsim/hafas/lib/StopReader.java +++ b/src/main/java/org/matsim/pt2matsim/hafas/lib/StopReader.java @@ -21,7 +21,8 @@ package org.matsim.pt2matsim.hafas.lib; -import org.apache.log4j.Logger; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.LogManager; import org.matsim.api.core.v01.Coord; import org.matsim.api.core.v01.Id; import org.matsim.core.utils.geometry.CoordinateTransformation; @@ -37,53 +38,55 @@ import java.util.Map; /** - * Reads all stops from HAFAS-BFKOORD_GEO and adds them as TransitStopFacilities + * Reads all stops from HAFAS-BFKOORD_WGS and adds them as TransitStopFacilities * to the provided TransitSchedule. * * @author boescpa */ public class StopReader { - protected static Logger log = Logger.getLogger(StopReader.class); + protected static Logger log = LogManager.getLogger(StopReader.class); private final CoordinateTransformation transformation; private final TransitSchedule schedule; private final TransitScheduleFactory scheduleBuilder; private final Map usedCoordinates = new HashMap<>(); - private final String pathToBFKOORD_GEOFile; + private final String pathToBFKOORD_WGSFile; - public StopReader(TransitSchedule schedule, CoordinateTransformation transformation, String pathToBFKOORD_GEOFile) { + public StopReader(TransitSchedule schedule, CoordinateTransformation transformation, String pathToBFKOORD_WGSFile) { this.schedule = schedule; this.transformation = transformation; this.scheduleBuilder = this.schedule.getFactory(); - this.pathToBFKOORD_GEOFile = pathToBFKOORD_GEOFile; + this.pathToBFKOORD_WGSFile = pathToBFKOORD_WGSFile; } - public static void run(TransitSchedule schedule, CoordinateTransformation transformation, String pathToBFKOORD_GEOFile) throws IOException { - new StopReader(schedule, transformation, pathToBFKOORD_GEOFile).createStops(); + public static void run(TransitSchedule schedule, CoordinateTransformation transformation, String pathToBFKOORD_WGSFile) throws IOException { + new StopReader(schedule, transformation, pathToBFKOORD_WGSFile).createStops(); } private void createStops() throws IOException { log.info(" Read transit stops..."); - BufferedReader readsLines = new BufferedReader(new InputStreamReader(new FileInputStream(pathToBFKOORD_GEOFile), "utf-8")); - String newLine = readsLines.readLine(); - while (newLine != null) { + BufferedReader readsLines = new BufferedReader(new InputStreamReader(new FileInputStream(pathToBFKOORD_WGSFile), "utf-8")); + String newLine; + while ((newLine = readsLines.readLine()) != null) { + if (newLine.startsWith("*")) { + continue; + } /* 1−7 INT32 Nummer der Haltestelle - 9−18 FLOAT X-Koordinate - 20−29 FLOAT Y-Koordinate - 31−36 INT16 Z-Koordinate (Tunnel und andere Streckenelemente ohne eigentliche Haltestelle haben keine Z-Koordinate) - 38ff CHAR Kommentarzeichen "%"gefolgt vom Klartext des Haltestellennamens (optional zur besseren Lesbarkeit) + 9−19 FLOAT X-Koordinate + 21−31 FLOAT Y-Koordinate + 33−38 INT16 Z-Koordinate (Tunnel und andere Streckenelemente ohne eigentliche Haltestelle haben keine Z-Koordinate) + 40ff CHAR Kommentarzeichen "%"gefolgt vom Klartext des Haltestellennamens (optional zur besseren Lesbarkeit) */ Id stopId = Id.create(newLine.substring(0, 7), TransitStopFacility.class); - double xCoord = Double.parseDouble(newLine.substring(8, 18)); - double yCoord = Double.parseDouble(newLine.substring(19, 29)); + double xCoord = Double.parseDouble(newLine.substring(8, 19)); + double yCoord = Double.parseDouble(newLine.substring(20, 31)); Coord coord = new Coord(xCoord, yCoord); if (this.transformation != null) { coord = this.transformation.transform(coord); } - String stopName = newLine.substring(39, newLine.length()); + String stopName = newLine.substring(41); createStop(stopId, coord, stopName); - newLine = readsLines.readLine(); } readsLines.close(); log.info(" Read transit stops... done."); diff --git a/src/main/java/org/matsim/pt2matsim/mapping/PTMapper.java b/src/main/java/org/matsim/pt2matsim/mapping/PTMapper.java index 3acdd254..09299f64 100644 --- a/src/main/java/org/matsim/pt2matsim/mapping/PTMapper.java +++ b/src/main/java/org/matsim/pt2matsim/mapping/PTMapper.java @@ -21,7 +21,8 @@ package org.matsim.pt2matsim.mapping; -import org.apache.log4j.Logger; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.LogManager; import org.matsim.api.core.v01.Id; import org.matsim.api.core.v01.network.Link; import org.matsim.api.core.v01.network.Network; @@ -66,7 +67,7 @@ */ public class PTMapper { - protected static Logger log = Logger.getLogger(PTMapper.class); + protected static Logger log = LogManager.getLogger(PTMapper.class); private final PseudoSchedule pseudoSchedule = new PseudoScheduleImpl(); private Network network; private TransitSchedule schedule; diff --git a/src/main/java/org/matsim/pt2matsim/mapping/Progress.java b/src/main/java/org/matsim/pt2matsim/mapping/Progress.java index ecb3f766..8b4c6396 100644 --- a/src/main/java/org/matsim/pt2matsim/mapping/Progress.java +++ b/src/main/java/org/matsim/pt2matsim/mapping/Progress.java @@ -1,9 +1,10 @@ package org.matsim.pt2matsim.mapping; -import org.apache.log4j.Logger; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.LogManager; public class Progress { - private Logger logger = Logger.getLogger(Progress.class); + private Logger logger = LogManager.getLogger(Progress.class); private final long total; private final String description; diff --git a/src/main/java/org/matsim/pt2matsim/mapping/PseudoRoutingImpl.java b/src/main/java/org/matsim/pt2matsim/mapping/PseudoRoutingImpl.java index 2a9e1b7f..3d9db86c 100644 --- a/src/main/java/org/matsim/pt2matsim/mapping/PseudoRoutingImpl.java +++ b/src/main/java/org/matsim/pt2matsim/mapping/PseudoRoutingImpl.java @@ -18,7 +18,8 @@ package org.matsim.pt2matsim.mapping; -import org.apache.log4j.Logger; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.LogManager; import org.matsim.api.core.v01.network.Link; import org.matsim.api.core.v01.network.Network; import org.matsim.core.router.util.LeastCostPathCalculator; @@ -31,10 +32,11 @@ import org.matsim.pt2matsim.mapping.networkRouter.ScheduleRoutersFactory; import org.matsim.pt2matsim.mapping.pseudoRouter.*; -import java.util.ArrayList; import java.util.HashSet; import java.util.List; +import java.util.Queue; import java.util.Set; +import java.util.concurrent.ConcurrentLinkedQueue; /** * Generates and calculates the pseudoRoutes for all the queued @@ -46,14 +48,14 @@ */ public class PseudoRoutingImpl implements PseudoRouting { - protected static Logger log = Logger.getLogger(PseudoRoutingImpl.class); + protected static Logger log = LogManager.getLogger(PseudoRoutingImpl.class); private final Progress progress; private static boolean warnMinTravelCost = true; + private static Queue queue = new ConcurrentLinkedQueue<>(); private final LinkCandidateCreator linkCandidates; - private final ScheduleRoutersFactory scheduleRoutersFactory; - private final List queue = new ArrayList<>(); + private final ScheduleRouters scheduleRouters; private final Set necessaryArtificialLinks = new HashSet<>(); @@ -62,7 +64,7 @@ public class PseudoRoutingImpl implements PseudoRouting { public PseudoRoutingImpl(ScheduleRoutersFactory scheduleRoutersFactory, LinkCandidateCreator linkCandidates, double maxTravelCostFactor, Progress progress) { this.maxTravelCostFactor = maxTravelCostFactor; - this.scheduleRoutersFactory = scheduleRoutersFactory; + this.scheduleRouters = scheduleRoutersFactory.createInstance(); this.linkCandidates = linkCandidates; this.progress = progress; } @@ -74,9 +76,9 @@ public void addTransitLineToQueue(TransitLine transitLine) { @Override public void run() { - ScheduleRouters scheduleRouters = scheduleRoutersFactory.createInstance(); - for(TransitLine transitLine : queue) { + TransitLine transitLine; + while ((transitLine = queue.poll()) != null) { for(TransitRoute transitRoute : transitLine.getRoutes().values()) { /* [1] Initiate pseudoGraph and Dijkstra algorithm for the current transitRoute. diff --git a/src/main/java/org/matsim/pt2matsim/mapping/linkCandidateCreation/LinkCandidateCreatorStandard.java b/src/main/java/org/matsim/pt2matsim/mapping/linkCandidateCreation/LinkCandidateCreatorStandard.java index 26c20c2e..0153d825 100644 --- a/src/main/java/org/matsim/pt2matsim/mapping/linkCandidateCreation/LinkCandidateCreatorStandard.java +++ b/src/main/java/org/matsim/pt2matsim/mapping/linkCandidateCreation/LinkCandidateCreatorStandard.java @@ -18,7 +18,8 @@ package org.matsim.pt2matsim.mapping.linkCandidateCreation; -import org.apache.log4j.Logger; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.LogManager; import org.matsim.api.core.v01.Coord; import org.matsim.api.core.v01.Id; import org.matsim.api.core.v01.network.Link; @@ -45,7 +46,7 @@ public class LinkCandidateCreatorStandard implements LinkCandidateCreator { private static final Set loopLinkModes = CollectionUtils.stringToSet(PublicTransitMappingStrings.ARTIFICIAL_LINK_MODE + "," + PublicTransitMappingStrings.STOP_FACILITY_LOOP_LINK); - protected static Logger log = Logger.getLogger(LinkCandidateCreatorStandard.class); + protected static Logger log = LogManager.getLogger(LinkCandidateCreatorStandard.class); private final TransitSchedule schedule; private final Network network; diff --git a/src/main/java/org/matsim/pt2matsim/mapping/networkRouter/ScheduleRoutersGtfsShapes.java b/src/main/java/org/matsim/pt2matsim/mapping/networkRouter/ScheduleRoutersGtfsShapes.java index b95c8780..4a3403c4 100755 --- a/src/main/java/org/matsim/pt2matsim/mapping/networkRouter/ScheduleRoutersGtfsShapes.java +++ b/src/main/java/org/matsim/pt2matsim/mapping/networkRouter/ScheduleRoutersGtfsShapes.java @@ -1,12 +1,13 @@ package org.matsim.pt2matsim.mapping.networkRouter; -import org.apache.log4j.Logger; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.LogManager; import org.matsim.api.core.v01.Id; import org.matsim.api.core.v01.network.Link; import org.matsim.api.core.v01.network.Network; import org.matsim.api.core.v01.network.Node; import org.matsim.api.core.v01.population.Person; -import org.matsim.core.router.FastAStarEuclideanFactory; +import org.matsim.core.router.speedy.SpeedyALTFactory; import org.matsim.core.router.util.LeastCostPathCalculator; import org.matsim.core.router.util.TravelDisutility; import org.matsim.core.router.util.TravelTime; @@ -38,7 +39,7 @@ */ public class ScheduleRoutersGtfsShapes implements ScheduleRouters { - protected static Logger log = Logger.getLogger(ScheduleRoutersGtfsShapes.class); + protected static Logger log = LogManager.getLogger(ScheduleRoutersGtfsShapes.class); // standard fields private final TransitSchedule schedule; @@ -105,7 +106,8 @@ private void load() { NetworkTools.cutNetwork(cutNetwork, nodesWithinBuffer); ShapeRouter r = new ShapeRouter(shape); - pathCalculator = new PathCalculator(new FastAStarEuclideanFactory().createPathCalculator(cutNetwork, r, r)); + pathCalculator = new PathCalculator( + new SpeedyALTFactory().createPathCalculator(cutNetwork, r, r)); pathCalculatorsByShape.put(shapeId, pathCalculator); networksByShape.put(shapeId, cutNetwork); diff --git a/src/main/java/org/matsim/pt2matsim/mapping/networkRouter/ScheduleRoutersOsmAttributes.java b/src/main/java/org/matsim/pt2matsim/mapping/networkRouter/ScheduleRoutersOsmAttributes.java index 64fd698f..45e5102d 100755 --- a/src/main/java/org/matsim/pt2matsim/mapping/networkRouter/ScheduleRoutersOsmAttributes.java +++ b/src/main/java/org/matsim/pt2matsim/mapping/networkRouter/ScheduleRoutersOsmAttributes.java @@ -18,13 +18,14 @@ package org.matsim.pt2matsim.mapping.networkRouter; -import org.apache.log4j.Logger; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.LogManager; import org.matsim.api.core.v01.Id; import org.matsim.api.core.v01.network.Link; import org.matsim.api.core.v01.network.Network; import org.matsim.api.core.v01.network.Node; import org.matsim.api.core.v01.population.Person; -import org.matsim.core.router.FastAStarLandmarksFactory; +import org.matsim.core.router.speedy.SpeedyALTFactory; import org.matsim.core.router.util.LeastCostPathCalculator; import org.matsim.core.router.util.LeastCostPathCalculatorFactory; import org.matsim.core.router.util.TravelDisutility; @@ -52,7 +53,7 @@ public class ScheduleRoutersOsmAttributes implements ScheduleRouters { - protected static Logger log = Logger.getLogger(ScheduleRoutersGtfsShapes.class); + protected static Logger log = LogManager.getLogger(ScheduleRoutersGtfsShapes.class); /** * If a link has a route with the same transport mode as the transit route, * the link's travel cost is multiplied by this factor. @@ -99,7 +100,7 @@ public ScheduleRoutersOsmAttributes(TransitSchedule schedule, Network network, M */ private void load() { log.info("Initiating network and router for transit routes..."); - LeastCostPathCalculatorFactory factory = new FastAStarLandmarksFactory(nThreads); + LeastCostPathCalculatorFactory factory = new SpeedyALTFactory(); for (TransitLine transitLine : schedule.getTransitLines().values()) { for (TransitRoute transitRoute : transitLine.getRoutes().values()) { String scheduleMode = transitRoute.getTransportMode(); diff --git a/src/main/java/org/matsim/pt2matsim/mapping/networkRouter/ScheduleRoutersStandard.java b/src/main/java/org/matsim/pt2matsim/mapping/networkRouter/ScheduleRoutersStandard.java index 0cc38a72..0352c45e 100755 --- a/src/main/java/org/matsim/pt2matsim/mapping/networkRouter/ScheduleRoutersStandard.java +++ b/src/main/java/org/matsim/pt2matsim/mapping/networkRouter/ScheduleRoutersStandard.java @@ -1,12 +1,13 @@ package org.matsim.pt2matsim.mapping.networkRouter; -import org.apache.log4j.Logger; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.LogManager; import org.matsim.api.core.v01.Id; import org.matsim.api.core.v01.network.Link; import org.matsim.api.core.v01.network.Network; import org.matsim.api.core.v01.network.Node; import org.matsim.api.core.v01.population.Person; -import org.matsim.core.router.FastAStarLandmarksFactory; +import org.matsim.core.router.speedy.SpeedyALTFactory; import org.matsim.core.router.util.LeastCostPathCalculator; import org.matsim.core.router.util.LeastCostPathCalculatorFactory; import org.matsim.core.router.util.TravelDisutility; @@ -35,7 +36,7 @@ */ public class ScheduleRoutersStandard implements ScheduleRouters { - protected static Logger log = Logger.getLogger(ScheduleRoutersStandard.class); + protected static Logger log = LogManager.getLogger(ScheduleRoutersStandard.class); // standard fields private final TransitSchedule schedule; @@ -78,7 +79,7 @@ private void load() { log.info("=============================================="); log.info("Creating network routers for transit routes..."); log.info("Initiating network and router for transit routes..."); - LeastCostPathCalculatorFactory factory = new FastAStarLandmarksFactory(nThreads); + LeastCostPathCalculatorFactory factory = new SpeedyALTFactory(); for(TransitLine transitLine : schedule.getTransitLines().values()) { for(TransitRoute transitRoute : transitLine.getRoutes().values()) { String scheduleMode = transitRoute.getTransportMode(); diff --git a/src/main/java/org/matsim/pt2matsim/mapping/pseudoRouter/ArtificialLinkImpl.java b/src/main/java/org/matsim/pt2matsim/mapping/pseudoRouter/ArtificialLinkImpl.java index 257a9594..cc557c10 100644 --- a/src/main/java/org/matsim/pt2matsim/mapping/pseudoRouter/ArtificialLinkImpl.java +++ b/src/main/java/org/matsim/pt2matsim/mapping/pseudoRouter/ArtificialLinkImpl.java @@ -26,6 +26,7 @@ import org.matsim.pt2matsim.mapping.linkCandidateCreation.LinkCandidate; import org.matsim.pt2matsim.tools.PTMapperTools; import org.matsim.utils.objectattributes.attributable.Attributes; +import org.matsim.utils.objectattributes.attributable.AttributesImpl; import java.util.Set; @@ -46,7 +47,7 @@ public class ArtificialLinkImpl implements ArtificialLink { private double capacity = 9999; private Set transportModes = PublicTransitMappingStrings.ARTIFICIAL_LINK_MODE_AS_SET; - private Attributes attributes = new Attributes(); + private Attributes attributes = new AttributesImpl(); public ArtificialLinkImpl(LinkCandidate fromLinkCandidate, LinkCandidate toLinkCandidate, double freespeed, double linkLength) { this.id = PTMapperTools.createArtificialLinkId(fromLinkCandidate, toLinkCandidate); diff --git a/src/main/java/org/matsim/pt2matsim/mapping/pseudoRouter/PseudoGraphImpl.java b/src/main/java/org/matsim/pt2matsim/mapping/pseudoRouter/PseudoGraphImpl.java index 431a562e..680c4d22 100644 --- a/src/main/java/org/matsim/pt2matsim/mapping/pseudoRouter/PseudoGraphImpl.java +++ b/src/main/java/org/matsim/pt2matsim/mapping/pseudoRouter/PseudoGraphImpl.java @@ -19,7 +19,8 @@ package org.matsim.pt2matsim.mapping.pseudoRouter; -import org.apache.log4j.Logger; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.LogManager; import org.matsim.api.core.v01.Id; import org.matsim.api.core.v01.network.Link; import org.matsim.core.utils.geometry.CoordUtils; @@ -35,7 +36,7 @@ public class PseudoGraphImpl implements PseudoGraph { /*package*/ static final String SOURCE = "SOURCE"; /*package*/ static final String DESTINATION = "DESTINATION"; - protected static Logger log = Logger.getLogger(PseudoGraphImpl.class); + protected static Logger log = LogManager.getLogger(PseudoGraphImpl.class); private final Id SOURCE_ID = Id.create(SOURCE, PseudoRouteStop.class); private final PseudoRouteStop SOURCE_PSEUDO_STOP = new PseudoRouteStopImpl(SOURCE); private final Id DESTINATION_ID = Id.create(DESTINATION, PseudoRouteStop.class); @@ -120,8 +121,8 @@ private void runDijkstra() { for(Link l : stopPairLinks.get(getKey(stopA, stopB))) { networkLinkIds.add(l.getId()); - if(l instanceof ArtificialLink) { - artificialNetworkLinks.add((ArtificialLink) l); + if (l instanceof ArtificialLink al) { + artificialNetworkLinks.add(al); } } networkLinkIds.add(stopB.getLinkId()); diff --git a/src/main/java/org/matsim/pt2matsim/mapping/pseudoRouter/PseudoScheduleImpl.java b/src/main/java/org/matsim/pt2matsim/mapping/pseudoRouter/PseudoScheduleImpl.java index a6fe6550..64e079d0 100644 --- a/src/main/java/org/matsim/pt2matsim/mapping/pseudoRouter/PseudoScheduleImpl.java +++ b/src/main/java/org/matsim/pt2matsim/mapping/pseudoRouter/PseudoScheduleImpl.java @@ -25,7 +25,8 @@ import java.util.Map; import java.util.Set; -import org.apache.log4j.Logger; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.LogManager; import org.matsim.api.core.v01.Id; import org.matsim.api.core.v01.network.Link; import org.matsim.pt.transitSchedule.api.MinimalTransferTimes.MinimalTransferTimesIterator; @@ -66,7 +67,7 @@ public void createFacilitiesAndLinkSequences(TransitSchedule schedule) { Map, Set>> parentsToChildren = new HashMap<>(); - Logger logger = Logger.getLogger(PseudoScheduleImpl.class); + Logger logger = LogManager.getLogger(PseudoScheduleImpl.class); int totalNumber = pseudoSchedule.size(); int currentNumber = 0; diff --git a/src/main/java/org/matsim/pt2matsim/osm/OsmMultimodalNetworkConverter.java b/src/main/java/org/matsim/pt2matsim/osm/OsmMultimodalNetworkConverter.java index c82d1c88..ac5d16b6 100644 --- a/src/main/java/org/matsim/pt2matsim/osm/OsmMultimodalNetworkConverter.java +++ b/src/main/java/org/matsim/pt2matsim/osm/OsmMultimodalNetworkConverter.java @@ -21,13 +21,33 @@ package org.matsim.pt2matsim.osm; -import org.apache.log4j.Logger; +import java.io.IOException; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; + +import javax.annotation.Nullable; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.IdMap; import org.matsim.api.core.v01.TransportMode; import org.matsim.api.core.v01.network.Link; import org.matsim.api.core.v01.network.Network; import org.matsim.api.core.v01.network.Node; import org.matsim.core.config.ConfigGroup; +import org.matsim.core.network.DisallowedNextLinks; import org.matsim.core.network.NetworkUtils; import org.matsim.core.network.algorithms.NetworkCleaner; import org.matsim.core.utils.collections.CollectionUtils; @@ -42,10 +62,6 @@ import org.matsim.pt2matsim.osm.lib.OsmData; import org.matsim.pt2matsim.tools.NetworkTools; -import java.io.IOException; -import java.nio.file.Paths; -import java.util.*; - /** * Converts {@link OsmData} to a MATSim network, uses a config file * ({@link OsmConverterConfigGroup}) to store conversion parameters and default @@ -64,8 +80,32 @@ */ public class OsmMultimodalNetworkConverter { - private final static Logger log = Logger.getLogger(OsmMultimodalNetworkConverter.class); - + private static final Logger log = LogManager.getLogger(OsmMultimodalNetworkConverter.class); + + /** + * mode == null means "all modes" + */ + static record OsmTurnRestriction(Set modes, List> nextWayIds, RestrictionType restrictionType) { + + enum RestrictionType { + PROHIBITIVE, // no_* + MANDATORY; // only_* + } + + } + + private static final Map OSM_2_MATSIM_MODE_MAP = Map.of( + Osm.Key.BUS, "bus", + Osm.Key.BICYCLE, TransportMode.bike, + Osm.Key.MOTORCYCLE, TransportMode.motorcycle, + Osm.Key.MOTORCAR, TransportMode.car); + + private static final List TURN_RESTRICTION_KEY_SUFFIXES = List.of( + "", // for all modes + ":" + Osm.Key.BUS, + ":" + Osm.Key.BICYCLE, + ":" + Osm.Key.MOTORCAR); + static final int SPEED_LIMIT_WALK_KPH = 10; // // no speed limit (Germany) .. assume 200kph static final int SPEED_LIMIT_NONE_KPH = 200; @@ -84,6 +124,8 @@ public class OsmMultimodalNetworkConverter { * connects osm way ids and link ids of the generated network **/ protected final Map, Id> osmIds = new HashMap<>(); + protected final Map, List>> wayLinkMap = new HashMap<>(); // reverse of osmIds + protected final Map, DisallowedNextLinks> disallowedNextLinks = new IdMap<>(Link.class); protected OsmConverterConfigGroup config; protected Network network; protected long id = 0; @@ -110,6 +152,9 @@ public void convert(OsmConverterConfigGroup config) { readWayParams(); convertToNetwork(transformation); cleanNetwork(); + if (config.parseTurnRestrictions) { + addDisallowedNextLinksAttributes(); + } if(config.getKeepTagsAsAttributes()) addAttributes(); if (this.config.getOutputDetailedLinkGeometryFile() != null) { @@ -270,26 +315,33 @@ protected void convertToNetwork(CoordinateTransformation transformation) { } } + // create reverse lookup map for link ids + wayLinkMap.putAll(osmIds.entrySet().stream().collect( + Collectors.groupingBy(Entry::getValue, Collectors.mapping(Entry::getKey, Collectors.toList())))); + + // parse turn restriction relations into disallowed links + this.attachTurnRestrictionsAsDisallowedNextLinks(); + log.info("= conversion statistics: =========================="); - log.info("MATSim: # nodes created: " + this.network.getNodes().size()); - log.info("MATSim: # links created: " + this.network.getLinks().size()); + log.info("MATSim: # nodes created: {}", this.network.getNodes().size()); + log.info("MATSim: # links created: {}", this.network.getLinks().size()); - if(this.unknownHighways.size() > 0) { + if (!this.unknownHighways.isEmpty()) { log.info("The following highway-types had no defaults set and were thus NOT converted:"); for(String highwayType : this.unknownHighways) { - log.info("- \"" + highwayType + "\""); + log.info("- \"{}\"", highwayType); } } - if(this.unknownRailways.size() > 0) { + if (!this.unknownRailways.isEmpty()) { log.info("The following railway-types had no defaults set and were thus NOT converted:"); for(String railwayType : this.unknownRailways) { - log.info("- \"" + railwayType + "\""); + log.info("- \"{}\"", railwayType); } } - if(this.unknownWays.size() > 0) { + if (!this.unknownWays.isEmpty()) { log.info("The way-types with the following tags had no defaults set and were thus NOT converted:"); for(String wayType : this.unknownWays) { - log.info("- \"" + wayType + "\""); + log.info("- \"{}\"", wayType); } } log.info("= end of conversion statistics ===================="); @@ -367,7 +419,10 @@ protected void createLink(final Osm.Way way, final Osm.Node fromNode, final Osm. modes.add(TransportMode.pt); } } - + + // TURN RESTRICTIONS + List osmTurnRestrictions = this.parseTurnRestrictions(way, modes); + // LENGTH if (length == 0.0) { log.warn("Attempting to create a link of length 0.0, which will mess up the routing. Fixing to 1.0!"); @@ -388,6 +443,9 @@ protected void createLink(final Osm.Way way, final Osm.Node fromNode, final Osm. l.setCapacity(laneCountForward * laneCapacity); l.setNumberOfLanes(laneCountForward); l.setAllowedModes(modes); + if (config.parseTurnRestrictions) { + l.getAttributes().putAttribute(OsmTurnRestriction.class.getSimpleName(), osmTurnRestrictions); + } network.addLink(l); osmIds.put(l.getId(), way.getId()); @@ -403,6 +461,9 @@ protected void createLink(final Osm.Way way, final Osm.Node fromNode, final Osm. l.setCapacity(laneCountBackward * laneCapacity); l.setNumberOfLanes(laneCountBackward); l.setAllowedModes(modes); + if (config.parseTurnRestrictions) { + l.getAttributes().putAttribute(OsmTurnRestriction.class.getSimpleName(), osmTurnRestrictions); + } network.addLink(l); osmIds.put(l.getId(), way.getId()); @@ -458,7 +519,7 @@ else if(Osm.Value.WALK.equals(value)) { } catch (NumberFormatException e) { if(!unknownMaxspeedTags.contains(value)) { unknownMaxspeedTags.add(value); - log.warn("Could not parse '" + key + "': " + e.getMessage() + " (way " + way.getId() + ")"); + log.warn("Could not parse '{}': {} (way {})", key, e.getMessage(), way.getId()); } return Optional.empty(); } @@ -505,7 +566,7 @@ private Optional parseLanesValue(final Osm.Way way, String key) { } catch (NumberFormatException e) { if(!unknownLanesTags.contains(value)) { unknownLanesTags.add(value); - log.warn("Could not parse '" + key + "': " + e.getMessage() + " (way " + way.getId() + ")"); + log.warn("Could not parse '{}': {} (way {})", key, e.getMessage(), way.getId()); } return Optional.empty(); } @@ -585,6 +646,19 @@ protected OsmConverterConfigGroup.OsmWayParams getWayDefaultParams(Osm.Way way) return wayDefaults; } + /** + * Adds DisallowedNextLinks attributes to links. See {@link #addAttributes()} + * documentation as to why this cannot be done directly when creating the link. + */ + private void addDisallowedNextLinksAttributes() { + network.getLinks().values().forEach(link -> { + DisallowedNextLinks dnl = disallowedNextLinks.get(link.getId()); + if (dnl != null) { + NetworkUtils.setDisallowedNextLinks(link, dnl); + } + }); + } + /** * Adds attributes to the network link. Cannot be added directly upon link creation since we need to * clean the road network and attributes are not copied while filtering @@ -681,5 +755,187 @@ public Network getNetwork() { return this.network; } + // Turn Restrictions + + @Nullable + private List parseTurnRestrictions(final Osm.Way way, Set modes) { + + if (!config.parseTurnRestrictions) { + return null; + } + + List osmTurnRestrictions = new ArrayList<>(); + for (Osm.Relation relation : way.getRelations().values()) { + + Map relationTags = relation.getTags(); + + // we only consider this relation, if + // - it is a turn restriction relation and + // - this way is the "from" link + if (!(Osm.Key.RESTRICTION.equals(relationTags.get(Osm.Key.TYPE)) + && Osm.Value.FROM.equals(relation.getMemberRole(way)))) { + continue; + } + + // identify modes + Set restrictionModes = new HashSet<>(modes); + // remove except modes + String exceptModesString = relationTags.get(Osm.Key.EXCEPT); + if (exceptModesString != null) { + for (String exceptMode : exceptModesString.split(";")) { + String matsimExceptMode = OSM_2_MATSIM_MODE_MAP.getOrDefault(exceptMode, exceptMode); + modes.remove(matsimExceptMode); + } + } + + // identify restriction type and eventually add modes + OsmTurnRestriction.RestrictionType restrictionType = null; + for (String suffix : TURN_RESTRICTION_KEY_SUFFIXES) { + String restrictionTypeString = relationTags.get(Osm.Key.RESTRICTION + suffix); + if (restrictionTypeString != null) { + + // add restriction type + if (restrictionTypeString.startsWith(Osm.Key.PROHIBITORY_RESTRICTION_PREFIX)) { + restrictionType = OsmTurnRestriction.RestrictionType.PROHIBITIVE; + } else if (restrictionTypeString.startsWith(Osm.Key.MANDATORY_RESTRICTION_PREFIX)) { + restrictionType = OsmTurnRestriction.RestrictionType.MANDATORY; + } + + // add explicit modes, if + // - suffix specified it and + // - it is a MATSim mode + if (suffix.length() > 1) { + String mode = suffix.substring(1); + String matsimMode = OSM_2_MATSIM_MODE_MAP.get(mode); + if (matsimMode == null) { + // skip this, if not one of MATSim modes + restrictionType = null; + continue; + } + restrictionModes.add(matsimMode); + } + + break; // take first one + } + } + if (restrictionType == null) { + log.warn("Could not identify turn restriction relation: https://www.openstreetmap.org/relation/{}", + relation.getId()); + continue; + } + + // create intermediate turn restriction record + List> nextWayIds = new ArrayList<>(); + Id toWayId = null; + for (Osm.Element element : relation.getMembers()) { + if (element instanceof Osm.Way wayElement) { + if (Osm.Value.TO.equals(relation.getMemberRole(wayElement))) { + toWayId = wayElement.getId(); + } else if (Osm.Value.VIA.equals(relation.getMemberRole(wayElement))) { + nextWayIds.add(wayElement.getId()); + } + } + } + nextWayIds.add(toWayId); + osmTurnRestrictions.add(new OsmTurnRestriction(restrictionModes, nextWayIds, restrictionType)); + } + + return osmTurnRestrictions; + } + + private void attachTurnRestrictionsAsDisallowedNextLinks() { + + if (!config.parseTurnRestrictions) { + return; + } + + for (Link link : network.getLinks().values()) { + + // get turn restrictions + List osmTurnRestrictions = (List) link.getAttributes() + .getAttribute(OsmTurnRestriction.class.getSimpleName()); + if (osmTurnRestrictions == null) { + break; + } + + // create DisallowedNextLink + for (OsmTurnRestriction tr : osmTurnRestrictions) { + + // find next link ids from next way ids + List> nextLinkIds = findLinkIds(wayLinkMap, network, link.getToNode(), tr.nextWayIds); + if (nextLinkIds.size() == tr.nextWayIds.size()) { // found next link ids from this link's toNode + + // find link id lists to disallow + List>> disallowedNextLinkIdLists = new ArrayList<>(); + if (tr.restrictionType.equals(OsmTurnRestriction.RestrictionType.PROHIBITIVE)) { + disallowedNextLinkIdLists.add(nextLinkIds); + } else if (tr.restrictionType.equals(OsmTurnRestriction.RestrictionType.MANDATORY)) { + // we need to exclude all other links originating from fromWay's toNode + link.getToNode().getOutLinks().values().stream() + .map(Link::getId) + .filter(lId -> !lId.equals(nextLinkIds.get(0))) + .forEach(lId -> disallowedNextLinkIdLists.add(List.of(lId))); + } + + // attach DisallowedNextLinks objects + DisallowedNextLinks dnl = new DisallowedNextLinks(); + for (List> disallowedNextLinkIds : disallowedNextLinkIdLists) { + for (String mode : tr.modes) { + dnl.addDisallowedLinkSequence(mode, disallowedNextLinkIds); + } + } + disallowedNextLinks.put(link.getId(), dnl); + } + + } + + // remove attribute + link.getAttributes().removeAttribute(OsmTurnRestriction.class.getSimpleName()); + } + } + + // Statics + + /** + * Finds list of link ids starting from {@code lastNode} from list of OSM way + * ids. + * + * @param wayLinkMap + * @param network + * @param lastNode + * @param wayIds + * @return + */ + protected static List> findLinkIds(Map, List>> wayLinkMap, Network network, + Node lastNode, List> wayIds) { + + List> linkIds = new ArrayList<>(); + + int i = 0; + do { + Id wayId = wayIds.get(i); + // for every link id, that could stem from this way + List> linkIdCandidates = wayLinkMap.get(wayId); + if (linkIdCandidates == null) { + // requested way id has no link ids -> turn restriction is incomplete + return Collections.emptyList(); + } + for (Id linkIdCandidate : linkIdCandidates) { + if (lastNode.getId().equals(network.getLinks().get(linkIdCandidate).getFromNode().getId())) { + linkIds.add(linkIdCandidate); + i += 1; + lastNode = network.getLinks().get(linkIds.get(linkIds.size() - 1)).getToNode(); + break; + } + // try next link candidate + } + if (i == 0) { // no linkCandidate was fitting -> lastNode is not attached to way ids + return Collections.emptyList(); + } + } while (i < wayIds.size()); + + return linkIds; + } + } diff --git a/src/main/java/org/matsim/pt2matsim/osm/OsmTransitScheduleConverter.java b/src/main/java/org/matsim/pt2matsim/osm/OsmTransitScheduleConverter.java index e1f0b624..7302ab46 100644 --- a/src/main/java/org/matsim/pt2matsim/osm/OsmTransitScheduleConverter.java +++ b/src/main/java/org/matsim/pt2matsim/osm/OsmTransitScheduleConverter.java @@ -19,7 +19,8 @@ package org.matsim.pt2matsim.osm; -import org.apache.log4j.Logger; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.LogManager; import org.matsim.api.core.v01.Coord; import org.matsim.api.core.v01.Id; import org.matsim.api.core.v01.network.Link; @@ -44,7 +45,7 @@ */ public class OsmTransitScheduleConverter { - protected static final Logger log = Logger.getLogger(OsmTransitScheduleConverter.class); + protected static final Logger log = LogManager.getLogger(OsmTransitScheduleConverter.class); protected final OsmData osmData; @@ -235,7 +236,7 @@ protected TransitRoute createTransitRoute(Osm.Relation relation) { } } - NetworkRoute networkRoute = (linkSequenceForward.size() == 0 ? null : RouteUtils.createNetworkRoute(linkSequenceForward, null)); + NetworkRoute networkRoute = (linkSequenceForward.size() == 0 ? null : RouteUtils.createNetworkRoute(linkSequenceForward)); if(stopSequenceForward.size() == 0) { return null; diff --git a/src/main/java/org/matsim/pt2matsim/osm/lib/Osm.java b/src/main/java/org/matsim/pt2matsim/osm/lib/Osm.java index 43afe9cb..9b8ec62b 100644 --- a/src/main/java/org/matsim/pt2matsim/osm/lib/Osm.java +++ b/src/main/java/org/matsim/pt2matsim/osm/lib/Osm.java @@ -95,7 +95,7 @@ public interface Way extends Element, Identifiable { List getNodes(); /** - * @return the relations of which this node is a member + * @return the relations of which this way is a member */ Map, Relation> getRelations(); } @@ -113,7 +113,7 @@ public interface Relation extends Element, Identifiable { String getMemberRole(Element member); /** - * @return the relations of which this node is a member + * @return the relations of which this relation is a member */ Map, Relation> getRelations(); } @@ -133,17 +133,24 @@ public static final class Key { public static final String HIGHWAY = "highway"; public static final String SERVICE = "service"; - public final static String LANES = "lanes"; - public final static String MAXSPEED = "maxspeed"; - public final static String JUNCTION = "junction"; - public final static String ONEWAY = "oneway"; - public final static String ACCESS = "access"; + public static final String LANES = "lanes"; + public static final String MAXSPEED = "maxspeed"; + public static final String JUNCTION = "junction"; + public static final String ONEWAY = "oneway"; + public static final String ACCESS = "access"; public static final String PSV = "psv"; public static final String BUS = "bus"; public static final String TAXI = "taxi"; - public final static String FORWARD = "forward"; - public final static String BACKWARD = "backward"; + public static final String FORWARD = "forward"; + public static final String BACKWARD = "backward"; + + public static final String RESTRICTION = "restriction"; + public static final String PROHIBITORY_RESTRICTION_PREFIX = "no_"; + public static final String MANDATORY_RESTRICTION_PREFIX = "only_"; + public static final String EXCEPT = "except"; + public static final String MOTORCAR = "motorcar"; + public static final String BICYCLE = "bicycle"; // rarely used public static final String TYPE = "type"; @@ -195,9 +202,9 @@ public static final class Value { public static final String RESIDENTIAL = "residential"; public static final String LIVING_STREET = "living_street"; public static final String SERVICE = "service"; - public final static String STOP_POSITION = "stop_position"; - public final static String BUS = "bus"; - public final static String TROLLEYBUS = "trolleybus"; + public static final String STOP_POSITION = "stop_position"; + public static final String BUS = "bus"; + public static final String TROLLEYBUS = "trolleybus"; public static final String FERRY = "ferry"; @@ -217,6 +224,12 @@ public static final class Value { // values for maxspeed=* public static final String WALK = "walk"; public static final String NONE = "none"; + + // turn restriction roles + public static final String FROM = "from"; + public static final String VIA = "via"; + public static final String TO = "to"; + } diff --git a/src/main/java/org/matsim/pt2matsim/osm/lib/OsmDataImpl.java b/src/main/java/org/matsim/pt2matsim/osm/lib/OsmDataImpl.java index 71762efd..d587c2d1 100644 --- a/src/main/java/org/matsim/pt2matsim/osm/lib/OsmDataImpl.java +++ b/src/main/java/org/matsim/pt2matsim/osm/lib/OsmDataImpl.java @@ -18,7 +18,8 @@ package org.matsim.pt2matsim.osm.lib; -import org.apache.log4j.Logger; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.LogManager; import org.matsim.api.core.v01.Id; import org.matsim.core.utils.misc.Counter; @@ -29,7 +30,7 @@ */ public class OsmDataImpl implements OsmData { - private final static Logger log = Logger.getLogger(OsmData.class); + private static final Logger log = LogManager.getLogger(OsmData.class); protected final Map, Osm.Node> nodes = new HashMap<>(); protected final Map, Osm.Way> ways = new HashMap<>(); @@ -130,14 +131,14 @@ public void buildMap() { // add relations to nodes/ways/relations for(Osm.Element e : memberList) { - if(e instanceof OsmElement.Node) { - ((OsmElement.Node) e).addRelation(currentRel); + if (e instanceof OsmElement.Node n) { + n.addRelation(currentRel); } - if(e instanceof OsmElement.Way) { - ((OsmElement.Way) e).addRelation(currentRel); + if (e instanceof OsmElement.Way w) { + w.addRelation(currentRel); } - if(e instanceof OsmElement.Relation) { - ((OsmElement.Relation) e).addRelation(currentRel); + if (e instanceof OsmElement.Relation r) { + r.addRelation(currentRel); } } } @@ -186,14 +187,14 @@ public void removeRelation(Id id) { Osm.Relation rel = relations.get(id); for(Osm.Element e : rel.getMembers()) { - if(e instanceof OsmElement.Node) { - ((OsmElement.Node) e).getRelations().remove(rel.getId()); + if (e instanceof OsmElement.Node n) { + n.getRelations().remove(rel.getId()); } - if(e instanceof OsmElement.Way) { - ((OsmElement.Way) e).getRelations().remove(rel.getId()); + if (e instanceof OsmElement.Way w) { + w.getRelations().remove(rel.getId()); } - if(e instanceof OsmElement.Relation) { - ((OsmElement.Relation) e).getRelations().remove(rel.getId()); + if (e instanceof OsmElement.Relation r) { + r.getRelations().remove(rel.getId()); } } removeMemberFromRelations(rel); @@ -202,14 +203,14 @@ public void removeRelation(Id id) { private void removeMemberFromRelations(Osm.Element e) { Collection memberOfRelations = null; - if(e instanceof Osm.Node) { - memberOfRelations = ((Osm.Node) e).getRelations().values(); + if (e instanceof Osm.Node n) { + memberOfRelations = n.getRelations().values(); } - else if(e instanceof Osm.Way) { - memberOfRelations = ((Osm.Way) e).getRelations().values(); + else if (e instanceof Osm.Way w) { + memberOfRelations = w.getRelations().values(); } - else if(e instanceof Osm.Relation) { - memberOfRelations = ((Osm.Relation) e).getRelations().values(); + else if (e instanceof Osm.Relation r) { + memberOfRelations = r.getRelations().values(); } assert memberOfRelations != null; diff --git a/src/main/java/org/matsim/pt2matsim/osm/lib/OsmFileReader.java b/src/main/java/org/matsim/pt2matsim/osm/lib/OsmFileReader.java index 58103754..b2d84363 100644 --- a/src/main/java/org/matsim/pt2matsim/osm/lib/OsmFileReader.java +++ b/src/main/java/org/matsim/pt2matsim/osm/lib/OsmFileReader.java @@ -40,7 +40,7 @@ public class OsmFileReader extends MatsimXmlParser { private ParsedRelation currentRelation = null; public OsmFileReader(OsmData osmData) { - super(); + super(ValidationType.DTD_OR_XSD); this.osmData = osmData; this.setValidating(false); } diff --git a/src/main/java/org/matsim/pt2matsim/plausibility/MappingAnalysis.java b/src/main/java/org/matsim/pt2matsim/plausibility/MappingAnalysis.java index bfe54b03..a1eaaadc 100644 --- a/src/main/java/org/matsim/pt2matsim/plausibility/MappingAnalysis.java +++ b/src/main/java/org/matsim/pt2matsim/plausibility/MappingAnalysis.java @@ -18,7 +18,8 @@ package org.matsim.pt2matsim.plausibility; -import org.apache.log4j.Logger; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.LogManager; import org.matsim.api.core.v01.Coord; import org.matsim.api.core.v01.Id; import org.matsim.api.core.v01.network.Link; @@ -49,7 +50,7 @@ public class MappingAnalysis { private static final double MEASURE_INTERVAL = 1; - private static final Logger log = Logger.getLogger(MappingAnalysis.class); + private static final Logger log = LogManager.getLogger(MappingAnalysis.class); private final TransitSchedule schedule; private final Map, RouteShape> shapes; private final Network network; diff --git a/src/main/java/org/matsim/pt2matsim/plausibility/PlausibilityCheck.java b/src/main/java/org/matsim/pt2matsim/plausibility/PlausibilityCheck.java index 2a14de30..e5196324 100644 --- a/src/main/java/org/matsim/pt2matsim/plausibility/PlausibilityCheck.java +++ b/src/main/java/org/matsim/pt2matsim/plausibility/PlausibilityCheck.java @@ -18,8 +18,10 @@ package org.matsim.pt2matsim.plausibility; -import org.apache.log4j.Level; -import org.apache.log4j.Logger; +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.core.config.Configurator; +import org.apache.logging.log4j.LogManager; import org.geojson.Feature; import org.geojson.FeatureCollection; import org.matsim.api.core.v01.Id; @@ -63,7 +65,7 @@ */ public class PlausibilityCheck { - protected static final Logger log = Logger.getLogger(PlausibilityCheck.class); + protected static final Logger log = LogManager.getLogger(PlausibilityCheck.class); public static final String CsvSeparator = ","; @@ -509,12 +511,12 @@ private void addWarningToContainers(PlausibilityWarning warning) { } public static void setLogLevels() { - Logger.getLogger(MGC.class).setLevel(Level.ERROR); - Logger.getLogger(MatsimFileTypeGuesser.class).setLevel(Level.ERROR); - Logger.getLogger(Network.class).setLevel(Level.ERROR); - Logger.getLogger(Node.class).setLevel(Level.ERROR); - Logger.getLogger(Link.class).setLevel(Level.ERROR); - Logger.getLogger(MatsimXmlParser.class).setLevel(Level.ERROR); + Configurator.setLevel(LogManager.getLogger(MGC.class).getName(), Level.ERROR); + Configurator.setLevel(LogManager.getLogger(MatsimFileTypeGuesser.class).getName(), Level.ERROR); + Configurator.setLevel(LogManager.getLogger(Network.class).getName(), Level.ERROR); + Configurator.setLevel(LogManager.getLogger(Node.class).getName(), Level.ERROR); + Configurator.setLevel(LogManager.getLogger(Link.class).getName(), Level.ERROR); + Configurator.setLevel(LogManager.getLogger(MatsimXmlParser.class).getName(), Level.ERROR); } public Map> getWarnings() { diff --git a/src/main/java/org/matsim/pt2matsim/run/CheckMappedSchedulePlausibility.java b/src/main/java/org/matsim/pt2matsim/run/CheckMappedSchedulePlausibility.java index 0412bb98..fc932086 100644 --- a/src/main/java/org/matsim/pt2matsim/run/CheckMappedSchedulePlausibility.java +++ b/src/main/java/org/matsim/pt2matsim/run/CheckMappedSchedulePlausibility.java @@ -18,7 +18,8 @@ package org.matsim.pt2matsim.run; -import org.apache.log4j.Logger; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.LogManager; import org.matsim.api.core.v01.network.Network; import org.matsim.core.utils.geometry.geotools.MGC; import org.matsim.pt.transitSchedule.api.TransitSchedule; @@ -37,7 +38,7 @@ */ public final class CheckMappedSchedulePlausibility { - protected static final Logger log = Logger.getLogger(PlausibilityCheck.class); + protected static final Logger log = LogManager.getLogger(PlausibilityCheck.class); /** * Performs a plausibility check on the given schedule and network files diff --git a/src/main/java/org/matsim/pt2matsim/run/Gtfs2TransitSchedule.java b/src/main/java/org/matsim/pt2matsim/run/Gtfs2TransitSchedule.java index 802c6541..9d01c9d4 100644 --- a/src/main/java/org/matsim/pt2matsim/run/Gtfs2TransitSchedule.java +++ b/src/main/java/org/matsim/pt2matsim/run/Gtfs2TransitSchedule.java @@ -18,8 +18,10 @@ package org.matsim.pt2matsim.run; -import org.apache.log4j.Level; -import org.apache.log4j.Logger; +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.core.config.Configurator; +import org.apache.logging.log4j.LogManager; import org.matsim.api.core.v01.Id; import org.matsim.core.utils.geometry.geotools.MGC; import org.matsim.core.utils.io.IOUtils; @@ -47,7 +49,7 @@ */ public final class Gtfs2TransitSchedule { - protected static Logger log = Logger.getLogger(Gtfs2TransitSchedule.class); + protected static Logger log = LogManager.getLogger(Gtfs2TransitSchedule.class); private static final String INFO_OUTPUT_OPTION_SCHEDULE = "schedule"; @@ -112,7 +114,7 @@ public static void main(final String[] args) { * */ public static void run(String gtfsFolder, String sampleDayParam, String outputCoordinateSystem, String scheduleFile, String vehicleFile, String additionalLineInfoFile) { - Logger.getLogger(MGC.class).setLevel(Level.ERROR); + Configurator.setLevel(LogManager.getLogger(MGC.class).getName(), Level.ERROR); // check sample day parameter if(!isValidSampleDayParam(sampleDayParam)) { diff --git a/src/main/java/org/matsim/pt2matsim/run/PublicTransitMapper.java b/src/main/java/org/matsim/pt2matsim/run/PublicTransitMapper.java index 2e744a6b..c4a830a2 100644 --- a/src/main/java/org/matsim/pt2matsim/run/PublicTransitMapper.java +++ b/src/main/java/org/matsim/pt2matsim/run/PublicTransitMapper.java @@ -21,7 +21,8 @@ package org.matsim.pt2matsim.run; -import org.apache.log4j.Logger; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.LogManager; import org.matsim.api.core.v01.TransportMode; import org.matsim.api.core.v01.network.Network; import org.matsim.pt.transitSchedule.api.TransitSchedule; @@ -43,7 +44,7 @@ */ public final class PublicTransitMapper { - protected static Logger log = Logger.getLogger(PublicTransitMapper.class); + protected static Logger log = LogManager.getLogger(PublicTransitMapper.class); private PublicTransitMapper() { } diff --git a/src/main/java/org/matsim/pt2matsim/run/gis/Network2Geojson.java b/src/main/java/org/matsim/pt2matsim/run/gis/Network2Geojson.java index 4237d1d2..e57c68e7 100644 --- a/src/main/java/org/matsim/pt2matsim/run/gis/Network2Geojson.java +++ b/src/main/java/org/matsim/pt2matsim/run/gis/Network2Geojson.java @@ -18,7 +18,8 @@ package org.matsim.pt2matsim.run.gis; -import org.apache.log4j.Logger; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.LogManager; import org.geojson.Feature; import org.geojson.FeatureCollection; import org.matsim.api.core.v01.Coord; @@ -80,7 +81,7 @@ public static void run(String networkCoordSys, Network network, String networkOu } - protected static Logger log = Logger.getLogger(Network2Geojson.class); + protected static Logger log = LogManager.getLogger(Network2Geojson.class); private final CoordinateTransformation ct; private Network network; private FeatureCollection linkFeatures = new FeatureCollection(); diff --git a/src/main/java/org/matsim/pt2matsim/run/gis/Network2ShapeFile.java b/src/main/java/org/matsim/pt2matsim/run/gis/Network2ShapeFile.java index 8d9bd412..9acf3cb1 100644 --- a/src/main/java/org/matsim/pt2matsim/run/gis/Network2ShapeFile.java +++ b/src/main/java/org/matsim/pt2matsim/run/gis/Network2ShapeFile.java @@ -24,9 +24,9 @@ import org.matsim.api.core.v01.network.Node; import org.matsim.core.utils.collections.CollectionUtils; import org.matsim.core.utils.geometry.geotools.MGC; +import org.matsim.core.utils.gis.GeoFileWriter; import org.matsim.core.utils.gis.PointFeatureFactory; import org.matsim.core.utils.gis.PolylineFeatureFactory; -import org.matsim.core.utils.gis.ShapeFileWriter; import org.matsim.pt2matsim.tools.NetworkTools; import org.opengis.feature.simple.SimpleFeature; @@ -94,7 +94,7 @@ public void convertNodes(String nodesOutputFile) { nodeFeatures.add(f); } - ShapeFileWriter.writeGeometries(nodeFeatures, nodesOutputFile); + GeoFileWriter.writeGeometries(nodeFeatures, nodesOutputFile); } public void convertLinks(String linksOutputFile) { @@ -125,7 +125,7 @@ public void convertLinks(String linksOutputFile) { linkFeatures.add(f); } - ShapeFileWriter.writeGeometries(linkFeatures, linksOutputFile); + GeoFileWriter.writeGeometries(linkFeatures, linksOutputFile); } private Coordinate[] getCoordinates(Link link) { diff --git a/src/main/java/org/matsim/pt2matsim/run/gis/Schedule2Geojson.java b/src/main/java/org/matsim/pt2matsim/run/gis/Schedule2Geojson.java index 1d6ca188..1518cd2b 100644 --- a/src/main/java/org/matsim/pt2matsim/run/gis/Schedule2Geojson.java +++ b/src/main/java/org/matsim/pt2matsim/run/gis/Schedule2Geojson.java @@ -18,7 +18,8 @@ package org.matsim.pt2matsim.run.gis; -import org.apache.log4j.Logger; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.LogManager; import org.geojson.Feature; import org.geojson.FeatureCollection; import org.matsim.api.core.v01.Coord; @@ -92,7 +93,7 @@ public static void run(String crs, TransitSchedule schedule, Network network, St s2s.writeSchedule(outputFile); } - private static final Logger log = Logger.getLogger(Schedule2Geojson.class); + private static final Logger log = LogManager.getLogger(Schedule2Geojson.class); private final TransitSchedule schedule; private final Network network; private final CoordinateTransformation ct; diff --git a/src/main/java/org/matsim/pt2matsim/run/gis/Schedule2ShapeFile.java b/src/main/java/org/matsim/pt2matsim/run/gis/Schedule2ShapeFile.java index 1aa27910..8a1e5981 100644 --- a/src/main/java/org/matsim/pt2matsim/run/gis/Schedule2ShapeFile.java +++ b/src/main/java/org/matsim/pt2matsim/run/gis/Schedule2ShapeFile.java @@ -19,16 +19,17 @@ package org.matsim.pt2matsim.run.gis; import org.locationtech.jts.geom.Coordinate; -import org.apache.log4j.Logger; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.LogManager; import org.matsim.api.core.v01.Id; import org.matsim.api.core.v01.network.Link; import org.matsim.api.core.v01.network.Network; import org.matsim.core.utils.collections.CollectionUtils; import org.matsim.core.utils.collections.MapUtils; import org.matsim.core.utils.geometry.geotools.MGC; +import org.matsim.core.utils.gis.GeoFileWriter; import org.matsim.core.utils.gis.PointFeatureFactory; import org.matsim.core.utils.gis.PolylineFeatureFactory; -import org.matsim.core.utils.gis.ShapeFileWriter; import org.matsim.pt.transitSchedule.api.*; import org.matsim.pt2matsim.tools.NetworkTools; import org.matsim.pt2matsim.tools.ScheduleTools; @@ -43,7 +44,7 @@ */ public class Schedule2ShapeFile { - private static final Logger log = Logger.getLogger(Schedule2ShapeFile.class); + private static final Logger log = LogManager.getLogger(Schedule2ShapeFile.class); private final TransitSchedule schedule; private final Network network; private final String crs; @@ -143,7 +144,7 @@ public void stopRefLinks2Polylines(String outputFile) { } } - ShapeFileWriter.writeGeometries(lineFeatures, outputFile); + GeoFileWriter.writeGeometries(lineFeatures, outputFile); } @@ -180,7 +181,7 @@ public void stopFacilities2Points(String pointOutputFile) { pointFeatures.add(pf); } - ShapeFileWriter.writeGeometries(pointFeatures, pointOutputFile); + GeoFileWriter.writeGeometries(pointFeatures, pointOutputFile); } /** @@ -228,7 +229,7 @@ public void routes2Polylines(String outputFile, boolean useNetworkLinks) { } } - ShapeFileWriter.writeGeometries(features, outputFile); + GeoFileWriter.writeGeometries(features, outputFile); } /** diff --git a/src/main/java/org/matsim/pt2matsim/tools/CoordTools.java b/src/main/java/org/matsim/pt2matsim/tools/CoordTools.java index 9a7d62ac..f2b14071 100644 --- a/src/main/java/org/matsim/pt2matsim/tools/CoordTools.java +++ b/src/main/java/org/matsim/pt2matsim/tools/CoordTools.java @@ -269,6 +269,7 @@ public static Map getStopsInAreaBool(TransitSchedu * * @deprecated not used anywhere */ + @Deprecated public static int getBorderCrossType(Coord SWcut, Coord NEcut, Coord fromCoord, Coord toCoord) { int fromSector = getAreaOfInterestSector(SWcut, NEcut, fromCoord); int toSector = getAreaOfInterestSector(SWcut, NEcut, toCoord); diff --git a/src/main/java/org/matsim/pt2matsim/tools/CsvTools.java b/src/main/java/org/matsim/pt2matsim/tools/CsvTools.java index 60b03708..29258185 100644 --- a/src/main/java/org/matsim/pt2matsim/tools/CsvTools.java +++ b/src/main/java/org/matsim/pt2matsim/tools/CsvTools.java @@ -20,6 +20,8 @@ package org.matsim.pt2matsim.tools; import com.opencsv.CSVReader; +import com.opencsv.exceptions.CsvValidationException; + import org.matsim.core.utils.collections.MapUtils; import org.matsim.core.utils.collections.Tuple; @@ -142,15 +144,16 @@ public static void writeNestedMapToFile(Object[] header, Map> readNestedMapFromFile(String fileName, boolean ignoreFirstLine) throws IOException { Map> map = new HashMap<>(); - - CSVReader reader = new CSVReader(new FileReader(fileName)); - if(ignoreFirstLine) reader.readNext(); - String[] line = reader.readNext(); - while(line != null) { - MapUtils.getMap(line[0], map).put(line[1], line[2]); - line = reader.readNext(); + try(CSVReader reader = new CSVReader(new FileReader(fileName))) { + if(ignoreFirstLine) reader.readNext(); + String[] line = reader.readNext(); + while(line != null) { + MapUtils.getMap(line[0], map).put(line[1], line[2]); + line = reader.readNext(); + } + } catch (CsvValidationException e) { + throw new RuntimeException(e); } - reader.close(); return map; } diff --git a/src/main/java/org/matsim/pt2matsim/tools/GtfsTools.java b/src/main/java/org/matsim/pt2matsim/tools/GtfsTools.java index 0ea38f21..409873f2 100644 --- a/src/main/java/org/matsim/pt2matsim/tools/GtfsTools.java +++ b/src/main/java/org/matsim/pt2matsim/tools/GtfsTools.java @@ -137,7 +137,7 @@ public static Map> getTripsOndates(GtfsFeed feed) { * usually the largest file. */ public static void writeStopTimes(Collection trips, String folder) throws IOException { - CSVWriter stopTimesWriter = new CSVWriter(new FileWriter(folder + GtfsDefinitions.Files.STOP_TIMES.fileName), ','); + CSVWriter stopTimesWriter = new CSVWriter(new FileWriter(folder + GtfsDefinitions.Files.STOP_TIMES.fileName)); String[] header = GtfsDefinitions.Files.STOP_TIMES.columns; stopTimesWriter.writeNext(header, true); @@ -161,7 +161,7 @@ public static void writeStopTimes(Collection trips, String folder) throws * Experimental class to write stops.txt (i.e. after filtering for one date) */ public static void writeStops(Collection stops, String path) throws IOException { - CSVWriter stopsWriter = new CSVWriter(new FileWriter(path + GtfsDefinitions.Files.STOPS.fileName), ','); + CSVWriter stopsWriter = new CSVWriter(new FileWriter(path + GtfsDefinitions.Files.STOPS.fileName)); String[] header = GtfsDefinitions.Files.STOPS.columns; stopsWriter.writeNext(header, true); for(Stop stop : stops) { @@ -180,7 +180,7 @@ public static void writeStops(Collection stops, String path) throws IOExce * Experimental class to write trips.txt (i.e. after filtering for one date) */ public static void writeTrips(Collection trips, String path) throws IOException { - CSVWriter tripsWriter = new CSVWriter(new FileWriter(path + GtfsDefinitions.Files.TRIPS.fileName), ','); + CSVWriter tripsWriter = new CSVWriter(new FileWriter(path + GtfsDefinitions.Files.TRIPS.fileName)); String[] header = GtfsDefinitions.Files.TRIPS.columns; tripsWriter.writeNext(header, true); for(Trip trip : trips) { @@ -198,7 +198,7 @@ public static void writeTrips(Collection trips, String path) throws IOExce * Experimental class to write transfers.txt (i.e. after creating additional walk transfer) */ public static void writeTransfers(Collection transfers, String path) throws IOException { - CSVWriter transfersWiter = new CSVWriter(new FileWriter(path + GtfsDefinitions.Files.TRANSFERS.fileName), ','); + CSVWriter transfersWiter = new CSVWriter(new FileWriter(path + GtfsDefinitions.Files.TRANSFERS.fileName)); String[] columns = GtfsDefinitions.Files.TRANSFERS.columns; String[] optionalColumns = GtfsDefinitions.Files.TRANSFERS.optionalColumns; String[] header = Stream.concat(Arrays.stream(columns), Arrays.stream(optionalColumns)).toArray(String[]::new); diff --git a/src/main/java/org/matsim/pt2matsim/tools/NetworkTools.java b/src/main/java/org/matsim/pt2matsim/tools/NetworkTools.java index c590cf6a..a4c1a7df 100644 --- a/src/main/java/org/matsim/pt2matsim/tools/NetworkTools.java +++ b/src/main/java/org/matsim/pt2matsim/tools/NetworkTools.java @@ -18,7 +18,8 @@ package org.matsim.pt2matsim.tools; -import org.apache.log4j.Logger; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.LogManager; import org.matsim.api.core.v01.Coord; import org.matsim.api.core.v01.Id; import org.matsim.api.core.v01.TransportMode; @@ -26,6 +27,7 @@ import org.matsim.api.core.v01.network.Network; import org.matsim.api.core.v01.network.NetworkFactory; import org.matsim.api.core.v01.network.Node; +import org.matsim.core.config.groups.NetworkConfigGroup; import org.matsim.core.network.NetworkUtils; import org.matsim.core.network.algorithms.NetworkTransform; import org.matsim.core.network.filter.NetworkFilterManager; @@ -53,7 +55,7 @@ */ public final class NetworkTools { - protected static Logger log = Logger.getLogger(NetworkTools.class); + protected static Logger log = LogManager.getLogger(NetworkTools.class); private NetworkTools() {} @@ -180,7 +182,10 @@ public static Map> findClosestLinks(Network network, Coord coo * For opposite links, the link which has the coordinate on its right side is sorted "closer" to the coordinate. * If more than two links have the exact same distance, links are sorted by distance to their respective closest node. * After that, behaviour is undefined. + * + * @deprecated See https://github.com/matsim-org/pt2matsim/issues/199 */ + @Deprecated(since = "23.10-SNAPSHOT") public static List findClosestLinksSorted(Network network, Coord coord, double nodeSearchRadius, Set allowedTransportModes) { List links = new ArrayList<>(); Map> sortedLinks = findClosestLinks(network, coord, nodeSearchRadius, allowedTransportModes); @@ -201,7 +206,7 @@ public static List findClosestLinksSorted(Network network, Coord coord, do Map tmp = new HashMap<>(); for(Link l : list) { double fromNodeDist = CoordUtils.calcEuclideanDistance(l.getFromNode().getCoord(), coord); - double toNodeDist = CoordUtils.calcEuclideanDistance(l.getFromNode().getCoord(), coord); + double toNodeDist = CoordUtils.calcEuclideanDistance(l.getToNode().getCoord(), coord); double nodeDist = fromNodeDist < toNodeDist ? fromNodeDist : toNodeDist; double d = nodeDist + (coordIsOnRightSideOfLink(coord, l) ? 1 : 100); @@ -225,7 +230,7 @@ public static List findClosestLinksSorted(Network network, Coord coord, do * @return the filtered new network */ public static Network createFilteredNetworkByLinkMode(Network network, Set transportModes) { - NetworkFilterManager filterManager = new NetworkFilterManager(network); + NetworkFilterManager filterManager = new NetworkFilterManager(network, new NetworkConfigGroup()); filterManager.addLinkFilter(new LinkFilter(transportModes)); Network newNetwork = filterManager.applyFilters(); removeNotUsedNodes(newNetwork); @@ -233,7 +238,7 @@ public static Network createFilteredNetworkByLinkMode(Network network, Set transportModes) { - NetworkFilterManager filterManager = new NetworkFilterManager(network); + NetworkFilterManager filterManager = new NetworkFilterManager(network, new NetworkConfigGroup()); filterManager.addLinkFilter(new InverseLinkFilter(transportModes)); return filterManager.applyFilters(); } diff --git a/src/main/java/org/matsim/pt2matsim/tools/PTMapperTools.java b/src/main/java/org/matsim/pt2matsim/tools/PTMapperTools.java index 91e309f4..9f889024 100644 --- a/src/main/java/org/matsim/pt2matsim/tools/PTMapperTools.java +++ b/src/main/java/org/matsim/pt2matsim/tools/PTMapperTools.java @@ -18,8 +18,10 @@ package org.matsim.pt2matsim.tools; -import org.apache.log4j.Level; -import org.apache.log4j.Logger; +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.core.config.Configurator; +import org.apache.logging.log4j.LogManager; import org.matsim.api.core.v01.Coord; import org.matsim.api.core.v01.Id; import org.matsim.api.core.v01.network.Link; @@ -45,7 +47,7 @@ */ public final class PTMapperTools { - protected static Logger log = Logger.getLogger(PTMapperTools.class); + protected static Logger log = LogManager.getLogger(PTMapperTools.class); private PTMapperTools() { } @@ -208,13 +210,13 @@ private static Id useCloserRefLinkForChildStopFacility(TransitSchedule sch } public static void setLogLevels() { - Logger.getLogger(org.matsim.core.router.Dijkstra.class).setLevel(Level.ERROR); // suppress no route found warnings - Logger.getLogger(Network.class).setLevel(Level.WARN); - Logger.getLogger(org.matsim.core.network.filter.NetworkFilterManager.class).setLevel(Level.WARN); - Logger.getLogger(org.matsim.core.router.util.PreProcessDijkstra.class).setLevel(Level.WARN); - Logger.getLogger(org.matsim.core.router.util.PreProcessDijkstra.class).setLevel(Level.WARN); - Logger.getLogger(org.matsim.core.router.util.PreProcessEuclidean.class).setLevel(Level.WARN); - Logger.getLogger(org.matsim.core.router.util.PreProcessLandmarks.class).setLevel(Level.WARN); + Configurator.setLevel(LogManager.getLogger(org.matsim.core.router.Dijkstra.class).getName(), Level.ERROR); // suppress no route found warnings + Configurator.setLevel(LogManager.getLogger(Network.class).getName(), Level.WARN); + Configurator.setLevel(LogManager.getLogger(org.matsim.core.network.filter.NetworkFilterManager.class).getName(), Level.WARN); + Configurator.setLevel(LogManager.getLogger(org.matsim.core.router.util.PreProcessDijkstra.class).getName(), Level.WARN); + Configurator.setLevel(LogManager.getLogger(org.matsim.core.router.util.PreProcessDijkstra.class).getName(), Level.WARN); + Configurator.setLevel(LogManager.getLogger(org.matsim.core.router.util.PreProcessEuclidean.class).getName(), Level.WARN); + Configurator.setLevel(LogManager.getLogger(org.matsim.core.router.util.PreProcessLandmarks.class).getName(), Level.WARN); } /** diff --git a/src/main/java/org/matsim/pt2matsim/tools/ScheduleTools.java b/src/main/java/org/matsim/pt2matsim/tools/ScheduleTools.java index ce561f3d..88f55eb8 100644 --- a/src/main/java/org/matsim/pt2matsim/tools/ScheduleTools.java +++ b/src/main/java/org/matsim/pt2matsim/tools/ScheduleTools.java @@ -18,7 +18,8 @@ package org.matsim.pt2matsim.tools; -import org.apache.log4j.Logger; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.LogManager; import org.matsim.api.core.v01.Id; import org.matsim.api.core.v01.Scenario; import org.matsim.api.core.v01.TransportMode; @@ -49,7 +50,7 @@ */ public final class ScheduleTools { - protected static Logger log = Logger.getLogger(ScheduleTools.class); + protected static Logger log = LogManager.getLogger(ScheduleTools.class); private ScheduleTools() {} @@ -204,10 +205,11 @@ public static VehicleType createDefaultVehicleType(String id, String defaultVehi VehicleType vehicleType = vf.createVehicleType(vTypeId); vehicleType.setLength(defaultValues.length); vehicleType.setWidth(defaultValues.width); - vehicleType.setAccessTime(defaultValues.accessTime); - vehicleType.setEgressTime(defaultValues.egressTime); - vehicleType.setDoorOperationMode(defaultValues.doorOperation); + VehicleUtils.setAccessTime(vehicleType, defaultValues.accessTime); + VehicleUtils.setEgressTime(vehicleType, defaultValues.egressTime); + VehicleUtils.setDoorOperationMode(vehicleType, defaultValues.doorOperation); vehicleType.setPcuEquivalents(defaultValues.pcuEquivalents); + vehicleType.setNetworkMode(defaultValues.transportMode.name); VehicleCapacity capacity = vehicleType.getCapacity(); capacity.setSeats(defaultValues.capacitySeats); @@ -315,7 +317,7 @@ public static void routeSchedule(TransitSchedule schedule, Network network, Sche // add link sequence to schedule if(linkIdSequence != null) { - transitRoute.setRoute(RouteUtils.createNetworkRoute(linkIdSequence, network)); + transitRoute.setRoute(RouteUtils.createNetworkRoute(linkIdSequence)); } } else { log.warn("Route " + transitRoute.getId() + " on line " + transitLine.getId() + " has no stop sequence"); diff --git a/src/main/java/org/matsim/pt2matsim/tools/ShapeTools.java b/src/main/java/org/matsim/pt2matsim/tools/ShapeTools.java index c30aec90..00e1b416 100644 --- a/src/main/java/org/matsim/pt2matsim/tools/ShapeTools.java +++ b/src/main/java/org/matsim/pt2matsim/tools/ShapeTools.java @@ -19,6 +19,8 @@ package org.matsim.pt2matsim.tools; import com.opencsv.CSVReader; +import com.opencsv.exceptions.CsvValidationException; + import org.locationtech.jts.geom.Coordinate; import org.matsim.api.core.v01.Coord; import org.matsim.api.core.v01.Id; @@ -30,8 +32,8 @@ import org.matsim.core.utils.geometry.CoordinateTransformation; import org.matsim.core.utils.geometry.geotools.MGC; import org.matsim.core.utils.geometry.transformations.TransformationFactory; +import org.matsim.core.utils.gis.GeoFileWriter; import org.matsim.core.utils.gis.PolylineFeatureFactory; -import org.matsim.core.utils.gis.ShapeFileWriter; import org.matsim.pt2matsim.gtfs.GtfsFeed; import org.matsim.pt2matsim.gtfs.GtfsFeedImpl; import org.matsim.pt2matsim.gtfs.lib.GtfsDefinitions; @@ -226,7 +228,7 @@ public static void writeGtfsTripsToFile(GtfsFeed gtfsFeed, Set serviceId } } } - ShapeFileWriter.writeGeometries(features, outFile); + GeoFileWriter.writeGeometries(features, outFile); } /** @@ -255,7 +257,7 @@ public static void writeESRIShapeFile(Collection shapes, S features.add(f); } } - ShapeFileWriter.writeGeometries(features, filename); + GeoFileWriter.writeGeometries(features, filename); } @@ -263,9 +265,7 @@ public static Map, RouteShape> readShapesFile(String shapeFile, S Map, RouteShape> shapes = new HashMap<>(); CoordinateTransformation ct = TransformationFactory.getCoordinateTransformation("WGS84", outputCoordinateSystem); - CSVReader reader; - try { - reader = new CSVReader(new FileReader(shapeFile)); + try (CSVReader reader = new CSVReader(new FileReader(shapeFile))) { String[] header = reader.readNext(); Map col = getIndices(header, GtfsDefinitions.Files.SHAPES.columns); String[] line = reader.readNext(); @@ -280,7 +280,6 @@ public static Map, RouteShape> readShapesFile(String shapeFile, S currentShape.addPoint(ct.transform(point), Integer.parseInt(line[col.get(GtfsDefinitions.SHAPE_PT_SEQUENCE)])); line = reader.readNext(); } - reader.close(); } catch (FileNotFoundException e) { e.printStackTrace(); throw new RuntimeException("File not found!"); @@ -288,6 +287,8 @@ public static Map, RouteShape> readShapesFile(String shapeFile, S throw new RuntimeException("Emtpy line found file!"); } catch (IOException e) { e.printStackTrace(); + } catch (CsvValidationException e) { + throw new RuntimeException(e); } return shapes; } diff --git a/src/main/java/org/matsim/pt2matsim/tools/debug/ScheduleCleaner.java b/src/main/java/org/matsim/pt2matsim/tools/debug/ScheduleCleaner.java index 23193a0a..c1521937 100644 --- a/src/main/java/org/matsim/pt2matsim/tools/debug/ScheduleCleaner.java +++ b/src/main/java/org/matsim/pt2matsim/tools/debug/ScheduleCleaner.java @@ -18,7 +18,8 @@ package org.matsim.pt2matsim.tools.debug; -import org.apache.log4j.Logger; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.LogManager; import org.matsim.api.core.v01.Coord; import org.matsim.api.core.v01.Id; import org.matsim.api.core.v01.network.Link; @@ -47,7 +48,7 @@ */ public final class ScheduleCleaner { - protected static Logger log = Logger.getLogger(ScheduleTools.class); + protected static Logger log = LogManager.getLogger(ScheduleTools.class); private ScheduleCleaner() {} diff --git a/src/test/java/org/matsim/pt2matsim/editor/BasicScheduleEditorTest.java b/src/test/java/org/matsim/pt2matsim/editor/BasicScheduleEditorTest.java index 52a3dcb4..89c8cf87 100644 --- a/src/test/java/org/matsim/pt2matsim/editor/BasicScheduleEditorTest.java +++ b/src/test/java/org/matsim/pt2matsim/editor/BasicScheduleEditorTest.java @@ -1,7 +1,7 @@ package org.matsim.pt2matsim.editor; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; import org.matsim.api.core.v01.Id; import org.matsim.api.core.v01.network.Link; import org.matsim.api.core.v01.network.Network; @@ -17,7 +17,7 @@ /** * @author polettif */ -public class BasicScheduleEditorTest { +class BasicScheduleEditorTest { /** * Possible Commands: @@ -25,7 +25,7 @@ public class BasicScheduleEditorTest { * ["rerouteViaLink"] [TransitLineId] [TransitRouteId] [oldLinkId] [newLinkId] */ @Test - public void rerouteViaLink() { + void rerouteViaLink() { TransitSchedule schedule = initSchedule(); Network network = NetworkToolsTest.initNetwork(); @@ -47,7 +47,7 @@ public void rerouteViaLink() { linkIdsExpected.add(Id.createLinkId("ZI")); linkIdsExpected.add(Id.createLinkId("IB")); - Assert.assertEquals(linkIdsExpected, linkIds); + Assertions.assertEquals(linkIdsExpected, linkIds); } /** @@ -57,7 +57,7 @@ public void rerouteViaLink() { * ["changeRefLink"] ["allTransitRoutesOnLink"] [linkId] [ParentId] [newlinkId] */ @Test - public void changeRefLink() { + void changeRefLink() { TransitSchedule schedule = initSchedule(); Network network = NetworkToolsTest.initNetwork(); @@ -79,7 +79,7 @@ public void changeRefLink() { linkIdsExpected.add(Id.createLinkId("ZI")); linkIdsExpected.add(Id.createLinkId("IB")); - Assert.assertEquals(linkIdsExpected, linkIds); + Assertions.assertEquals(linkIdsExpected, linkIds); } } \ No newline at end of file diff --git a/src/test/java/org/matsim/pt2matsim/gtfs/GtfsConverterTest.java b/src/test/java/org/matsim/pt2matsim/gtfs/GtfsConverterTest.java index 33a5b2be..6a0bd492 100644 --- a/src/test/java/org/matsim/pt2matsim/gtfs/GtfsConverterTest.java +++ b/src/test/java/org/matsim/pt2matsim/gtfs/GtfsConverterTest.java @@ -1,8 +1,8 @@ package org.matsim.pt2matsim.gtfs; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.matsim.api.core.v01.Coord; import org.matsim.api.core.v01.Id; import org.matsim.core.utils.geometry.transformations.TransformationFactory; @@ -16,14 +16,14 @@ /** * @author polettif */ -public class GtfsConverterTest { +class GtfsConverterTest { private GtfsFeed gtfsFeed; private GtfsConverter gtfsConverter; private String coordSystem = TransformationFactory.CH1903_LV03_Plus; private TransitSchedule convertedSchedule; - @Before + @BeforeEach public void convert() { gtfsFeed = new GtfsFeedImpl("test/gtfs-feed/"); @@ -32,25 +32,25 @@ public void convert() { } @Test - public void convertAll() { + void convertAll() { TransitSchedule schedule = gtfsConverter.convert(GtfsConverter.ALL_SERVICE_IDS, coordSystem); - Assert.assertTrue(TransitScheduleValidator.validateAllStopsExist(schedule).isValid()); - Assert.assertTrue(TransitScheduleValidator.validateOffsets(schedule).isValid()); + Assertions.assertTrue(TransitScheduleValidator.validateAllStopsExist(schedule).isValid()); + Assertions.assertTrue(TransitScheduleValidator.validateOffsets(schedule).isValid()); } @Test - public void numberOfStopsAndRoutes() { + void numberOfStopsAndRoutes() { int nTransitRoutes = 0; for(TransitLine transitLine : convertedSchedule.getTransitLines().values()) { nTransitRoutes += transitLine.getRoutes().size(); } - Assert.assertEquals(6, convertedSchedule.getFacilities().size()); - Assert.assertEquals(3, convertedSchedule.getTransitLines().size()); - Assert.assertEquals(3, nTransitRoutes); + Assertions.assertEquals(6, convertedSchedule.getFacilities().size()); + Assertions.assertEquals(3, convertedSchedule.getTransitLines().size()); + Assertions.assertEquals(3, nTransitRoutes); } @Test - public void departuresFromFrequencies() { + void departuresFromFrequencies() { TransitSchedule baseSchedule = ScheduleToolsTest.initSchedule(); for(TransitLine transitLine : convertedSchedule.getTransitLines().values()) { for(TransitRoute transitRoute : transitLine.getRoutes().values()) { @@ -67,25 +67,25 @@ public void departuresFromFrequencies() { actualDepTimes.add(departure.getDepartureTime()); } - Assert.assertEquals(expectedDepTimes, actualDepTimes); + Assertions.assertEquals(expectedDepTimes, actualDepTimes); } } } @Test - public void offsets() { + void offsets() { TransitSchedule baseSchedule = ScheduleToolsTest.initSchedule(); for(TransitLine transitLine : convertedSchedule.getTransitLines().values()) { for(TransitRoute transitRoute : transitLine.getRoutes().values()) { TransitRoute expectedRoute = baseSchedule.getTransitLines().get(transitLine.getId()).getRoutes().get(transitRoute.getId()); - Assert.assertEquals(expectedRoute.getStops().size(), transitRoute.getStops().size()); + Assertions.assertEquals(expectedRoute.getStops().size(), transitRoute.getStops().size()); for(int i = 0; i < transitRoute.getStops().size() - 1; i++) { if(i > 0) { - Assert.assertEquals(expectedRoute.getStops().get(i).getArrivalOffset().seconds(), + Assertions.assertEquals(expectedRoute.getStops().get(i).getArrivalOffset().seconds(), transitRoute.getStops().get(i).getArrivalOffset().seconds(), 0.1); } if(i < transitRoute.getStops().size() - 2) { - Assert.assertEquals(expectedRoute.getStops().get(i).getDepartureOffset().seconds(), + Assertions.assertEquals(expectedRoute.getStops().get(i).getDepartureOffset().seconds(), transitRoute.getStops().get(i).getDepartureOffset().seconds(), 0.1); } } @@ -94,17 +94,17 @@ public void offsets() { } @Test - public void stops() { + void stops() { TransitSchedule baseSchedule = ScheduleToolsTest.initUnmappedSchedule(); for(TransitStopFacility actualStopFac : convertedSchedule.getFacilities().values()) { TransitStopFacility expectedStopFac = baseSchedule.getFacilities().get(actualStopFac.getId()); - Assert.assertEquals(expectedStopFac.getCoord(), actualStopFac.getCoord()); - Assert.assertEquals(expectedStopFac.getName(), actualStopFac.getName()); + Assertions.assertEquals(expectedStopFac.getCoord(), actualStopFac.getCoord()); + Assertions.assertEquals(expectedStopFac.getName(), actualStopFac.getName()); } } @Test - public void combineRoutes() { + void combineRoutes() { TransitSchedule test = ScheduleTools.createSchedule(); TransitScheduleFactory f = test.getFactory(); Id lineId = Id.create("L", TransitLine.class); @@ -137,14 +137,14 @@ public void combineRoutes() { line.addRoute(route2); line.addRoute(route3); - Assert.assertEquals(3, line.getRoutes().size()); + Assertions.assertEquals(3, line.getRoutes().size()); // only routes with identical stop sequence (1, 2, 3) and departure sequence (2, 3) are combined. gtfsConverter.combineTransitRoutes(test); - Assert.assertEquals(2, line.getRoutes().size()); + Assertions.assertEquals(2, line.getRoutes().size()); } @Test - public void testTransfers() { + void testTransfers() { Set expectedTransferTimes = new TreeSet<>(); MinimalTransferTimes.MinimalTransferTimesIterator iter1 = ScheduleToolsTest.initUnmappedSchedule().getMinimalTransferTimes().iterator(); while(iter1.hasNext()) { @@ -159,7 +159,7 @@ public void testTransfers() { actualTransferTime.add(getTransferTimeTestString(iter2)); } - Assert.assertEquals(expectedTransferTimes, actualTransferTime); + Assertions.assertEquals(expectedTransferTimes, actualTransferTime); } private String getTransferTimeTestString(MinimalTransferTimes.MinimalTransferTimesIterator iterator) { diff --git a/src/test/java/org/matsim/pt2matsim/gtfs/GtfsFeedImplTest.java b/src/test/java/org/matsim/pt2matsim/gtfs/GtfsFeedImplTest.java index 5d093d3c..ddd1781c 100644 --- a/src/test/java/org/matsim/pt2matsim/gtfs/GtfsFeedImplTest.java +++ b/src/test/java/org/matsim/pt2matsim/gtfs/GtfsFeedImplTest.java @@ -1,8 +1,8 @@ package org.matsim.pt2matsim.gtfs; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.matsim.api.core.v01.Coord; import org.matsim.api.core.v01.Id; import org.matsim.core.utils.geometry.transformations.TransformationFactory; @@ -23,39 +23,39 @@ /** * @author polettif */ -public class GtfsFeedImplTest { +class GtfsFeedImplTest { private GtfsFeed feed; - @Before + @BeforeEach public void prepare() { feed = new GtfsFeedImpl("test/gtfs-feed/"); - Assert.assertEquals(TransformationFactory.WGS84, feed.getCurrentCoordSystem()); + Assertions.assertEquals(TransformationFactory.WGS84, feed.getCurrentCoordSystem()); } @Test - public void compareShapes() { + void compareShapes() { feed.transform(TransformationFactory.CH1903_LV03_Plus); for(Map.Entry, RouteShape> entry : ShapeToolsTest.initShapes().entrySet()) { RouteShape feedShape = feed.getShapes().get(entry.getKey()); for(Map.Entry coordEntry : entry.getValue().getCoordsSorted().entrySet()) { - Assert.assertEquals(coordEntry.getValue(), feedShape.getCoordsSorted().get(coordEntry.getKey())); + Assertions.assertEquals(coordEntry.getValue(), feedShape.getCoordsSorted().get(coordEntry.getKey())); } } } @Test - public void statistics() { - Assert.assertEquals(6, feed.getStops().size()); - Assert.assertEquals(3, feed.getRoutes().size()); - Assert.assertEquals(4, feed.getServices().size()); - Assert.assertEquals(3, feed.getShapes().size()); - Assert.assertEquals(6, feed.getTrips().size()); - Assert.assertEquals(6, feed.getTransfers().size()); + void statistics() { + Assertions.assertEquals(6, feed.getStops().size()); + Assertions.assertEquals(3, feed.getRoutes().size()); + Assertions.assertEquals(4, feed.getServices().size()); + Assertions.assertEquals(3, feed.getShapes().size()); + Assertions.assertEquals(6, feed.getTrips().size()); + Assertions.assertEquals(6, feed.getTransfers().size()); } @Test - public void stopsAndCoordsEqualAfterRetransform() { + void stopsAndCoordsEqualAfterRetransform() { Map stopCoords1 = cloneFeedStopCoords(feed); // transform @@ -69,9 +69,9 @@ public void stopsAndCoordsEqualAfterRetransform() { Stop testStop = feed.getStops().values().stream().findFirst(). map(s -> new StopImpl(s.getId(), s.getName(), s.getLon(), s.getLat(), s.getLocationType(), s.getParentStationId())). orElse(null); - Assert.assertNotNull(testStop); - Assert.assertEquals(testStop, feed.getStops().get(testStop.getId())); - Assert.assertEquals(TransformationFactory.CH1903_LV03_Plus, feed.getCurrentCoordSystem()); + Assertions.assertNotNull(testStop); + Assertions.assertEquals(testStop, feed.getStops().get(testStop.getId())); + Assertions.assertEquals(TransformationFactory.CH1903_LV03_Plus, feed.getCurrentCoordSystem()); // retransform feed.transform(TransformationFactory.WGS84); @@ -95,40 +95,40 @@ private void testCoordsEqual(Map stopCoordsExpected, Map covered = new TreeSet<>(); covered.add(LocalDate.of(2018, 10, 2)); covered.add(LocalDate.of(2018, 10, 3)); covered.add(LocalDate.of(2018, 10, 4)); covered.add(LocalDate.of(2018, 10, 6)); - Assert.assertEquals(covered, emptService.getCoveredDays()); + Assertions.assertEquals(covered, emptService.getCoveredDays()); } @Test - public void gtfsShapesGeojson() { + void gtfsShapesGeojson() { GtfsTools.writeShapesToGeojson(feed, "test/shapes.geojson"); new File("test/shapes.geojson").delete(); } @Test - public void missingCalendar() { + void missingCalendar() { new GtfsFeedImpl("test/gtfs-feed-cal/"); } diff --git a/src/test/java/org/matsim/pt2matsim/gtfs/GtfsRealFeedTest.java b/src/test/java/org/matsim/pt2matsim/gtfs/GtfsRealFeedTest.java index 1920e4db..d7d7c5fb 100644 --- a/src/test/java/org/matsim/pt2matsim/gtfs/GtfsRealFeedTest.java +++ b/src/test/java/org/matsim/pt2matsim/gtfs/GtfsRealFeedTest.java @@ -1,33 +1,33 @@ package org.matsim.pt2matsim.gtfs; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; /** * @author polettif */ -public class GtfsRealFeedTest { +class GtfsRealFeedTest { private GtfsFeed feed; private GtfsConverter converter; - @Before + @BeforeEach public void loadAndConvert() { feed = new GtfsFeedImpl("test/stib-mivb-gtfs.zip"); converter = new GtfsConverter(feed); } @Test - public void statistics() { - Assert.assertEquals(2514, feed.getStops().size()); - Assert.assertEquals(92, feed.getRoutes().size()); - Assert.assertEquals(139, feed.getServices().size()); - Assert.assertEquals(806, feed.getShapes().size()); + void statistics() { + Assertions.assertEquals(2514, feed.getStops().size()); + Assertions.assertEquals(92, feed.getRoutes().size()); + Assertions.assertEquals(139, feed.getServices().size()); + Assertions.assertEquals(806, feed.getShapes().size()); } @Test - public void convert() { + void convert() { converter.convert(GtfsConverter.DAY_WITH_MOST_TRIPS, "EPSG:32631"); } diff --git a/src/test/java/org/matsim/pt2matsim/gtfs/SpaceIdTest.java b/src/test/java/org/matsim/pt2matsim/gtfs/SpaceIdTest.java index 9422ff4a..099ac24a 100644 --- a/src/test/java/org/matsim/pt2matsim/gtfs/SpaceIdTest.java +++ b/src/test/java/org/matsim/pt2matsim/gtfs/SpaceIdTest.java @@ -4,8 +4,8 @@ import java.util.Arrays; import java.util.HashSet; -import org.junit.After; -import org.junit.Test; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Test; import org.matsim.api.core.v01.Coord; import org.matsim.api.core.v01.Id; import org.matsim.api.core.v01.Scenario; @@ -25,8 +25,8 @@ import org.matsim.vehicles.VehicleUtils; import org.matsim.vehicles.Vehicles; -public class SpaceIdTest { - @After +class SpaceIdTest { + @AfterEach public void cleanup() { new File("test_output_schedule.xml").delete(); } @@ -41,7 +41,7 @@ public void cleanup() { * link IDs that do not have spaces included. */ @Test - public void testFeedWithSpacesInId() { + void testFeedWithSpacesInId() { GtfsFeed feed = new GtfsFeedImpl("test/space-feed/"); GtfsConverter covnerter = new GtfsConverter(feed); diff --git a/src/test/java/org/matsim/pt2matsim/hafas/HafasConverterTest.java b/src/test/java/org/matsim/pt2matsim/hafas/HafasConverterTest.java index 5573bea9..f9a63c22 100644 --- a/src/test/java/org/matsim/pt2matsim/hafas/HafasConverterTest.java +++ b/src/test/java/org/matsim/pt2matsim/hafas/HafasConverterTest.java @@ -1,8 +1,8 @@ package org.matsim.pt2matsim.hafas; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.matsim.api.core.v01.Id; import org.matsim.core.utils.geometry.CoordinateTransformation; import org.matsim.core.utils.geometry.transformations.TransformationFactory; @@ -16,12 +16,12 @@ /** * @author polettif */ -public class HafasConverterTest { +class HafasConverterTest { private TransitSchedule schedule; private Vehicles vehicles; - @Before + @BeforeEach public void convert() throws IOException { this.schedule = ScheduleTools.createSchedule(); this.vehicles = VehicleUtils.createVehiclesContainer(); @@ -33,21 +33,21 @@ public void convert() throws IOException { } @Test - public void transitRoutes() { - Assert.assertEquals(1, schedule.getTransitLines().size()); + void transitRoutes() { + Assertions.assertEquals(1, schedule.getTransitLines().size()); int nRoutes = 0; for(TransitLine tl : schedule.getTransitLines().values()) { - Assert.assertEquals("BRB", tl.getId().toString()); + Assertions.assertEquals("BRB", tl.getId().toString()); for(TransitRoute tr : tl.getRoutes().values()) { nRoutes++; } } - Assert.assertEquals(2, nRoutes); + Assertions.assertEquals(2, nRoutes); } @Test - public void minimalTransferTimes() { + void minimalTransferTimes() { int nbMinimalTransferTimes = 0; MinimalTransferTimes transferTimes = schedule.getMinimalTransferTimes(); MinimalTransferTimes.MinimalTransferTimesIterator iterator = transferTimes.iterator(); @@ -55,24 +55,24 @@ public void minimalTransferTimes() { iterator.next(); nbMinimalTransferTimes += 1; } - Assert.assertEquals(3, nbMinimalTransferTimes); + Assertions.assertEquals(3, nbMinimalTransferTimes); - Assert.assertEquals(5*60.0, transferTimes.get( + Assertions.assertEquals(5 * 60.0, transferTimes.get( Id.create("8508350", TransitStopFacility.class), Id.create("8508350", TransitStopFacility.class)), 0.00001); - Assert.assertEquals(6*60.0, transferTimes.get( + Assertions.assertEquals(6 * 60.0, transferTimes.get( Id.create("8508351", TransitStopFacility.class), Id.create("8508351", TransitStopFacility.class)), 0.00001); - Assert.assertEquals(60*60.0, transferTimes.get( + Assertions.assertEquals(60 * 60.0, transferTimes.get( Id.create("8508350", TransitStopFacility.class), Id.create("8508351", TransitStopFacility.class)), 0.00001); } @Test - public void nStops() { - Assert.assertEquals(3, schedule.getFacilities().size()); + void nStops() { + Assertions.assertEquals(3, schedule.getFacilities().size()); } } \ No newline at end of file diff --git a/src/test/java/org/matsim/pt2matsim/hafas/HafasFplanTest.java b/src/test/java/org/matsim/pt2matsim/hafas/HafasFplanTest.java index 4b96cfa7..999022b4 100644 --- a/src/test/java/org/matsim/pt2matsim/hafas/HafasFplanTest.java +++ b/src/test/java/org/matsim/pt2matsim/hafas/HafasFplanTest.java @@ -1,7 +1,7 @@ package org.matsim.pt2matsim.hafas; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; import org.matsim.pt.transitSchedule.api.TransitSchedule; import org.matsim.pt2matsim.tools.ScheduleTools; import org.matsim.vehicles.VehicleUtils; @@ -10,9 +10,9 @@ import java.io.IOException; import java.util.stream.Collectors; -public class HafasFplanTest { +class HafasFplanTest { @Test - public void simpleFplanTest() throws IOException { + void simpleFplanTest() throws IOException { String hafasFolder = "test/FPLAN_HAFAS/"; @@ -21,10 +21,10 @@ public void simpleFplanTest() throws IOException { HafasConverter.run(hafasFolder, schedule, null, vehicles); int nbRoutes = schedule.getTransitLines().values().stream().flatMap(l -> l.getRoutes().values().stream()).collect(Collectors.toList()).size(); - Assert.assertEquals(2, nbRoutes); + Assertions.assertEquals(2, nbRoutes); int nbDeps = schedule.getTransitLines().values().stream(). flatMap(l -> l.getRoutes().values().stream().flatMap(r -> r.getDepartures().values().stream())).collect(Collectors.toList()).size(); - Assert.assertEquals(3, nbDeps); + Assertions.assertEquals(3, nbDeps); } } diff --git a/src/test/java/org/matsim/pt2matsim/mapping/PTMapperShapesTest.java b/src/test/java/org/matsim/pt2matsim/mapping/PTMapperShapesTest.java index 3a2d080a..cc4b41ee 100644 --- a/src/test/java/org/matsim/pt2matsim/mapping/PTMapperShapesTest.java +++ b/src/test/java/org/matsim/pt2matsim/mapping/PTMapperShapesTest.java @@ -1,8 +1,8 @@ package org.matsim.pt2matsim.mapping; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.matsim.api.core.v01.Id; import org.matsim.api.core.v01.network.Link; import org.matsim.api.core.v01.network.Network; @@ -29,13 +29,13 @@ /** * @author polettif */ -public class PTMapperShapesTest { +class PTMapperShapesTest { public Network network; public TransitSchedule schedule; public PublicTransitMappingConfigGroup ptmConfig; - @Before + @BeforeEach public void prepare() { ptmConfig = initPTMConfig(); network = NetworkToolsTest.initNetwork(); @@ -50,20 +50,20 @@ public void prepare() { } @Test - public void validateMappedSchedule() { - Assert.assertTrue(TransitScheduleValidator.validateAll(schedule, network).isValid()); + void validateMappedSchedule() { + Assertions.assertTrue(TransitScheduleValidator.validateAll(schedule, network).isValid()); } @Test - public void allowedModes() { + void allowedModes() { for(Link l : network.getLinks().values()) { - Assert.assertFalse(l.getAllowedModes().contains(PublicTransitMappingStrings.ARTIFICIAL_LINK_MODE)); + Assertions.assertFalse(l.getAllowedModes().contains(PublicTransitMappingStrings.ARTIFICIAL_LINK_MODE)); } } @Test - public void linkSequences() { + void linkSequences() { TransitSchedule initSchedule = ScheduleToolsTest.initSchedule(); for(TransitLine l : schedule.getTransitLines().values()) { @@ -71,7 +71,7 @@ public void linkSequences() { TransitRoute initRoute = initSchedule.getTransitLines().get(l.getId()).getRoutes().get(r.getId()); List> initLinkIds = ScheduleTools.getTransitRouteLinkIds(initRoute); List> linkIds = ScheduleTools.getTransitRouteLinkIds(r); - Assert.assertEquals(initLinkIds, linkIds); + Assertions.assertEquals(initLinkIds, linkIds); } } } diff --git a/src/test/java/org/matsim/pt2matsim/mapping/PTMapperTest.java b/src/test/java/org/matsim/pt2matsim/mapping/PTMapperTest.java index 78004810..2b07cc09 100644 --- a/src/test/java/org/matsim/pt2matsim/mapping/PTMapperTest.java +++ b/src/test/java/org/matsim/pt2matsim/mapping/PTMapperTest.java @@ -1,8 +1,8 @@ package org.matsim.pt2matsim.mapping; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.matsim.api.core.v01.Id; import org.matsim.api.core.v01.network.Link; import org.matsim.api.core.v01.network.Network; @@ -11,7 +11,6 @@ import org.matsim.pt.transitSchedule.api.TransitSchedule; import org.matsim.pt.transitSchedule.api.TransitStopFacility; import org.matsim.pt.utils.TransitScheduleValidator; -import org.matsim.pt2matsim.config.OsmConverterConfigGroup; import org.matsim.pt2matsim.config.PublicTransitMappingConfigGroup; import org.matsim.pt2matsim.config.PublicTransitMappingStrings; import org.matsim.pt2matsim.run.CreateDefaultPTMapperConfig; @@ -47,7 +46,7 @@ public static PublicTransitMappingConfigGroup initPTMConfig() { return config; } - @Before + @BeforeEach public void prepare() { ptmConfig = initPTMConfig(); network = NetworkToolsTest.initNetwork(); @@ -57,25 +56,25 @@ public void prepare() { } @Test - public void validateMappedSchedule() { - Assert.assertTrue(TransitScheduleValidator.validateAll(schedule, network).isValid()); + void validateMappedSchedule() { + Assertions.assertTrue(TransitScheduleValidator.validateAll(schedule, network).isValid()); } @Test - public void allowedModes() { + void allowedModes() { for(Link l : network.getLinks().values()) { - Assert.assertFalse(l.getAllowedModes().contains(PublicTransitMappingStrings.ARTIFICIAL_LINK_MODE)); + Assertions.assertFalse(l.getAllowedModes().contains(PublicTransitMappingStrings.ARTIFICIAL_LINK_MODE)); } } @Test - public void numberOfStopFacilities() { - Assert.assertEquals(10, schedule.getFacilities().size()); + void numberOfStopFacilities() { + Assertions.assertEquals(10, schedule.getFacilities().size()); } @Test - public void linkSequences() { + void linkSequences() { TransitSchedule initSchedule = ScheduleToolsTest.initSchedule(); for(TransitLine l : schedule.getTransitLines().values()) { @@ -84,14 +83,14 @@ public void linkSequences() { List> initLinkIds = ScheduleTools.getTransitRouteLinkIds(initRoute); List> linkIds = ScheduleTools.getTransitRouteLinkIds(r); if(!r.getId().equals(ROUTE_B)) { // route B cantt be guessed by the mapper because there's not enough information - Assert.assertEquals(initLinkIds, linkIds); + Assertions.assertEquals(initLinkIds, linkIds); } } } } @Test - public void artificialLinks() { + void artificialLinks() { PublicTransitMappingConfigGroup ptmConfig2 = initPTMConfig(); ptmConfig2.setMaxLinkCandidateDistance(3); @@ -100,11 +99,11 @@ public void artificialLinks() { new PTMapper(schedule2, network2).run(ptmConfig2); // 1 loop link, 3 artificial links - Assert.assertEquals(NetworkToolsTest.initNetwork().getLinks().size()+4, network2.getLinks().size()); - Assert.assertEquals(9, schedule2.getFacilities().size()); + Assertions.assertEquals(NetworkToolsTest.initNetwork().getLinks().size() + 4, network2.getLinks().size()); + Assertions.assertEquals(9, schedule2.getFacilities().size()); } @Test - public void noTransportModeAssignment() { + void noTransportModeAssignment() { PublicTransitMappingConfigGroup noTMAConfig = new PublicTransitMappingConfigGroup(); noTMAConfig.getModesToKeepOnCleanUp().add("car"); noTMAConfig.setNumOfThreads(2); @@ -122,18 +121,18 @@ public void noTransportModeAssignment() { for(TransitRoute transitRoute : transitLine.getRoutes().values()) { List> linkIds = ScheduleTools.getTransitRouteLinkIds(transitRoute); for(Id linkId : linkIds) { - Assert.assertTrue(linkId.toString().contains("pt_")); + Assertions.assertTrue(linkId.toString().contains("pt_")); } } } // only artificial stop links for(TransitStopFacility transitStopFacility : schedule2.getFacilities().values()) { - Assert.assertTrue(transitStopFacility.getLinkId().toString().contains("pt_")); + Assertions.assertTrue(transitStopFacility.getLinkId().toString().contains("pt_")); } } @Test - public void defaultConfig() { + void defaultConfig() { CreateDefaultPTMapperConfig.main(new String[]{"doc/defaultPTMapperConfig.xml"}); } diff --git a/src/test/java/org/matsim/pt2matsim/osm/OsmMultimodalNetworkConverterTest.java b/src/test/java/org/matsim/pt2matsim/osm/OsmMultimodalNetworkConverterTest.java index d26bb33b..bc05adc6 100644 --- a/src/test/java/org/matsim/pt2matsim/osm/OsmMultimodalNetworkConverterTest.java +++ b/src/test/java/org/matsim/pt2matsim/osm/OsmMultimodalNetworkConverterTest.java @@ -1,16 +1,14 @@ package org.matsim.pt2matsim.osm; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; - import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; -import org.junit.BeforeClass; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; import org.matsim.api.core.v01.network.Link; import org.matsim.api.core.v01.network.Network; import org.matsim.pt2matsim.config.OsmConverterConfigGroup; @@ -18,7 +16,6 @@ import org.matsim.pt2matsim.osm.lib.OsmDataImpl; import org.matsim.pt2matsim.osm.lib.OsmFileReader; import org.matsim.pt2matsim.run.CreateDefaultOsmConfig; -import org.matsim.pt2matsim.run.CreateDefaultPTMapperConfig; /** * @author polettif @@ -29,7 +26,7 @@ public class OsmMultimodalNetworkConverterTest { private static Map> osmid2link; private static final double DELTA = 0.001; - @BeforeClass + @BeforeAll public static void convertGerasdorfArtificialLanesAndMaxspeed() { // setup config OsmConverterConfigGroup osmConfig = OsmConverterConfigGroup.createDefaultConfig(); @@ -37,6 +34,7 @@ public static void convertGerasdorfArtificialLanesAndMaxspeed() { osmConfig.setOsmFile("test/osm/GerasdorfArtificialLanesAndMaxspeed.osm"); osmConfig.setOutputNetworkFile("test/osm/GerasdorfArtificialLanesAndMaxspeed.xml.gz"); osmConfig.setMaxLinkLength(1000); + osmConfig.parseTurnRestrictions = true; // turn restrictions not explicitly tested in this class // read OSM file OsmData osm = new OsmDataImpl(); @@ -72,41 +70,41 @@ private static Set getLinksTowardsNode(Set links, long osmNodeId) { } @Test - public void testDefaultResidential() { + void testDefaultResidential() { Set links = osmid2link.get(7994891L); - assertEquals("bidirectional", 2, links.size()); + Assertions.assertEquals(2, links.size(), "bidirectional"); assertLanes(links, 1); assertMaxspeed("taken from OsmConverterConfigGroup.createDefaultConfig", links, 15); } @Test - public void testDefaultPrimary() { + void testDefaultPrimary() { Set links = osmid2link.get(7994890L); - assertEquals("bidirectional", 2, links.size()); + Assertions.assertEquals(2, links.size(), "bidirectional"); assertLanes("taken from OsmConverterConfigGroup.createDefaultConfig", links, 1); assertMaxspeed("taken from OsmConverterConfigGroup.createDefaultConfig", links, 80); } @Test - public void testPrimaryWithLanesAndMaxspeed() { + void testPrimaryWithLanesAndMaxspeed() { Set links = osmid2link.get(7994889L); - assertEquals("bidirectional", 2, links.size()); + Assertions.assertEquals(2, links.size(), "bidirectional"); assertLanes(links, 3); assertMaxspeed(links, 70); } @Test - public void testPrimaryWithOddLanesAndMaxspeed() { + void testPrimaryWithOddLanesAndMaxspeed() { Set links = osmid2link.get(7994888L); - assertEquals("bidirectional", 2, links.size()); + Assertions.assertEquals(2, links.size(), "bidirectional"); assertLanes(links, 3.5); assertMaxspeed(links, 70); } @Test - public void testPrimaryWithForwardAndBackwardLanesAndMaxspeed() { + void testPrimaryWithForwardAndBackwardLanesAndMaxspeed() { Set links = osmid2link.get(7994887L); - assertEquals("bidirectional", 2, links.size()); + Assertions.assertEquals(2, links.size(), "bidirectional"); Set linksToNorth = getLinksTowardsNode(links, 59836731L); assertLanes(linksToNorth, 3); @@ -118,9 +116,9 @@ public void testPrimaryWithForwardAndBackwardLanesAndMaxspeed() { } @Test - public void testPrimaryWithForwardAndBackwardSpecialLanesAndMaxspeed() { + void testPrimaryWithForwardAndBackwardSpecialLanesAndMaxspeed() { Set links = osmid2link.get(7994886L); - assertEquals("bidirectional", 2, links.size()); + Assertions.assertEquals(2, links.size(), "bidirectional"); Set linksToNorth = getLinksTowardsNode(links, 57443579L); assertLanes("4 minus one bus lane", linksToNorth, 3); @@ -132,128 +130,129 @@ public void testPrimaryWithForwardAndBackwardSpecialLanesAndMaxspeed() { } @Test - public void testPrimaryWithSpecialLanes() { + void testPrimaryWithSpecialLanes() { Set links = osmid2link.get(7994912L); - assertEquals("bidirectional", 2, links.size()); + Assertions.assertEquals(2, links.size(), "bidirectional"); assertLanes("4 per direction minus one taxi lane", links, 3); assertMaxspeed(links, 70); } @Test - public void testDefaultResidentialOneway() { + void testDefaultResidentialOneway() { Set links = osmid2link.get(7994914L); - assertEquals("oneway", 1, links.size()); - assertEquals("oneway up north", 1, getLinksTowardsNode(links, 59836794L).size()); + Assertions.assertEquals(1, links.size(), "oneway"); + Assertions.assertEquals(1, getLinksTowardsNode(links, 59836794L).size(), "oneway up north"); assertLanes(links, 1); assertMaxspeed("taken from OsmConverterConfigGroup.createDefaultConfig", links, 15); } @Test - public void testResidentialInvalidLanesAndMaxspeed() { + void testResidentialInvalidLanesAndMaxspeed() { Set links = osmid2link.get(7994891L); - assertEquals("bidirectional", 2, links.size()); + Assertions.assertEquals(2, links.size(), "bidirectional"); assertLanes("taken from OsmConverterConfigGroup.createDefaultConfig", links, 1); assertMaxspeed("taken from OsmConverterConfigGroup.createDefaultConfig", links, 15); } @Test - public void testDefaultPrimaryOneway() { + void testDefaultPrimaryOneway() { Set links = osmid2link.get(7994919L); - assertEquals("oneway", 1, links.size()); - assertEquals("oneway up north", 1, getLinksTowardsNode(links, 59836804L).size()); + Assertions.assertEquals(1, links.size(), "oneway"); + Assertions.assertEquals(1, getLinksTowardsNode(links, 59836804L).size(), "oneway up north"); assertLanes("taken from OsmConverterConfigGroup.createDefaultConfig", links, 1); assertMaxspeed("taken from OsmConverterConfigGroup.createDefaultConfig", links, 80); } @Test - public void testPrimaryOnewayWithLanesAndMaxspeed() { + void testPrimaryOnewayWithLanesAndMaxspeed() { Set links = osmid2link.get(240536138L); - assertEquals("oneway", 1, links.size()); - assertEquals("oneway up north", 1, getLinksTowardsNode(links, 2482638327L).size()); + Assertions.assertEquals(1, links.size(), "oneway"); + Assertions.assertEquals(1, getLinksTowardsNode(links, 2482638327L).size(), "oneway up north"); assertLanes(links, 3); assertMaxspeed(links, 70); } @Test - public void testPrimaryOnewayWithForwardLanesAndMaxspeed() { + void testPrimaryOnewayWithForwardLanesAndMaxspeed() { Set links = osmid2link.get(7994920L); - assertEquals("oneway", 1, links.size()); - assertEquals("oneway up north", 1, getLinksTowardsNode(links, 59836807L).size()); + Assertions.assertEquals(1, links.size(), "oneway"); + Assertions.assertEquals(1, getLinksTowardsNode(links, 59836807L).size(), "oneway up north"); assertLanes(links, 3); assertMaxspeed(links, 70); } @Test - public void testPrimaryOnewayWithForwardSpecialLanesAndMaxspeed() { + void testPrimaryOnewayWithForwardSpecialLanesAndMaxspeed() { Set links = osmid2link.get(7994925L); - assertEquals("oneway", 1, links.size()); - assertEquals("oneway up north", 1, getLinksTowardsNode(links, 59836816L).size()); + Assertions.assertEquals(1, links.size(), "oneway"); + Assertions.assertEquals(1, getLinksTowardsNode(links, 59836816L).size(), "oneway up north"); assertLanes("4 minus one bus lane", links, 3); assertMaxspeed(links, 70); } @Test - public void testPrimaryOnewayWithSpecialLane() { + void testPrimaryOnewayWithSpecialLane() { Set links = osmid2link.get(7994927L); - assertEquals("oneway", 1, links.size()); - assertEquals("oneway up north", 1, getLinksTowardsNode(links, 59836820L).size()); + Assertions.assertEquals(1, links.size(), "oneway"); + Assertions.assertEquals(1, getLinksTowardsNode(links, 59836820L).size(), "oneway up north"); assertLanes("4 minus one bus lane", links, 3); assertMaxspeed(links, 70); } @Test - public void testPrimaryDefaultReversedOneway() { + void testPrimaryDefaultReversedOneway() { Set links = osmid2link.get(7994930L); - assertEquals("oneway", 1, links.size()); - assertEquals("oneway down south", 1, getLinksTowardsNode(links, 59836834L).size()); + Assertions.assertEquals(1, links.size(), "oneway"); + Assertions.assertEquals(1, getLinksTowardsNode(links, 59836834L).size(), "oneway down south"); assertLanes(links, 3); assertMaxspeed(links, 70); } @Test - public void testMotorwayWithoutMaxspeedAndOneway() { + void testMotorwayWithoutMaxspeedAndOneway() { Set links = osmid2link.get(7994932L); - assertEquals("oneway by default - taken from OsmConverterConfigGroup.createDefaultConfig", 1, links.size()); - assertEquals("oneway up north", 1, getLinksTowardsNode(links, 59836844L).size()); + Assertions.assertEquals(1, links.size(), + "oneway by default - taken from OsmConverterConfigGroup.createDefaultConfig"); + Assertions.assertEquals(1, getLinksTowardsNode(links, 59836844L).size(), "oneway up north"); assertLanes("taken from OsmConverterConfigGroup.createDefaultConfig", links, 2); assertMaxspeed(links, OsmMultimodalNetworkConverter.SPEED_LIMIT_NONE_KPH); } @Test - public void testResidentialWithMaxspeedWalk() { + void testResidentialWithMaxspeedWalk() { Set links = osmid2link.get(7994934L); - assertEquals("bidirectional", 2, links.size()); + Assertions.assertEquals(2, links.size(), "bidirectional"); assertMaxspeed(links, OsmMultimodalNetworkConverter.SPEED_LIMIT_WALK_KPH); } @Test - public void testResidentialWithMaxspeedMiles() { + void testResidentialWithMaxspeedMiles() { Set links = osmid2link.get(7994935L); - assertEquals("bidirectional", 2, links.size()); + Assertions.assertEquals(2, links.size(), "bidirectional"); assertMaxspeed(links, 20 * 1.609344); } @Test - public void testResidentialWithMaxspeedKnots() { + void testResidentialWithMaxspeedKnots() { Set links = osmid2link.get(7994935L); - assertEquals("bidirectional", 2, links.size()); + Assertions.assertEquals(2, links.size(), "bidirectional"); assertMaxspeed(links, 20 * 1.609344); } @Test - public void testResidentialMultipleSpeedLimits() { + void testResidentialMultipleSpeedLimits() { Set links = osmid2link.get(7999581L); - assertEquals("bidirectional", 2, links.size()); + Assertions.assertEquals(2, links.size(), "bidirectional"); assertMaxspeed("second speed limit is ignored", links, 40); } @Test - public void testDeadEndStreetsAreContainedInNetwork() { - assertEquals(2, osmid2link.get(22971704L).size()); - assertEquals(2, osmid2link.get(153227314L).size()); - assertEquals(2, osmid2link.get(95142433L).size()); - assertEquals(2, osmid2link.get(95142441L).size()); + void testDeadEndStreetsAreContainedInNetwork() { + Assertions.assertEquals(2, osmid2link.get(22971704L).size()); + Assertions.assertEquals(2, osmid2link.get(153227314L).size()); + Assertions.assertEquals(2, osmid2link.get(95142433L).size()); + Assertions.assertEquals(2, osmid2link.get(95142441L).size()); } private static void assertLanes(Set links, double expectedLanes) { @@ -261,9 +260,10 @@ private static void assertLanes(Set links, double expectedLanes) { } private static void assertLanes(String message, Set links, double expectedLanes) { - assertFalse("at least one link expected", links.isEmpty()); + Assertions.assertFalse(links.isEmpty(), "at least one link expected"); for (Link link : links) { - assertEquals("lanes (in one direction): " + message, expectedLanes, link.getNumberOfLanes(), DELTA); + Assertions.assertEquals(expectedLanes, link.getNumberOfLanes(), DELTA, + "lanes (in one direction): " + message); } } @@ -272,14 +272,15 @@ private static void assertMaxspeed(Set links, double expectedFreespeedKph) } private static void assertMaxspeed(String message, Set links, double expectedFreespeedKph) { - assertFalse("at least one link expected", links.isEmpty()); + Assertions.assertFalse(links.isEmpty(), "at least one link expected"); for (Link link : links) { - assertEquals("freespeed m/s: message", expectedFreespeedKph / 3.6, link.getFreespeed(), DELTA); + Assertions.assertEquals(expectedFreespeedKph / 3.6, link.getFreespeed(), DELTA, + "freespeed m/s: " + message); } } @Test - public void convertWaterlooCityCentre() { + void convertWaterlooCityCentre() { // setup config OsmConverterConfigGroup osmConfig = OsmConverterConfigGroup.createDefaultConfig(); osmConfig.setOutputCoordinateSystem("WGS84"); @@ -300,7 +301,7 @@ public void convertWaterlooCityCentre() { } @Test - public void convertEPSG() { + void convertEPSG() { OsmConverterConfigGroup osmConfig = OsmConverterConfigGroup.createDefaultConfig(); osmConfig.setOutputCoordinateSystem("EPSG:8682"); osmConfig.setOsmFile("test/osm/Belgrade.osm"); @@ -313,7 +314,7 @@ public void convertEPSG() { } @Test - public void defaultConfig() { + void defaultConfig() { CreateDefaultOsmConfig.main(new String[]{"doc/defaultOsmConfig.xml"}); } diff --git a/src/test/java/org/matsim/pt2matsim/osm/OsmMultimodalNetworkConverterTurnRestrictionsTest.java b/src/test/java/org/matsim/pt2matsim/osm/OsmMultimodalNetworkConverterTurnRestrictionsTest.java new file mode 100644 index 00000000..0575db68 --- /dev/null +++ b/src/test/java/org/matsim/pt2matsim/osm/OsmMultimodalNetworkConverterTurnRestrictionsTest.java @@ -0,0 +1,70 @@ +package org.matsim.pt2matsim.osm; + +import java.util.List; +import java.util.Map; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.TransportMode; +import org.matsim.api.core.v01.network.Link; +import org.matsim.api.core.v01.network.Network; +import org.matsim.core.network.DisallowedNextLinks; +import org.matsim.core.network.DisallowedNextLinksUtils; +import org.matsim.core.network.NetworkUtils; +import org.matsim.pt2matsim.config.OsmConverterConfigGroup; +import org.matsim.pt2matsim.osm.lib.OsmData; +import org.matsim.pt2matsim.osm.lib.OsmDataImpl; +import org.matsim.pt2matsim.osm.lib.OsmFileReader; + +class OsmMultimodalNetworkConverterTurnRestrictionsTest { + + private static Network network; + + @BeforeAll + static void convertRudolfplatz() { + // setup config + OsmConverterConfigGroup osmConfig = OsmConverterConfigGroup.createDefaultConfig(); + osmConfig.setOutputCoordinateSystem("EPSG:25832"); + osmConfig.setOsmFile("test/osm/Rudolfplatz.osm"); + osmConfig.setOutputNetworkFile("test/osm/Rudolfplatz.xml.gz"); + osmConfig.setMaxLinkLength(1000); + osmConfig.parseTurnRestrictions = true; + + // read OSM file + OsmData osm = new OsmDataImpl(); + new OsmFileReader(osm).readFile(osmConfig.getOsmFile()); + + // convert + OsmMultimodalNetworkConverter converter = new OsmMultimodalNetworkConverter(osm); + converter.convert(osmConfig); + + network = converter.getNetwork(); + + // write file + // NetworkTools.writeNetwork(network, osmConfig.getOutputNetworkFile()); + } + + @Test + void testisValid() { + + Assertions.assertTrue(DisallowedNextLinksUtils.isValid(network)); + + } + + @Test + void testDisallowedNextLinks() { + + Id lId124 = Id.createLinkId("124"); + Link l124 = network.getLinks().get(lId124); + DisallowedNextLinks dnl = NetworkUtils.getDisallowedNextLinks(l124); + + Assertions.assertEquals(Map.of( + "bus", List.of(List.of(Id.createLinkId("68"), Id.createLinkId("414"))), + TransportMode.car, List.of(List.of(Id.createLinkId("68"), Id.createLinkId("414"))), + TransportMode.pt, List.of(List.of(Id.createLinkId("68"), Id.createLinkId("414")))), dnl.getAsMap()); + + } + +} diff --git a/src/test/java/org/matsim/pt2matsim/osm/OsmTurnRestrictionTest.java b/src/test/java/org/matsim/pt2matsim/osm/OsmTurnRestrictionTest.java new file mode 100644 index 00000000..efab6660 --- /dev/null +++ b/src/test/java/org/matsim/pt2matsim/osm/OsmTurnRestrictionTest.java @@ -0,0 +1,227 @@ +package org.matsim.pt2matsim.osm; + +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.stream.Collectors; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.matsim.api.core.v01.Id; +import org.matsim.api.core.v01.network.Link; +import org.matsim.api.core.v01.network.Network; +import org.matsim.api.core.v01.network.Node; +import org.matsim.core.network.NetworkUtils; +import org.matsim.pt2matsim.osm.lib.Osm; + +/** + * Test finding a sequence of link ids from OSM way ids. + */ +class OsmTurnRestrictionTest { + + private static final Logger LOG = LogManager.getLogger(OsmTurnRestrictionTest.class); + + protected static final Map, Id> osmIds = new HashMap<>(); + protected static final Map, List>> wayLinkMap = new HashMap<>(); // reverse of osmIds + protected static final Network network = NetworkUtils.createNetwork(); + + static { + + Node n0 = NetworkUtils.createNode(Id.createNodeId("0")); + Node n1 = NetworkUtils.createNode(Id.createNodeId("1")); + Node n2 = NetworkUtils.createNode(Id.createNodeId("2")); + Node n3 = NetworkUtils.createNode(Id.createNodeId("3")); + Node n4 = NetworkUtils.createNode(Id.createNodeId("4")); + Node n5 = NetworkUtils.createNode(Id.createNodeId("5")); + + network.addNode(n0); + network.addNode(n1); + network.addNode(n2); + network.addNode(n3); + network.addNode(n4); + network.addNode(n5); + + // * n0 + // l01 l10 (0110) + // * n1 - l15 l51 (1551) - n5 + // l12 l21 (1221) \ + // * n2 + // l23 l32 (2332) | l14 l41 (1441) + // * n3 + // l34 l43 (3443) / + // * n4 + + Id w0110 = Id.create("0110", Osm.Way.class); + Link l01 = NetworkUtils.createLink(Id.createLinkId("01"), n0, n1, network, 1, 1, 300, 1); + Link l10 = NetworkUtils.createLink(Id.createLinkId("10"), n1, n0, network, 1, 1, 300, 1); + osmIds.put(l01.getId(), w0110); + osmIds.put(l10.getId(), w0110); + + Id w1221 = Id.create("1221", Osm.Way.class); + Link l12 = NetworkUtils.createLink(Id.createLinkId("12"), n1, n2, network, 1, 1, 300, 1); + Link l21 = NetworkUtils.createLink(Id.createLinkId("21"), n2, n1, network, 1, 1, 300, 1); + osmIds.put(l12.getId(), w1221); + osmIds.put(l21.getId(), w1221); + + Id w1441 = Id.create("1441", Osm.Way.class); + Link l14 = NetworkUtils.createLink(Id.createLinkId("14"), n1, n4, network, 1, 1, 300, 1); + Link l41 = NetworkUtils.createLink(Id.createLinkId("41"), n4, n1, network, 1, 1, 300, 1); + osmIds.put(l14.getId(), w1441); + osmIds.put(l41.getId(), w1441); + + Id w2332 = Id.create("2332", Osm.Way.class); + Link l23 = NetworkUtils.createLink(Id.createLinkId("23"), n2, n3, network, 1, 1, 300, 1); + Link l32 = NetworkUtils.createLink(Id.createLinkId("32"), n3, n2, network, 1, 1, 300, 1); + osmIds.put(l23.getId(), w2332); + osmIds.put(l32.getId(), w2332); + + Id w3443 = Id.create("3443", Osm.Way.class); + Link l34 = NetworkUtils.createLink(Id.createLinkId("34"), n3, n4, network, 1, 1, 300, 1); + Link l43 = NetworkUtils.createLink(Id.createLinkId("43"), n4, n3, network, 1, 1, 300, 1); + osmIds.put(l34.getId(), w3443); + osmIds.put(l43.getId(), w3443); + + Id w1551 = Id.create("1551", Osm.Way.class); + Link l15 = NetworkUtils.createLink(Id.createLinkId("15"), n1, n5, network, 1, 1, 300, 1); + Link l51 = NetworkUtils.createLink(Id.createLinkId("51"), n5, n1, network, 1, 1, 300, 1); + osmIds.put(l15.getId(), w1551); + osmIds.put(l51.getId(), w1551); + + network.addLink(l01); + network.addLink(l10); + network.addLink(l12); + network.addLink(l21); + network.addLink(l14); + network.addLink(l41); + network.addLink(l23); + network.addLink(l32); + network.addLink(l34); + network.addLink(l43); + network.addLink(l15); + network.addLink(l51); + + wayLinkMap.putAll(osmIds.entrySet().stream().collect( + Collectors.groupingBy(Entry::getValue, Collectors.mapping(Entry::getKey, Collectors.toList())))); + } + + @Test + void testFindLinks0() { + + OsmMultimodalNetworkConverter.OsmTurnRestriction tr = new OsmMultimodalNetworkConverter.OsmTurnRestriction(null, + List.of(Id.create("1221", Osm.Way.class), + Id.create("2332", Osm.Way.class)), + OsmMultimodalNetworkConverter.OsmTurnRestriction.RestrictionType.PROHIBITIVE); + LOG.info(tr.nextWayIds()); + + Id nodeId = Id.createNodeId("0"); // wrong! + LOG.info(nodeId); + Node node = network.getNodes().get(nodeId); + List> linkIds = OsmMultimodalNetworkConverter.findLinkIds(wayLinkMap, network, node, + tr.nextWayIds()); + LOG.info(linkIds); + + // NodeId does not fit to nextWayIds -> list of links should be empty + Assertions.assertEquals(Collections.emptyList(), linkIds); + } + + @Test + void testFindLinks1() { + + OsmMultimodalNetworkConverter.OsmTurnRestriction tr = new OsmMultimodalNetworkConverter.OsmTurnRestriction(null, + List.of(Id.create("1221", Osm.Way.class), + Id.create("2332", Osm.Way.class)), + OsmMultimodalNetworkConverter.OsmTurnRestriction.RestrictionType.PROHIBITIVE); + LOG.info(tr.nextWayIds()); + + Id nodeId = Id.createNodeId("1"); + LOG.info(nodeId); + Node node = network.getNodes().get(nodeId); + List> linkIds = OsmMultimodalNetworkConverter.findLinkIds(wayLinkMap, network, node, + tr.nextWayIds()); + LOG.info(linkIds); + + Assertions.assertEquals(List.of(Id.createLinkId("12"), Id.createLinkId("23")), linkIds); + } + + @Test + void testFindLinks2() { + + OsmMultimodalNetworkConverter.OsmTurnRestriction tr = new OsmMultimodalNetworkConverter.OsmTurnRestriction(null, + List.of(Id.create("1221", Osm.Way.class), + Id.create("2332", Osm.Way.class), + Id.create("3443", Osm.Way.class)), + OsmMultimodalNetworkConverter.OsmTurnRestriction.RestrictionType.PROHIBITIVE); + LOG.info(tr.nextWayIds()); + + Id nodeId = Id.createNodeId("1"); + LOG.info(nodeId); + Node node = network.getNodes().get(nodeId); + List> linkIds = OsmMultimodalNetworkConverter.findLinkIds(wayLinkMap, network, node, + tr.nextWayIds()); + LOG.info(linkIds); + + Assertions.assertEquals(List.of(Id.createLinkId("12"), Id.createLinkId("23"), Id.createLinkId("34")), linkIds); + } + + @Test + void testFindLinks3() { + + OsmMultimodalNetworkConverter.OsmTurnRestriction tr = new OsmMultimodalNetworkConverter.OsmTurnRestriction(null, + List.of(Id.create("1221", Osm.Way.class), + Id.create("2332", Osm.Way.class), + Id.create("3443", Osm.Way.class), + Id.create("3443", Osm.Way.class), + Id.create("2332", Osm.Way.class)), + OsmMultimodalNetworkConverter.OsmTurnRestriction.RestrictionType.PROHIBITIVE); + LOG.info(tr.nextWayIds()); + + Id nodeId = Id.createNodeId("1"); + LOG.info(nodeId); + Node node = network.getNodes().get(nodeId); + List> linkIds = OsmMultimodalNetworkConverter.findLinkIds(wayLinkMap, network, node, + tr.nextWayIds()); + LOG.info(linkIds); + + Assertions.assertEquals(List.of( + Id.createLinkId("12"), + Id.createLinkId("23"), + Id.createLinkId("34"), + Id.createLinkId("43"), + Id.createLinkId("32")), linkIds); + } + + @Test + void testFindLinks4() { + + OsmMultimodalNetworkConverter.OsmTurnRestriction tr = new OsmMultimodalNetworkConverter.OsmTurnRestriction(null, + List.of(Id.create("1221", Osm.Way.class), + Id.create("2332", Osm.Way.class), + Id.create("3443", Osm.Way.class), + Id.create("3443", Osm.Way.class), + Id.create("2332", Osm.Way.class), + Id.create("1221", Osm.Way.class), + Id.create("1551", Osm.Way.class)), + OsmMultimodalNetworkConverter.OsmTurnRestriction.RestrictionType.PROHIBITIVE); + LOG.info(tr.nextWayIds()); + + Id nodeId = Id.createNodeId("1"); + LOG.info(nodeId); + Node node = network.getNodes().get(nodeId); + List> linkIds = OsmMultimodalNetworkConverter.findLinkIds(wayLinkMap, network, node, + tr.nextWayIds()); + LOG.info(linkIds); + + Assertions.assertEquals(List.of( + Id.createLinkId("12"), + Id.createLinkId("23"), + Id.createLinkId("34"), + Id.createLinkId("43"), + Id.createLinkId("32"), + Id.createLinkId("21"), + Id.createLinkId("15")), linkIds); + } +} diff --git a/src/test/java/org/matsim/pt2matsim/osm/RoutableSubnetworkTest.java b/src/test/java/org/matsim/pt2matsim/osm/RoutableSubnetworkTest.java index f28530b4..fd2fc4f3 100644 --- a/src/test/java/org/matsim/pt2matsim/osm/RoutableSubnetworkTest.java +++ b/src/test/java/org/matsim/pt2matsim/osm/RoutableSubnetworkTest.java @@ -1,6 +1,7 @@ package org.matsim.pt2matsim.osm; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; import org.matsim.api.core.v01.network.Link; import org.matsim.api.core.v01.network.Network; import org.matsim.core.config.ConfigGroup; @@ -13,15 +14,13 @@ import java.util.HashSet; import java.util.Set; -import static org.junit.Assert.assertEquals; - /** * @author shoerl */ -public class RoutableSubnetworkTest { +class RoutableSubnetworkTest { @Test - public void customSubnetworks() { + void customSubnetworks() { // setup config OsmConverterConfigGroup osmConfig = OsmConverterConfigGroup.createDefaultConfig(); osmConfig.setOutputCoordinateSystem("WGS84"); @@ -52,7 +51,7 @@ public void customSubnetworks() { int carPassengerLinks = countModeLinks(converter.getNetwork(), "car_passenger"); // Since some car links are not connected, we expect that there are more (uncleaned) passenger links now - assertEquals(carLinks + 8, carPassengerLinks); + Assertions.assertEquals(carLinks + 8, carPassengerLinks); // II) Convert with a network layer for car_passenger osmConfig.addParameterSet(new OsmConverterConfigGroup.RoutableSubnetworkParams("car_passenger", Collections.singleton("car"))); @@ -64,7 +63,7 @@ public void customSubnetworks() { int carPassengerLinks2 = countModeLinks(converter2.getNetwork(), "car_passenger"); // Now car_passenger should be cleaned just as car... Thus it should be the same number. - assertEquals(carLinks2, carPassengerLinks2); + Assertions.assertEquals(carLinks2, carPassengerLinks2); } private static int countModeLinks(Network network, String mode) { diff --git a/src/test/java/org/matsim/pt2matsim/osm/lib/AllowedTagsFilterTest.java b/src/test/java/org/matsim/pt2matsim/osm/lib/AllowedTagsFilterTest.java index 083c086d..6e054211 100644 --- a/src/test/java/org/matsim/pt2matsim/osm/lib/AllowedTagsFilterTest.java +++ b/src/test/java/org/matsim/pt2matsim/osm/lib/AllowedTagsFilterTest.java @@ -1,8 +1,8 @@ package org.matsim.pt2matsim.osm.lib; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import java.util.HashMap; import java.util.Map; @@ -10,7 +10,7 @@ /** * @author polettif */ -public class AllowedTagsFilterTest { +class AllowedTagsFilterTest { private AllowedTagsFilter filter1; private AllowedTagsFilter filter2; @@ -21,7 +21,7 @@ public class AllowedTagsFilterTest { private Osm.Element way22; private Osm.Element node; - @Before + @BeforeEach public void prepare() { filter1 = new AllowedTagsFilter(); filter1.add(Osm.ElementType.WAY, "key", "value1"); @@ -63,43 +63,43 @@ public void prepare() { } @Test - public void matches() { - Assert.assertTrue(filter1.matches(way11)); - Assert.assertTrue(filter1.matches(way12)); - Assert.assertTrue(filter1.matches(way21)); - Assert.assertFalse(filter1.matches(way22)); - Assert.assertFalse(filter1.matches(node)); - - Assert.assertFalse(filter2.matches(way11)); - Assert.assertTrue(filter2.matches(way12)); - Assert.assertTrue(filter2.matches(way21)); - Assert.assertTrue(filter2.matches(way22)); - Assert.assertTrue(filter2.matches(node)); - - Assert.assertTrue(filter3.matches(way11)); - Assert.assertTrue(filter3.matches(way12)); - Assert.assertFalse(filter3.matches(way21)); - Assert.assertFalse(filter3.matches(way22)); + void matches() { + Assertions.assertTrue(filter1.matches(way11)); + Assertions.assertTrue(filter1.matches(way12)); + Assertions.assertTrue(filter1.matches(way21)); + Assertions.assertFalse(filter1.matches(way22)); + Assertions.assertFalse(filter1.matches(node)); + + Assertions.assertFalse(filter2.matches(way11)); + Assertions.assertTrue(filter2.matches(way12)); + Assertions.assertTrue(filter2.matches(way21)); + Assertions.assertTrue(filter2.matches(way22)); + Assertions.assertTrue(filter2.matches(node)); + + Assertions.assertTrue(filter3.matches(way11)); + Assertions.assertTrue(filter3.matches(way12)); + Assertions.assertFalse(filter3.matches(way21)); + Assertions.assertFalse(filter3.matches(way22)); } @Test - public void mergeFilter() { + void mergeFilter() { AllowedTagsFilter merged12 = new AllowedTagsFilter(); merged12.mergeFilter(filter1); merged12.mergeFilter(filter2); - Assert.assertTrue(merged12.matches(way11)); - Assert.assertTrue(merged12.matches(way12)); - Assert.assertTrue(merged12.matches(way21)); - Assert.assertTrue(merged12.matches(way22)); + Assertions.assertTrue(merged12.matches(way11)); + Assertions.assertTrue(merged12.matches(way12)); + Assertions.assertTrue(merged12.matches(way21)); + Assertions.assertTrue(merged12.matches(way22)); AllowedTagsFilter merged123 = new AllowedTagsFilter(); merged123.mergeFilter(filter1); merged123.mergeFilter(filter2); merged123.mergeFilter(filter3); - Assert.assertTrue(merged123.matches(way11)); - Assert.assertTrue(merged123.matches(way12)); - Assert.assertFalse(merged123.matches(way21)); - Assert.assertFalse(merged123.matches(way22)); + Assertions.assertTrue(merged123.matches(way11)); + Assertions.assertTrue(merged123.matches(way12)); + Assertions.assertFalse(merged123.matches(way21)); + Assertions.assertFalse(merged123.matches(way22)); } } \ No newline at end of file diff --git a/src/test/java/org/matsim/pt2matsim/plausibility/MappingAnalysisTest.java b/src/test/java/org/matsim/pt2matsim/plausibility/MappingAnalysisTest.java index 3ea022f7..3fae35fa 100644 --- a/src/test/java/org/matsim/pt2matsim/plausibility/MappingAnalysisTest.java +++ b/src/test/java/org/matsim/pt2matsim/plausibility/MappingAnalysisTest.java @@ -1,8 +1,8 @@ package org.matsim.pt2matsim.plausibility; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.matsim.api.core.v01.Id; import org.matsim.api.core.v01.network.Network; import org.matsim.pt.transitSchedule.api.TransitLine; @@ -22,7 +22,7 @@ /** * @author polettif */ -public class MappingAnalysisTest { +class MappingAnalysisTest { private MappingAnalysis analysis; private Id lineA = Id.create("lineA", TransitLine.class); @@ -31,7 +31,7 @@ public class MappingAnalysisTest { private Id routeA2 = Id.create("routeA2", TransitRoute.class); private Id routeB = Id.create("routeB", TransitRoute.class); - @Before + @BeforeEach public void prepare() { PublicTransitMappingConfigGroup ptmConfig = PTMapperTest.initPTMConfig(); Network network = NetworkToolsTest.initNetwork(); @@ -45,21 +45,21 @@ public void prepare() { } @Test - public void quantiles() { - Assert.assertEquals(7, analysis.getQ8585(), 0.001); + void quantiles() { + Assertions.assertEquals(7, analysis.getQ8585(), 0.001); TreeMap quantilesA1 = analysis.getQuantiles(lineA, routeA1); - Assert.assertEquals(0.0, quantilesA1.get(0), 0.001); + Assertions.assertEquals(0.0, quantilesA1.get(0), 0.001); TreeMap quantilesA2 = analysis.getQuantiles(lineA, routeA2); - Assert.assertEquals(ShapeToolsTest.offset, quantilesA2.get(50), 0.001); + Assertions.assertEquals(ShapeToolsTest.offset, quantilesA2.get(50), 0.001); TreeMap quantilesB = analysis.getQuantiles(lineB, routeB); - Assert.assertEquals(0.0, quantilesB.get(0), 0.001); + Assertions.assertEquals(0.0, quantilesB.get(0), 0.001); } @Test - public void lengthRatios() { + void lengthRatios() { analysis.getLengthRatio(lineA, routeA1); } } \ No newline at end of file diff --git a/src/test/java/org/matsim/pt2matsim/plausibility/PlausibilityCheckTest.java b/src/test/java/org/matsim/pt2matsim/plausibility/PlausibilityCheckTest.java index fb0d44f2..d30ec248 100644 --- a/src/test/java/org/matsim/pt2matsim/plausibility/PlausibilityCheckTest.java +++ b/src/test/java/org/matsim/pt2matsim/plausibility/PlausibilityCheckTest.java @@ -1,10 +1,9 @@ package org.matsim.pt2matsim.plausibility; -import org.locationtech.jts.util.Assert; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; import org.matsim.api.core.v01.network.Network; import org.matsim.pt.transitSchedule.api.TransitSchedule; import org.matsim.pt2matsim.plausibility.log.PlausibilityWarning; @@ -15,23 +14,24 @@ import org.matsim.pt2matsim.tools.ScheduleToolsTest; import java.io.File; +import java.nio.file.Path; import java.util.Map; import java.util.Set; /** * @author polettif */ -public class PlausibilityCheckTest { +class PlausibilityCheckTest { - @Rule - public TemporaryFolder temporaryFolder = new TemporaryFolder(); + @TempDir + public Path temporaryFolder; private String testDir; private PlausibilityCheck check; - @Before + @BeforeEach public void prepare() { - testDir = temporaryFolder.getRoot().toString(); + testDir = temporaryFolder.toString(); TransitSchedule s = ScheduleToolsTest.initSchedule(); Network n = NetworkToolsTest.initNetwork(); @@ -43,22 +43,22 @@ public void prepare() { } @Test - public void checks() { + void checks() { Map> warnings = check.getWarnings(); - Assert.equals(0, warnings.get(PlausibilityWarning.Type.ArtificialLinkWarning).size()); - Assert.equals(0, warnings.get(PlausibilityWarning.Type.LoopWarning).size()); - Assert.equals(4, warnings.get(PlausibilityWarning.Type.DirectionChangeWarning).size()); - Assert.equals(0, warnings.get(PlausibilityWarning.Type.TravelTimeWarning).size()); + Assertions.assertEquals(0, warnings.get(PlausibilityWarning.Type.ArtificialLinkWarning).size()); + Assertions.assertEquals(0, warnings.get(PlausibilityWarning.Type.LoopWarning).size()); + Assertions.assertEquals(4, warnings.get(PlausibilityWarning.Type.DirectionChangeWarning).size()); + Assertions.assertEquals(0, warnings.get(PlausibilityWarning.Type.TravelTimeWarning).size()); } @Test - public void writeGeojson() { + void writeGeojson() { check.writeResultsGeojson(testDir + "plausibility.geojson"); new File(testDir + "plausibility.geojson").delete(); } @Test - public void staticRun() { + void staticRun() { String scheduleFile = testDir + "testSchedule.xml"; String networkFile = testDir + "testNetwork.xml"; String outputfolder = testDir + "plausibility/"; diff --git a/src/test/java/org/matsim/pt2matsim/run/gis/Network2GeojsonTest.java b/src/test/java/org/matsim/pt2matsim/run/gis/Network2GeojsonTest.java index 3cabd575..dbb41065 100644 --- a/src/test/java/org/matsim/pt2matsim/run/gis/Network2GeojsonTest.java +++ b/src/test/java/org/matsim/pt2matsim/run/gis/Network2GeojsonTest.java @@ -1,7 +1,7 @@ package org.matsim.pt2matsim.run.gis; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.matsim.api.core.v01.network.Network; import org.matsim.core.utils.geometry.transformations.TransformationFactory; import org.matsim.pt2matsim.tools.NetworkToolsTest; @@ -11,17 +11,17 @@ /** * @author polettif */ -public class Network2GeojsonTest { +class Network2GeojsonTest { private Network network; - @Before + @BeforeEach public void prepare() { this.network = NetworkToolsTest.initNetwork(); } @Test - public void run() { + void run() { Network2Geojson.run(TransformationFactory.CH1903_LV03_Plus, network, "test/nodes.geojson", "test/links.geojson"); new File("test/nodes.geojson").delete(); new File("test/links.geojson").delete(); diff --git a/src/test/java/org/matsim/pt2matsim/run/gis/Schedule2GeojsonTest.java b/src/test/java/org/matsim/pt2matsim/run/gis/Schedule2GeojsonTest.java index 7f9e1bde..f936982a 100644 --- a/src/test/java/org/matsim/pt2matsim/run/gis/Schedule2GeojsonTest.java +++ b/src/test/java/org/matsim/pt2matsim/run/gis/Schedule2GeojsonTest.java @@ -1,7 +1,7 @@ package org.matsim.pt2matsim.run.gis; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.matsim.api.core.v01.network.Network; import org.matsim.core.utils.geometry.transformations.TransformationFactory; import org.matsim.pt.transitSchedule.api.TransitSchedule; @@ -13,19 +13,19 @@ /** * @author polettif */ -public class Schedule2GeojsonTest { +class Schedule2GeojsonTest { private TransitSchedule schedule; private Network network; - @Before + @BeforeEach public void prepare() { this.schedule = ScheduleToolsTest.initSchedule(); this.network = NetworkToolsTest.initNetwork(); } @Test - public void run() { + void run() { Schedule2Geojson.run(TransformationFactory.CH1903_LV03_Plus, this.schedule, this.network, "test/schedule.geojson"); new File("test/schedule.geojson").delete(); } diff --git a/src/test/java/org/matsim/pt2matsim/tools/CoordToolsTest.java b/src/test/java/org/matsim/pt2matsim/tools/CoordToolsTest.java index d2f2b423..3b52489a 100644 --- a/src/test/java/org/matsim/pt2matsim/tools/CoordToolsTest.java +++ b/src/test/java/org/matsim/pt2matsim/tools/CoordToolsTest.java @@ -1,15 +1,13 @@ package org.matsim.pt2matsim.tools; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; import org.matsim.api.core.v01.Coord; import org.matsim.core.utils.geometry.CoordUtils; import java.util.HashMap; import java.util.Map; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - /** * @author polettif */ @@ -57,29 +55,29 @@ public class CoordToolsTest { */ @Test - public void getAzimuth() { - assertEquals(0, 200* CoordTools.getAzimuth(coordA,coordD)/Math.PI, testDelta); - assertEquals(50, 200* CoordTools.getAzimuth(coordA,coordC)/Math.PI, testDelta); - assertEquals(100, 200* CoordTools.getAzimuth(coordA,coordB)/Math.PI, testDelta); - assertEquals(150, 200* CoordTools.getAzimuth(coordA,coordI)/Math.PI, testDelta); - assertEquals(200, 200* CoordTools.getAzimuth(coordA,coordH)/Math.PI, testDelta); - assertEquals(250, 200* CoordTools.getAzimuth(coordA,coordG)/Math.PI, testDelta); - assertEquals(300, 200* CoordTools.getAzimuth(coordA,coordF)/Math.PI, testDelta); - assertEquals(350, 200* CoordTools.getAzimuth(coordA,coordE)/Math.PI, testDelta); + void getAzimuth() { + Assertions.assertEquals(0, 200 * CoordTools.getAzimuth(coordA, coordD) / Math.PI, testDelta); + Assertions.assertEquals(50, 200 * CoordTools.getAzimuth(coordA, coordC) / Math.PI, testDelta); + Assertions.assertEquals(100, 200 * CoordTools.getAzimuth(coordA, coordB) / Math.PI, testDelta); + Assertions.assertEquals(150, 200 * CoordTools.getAzimuth(coordA, coordI) / Math.PI, testDelta); + Assertions.assertEquals(200, 200 * CoordTools.getAzimuth(coordA, coordH) / Math.PI, testDelta); + Assertions.assertEquals(250, 200 * CoordTools.getAzimuth(coordA, coordG) / Math.PI, testDelta); + Assertions.assertEquals(300, 200 * CoordTools.getAzimuth(coordA, coordF) / Math.PI, testDelta); + Assertions.assertEquals(350, 200 * CoordTools.getAzimuth(coordA, coordE) / Math.PI, testDelta); } @Test - public void getAzimuthDiff() { - assertEquals(100, 200*CoordTools.getAngleDiff(coordA, coordD, coordC)/Math.PI, testDelta); - assertEquals(150, 200*CoordTools.getAngleDiff(coordA, coordD, coordB)/Math.PI, testDelta); - assertEquals(-100, 200*CoordTools.getAngleDiff(coordA, coordB, coordC)/Math.PI, testDelta); - assertEquals(-150, 200*CoordTools.getAngleDiff(coordA, coordB, coordD)/Math.PI, testDelta); + void getAzimuthDiff() { + Assertions.assertEquals(100, 200 * CoordTools.getAngleDiff(coordA, coordD, coordC) / Math.PI, testDelta); + Assertions.assertEquals(150, 200 * CoordTools.getAngleDiff(coordA, coordD, coordB) / Math.PI, testDelta); + Assertions.assertEquals(-100, 200 * CoordTools.getAngleDiff(coordA, coordB, coordC) / Math.PI, testDelta); + Assertions.assertEquals(-150, 200 * CoordTools.getAngleDiff(coordA, coordB, coordD) / Math.PI, testDelta); - assertEquals(50, 200*CoordTools.getAngleDiff(coordH, coordA, coordC)/Math.PI, testDelta); - assertEquals(-50, 200*CoordTools.getAngleDiff(coordH, coordA, coordE)/Math.PI, testDelta); + Assertions.assertEquals(50, 200 * CoordTools.getAngleDiff(coordH, coordA, coordC) / Math.PI, testDelta); + Assertions.assertEquals(-50, 200 * CoordTools.getAngleDiff(coordH, coordA, coordE) / Math.PI, testDelta); - assertEquals(0, 200*CoordTools.getAngleDiff(coordF, coordA, coordB)/Math.PI, testDelta); - assertEquals(200, 200*CoordTools.getAngleDiff(coordA, coordF, coordB)/Math.PI, testDelta); + Assertions.assertEquals(0, 200 * CoordTools.getAngleDiff(coordF, coordA, coordB) / Math.PI, testDelta); + Assertions.assertEquals(200, 200 * CoordTools.getAngleDiff(coordA, coordF, coordB) / Math.PI, testDelta); Map coords = new HashMap<>(); coords.put("A", coordA); coords.put("B", coordB); coords.put("C", coordC); coords.put("D", coordD); @@ -91,8 +89,8 @@ public void getAzimuthDiff() { for(Map.Entry c2 : coords.entrySet()) { if(!c1.equals(c0) && !c2.equals(c0) && !c1.equals(c2)) { double diff = CoordTools.getAngleDiff(c0.getValue(), c1.getValue(), c2.getValue()); - assertTrue(diff <= Math.PI); - assertTrue(diff >= -Math.PI); + Assertions.assertTrue(diff <= Math.PI); + Assertions.assertTrue(diff >= -Math.PI); } } } @@ -101,26 +99,26 @@ public void getAzimuthDiff() { } @Test - public void calcNewPoint() { + void calcNewPoint() { Coord newPointD = CoordTools.calcNewPoint(coordA, 0.00 * Math.PI, CoordUtils.calcEuclideanDistance(coordA, coordD)); - assertEquals(newPointD.getX(), coordD.getX(), testDelta); - assertEquals(newPointD.getY(), coordD.getY(), testDelta); + Assertions.assertEquals(newPointD.getX(), coordD.getX(), testDelta); + Assertions.assertEquals(newPointD.getY(), coordD.getY(), testDelta); Coord newPointX = CoordTools.calcNewPoint(coordA, 0.25 * Math.PI, CoordUtils.calcEuclideanDistance(coordA, coordC)); - assertEquals(newPointX.getX(), coordC.getX(), testDelta); - assertEquals(newPointX.getY(), coordC.getY(), testDelta); + Assertions.assertEquals(newPointX.getX(), coordC.getX(), testDelta); + Assertions.assertEquals(newPointX.getY(), coordC.getY(), testDelta); Coord duplicateCoordZ = CoordTools.calcNewPoint(coordA, CoordTools.getAzimuth(coordA, coordZ), CoordUtils.calcEuclideanDistance(coordA, coordZ)); - assertEquals(duplicateCoordZ.getX(), coordZ.getX(), testDelta); - assertEquals(duplicateCoordZ.getY(), coordZ.getY(), testDelta); + Assertions.assertEquals(duplicateCoordZ.getX(), coordZ.getX(), testDelta); + Assertions.assertEquals(duplicateCoordZ.getY(), coordZ.getY(), testDelta); Coord newPointB = CoordTools.calcNewPoint(coordA, 0.50 * Math.PI, 20); - assertEquals(newPointB.getX(), coordB.getX(), testDelta); - assertEquals(newPointB.getY(), coordB.getY(), testDelta); + Assertions.assertEquals(newPointB.getX(), coordB.getX(), testDelta); + Assertions.assertEquals(newPointB.getY(), coordB.getY(), testDelta); Coord newPointG = CoordTools.calcNewPoint(coordA, 1.25*Math.PI, CoordUtils.calcEuclideanDistance(coordA, coordG)); - assertEquals(newPointG.getX(), coordG.getX(), testDelta); - assertEquals(newPointG.getY(), coordG.getY(), testDelta); + Assertions.assertEquals(newPointG.getX(), coordG.getX(), testDelta); + Assertions.assertEquals(newPointG.getY(), coordG.getY(), testDelta); } } \ No newline at end of file diff --git a/src/test/java/org/matsim/pt2matsim/tools/CsvToolsTest.java b/src/test/java/org/matsim/pt2matsim/tools/CsvToolsTest.java index 730f5ea0..38236c6f 100644 --- a/src/test/java/org/matsim/pt2matsim/tools/CsvToolsTest.java +++ b/src/test/java/org/matsim/pt2matsim/tools/CsvToolsTest.java @@ -1,7 +1,7 @@ package org.matsim.pt2matsim.tools; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; import org.matsim.core.utils.collections.MapUtils; import java.io.File; @@ -12,10 +12,10 @@ /** * @author polettif */ -public class CsvToolsTest { +class CsvToolsTest { @Test - public void mapCsvTest() throws IOException { + void mapCsvTest() throws IOException { String file = "test/testfile.csv"; Map> testMap = new HashMap<>(); @@ -30,7 +30,7 @@ public void mapCsvTest() throws IOException { CsvTools.writeNestedMapToFile(testMap, file); Map> readMap = CsvTools.readNestedMapFromFile(file, false); - Assert.assertEquals(testMap, readMap); + Assertions.assertEquals(testMap, readMap); File f = new File(file); boolean del = f.delete(); diff --git a/src/test/java/org/matsim/pt2matsim/tools/GtfsToolsTest.java b/src/test/java/org/matsim/pt2matsim/tools/GtfsToolsTest.java index c9c53ce2..a248d5a2 100644 --- a/src/test/java/org/matsim/pt2matsim/tools/GtfsToolsTest.java +++ b/src/test/java/org/matsim/pt2matsim/tools/GtfsToolsTest.java @@ -1,9 +1,9 @@ package org.matsim.pt2matsim.tools; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.matsim.pt2matsim.gtfs.GtfsFeed; import org.matsim.pt2matsim.gtfs.GtfsFeedImpl; @@ -14,19 +14,19 @@ /** * @author polettif */ -public class GtfsToolsTest { +class GtfsToolsTest { private GtfsFeed gtfsFeed; private String output = "test/gtfs-feed-rewrite/"; - @Before + @BeforeEach public void prepare() { gtfsFeed = new GtfsFeedImpl("test/gtfs-feed/"); new File(output).mkdir(); } @Test - public void writeFiles() throws IOException { + void writeFiles() throws IOException { GtfsTools.writeStopTimes(gtfsFeed.getTrips().values(), output); GtfsTools.writeStops(gtfsFeed.getStops().values(), output); GtfsTools.writeTrips(gtfsFeed.getTrips().values(), output); @@ -34,16 +34,16 @@ public void writeFiles() throws IOException { } @Test - public void getDayWithMostServices() { - Assert.assertEquals(LocalDate.of(2018, 10, 2), GtfsTools.getDayWithMostServices(gtfsFeed)); + void getDayWithMostServices() { + Assertions.assertEquals(LocalDate.of(2018, 10, 2), GtfsTools.getDayWithMostServices(gtfsFeed)); } @Test - public void getDayWithMostTrips() { - Assert.assertEquals(LocalDate.of(2018, 10, 5), GtfsTools.getDayWithMostTrips(gtfsFeed)); + void getDayWithMostTrips() { + Assertions.assertEquals(LocalDate.of(2018, 10, 5), GtfsTools.getDayWithMostTrips(gtfsFeed)); } - @After + @AfterEach public void clean() { new File(output).delete(); } diff --git a/src/test/java/org/matsim/pt2matsim/tools/NetworkToolsTest.java b/src/test/java/org/matsim/pt2matsim/tools/NetworkToolsTest.java index bbe727ff..574392e7 100644 --- a/src/test/java/org/matsim/pt2matsim/tools/NetworkToolsTest.java +++ b/src/test/java/org/matsim/pt2matsim/tools/NetworkToolsTest.java @@ -1,8 +1,8 @@ package org.matsim.pt2matsim.tools; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.matsim.api.core.v01.Coord; import org.matsim.api.core.v01.Id; import org.matsim.api.core.v01.network.Link; @@ -14,7 +14,6 @@ import java.util.*; -import static org.junit.Assert.assertTrue; import static org.matsim.pt2matsim.tools.CoordToolsTest.*; /** @@ -148,7 +147,7 @@ public static Network initNetwork() { return net; } - @Before + @BeforeEach public void prepare() { network = initNetwork(); } @@ -158,39 +157,40 @@ private Link getLink(String id) { } @Test - public void getNearestLink() { + void getNearestLink() { Coord testR = new Coord(2600041.0, 1200050.0); Coord testL = new Coord(2600039.0, 1200050.0); Node nearestNode = NetworkUtils.getNearestNode(network, testR); - Assert.assertEquals("A", nearestNode.getId().toString()); + Assertions.assertEquals("A", nearestNode.getId().toString()); - Assert.assertEquals("AD", NetworkTools.getNearestLink(network, testR, 4).getId().toString()); - Assert.assertEquals("DA", NetworkTools.getNearestLink(network, testL, 4).getId().toString()); + Assertions.assertEquals("AD", NetworkTools.getNearestLink(network, testR, 4).getId().toString()); + Assertions.assertEquals("DA", NetworkTools.getNearestLink(network, testL, 4).getId().toString()); } @Test - public void getOppositeLink() { + void getOppositeLink() { Network network = initNetwork(); - Assert.assertEquals("AD", NetworkTools.getOppositeLink(network.getLinks().get(Id.createLinkId("DA"))).getId().toString()); + Assertions.assertEquals("AD", + NetworkTools.getOppositeLink(network.getLinks().get(Id.createLinkId("DA"))).getId().toString()); } @Test - public void coordIsOnRightSideOfLink() { + void coordIsOnRightSideOfLink() { Coord c = new Coord(2600039.0, 1200041.0); - Assert.assertTrue(NetworkTools.coordIsOnRightSideOfLink(c, network.getLinks().get(Id.createLinkId("IG")))); - Assert.assertTrue(NetworkTools.coordIsOnRightSideOfLink(c, network.getLinks().get(Id.createLinkId("FE")))); - Assert.assertTrue(NetworkTools.coordIsOnRightSideOfLink(c, network.getLinks().get(Id.createLinkId("ED")))); - Assert.assertTrue(NetworkTools.coordIsOnRightSideOfLink(c, network.getLinks().get(Id.createLinkId("DA")))); + Assertions.assertTrue(NetworkTools.coordIsOnRightSideOfLink(c, network.getLinks().get(Id.createLinkId("IG")))); + Assertions.assertTrue(NetworkTools.coordIsOnRightSideOfLink(c, network.getLinks().get(Id.createLinkId("FE")))); + Assertions.assertTrue(NetworkTools.coordIsOnRightSideOfLink(c, network.getLinks().get(Id.createLinkId("ED")))); + Assertions.assertTrue(NetworkTools.coordIsOnRightSideOfLink(c, network.getLinks().get(Id.createLinkId("DA")))); - Assert.assertFalse(NetworkTools.coordIsOnRightSideOfLink(c, network.getLinks().get(Id.createLinkId("AD")))); - Assert.assertFalse(NetworkTools.coordIsOnRightSideOfLink(c, network.getLinks().get(Id.createLinkId("AX")))); + Assertions.assertFalse(NetworkTools.coordIsOnRightSideOfLink(c, network.getLinks().get(Id.createLinkId("AD")))); + Assertions.assertFalse(NetworkTools.coordIsOnRightSideOfLink(c, network.getLinks().get(Id.createLinkId("AX")))); } @Test - public void linkSequenceHasDuplicateLink() { + void linkSequenceHasDuplicateLink() { List seq = new ArrayList<>(); seq.add(getLink("XA")); seq.add(getLink("AB")); @@ -201,64 +201,64 @@ public void linkSequenceHasDuplicateLink() { seq.add(getLink("BI")); seq.add(getLink("IH")); - assertTrue(NetworkTools.linkSequenceHasDuplicateLink(seq)); + Assertions.assertTrue(NetworkTools.linkSequenceHasDuplicateLink(seq)); } @Test - public void linkSequenceHasUTurns() { + void linkSequenceHasUTurns() { List seq = new ArrayList<>(); seq.add(getLink("AB")); seq.add(getLink("BC")); seq.add(getLink("CB")); seq.add(getLink("BI")); - assertTrue(NetworkTools.linkSequenceHasUTurns(seq)); + Assertions.assertTrue(NetworkTools.linkSequenceHasUTurns(seq)); } @Test - public void getSingleFilePrecedingLink() { - Assert.assertEquals("AH", NetworkTools.getSingleFilePrecedingLink(getLink("HZ")).getId().toString()); - Assert.assertEquals("ZI", NetworkTools.getSingleFileSucceedingLink(getLink("HZ")).getId().toString()); + void getSingleFilePrecedingLink() { + Assertions.assertEquals("AH", NetworkTools.getSingleFilePrecedingLink(getLink("HZ")).getId().toString()); + Assertions.assertEquals("ZI", NetworkTools.getSingleFileSucceedingLink(getLink("HZ")).getId().toString()); } @Test - public void reduceSequencedLinks() { + void reduceSequencedLinks() { List seq = new ArrayList<>(); seq.add(getLink("AH")); seq.add(getLink("HZ")); seq.add(getLink("ZI")); NetworkTools.reduceSequencedLinks(seq, new Coord(2600050.0, 1200035.0)); - Assert.assertEquals(1, seq.size()); - Assert.assertEquals("AH", seq.get(0).getId().toString()); + Assertions.assertEquals(1, seq.size()); + Assertions.assertEquals("AH", seq.get(0).getId().toString()); Collection seqAll = new HashSet<>(network.getLinks().values()); NetworkTools.reduceSequencedLinks(seqAll, new Coord(2600041.0, 1200042.0)); - Assert.assertEquals(10, network.getLinks().size()-seqAll.size()); + Assertions.assertEquals(10, network.getLinks().size() - seqAll.size()); } @Test - public void calcRouteLength() { + void calcRouteLength() { List seq = new ArrayList<>(); seq.add(getLink("AB")); seq.add(getLink("BC")); seq.add(getLink("CD")); seq.add(getLink("DA")); - Assert.assertEquals(80.0, NetworkTools.calcRouteLength(seq, true), 0.0001); + Assertions.assertEquals(80.0, NetworkTools.calcRouteLength(seq, true), 0.0001); } @Test - public void findClosestLinks() { + void findClosestLinks() { Node node = network.getNodes().get(Id.createNodeId("G")); Coord coordToLookFrom = new Coord(node.getCoord().getX() + 2, node.getCoord().getY() + 2); Map> cars = NetworkTools.findClosestLinks(network, coordToLookFrom, 3, Collections.singleton("car")); - Assert.assertEquals(1, cars.keySet().size()); - Assert.assertEquals(4, cars.get(2.0).size()); + Assertions.assertEquals(1, cars.keySet().size()); + Assertions.assertEquals(4, cars.get(2.0).size()); Map> nullTransportModes = NetworkTools.findClosestLinks(network, coordToLookFrom, 3, null); - Assert.assertEquals(1, nullTransportModes.keySet().size()); - Assert.assertEquals(4, nullTransportModes.get(2.0).size()); + Assertions.assertEquals(1, nullTransportModes.keySet().size()); + Assertions.assertEquals(4, nullTransportModes.get(2.0).size()); } diff --git a/src/test/java/org/matsim/pt2matsim/tools/ScheduleToolsTest.java b/src/test/java/org/matsim/pt2matsim/tools/ScheduleToolsTest.java index 06dc5395..34b4bc35 100644 --- a/src/test/java/org/matsim/pt2matsim/tools/ScheduleToolsTest.java +++ b/src/test/java/org/matsim/pt2matsim/tools/ScheduleToolsTest.java @@ -1,8 +1,8 @@ package org.matsim.pt2matsim.tools; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; import org.matsim.api.core.v01.Coord; import org.matsim.api.core.v01.Id; import org.matsim.api.core.v01.network.Link; @@ -179,16 +179,16 @@ public static TransitSchedule initUnmappedSchedule() { } @Test - public void validateTestSchedule() { + void validateTestSchedule() { ValidationResult result = TransitScheduleValidator.validateAll(ScheduleToolsTest.initSchedule(), NetworkToolsTest.initNetwork()); for(ValidationIssue issue : result.getIssues()) { System.err.println(issue.getSeverity() + ": " + issue.getMessage()); } - Assert.assertTrue(result.isValid()); + Assertions.assertTrue(result.isValid()); } @Test - public void mergeSchedules() { + void mergeSchedules() { TransitSchedule testSchedule = initSchedule(); ScheduleTools.mergeSchedules(testSchedule, initSchedule()); @@ -201,13 +201,13 @@ public void mergeSchedules() { nRoutesInit += l.getRoutes().size(); } - Assert.assertEquals(testSchedule.getTransitLines().size(), initSchedule().getTransitLines().size()); - Assert.assertEquals(nRoutesInit, nRoutesTest); - Assert.assertEquals(testSchedule.getFacilities().size(), initSchedule().getFacilities().size()); + Assertions.assertEquals(testSchedule.getTransitLines().size(), initSchedule().getTransitLines().size()); + Assertions.assertEquals(nRoutesInit, nRoutesTest); + Assertions.assertEquals(testSchedule.getFacilities().size(), initSchedule().getFacilities().size()); } @Test - public void mergeSchedulesOffset() { + void mergeSchedulesOffset() { TransitSchedule baseSchedule = initSchedule(); TransitSchedule testSchedule = initSchedule(); ScheduleTools.mergeSchedules(testSchedule, baseSchedule, 24 * 3600, 60 * 3600); @@ -226,14 +226,14 @@ public void mergeSchedulesOffset() { } } - Assert.assertEquals(testSchedule.getTransitLines().size(), initSchedule().getTransitLines().size()); - Assert.assertEquals(nRoutesInit, nRoutesTest); - Assert.assertEquals(testSchedule.getFacilities().size(), initSchedule().getFacilities().size()); - Assert.assertEquals(nDeparturesInit * 2, nDeparturesTest); + Assertions.assertEquals(testSchedule.getTransitLines().size(), initSchedule().getTransitLines().size()); + Assertions.assertEquals(nRoutesInit, nRoutesTest); + Assertions.assertEquals(testSchedule.getFacilities().size(), initSchedule().getFacilities().size()); + Assertions.assertEquals(nDeparturesInit * 2, nDeparturesTest); } @Test - public void mergeSchedulesOffsetTimeLimit() { + void mergeSchedulesOffsetTimeLimit() { TransitSchedule baseSchedule = initSchedule(); TransitSchedule testSchedule = initSchedule(); ScheduleTools.mergeSchedules(testSchedule, baseSchedule, 24 * 3600, 24 * 3600 + 12.5 * 3600); @@ -252,14 +252,14 @@ public void mergeSchedulesOffsetTimeLimit() { } } - Assert.assertEquals(testSchedule.getTransitLines().size(), initSchedule().getTransitLines().size()); - Assert.assertEquals(nRoutesInit, nRoutesTest); - Assert.assertEquals(testSchedule.getFacilities().size(), initSchedule().getFacilities().size()); - Assert.assertEquals(nDeparturesInit + 6, nDeparturesTest); + Assertions.assertEquals(testSchedule.getTransitLines().size(), initSchedule().getTransitLines().size()); + Assertions.assertEquals(nRoutesInit, nRoutesTest); + Assertions.assertEquals(testSchedule.getFacilities().size(), initSchedule().getFacilities().size()); + Assertions.assertEquals(nDeparturesInit + 6, nDeparturesTest); } @Test - public void freespeedBasedOnSchedule() { + void freespeedBasedOnSchedule() { TransitSchedule schedule = initSchedule(); Network network = NetworkToolsTest.initNetwork(); Network baseNetwork = NetworkToolsTest.initNetwork(); @@ -286,6 +286,6 @@ public void freespeedBasedOnSchedule() { linksChanged.add(link.getId()); } } - Assert.assertEquals(linksUsedBySchedule, linksChanged); + Assertions.assertEquals(linksUsedBySchedule, linksChanged); } } \ No newline at end of file diff --git a/src/test/java/org/matsim/pt2matsim/tools/ShapeToolsTest.java b/src/test/java/org/matsim/pt2matsim/tools/ShapeToolsTest.java index 5e3675ab..22839364 100644 --- a/src/test/java/org/matsim/pt2matsim/tools/ShapeToolsTest.java +++ b/src/test/java/org/matsim/pt2matsim/tools/ShapeToolsTest.java @@ -1,8 +1,8 @@ package org.matsim.pt2matsim.tools; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.matsim.api.core.v01.Coord; import org.matsim.api.core.v01.Id; import org.matsim.api.core.v01.network.Node; @@ -67,7 +67,7 @@ private static Coord offset(Coord c) { return new Coord(c.getX() + offset, c.getY() + offset); } - @Before + @BeforeEach public void prepare() { Map, RouteShape> shapes = initShapes(); this.shapeA1 = shapes.get(Id.create("A1", RouteShape.class)); @@ -76,26 +76,26 @@ public void prepare() { } @Test - public void calcMinDistanceToShape() { - Assert.assertEquals(0, ShapeTools.calcMinDistanceToShape(coordX, shapeB), d); - Assert.assertEquals(5, ShapeTools.calcMinDistanceToShape(new Coord(2600035, 1200035), shapeB), d); + void calcMinDistanceToShape() { + Assertions.assertEquals(0, ShapeTools.calcMinDistanceToShape(coordX, shapeB), d); + Assertions.assertEquals(5, ShapeTools.calcMinDistanceToShape(new Coord(2600035, 1200035), shapeB), d); Coord bx = CoordTools.calcNewPoint(coordX, CoordTools.getAzimuth(coordX, coordB), CoordUtils.calcEuclideanDistance(coordX, coordB) / 2); - Assert.assertEquals(0, ShapeTools.calcMinDistanceToShape(bx, shapeA1), d); + Assertions.assertEquals(0, ShapeTools.calcMinDistanceToShape(bx, shapeA1), d); } @Test - public void getNodesWithinBuffer() { + void getNodesWithinBuffer() { Collection nodes = ShapeTools.getNodesWithinBuffer(NetworkToolsTest.initNetwork(), shapeB, 1.0); - Assert.assertEquals(9, nodes.size()); + Assertions.assertEquals(9, nodes.size()); } @Test - public void getShapeLength() { + void getShapeLength() { double lengthA1 = ShapeTools.getShapeLength(shapeA1); double lengthA2 = ShapeTools.getShapeLength(shapeA2); - Assert.assertEquals(lengthA1, lengthA2, d); + Assertions.assertEquals(lengthA1, lengthA2, d); } } \ No newline at end of file diff --git a/test/BrienzRothornBahn-HAFAS/BETRIEB_DE b/test/BrienzRothornBahn-HAFAS/BETRIEB_DE index b3dc2045..df8c96d3 100644 --- a/test/BrienzRothornBahn-HAFAS/BETRIEB_DE +++ b/test/BrienzRothornBahn-HAFAS/BETRIEB_DE @@ -1,2 +1,3 @@ +* Kommentarzeile 00075 K "BRB" L "BRB" V "Brienz Rothorn Bahn AG" 00075 : 000104 diff --git a/test/BrienzRothornBahn-HAFAS/BFKOORD_GEO b/test/BrienzRothornBahn-HAFAS/BFKOORD_GEO deleted file mode 100644 index c1bfa2b5..00000000 --- a/test/BrienzRothornBahn-HAFAS/BFKOORD_GEO +++ /dev/null @@ -1,3 +0,0 @@ -8508350 8.038089 46.755214 566 % Brienz BRB -8508351 8.019845 46.772373 1346 % Planalp -8508352 8.038447 46.787399 2252 % Brienzer Rothorn diff --git a/test/BrienzRothornBahn-HAFAS/BFKOORD_WGS b/test/BrienzRothornBahn-HAFAS/BFKOORD_WGS new file mode 100644 index 00000000..a251e5e7 --- /dev/null +++ b/test/BrienzRothornBahn-HAFAS/BFKOORD_WGS @@ -0,0 +1,4 @@ +* Kommentarzeile +8508350 8.0380890 46.7552140 566 % Brienz BRB +8508351 8.0198450 46.7723730 1346 % Planalp +8508352 8.0384470 46.7873990 2252 % Brienzer Rothorn diff --git a/test/BrienzRothornBahn-HAFAS/BITFELD b/test/BrienzRothornBahn-HAFAS/BITFELD index 36de90af..7de27864 100644 --- a/test/BrienzRothornBahn-HAFAS/BITFELD +++ b/test/BrienzRothornBahn-HAFAS/BITFELD @@ -1 +1,2 @@ +* Kommentarzeile 003499 F00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 diff --git a/test/BrienzRothornBahn-HAFAS/FPLAN b/test/BrienzRothornBahn-HAFAS/FPLAN index 9cf79fa6..0fcf29bf 100644 --- a/test/BrienzRothornBahn-HAFAS/FPLAN +++ b/test/BrienzRothornBahn-HAFAS/FPLAN @@ -1,4 +1,4 @@ -*Z 00001 000104 001 % 00001 000104 001 (001) +*Z 000001 000104 001 % 00001 000104 001 (001) *G R 8508350 8508352 00730 00825 % 00001 000104 001 (002) *A VE 8508350 8508352 003499 00730 00825 % 00001 000104 001 (003) *A 2 8508350 8508352 00730 00825 % 00001 000104 001 (004) @@ -7,7 +7,7 @@ 8508350 Brienz BRB 00730 % 00001 000104 001 (007) 8508351 Planalp 00756 00756 % 00001 000104 001 (008) 8508352 Brienzer Rothorn 00825 % 00001 000104 001 (009) -*Z 00002 000104 001 % 00002 000104 001 (001) +*Z 000002 000104 001 % 00002 000104 001 (001) *G R 8508352 8508350 00830 00930 % 00002 000104 001 (002) *A VE 8508352 8508350 003499 00830 00930 % 00002 000104 001 (003) *A 2 8508352 8508350 00830 00930 % 00002 000104 001 (004) diff --git a/test/BrienzRothornBahn-HAFAS/readme.txt b/test/BrienzRothornBahn-HAFAS/readme.txt index 8881e9e8..6b40bea4 100644 --- a/test/BrienzRothornBahn-HAFAS/readme.txt +++ b/test/BrienzRothornBahn-HAFAS/readme.txt @@ -1,12 +1,13 @@ Extract of http://www.fahrplanfelder.ch/de/fahrplandaten.html => testdaten.zip (accessed 02.11.2016), which is publicly available. +Note 2024: test files are no longer available in the link above and the HAFAS-Format has changed since. The test files have been manually edited to reflect the changes. Extracted the files - BETRIEB_DE - - BFKOORD_GEO + - BFKOORD_WGS - BITFELD - FPLAN Modifications: - FPLAN is reduced to the first two public transport lines (Brienz BRB to Rothorn via Planalp and back). - - BETRIEB_DE and BFKOORD_GEO are reduced to only the values required by the reduced FPLAN. + - BETRIEB_DE and BFKOORD_WGS are reduced to only the values required by the reduced FPLAN. - BITFELD is also reduced to the line required by the reduced FPLAN, but additionally the BITFELD-Stream of this line was changed and simplified for testing purposes. diff --git a/test/FPLAN_HAFAS/BETRIEB_DE b/test/FPLAN_HAFAS/BETRIEB_DE index 3ffed341..d8d16d68 100644 --- a/test/FPLAN_HAFAS/BETRIEB_DE +++ b/test/FPLAN_HAFAS/BETRIEB_DE @@ -1,2 +1,3 @@ +* Kommentarzeile 00343 K "RhB" L "RhB" V "Rhätische Bahn" 00343 : 000072 \ No newline at end of file diff --git a/test/FPLAN_HAFAS/BFKOORD_GEO b/test/FPLAN_HAFAS/BFKOORD_GEO deleted file mode 100644 index 1be721b1..00000000 --- a/test/FPLAN_HAFAS/BFKOORD_GEO +++ /dev/null @@ -1,21 +0,0 @@ -8509002 9.554028 46.967439 523 % Landquart -8509056 9.560866 46.957199 523 % Landquart Ried -8509055 9.564754 46.949829 523 % Igis -8509054 9.559589 46.934843 531 % Zizers -8509053 9.559173 46.918987 537 % Untervaz-Trimmis -8509051 9.533122 46.876984 562 % Haldenstein -8509006 9.531445 46.861898 577 % Chur Wiesental -8509000 9.528925 46.853080 585 % Chur -8509183 9.412551 46.823664 604 % Reichenau-Tamins -8509167 9.359521 46.816578 609 % Trin -8509168 9.310299 46.807380 635 % Versam-Safien -8509169 9.275459 46.791794 669 % Valendas-Sagogn -8509170 9.233080 46.778494 655 % Castrisch -8509171 9.207437 46.775359 698 % Ilanz -8509173 9.145614 46.774698 733 % Rueun -8509174 9.120152 46.769560 744 % Waltensburg/Vuorz -8509175 9.062430 46.754768 788 % Tavanasa-Breil/Brigels -8509176 8.990444 46.742543 852 % Trun -8509177 8.957496 46.732577 928 % Rabius-Surrein -8509178 8.931326 46.724078 982 % Sumvitg-Cumpadials -8509179 8.855021 46.704979 1130 % Disentis/Mustér \ No newline at end of file diff --git a/test/FPLAN_HAFAS/BFKOORD_WGS b/test/FPLAN_HAFAS/BFKOORD_WGS new file mode 100644 index 00000000..4536a07a --- /dev/null +++ b/test/FPLAN_HAFAS/BFKOORD_WGS @@ -0,0 +1,22 @@ +* Kommentarzeile +8509002 9.5540280 46.9674390 523 % Landquart +8509056 9.5608660 46.9571990 523 % Landquart Ried +8509055 9.5647540 46.9498290 523 % Igis +8509054 9.5595890 46.9348430 531 % Zizers +8509053 9.5591730 46.9189870 537 % Untervaz-Trimmis +8509051 9.5331220 46.8769840 562 % Haldenstein +8509006 9.5314450 46.8618980 577 % Chur Wiesental +8509000 9.5289250 46.8530800 585 % Chur +8509183 9.4125510 46.8236640 604 % Reichenau-Tamins +8509167 9.3595210 46.8165780 609 % Trin +8509168 9.3102990 46.8073800 635 % Versam-Safien +8509169 9.2754590 46.7917940 669 % Valendas-Sagogn +8509170 9.2330800 46.7784940 655 % Castrisch +8509171 9.2074370 46.7753590 698 % Ilanz +8509173 9.1456140 46.7746980 733 % Rueun +8509174 9.1201520 46.7695600 744 % Waltensburg/Vuorz +8509175 9.0624300 46.7547680 788 % Tavanasa-Breil/Brigels +8509176 8.9904440 46.7425430 852 % Trun +8509177 8.9574960 46.7325770 928 % Rabius-Surrein +8509178 8.9313260 46.7240780 982 % Sumvitg-Cumpadials +8509179 8.8550210 46.7049790 1130 % Disentis/Mustér \ No newline at end of file diff --git a/test/FPLAN_HAFAS/FPLAN b/test/FPLAN_HAFAS/FPLAN index 0996916b..f7b21c1d 100644 --- a/test/FPLAN_HAFAS/FPLAN +++ b/test/FPLAN_HAFAS/FPLAN @@ -1,4 +1,4 @@ -*Z 01729 000072 001 % -- 6100720007 -- +*Z 001729 000072 001 % -- 6100720007 -- *G RE 8509002 8509179 % *A VE 8509002 8509179 % *A X 8509056 8509056 % @@ -35,7 +35,7 @@ 8509177 Rabius-Surrein 01057 01057 % 8509178 Sumvitg-Cumpadials 01100 01100 % 8509179 Disentis/Mustér 01111 % -*Z 99999 000072 001 % -- 6100720007 -- +*Z 099999 000072 001 % -- 6100720007 -- *G RE 8509002 8509179 % *A VE 8509002 8509179 % *A X 8509056 8509056 % @@ -72,7 +72,7 @@ 8509177 Rabius-Surrein 01057 01057 % 8509178 Sumvitg-Cumpadials 01100 01100 % 8509179 Disentis/Mustér 01111 % -*Z 01729 000072 001 % -- 6100720007 -- +*Z 001729 000072 001 % -- 6100720007 -- *G RE 8509002 8509179 % *A VE 8509002 8509179 % *A X 8509056 8509056 % diff --git a/test/osm/Rudolfplatz.osm b/test/osm/Rudolfplatz.osm new file mode 100644 index 00000000..9d6b1381 --- /dev/null +++ b/test/osm/Rudolfplatz.osm @@ -0,0 +1,72474 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +