onthegomap / planetiler Goto Github PK
View Code? Open in Web Editor NEWFlexible tool to build planet-scale vector tilesets from OpenStreetMap data fast
License: Apache License 2.0
Flexible tool to build planet-scale vector tilesets from OpenStreetMap data fast
License: Apache License 2.0
This block in the transportation name layer does too much work inside a synchronized
block, which holds OSM pass 1 way processing back from saturating CPU cores:
We've been using pyosmium-up-to-date to catch a planet.osm.pbf file up to date with changes to OSM. That process takes about 1 minute per day of updates to download plus 40 minutes to rewrite planet.osm.pbf - almost as long as rendering all tiles for the planet.
In order to produce live planet.mbtiles as quickly as possible, planetiler should at least be able to read OSM change files as input and apply them to the PBF file being read. Even better would be if it could automatically download the necessary change files to bring an input planet up-to-date without external dependencies.
Great project, the examples have been nice and concise and really great to work with.
Is there a way to also get the ocean polygons in with any of those examples at all?
Describe the bug
adm0_{l,r}
tags show up on regular boundaries at z5 but the demo shows them at z4 on maritime boundaries derived from OSM data and not natural earth.
To Reproduce
Steps to reproduce the behavior:
Expected behavior
Boundary lines have adm0_{l,r}
tags starting zt z5, not z4
Environment (please complete the following information):
n/a
Additional context
n/a
Is your feature request related to a problem? Please describe.
Problem 1: License. The license of OpenMapTiles is confusing me. I am never sure if I can use OpenMapTiles for a commercial project. I don't know if I have to give attribution to OpenMapTiles if I use for example only a single layer from OpenMapTiles like --only_layers=transportation
.
Problem 2: Customization. OpenMapTiles is a great start to make a map. But I don't need all the information it provides (e.g. landcover farmland). And other information is missing (e.g. powerlines). I don't know what is the best way to do this. Fork and edit the base profile?
Describe the solution you'd like
I would like to make a map from ground up where I say I would like to have roads, houses, residential area, forest, water, place names. The building blocks could still use the logic that is already implemented in the base profile.
Describe alternatives you've considered
My current approach would be to comment out all the things I do not need in the base profile and add new layers with my custom information.
Additional context
Discussion #81 is probably related to this issue.
Since the resulting tiles are not compliant with the OpenMapTiles schema, I would like to remove the attribution altogether. I don't know if this is unfair? It just feels wrong to keep linking to OpenMapTiles if the technology used for the map tiles is a different one...
Geotools is not in maven central which adds an extra step for people to build the project, and the licensing is not great. Geotools is really only needed to read shapefiles (including coordinate system transformation) which there should be another option for.
Apache SIS looks promising.
The main feedback on https://news.ycombinator.com/item?id=28986762 was that "flatmap" is ambiguous and not unique. Before publishing to maven central, package managers, etc should decide whether or not to keep "flatmap" or use something different.
Pros:
Cons:
Any suggestions?
Describe the bug
If wikidata names fail to download, the download exits with a stack trace such as:
Exception in thread "main" java.lang.IllegalStateException: java.util.concurrent.ExecutionException: java.lang.RuntimeException: java.net.http.HttpTimeoutException: request
timed out
at com.onthegomap.planetiler.stats.ProgressLoggers.await(ProgressLoggers.java:382)
at com.onthegomap.planetiler.stats.ProgressLoggers.awaitAndLog(ProgressLoggers.java:370)
at com.onthegomap.planetiler.worker.WorkerPipeline.awaitAndLog(WorkerPipeline.java:58)
at com.onthegomap.planetiler.util.Wikidata.fetch(Wikidata.java:152)
at com.onthegomap.planetiler.Planetiler.run(Planetiler.java:487)
at com.onthegomap.planetiler.basemap.BasemapMain.run(BasemapMain.java:50)
at com.onthegomap.planetiler.basemap.BasemapMain.main(BasemapMain.java:14)
at com.onthegomap.planetiler.Main.main(Main.java:50)
Caused by: java.util.concurrent.ExecutionException: java.lang.RuntimeException: java.net.http.HttpTimeoutException: request timed out
at java.base/java.util.concurrent.CompletableFuture.reportGet(Unknown Source)
at java.base/java.util.concurrent.CompletableFuture.get(Unknown Source)
at com.onthegomap.planetiler.stats.ProgressLoggers.await(ProgressLoggers.java:379)
... 7 more
Caused by: java.lang.RuntimeException: java.net.http.HttpTimeoutException: request timed out
at com.onthegomap.planetiler.util.Wikidata.flush(Wikidata.java:254)
at com.onthegomap.planetiler.util.Wikidata.fetch(Wikidata.java:266)
at com.onthegomap.planetiler.util.Wikidata.lambda$fetch$1(Wikidata.java:134)
at com.onthegomap.planetiler.worker.WorkerPipeline$Builder.lambda$sinkTo$2(WorkerPipeline.java:268)
at com.onthegomap.planetiler.worker.Worker.lambda$new$0(Worker.java:50)
at java.base/java.util.concurrent.CompletableFuture$AsyncRun.run(Unknown Source)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.base/java.lang.Thread.run(Unknown Source)
Caused by: java.net.http.HttpTimeoutException: request timed out
at java.net.http/jdk.internal.net.http.HttpClientImpl.send(Unknown Source)
at java.net.http/jdk.internal.net.http.HttpClientFacade.send(Unknown Source)
at com.onthegomap.planetiler.util.Wikidata$Client.lambda$wrap$0(Wikidata.java:328)
at com.onthegomap.planetiler.util.Wikidata.queryWikidata(Wikidata.java:293)
at com.onthegomap.planetiler.util.Wikidata.flush(Wikidata.java:249)
... 8 more
Instead, this download should be retried.
To Reproduce
Happens randomly when using --fetch-wikidata options.
Expected behavior
Failed wikidata downloads are retried
Environment (please complete the following information):
Additional context
Full command:
sudo docker run -e JAVA_TOOL_OPTIONS='-Xmx80g' -v "$(pwd)/data":/data \
ghcr.io/onthegomap/planetiler:latest --area=planet --bounds=world --download --download-threads=10 --download-chunk-size-mb=1000 \
--only-fetch-wikidata
Hi, thanks for creating this - it could be a good match to other map tooling I'm developing including a tile archive format and canvas renderer.
One thing I noticed with whipping up a quick example is that the basemap result for motorway network has gaps in it - see attached screenshot. The root cause for the gaps is that OSM ways that connect two other high-importance ways - like highway=motorway
, assigned to appear at a lower zoom level like z9
might actually be tagged at a lower level like highway=primary
and not be included in z9. This is because OSM tags are based on physical features and not cartographic importance.
The approach I usually take to solve this is to generalize roads via a new tag class outside of the OSM tagging conventions based on connectivity to other ways. This would break the parallel design described in ARCHITECTURE.md because feature generation at the early stage could not proceed independently per-feature. I also don't think it could fit into the advanced joining/grouping in README#Limitations because the late-stage, pre-write processing of features at the tile level would not have access to those missing ways.
Is this mode of processing something you would consider in scope for Planetiler, if it necessitates changing the tile generation strategy? There may be ways to accommodate it into the existing design if candidate ways were saved out similar to boundary relations but the quantity of candidates would be very large.
When implementing the basemap layer, I did not port road name abbreviations from https://github.com/giggls/mapnik-german-l10n because of the licensing and just pass road names from OpenStreetMap directly. This is not ideal because clients like MapLibre won't show labels on a line if we can't fit the entire string, so overall shorter label names will increase label density.
I think it would be best to abbreviate all road names (not just long ones), for example:
Input | Output |
---|---|
Park Avenue | Park Ave |
Northeast Boulevard | NE Blvd |
East 61st Street | E 61st St |
First Street | 1st St |
South Park Street | S Park St |
South Street | South St |
Some possible data sources:
Occasionally, when downloading resources on a digitalocean droplet, the download triggers a "black hole" condition where they think there's a denial of service attack underway against your droplet. To fix this, we should add an option to limit inbound bandwidth on the downloader.
The java install link in the contributing file goes to a page which says:
We're currently working out our installation page. Please check back later!
https://adoptium.net/installation.html
Should we update this link?
The java install link in the contributing file goes to a page which says:
We're currently working out our installation page. Please check back later!
https://adoptium.net/installation.html
Should we update this link?
Is your feature request related to a problem? Please describe.
I want to render a profile on planet.osm.pbf which creates a small output mbtiles file which is maybe only 100 MB. Currently, I need a machine with 128 GB ram for this.
Describe the solution you'd like
Being able to render profiles which create small mbtiles files on machines with smaller amount of ram, e.g., 8 GB ram.
Describe alternatives you've considered
First, run osmium on planet.osm.pbf to extract only relevant features which results in a smaller .osm.pbf file. Then, run planetiler.
Additional context
Toilts example can do this to some extent:
Osmium: https://docs.osmcode.org/osmium/latest/osmium-tags-filter.html
Relevant planetiler code:
Is your feature request related to a problem? Please describe.
Currently, Planetiler outputs mbtiles which requires a tileserver, i.e., static file hosting like on github pages is not enough to serve tiles.
Describe the solution you'd like
PMTiles can be used to serve vector tiles with range requests and they don't require a tile server. Planetiler could implement a pmtiles writer.
Describe alternatives you've considered
@bdon created a mbtiles to pmtiles converter:
pip install pmtiles
pmtiles-convert TILES.mbtiles TILES.pmtiles
Additional context
the powerlines example uses pmtiles https://github.com/wipfli/powerlines-switzerland
Currently the basemap profile uses lake centerlines from the unmaintained https://github.com/lukasmartinelli/osm-lakelines repo. It would be nice if flatmap could generate centerlines for polygons itself out of the box. In most cases you would probably want to fall back to a point label if the polygon is not elongated. It might also make sense to limit minzoom based on the length of the line or area of the polygon if it's a point so the entire text fits into the polygon.
Describe the bug
At zoom level at and above 5 I see no features.
To Reproduce
Expected behavior
I see something similar to what I see at https://onthegomap.github.io/flatmap-demo/#4.9/40.75/-108.36
Screenshots
This is what I see when I follow the to reproduce steps:
Environment (please complete the following information):
Additional context
I can reproduce in mobile Firefox and mobile Chrome. I haven't tested anything else.
First of all, huge thanks for building this great application!
Is your feature request related to a problem? Please describe.
I've generated tiles for Europe and it works great. I wonder if there would be an option to create tiles (country contours, rivers, etc) for the whole planet and the detailed tiles for the desired region?
I wonder if it would also make sense to provide scripts with recommended settings to run for an extract vs. full planet from source/latest jar with Java/with docker.
Yes - this was not clear from the docs when I ran the planet (thanks for the assist!)
Originally posted by @ZeLonewolf in #70 (comment)
OSM is distributing funds. See https://wiki.osmfoundation.org/wiki/Engineering_Working_Group/Tendering_Framework
Can Planetiler apply there?
Describe the bug
In Germany Planetiler is generating only few refs for major roads like motorways or trunks. The reason seems to be that Planetiler calculates the rank of a relation based on if it's part of a set of preconfigured networks (like US:
). If these are not set, Planetiler uses other tags for hiking networks etc to figure out the rank. See the code here.
Here are two examples from Germany where this approach does not work properly which leaves major roads without road signs.
Motorway: https://www.openstreetmap.org/relation/2166961
Trunk: https://www.openstreetmap.org/relation/1506786
Expected behavior
As these are important roads, it would be good to have road signs for these roads.
Screenshots
Here is a comparison on z11 between OMT (has road signs) and Planetiler (no road signs):
Potential fix
The transportation_name_minor
could be only used for minor roads. This would invalidate the fix for #145.
So how about we apply a low rank for relations with network=e-road
and when getting the relations of a road, we order them by rank? So right now, the default rank is 3, so maybe e-roads could be rank 4?
Describe the bug
Planetiler creates a transportation_name entry with a ref for minor roads. This differs to OMT. I have a style that shows road signs. It now shows road signs for hiking and cycling routes.
To Reproduce
Steps to reproduce the behavior:
For example:
https://www.openstreetmap.org/relation/2268453
https://www.openstreetmap.org/relation/1153402
Expected behavior
I don't think it's an issue that Planetiler does this. There are applications that want to show highway signs for cycle routes etc. At least I think we should document it. That way, I know what I am getting and can update my styles to consider this change.
Screenshots
Describe the bug
I noticed that highways and expressways in Poland have the wrong ref
. Right now, they are using the ref value of the International road network (network = "e-road"). This is an example relation https://www.openstreetmap.org/relation/33702 from e-road network. And this is a relation that should be actually used for ref https://www.openstreetmap.org/relation/112778
It looks that the problem only happens for polish roads. For example, highways in Germany have correct local refs.
To Reproduce
Steps to reproduce the behavior:
java -jar planetiler-dist/target/*with-deps.jar --force=true --osm-path=data/sources/pomorskie-latest.osm.pbf
Expected behavior
Relations that are part of network="e-road
shouldn't be used for getting ref
for transportation_name layer. Maybe
Screenshots
I would like to provide a customization example in Java. I made a powerlines map here https://github.com/wipfli/powerlines-switzerland and was wondering if we could add it or link it to planetiler?
For users, I think it would be nice to see how to use planetiler as a dependency. Having a separate example project might be useful for this. The powerlines example above has to be adjusted I think.
One thing I found useful when starting with Mapbox GL JS was their collection of examples https://docs.mapbox.com/mapbox-gl-js/example/. These examples have a title, a 3-sentence text, and like 20 lines of code. Maybe we could make something similar where we highlight how to use different features of Planetiler.
How can I make a custom layer with only forest polygons? I tried to figure it out from the base profile but failed...
To improve consistency between people who may use different editors, we should adopt a java linter like checkstyle or sonarlint. You should be able to run it from the command line, through plugins to popular editors, and a github action should highlight any issues as comments on a PR.
Describe the bug
The names of POI/buildings are missing using the default basemap profile.
Expected behavior
The output mbtiles should include the name tags of buildings and POIs but they are dropped.
To Reproduce
java -Xmx1g -jar planetiler.jar --download --osm_path="malaysia-singapore-brunei-old.osm.pbf"
Long description
I am generating vector tiles for Singapore and have been using tilemaker prior to planetiler. Using Way 427077072 as an example, the building name in OSM is 'Ridge View Tower' and I would expect the output mbtiles to contain the same information.
In the planetiler mbtiles, however, this name field is missing. Inspecting the planetiler mbtiles using QGIS reveals that planetiler only saves housenumbers and does not save POI/building names.
Here are some screenshots describing the problem:
OSM groundtruth:
Planetiler output:
Tilemaker output:
Is there a way I can edit the planetiler profile to match the detailed output of tilemaker/OSM ?
Environment (please complete the following information):
Right now you need to write Java code to build a custom profile. It might be nice if you could also write a json or yaml file that defines the logic and config for the profile.
I'd like to add contour lines.
It would be cool to include a profile showcasing all of the vector layers available in Natural Earth
Some issues I ran into prototyping this:
Describe the bug
On Windows 10, when generating using scripts/regenerate-openmaptiles
, an error is thrown during the download of omt yaml files.
Exception in thread "main" java.io.FileNotFoundException: https://raw.githubusercontent.com/openmaptiles/openmaptiles/v3.12.2/layers\water\mapping.yaml
Pasting the suspect URL into Chrome works fine. Turns out that accessing this URL through Java returns a 404 for this particular .yaml file.
This bug results from the forward-slash and backslash in the URL (probably due to windows file separator).
To fix this, I added url = url.replaceAll("\\\\", "/");
above line 108 of Generate.java
.
Note that I have not tested the impact of this patch on non-windows machines.
When an OSM input files uses the LocationsOnWays feature, we could bypass storing node locations to reduce memory usage substantially.
While generating the planet, there were a few NPEs:
0:33:28 ERR [osm_pass2:process] - Error processing OSM way 121137742
java.lang.NullPointerException: Cannot invoke "java.lang.Integer.intValue()" because the return value of "java.util.Map.get(Object)" is null
at com.onthegomap.planetiler.basemap.layers.Transportation.getMinzoom(Transportation.java:424)
at com.onthegomap.planetiler.basemap.layers.Transportation.process(Transportation.java:362)
at com.onthegomap.planetiler.basemap.BasemapProfile.lambda$new$6(BasemapProfile.java:134)
at com.onthegomap.planetiler.ForwardingProfile.processFeature(ForwardingProfile.java:116)
at com.onthegomap.planetiler.reader.osm.OsmReader.lambda$pass2$2(OsmReader.java:279)
at com.onthegomap.planetiler.worker.WorkerPipeline$Builder.lambda$addWorker$0(WorkerPipeline.java:246)
at com.onthegomap.planetiler.worker.Worker.lambda$new$0(Worker.java:49)
at java.base/java.util.concurrent.CompletableFuture$AsyncRun.run(Unknown Source)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.base/java.lang.Thread.run(Unknown Source)
0:38:40 ERR [osm_pass2:process] - Error processing OSM way 283144232
java.lang.NullPointerException
0:51:06 ERR [osm_pass2:process] - Error processing OSM way 712454442
java.lang.NullPointerException
During the mbtiles write phase, we read temporary features from disk and do a k-way merge to group features into tiles. This single-threaded bottleneck prevents us from saturating CPUs on larger machines:
To speed this up, optionally support 2 parallel read threads, and a thread that merges the results.
This feature was not included in the initial port from OpenMapTiles.
LanguageUtils is a straight port from openmaptiles logic, but there are a few issues with it. Please add a comment with any suggestions for improving the logic to assign element names, picking latin/nonlatin names, transliterating, etc. along with some example test cases to illustrate the desired behavior.
Is your feature request related to a problem? Please describe.
Planetiler was initially designed to work in batch mode but it might be possible to get incremental minutely updates from OpenStreetMap.
Describe the solution you'd like
Run planetiler once to get a base tileset plus some extra indices, then run a continuous (or cron) process to crawl the latest OSM replication diffs (https://wiki.openstreetmap.org/wiki/Planet.osm/diffs) and apply them to the tileset. The initial run could be slower than batch mode, but should still be reasonable (<12 hours) and incremental updates should be <1 minute. Ideally, incremental updates should need much less RAM than a full import.
Describe alternatives you've considered
Start from a planet.osm.pbf dump, then loop continuously:
This would result in a 1-3 hour latency, depending on how big of a machine you use.
Open Questions
Add support for other geographic encoding formats, for example:
Can planetiler handle shapefiles (https://en.wikipedia.org/wiki/Shapefile)?
The Swiss government distributes shapefiles (https://data.geo.admin.ch/) for example for natural protected areas. In the past, I converted shapefiles to GeoJSON and then to mbtiles with tippecanoe
.
Describe the bug
The quickstart-from-source.sh
script does not download data.
To Reproduce
Steps to reproduce the behavior:
./quickstart-from-source.sh
Exception in thread "main" java.lang.IllegalArgumentException: data/sources/lake_centerline.shp.zip does not exist
Expected behavior
quickstart-from-souce.sh
should download the required assets.
Environment (please complete the following information):
Is your feature request related to a problem? Please describe.
Maven support in GitHub packages is flaky and does not allow anonymous access.
Describe the solution you'd like
Get flatmap-core into Maven Central so it can be installed without changing your .m2/settings.xml
file.
Describe alternatives you've considered
A read-only personal access token included in the repo - github deletes it automatically.
Additional context
n/a
The most robust fix would be to limit the subkeys to those that would be valid BCP 47 codes, like xx and xx-YY and xx-YY-ZZZZ. But limiting it to the languages in the profile should work too.
I think the revised non-Latin detection code would still be worth pursuing regardless. With just the smaller fix you’re suggesting, there will be cases where an alternative language’s name is arbitrarily chosen just because of a “non-Latin” character.
Originally posted by @1ec5 in #86 (comment)
Planetiler currently limits the maximum zoom level to 14 since that was the highest needed for the OpenMapTiles port. Other schemas may want to go higher though. It should at least be possible to go to z15, and possibly z16.
Route relations with long network
values are not getting rendered by planetiler. Examples:
New Jersey Turnpike:
https://www.openstreetmap.org/relation/189809 network=US:NJ:NJTP
ref=NJTP
Atlantic City Expressway:
https://www.openstreetmap.org/relation/189490 network=US:NJ:NJTP
ref=NJTP
Garden State Parkway:
https://www.openstreetmap.org/relation/184099 network=US:NJ:GSP
ref=GSP
US-30 Alternate Truck Business:
https://www.openstreetmap.org/relation/6849001 network=US:US:Alternate:Truck:Business
ref=30
PA Turnpike
https://www.openstreetmap.org/relation/3075582 network=US:PA:Turnpike
ref=PATP
New Jersey CR 539
https://www.openstreetmap.org/relation/549770 network=US:NJ:CR
ref=539
Openstreetmap-americana rendering of NJ turnpike: https://zelonewolf.github.io/openstreetmap-americana/#11/40.2578/-74.4618
Tileserver output showing only I-95 and not NJTP:
To Reproduce
Steps to reproduce the behavior:
route_N
values from the route relation members above.Expected behavior
Listed route relations show be present on member ways in the tile server. For example, along the NJ turnpike, I expect to see route_1=US:I=95
+ route_2=US:NJ:NTJP=NTJP
.
Screenshots
Side by side openstreetmap-americana renderings of MapTiler Cloud vs planetiler:
Environment
Is your feature request related to a problem? Please describe.
If a planetiler render is launched with insufficient memory or disk space, the build will run until memory/disk is exhausted. However, this could be an hour or more before the limit is encountered, resulting in wasted time and an unclear error message to users (typically some type of out of memory error).
Describe the solution you'd like
Planetiler should note the size of the input file, and if it calculates that memory or disk space is insufficient to run to completion, it should fail quickly with an error message indicating the need for more disk space or memory.
Ideally we wouldn't check generated code (protobuf and OMT schema) into git and instead generate it on the fly as part of the maven build.
Related to #109
Describe the bug
When downloading area .osm.pbf
files, a 302 redirect is not followed, instead, an exception is raised.
To Reproduce
java -Xmx1g -jar flatmap.jar --download --area=germany
Stack trace
Expected behavior
The 302 redirect should be followed and the download should succeed.
Environment (please complete the following information):
Linux hostname 5.15.5-arch1-1 #1 SMP PREEMPT Thu, 25 Nov 2021 22:09:33 +0000 x86_64 GNU/Linux
openjdk version "17.0.1" 2021-10-19
OpenJDK Runtime Environment (build 17.0.1+12)
OpenJDK 64-Bit Server VM (build 17.0.1+12, mixed mode)
Additional context
As you can see, download.geofabrik.de
returns a 302 redirect:
$ curl -v https://download.geofabrik.de/europe/germany-latest.osm.pbf 2>&1 | grep -E '< HTTP|Location'
< HTTP/1.1 302 Found
< Location: http://ftp5.gwdg.de/pub/misc/openstreetmap/download.geofabrik.de/germany-latest.osm.pbf
There are these nice functions called canBeLine()
and canBePolygon()
. Do you think we could also have one called canBePoint()
?
It would be helpful if the tilejson output (which typically copies all key/value pairs from the mbtiles metadata table) included the timestamp/version of input source data to help you understand what you're seeing in the output. To do this let's add planetiler:osm:timestamp
metadata attribute that copies the OSM replication timestamp to output file.
Alternatives Considered
Include the input data source version/timestamp in description or version field. This stays within the tilejson/mbtiles spec, but is harder for clients to parse. Mbtiles servers seem to just pass any unknown fields through from metadata to tilejson, so custom keys seem like a better option.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.