Full Code of atlasr-org/atlasr for AI

master 6c36edf2367d cached
31 files
63.8 KB
15.4k tokens
29 symbols
1 requests
Download .txt
Repository: atlasr-org/atlasr
Branch: master
Commit: 6c36edf2367d
Files: 31
Total size: 63.8 KB

Directory structure:
gitextract_o8etyil8/

├── .gitignore
├── .gitmodules
├── LICENSE
├── README.md
├── justfile
├── public/
│   └── static/
│       ├── css/
│       │   └── default.css
│       ├── image/
│       │   └── README.md
│       └── javascript/
│           └── main.js
└── source/
    ├── api/
    │   ├── geocode/
    │   │   ├── indexer/
    │   │   │   ├── Cargo.toml
    │   │   │   └── src/
    │   │   │       └── main.rs
    │   │   └── searcher/
    │   │       ├── Cargo.toml
    │   │       └── src/
    │   │           └── main.rs
    │   └── tile/
    │       ├── Cargo.toml
    │       ├── database/
    │       │   └── .keep
    │       ├── diesel.toml
    │       └── src/
    │           ├── main.rs
    │           ├── models.rs
    │           └── schema.rs
    ├── client/
    │   ├── elm.json
    │   ├── src/
    │   │   ├── Atlasr/
    │   │   │   ├── Geocode.elm
    │   │   │   ├── Map.elm
    │   │   │   ├── MapboxGL/
    │   │   │   │   ├── Options.elm
    │   │   │   │   └── Ports.elm
    │   │   │   ├── Position.elm
    │   │   │   └── Route.elm
    │   │   ├── Main.elm
    │   │   └── index.html
    │   └── tests/
    │       ├── elm-package.json
    │       └── unit/
    │           └── Atlasr/
    │               └── Test/
    │                   └── Position.elm
    └── server/
        ├── Cargo.toml
        └── src/
            └── main.rs

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
/public/static/css/mapbox-gl.*
/public/static/index.html
/public/static/javascript/*.elm.js*
/public/static/javascript/mapbox-gl.*
/source/api/geocode/*.tsv
/source/api/geocode/index/
/source/api/geocode/indexer/target/
/source/api/geocode/searcher/target/
/source/api/tile/target/
/source/api/tile/database/*.mbtiles
/source/client/elm-stuff
/source/client/tests/elm-stuff
/source/server/target
.idea/
.DS_Store


================================================
FILE: .gitmodules
================================================
[submodule "source/api/graphhopper"]
	path = source/api/route
	url = https://github.com/atlasr-org/graphhopper
	branch = master
[submodule "source/map-style"]
	path = source/map-style
	url = https://github.com/atlasr-org/osm-liberty


================================================
FILE: LICENSE
================================================
                                New BSD License

Copyright © 2018, Ivan Enderlin.
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of Atlasr nor the names of its contributors may be
      used to endorse or promote products derived from this software without
      specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.



================================================
FILE: README.md
================================================
# 🌍 Atlasr

Atlasr is a truly open-source and free map browser. The goal is threefold:

  1. Learn about all the layers and components that make a map,
  2. Provide a ready-to-use set of tools to build a 100% open-source,
     free, and standalone map browser,
  3. Provide an alternative service to the famous [Google Maps][GMaps]
     or [Apple Maps][AMAps], with no ads, with respect to user privacy,
     with 100% open-source and free data, and the top 10 features of
     Google Maps.

A map architecture is composed of the following components:

  * **Map data**, A giant database containing all information about
    roads, trails, cafés, railway stations, buildings etc. The biggest
    major project is [OpenStreetMap][OSM],
  * **Tile server**, A program that, given a specific region, reads
    the map database and compiles those information in a certain
    format like [`.mbtiles`][MBtiles] for instance. Each region of a
    planet is named a _tile_. A tile is defined by a longitude, a
    latitude, and a zoom (an altitude scale),
  * **Map renderer**, A program that, given a set of tiles,
    renders/draws a map, so each roads, buildings etc. finally come
    alive at this step. A map renderer requires at least the following
    components:
      * **Tile decoder** to decode the tiles received from the tile
        server,
      * **Styles** to know how to draw the data from the map
        (e.g. “roads must be blue with a white strike”),
      * **Fonts** to render texts,
      * **Icons** to represent some places with an image (like
        hospitals, police stations, parcs etc.).
  * **Geocoding**, A program that can find the longitude and the
    latitude of a labellised element on earth, like a postal address,
    a building name, or a river name for examples,
  * **Routing**, A program that is able to find a path/route between
    one or many points (longitude + latitude) given some constraints
    (like the vehicule type, the road preference etc.). A route
    preferably comes with descriptions, like “Turn right in 100m”,
    “Follow A10 for 7km” etc.

Obviously, each component comes with thousands of details and
constraints. The previous list is a high overview of how it works.

## Goals

The open-source map ecosystem is mature. Many projects already exist
to address one component of the map architecture. However, a
mainstream tool that combined all these projects, based on 100%
open-source and free data, is still missing. Atlasr aims to be the
response to this problem.

The quality must be comparable with Google Maps or Apple Maps:

  * Smooth and fast experience,
  * Reliable data,
  * Beautiful design for the map and the UI.

## Roadmap

The main technologies are the following: [Rust] for the server, [Elm]
for the client, and [PostgreSQL]/[SQLite] for the databases.

The actual roadmap is the following:

  * **Map data**, _all data comes from OpenStreetMap_,
  * **Tile server** [`source/api/tile/`]:
    * [x] Vector tiles are pre-computed by [OpenMapTiles][OMT], which
          relies on OpenStreetMap.
    * [x] Format is `.mbtiles`,
    * [x] Solid and robust tile server.
  * **Map renderer** [`source/map-style`]:
    * [x] Use [Mapbox GL JS] to render the map,
    * [x] Elm ports to Mapbox GL (JavaScript) for the Web UI,
    * [x] Use [OSM Liberty] for the style, forked to remove the
          dependencies to external services, and to use only “local”
          data,
    * [x] Icons/sprites,
    * [ ] Fonts.
  * **Geocoding** [`source/api/geocode`]:
    * [x] Data are pre-computed by [OSM Names][OSMNames], which relies
          on OpenStreetMap,
    * [x] Transform the data to build an index for the search engine,
    * [x] Custom and fast search engine to query the index, build with [Tantivy],
    * [x] Solid and robust server.
  * **Routing** [`source/api/route/`]:
    * [x] Delegate all the works to [GraphHopper], only use the
          open-source API. API to use:
      * [x] Routing API,
      * [ ] Isochrone API.
  * **HTTP server** [`source/server/`]:
    * [x] Fast and robust HTTP server between the client and all the API.
  * **Client**/**Web UI** [`source/client`]:
    * [x] Mobile-first,
    * [x] Smooth and fast,
    * [x] Search one or many positions (geocoding),
    * [x] Search a route (routing),
    * [ ] Search a route with constraints,
    * [ ] Enhance data with Wikipedia (photos, descriptions, metadata etc.),
    * [ ] All links are sharable,
    * More features.
    
**Current focus**: The current hard work is to provide all map
components as local and standalone instances. Everything has been
addressed except the fonts in the map renderer (yet).

**Next focus**: Replace the top 10 features on Google Maps.

### Screenshots

  * **Map renderer**: The tiles, the style, the icons, everything
    comes from Atlasr. No external service is used.

    ![Map](./documentation/images/map.jpg)
    
  * **Geocoding** and **Routing**: Atlasr is able to geoencode 2
    postal addresses, and find a route between the two:
  
    ![Geocoding and routing](./documentation/images/routing.jpg)

## Usages/Installations

[`just`] is required to run all the commands. Run `just --list` to get an overview of all the commands.

  * **Tile server**:

    ```sh
    $ # Install API tile server.
    $ just install-api-tile

    $ # Run the tile server.
    $ just run-api-tile
    ```
  
  * **Geocoding**:

    ```sh
    $ # Download the data, install the indexer, and install the search engine.
    $ just install-api-geocode

    $ # Run the geocoding server.
    $ just run-api-geocode-searcher
    ```
  
  * **Routing**:
  
    ```sh
    $ # Install the geocoding server.
    $ just install-api-route

    $ # Run the geocoding server.
    $ just run-api-route
    ```
  
  * **Client**/**Web UI**:
  
    ```sh
    $ # Install the HTTP server for the client.
    $ just install-server

    $ # Run the HTTP server for the client.
    $ just run-server

    $ # Install the Web UI, its dependencies, and prepare the frontend.
    $ just install-client

    $ # Open the client.
    $ just open
    ```
  
Enjoy!

## License

The entire project is under the BSD-3-Clause license. Please read the
`LICENSE` file.

[OSM]: https://openstreetmap.org/ 
[MBTiles]: https://github.com/mapbox/mbtiles-spec
[GMaps]: https://google.com/maps
[AMaps]: https://maps.apple.com/
[Rust]: https://rust-lang.org/
[Elm]: https://elm-lang.org/
[PostgreSQL]: https://www.postgresql.org/
[SQLite]: https://www.sqlite.org/
[OMT]: https://openmaptiles.org/
[Mapbox GL JS]: https://www.mapbox.com/mapbox-gl-js/api/
[OSM Liberty]: https://github.com/atlasr-org/osm-liberty/
[OSMNames]: http://osmnames.org/
[Tantivy]: https://github.com/tantivy-search/tantivy/
[GraphHopper]: https://www.graphhopper.com/
[`just`]: https://github.com/casey/just/


================================================
FILE: justfile
================================================
# vim: filetype=just

mapbox_gl_js_version = "0.50.0"
server_address = "localhost:8889"
geocode_api_address = "localhost:8990"
route_api_address = "localhost:8989"
geocode_data_planet = "https://github.com/OSMNames/OSMNames/releases/download/v2.0.4/planet-latest_geonames.tsv.gz"
tile_api_address = "127.0.0.1:8991"

# Open Atlasr in your favorite browser.
open: install
	open http://{{server_address}}

# Install Atlasr!
install: install-server install-api install-client

# Test Atlasr.
test: test-server test-client

# Uninstall Atlasr.
uninstall: uninstall-server uninstall-api uninstall-client

# Install the HTTP server.
install-server:
	cd source/server && \
		SERVER_ADDRESS={{server_address}} \
		ROUTE_API_ADDRESS={{route_api_address}} \
		GEOCODE_API_ADDRESS={{geocode_api_address}} \
		TILE_API_ADDRESS={{tile_api_address}} \
		cargo build --release

# Test the HTTP server.
test-server:
	cd source/server && cargo test

# Uninstall the HTTP server.
uninstall-server:
	rm -rf source/server/Cargo.lock source/server/target

# Run the HTTP server (will not exit).
run-server: install-server
	cd source/server && cargo run --release

# Install all the APIs.
install-api: install-api-geocode install-api-route install-api-tile

# Uninstall all the APIs.
uninstall-api: uninstall-api-geocode uninstall-api-route

# Install the geocode API.
install-api-geocode: install-api-geocode-data install-api-geocode-indexer install-api-geocode-searcher

# Install/download data for the geocode API.
install-api-geocode-data: install-api-geocode-indexer
	cd source/api/geocode && \
		curl -L {{geocode_data_planet}} > planet.tsv.gz && \
		gzip -df planet.tsv.gz && \
		mkdir -p index && \
		./indexer/target/release/atlasr-api-geocode-indexer --source-file planet.tsv --index-directory index

# Install the indexer for the geocode API.
install-api-geocode-indexer:
	cd source/api/geocode/indexer && cargo build --release

# Install the searcher for the geocode API.
install-api-geocode-searcher:
	cd source/api/geocode/searcher && \
		GEOCODE_API_ADDRESS={{geocode_api_address}} \
		cargo build --release

uninstall-api-geocode:
	# noop

run-api-geocode-searcher:
	cd source/api/geocode/searcher && cargo run --release

# Install the route API (GraphHopper).
install-api-route:
	git submodule update --init source/api/route

# Uninstall the route API (GraphHopper).
uninstall-api-route:
	# noop

# Run the route API (GraphHopper) for a particular PBF zone.
run-api-route map_file='europe_switzerland': install-api-route
	cd source/api/route && ./graphhopper.sh web {{map_file}}.pbf

# Install the tile API.
install-api-tile:
	cd source/api/tile && \
		SERVER_ADDRESS={{server_address}} \
		TILE_API_ADDRESS={{tile_api_address}} \
		cargo build --release

# Run the tile API.
run-api-tile:
	cd source/api/tile && cargo run --release

# Uninstall the tile API.
uninstall-api-tile:
	# noop

#run-api-tile map_file='europe_switzerland': install-api-tile
#	cd source/api/tile && \
#		curl -L 'https://openmaptiles.com/download/WyJjOWUzNGM1NS04MDQxLTQ4MTMtYmUzMy0yNmFjMGUyN2I5MWIiLCItMSIsODcxM10.DsGknA.wk4qsZRjBSL8gQrp22h2CRpCyi4/osm-2017-07-03-v3.6.1-{{map_file}}.mbtiles?usage=open-source' > database/{{map_file}}.mbtiles

# Install client.
install-client: install-client-index install-client-application install-client-dependencies

# Test client.
test-client: test-client-application

# Uninstall client.
uninstall-client: uninstall-client-index uninstall-client-application

# Create a public `index.html` file.
SED_INPLACE_OPTION = "\"s@{MAP-PLACEHOLDER.svg}@`cat public/static/image/map-placeholder.svg | sed -E 's/^ +//g; s/\"/'\"'\"'/g; s/</%3c/g; s/>/%3e/g; s/\\#/%23/g' | tr -d \"\\n\"`@\""
install-client-index:
	#!/bin/sh
	cp source/client/src/index.html public/static/index.html
	if [[ "$OSTYPE" == "darwin"* ]]; then
		sed -i '' {{SED_INPLACE_OPTION}}  public/static/index.html
	else
		sed -i {{SED_INPLACE_OPTION}} public/static/index.html
	fi

# Remove the public `index.html` file.
uninstall-client-index:
	rm -f public/static/index.html

# Compile the Elm application to JS.
install-client-application:
	cd source/client && elm make src/Main.elm --optimize --output ../../public/static/javascript/application.elm.js
	cd public/static/javascript && \
		uglifyjs application.elm.js \
			--compress 'pure_funcs="F2,F3,F4,F5,F6,F7,F8,F9,A2,A3,A4,A5,A6,A7,A8,A9",pure_getters,keep_fargs=false,unsafe_comps,unsafe' | \
		uglifyjs \
			--mangle \
			--output=application.min.elm.js && \
		gzip --best --stdout application.min.elm.js > application.min.elm.js.gz && \
		brotli --best --stdout application.min.elm.js > application.min.elm.js.br

# Test the Elm application.
test-client-application:
	cd source/client && elm-test tests/unit/

# Remove the Elm build artifact.
uninstall-client-application:
	rm -f public/static/javascript/application.elm.js

# Install client dependencies.
install-client-dependencies: install-mapbox-gl-js install-mapbox-gl-css

# Uninstall client dependencies.
uninstall-client-dependencies: uninstall-mapbox-gl-js uninstall-mapbox-gl-css

# Install Mapbox GL JS, so JS and SourceMap.
install-mapbox-gl-js:
	cd public/static/javascript/ && \
		curl -L https://api.tiles.mapbox.com/mapbox-gl-js/v{{mapbox_gl_js_version}}/mapbox-gl.js > mapbox-gl.js && \
		curl -L https://api.tiles.mapbox.com/mapbox-gl-js/v{{mapbox_gl_js_version}}/mapbox-gl.js.map > mapbox-gl.js.map && \
		uglifyjs \
			--compress \
			--mangle \
			--output=mapbox-gl.min.js mapbox-gl.js && \
		gzip --best --stdout mapbox-gl.min.js > mapbox-gl.min.js.gz && \
		brotli --best --stdout mapbox-gl.min.js > mapbox-gl.min.js.br

# Install Mapbox GL CSS
install-mapbox-gl-css:
	cd public/static/css/ && \
		curl -L https://api.tiles.mapbox.com/mapbox-gl-js/v{{mapbox_gl_js_version}}/mapbox-gl.css > mapbox-gl.css 

# Uninstall Mapbox GL JS.
uninstall-mapbox-gl-js:
	rm public/static/javascript/mapbox-gl.js
	rm public/static/javascript/mapbox-gl.js.map

# Uninstall Mapbox GL CSS.
uninstall-mapbox-gl-css:
	rm public/static/css/mapbox-gl.css

# Local Variables:
# mode: makefile
# End:


================================================
FILE: public/static/css/default.css
================================================
:root {
    --brand-color        : hsla(221,  40%,  14%, 1  );
    --alt-color-lighter  : hsla(  9,  93%, 100%, 1  );
    --alt-color-light    : hsla(  9,  50%,  72%, 1  );
    --alt-color          : hsla(  9,  93%,  72%, 1  );
    --alt-color-dark     : hsla(  9,  93%,  25%,  .7);
    --spacing            : 1rem;
    --spacing-small      : calc(var(--spacing) / 2);
    --spacing-large      : calc(var(--spacing) * 2);
    --border-radius      : 2px;
    --transition-duration: .1s;

    --panel-width                   : 100vw;
    --panel-height                  : 70vh;
    --panel-min-width               : auto;
    --panel-max-width               : auto;
    --panel-unexpanded-translate-x  : 0;
    --panel-unexpanded-translate-y  : -100%;
    --panel-expanded-map-translate-x: 0;
    --panel-expanded-map-translate-y: 35vh;
}

@media all and (min-width: 600px) {
    :root {
        --panel-width                   : 30vw;
        --panel-height                  : 100vh;
        --panel-min-width               : 300px;
        --panel-max-width               : 500px;
        --panel-unexpanded-translate-x  : -100%;
        --panel-unexpanded-translate-y  : 0;
        --panel-expanded-map-translate-x: 15vw;;
        --panel-expanded-map-translate-y: 0;
    }
}

@font-face {
    font-family: Text;
    src: url('../font/OpenSans-regular.woff') format('woff');
    font-weight: normal;
    font-style: normal;
    font-display: swap;
}

* {
    box-sizing: border-box !important;
    margin: 0;
    padding: 0;
}

[aria-hidden="true"] {
    display: none;
}

html {
    font-size: 100%;
}

body {
    color: var(--brand-color);
    font: 1.1rem/1.4rem Text, system-ui, sans-serif;
    -webkit-font-smoothing: antialiased;
    height: 100vh;
}

#body-background {
    position: absolute;
    object-fit: cover;
    width: 100%;
    height: 100%;
}

main {
    position: relative;
    width: 100vw;
    height: 100vh;
    overflow: hidden;
}

nav > form[role="search"] {
    position: fixed;
    top: var(--spacing);
    padding: 0 var(--spacing);
    width: var(--panel-width);
    min-width: var(--panel-min-width);
    max-width: var(--panel-max-width);
    z-index: 2;
}

nav > section {
    z-index: 1;
    position: absolute;
    width: var(--panel-width);
    min-width: var(--panel-min-width);
    max-width: var(--panel-max-width);
    height: var(--panel-height);
    padding: var(--spacing);
    display: flex;
    flex-direction: column;
    background: var(--alt-color);

    transform:
        translateX(var(--panel-unexpanded-translate-x))
        translateY(var(--panel-unexpanded-translate-y));
    transition: var(--transition-duration) transform ease-in-out;
}

    nav[aria-expanded="true"] > section {
        box-shadow: 3px 0 var(--spacing) var(--alt-color-dark);
        transform: translateX(0) translateY(0);
    }

article {
    position: absolute !important;
    width: 100vw;
    height: 100vh;
}

    article > .mapboxgl-canvas-container {
        transform: translateX(0) translateY(0);
        transition: var(--transition-duration) transform ease-in-out;
    }

    nav[aria-expanded="true"] ~ article > .mapboxgl-canvas-container {
        transform:
            translateX(var(--panel-expanded-map-translate-x))
            translateY(var(--panel-expanded-map-translate-y));
    }

footer {
    position: fixed;
    bottom: var(--spacing);
    right: var(--spacing);
    color: var(--alt-color);
    font-size: 1.1em;
    font-weight: bold;
    font-variant: all-small-caps;
    letter-spacing: .1em;
    text-shadow:
        var(--alt-color-lighter)  0    2px,
        var(--alt-color-lighter)  0   -2px,
        var(--alt-color-lighter)  2px  0,
        var(--alt-color-lighter) -2px  0;
}

@media all and (min-width: 600px) {
    footer {
        right: auto;
        left: 50%;
        transform: translateX(-50%);
    }
}

input {
    all: unset;
    -moz-appearance: none;
    -webkit-appearance: none;
    appearance: none;
    width: 100%;
    padding: var(--spacing-small) var(--spacing);
    line-height: var(--spacing-large);
    border: 1px var(--alt-color-light) solid;
    border-radius: var(--border-radius);
    background: var(--alt-color-lighter);
}

#map {
    font: inherit;
}

    #map .mapboxgl-ctrl-group {
        border: 1px var(--alt-color-light) solid;
        box-shadow: unset;
    }

    #map .mapboxgl-ctrl-icon {
        border-color: var(--alt-color-light);
    }

    #map .mapboxgl-ctrl-attrib {
        font-size: .6em;
        background: hsla(0, 0%, 100%, .8);
    }


================================================
FILE: public/static/image/README.md
================================================
# `map-placeholder.svg`

1. Raster a part of the map,
2. Install [`primitive`](https://github.com/fogleman/primitive),
3. `primitive -m 1 -n 60 -i map-rasterized.png -o map-triangles.svg`,
4. Optimise it with [SVGOMG](https://jakearchibald.github.io/svgomg/),
5. Put the paths (only) into the following template:
   ```xml
   <svg xmlns="http://www.w3.org/2000/svg" width="1024" height="540" version="1">
     <filter id="blur">
       <feGaussianBlur stdDeviation="12" />
     </filter>
     <g filter="url(#blur)">
       …
     </g>
   </svg>
   ```


================================================
FILE: public/static/javascript/main.js
================================================
(
    () => {
        const atlasr = Elm.Atlasr.Main.init({
            node: document.body,
            flags: 1
        });
        const LAYER_ROUTE_MARKERS_PREFIX = 'markers-';
        let   map                        = null;
        let   layer_route_markers        = '';
        let   markers                    = [];

        atlasr.ports.mapboxgl_create_map.subscribe(
            ([id, options]) => {
                mapboxgl.accessToken = 'undefined';

                map = new mapboxgl.Map({
                    container         : id,
                    style             : options.style,
                    center            : options.center,
                    zoom              : options.zoom,
                    hash              : options.hash,
                    pitchWithRotate   : options.pitchWithRotate,
                    attributionControl: options.attributionControl,
                    dragRotate        : options.dragRotate,
                    dragPan           : options.dragPan,
                    keyboard          : options.keyboard,
                    doubleClickZoom   : options.doubleClickZoom,
                    touchZoomRotate   : options.touchZoomRotate,
                    trackResize       : options.trackResize,
                    renderWorldCopies : options.renderWorldCopies
                });
                map.addControl(
                    new mapboxgl.GeolocateControl(
                        {
                            positionOptions: {
                                enableHighAccuracy: true
                            },
                            trackUserLocation: true
                        }
                    ),
                    'bottom-right'
                );
                map.addControl(
                    new mapboxgl.NavigationControl(),
                    'bottom-right'
                );
            }
        );
        atlasr.ports.mapboxgl_fly_to.subscribe(
            (cameraOptions) => {
                map.flyTo(cameraOptions);
            }
        );
        atlasr.ports.mapboxgl_add_markers.subscribe(
            (positions) => {
                for (let [longitude, latitude] of positions) {
                    markers.push(
                        new mapboxgl.Marker()
                            .setLngLat([longitude, latitude])
                            .addTo(map)
                    );
                }
            }
        );
        atlasr.ports.mapboxgl_remove_markers.subscribe(
            () => {
                for (let marker of markers) {
                    marker.remove();
                }

                markers = [];

                if (undefined !== map.getLayer(layer_route_markers)) {
                    map.removeLayer(layer_route_markers);
                }
            }
        );
        atlasr.ports.mapboxgl_connect_markers.subscribe(
            (positions) => {
                if (1 < positions.length) {
                    layer_route_markers = LAYER_ROUTE_MARKERS_PREFIX + guid();

                    map.addLayer({
                        'id': layer_route_markers,
                        'type': 'line',
                        'source': {
                            'type': 'geojson',
                            'data': {
                                'type': 'Feature',
                                'properties': {},
                                'geometry': {
                                    'type': 'LineString',
                                    'coordinates': positions
                                }
                            }
                        },
                        'layout': {
                            'line-join': 'round',
                            'line-cap': 'round'
                        },
                        'paint': {
                            'line-color': '#00b3fd',
                            'line-width': 8
                        }
                    });
                }
            }
        );

        function guid() {
            const s4 = () => {
                return Math.floor((1 + Math.random()) * 0x10000)
                    .toString(16)
                    .substring(1);
            };

            return s4() + s4() + '-' + s4() + '-' + s4() + '-' + s4() + '-' + s4() + s4() + s4();
        }
    }
)();


================================================
FILE: source/api/geocode/indexer/Cargo.toml
================================================
[package]
name = "atlasr-api-geocode-indexer"
version = "0.1.0"
authors = ["Ivan Enderlin <ivan.enderlin@hoa-project.net>"]

[dependencies]
tantivy = "^0.6"
clap = "^2.31.2"
failure = "^0.1.1"
csv = "^1.0.0"
serde = "^1.0.66"
serde_derive = "^1.0.66"

================================================
FILE: source/api/geocode/indexer/src/main.rs
================================================
extern crate failure;
extern crate clap;
extern crate csv;
#[macro_use] extern crate serde_derive;
extern crate tantivy;

use failure::{
    Error,
    ResultExt
};
use clap::{App, Arg};
use tantivy::{
    Index,
    IndexWriter,
    directory,
    schema::*
};
use std::fs::File;
use std::io::{
    self,
    BufReader,
    Write
};

/// [Definition of these fields](http://osmnames.readthedocs.io/en/latest/introduction.html#output-format).
#[derive(Debug, Deserialize)]
struct Record {
    name: String,
    alternative_names: Option<String>,
    osm_type: String,
    osm_id: u64,
    class: String,
    #[serde(rename = "type")]
    object_type: String,
    #[serde(rename = "lon")]
    longitude: Option<f64>,
    #[serde(rename = "lat")]
    latitude: Option<f64>,
    place_rank: Option<u64>,
    importance: Option<f64>,
    street: Option<String>,
    city: Option<String>,
    county: Option<String>,
    state: Option<String>,
    country: Option<String>,
    country_code: Option<String>,
    display_name: String,
    #[serde(rename = "west")]
    bbox_west: Option<f64>,
    #[serde(rename = "south")]
    bbox_south: Option<f64>,
    #[serde(rename = "east")]
    bbox_east: Option<f64>,
    #[serde(rename = "north")]
    bbox_north: Option<f64>,
    wikidata: Option<String>,
    wikipedia: Option<String>,
    housenumbers: Option<String>
}

impl Record {
    fn indexable(&self) -> bool {
        if self.longitude.is_none() || self.latitude.is_none() {
            return false;
        }

        match (self.class.as_str(), self.object_type.as_str()) {
            ("boundary", _) |
            ("highway", "residential") => {
                return true;
            },

            (_, _) => { }
        }

        false
    }
}

fn create_schema() -> Schema {
    let mut schema_builder = SchemaBuilder::default();

    schema_builder.add_text_field("display_name", TEXT | STORED);
    schema_builder.add_text_field("class", STORED);
    schema_builder.add_text_field("type", STORED);
    schema_builder.add_text_field("longitude", STORED);
    schema_builder.add_text_field("latitude", STORED);

    schema_builder.build()
}

fn create_index(index_directory: directory::MmapDirectory, schema: &Schema) -> Index {
    Index::create(index_directory, schema.clone()).unwrap()
}

fn index_record(index_writer: &mut IndexWriter, schema: &Schema, record: Record) -> tantivy::Result<()> {
    if ! record.indexable() {
        return Ok(());
    }

    let field_display_name = schema.get_field("display_name").unwrap();
    let field_class = schema.get_field("class").unwrap();
    let field_type = schema.get_field("type").unwrap();
    let field_longitude = schema.get_field("longitude").unwrap();
    let field_latitude = schema.get_field("latitude").unwrap();

    let mut document = Document::default();
    document.add_text(field_display_name, &record.display_name);
    document.add_text(field_class, &record.class);
    document.add_text(field_type, &record.object_type);
    document.add_text(field_longitude, &record.longitude.unwrap().to_string());
    document.add_text(field_latitude, &record.latitude.unwrap().to_string());

    index_writer.add_document(document);

    Ok(())
}

fn main() -> Result<(), Error> {
    let matches =
        App::new("atlasr-api-geocode-indexer")
            .version(env!("CARGO_PKG_VERSION"))
            .about("Atlasr: Indexer for the geocode API.")
            .author("Ivan Enderlin")
            .arg(
                Arg::with_name("source-file")
                    .help("File containing the data to index, must be a `.tsv` file.")
                    .short("s")
                    .long("source-file")
                    .value_name("SOURCE_FILE")
                    .takes_value(true)
                    .required(true)
            )
            .arg(
                Arg::with_name("index-directory")
                    .help("Directory that will contain the index.")
                    .short("i")
                    .long("index-directory")
                    .value_name("INDEX_DIRECTORY")
                    .takes_value(true)
                    .required(true)
            )
            .get_matches();

    let source_file_name = matches.value_of("source-file").unwrap();
    let source_file = File::open(source_file_name).context("Cannot open the given file.")?;
    let source_buffer = BufReader::new(source_file);

    let mut source_reader =
        csv::ReaderBuilder::new()
            .delimiter(b'\t')
            .double_quote(false)
            .flexible(true)
            .from_reader(source_buffer);

    let index_directory = matches.value_of("index-directory").unwrap();
    let schema = create_schema();
    let index = create_index(directory::MmapDirectory::open(index_directory)?, &schema);
    let mut index_writer = index.writer(50_000_000)?;
    let stdout = io::stdout();
    let mut handle = stdout.lock();

    for record in source_reader.deserialize() {
        let record: Record = record?;

        handle.write(b"~~> ").unwrap();
        handle.write(record.name.as_bytes()).unwrap();
        handle.write(b"\n").unwrap();

        index_record(&mut index_writer, &schema, record)?;
    }

    index_writer.commit()?;

    Ok(())
}


================================================
FILE: source/api/geocode/searcher/Cargo.toml
================================================
[package]
name = "atlasr-api-geocode-searcher"
version = "0.1.0"
authors = ["Ivan Enderlin <ivan.enderlin@hoa-project.net>"]

[dependencies]
tantivy = "^0.6"
actix-web = "^0.6.10"

================================================
FILE: source/api/geocode/searcher/src/main.rs
================================================
extern crate actix_web;
extern crate tantivy;

use actix_web::{
    App,
    HttpRequest,
    HttpResponse,
    http::Method,
    server
};
use tantivy::{
    Index,
    collector::TopCollector,
    directory,
    query::QueryParser
};
use std::cmp::min;

const GEOCODE_API_ADDRESS: &'static str = env!("GEOCODE_API_ADDRESS");

struct SearchState {
    index: Index,
    query_parser: QueryParser
}

fn serve_search(request: HttpRequest<SearchState>) -> HttpResponse {
    let term: &str;

    match request.query().get("term") {
        Some(value) => term = value,
        None => return HttpResponse::BadRequest().reason("Query `term` is missing").finish()
    }

    let limit: u8 = match request.query().get("limit") {
        Some(value) => min(value.parse().unwrap_or(3), 10),
        None => 3
    };

    let index = &request.state().index;
    let query_parser = &request.state().query_parser;

    let schema = index.schema();
    let searcher = index.searcher();

    let query = match query_parser.parse_query(term) {
        Ok(value) => {
            value
        },

        Err(_) => {
            return HttpResponse::InternalServerError().finish();
        }
    };

    let mut top_collector = TopCollector::with_limit(limit as usize);

    match searcher.search(&*query, &mut top_collector) {
        Err(_) => {
            return HttpResponse::InternalServerError().finish();
        }

        _ => { }
    }

    let mut response = String::from("[");

    for document in top_collector.docs() {
        let retrieved_document = match searcher.doc(&document) {
            Ok(value) => {
                value
            },

            Err(_) => {
                return HttpResponse::InternalServerError().finish();
            }
        };

        response.push_str(&schema.to_json(&retrieved_document));
        response.push_str(",");
    }

    if response.len() > 1 {
        response.pop();
    }

    response.push_str("]");

    HttpResponse::Ok().content_type("application/json").body(response)
}

fn main() {
    server
        ::new(
            || {
                App
                    ::with_state(
                        {
                            let index = Index::open(directory::MmapDirectory::open("../index").unwrap()).unwrap();
                            index.load_searchers().unwrap();

                            let schema = index.schema();
                            let query_parser = QueryParser::for_index(
                                &index,
                                vec![
                                    schema.get_field("display_name").unwrap()
                                ]
                            );

                            SearchState {
                                index: index,
                                query_parser: query_parser
                            }
                        }
                    )
                    .resource(
                        "/search", // ?term=…&limit=…
                        |resource| {
                            resource.method(Method::GET).f(serve_search)
                        }
                    )
            }
        )
        .bind(GEOCODE_API_ADDRESS)
        .expect(&format!("Cannot bind the server to {}.", GEOCODE_API_ADDRESS))
        .shutdown_timeout(30)
        .run();
}


================================================
FILE: source/api/tile/Cargo.toml
================================================
[package]
name = "atlasr-api-tile"
version = "0.1.0"
authors = ["Ivan Enderlin <ivan.enderlin@hoa-project.net>"]

[dependencies]
warp = "^0.1.9"
diesel = { version = "^1.3.3", features = ["sqlite"] }
r2d2 = "^0.8.3"
r2d2-diesel = "^1.0.0"
serde_json = "^1.0.0"

================================================
FILE: source/api/tile/database/.keep
================================================


================================================
FILE: source/api/tile/diesel.toml
================================================
[print_schema]
file = "src/schema.rs"


================================================
FILE: source/api/tile/src/main.rs
================================================
#[macro_use]
extern crate warp;
#[macro_use]
extern crate diesel;
extern crate r2d2;
extern crate r2d2_diesel;
extern crate serde_json as json;

use warp::Filter;
use warp::http;
use diesel::prelude::*;
use r2d2_diesel::ConnectionManager;
use std::net::SocketAddr;
use std::str::FromStr;

mod schema;
mod models;

const SERVER_ADDRESS: &'static str = env!("SERVER_ADDRESS");
const TILE_API_ADDRESS: &'static str = env!("TILE_API_ADDRESS");

fn not_found() -> http::Result<http::Response<Vec<u8>>> {
    http::Response::builder()
        .status(http::StatusCode::NOT_FOUND)
        .header("content-type", "text/plain; charset=utf-8")
        .body(vec![])
}

fn error() -> http::Result<http::Response<String>> {
    http::Response::builder()
        .status(http::StatusCode::NOT_FOUND)
        .header("content-type", "text/plain; charset=utf-8")
        .body("error".to_string())
}

fn main() {
    let manager = ConnectionManager::<SqliteConnection>::new("database/europe_switzerland.mbtiles");
    let pool =
        r2d2::Pool::builder()
            .max_size(15)
            .build(manager)
            .expect("Failed to create pool.");

    let pool1 = pool.clone();
    let pool2 = pool.clone();

    // `GET /<zoom_level>/<tile_column>/<tile_row>/`
    let tiles =
        path!(u8 / u16 / u16)
            .map(
                move |z, x, y| {
                    match pool1.get() {
                        Ok(connection) => {
                            use schema::tiles::dsl::*;
                            use models::Tiles;

                            let x = x as u32;
                            let y = y as u32;
                            let z = z as u32;

                            let y = 2u32.pow(z) - 1 - y;

                            let tile =
                                tiles
                                    .filter(zoom_level.eq(z as i32))
                                    .filter(tile_column.eq(x as i32))
                                    .filter(tile_row.eq(y as i32))
                                    .first::<Tiles>(&*connection);

                            match tile {
                                Ok(tile) => {
                                    http::Response::builder()
                                        .header("content-type", "application/x-protobuf")
                                        .header("content-encoding", "gzip")
                                        .body(tile.tile_data)
                                },

                                Err(_) => {
                                    not_found()
                                }
                            }
                        },

                        Err(_) => {
                            not_found()
                        }
                    }
                }
            );

    // `GET /metadata.json`
    let metadata =
        path!("metadata.json")
            .map(
                move || {
                    match pool2.get() {
                        Ok(connection) => {
                            use schema::metadata::dsl::*;
                            use models::Metadata;

                            match metadata.load::<Metadata>(&*connection) {
                                Ok(all_metadata) => {
                                    let mut output = json::map::Map::with_capacity(all_metadata.len());

                                    for metadatum in all_metadata {
                                        let v = metadatum.value;

                                        let map_value = match metadatum.name.as_ref() {
                                            "bounds" | "center" => {
                                                Ok(
                                                    json::Value::Array(
                                                        v
                                                            .splitn(4, ',')
                                                            .map(
                                                                |p| {
                                                                    json::Value::Number(
                                                                        json::Number::from_str(p).unwrap_or_else(|_| json::Number::from_f64(0.0).unwrap())
                                                                    )
                                                                }
                                                            )
                                                            .collect()
                                                    )
                                                )
                                            },

                                            "json" => {
                                                if let Ok(json::Value::Object(meta_metadata)) = json::from_str(&v) {
                                                    output.extend(meta_metadata);
                                                }

                                                Err(())
                                            },

                                            _ => Ok(json::Value::String(v))
                                        };

                                        if let Ok(map_value) = map_value {
                                            output.insert(metadatum.name, map_value);
                                        }
                                    }

                                    if !output.contains_key("profile") {
                                        output.insert("profile".to_string(), json::Value::String("mercator".to_string()));
                                    }

                                    if !output.contains_key("scale") {
                                        output.insert("scale".to_string(), json::Value::Number(json::Number::from_f64(1.0).unwrap()));
                                    }

                                    if !output.contains_key("tilejson") {
                                        output.insert("tilejson".to_string(), json::Value::String("2.0.0".to_string()));
                                    }

                                    if !output.contains_key("tiles") {
                                        output.insert(
                                            "tiles".to_string(),
                                            json::Value::Array(vec![
                                                json::Value::String(
                                                    format!("http://{}/api/tile/{{z}}/{{x}}/{{y}}", SERVER_ADDRESS)
                                                )
                                            ])
                                        );
                                    }

                                    http::Response::builder()
                                        .header("content-type", "application/json")
                                        .body(json::to_string(&output).unwrap())
                                },

                                Err(_) => error()
                            }
                        },

                        Err(_) => error()
                    }
                }
            );

    let routes = tiles.or(metadata);

    warp::serve(routes)
        .run(TILE_API_ADDRESS.parse::<SocketAddr>().expect(&format!("Cannot bind the server to {}", TILE_API_ADDRESS)));
}


================================================
FILE: source/api/tile/src/models.rs
================================================
#[derive(Debug, Queryable)]
pub struct Tiles {
    pub zoom_level: i32,
    pub tile_column: i32,
    pub tile_row: i32,
    pub tile_data: Vec<u8>,
}

#[derive(Debug, Queryable)]
pub struct Metadata {
    pub name: String,
    pub value: String
}


================================================
FILE: source/api/tile/src/schema.rs
================================================
table! {
    tiles (zoom_level, tile_column, tile_row) {
        zoom_level -> Integer,
        tile_column -> Integer,
        tile_row -> Integer,
        tile_data -> Binary,
    }
}

table! {
    metadata (name, value) {
        name -> Text,
        value -> Text,
    }
}


================================================
FILE: source/client/elm.json
================================================
{
    "type": "application",
    "source-directories": [
        "src"
    ],
    "elm-version": "0.19.0",
    "dependencies": {
        "direct": {
            "elm/browser": "1.0.1",
            "elm/core": "1.0.0",
            "elm/html": "1.0.0",
            "elm/http": "1.0.0",
            "elm/json": "1.0.0",
            "elm/url": "1.0.0",
            "fapian/elm-html-aria": "1.4.0"
        },
        "indirect": {
            "elm/time": "1.0.0",
            "elm/virtual-dom": "1.0.2"
        }
    },
    "test-dependencies": {
        "direct": {},
        "indirect": {}
    }
}

================================================
FILE: source/client/src/Atlasr/Geocode.elm
================================================
module Atlasr.Geocode exposing (Geocode, toGeocodes)

import Atlasr.Position exposing (NamedPosition, defaultNamedPosition)
import Http
import Json.Decode
import Task


type alias Geocode =
    { label : String
    , longitude : String
    , latitude : String
    }


{-| Geocode a list of position names.
-}
toGeocodes : (Result Http.Error (List (Maybe Geocode)) -> msg) -> List NamedPosition -> Cmd msg
toGeocodes outputType positionsToGeocode =
    let
        ( defaultName, defaultPosition ) =
            defaultNamedPosition

        tasks =
            List.map
                (\( positionName, position ) ->
                    if positionName /= defaultName then
                        if position == defaultPosition then
                            positionToGeocodeRequest positionName
                                |> Http.toTask
                                |> Task.map (\geocode -> Just geocode)

                        else
                            let
                                ( longitude, latitude ) =
                                    position

                                geocode =
                                    { label = positionName
                                    , longitude = String.fromFloat longitude
                                    , latitude = String.fromFloat latitude
                                    }
                            in
                            Task.succeed (Just geocode)

                    else
                        Task.succeed Nothing
                )
                positionsToGeocode
    in
    Task.attempt outputType <| Task.sequence tasks


{-| Create an HTTP request to geocode a position.
-}
positionToGeocodeRequest : String -> Http.Request Geocode
positionToGeocodeRequest positionName =
    let
        url =
            "/api/geocode?term=" ++ positionName ++ "&limit=1"
    in
    Http.get url decodeGeocode


{-| Decoder for the geocode payload from the HTTP service.
-}
decodeGeocode : Json.Decode.Decoder Geocode
decodeGeocode =
    Json.Decode.at [ "0" ]
        (Json.Decode.map3
            Geocode
            (Json.Decode.at [ "display_name", "0" ] Json.Decode.string)
            (Json.Decode.at [ "longitude", "0" ] Json.Decode.string)
            (Json.Decode.at [ "latitude", "0" ] Json.Decode.string)
        )


================================================
FILE: source/client/src/Atlasr/Map.elm
================================================
module Atlasr.Map exposing (addMarkers, connectMarkers, create, flyTo, removeMarkers)

import Atlasr.MapboxGL.Options as Options
import Atlasr.MapboxGL.Ports exposing (..)
import Atlasr.Position exposing (Position)


{-| Create a map with an ID and some options.
-}
create : String -> Options.Map -> Cmd msg
create id options =
    mapboxgl_create_map ( id, options )


{-| Move the camera to a specific position.
-}
flyTo : Position -> Cmd msg
flyTo position =
    mapboxgl_fly_to { center = position }


{-| Add markers to certain positions, and connect them.
-}
addMarkers : List Position -> Cmd msg
addMarkers positions =
    mapboxgl_add_markers positions


{-| Remove all markers.
-}
removeMarkers : Cmd msg
removeMarkers =
    mapboxgl_remove_markers ()


{-| Draw lines between points/positions.
-}
connectMarkers : List Position -> Cmd msg
connectMarkers positions =
    mapboxgl_connect_markers positions


================================================
FILE: source/client/src/Atlasr/MapboxGL/Options.elm
================================================
module Atlasr.MapboxGL.Options exposing (Camera, Map, default)

import Atlasr.Position exposing (Position)


type alias Map =
    { style : String
    , center : Position
    , zoom : Int
    , hash : Bool
    , pitchWithRotate : Bool
    , attributionControl : Bool
    , dragRotate : Bool
    , dragPan : Bool
    , keyboard : Bool
    , doubleClickZoom : Bool
    , touchZoomRotate : Bool
    , trackResize : Bool
    , renderWorldCopies : Bool
    }


default : Map
default =
    { style = "/static/map-style/style.json"
    , center = ( 2.294504285127, 48.858262790681 )
    , zoom = 15
    , hash = True
    , pitchWithRotate = True
    , attributionControl = True
    , dragRotate = True
    , dragPan = True
    , keyboard = True
    , doubleClickZoom = True
    , touchZoomRotate = True
    , trackResize = True
    , renderWorldCopies = True
    }


type alias Camera =
    { center : Position }


================================================
FILE: source/client/src/Atlasr/MapboxGL/Ports.elm
================================================
port module Atlasr.MapboxGL.Ports exposing (mapboxgl_add_markers, mapboxgl_connect_markers, mapboxgl_create_map, mapboxgl_fly_to, mapboxgl_remove_markers)

import Atlasr.MapboxGL.Options as Options
import Atlasr.Position exposing (Position)


port mapboxgl_create_map : ( String, Options.Map ) -> Cmd msg


port mapboxgl_fly_to : Options.Camera -> Cmd msg


port mapboxgl_add_markers : List Position -> Cmd msg


port mapboxgl_remove_markers : () -> Cmd msg


port mapboxgl_connect_markers : List Position -> Cmd msg


================================================
FILE: source/client/src/Atlasr/Position.elm
================================================
module Atlasr.Position exposing (Latitude, Longitude, NamedPosition, Position, defaultName, defaultNamedPosition, defaultPosition, extractLatitude, extractLongitude)


type alias Longitude =
    Float


type alias Latitude =
    Float


type alias Position =
    ( Longitude, Latitude )


{-| Allocate a default position.
-}
defaultPosition : Position
defaultPosition =
    ( 0.0, 0.0 )


{-| Extract the longitude of a position.
-}
extractLongitude : Position -> Float
extractLongitude ( longitude, _ ) =
    longitude


{-| Extract the latitude of a position.
-}
extractLatitude : Position -> Float
extractLatitude ( _, latitude ) =
    latitude


type alias NamedPosition =
    ( String, Position )


{-| Allocate a default position name.
-}
defaultName : String
defaultName =
    ""


{-| Allocate a default named position.
-}
defaultNamedPosition : NamedPosition
defaultNamedPosition =
    ( defaultName, defaultPosition )


================================================
FILE: source/client/src/Atlasr/Route.elm
================================================
module Atlasr.Route exposing (Route, toRoute)

import Atlasr.Position exposing (Position)
import Http
import Json.Decode
import Task
import Url.Builder exposing (absolute, string)


type alias Route =
    { points : List Position
    }


type alias RawRoute =
    { points : List Point
    }


type alias Point =
    { longitude : Float
    , latitude : Float
    }


emptyRoute : Route
emptyRoute =
    { points = [] }


{-| Get a route from a list of position.
-}
toRoute : (Result Http.Error Route -> msg) -> List Position -> Cmd msg
toRoute outputType positions =
    let
        task =
            if List.length positions <= 1 then
                Task.succeed emptyRoute

            else
                positionsToRouteRequest positions
                    |> Http.toTask
                    |> Task.map
                        (\route ->
                            Route
                                (List.map
                                    (\point ->
                                        ( point.longitude, point.latitude )
                                    )
                                    route.points
                                )
                        )
    in
    Task.attempt outputType task


{-| Create an HTTP request to get the route between positions.
-}
positionsToRouteRequest : List Position -> Http.Request RawRoute
positionsToRouteRequest positions =
    let
        url =
            absolute
                [ "api/route" ]
                ([ string "points_encoded" "false"
                 , string "vehicle" "car"
                 ]
                    ++ List.map
                        (\position ->
                            let
                                ( longitude, latitude ) =
                                    position
                            in
                            string "point" (String.fromFloat latitude ++ "," ++ String.fromFloat longitude)
                        )
                        positions
                )
    in
    Http.get url decodeRoute


{-| Decoder for the route payload from the HTTP service.
-}
decodeRoute : Json.Decode.Decoder RawRoute
decodeRoute =
    Json.Decode.at [ "paths", "0" ]
        (Json.Decode.map
            RawRoute
            (Json.Decode.at [ "points", "coordinates" ]
                (Json.Decode.list
                    (Json.Decode.map2
                        Point
                        (Json.Decode.field "0" Json.Decode.float)
                        (Json.Decode.field "1" Json.Decode.float)
                    )
                )
            )
        )


================================================
FILE: source/client/src/Main.elm
================================================
module Atlasr.Main exposing (Model, Msg(..), init, main, subscriptions, update, view)

import Array exposing (Array)
import Atlasr.Geocode as Geocode
import Atlasr.Map as Map
import Atlasr.MapboxGL.Options as MapOptions
import Atlasr.Position as Position exposing (NamedPosition, Position)
import Atlasr.Route as Route
import Browser
import Html exposing (..)
import Html.Attributes exposing (..)
import Html.Attributes.Aria exposing (..)
import Html.Events exposing (..)
import Http
import Process
import Task as CoreTask


main =
    Browser.document
        { init = init
        , view = view
        , update = update
        , subscriptions = subscriptions
        }


type alias Model =
    { positions : Array NamedPosition }


init : Int -> ( Model, Cmd Msg )
init x =
    ( { positions = Array.repeat 2 Position.defaultNamedPosition }
    , Map.create "map" MapOptions.default
    )


view : Model -> Browser.Document Msg
view model =
    let
        hasAtLeastOnePositionName =
            Array.toList model.positions
                |> List.any (\( positionName, _ ) -> not (String.isEmpty positionName))

        expandedNav =
            if hasAtLeastOnePositionName then
                "true"

            else
                "false"
    in
    { title = "Atlasr"
    , body =
        [ main_ []
            [ nav
                [ ariaExpanded expandedNav ]
                [ Html.form [ role "search", onSubmit Search ]
                    [ input
                        [ type_ "text"
                        , onInput (NewPositionName 0)
                        , ariaLabel "Browse the world"
                        , ariaRequired True
                        , placeholder "Browse the world"
                        , value
                            (Array.get 0 model.positions
                                |> Maybe.map (\( positionName, _ ) -> positionName)
                                |> Maybe.withDefault Position.defaultName
                            )
                        ]
                        []
                    , input
                        [ type_ "text"
                        , onInput (NewPositionName 1)
                        , ariaLabel "Search for a direction"
                        , ariaRequired False
                        , placeholder "Search for a direction"
                        , value
                            (Array.get 1 model.positions
                                |> Maybe.map (\( positionName, _ ) -> positionName)
                                |> Maybe.withDefault Position.defaultName
                            )
                        ]
                        []
                    , input
                        [ type_ "submit"
                        , value "Search"
                        ]
                        []
                    ]
                , section [] []
                ]
            , article [ id "map" ] []
            , footer [] [ text "Atlasr" ]
            ]
        ]
    }


type Msg
    = NewPositionName Int String
    | GeoencodePositionNames (List NamedPosition)
    | NewPositionGeocodes (Result Http.Error (List (Maybe Geocode.Geocode)))
    | GetRoute (List Position)
    | NewPositionRoute (Result Http.Error Route.Route)
    | Search
    | AddMarkers (List Position)
    | RemoveMarkers
    | ConnectMarkers (List Position)
    | FlyTo Position
    | Chain (List Msg)


update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case msg of
        NewPositionName index positionName ->
            let
                positions =
                    Array.set index ( positionName, Position.defaultPosition ) model.positions
            in
            ( { model | positions = positions }, Cmd.none )

        GeoencodePositionNames positionsToGeocode ->
            ( model, Geocode.toGeocodes NewPositionGeocodes positionsToGeocode )

        NewPositionGeocodes (Ok geocodes) ->
            let
                ( defaultLongitude, defaultLatitude ) =
                    Position.defaultPosition

                namedPositions =
                    List.map
                        (\geocode_item ->
                            Maybe.map
                                (\geocode ->
                                    let
                                        positionName =
                                            geocode.label

                                        position =
                                            ( Maybe.withDefault defaultLongitude (String.toFloat geocode.longitude)
                                            , Maybe.withDefault defaultLatitude (String.toFloat geocode.latitude)
                                            )
                                    in
                                    ( positionName, position )
                                )
                                geocode_item
                        )
                        geocodes

                positions =
                    List.filterMap
                        (\namedPosition ->
                            Maybe.map
                                (\( positionName, position ) -> Just position)
                                namedPosition
                                |> Maybe.withDefault Nothing
                        )
                        namedPositions
            in
            update
                (Chain [ AddMarkers positions, GetRoute positions ])
                { model
                    | positions =
                        List.map
                            (\namedPosition ->
                                Maybe.withDefault Position.defaultNamedPosition namedPosition
                            )
                            namedPositions
                            |> Array.fromList
                }

        NewPositionGeocodes (Err _) ->
            ( model, Cmd.batch [] )

        GetRoute positions ->
            ( model, Route.toRoute NewPositionRoute positions )

        NewPositionRoute (Ok route) ->
            update
                (ConnectMarkers route.points)
                model

        NewPositionRoute (Err _) ->
            ( model, Cmd.batch [] )

        Search ->
            update
                (Chain [ RemoveMarkers, Array.toList model.positions |> GeoencodePositionNames ])
                model

        AddMarkers positions ->
            ( model, Map.addMarkers positions )

        RemoveMarkers ->
            ( model, Map.removeMarkers )

        ConnectMarkers positions ->
            ( model, Map.connectMarkers positions )

        FlyTo position ->
            ( model, Map.flyTo position )

        Chain messages ->
            let
                chain message ( model1, commands ) =
                    let
                        ( nextModel, nextCommands ) =
                            update message model
                    in
                    ( nextModel, Cmd.batch [ commands, nextCommands ] )
            in
            List.foldl chain ( model, Cmd.batch [] ) messages


subscriptions : Model -> Sub Msg
subscriptions model =
    Sub.none


================================================
FILE: source/client/src/index.html
================================================
<!DOCTYPE html>

<html>
  <head>
    <title>Atlasr</title>

    <meta http-equiv="content-type" content="text/html; charset=utf-8" />
    <meta http-equiv="content-type" content="text/javascript; charset=utf-8" />
    <meta http-equiv="content-type" content="text/css; charset=utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />

    <link rel="preload" href="/static/css/default.css" as="style" />
    <link rel="preload" href="/static/javascript/application.min.elm.js" as="script" />
    <link rel="preload" href="/static/javascript/main.js" as="script" />
    <link rel="preload" href="/static/javascript/mapbox-gl.min.js" as="script" />

    <link rel="stylesheet" href="/static/css/default.css" media="all" />
    <script src="/static/javascript/application.min.elm.js"></script>
    <script src="/static/javascript/mapbox-gl.min.js"></script>
    <link rel="stylesheet" href="/static/css/mapbox-gl.css" media="all" />
  </head>
  <body>
    <script src="/static/javascript/main.js" async defer></script>
    <img id="body-background" src="data:image/svg+xml,{MAP-PLACEHOLDER.svg}" />
  </body>
</html>


================================================
FILE: source/client/tests/elm-package.json
================================================
{
    "version": "0.0.0",
    "summary": "Atlasr's test suites",
    "repository": "https://github.com/atlasr-org/atlasr.git",
    "license": "BSD3",
    "source-directories": [
        "../src/",
        "./unit/",
        "./VerifyExamples/"
    ],
    "exposed-modules": [],
    "dependencies": {
        "eeue56/elm-html-test": "5.2.0 <= v < 6.0.0",
        "elm-community/elm-test": "4.0.0 <= v < 5.0.0",
        "elm-lang/core": "5.1.1 <= v < 6.0.0",
        "elm-lang/html": "2.0.0 <= v < 3.0.0",
        "elm-lang/http": "1.0.0 <= v < 2.0.0",
        "fapian/elm-html-aria": "1.2.2 <= v < 2.0.0"
    },
    "elm-version": "0.18.0 <= v < 0.19.0"
}


================================================
FILE: source/client/tests/unit/Atlasr/Test/Position.elm
================================================
module Atlasr.Test.Position exposing (..)

import Atlasr.Position as Position
import Test exposing (..)
import Expect


position : Test
position =
    describe "Test suite for the `Position` module."
        [ test "Default position" <|
            \() ->
                Expect.equal ( 0.0, 0.0 ) Position.defaultPosition
        , test "Extract longitude" <|
            \() ->
                Expect.equal 1.2 (Position.extractLongitude ( 1.2, 3.4 ))
        , test "Extract latitude" <|
            \() ->
                Expect.equal 3.4 (Position.extractLatitude ( 1.2, 3.4 ))
        , test "Default name" <|
            \() ->
                Expect.equal "" Position.defaultName
        , test "Default named position" <|
            \() ->
                Expect.equal ( "", ( 0.0, 0.0 ) ) Position.defaultNamedPosition
        ]


================================================
FILE: source/server/Cargo.toml
================================================
[package]
name = "atlasr-server"
version = "0.0.1"
authors = ["Ivan Enderlin <ivan.enderlin@hoa-project.net>"]

[dependencies]
actix-web = "^0.6.10"
futures = "^0.1.21"

================================================
FILE: source/server/src/main.rs
================================================
extern crate actix_web;
extern crate futures;

use actix_web::{
    App,
    HttpRequest,
    HttpResponse,
    Result,
    dev::HttpResponseBuilder,
    fs::NamedFile,
    http::Method,
    client,
    server,
};
use futures::Future;
use std::path::PathBuf;

macro_rules! ROOT_DIRECTORY { () => { "../../public/" }; }
const STATIC_DIRECTORY: &'static str = concat!(ROOT_DIRECTORY!(), "static/");
const SERVER_ADDRESS: &'static str = env!("SERVER_ADDRESS");
const ROUTE_API_ADDRESS: &'static str = env!("ROUTE_API_ADDRESS");
const GEOCODE_API_ADDRESS: &'static str = env!("GEOCODE_API_ADDRESS");
const TILE_API_ADDRESS: &'static str = env!("TILE_API_ADDRESS");

fn serve_static_files(request: HttpRequest) -> Result<NamedFile> {
    let mut path: PathBuf = PathBuf::from(STATIC_DIRECTORY);
    let tail: String = request.match_info().query("tail")?;

    path.push(tail);

    Ok(NamedFile::open(path)?)
}

fn serve_api_geocode(request: HttpRequest) -> impl Future<Item=HttpResponse, Error=client::SendRequestError> {
    client
        ::get(format!("http://{}/search?{}", GEOCODE_API_ADDRESS, request.query_string()))
        .finish()
        .unwrap()
        .send()
        .map(
            |client_response| {
                HttpResponseBuilder
                    ::from(&client_response)
                    .chunked()
                    .streaming(client_response)
            }
        )
}

fn serve_api_route(request: HttpRequest) -> impl Future<Item=HttpResponse, Error=client::SendRequestError> {
    client
        ::get(format!("http://{}/route?{}", ROUTE_API_ADDRESS, request.query_string()))
        .finish()
        .unwrap()
        .send()
        .map(
            |client_response| {
                HttpResponseBuilder
                    ::from(&client_response)
                    .chunked()
                    .streaming(client_response)
            }
        )
}

fn serve_api_tile(request: HttpRequest) -> impl Future<Item=HttpResponse, Error=client::SendRequestError> {
    let tail = request.match_info().get("tail").unwrap_or("");

    client
        ::get(format!("http://{}/{}", TILE_API_ADDRESS, tail))
        .finish()
        .unwrap()
        .send()
        .map(
            |client_response| {
                HttpResponseBuilder
                    ::from(&client_response)
                    .chunked()
                    .streaming(client_response)
            }
        )
}

fn serve_index(_request: HttpRequest) -> Result<NamedFile> {
    let mut path: PathBuf = PathBuf::from(STATIC_DIRECTORY);

    path.push("index.html");

    Ok(NamedFile::open(path)?)
}

fn main() {
    server
        ::new(
            || {
                vec![
                    App::new()
                        .prefix("/static")
                        .resource(
                            r"/{tail:.*}",
                            |resource| {
                                resource.method(Method::GET).f(serve_static_files)
                            }
                        ),

                    App::new()
                        .prefix("/api")
                        .resource(
                            "/geocode",
                            |resource| {
                                resource.method(Method::GET).a(serve_api_geocode)
                            }
                        )
                        .resource(
                            "/route",
                            |resource| {
                                resource.method(Method::GET).a(serve_api_route)
                            }
                        )
                        .resource(
                            "/tile/{tail:.*}",
                            |resource| {
                                resource.method(Method::GET).a(serve_api_tile)
                            }
                        ),

                    App::new()
                        .prefix("/")
                        .resource(
                            "/index.html",
                            |resource| {
                                resource.method(Method::GET).f(serve_index)
                            }
                        )
                        .resource(
                            "/",
                            |resource| {
                                resource.method(Method::GET).f(serve_index)
                            }
                        )
                ]
            }
        )
        .bind(SERVER_ADDRESS)
        .expect(&format!("Cannot bind the server to {}.", SERVER_ADDRESS))
        .shutdown_timeout(30)
        .run();
}
Download .txt
gitextract_o8etyil8/

├── .gitignore
├── .gitmodules
├── LICENSE
├── README.md
├── justfile
├── public/
│   └── static/
│       ├── css/
│       │   └── default.css
│       ├── image/
│       │   └── README.md
│       └── javascript/
│           └── main.js
└── source/
    ├── api/
    │   ├── geocode/
    │   │   ├── indexer/
    │   │   │   ├── Cargo.toml
    │   │   │   └── src/
    │   │   │       └── main.rs
    │   │   └── searcher/
    │   │       ├── Cargo.toml
    │   │       └── src/
    │   │           └── main.rs
    │   └── tile/
    │       ├── Cargo.toml
    │       ├── database/
    │       │   └── .keep
    │       ├── diesel.toml
    │       └── src/
    │           ├── main.rs
    │           ├── models.rs
    │           └── schema.rs
    ├── client/
    │   ├── elm.json
    │   ├── src/
    │   │   ├── Atlasr/
    │   │   │   ├── Geocode.elm
    │   │   │   ├── Map.elm
    │   │   │   ├── MapboxGL/
    │   │   │   │   ├── Options.elm
    │   │   │   │   └── Ports.elm
    │   │   │   ├── Position.elm
    │   │   │   └── Route.elm
    │   │   ├── Main.elm
    │   │   └── index.html
    │   └── tests/
    │       ├── elm-package.json
    │       └── unit/
    │           └── Atlasr/
    │               └── Test/
    │                   └── Position.elm
    └── server/
        ├── Cargo.toml
        └── src/
            └── main.rs
Download .txt
SYMBOL INDEX (29 symbols across 6 files)

FILE: public/static/javascript/main.js
  function guid (line 110) | function guid() {

FILE: source/api/geocode/indexer/src/main.rs
  type Record (line 27) | struct Record {
    method indexable (line 62) | fn indexable(&self) -> bool {
  function create_schema (line 80) | fn create_schema() -> Schema {
  function create_index (line 92) | fn create_index(index_directory: directory::MmapDirectory, schema: &Sche...
  function index_record (line 96) | fn index_record(index_writer: &mut IndexWriter, schema: &Schema, record:...
  function main (line 119) | fn main() -> Result<(), Error> {

FILE: source/api/geocode/searcher/src/main.rs
  constant GEOCODE_API_ADDRESS (line 19) | const GEOCODE_API_ADDRESS: &'static str = env!("GEOCODE_API_ADDRESS");
  type SearchState (line 21) | struct SearchState {
  function serve_search (line 26) | fn serve_search(request: HttpRequest<SearchState>) -> HttpResponse {
  function main (line 91) | fn main() {

FILE: source/api/tile/src/main.rs
  constant SERVER_ADDRESS (line 19) | const SERVER_ADDRESS: &'static str = env!("SERVER_ADDRESS");
  constant TILE_API_ADDRESS (line 20) | const TILE_API_ADDRESS: &'static str = env!("TILE_API_ADDRESS");
  function not_found (line 22) | fn not_found() -> http::Result<http::Response<Vec<u8>>> {
  function error (line 29) | fn error() -> http::Result<http::Response<String>> {
  function main (line 36) | fn main() {

FILE: source/api/tile/src/models.rs
  type Tiles (line 2) | pub struct Tiles {
  type Metadata (line 10) | pub struct Metadata {

FILE: source/server/src/main.rs
  constant STATIC_DIRECTORY (line 19) | const STATIC_DIRECTORY: &'static str = concat!(ROOT_DIRECTORY!(), "stati...
  constant SERVER_ADDRESS (line 20) | const SERVER_ADDRESS: &'static str = env!("SERVER_ADDRESS");
  constant ROUTE_API_ADDRESS (line 21) | const ROUTE_API_ADDRESS: &'static str = env!("ROUTE_API_ADDRESS");
  constant GEOCODE_API_ADDRESS (line 22) | const GEOCODE_API_ADDRESS: &'static str = env!("GEOCODE_API_ADDRESS");
  constant TILE_API_ADDRESS (line 23) | const TILE_API_ADDRESS: &'static str = env!("TILE_API_ADDRESS");
  function serve_static_files (line 25) | fn serve_static_files(request: HttpRequest) -> Result<NamedFile> {
  function serve_api_geocode (line 34) | fn serve_api_geocode(request: HttpRequest) -> impl Future<Item=HttpRespo...
  function serve_api_route (line 50) | fn serve_api_route(request: HttpRequest) -> impl Future<Item=HttpRespons...
  function serve_api_tile (line 66) | fn serve_api_tile(request: HttpRequest) -> impl Future<Item=HttpResponse...
  function serve_index (line 84) | fn serve_index(_request: HttpRequest) -> Result<NamedFile> {
  function main (line 92) | fn main() {
Condensed preview — 31 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (70K chars).
[
  {
    "path": ".gitignore",
    "chars": 413,
    "preview": "/public/static/css/mapbox-gl.*\n/public/static/index.html\n/public/static/javascript/*.elm.js*\n/public/static/javascript/m"
  },
  {
    "path": ".gitmodules",
    "chars": 233,
    "preview": "[submodule \"source/api/graphhopper\"]\n\tpath = source/api/route\n\turl = https://github.com/atlasr-org/graphhopper\n\tbranch ="
  },
  {
    "path": "LICENSE",
    "chars": 1557,
    "preview": "                                New BSD License\n\nCopyright © 2018, Ivan Enderlin.\nAll rights reserved.\n\nRedistribution a"
  },
  {
    "path": "README.md",
    "chars": 6832,
    "preview": "# 🌍 Atlasr\n\nAtlasr is a truly open-source and free map browser. The goal is threefold:\n\n  1. Learn about all the layers "
  },
  {
    "path": "justfile",
    "chars": 6083,
    "preview": "# vim: filetype=just\n\nmapbox_gl_js_version = \"0.50.0\"\nserver_address = \"localhost:8889\"\ngeocode_api_address = \"localhost"
  },
  {
    "path": "public/static/css/default.css",
    "chars": 4554,
    "preview": ":root {\n    --brand-color        : hsla(221,  40%,  14%, 1  );\n    --alt-color-lighter  : hsla(  9,  93%, 100%, 1  );\n  "
  },
  {
    "path": "public/static/image/README.md",
    "chars": 553,
    "preview": "# `map-placeholder.svg`\n\n1. Raster a part of the map,\n2. Install [`primitive`](https://github.com/fogleman/primitive),\n3"
  },
  {
    "path": "public/static/javascript/main.js",
    "chars": 4365,
    "preview": "(\n    () => {\n        const atlasr = Elm.Atlasr.Main.init({\n            node: document.body,\n            flags: 1\n      "
  },
  {
    "path": "source/api/geocode/indexer/Cargo.toml",
    "chars": 250,
    "preview": "[package]\nname = \"atlasr-api-geocode-indexer\"\nversion = \"0.1.0\"\nauthors = [\"Ivan Enderlin <ivan.enderlin@hoa-project.net"
  },
  {
    "path": "source/api/geocode/indexer/src/main.rs",
    "chars": 5257,
    "preview": "extern crate failure;\nextern crate clap;\nextern crate csv;\n#[macro_use] extern crate serde_derive;\nextern crate tantivy;"
  },
  {
    "path": "source/api/geocode/searcher/Cargo.toml",
    "chars": 179,
    "preview": "[package]\nname = \"atlasr-api-geocode-searcher\"\nversion = \"0.1.0\"\nauthors = [\"Ivan Enderlin <ivan.enderlin@hoa-project.ne"
  },
  {
    "path": "source/api/geocode/searcher/src/main.rs",
    "chars": 3353,
    "preview": "extern crate actix_web;\nextern crate tantivy;\n\nuse actix_web::{\n    App,\n    HttpRequest,\n    HttpResponse,\n    http::Me"
  },
  {
    "path": "source/api/tile/Cargo.toml",
    "chars": 260,
    "preview": "[package]\nname = \"atlasr-api-tile\"\nversion = \"0.1.0\"\nauthors = [\"Ivan Enderlin <ivan.enderlin@hoa-project.net>\"]\n\n[depen"
  },
  {
    "path": "source/api/tile/database/.keep",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "source/api/tile/diesel.toml",
    "chars": 38,
    "preview": "[print_schema]\nfile = \"src/schema.rs\"\n"
  },
  {
    "path": "source/api/tile/src/main.rs",
    "chars": 7512,
    "preview": "#[macro_use]\nextern crate warp;\n#[macro_use]\nextern crate diesel;\nextern crate r2d2;\nextern crate r2d2_diesel;\nextern cr"
  },
  {
    "path": "source/api/tile/src/models.rs",
    "chars": 248,
    "preview": "#[derive(Debug, Queryable)]\npub struct Tiles {\n    pub zoom_level: i32,\n    pub tile_column: i32,\n    pub tile_row: i32,"
  },
  {
    "path": "source/api/tile/src/schema.rs",
    "chars": 278,
    "preview": "table! {\n    tiles (zoom_level, tile_column, tile_row) {\n        zoom_level -> Integer,\n        tile_column -> Integer,\n"
  },
  {
    "path": "source/client/elm.json",
    "chars": 594,
    "preview": "{\n    \"type\": \"application\",\n    \"source-directories\": [\n        \"src\"\n    ],\n    \"elm-version\": \"0.19.0\",\n    \"dependen"
  },
  {
    "path": "source/client/src/Atlasr/Geocode.elm",
    "chars": 2336,
    "preview": "module Atlasr.Geocode exposing (Geocode, toGeocodes)\n\nimport Atlasr.Position exposing (NamedPosition, defaultNamedPositi"
  },
  {
    "path": "source/client/src/Atlasr/Map.elm",
    "chars": 915,
    "preview": "module Atlasr.Map exposing (addMarkers, connectMarkers, create, flyTo, removeMarkers)\n\nimport Atlasr.MapboxGL.Options as"
  },
  {
    "path": "source/client/src/Atlasr/MapboxGL/Options.elm",
    "chars": 906,
    "preview": "module Atlasr.MapboxGL.Options exposing (Camera, Map, default)\n\nimport Atlasr.Position exposing (Position)\n\n\ntype alias "
  },
  {
    "path": "source/client/src/Atlasr/MapboxGL/Ports.elm",
    "chars": 517,
    "preview": "port module Atlasr.MapboxGL.Ports exposing (mapboxgl_add_markers, mapboxgl_connect_markers, mapboxgl_create_map, mapboxg"
  },
  {
    "path": "source/client/src/Atlasr/Position.elm",
    "chars": 928,
    "preview": "module Atlasr.Position exposing (Latitude, Longitude, NamedPosition, Position, defaultName, defaultNamedPosition, defaul"
  },
  {
    "path": "source/client/src/Atlasr/Route.elm",
    "chars": 2603,
    "preview": "module Atlasr.Route exposing (Route, toRoute)\n\nimport Atlasr.Position exposing (Position)\nimport Http\nimport Json.Decode"
  },
  {
    "path": "source/client/src/Main.elm",
    "chars": 7132,
    "preview": "module Atlasr.Main exposing (Model, Msg(..), init, main, subscriptions, update, view)\n\nimport Array exposing (Array)\nimp"
  },
  {
    "path": "source/client/src/index.html",
    "chars": 1144,
    "preview": "<!DOCTYPE html>\n\n<html>\n  <head>\n    <title>Atlasr</title>\n\n    <meta http-equiv=\"content-type\" content=\"text/html; char"
  },
  {
    "path": "source/client/tests/elm-package.json",
    "chars": 655,
    "preview": "{\n    \"version\": \"0.0.0\",\n    \"summary\": \"Atlasr's test suites\",\n    \"repository\": \"https://github.com/atlasr-org/atlasr"
  },
  {
    "path": "source/client/tests/unit/Atlasr/Test/Position.elm",
    "chars": 840,
    "preview": "module Atlasr.Test.Position exposing (..)\n\nimport Atlasr.Position as Position\nimport Test exposing (..)\nimport Expect\n\n\n"
  },
  {
    "path": "source/server/Cargo.toml",
    "chars": 168,
    "preview": "[package]\nname = \"atlasr-server\"\nversion = \"0.0.1\"\nauthors = [\"Ivan Enderlin <ivan.enderlin@hoa-project.net>\"]\n\n[depende"
  },
  {
    "path": "source/server/src/main.rs",
    "chars": 4617,
    "preview": "extern crate actix_web;\nextern crate futures;\n\nuse actix_web::{\n    App,\n    HttpRequest,\n    HttpResponse,\n    Result,\n"
  }
]

About this extraction

This page contains the full source code of the atlasr-org/atlasr GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 31 files (63.8 KB), approximately 15.4k tokens, and a symbol index with 29 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!