How to: v1.x - pgRouting/pgrouting GitHub Wiki

pgRouting v1.x

  • Is no longer supported
  • This page is Historical

Table of Contents:

Build pgRouting for Windows

  • Author: René Westerholt (edited by Daniel Kastl)
  • License: Creative Commons

Warning

This manual page is a checklist of what is needed to build a Windows binary 
for pgRouting. It was written some time ago, so it might be outdated.

Download prebuild-dll-2-7-0-release from ftp://sources.redhat.com/pub/pthreads-win32/

	cp /include/*.h /mingw/include
	cp /lib/libpthreadGC2.a /mingw/lib/libpthread.a
  • CMake

Use latest version(2.4.7)

	#./configure --prefix=E:/Build/msys/1.0/local
	#make
	#make install

Or you can use Windows installer.

  • Boost

Use previous version (1.33.1) because of v2 problem

	#bjam -sTOOLS=mingw "-sBUILD=release <runtime-link>static <threading>multi <native-wchar_t>on" --prefix=/e/Build/msys/1.0/local install 
	#mv /usr/local/include/boost-1_33_1/boost /usr/local/include/boost 
	#rmdir /usr/local/include/boost-1_33_1 

If you don't need CGAL library (driving distance functionality), pgRouting uses only Boost headers. So you needs download Boost headers(1.33.1 or later), and extract it.

  • Gaul

Use latest version(0.1849-0)

	#./configure --enable-slang=no
	edit /util/Makefile
		DEFS = -DHAVE_CONFIG_H
		 -> DEFS = -DHAVE_CONFIG_H -DBUILDING_DLL
	edit /src/Makefile
		DEFS = -DHAVE_CONFIG_H
		 -> DEFS = -DHAVE_CONFIG_H -DBUILDING_DLL
		INCLUDES = -I../util/ -I../../util/
		 -> INCLUDES = -I../util -I../../util
	edit /tests/Makefile
		DEFS = -DHAVE_CONFIG_H
		 -> DEFS = -DHAVE_CONFIG_H -DBUILDING_DLL
		INCLUDES = -I../util/ -I../../util/ -I../src/ -I../../src/ -I/usr/include/slang/
		 -> INCLUDES = -I../util -I../../util -I../src -I../../src -I/usr/include/slang/
	#make
	#make install
  • CGAL

Use latest version(3.2.1)

	#./install_cgal --prefix=/usr/local/cgal  --with-BOOST --BOOST_INCL_DIR=/usr/local/include --BOOST_LIB_DIR=/usr/local/lib --without-autofind -ni /mingw/bin/g++
	#cp /usr/local/cgal/include/CGAL/config/i686_MINGW32NT-5.1_g++-3.4.2/CGAL/compiler_config.h /usr/local/cgal/include/CGAL/compiler_config.h
	#cp /usr/local/cgal/lib/i686_MINGW32NT-5.1_g++-3.4.2/libCGAL.a /usr/local/cgal/lib/libCGAL.a
	#cp /usr/local/cgal/lib/i686_MINGW32NT-5.1_g++-3.4.2/libCGAL.so /usr/local/cgal/lib/libCGAL.so
  • pgRouting
	#cmake -G"MSYS Makefiles" -DWITH_TSP=ON -DWITH_DD=ON .
  • Edit CMakeCache.txt
	Boost_INCLUDE_DIR:PATH=Boost_INCLUDE_DIR-NOTFOUND
	 -> Boost_INCLUDE_DIR:PATH=E:/Build/msys/1.0/local/include

	CGAL_INCLUDE_DIR:PATH=CGAL_INCLUDE_DIR-NOTFOUND
	 -> CGAL_INCLUDE_DIR:PATH=E:/Build/msys/1.0/local/cgal/include

	CGAL_LIBRARIES:FILEPATH=CGAL_LIBRARIES-NOTFOUND
	 -> CGAL_LIBRARIES:FILEPATH=E:/Build/msys/1.0/local/cgal/lib

	GAUL_LIBRARIES:FILEPATH=GAUL_LIBRARIES-NOTFOUND
	 -> GAUL_LIBRARIES:FILEPATH=E:/Build/msys/1.0/local/lib
  • Edit core\src\CMakeFiles\routing.dir\flags.make

Adjust (ie. "C") and to your system environment!

	C_FLAGS = -Drouting_EXPORTS -O2 -g \
		      -I/<drive>/<my path>/msys/1.0/local/src/pgrouting/pgrouting/. \
		      -I/<drive>/<my path>/msys/1.0/local/src/pgrouting/pgrouting/core \
		      -I/<drive>/<my path>/msys/1.0/local/src/pgrouting/pgrouting/core/src \
		      -I/<drive>/<my path>/msys/1.0/local/src/pgrouting/pgrouting/extra \
		      -I/<drive>/<my path>/msys/1.0/local/src/pgrouting/pgrouting/extra/tsp \
		      -I/<drive>/<my path>/msys/1.0/local/src/pgrouting/pgrouting/extra/tsp/src \
		      -I/<drive>/<my path>/msys/1.0/local/src/pgrouting/pgrouting/extra/driving_distance \
		      -I/<drive>/<my path>/msys/1.0/local/src/pgrouting/pgrouting/extra/driving_distance/src \
		      -I/boost \
		      -I/<drive>/<my path>/msys/1.0/local/include \
		      -IC:/PROGRA~1/PostgreSQL/8.2/include/server \
		      -IC:/PROGRA~1/PostgreSQL/8.2/include/server/port/win32
	CXX_FLAGS = -Drouting_EXPORTS -O2 -g 
		        -I/<drive>/<my path>/msys/1.0/local/src/pgrouting/pgrouting/. \
		        -I/<drive>/<my path>/msys/1.0/local/src/pgrouting/pgrouting/core \
		        -I/<drive>/<my path>/msys/1.0/local/src/pgrouting/pgrouting/core/src \
		        -I/<drive>/<my path>/msys/1.0/local/src/pgrouting/pgrouting/extra \
		        -I/<drive>/<my path>/msys/1.0/local/src/pgrouting/pgrouting/extra/tsp \
		        -I/<drive>/<my path>/msys/1.0/local/src/pgrouting/pgrouting/extra/tsp/src \
		        -I/<drive>/<my path>/msys/1.0/local/src/pgrouting/pgrouting/extra/driving_distance \
		        -I/<drive>/<my path>/msys/1.0/local/src/pgrouting/pgrouting/extra/driving_distance/src \
		        -I/boost \
		        -I/<drive>/<my path>/msys/1.0/local/include \
		        -IC:/PROGRA~1/PostgreSQL/8.2/include/server \
		        -IC:/PROGRA~1/PostgreSQL/8.2/include/server/port/win32
  • Edit core\src\CMakeFiles\routing.dir\build.make

Adjust (ie. "C") and to your system environment!

	routing_EXTERNAL_OBJECTS = \

Edit last line as follows (not make clean!!!)

	cd /<drive>/<my path>/pgrouting/core/src && /<drive>/<my path>/mingw/bin/g++.exe $(routing_OBJECTS) $(routing_EXTERNAL_OBJECTS) \
		       -L/<drive>/<my path>/msys/1.0/local/lib \
		       -LC:/PROGRA~1/PostgreSQL/8.2/lib \
		       -lpostgres -shared -o ../../lib/librouting.dll \
		       -Wl,--out-implib,../../lib/librouting.dll.a \
		       -Wl,--major-image-version,0,--minor-image-version,0
  • Edit extra\tsp\src\CMakeFiles\routing_tsp.dir\flags.make
	C_FLAGS = -Drouting_tsp_EXPORTS -g -O2 -IE:/Build/msys/1.0/local/include -I/E/Build/msys/1.0/local/src/pgrouting/pgrouting/core/src -IC:/PROGRA~1/PostgreSQL/8.2/include/server -IC:/PROGRA~1/PostgreSQL/8.2/include/server/port/win32
	CXX_FLAGS = -Drouting_tsp_EXPORTS -g -O2 -IE:/Build/msys/1.0/local/include -I/E/Build/msys/1.0/local/src/pgrouting/pgrouting/core/src -IC:/PROGRA~1/PostgreSQL/8.2/include/server -IC:/PROGRA~1/PostgreSQL/8.2/include/server/port/win32 -DBUILDING_DLL
  • Edit extra\tsp\src\CMakeFiles\routing_tsp.dir\build.make
	routing_tsp_EXTERNAL_OBJECTS = \

Edit last line as follows

	cd /E/Build/msys/1.0/local/src/pgrouting/pgrouting/extra/tsp/src && /e/Build/mingw/bin/g++.exe $(routing_tsp_OBJECTS) $(routing_tsp_EXTERNAL_OBJECTS) -LE:/Build/msys/1.0/local/lib -LC:/PROGRA~1/PostgreSQL/8.2/lib -lpostgres -lgaul -lgaul_util -lm -shared -o ../../../lib/librouting_tsp.dll -Wl,--out-implib,../../../lib/librouting_tsp.dll.a -Wl,--major-image-version,0,--minor-image-version,0 -Wl,--export-all-symbols
  • Edit extra\driving_distance\src\CMakeFiles\routing_dd.dir\flags.make
	C_FLAGS = -Drouting_dd_EXPORTS -g -O2 -IE:/Build/msys/1.0/local/include -I/E/Build/msys/1.0/local/src/pgrouting/pgrouting/core/src -I/E/Build/msys/1.0/local/cgal/include -IC:/PROGRA~1/PostgreSQL/8.2/include/server -IC:/PROGRA~1/PostgreSQL/8.2/include/server/port/win32
	CXX_FLAGS = -Drouting_dd_EXPORTS -g -O2 -IE:/Build/msys/1.0/local/include -I/E/Build/msys/1.0/local/src/pgrouting/pgrouting/core/src -I/E/Build/msys/1.0/local/cgal/include -IC:/PROGRA~1/PostgreSQL/8.2/include/server -IC:/PROGRA~1/PostgreSQL/8.2/include/server/port/win32
  • Edit extra\driving_distance\src\CMakeFiles\routing_dd.dir\build.make
	routing_dd_EXTERNAL_OBJECTS = \

Edit last line as follows

	cd /E/Build/msys/1.0/local/src/pgrouting/pgrouting/extra/driving_distance/src && /e/Build/mingw/bin/g++.exe $(routing_dd_OBJECTS) $(routing_dd_EXTERNAL_OBJECTS) -LE:/Build/msys/1.0/local/lib -LE:/Build/msys/1.0/local/cgal/lib -LC:/PROGRA~1/PostgreSQL/8.2/lib -lCGAL -lpostgres -shared -o ../../../lib/librouting_dd.dll -Wl,--out-implib,../../../lib/librouting_dd.dll.a -Wl,--major-image-version,0,--minor-image-version,0
  • Build pgRouting
	#make

Converting OSM-Files into PostgreSQL-Scripts

  • Author: Westerholt (edited by Daniel Kastl)

If you desire to put some data for displaying as a WFS or WMS into your database you will assert, that most of the available tools for doing something like this are not very satisfying. The tool "osm2pgsql" has the fault, that only attributes that are necessary for rendering the map, are imported into your database. If you want to have the attribute "surface" (for example) in your database, this wouldn't be imported by osm2pgsql.

The tool "osm2pgrouting" works well with creating a routing topology, but it's not useful for the problem aforementioned. "osmosis" is another tool for importing data into a PostgreSQL database. But it creates a table structure that is very disastrous because it creates one row for each attribute that belongs to geometry. So, if your geometry has 5 attributes, there would be 5 rows with the structure: ID, Attribute. If you have a big amount of data, you will assert that this would be very uncomfortable.

Here are some new java programs are written by myself, that make it very easy to import data from OSM-Files into your PostgreSQL databases:

Download:

The use of the programs is as follows:

For nodes2postgis.jar:

	java -jar nodes2postgis.jar map.osm 

For lines2postgis.jar:

	java -jar lines2postgis.jar map.osm 

For latlon2google.jar:

	java -jar latlon2google.jar yourTablename 

The result of running those java-programs are .sql scripts that can be easily loaded in the SQL-Performer in PGAdmin III or even be executed on command-line as usually.

Note:

The program "latlon2google" converts the data in the declared table from 
geographical reference system into the google projection.

Diagnostic Tools

  • Author: Stephen Woodbridge (edited by Daniel Kastl)
  • License: Creative Commons

pgRouting is a large black box for most users. When things are working nobody has a problem, but when it is not working as expected what do you do? One of the most common problems is issues with the routing data. I built the following tools that are easy to implement and use and can reveal a lot about your data. I assume that you are working with OpenLayers as you map viewer and we will build two visualization tools.

  • View just the streets in the routing database
  • View intersections and detect deadends

You can see these tools in action at http://imaptools.com/leaddog/routing/dd.html Zoom into a city, open the layer switcher and select "Just the Streets" and "Dead Ends".

  1. View just the streets in the routing database

Create a mapfile that displays the street segments from the routing database and add this as an optional base layer. You might want to add color oneway streets a different color, but in general, keep the display simple and probably single pixel lines. You might label the segments with their UID so you can go back to the database and query them in detail.

	LAYER
		NAME "Streets"
		STATUS DEFAULT
		TYPE LINE
		CONNECTIONTYPE postgis
		CONNECTION "user=postgres dbname=routing host=centos port=5432"
		DATA "the_geom from (select gid, the_geom from st) as foo
			  using SRID=4326 using unique gid"
		LABELITEM "gid"
		MAXLABELSCALEDENOM 25000
		CLASS
		  STYLE
			COLOR 87 87 87
			WIDTH 1
		  END
		  LABEL
			FONT "arial"
			TYPE TRUETYPE
			ANGLE AUTO
			SIZE 7
			COLOR 1 1 1
		  END
		END
		END

		symbol
		name "one_way_from"
		type truetype
		font arial-bold
		character ">"
		gap -40
		end

		symbol
		name "one_way_to"
		type truetype
		font arial-bold
		character "<"
		gap -40
		end


		LAYER
		NAME "One_Way_Arrows"
		STATUS DEFAULT
		TYPE LINE
		MAXSCALEDENOM 25000
		CONNECTIONTYPE postgis
		CONNECTION "user=postgres dbname=routing host=centos port=5432"
		DATA "the_geom from (select gid, one_way, the_geom from st
			  where one_way is not null and length(one_way)>0) as foo
			  using SRID=4326 using unique gid"
		CLASSITEM 'one_way'
		CLASS
		  NAME 'From'
		  EXPRESSION "FT"
		  STYLE
			SYMBOL "one_way_from"
			COLOR 80 80 80
			SIZE 8
		  END
		END
		CLASS
		  NAME 'To'
		  EXPRESSION "TF"
		  STYLE
			SYMBOL "one_way_to"
			COLOR 80 80 80
			SIZE 8
		  END
		END
	END
  1. View intersections and detect deadends

Add a column cnt integer to the vertices_tmp table and update it with the count of segments that reference that node. Maybe something like this:

	alter table vertices_tmp add column cnt integer;
	update vertices_tmp set cnt=0;
	update vertices_tmp set cnt=cnt+1 where streets.source=id;
	update vertices_tmp set cnt=cnt+1 where streets.target=id;

Now create a mapfile layer for points and display the vertices_tmp

	LAYER
	   NAME "deadends"
	   TYPE POINT
	   CONNECTIONTYPE "postgis"
	   CONNECTION ...
	   DATA ...
	   CLASSEXPRESSION "cnt"
	   CLASS
		 EXPRESSION "cnt=1"
		 STYLE
		   SYMBOL "circle"
		   SIZE 5
		   COLOR 255 0 0
		 END
	   END
	   CLASS
		 EXPRESSION "cnt>2"
		 STYLE
		   SYMBOL "circle"
		   SIZE 3
		   COLOR 0 255 0
		 END
	   END
	END

This will display red dots at dead ends and green dots as good connections be segments. If you have a lot of red dots between segments that should be joined, you probably need to rebuild your vertices_tmp table with a larger tolerance.

It is very hard to debug a large black box like a router without having some tools that can give you some better insight as to what is going on.

How to show the route with Mapserver

  • Author: Camptocamp/ pgDijkstra (edited by Daniel Kastl)
  • License: Creative Commons

The shortest path function (i.e. "dijkstra_sp()") can be used inside Mapserver to draw the shortest path directly:

	LAYER
		NAME "europe"
		TYPE LINE

		STATUS DEFAULT
		CONNECTIONTYPE postgis
		    CONNECTION "user=postgres host=localhost dbname=geo"
		    DATA "the_geom from (SELECT the_geom, gid from
		      dijkstra_sp('bahnlinien_europa_polyline', 2629, 10171)) AS
		      foo using unique gid using srid=-1"

		TEMPLATE "t"
		CLASS
		  NAME "0"
		  STYLE
		    SYMBOL "circle"
		    SIZE 10
		    COLOR 50 50 100
		  END
		END
	END

Notice, however, that this function will be called at each map display, computing the shortest path every time.

A better approach would be to generate the shortest path in a temporary table.

Working with OpenStreetMap data

  • Author: Kai Behncke (edited by Daniel Kastl)
  • License: Creative Commons

In that case as an example from Osnabrück ... (in lower Saxony(Germany))

Getting your own OpenStreetMap-Routing-data is not the easiest step in the world. Do you know that you need data with a real topology?

In general, Shapefiles should have one, but be very careful with OSM-Shapefiles. For most thing they work very nice, you get them e.g. from here: http://download.geofabrik.de/osm/

But please don`t use these Shapefiles (and shp2pgsql) for a routing and have a look at that discussion:

http://lists.postlbs.org/pipermail/pgrouting-users/2009-April/000096.html

Many thanks to Daniel KASTL who brought the needed information:

... shp2pgsql imports the geometry correctly, but the topology function will not work with how OSM represents their ways, because ways consist (can consist) of more than one edge often.

osm2pgrouting cares about this and splits a way into more edges if they cross each other. It then automatically does the assign_vertex topology script and adds a few more tables to keep information about road types and classes.

To get your own data you need to work with .osm (XML) files.

Please download the .osm-data from lower Saxony (Niedersachsen.osm.bz2), e.g. from here:

http://download.geofabrik.de/osm/europe/germany/

And then install osmosis, a very nice tool to work with osm-data, The wiki-site for osmosis you find here:

http://wiki.openstreetmap.org/wiki/Osmosis

You need to extract the data from Osnabrück out of Lower Saxony, it works like that:

	osmosis --read-xml niedersachsen.osm --bb left=7.917 right=8.1694 \
					top=52.3537 bottom=52.3537 --write-xml osnabrueck.osm

Now, you have the "real"-OSM-XML-Data from Osnabrück but without a topology.

For that, you need the tool "osm2pgrouting". After you have loaded the .osm-File in the database via osm2pgrouting, the table-structure should look like:

Working with Shapefiles

  • Author: Kai Behncke (edited by Daniel Kastl)
  • License: Creative Commons

Nearly a standard are the well-known ESRI-Shapefiles that consist of -at least - a .dbf-File, a .shp-File and a .shx-File.

These files mostly have already a topology.

If you have installed postgresql a tool called "shp2pgsql" will exist on your computer. You can transform your data into the sql-format doing:

	shp2pgsql /home/mydata/roads.shp newtable >/home/mydata/roads.sql“

For test-purposes you can take data from British Columbia (nrn_rrn_bc_shp_en.zip). You get it from the GeoBase <http://geobase.ca/geobase/en/data/nrn/index.html>_ "National Road Network" dataset.

Please be aware: Don`t use OpenStreetMap-Shapefiles, as thew will create some problems because of their structure.

That sql-file that was created by shp2pgsql you need to bring in your routing-database.

Collection of useful SQL commands

  • Author: Daniel Kastl
  • License: Creative Commons

JOIN two tables

	SELECT 
		count(gid) AS links, 
		sum(a.cost) AS cost, 
		sum(length) AS length

	FROM shortest_path(
		'SELECT gid AS id, 
			source::integer, 
			target::integer, 
			length::double precision AS cost 
		FROM <TABLE A> 
		WHERE <...>, 
		false, 
		false
	) AS a LEFT JOIN <TABLE B> ON (a.gid = gid)

Note:

If you have some SQL commands to share, that are useful for pgRouting,send an email to [email protected] for further information.

Network data validation

  • Author: Kaib Behncke (edited by Daniel Kastl)
  • License: Creative Commons

An important thing is to test if your data work properly for routing. If you are more or less fit to UMN MapServer you can easily do some tests. First of all many thank to Stephen WOODBRIDGE for that idea.

You need to type the following commands on your vertices_tmp-table

alter table vertices_tmp add column cnt integer;
update vertices_tmp set cnt=0;
update vertices_tmp set cnt=cnt+1 from ways where ways.source=vertices_tmp.id;
update vertices_tmp set cnt=cnt+1 from ways where ways.target=vertices_tmp.id;

This will display red dots at dead ends and green dots as good connections be segments.

You can visualize it with the UMN MapServer, just take a mapfile like:


	MAP 

	NAME           'mymap' 
	STATUS ON 
	#EXTENT 3427065.200000 5788323.530000 3443999.370000 5800691.660000
	#EXTENT 7.9189 52.2102 8.1716 52.3467
	EXTENT 880000 6840000 915000 6860000
	IMAGECOLOR 255 255 255
	SIZE      700 700
	SYMBOLSET    	'/your_path/symbols/symbols.sym'
	FONTSET       '/your_path/fonts/fonts.list'

	WEB
	TEMPLATE  'template.html'
	IMAGEPATH '/your_path/tmp/'
	IMAGEURL   '/tmp/'

	METADATA 
	'WMS_TITLE'   'Gastronomap_routing'
	 'WMS_FEATURE_INFO_MIME_TYPE' 'text/html'
	'WMS_ONLINERESOURCE'   'http://localhost/cgi-bin/mapserv?map=/your_path/routing.map' 		
		'WMS_SRS'       "EPSG:900913"	
	  END 
	END 

	PROJECTION 
	'init=epsg:900913'
	END 

	LAYER 
	OFFSITE 255 255 255
	#LABELITEM 'name'
	TOLERANCE 20
	NAME		'streets' 
	TYPE		LINE
	STATUS	DEFAULT
	CONNECTIONTYPE postgis
	CONNECTION 'user=postgres password=postgres dbname=routing host=localhost port=5432'
	DATA 'the_geom from ways as foo using unique gid using SRID=900913'
	CLASSITEM 'gid'
	TEMPLATE 'ausgabe.phtml'

	METADATA 
	'WMS_TITLE'   'streets' 
	'WMS_SRS'    "EPSG:900913"	
	'WMS_INCLUDE_ITEMS' 'all'	
	END 

	CLASS 
	TEXT ([gid],[source],[target])
	EXPRESSION /./

	STYLE 
	WIDTH 1
	COLOR 0 0 0
	END 

	LABEL 
		TYPE TRUETYPE 
		ANTIALIAS TRUE 
		FONT 'arial' 
		COLOR 0 0 0 
		BACKGROUNDCOLOR 240 240 240 
		 POSITION cc
		  MINSIZE 8
		MAXSIZE 12
	  	BUFFER 2
		 END 
	END 
	END

	LAYER 
	OFFSITE 255 255 255
	#LABELITEM 'name'
	TOLERANCE 20
	NAME		'dead_ends' 
	TYPE		POINT
	STATUS	DEFAULT
	CONNECTIONTYPE postgis
	CONNECTION 'user=postgres password=postgres dbname=routing host=localhost port=5432'
	DATA 'the_geom from vertices_tmp as foo using unique id using SRID=900913'


	CLASSITEM 'cnt'
	TEMPLATE 'ausgabe.phtml'

	METADATA 
	'WMS_TITLE'   'dead_ends' 
	'WMS_SRS'    "EPSG:900913"	
	'WMS_INCLUDE_ITEMS' 'all'	
	END 
	CLASS 
	Text ([id])
	EXPRESSION /1/
	STYLE 
	SYMBOL 'tent'
	SIZE 11
	COLOR 255 0 0
	END 

	LABEL 
		TYPE TRUETYPE 
		ANTIALIAS TRUE 
		FONT 'arial' 
		COLOR 255 0 0
		BACKGROUNDCOLOR 240 240 240 
		 POSITION cr
		  MINSIZE 8
		MAXSIZE 12
	  	BUFFER 2
		 END 
	END 

	CLASS 
	TEXT ([id])
	EXPRESSION /./

	STYLE 
	SYMBOL 'tent'
	SIZE 11
	COLOR 0 0 255
	END 

	LABEL 
		TYPE TRUETYPE 
		ANTIALIAS TRUE 
		FONT 'arial' 
		COLOR 0 0 255 
		BACKGROUNDCOLOR 240 240 240 
		 POSITION cr
		  MINSIZE 8
		MAXSIZE 12
	  	BUFFER 2
		 END 
	END 
	END
	END 

If you open your MapServer-testing-apllication via: http://localhost/cgi-bin/mapserv?map=/var/www/gastronomap_wms/gastronomap_routing.map

and you zoom in you get something like:

Everything fine with the data ! :-)

But if it looks like:

Definitely something went wrong........

⚠️ **GitHub.com Fallback** ⚠️