Index: /trunk/data/gpx-drawing-extensions-1.0.xsd
===================================================================
--- /trunk/data/gpx-drawing-extensions-1.0.xsd	(revision 15496)
+++ /trunk/data/gpx-drawing-extensions-1.0.xsd	(revision 15496)
@@ -0,0 +1,103 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<schema targetNamespace="https://josm.openstreetmap.de/gpx-drawing-extensions-1.0"
+    elementFormDefault="qualified"
+    xmlns="http://www.w3.org/2001/XMLSchema"
+    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xmlns:gpxd="https://josm.openstreetmap.de/gpx-drawing-extensions-1.0"
+    xsi:schemaLocation="https://josm.openstreetmap.de/gpx-drawing-extensions-1.0 https://josm.openstreetmap.de/gpx-drawing-extensions-1.0.xsd">
+
+    <xsd:annotation>
+        <xsd:documentation>
+            This schema defines drawing extensions for the GPX 1.1 schema (http://www.topografix.com/GPX/1/1/gpx.xsd).
+            Elements in this schema should be used as child elements of the "extensions" element defined by the GPX schema.
+        </xsd:documentation>
+    </xsd:annotation>
+    
+    <!-- Elements -->
+
+    <xsd:element name="color" type="gpxd:hexColor_type">
+        <xsd:annotation>
+            <xsd:documentation>
+                The color of the element, i.e. #RRGGBB or #RRGGBBAA.
+                Note that applications should apply possible alpha values to the lines and opacity to the whole track. This means that overlapping parts of the
+                track with alpha values will look more intense than individual lines, whereas the opacity affects the whole track including overlapping parts.
+            </xsd:documentation>
+        </xsd:annotation>
+    </xsd:element>
+    
+    <xsd:element name="opacity" type="gpxd:opacity_type">
+        <xsd:annotation>
+            <xsd:documentation>
+                The opacity of the element between 0.00 and 1.00.
+            </xsd:documentation>
+        </xsd:annotation>
+    </xsd:element>
+    
+    <xsd:element name="width" type="xsd:positiveInteger">
+        <xsd:annotation>
+            <xsd:documentation>
+                The width of the line in pixels, applications may use a width relative to this value if required.
+            </xsd:documentation>
+        </xsd:annotation>
+    </xsd:element>
+    
+    <xsd:element name="dashPattern" type="gpxd:dashPattern_type">
+        <xsd:annotation>
+            <xsd:documentation>
+                The dash pattern of the line, see gpxd:dashPattern_type. Should always be relative to the width.
+            </xsd:documentation>
+        </xsd:annotation>
+    </xsd:element>
+    
+    <!-- Types -->
+
+    <xsd:simpleType name="hexColor_type">
+        <xsd:annotation>
+            <xsd:documentation>
+                The hexColor_type must be a # followed by a 6 or 8-digit hex representation of the color (with or without the alpha value).            
+            </xsd:documentation>
+        </xsd:annotation>
+        <xsd:restriction base="xsd:string">
+            <xsd:pattern value="\#([a-fA-F0-9]{6}|[a-fA-F0-9]{8})" />
+            <xsd:whiteSpace value="collapse" />
+        </xsd:restriction>
+    </xsd:simpleType>
+
+    <xsd:simpleType name="opacity_type">
+        <xsd:annotation>
+            <xsd:documentation>
+                The opacity_type must be a decimal value between 0 and 1.
+            </xsd:documentation>
+        </xsd:annotation>
+        <xsd:restriction base="xsd:decimal">
+            <xsd:minInclusive value="0" />
+            <xsd:maxInclusive value="1" />
+        </xsd:restriction>
+    </xsd:simpleType>
+    
+    <xsd:simpleType name="dashPattern_type">
+        <xsd:annotation>
+            <xsd:documentation>
+                The dashPattern_type can be 
+                    - a representation of the pattern as y-n-y-n-... with y being the relative length of the line that is
+                      visible and n being the relative length of the line that is hidden to create a dashed / dotted line.
+                      Has to have an even number of segments (at least two) and can contain multi-digit numbers.
+                    - one of the following predefined values:
+                      none, dash-long, dash-medium, dash-short, dot-sparse, dot-normal, dot-dense, dash-dot, dash-dot-dot
+            </xsd:documentation>
+        </xsd:annotation>
+        <xsd:restriction base="xsd:string">               <!-- use string based pattern instead of enum because both pattern and enums are allowed -->
+            <xsd:pattern value="\d+\-\d+(\-\d+\-\d+)*" /> <!-- pattern, see documentation above -->
+            <xsd:pattern value="none" />                  <!-- 1-0, default value/line -->
+            <xsd:pattern value="dash-long" />             <!-- 6-2 -->
+            <xsd:pattern value="dash-medium" />           <!-- 4-4 -->
+            <xsd:pattern value="dash-short" />            <!-- 2-6 -->
+            <xsd:pattern value="dot-sparse" />            <!-- 1-4 -->
+            <xsd:pattern value="dot-normal" />            <!-- 1-2 -->
+            <xsd:pattern value="dot-dense" />             <!-- 1-1 -->
+            <xsd:pattern value="dash-dot" />              <!-- 4-2-1-2 -->
+            <xsd:pattern value="dash-dot-dot" />          <!-- 4-2-1-2-1-2 -->            
+        </xsd:restriction>
+    </xsd:simpleType>
+</schema>
Index: /trunk/data/gpx-extensions-1.1.xsd
===================================================================
--- /trunk/data/gpx-extensions-1.1.xsd	(revision 15496)
+++ /trunk/data/gpx-extensions-1.1.xsd	(revision 15496)
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<schema targetNamespace="http://josm.openstreetmap.de/gpx-extensions-1.1"
+    elementFormDefault="qualified"
+    xmlns="http://www.w3.org/2001/XMLSchema"
+    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xmlns:josm="http://josm.openstreetmap.de/gpx-extensions-1.1"
+    xsi:schemaLocation="http://josm.openstreetmap.de/gpx-extensions-1.1 http://josm.openstreetmap.de/gpx-extensions-1.1.xsd">
+    
+    <!-- true, if gpx data has been downloaded from the osm server -->
+    <!-- it this case, JOSM improves the rendering of clouds of anonymous TrackPoints -->
+    <element name="from-server" type="boolean"/>
+    
+    <!-- the following properties are only set for marker layer export -->
+    <element name="offset" type="decimal"/>
+    <element name="sync-offset" type="decimal"/>
+    <element name="text" type="string" />
+    
+    <xsd:element name="layerPreferences" type="josm:preferences_type">
+        <xsd:annotation>
+            <xsd:documentation>
+                The layerPreferences contain the preferences that can be set for the layer, e.g. in the "Customize track drawing" dialog in JOSM.
+            </xsd:documentation>
+        </xsd:annotation>
+    </xsd:element>
+
+    <xsd:complexType name="preferences_type">
+        <xsd:sequence>
+            <xsd:element name="entry" type="josm:entry_type" minOccurs="0" />
+        </xsd:sequence>
+    </xsd:complexType>
+
+    <xsd:complexType name="entry_type">
+        <xsd:attribute name="key" type="xsd:string" use="required" />
+        <xsd:attribute name="value" type="xsd:string" use="required" />
+    </xsd:complexType>
+
+</schema>
Index: /trunk/data/validator/deprecated.mapcss
===================================================================
--- /trunk/data/validator/deprecated.mapcss	(revision 15495)
+++ /trunk/data/validator/deprecated.mapcss	(revision 15496)
@@ -662,6 +662,7 @@
   assertMatch: "way roof:color=red roof:colour=green";
 }
-  /* further more universal checks, no autofix */
-*[/:color/][!building:color][!roof:color] {
+/* further more universal checks, no autofix */
+/* gpxd:color has another warning in unnecessary.mapcss */ 
+*[/:color/][!building:color][!roof:color][!gpxd:color] {
   throwWarning: tr("{0} is deprecated", "{0.key}");
   suggestAlternative: ":colour";
Index: /trunk/data/validator/unnecessary.mapcss
===================================================================
--- /trunk/data/validator/unnecessary.mapcss	(revision 15495)
+++ /trunk/data/validator/unnecessary.mapcss	(revision 15496)
@@ -168,9 +168,10 @@
 
 /* #2760 */
-*[/^gpx:/] {
+*[/^(gpx|gpxx|gpxd):/] {
   throwWarning: tr("{0} should not be uploaded", "{0.key}");
   group: tr("unnecessary tag");
   fixRemove: "{0.key}";
   assertMatch: "node gpx:time=2018-01-01T12:00:00Z";
+  assertMatch: "node gpxd:color=#FF0000";
   assertNoMatch: "node source=gpx:foo";
 }
Index: /trunk/src/org/openstreetmap/josm/actions/SaveAction.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/actions/SaveAction.java	(revision 15495)
+++ /trunk/src/org/openstreetmap/josm/actions/SaveAction.java	(revision 15496)
@@ -5,8 +5,15 @@
 import static org.openstreetmap.josm.tools.I18n.tr;
 
+import java.awt.GridBagLayout;
 import java.awt.event.KeyEvent;
 import java.beans.PropertyChangeListener;
 import java.io.File;
 
+import javax.swing.JCheckBox;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.SwingConstants;
+
+import org.openstreetmap.josm.data.gpx.GpxData.GpxDataChangeListener;
 import org.openstreetmap.josm.gui.ExtendedDialog;
 import org.openstreetmap.josm.gui.MainApplication;
@@ -17,4 +24,7 @@
 import org.openstreetmap.josm.gui.layer.OsmDataLayer;
 import org.openstreetmap.josm.gui.layer.SaveToFile;
+import org.openstreetmap.josm.gui.util.GuiHelper;
+import org.openstreetmap.josm.spi.preferences.Config;
+import org.openstreetmap.josm.tools.GBC;
 import org.openstreetmap.josm.tools.Shortcut;
 
@@ -33,4 +43,6 @@
     };
 
+    private final GpxDataChangeListener updateOnRequireSaveChangeGpx = evt -> updateEnabledState();
+
     /**
      * Construct the action with "Save" as label.
@@ -38,5 +50,6 @@
     private SaveAction() {
         super(tr("Save"), "save", tr("Save the current data."),
-                Shortcut.registerShortcut("system:save", tr("File: {0}", tr("Save")), KeyEvent.VK_S, Shortcut.CTRL));
+                Shortcut.registerShortcut("system:save", tr("File: {0}", tr("Save")), KeyEvent.VK_S, Shortcut.CTRL),
+                true);
         setHelpId(ht("/Action/Save"));
     }
@@ -55,6 +68,10 @@
             @Override
             public void layerAdded(LayerAddEvent e) {
-                if (e.getAddedLayer() instanceof OsmDataLayer) {
-                    e.getAddedLayer().addPropertyChangeListener(updateOnRequireSaveChange);
+                Layer l = e.getAddedLayer();
+                if (l instanceof OsmDataLayer) {
+                    l.addPropertyChangeListener(updateOnRequireSaveChange);
+                }
+                if (l instanceof GpxLayer) {
+                    ((GpxLayer) l).data.addWeakChangeListener(updateOnRequireSaveChangeGpx);
                 }
                 super.layerAdded(e);
@@ -63,6 +80,10 @@
             @Override
             public void layerRemoving(LayerRemoveEvent e) {
-                if (e.getRemovedLayer() instanceof OsmDataLayer) {
-                    e.getRemovedLayer().removePropertyChangeListener(updateOnRequireSaveChange);
+                Layer l = e.getRemovedLayer();
+                if (l instanceof OsmDataLayer) {
+                    l.removePropertyChangeListener(updateOnRequireSaveChange);
+                }
+                if (l instanceof GpxLayer) {
+                    ((GpxLayer) l).data.removeChangeListener(updateOnRequireSaveChangeGpx);
                 }
                 super.layerRemoving(e);
@@ -74,7 +95,8 @@
     protected void updateEnabledState() {
         Layer activeLayer = getLayerManager().getActiveLayer();
-        setEnabled(activeLayer != null && activeLayer.isSavable()
-                && (!(activeLayer.getAssociatedFile() != null
-                    && activeLayer instanceof SaveToFile && !((SaveToFile) activeLayer).requiresSaveToFile())));
+        boolean en = activeLayer != null
+                && activeLayer.isSavable() && (!(activeLayer.getAssociatedFile() != null
+                && activeLayer instanceof SaveToFile && !((SaveToFile) activeLayer).requiresSaveToFile()));
+        GuiHelper.runInEDT(() -> setEnabled(en));
     }
 
@@ -86,7 +108,13 @@
         }
 
-        // Ask for overwrite in case of GpxLayer: GpxLayers usually are imports
-        // and modifying is an error most of the time.
-        if (f != null && layer instanceof GpxLayer) {
+        // Ask for overwrite in case of GpxLayer
+        if (f != null && layer instanceof GpxLayer && !Config.getPref().getBoolean("gpx.export.overwrite", false)) {
+            JPanel p = new JPanel(new GridBagLayout());
+            JLabel label = new JLabel(tr("File {0} exists. Overwrite?", f.getName()));
+            label.setHorizontalAlignment(SwingConstants.CENTER);
+            JCheckBox remember = new JCheckBox(tr("Remember choice"));
+            remember.setHorizontalAlignment(SwingConstants.CENTER);
+            p.add(label, GBC.eol().fill(GBC.HORIZONTAL).insets(5, 5, 5, 10));
+            p.add(remember, GBC.eop().fill(GBC.HORIZONTAL));
             ExtendedDialog dialog = new ExtendedDialog(
                     MainApplication.getMainFrame(),
@@ -94,7 +122,9 @@
                     tr("Overwrite"), tr("Cancel"))
                 .setButtonIcons("save_as", "cancel")
-                .setContent(tr("File {0} exists. Overwrite?", f.getName()));
+                .setContent(p);
             if (dialog.showDialog().getValue() != 1) {
                 f = null;
+            } else if (remember.isSelected()) {
+                Config.getPref().putBoolean("gpx.export.overwrite", true);
             }
         }
Index: /trunk/src/org/openstreetmap/josm/actions/SaveActionBase.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/actions/SaveActionBase.java	(revision 15495)
+++ /trunk/src/org/openstreetmap/josm/actions/SaveActionBase.java	(revision 15496)
@@ -20,7 +20,6 @@
 import org.openstreetmap.josm.gui.MainApplication;
 import org.openstreetmap.josm.gui.io.importexport.FileExporter;
+import org.openstreetmap.josm.gui.layer.AbstractModifiableLayer;
 import org.openstreetmap.josm.gui.layer.Layer;
-import org.openstreetmap.josm.gui.layer.OsmDataLayer;
-import org.openstreetmap.josm.gui.layer.SaveToFile;
 import org.openstreetmap.josm.gui.util.GuiHelper;
 import org.openstreetmap.josm.gui.widgets.AbstractFileChooser;
@@ -36,4 +35,6 @@
 public abstract class SaveActionBase extends DiskAccessAction {
 
+    private boolean quiet;
+
     /**
      * Constructs a new {@code SaveActionBase}.
@@ -47,9 +48,23 @@
     }
 
+    /**
+     * Constructs a new {@code SaveActionBase}.
+     * @param name The action's text as displayed on the menu (if it is added to a menu)
+     * @param iconName The filename of the icon to use
+     * @param tooltip A longer description of the action that will be displayed in the tooltip
+     * @param shortcut A ready-created shortcut object or {@code null} if you don't want a shortcut
+     * @param quiet whether the quiet exporter is called
+     * @since 15496
+     */
+    public SaveActionBase(String name, String iconName, String tooltip, Shortcut shortcut, boolean quiet) {
+        super(name, iconName, tooltip, shortcut);
+        this.quiet = quiet;
+    }
+
     @Override
     public void actionPerformed(ActionEvent e) {
         if (!isEnabled())
             return;
-        doSave();
+        doSave(quiet);
     }
 
@@ -59,7 +74,17 @@
      */
     public boolean doSave() {
+        return doSave(false);
+    }
+
+    /**
+     * Saves the active layer.
+     * @param quiet If the file is saved without prompting the user
+     * @return {@code true} if the save operation succeeds
+     * @since 15496
+     */
+    public boolean doSave(boolean quiet) {
         Layer layer = getLayerManager().getActiveLayer();
         if (layer != null && layer.isSavable()) {
-            return doSave(layer);
+            return doSave(layer, quiet);
         }
         return false;
@@ -72,11 +97,19 @@
      */
     public boolean doSave(Layer layer) {
+        return doSave(layer, false);
+    }
+
+    /**
+     * Saves the given layer.
+     * @param layer layer to save
+     * @param quiet If the file is saved without prompting the user
+     * @return {@code true} if the save operation succeeds
+     * @since 15496
+     */
+    public boolean doSave(Layer layer, boolean quiet) {
         if (!layer.checkSaveConditions())
             return false;
-        final boolean requiresSave = layer instanceof SaveToFile && ((SaveToFile) layer).requiresSaveToFile();
-        final boolean result = doInternalSave(layer, getFile(layer));
-        if (!requiresSave) {
-            updateEnabledState();
-        }
+        final boolean result = doInternalSave(layer, getFile(layer), quiet);
+        updateEnabledState();
         return result;
     }
@@ -87,6 +120,5 @@
      * @param file The destination file
      * @param checkSaveConditions if {@code true}, checks preconditions before saving. Set it to {@code false} to skip it
-     * if preconditions have already been checked (as this check can prompt UI dialog in EDT it may be best in some cases
-     * to do it earlier).
+     * and prevent dialogs from being shown.
      * @return {@code true} if the layer has been successfully saved, {@code false} otherwise
      * @since 7204
@@ -95,8 +127,8 @@
         if (checkSaveConditions && !layer.checkSaveConditions())
             return false;
-        return doInternalSave(layer, file);
-    }
-
-    private static boolean doInternalSave(Layer layer, File file) {
+        return doInternalSave(layer, file, !checkSaveConditions);
+    }
+
+    private static boolean doInternalSave(Layer layer, File file, boolean quiet) {
         if (file == null)
             return false;
@@ -107,5 +139,9 @@
             for (FileExporter exporter : ExtensionFileFilter.getExporters()) {
                 if (exporter.acceptFile(file, layer)) {
-                    exporter.exportData(file, layer);
+                    if (quiet) {
+                        exporter.exportDataQuiet(file, layer);
+                    } else {
+                        exporter.exportData(file, layer);
+                    }
                     exported = true;
                     canceled = exporter.isCanceled();
@@ -125,6 +161,6 @@
             }
             layer.setAssociatedFile(file);
-            if (layer instanceof OsmDataLayer) {
-                ((OsmDataLayer) layer).onPostSaveToFile();
+            if (layer instanceof AbstractModifiableLayer) {
+                ((AbstractModifiableLayer) layer).onPostSaveToFile();
             }
         } catch (IOException | InvalidPathException e) {
Index: /trunk/src/org/openstreetmap/josm/actions/SaveAsAction.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/actions/SaveAsAction.java	(revision 15495)
+++ /trunk/src/org/openstreetmap/josm/actions/SaveAsAction.java	(revision 15496)
@@ -25,5 +25,5 @@
         super(tr("Save As..."), "save_as", tr("Save the current data to a new file."),
             Shortcut.registerShortcut("system:saveas", tr("File: {0}", tr("Save As...")),
-            KeyEvent.VK_S, Shortcut.CTRL_SHIFT));
+            KeyEvent.VK_S, Shortcut.CTRL_SHIFT), false);
         setHelpId(ht("/Action/SaveAs"));
     }
Index: /trunk/src/org/openstreetmap/josm/actions/ShowStatusReportAction.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/actions/ShowStatusReportAction.java	(revision 15495)
+++ /trunk/src/org/openstreetmap/josm/actions/ShowStatusReportAction.java	(revision 15496)
@@ -294,6 +294,5 @@
 
         Preferences.main().getAllSettings().forEach((key, setting) -> {
-            if (key.startsWith("marker.show")
-                    || "file-open.history".equals(key)
+            if ("file-open.history".equals(key)
                     || "download.overpass.query".equals(key)
                     || "download.overpass.queries".equals(key)
Index: /trunk/src/org/openstreetmap/josm/actions/relation/ExportRelationToGpxAction.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/actions/relation/ExportRelationToGpxAction.java	(revision 15495)
+++ /trunk/src/org/openstreetmap/josm/actions/relation/ExportRelationToGpxAction.java	(revision 15496)
@@ -26,5 +26,5 @@
 import org.openstreetmap.josm.actions.IPrimitiveAction;
 import org.openstreetmap.josm.data.gpx.GpxData;
-import org.openstreetmap.josm.data.gpx.ImmutableGpxTrack;
+import org.openstreetmap.josm.data.gpx.GpxTrack;
 import org.openstreetmap.josm.data.gpx.WayPoint;
 import org.openstreetmap.josm.data.osm.IPrimitive;
@@ -155,5 +155,5 @@
                 if (!wayConnectionType.isOnewayLoopBackwardPart && !wayConnectionType.direction.isRoundabout()) {
                     if (!wayConnectionType.linkPrev && !trkseg.isEmpty()) {
-                        gpxData.addTrack(new ImmutableGpxTrack(trk, trkAttr));
+                        gpxData.addTrack(new GpxTrack(trk, trkAttr));
                         trkAttr.clear();
                         trk.clear();
@@ -180,5 +180,5 @@
                 }
             }
-            gpxData.addTrack(new ImmutableGpxTrack(trk, trkAttr));
+            gpxData.addTrack(new GpxTrack(trk, trkAttr));
 
             String lprefix = relations.iterator().next().getName();
Index: /trunk/src/org/openstreetmap/josm/data/Preferences.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/Preferences.java	(revision 15495)
+++ /trunk/src/org/openstreetmap/josm/data/Preferences.java	(revision 15496)
@@ -22,4 +22,5 @@
 import java.util.HashSet;
 import java.util.Iterator;
+import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
@@ -30,4 +31,5 @@
 import java.util.concurrent.TimeUnit;
 import java.util.function.Predicate;
+import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
@@ -82,4 +84,5 @@
 public class Preferences extends AbstractPreferences {
 
+    /** remove if key equals */
     private static final String[] OBSOLETE_PREF_KEYS = {
         "remotecontrol.https.enabled", /* remove entry after Dec. 2019 */
@@ -87,7 +90,78 @@
     };
 
+    /** remove if key starts with */
+    private static final String[] OBSOLETE_PREF_KEYS_START = {
+            //only remove layer specific prefs
+            "draw.rawgps.layer.wpt.",
+            "draw.rawgps.layer.audiowpt.",
+            "draw.rawgps.lines.force.",
+            "draw.rawgps.lines.alpha-blend.",
+            "draw.rawgps.lines.",
+            "markers.show ", //uses space as separator
+            "marker.makeautomarker.",
+            "clr.layer.",
+
+            //remove both layer specific and global prefs
+            "draw.rawgps.colors",
+            "draw.rawgps.direction",
+            "draw.rawgps.alternatedirection",
+            "draw.rawgps.linewidth",
+            "draw.rawgps.max-line-length.local",
+            "draw.rawgps.max-line-length",
+            "draw.rawgps.large",
+            "draw.rawgps.large.size",
+            "draw.rawgps.hdopcircle",
+            "draw.rawgps.min-arrow-distance",
+            "draw.rawgps.colorTracksTune",
+            "draw.rawgps.colors.dynamic",
+            "draw.rawgps.lines.local",
+            "draw.rawgps.heatmap"
+    };
+
+    /** keep subkey even if it starts with any of {@link #OBSOLETE_PREF_KEYS_START} */
+    private static final List<String> KEEP_PREF_KEYS = Arrays.asList(
+            "draw.rawgps.lines.alpha-blend",
+            "draw.rawgps.lines.arrows",
+            "draw.rawgps.lines.arrows.fast",
+            "draw.rawgps.lines.arrows.min-distance",
+            "draw.rawgps.lines.force",
+            "draw.rawgps.lines.max-length",
+            "draw.rawgps.lines.max-length.local",
+            "draw.rawgps.lines.width"
+    );
+
+    /** rename keys that equal */
+    private final static Map<String, String> UPDATE_PREF_KEYS = getUpdatePrefKeys();
+
+    private static Map<String, String> getUpdatePrefKeys() {
+        HashMap<String, String> m = new HashMap<>();
+        m.put("draw.rawgps.direction", "draw.rawgps.lines.arrows");
+        m.put("draw.rawgps.alternatedirection", "draw.rawgps.lines.arrows.fast");
+        m.put("draw.rawgps.min-arrow-distance", "draw.rawgps.lines.arrows.min-distance");
+        m.put("draw.rawgps.linewidth", "draw.rawgps.lines.width");
+        m.put("draw.rawgps.max-line-length.local", "draw.rawgps.lines.max-length.local");
+        m.put("draw.rawgps.max-line-length", "draw.rawgps.lines.max-length");
+        m.put("draw.rawgps.large", "draw.rawgps.points.large");
+        m.put("draw.rawgps.large.alpha", "draw.rawgps.points.large.alpha");
+        m.put("draw.rawgps.large.size", "draw.rawgps.points.large.size");
+        m.put("draw.rawgps.hdopcircle", "draw.rawgps.points.hdopcircle");
+        m.put("draw.rawgps.layer.wpt.pattern", "draw.rawgps.markers.pattern");
+        m.put("draw.rawgps.layer.audiowpt.pattern", "draw.rawgps.markers.audio.pattern");
+        m.put("draw.rawgps.colors", "draw.rawgps.colormode");
+        m.put("draw.rawgps.colorTracksTune", "draw.rawgps.colormode.velocity.tune");
+        m.put("draw.rawgps.colors.dynamic", "draw.rawgps.colormode.dynamic-range");
+        m.put("draw.rawgps.heatmap.line-extra", "draw.rawgps.colormode.heatmap.line-extra");
+        m.put("draw.rawgps.heatmap.colormap", "draw.rawgps.colormode.heatmap.colormap");
+        m.put("draw.rawgps.heatmap.use-points", "draw.rawgps.colormode.heatmap.use-points");
+        m.put("draw.rawgps.heatmap.gain", "draw.rawgps.colormode.heatmap.gain");
+        m.put("draw.rawgps.heatmap.lower-limit", "draw.rawgps.colormode.heatmap.lower-limit");
+        m.put("draw.rawgps.date-coloring-min-dt", "draw.rawgps.colormode.time.min-distance");
+        return Collections.unmodifiableMap(m);
+    }
+
     private static final long MAX_AGE_DEFAULT_PREFERENCES = TimeUnit.DAYS.toSeconds(50);
 
     private final IBaseDirectories dirs;
+    boolean modifiedDefault;
 
     /**
@@ -416,5 +490,5 @@
         settingsMap.clear();
         settingsMap.putAll(reader.getSettings());
-        removeObsolete(reader.getVersion());
+        removeAndUpdateObsolete(reader.getVersion());
     }
 
@@ -521,4 +595,17 @@
             return;
         }
+        File def = getDefaultsCacheFile();
+        if (def.exists()) {
+            try {
+                loadDefaults();
+            } catch (IOException | XMLStreamException | SAXException e) {
+                Logging.error(e);
+                Logging.warn(tr("Failed to load defaults cache file: {0}", def));
+                defaultsMap.clear();
+                if (!def.delete()) {
+                    Logging.warn(tr("Failed to delete faulty defaults cache file: {0}", def));
+                }
+            }
+        }
         try {
             load();
@@ -544,17 +631,4 @@
                 Logging.error(e1);
                 Logging.warn(tr("Failed to initialize preferences. Failed to reset preference file to default: {0}", getPreferenceFile()));
-            }
-        }
-        File def = getDefaultsCacheFile();
-        if (def.exists()) {
-            try {
-                loadDefaults();
-            } catch (IOException | XMLStreamException | SAXException e) {
-                Logging.error(e);
-                Logging.warn(tr("Failed to load defaults cache file: {0}", def));
-                defaultsMap.clear();
-                if (!def.delete()) {
-                    Logging.warn(tr("Failed to delete faulty defaults cache file: {0}", def));
-                }
             }
         }
@@ -756,16 +830,64 @@
 
     /**
-     * Removes obsolete preference settings. If you throw out a once-used preference
+     * Removes and updates obsolete preference settings. If you throw out a once-used preference
      * setting, add it to the list here with an expiry date (written as comment). If you
      * see something with an expiry date in the past, remove it from the list.
      * @param loadedVersion JOSM version when the preferences file was written
      */
-    private void removeObsolete(int loadedVersion) {
+    private void removeAndUpdateObsolete(int loadedVersion) {
+        Logging.trace("Update obsolete preference keys for version {0}", Integer.toString(loadedVersion));
+        for (Entry<String, String> e : UPDATE_PREF_KEYS.entrySet()) {
+            String oldkey = e.getKey();
+            String newkey = e.getValue();
+            if (settingsMap.containsKey(oldkey)) {
+                Setting<?> value = settingsMap.remove(oldkey);
+                settingsMap.putIfAbsent(newkey, value);
+                Logging.info(tr("Updated preference setting {0} to {1}", oldkey, newkey));
+            }
+        }
+
         Logging.trace("Remove obsolete preferences for version {0}", Integer.toString(loadedVersion));
         for (String key : OBSOLETE_PREF_KEYS) {
             if (settingsMap.containsKey(key)) {
                 settingsMap.remove(key);
-                Logging.info(tr("Preference setting {0} has been removed since it is no longer used.", key));
-            }
+                Logging.info(tr("Removed preference setting {0} since it is no longer used", key));
+            }
+            if (defaultsMap.containsKey(key)) {
+                defaultsMap.remove(key);
+                Logging.info(tr("Removed preference default {0} since it is no longer used", key));
+                modifiedDefault = true;
+            }
+        }
+        for (String key : OBSOLETE_PREF_KEYS_START) {
+            settingsMap.entrySet().stream()
+            .filter(e -> e.getKey().startsWith(key))
+            .collect(Collectors.toSet())
+            .forEach(e -> {
+                String k = e.getKey();
+                if (!KEEP_PREF_KEYS.contains(k)) {
+                    settingsMap.remove(k);
+                    Logging.info(tr("Removed preference setting {0} since it is no longer used", k));
+                }
+            });
+            defaultsMap.entrySet().stream()
+            .filter(e -> e.getKey().startsWith(key))
+            .collect(Collectors.toSet())
+            .forEach(e -> {
+                String k = e.getKey();
+                if (!KEEP_PREF_KEYS.contains(k)) {
+                    defaultsMap.remove(k);
+                    Logging.info(tr("Removed preference default {0} since it is no longer used", k));
+                    modifiedDefault = true;
+                }
+            });
+        }
+        if (modifiedDefault) {
+            try {
+                saveDefaults();
+                Logging.info(tr("Saved updated default preferences."));
+            } catch (IOException ex) {
+                Logging.log(Logging.LEVEL_WARN, tr("Failed to save default preferences."), ex);
+            }
+            modifiedDefault = false;
         }
     }
Index: unk/src/org/openstreetmap/josm/data/gpx/Extensions.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/gpx/Extensions.java	(revision 15495)
+++ 	(revision )
@@ -1,19 +1,0 @@
-// License: GPL. For details, see LICENSE file.
-package org.openstreetmap.josm.data.gpx;
-
-import java.util.LinkedHashMap;
-
-/**
- * Data class for extensions in a GPX-File.
- */
-public class Extensions extends LinkedHashMap<String, String> {
-
-    private static final long serialVersionUID = 1L;
-
-    /**
-     * Constructs a new {@code Extensions}.
-     */
-    public Extensions() {
-        super();
-    }
-}
Index: /trunk/src/org/openstreetmap/josm/data/gpx/GpxConstants.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/gpx/GpxConstants.java	(revision 15495)
+++ /trunk/src/org/openstreetmap/josm/data/gpx/GpxConstants.java	(revision 15496)
@@ -2,8 +2,11 @@
 package org.openstreetmap.josm.data.gpx;
 
+import java.awt.Color;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
 
 import org.openstreetmap.josm.data.Bounds;
@@ -96,15 +99,36 @@
      */
     String META_BOUNDS = META_PREFIX + "bounds";
-    /**
-     * A constant for the metadata hash map: the extension data. This is a {@link Extensions} object
-     * @see GpxData#addExtension(String, String)
-     * @see GpxData#get(String)
-     */
-    String META_EXTENSIONS = META_PREFIX + "extensions";
-
-    /**
-     * A namespace for josm GPX extensions
-     */
-    String JOSM_EXTENSIONS_NAMESPACE_URI = Config.getUrls().getXMLBase() + "/gpx-extensions-1.0";
+
+    /**
+     * Namespace for the XSD
+     */
+    String XML_URI_XSD = "http://www.w3.org/2001/XMLSchema-instance";
+
+    /**
+     * Namespace for JOSM GPX extensions
+     */
+    String XML_URI_EXTENSIONS_JOSM = Config.getUrls().getXMLBase() + "/gpx-extensions-1.1";
+    /**
+     * Location of the XSD schema for JOSM GPX extensions
+     */
+    String XML_XSD_EXTENSIONS_JOSM = Config.getUrls().getXMLBase() + "/gpx-extensions-1.1.xsd";
+
+    /**
+     * Namespace for GPX drawing extensions
+     */
+    String XML_URI_EXTENSIONS_DRAWING = Config.getUrls().getXMLBase() + "/gpx-drawing-extensions-1.0";
+    /**
+     * Location of the XSD schema for GPX drawing extensions
+     */
+    String XML_XSD_EXTENSIONS_DRAWING = Config.getUrls().getXMLBase() + "/gpx-drawing-extensions-1.0.xsd";
+
+    /**
+     * Namespace for Garmin GPX extensions
+     */
+    String XML_URI_EXTENSIONS_GARMIN = "http://www.garmin.com/xmlschemas/GpxExtensions/v3";
+    /**
+     * Location of the XSD schema for GPX drawing extensions
+     */
+    String XML_XSD_EXTENSIONS_GARMIN = "http://www.garmin.com/xmlschemas/GpxExtensionsv3.xsd";
 
     /** Elevation (in meters) of the point. */
@@ -155,5 +179,5 @@
     List<String> WPT_KEYS = Collections.unmodifiableList(Arrays.asList(PT_ELE, PT_TIME, PT_MAGVAR, PT_GEOIDHEIGHT,
             GPX_NAME, GPX_CMT, GPX_DESC, GPX_SRC, META_LINKS, PT_SYM, PT_TYPE,
-            PT_FIX, PT_SAT, PT_HDOP, PT_VDOP, PT_PDOP, PT_AGEOFDGPSDATA, PT_DGPSID, META_EXTENSIONS));
+            PT_FIX, PT_SAT, PT_HDOP, PT_VDOP, PT_PDOP, PT_AGEOFDGPSDATA, PT_DGPSID));
 
     /**
@@ -161,5 +185,62 @@
      */
     List<String> RTE_TRK_KEYS = Collections.unmodifiableList(Arrays.asList(
-            GPX_NAME, GPX_CMT, GPX_DESC, GPX_SRC, META_LINKS, "number", PT_TYPE, META_EXTENSIONS));
+            GPX_NAME, GPX_CMT, GPX_DESC, GPX_SRC, META_LINKS, "number", PT_TYPE));
+
+    /**
+     * Map with all supported Garmin colors
+     */
+    Map<String, Color> GARMIN_COLORS = getGarminColors();
+
+    /**
+     * Helper method for {@link #GARMIN_COLORS}
+     * @return Map with all supported Garmin colors
+     */
+    static Map<String, Color> getGarminColors() {
+        TreeMap<String, Color> m = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
+        m.put("Black", Color.BLACK);
+        m.put("DarkRed", new Color(139, 0, 0));
+        m.put("DarkGreen", new Color(0, 100, 0));
+        m.put("DarkYellow", new Color(255, 170, 0));
+        m.put("DarkBlue", new Color(0, 0, 139));
+        m.put("DarkMagenta", new Color(139, 0, 139));
+        m.put("DarkCyan", new Color(0, 139, 139));
+        m.put("LightGray", Color.LIGHT_GRAY);
+        m.put("DarkGray", Color.DARK_GRAY);
+        m.put("Red", Color.RED);
+        m.put("Green", Color.GREEN);
+        m.put("Yellow", Color.YELLOW);
+        m.put("Blue", Color.BLUE);
+        m.put("Magenta", Color.MAGENTA);
+        m.put("Cyan", Color.CYAN);
+        m.put("White", Color.WHITE);
+        m.put("Transparent", new Color(0, 0, 0, 255));
+        return Collections.unmodifiableMap(m);
+    }
+
+    /**
+     * Enum with color formats that can be written by JOSM
+     */
+    enum ColorFormat {
+        /** Drawing extension format */
+        GPXD,
+        /** Garmin track extension format */
+        GPXX
+    }
+
+    /**
+     * Map with all supported extension abbreviations for easier readability in OSM layers
+     */
+    Map<String, String> EXTENSION_ABBREVIATIONS = getExtensionAbbreviations();
+
+    /**
+     * Helper method for {@link #EXTENSION_ABBREVIATIONS}
+     * @return Map with all supported extension abbreviations
+     */
+    static Map<String, String> getExtensionAbbreviations() {
+        TreeMap<String, String> m = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
+        m.put("gpx:extension:gpxx:TrackExtensions:DisplayColor", "gpxx:DisplayColor");
+        m.put("gpx:extension:gpxd:color", "gpxd:color");
+        return m;
+    }
 
     /**
Index: /trunk/src/org/openstreetmap/josm/data/gpx/GpxData.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/gpx/GpxData.java	(revision 15495)
+++ /trunk/src/org/openstreetmap/josm/data/gpx/GpxData.java	(revision 15496)
@@ -16,4 +16,6 @@
 import java.util.Map;
 import java.util.NoSuchElementException;
+import java.util.Objects;
+import java.util.Optional;
 import java.util.Set;
 import java.util.stream.Collectors;
@@ -24,5 +26,5 @@
 import org.openstreetmap.josm.data.DataSource;
 import org.openstreetmap.josm.data.coor.EastNorth;
-import org.openstreetmap.josm.data.gpx.GpxTrack.GpxTrackChangeListener;
+import org.openstreetmap.josm.data.gpx.IGpxTrack.GpxTrackChangeListener;
 import org.openstreetmap.josm.data.projection.ProjectionRegistry;
 import org.openstreetmap.josm.gui.MainApplication;
@@ -41,4 +43,18 @@
 
     /**
+     * Constructs a new GpxData.
+     */
+    public GpxData() {}
+
+    /**
+     * Constructs a new GpxData that is currently being initialized, so no listeners will be fired until {@link #endUpdate()} is called.
+     * @param initializing true
+     * @since 15496
+     */
+    public GpxData(boolean initializing) {
+        this.initializing = initializing;
+    }
+
+    /**
      * The disk file this layer is stored in, if it is a local layer. May be <code>null</code>.
      */
@@ -66,5 +82,17 @@
      */
     private final ArrayList<WayPoint> privateWaypoints = new ArrayList<>();
-    private final GpxTrackChangeListener proxy = e -> fireInvalidate();
+    /**
+     * All namespaces read from the original file
+     */
+    private final List<XMLNamespace> namespaces = new ArrayList<>();
+    /**
+     * The layer specific prefs formerly saved in the preferences, e.g. drawing options.
+     * NOT the track specific settings (e.g. color, width)
+     */
+    private final Map<String, String> layerPrefs = new HashMap<>();
+
+    private final GpxTrackChangeListener proxy = e -> invalidate();
+    private boolean modified, updating, initializing;
+    private boolean suppressedInvalidate;
 
     /**
@@ -72,5 +100,5 @@
      * @see #getTracks()
      */
-    public final Collection<GpxTrack> tracks = new ListeningCollection<GpxTrack>(privateTracks, this::fireInvalidate) {
+    public final Collection<GpxTrack> tracks = new ListeningCollection<GpxTrack>(privateTracks, this::invalidate) {
 
         @Override
@@ -91,5 +119,5 @@
      * @see #getRoutes()
      */
-    public final Collection<GpxRoute> routes = new ListeningCollection<>(privateRoutes, this::fireInvalidate);
+    public final Collection<GpxRoute> routes = new ListeningCollection<>(privateRoutes, this::invalidate);
 
     /**
@@ -97,5 +125,5 @@
      * @see #getWaypoints()
      */
-    public final Collection<WayPoint> waypoints = new ListeningCollection<>(privateWaypoints, this::fireInvalidate);
+    public final Collection<WayPoint> waypoints = new ListeningCollection<>(privateWaypoints, this::invalidate);
 
     /**
@@ -108,6 +136,4 @@
 
     private final ListenerList<GpxDataChangeListener> listeners = ListenerList.create();
-
-    static class TimestampConfictException extends Exception {}
 
     private List<GpxTrackSegmentSpan> segSpans;
@@ -157,11 +183,11 @@
         other.privateWaypoints.forEach(this::addWaypoint);
         dataSources.addAll(other.dataSources);
-        fireInvalidate();
+        invalidate();
     }
 
     private void cutOverlapping(GpxTrack trk, boolean connect) {
-        List<GpxTrackSegment> segsOld = new ArrayList<>(trk.getSegments());
-        List<GpxTrackSegment> segsNew = new ArrayList<>();
-        for (GpxTrackSegment seg : segsOld) {
+        List<IGpxTrackSegment> segsOld = new ArrayList<>(trk.getSegments());
+        List<IGpxTrackSegment> segsNew = new ArrayList<>();
+        for (IGpxTrackSegment seg : segsOld) {
             GpxTrackSegmentSpan s = GpxTrackSegmentSpan.tryGetFromSegment(seg);
             if (s != null && anySegmentOverlapsWith(s)) {
@@ -204,8 +230,8 @@
                                     // because other high priority tracks between the same waypoints could follow
                                     if (!wpsNew.isEmpty()) {
-                                        segsNew.add(new ImmutableGpxTrackSegment(wpsNew));
+                                        segsNew.add(new GpxTrackSegment(wpsNew));
                                     }
                                     if (!segsNew.isEmpty()) {
-                                        privateTracks.add(new ImmutableGpxTrack(segsNew, trk.getAttributes()));
+                                        privateTracks.add(new GpxTrack(segsNew, trk.getAttributes()));
                                     }
                                     segsNew = new ArrayList<>();
@@ -222,8 +248,8 @@
                             //track has to be split, because we have an overlapping short track in the middle
                             if (!wpsNew.isEmpty()) {
-                                segsNew.add(new ImmutableGpxTrackSegment(wpsNew));
+                                segsNew.add(new GpxTrackSegment(wpsNew));
                             }
                             if (!segsNew.isEmpty()) {
-                                privateTracks.add(new ImmutableGpxTrack(segsNew, trk.getAttributes()));
+                                privateTracks.add(new GpxTrack(segsNew, trk.getAttributes()));
                             }
                             segsNew = new ArrayList<>();
@@ -239,5 +265,5 @@
                 }
                 if (!wpsNew.isEmpty()) {
-                    segsNew.add(new ImmutableGpxTrackSegment(wpsNew));
+                    segsNew.add(new GpxTrackSegment(wpsNew));
                 }
             } else {
@@ -248,5 +274,5 @@
             privateTracks.add(trk);
         } else if (!segsNew.isEmpty()) {
-            privateTracks.add(new ImmutableGpxTrack(segsNew, trk.getAttributes()));
+            privateTracks.add(new GpxTrack(segsNew, trk.getAttributes()));
         }
     }
@@ -254,5 +280,5 @@
     private void connectTracks(WayPoint prevWp, GpxTrackSegmentSpan span, Map<String, Object> attr) {
         if (prevWp != null && !span.lastEquals(prevWp)) {
-            privateTracks.add(new ImmutableGpxTrack(Arrays.asList(Arrays.asList(new WayPoint(prevWp), span.getFirstWp())), attr));
+            privateTracks.add(new GpxTrack(Arrays.asList(Arrays.asList(new WayPoint(prevWp), span.getFirstWp())), attr));
         }
     }
@@ -310,5 +336,5 @@
         }
 
-        static GpxTrackSegmentSpan tryGetFromSegment(GpxTrackSegment seg) {
+        static GpxTrackSegmentSpan tryGetFromSegment(IGpxTrackSegment seg) {
             WayPoint b = getNextWpWithTime(seg, true);
             if (b != null) {
@@ -321,5 +347,5 @@
         }
 
-        private static WayPoint getNextWpWithTime(GpxTrackSegment seg, boolean forward) {
+        private static WayPoint getNextWpWithTime(IGpxTrackSegment seg, boolean forward) {
             List<WayPoint> wps = new ArrayList<>(seg.getWayPoints());
             for (int i = forward ? 0 : wps.size() - 1; i >= 0 && i < wps.size(); i += forward ? 1 : -1) {
@@ -341,5 +367,5 @@
             segSpans = new ArrayList<>();
             for (GpxTrack trk : privateTracks) {
-                for (GpxTrackSegment seg : trk.getSegments()) {
+                for (IGpxTrackSegment seg : trk.getSegments()) {
                     GpxTrackSegmentSpan s = GpxTrackSegmentSpan.tryGetFromSegment(seg);
                     if (s != null) {
@@ -374,5 +400,5 @@
      * @return {@code Stream<GPXTrack>}
      */
-    private synchronized Stream<GpxTrackSegment> getTrackSegmentsStream() {
+    public synchronized Stream<IGpxTrackSegment> getTrackSegmentsStream() {
         return getTracks().stream().flatMap(trk -> trk.getSegments().stream());
     }
@@ -398,5 +424,5 @@
         privateTracks.add(track);
         track.addListener(proxy);
-        fireInvalidate();
+        invalidate();
     }
 
@@ -411,5 +437,5 @@
         }
         track.removeListener(proxy);
-        fireInvalidate();
+        invalidate();
     }
 
@@ -421,6 +447,6 @@
      */
     public synchronized void combineTracksToSegmentedTrack() {
-        List<GpxTrackSegment> segs = getTrackSegmentsStream()
-                .collect(Collectors.toCollection(ArrayList<GpxTrackSegment>::new));
+        List<IGpxTrackSegment> segs = getTrackSegmentsStream()
+                .collect(Collectors.toCollection(ArrayList<IGpxTrackSegment>::new));
         Map<String, Object> attrs = new HashMap<>(privateTracks.get(0).getAttributes());
 
@@ -432,5 +458,5 @@
 
         clearTracks();
-        addTrack(new ImmutableGpxTrack(segs, attrs));
+        addTrack(new GpxTrack(segs, attrs));
     }
 
@@ -468,5 +494,5 @@
                     HashMap<String, Object> attrs = new HashMap<>(trk.getAttributes());
                     ensureUniqueName(attrs, counts, srcLayerName);
-                    return new ImmutableGpxTrack(Arrays.asList(seg), attrs);
+                    return new GpxTrack(Arrays.asList(seg), attrs);
                 }))
             .collect(Collectors.toCollection(ArrayList<GpxTrack>::new));
@@ -539,5 +565,5 @@
         }
         privateRoutes.add(route);
-        fireInvalidate();
+        invalidate();
     }
 
@@ -551,5 +577,5 @@
             throw new IllegalArgumentException(MessageFormat.format("The route was not in this data: {0}", route));
         }
-        fireInvalidate();
+        invalidate();
     }
 
@@ -573,5 +599,5 @@
         }
         privateWaypoints.add(waypoint);
-        fireInvalidate();
+        invalidate();
     }
 
@@ -585,5 +611,5 @@
             throw new IllegalArgumentException(MessageFormat.format("The route was not in this data: {0}", waypoint));
         }
-        fireInvalidate();
+        invalidate();
     }
 
@@ -601,5 +627,5 @@
      * @see #getTracks()
      * @see GpxTrack#getSegments()
-     * @see GpxTrackSegment#getWayPoints()
+     * @see IGpxTrackSegment#getWayPoints()
      * @since 12156
      */
@@ -768,5 +794,5 @@
         double rx = 0.0, ry = 0.0, sx, sy, x, y;
         for (GpxTrack track : privateTracks) {
-            for (GpxTrackSegment seg : track.getSegments()) {
+            for (IGpxTrackSegment seg : track.getSegments()) {
                 WayPoint r = null;
                 for (WayPoint wpSeg : seg.getWayPoints()) {
@@ -883,5 +909,5 @@
         private Iterator<GpxTrack> itTracks;
         private int idxTracks;
-        private Iterator<GpxTrackSegment> itTrackSegments;
+        private Iterator<IGpxTrackSegment> itTrackSegments;
         private final Iterator<GpxRoute> itRoutes;
 
@@ -889,4 +915,5 @@
         private final boolean[] trackVisibility;
         private Map<String, Object> trackAttributes;
+        private GpxTrack curTrack;
 
         /**
@@ -922,15 +949,15 @@
             if (itTracks != null) {
                 if (itTrackSegments != null && itTrackSegments.hasNext()) {
-                    return new Line(itTrackSegments.next(), trackAttributes);
+                    return new Line(itTrackSegments.next(), trackAttributes, curTrack.getColor());
                 } else {
                     while (itTracks.hasNext()) {
-                        GpxTrack nxtTrack = itTracks.next();
-                        trackAttributes = nxtTrack.getAttributes();
+                        curTrack = itTracks.next();
+                        trackAttributes = curTrack.getAttributes();
                         idxTracks++;
                         if (trackVisibility != null && !trackVisibility[idxTracks])
                             continue;
-                        itTrackSegments = nxtTrack.getSegments().iterator();
+                        itTrackSegments = curTrack.getSegments().iterator();
                         if (itTrackSegments.hasNext()) {
-                            return new Line(itTrackSegments.next(), trackAttributes);
+                            return new Line(itTrackSegments.next(), trackAttributes, curTrack.getColor());
                         }
                     }
@@ -957,8 +984,29 @@
     }
 
+    /**
+     * The layer specific prefs formerly saved in the preferences, e.g. drawing options.
+     * NOT the track specific settings (e.g. color, width)
+     * @return Modifiable map
+     * @since 15496
+     */
+    public Map<String, String> getLayerPrefs() {
+        return layerPrefs;
+    }
+
+    /**
+     * All XML namespaces read from the original file
+     * @return Modifiable list
+     * @since 15496
+     */
+    public List<XMLNamespace> getNamespaces() {
+        return namespaces;
+    }
+
     @Override
     public synchronized int hashCode() {
         final int prime = 31;
-        int result = 1;
+        int result = prime + super.hashCode();
+        result = prime * result + ((namespaces == null) ? 0 : namespaces.hashCode());
+        result = prime * result + ((layerPrefs == null) ? 0 : layerPrefs.hashCode());
         result = prime * result + ((dataSources == null) ? 0 : dataSources.hashCode());
         result = prime * result + ((privateRoutes == null) ? 0 : privateRoutes.hashCode());
@@ -973,4 +1021,6 @@
             return true;
         if (obj == null)
+            return false;
+        if (!super.equals(obj))
             return false;
         if (getClass() != obj.getClass())
@@ -981,4 +1031,9 @@
                 return false;
         } else if (!dataSources.equals(other.dataSources))
+            return false;
+        if (layerPrefs == null) {
+            if (other.layerPrefs != null)
+                return false;
+        } else if (!layerPrefs.equals(other.layerPrefs))
             return false;
         if (privateRoutes == null) {
@@ -997,5 +1052,16 @@
         } else if (!privateWaypoints.equals(other.privateWaypoints))
             return false;
+        if (namespaces == null) {
+            if (other.namespaces != null)
+                return false;
+        } else if (!namespaces.equals(other.namespaces))
+            return false;
         return true;
+    }
+
+    @Override
+    public void put(String key, Object value) {
+        super.put(key, value);
+        invalidate();
     }
 
@@ -1026,8 +1092,43 @@
     }
 
-    private void fireInvalidate() {
-        if (listeners.hasListeners()) {
-            GpxDataChangeEvent e = new GpxDataChangeEvent(this);
-            listeners.fireEvent(l -> l.gpxDataChanged(e));
+    /**
+     * Fires event listeners and sets the modified flag to true.
+     */
+    public void invalidate() {
+        fireInvalidate(true);
+    }
+
+    private void fireInvalidate(boolean setModified) {
+        if (updating || initializing) {
+            suppressedInvalidate = true;
+        } else {
+            if (setModified) {
+                modified = true;
+            }
+            if (listeners.hasListeners()) {
+                GpxDataChangeEvent e = new GpxDataChangeEvent(this);
+                listeners.fireEvent(l -> l.gpxDataChanged(e));
+            }
+        }
+    }
+
+    /**
+     * Begins updating this GpxData and prevents listeners from being fired.
+     * @since 15496
+     */
+    public void beginUpdate() {
+        updating = true;
+    }
+
+    /**
+     * Finishes updating this GpxData and fires listeners if required.
+     * @since 15496
+     */
+    public void endUpdate() {
+        boolean setModified = updating;
+        updating = initializing = false;
+        if (suppressedInvalidate) {
+            fireInvalidate(setModified);
+            suppressedInvalidate = false;
         }
     }
@@ -1068,3 +1169,113 @@
         }
     }
+
+    /**
+     * @return whether anything has been modified (e.g. colors)
+     * @since 15496
+     */
+    public boolean isModified() {
+        return modified;
+    }
+
+    /**
+     * Sets the modified flag to the value.
+     * @param value modified flag
+     * @since 15496
+     */
+    public void setModified(boolean value) {
+        modified = value;
+    }
+
+    /**
+     * A class containing prefix, URI and location of a namespace
+     * @since 15496
+     */
+    public static class XMLNamespace {
+        private final String uri, prefix;
+        private String location;
+
+        /**
+         * Creates a schema with prefix and URI, tries to determine prefix from URI
+         * @param fallbackPrefix the namespace prefix, if not determined from URI
+         * @param uri the namespace URI
+         */
+        public XMLNamespace(String fallbackPrefix, String uri) {
+            this.prefix = Optional.ofNullable(GpxExtension.findPrefix(uri)).orElse(fallbackPrefix);
+            this.uri = uri;
+        }
+
+        /**
+         * Creates a schema with prefix, URI and location.
+         * Does NOT try to determine prefix from URI!
+         * @param prefix
+         * @param uri
+         * @param location
+         */
+        public XMLNamespace(String prefix, String uri, String location) {
+            this.prefix = prefix;
+            this.uri = uri;
+            this.location = location;
+        }
+
+        /**
+         * @return the URI of the namesapce
+         */
+        public String getURI() {
+            return uri;
+        }
+
+        /**
+         * @return the prefix of the namespace, determined from URI if possible
+         */
+        public String getPrefix() {
+            return prefix;
+        }
+
+        /**
+         * @return the location of the schema
+         */
+        public String getLocation() {
+            return location;
+        }
+
+        /**
+         * Sets the location of the schema
+         * @param location the location of the schema
+         */
+        public void setLocation(String location) {
+            this.location = location;
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(prefix, uri, location);
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj)
+                return true;
+            if (obj == null)
+                return false;
+            if (getClass() != obj.getClass())
+                return false;
+            XMLNamespace other = (XMLNamespace) obj;
+            if (prefix == null) {
+                if (other.prefix != null)
+                    return false;
+            } else if (!prefix.equals(other.prefix))
+                return false;
+            if (uri == null) {
+                if (other.uri != null)
+                    return false;
+            } else if (!uri.equals(other.uri))
+                return false;
+            if (location == null) {
+                if (other.location != null)
+                    return false;
+            } else if (!location.equals(other.location))
+                return false;
+            return true;
+        }
+    }
 }
Index: /trunk/src/org/openstreetmap/josm/data/gpx/GpxExtension.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/gpx/GpxExtension.java	(revision 15496)
+++ /trunk/src/org/openstreetmap/josm/data/gpx/GpxExtension.java	(revision 15496)
@@ -0,0 +1,279 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.data.gpx;
+
+import java.util.Objects;
+import java.util.Optional;
+
+import org.openstreetmap.josm.data.gpx.GpxData.XMLNamespace;
+import org.xml.sax.Attributes;
+
+/**
+ * A GpxExtension that has attributes and child extensions (implements {@link IWithAttributes}).
+ * @since 15496
+ */
+public class GpxExtension extends WithAttributes implements IWithAttributes, GpxConstants {
+    private final String qualifiedName, prefix, key;
+    private IWithAttributes parent;
+    private String value;
+    private boolean visible = true;
+
+    /**
+     * Constructs a new {@link GpxExtension}.
+     * @param prefix the prefix
+     * @param key the key
+     * @param value the value
+     */
+    public GpxExtension(String prefix, String key, String value) {
+        this.prefix = Optional.ofNullable(prefix).orElse("");
+        this.key = key;
+        this.value = value;
+        this.qualifiedName = (this.prefix.isEmpty() ? "" : this.prefix + ":") + key;
+    }
+
+    /**
+     * Creates a new {@link GpxExtension}
+     *
+     * @param namespaceURI the URI of the XML namespace, used to determine supported extensions
+     *                     (josm, gpxx, gpxd) regardless of the prefix that could legally vary from file to file.
+     * @param qName the qualified name of the XML element including prefix
+     * @param atts the attributes
+     */
+    public GpxExtension(String namespaceURI, String qName, Attributes atts) {
+        qualifiedName = qName;
+        int dot = qName.indexOf(':');
+        String p = findPrefix(namespaceURI);
+        if (p == null) {
+            if (dot != -1) {
+                prefix = qName.substring(0, dot);
+            } else {
+                prefix = "";
+            }
+        } else {
+            prefix = p;
+        }
+        key = qName.substring(dot + 1);
+        for (int i = 0; i < atts.getLength(); i++) {
+            attr.put(atts.getLocalName(i), atts.getValue(i));
+        }
+    }
+
+    /**
+     * Finds the default prefix used by JOSM for the given namespaceURI as the document is free specify another one.
+     * @param namespaceURI
+     * @return the prefix
+     */
+    public static String findPrefix(String namespaceURI) {
+        if (XML_URI_EXTENSIONS_DRAWING.equals(namespaceURI))
+            return "gpxd";
+
+        if (XML_URI_EXTENSIONS_GARMIN.equals(namespaceURI))
+            return "gpxx";
+
+        if (XML_URI_EXTENSIONS_JOSM.equals(namespaceURI))
+            return "josm";
+
+        return null;
+    }
+
+    /**
+     * Finds the namespace for the given default prefix, if supported with schema location
+     * @param prefix the prefix used by JOSM
+     * @return the {@link XMLNamespace} element, location and URI can be <code>null</code> if not found.
+     */
+    public static XMLNamespace findNamespace(String prefix) {
+        switch (prefix) {
+        case "gpxx":
+            return new XMLNamespace("gpxx", XML_URI_EXTENSIONS_GARMIN, XML_XSD_EXTENSIONS_GARMIN);
+        case "gpxd":
+            return new XMLNamespace("gpxd", XML_URI_EXTENSIONS_DRAWING, XML_XSD_EXTENSIONS_DRAWING);
+        case "josm":
+            return new XMLNamespace("josm", XML_URI_EXTENSIONS_JOSM, XML_XSD_EXTENSIONS_JOSM);
+        }
+        return null;
+    }
+
+    /**
+     * @return the qualified name of the XML element
+     */
+    public String getQualifiedName() {
+        return qualifiedName;
+    }
+
+    /**
+     * @return the prefix of the XML namespace
+     */
+    public String getPrefix() {
+        return prefix;
+    }
+
+    /**
+     * @return the key (local element name) of the extension
+     */
+    public String getKey() {
+        return key;
+    }
+
+    /**
+     * @return the flattened extension key of this extension, used for conversion to OSM layers
+     */
+    public String getFlatKey() {
+        String ret = "";
+        if (parent != null && parent instanceof GpxExtension) {
+            GpxExtension ext = (GpxExtension) parent;
+            ret = ext.getFlatKey() + ":";
+        }
+        return ret + getKey();
+    }
+
+    /**
+     * Searches recursively for the extension with the given key in all children
+     * @param sPrefix the prefix to look for
+     * @param sKey the key to look for
+     * @return the extension if found, otherwise <code>null</code>
+     */
+    public GpxExtension findExtension(String sPrefix, String sKey) {
+        if (prefix.equalsIgnoreCase(sPrefix) && key.equalsIgnoreCase(sKey)) {
+            return this;
+        } else {
+            for (GpxExtension child : getExtensions()) {
+                GpxExtension ext = child.findExtension(sPrefix, sKey);
+                if (ext != null) {
+                    return ext;
+                }
+            }
+            return null;
+        }
+    }
+
+    /**
+     * @return the value of the extension
+     */
+    public String getValue() {
+        return value;
+    }
+
+    /**
+     * @param value the value to set
+     */
+    public void setValue(String value) {
+        this.value = value;
+    }
+
+    /**
+     * Removes this extension from its parent and all then-empty parents
+     * @throws IllegalStateException if parent not set
+     */
+    public void remove() {
+        if (parent == null)
+            throw new IllegalStateException("Extension " + qualifiedName + " has no parent, can't remove it.");
+
+        parent.getExtensions().remove(this);
+        if (parent instanceof GpxExtension) {
+            GpxExtension gpx = ((GpxExtension) parent);
+            if ((gpx.getValue() == null || gpx.getValue().trim().isEmpty())
+                    && gpx.getAttributes().isEmpty()
+                    && gpx.getExtensions().isEmpty()) {
+                gpx.remove();
+            }
+        }
+    }
+
+    /**
+     * Hides this extension and all then-empty parents so it isn't written
+     * @see #isVisible()
+     */
+    public void hide() {
+        visible = false;
+        if (parent != null && parent instanceof GpxExtension) {
+            GpxExtension gpx = (GpxExtension) parent;
+            if ((gpx.getValue() == null || gpx.getValue().trim().isEmpty())
+                    && gpx.getAttributes().isEmpty()
+                    && !gpx.getExtensions().isVisible()) {
+                gpx.hide();
+            }
+        }
+    }
+
+    /**
+     * Shows this extension and all parents so it can be written
+     * @see #isVisible()
+     */
+    public void show() {
+        visible = true;
+        if (parent != null && parent instanceof GpxExtension) {
+            ((GpxExtension) parent).show();
+        }
+    }
+
+    /**
+     * @return if this extension should be written, used for hiding colors during export without removing them
+     */
+    public boolean isVisible() {
+        return visible;
+    }
+
+    /**
+     * @return the parent element of this extension, can be another extension or gpx elements (data, track, segment, ...)
+     */
+    public IWithAttributes getParent() {
+        return parent;
+    }
+
+    /**
+     * Sets the parent for this extension
+     * @param parent the parent
+     * @throws IllegalStateException if parent already set
+     */
+    public void setParent(IWithAttributes parent) {
+        if (this.parent != null)
+            throw new IllegalStateException("Parent of extension " + qualifiedName + " is already set");
+
+        this.parent = parent;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(prefix, key, value, attr, parent, visible, super.hashCode());
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (!super.equals(obj))
+            return false;
+        if (!(obj instanceof GpxExtension))
+            return false;
+        GpxExtension other = (GpxExtension) obj;
+        if (visible != other.visible)
+            return false;
+        if (prefix == null) {
+            if (other.prefix != null)
+                return false;
+        } else if (!prefix.equals(other.prefix))
+            return false;
+        if (key == null) {
+            if (other.key != null)
+                return false;
+        } else if (!key.equals(other.key))
+            return false;
+        if (value == null) {
+            if (other.value != null)
+                return false;
+        } else if (!value.equals(other.value))
+            return false;
+        if (attr == null) {
+            if (other.attr != null)
+                return false;
+        } else if (!attr.equals(other.attr))
+            return false;
+        if (parent == null) {
+            if (other.parent != null)
+                return false;
+        } else if (!parent.equals(other.parent))
+            return false;
+        return true;
+    }
+}
Index: /trunk/src/org/openstreetmap/josm/data/gpx/GpxExtensionCollection.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/gpx/GpxExtensionCollection.java	(revision 15496)
+++ /trunk/src/org/openstreetmap/josm/data/gpx/GpxExtensionCollection.java	(revision 15496)
@@ -0,0 +1,266 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.data.gpx;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Stack;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import org.apache.commons.jcs.access.exception.InvalidArgumentException;
+import org.openstreetmap.josm.io.GpxReader;
+import org.xml.sax.Attributes;
+
+/**
+ * Class extending <code>ArrayList&lt;GpxExtension&gt;</code>.
+ * Can be used to collect {@link GpxExtension}s while reading GPX files, see {@link GpxReader}
+ * @since 15496
+ */
+public class GpxExtensionCollection extends ArrayList<GpxExtension> {
+
+    private Stack<GpxExtension> childStack = new Stack<>();
+    private IWithAttributes parent;
+
+    /**
+     * Constructs a new {@link GpxExtensionCollection}
+     */
+    public GpxExtensionCollection() {}
+
+    /**
+     * Constructs a new {@link GpxExtensionCollection} with the given parent
+     * @param parent the parent extending {@link IWithAttributes}
+     */
+    public GpxExtensionCollection(IWithAttributes parent) {
+        this.parent = parent;
+    }
+
+    /**
+     * Adds a child extension to the last extension and pushes it to the stack.
+     * @param namespaceURI the URI of the XML namespace, used to determine supported
+     *                     extensions (josm, gpxx, gpxd) regardless of the prefix.
+     * @param qName the qualified name of the XML element including prefix
+     * @param atts the attributes
+     */
+    public void openChild(String namespaceURI, String qName, Attributes atts) {
+        GpxExtension child = new GpxExtension(namespaceURI, qName, atts);
+        if (!childStack.isEmpty()) {
+            childStack.lastElement().getExtensions().add(child);
+        } else {
+            this.add(child);
+        }
+        childStack.add(child);
+    }
+
+    /**
+     * Sets the value for the last child and pops it from the stack, so the next one will be added to its parent.
+     * The qualified name is verified.
+     * @param qName the qualified name
+     * @param value the value
+     */
+    public void closeChild(String qName, String value) {
+        if (childStack.isEmpty())
+            throw new InvalidArgumentException("Can't close child " + qName + ", no element in stack.");
+
+        GpxExtension child = childStack.pop();
+
+        String childQN = child.getQualifiedName();
+
+        if (!childQN.equals(qName))
+            throw new InvalidArgumentException("Can't close child " + qName + ", must close " + childQN + " first.");
+
+        child.setValue(value);
+    }
+
+    @Override
+    public boolean add(GpxExtension gpx) {
+        gpx.setParent(parent);
+        return super.add(gpx);
+    }
+
+    /**
+     * Creates and adds a new {@link GpxExtension} from the given parameters.
+     * @param prefix the prefix
+     * @param key the key/tag
+     * @return the added GpxExtension
+     */
+    public GpxExtension add(String prefix, String key) {
+        return add(prefix, key, null);
+    }
+
+    /**
+     * Creates and adds a new {@link GpxExtension} from the given parameters.
+     * @param prefix the prefix
+     * @param key the key/tag
+     * @param value the value, can be <code>null</code>
+     * @return the added GpxExtension
+     */
+    public GpxExtension add(String prefix, String key, String value) {
+        GpxExtension gpx = new GpxExtension(prefix, key, value);
+        add(gpx);
+        return gpx;
+    }
+
+    /**
+     * Creates and adds a new {@link GpxExtension}, if it hasn't been added yet. Shows it if it has.
+     * @param prefix the prefix
+     * @param key the key/tag
+     * @return the added or found GpxExtension
+     * @see GpxExtension#show()
+     */
+    public GpxExtension addIfNotPresent(String prefix, String key) {
+        GpxExtension gpx = get(prefix, key);
+        if (gpx != null) {
+            gpx.show();
+            return gpx;
+        }
+        return add(prefix, key);
+    }
+
+    /**
+     * Creates and adds a new {@link GpxExtension} or updates its value and shows it if already present.
+     * @param prefix the prefix
+     * @param key the key/tag
+     * @param value the value
+     * @return the added or found GpxExtension
+     * @see GpxExtension#show()
+     */
+    public GpxExtension addOrUpdate(String prefix, String key, String value) {
+        GpxExtension gpx = get(prefix, key);
+        if (gpx != null) {
+            gpx.show();
+            gpx.setValue(value);
+            return gpx;
+        } else {
+            return add(prefix, key, value);
+        }
+    }
+
+    @Override
+    public boolean addAll(Collection<? extends GpxExtension> extensions) {
+        extensions.forEach(e -> e.setParent(parent));
+        return super.addAll(extensions);
+    }
+
+    /**
+     * Adds an extension from a flat chain without prefix, e.g. when converting from OSM
+     * @param chain the full key chain, e.g. ["extension", "gpxx", "TrackExtensions", "DisplayColor"]
+     * @param value the value
+     */
+    public void addFlat(String[] chain, String value) {
+        if (chain.length >= 3 && "extension".equals(chain[0])) {
+            String prefix = "other".equals(chain[1]) ? "" : chain[1];
+            GpxExtensionCollection previous = this;
+            for (int i = 2; i < chain.length; i++) {
+                if (i != 2 || !"segment".equals(chain[2])) {
+                    previous = previous.add(prefix, chain[i], i == chain.length - 1 ? value : null).getExtensions();
+                }
+            }
+        }
+    }
+
+    /**
+     * Gets the extension with the given prefix and key
+     * @param prefix the prefix
+     * @param key the key/tag
+     * @return the {@link GpxExtension} if found or <code>null</code>
+     */
+    public GpxExtension get(String prefix, String key) {
+        return stream(prefix, key).findAny().orElse(null);
+    }
+
+    /**
+     * Gets all extensions with the given prefix and key
+     * @param prefix the prefix
+     * @param key the key/tag
+     * @return a {@link GpxExtensionCollection} with the extensions, empty collection if none found
+     */
+    public GpxExtensionCollection getAll(String prefix, String key) {
+        GpxExtensionCollection copy = new GpxExtensionCollection(this.parent);
+        copy.addAll(stream(prefix, key).collect(Collectors.toList()));
+        return copy;
+    }
+
+    /**
+     * Gets a stream with all extensions with the given prefix and key
+     * @param prefix the prefix
+     * @param key the key/tag
+     * @return the <code>Stream&lt;{@link GpxExtension}&gt;</code>
+     */
+    public Stream<GpxExtension> stream(String prefix, String key) {
+        return stream().filter(e -> Objects.equals(prefix, e.getPrefix()) && Objects.equals(key, e.getKey()));
+    }
+
+    /**
+     * Searches recursively for the extension with the given prefix and key in all children
+     * @param prefix the prefix to look for
+     * @param key the key to look for
+     * @return the extension if found, otherwise <code>null</code>
+     */
+    public GpxExtension find(String prefix, String key) {
+        for (GpxExtension child : this) {
+            GpxExtension ext = child.findExtension(prefix, key);
+            if (ext != null) {
+                return ext;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Searches and removes recursively all extensions with the given prefix and key in all children
+     * @param prefix the prefix to look for
+     * @param key the key to look for
+      */
+    public void findAndRemove(String prefix, String key) {
+        Optional.ofNullable(find(prefix, key)).ifPresent(GpxExtension::remove);
+    }
+
+    /**
+     * Removes all {@link GpxExtension}s with the given prefix and key in direct children
+     * @param prefix the prefix
+     * @param key the key/tag
+     */
+    public void remove(String prefix, String key) {
+        stream(prefix, key)
+        .collect(Collectors.toList()) //needs to be collected to avoid concurrent modification
+        .forEach(e -> super.remove(e));
+    }
+
+    /**
+     * Removes all extensions with the given prefix in direct children
+     * @param prefix the prefix
+     */
+    public void removeAllWithPrefix(String prefix) {
+        stream()
+        .filter(e -> Objects.equals(prefix, e.getPrefix()))
+        .collect(Collectors.toList()) //needs to be collected to avoid concurrent modification
+        .forEach(e -> super.remove(e));
+    }
+
+    /**
+     * Gets all prefixes of direct (writable) children
+     * @return stream with the prefixes
+     */
+    public Stream<String> getPrefixesStream() {
+        return stream()
+                .filter(GpxExtension::isVisible)
+                .map(GpxExtension::getPrefix)
+                .distinct();
+    }
+
+    /**
+     * @return <code>true</code> if this collection contains writable extensions
+     */
+    public boolean isVisible() {
+        return stream().anyMatch(GpxExtension::isVisible);
+    }
+
+    @Override
+    public void clear() {
+        childStack.clear();
+        super.clear();
+    }
+
+}
Index: /trunk/src/org/openstreetmap/josm/data/gpx/GpxImageCorrelation.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/gpx/GpxImageCorrelation.java	(revision 15495)
+++ /trunk/src/org/openstreetmap/josm/data/gpx/GpxImageCorrelation.java	(revision 15496)
@@ -40,5 +40,5 @@
         for (GpxTrack trk : selectedGpx.tracks) {
             List<List<WayPoint>> segs = new ArrayList<>();
-            for (GpxTrackSegment seg : trk.getSegments()) {
+            for (IGpxTrackSegment seg : trk.getSegments()) {
                 List<WayPoint> wps = new ArrayList<>(seg.getWayPoints());
                 if (!wps.isEmpty()) {
Index: /trunk/src/org/openstreetmap/josm/data/gpx/GpxTrack.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/gpx/GpxTrack.java	(revision 15495)
+++ /trunk/src/org/openstreetmap/josm/data/gpx/GpxTrack.java	(revision 15496)
@@ -2,66 +2,260 @@
 package org.openstreetmap.josm.data.gpx;
 
+import java.awt.Color;
+import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Optional;
 
 import org.openstreetmap.josm.data.Bounds;
+import org.openstreetmap.josm.tools.ListenerList;
+import org.openstreetmap.josm.tools.Logging;
 
 /**
- * Read-only gpx track. Implementations doesn't have to be immutable, but should always be thread safe.
- * @since 444
+ * GPX track.
+ * Note that the color attributes are not immutable and may be modified by the user.
+ * @since 15496
  */
-public interface GpxTrack extends IWithAttributes {
-
-    /**
-     * Returns the track segments.
-     * @return the track segments
-     */
-    Collection<GpxTrackSegment> getSegments();
-
-    /**
-     * Returns the track attributes.
-     * @return the track attributes
-     */
-    Map<String, Object> getAttributes();
-
-    /**
-     * Returns the track bounds.
-     * @return the track bounds
-     */
-    Bounds getBounds();
-
-    /**
-     * Returns the track length.
-     * @return the track length
-     */
-    double length();
-
-    /**
-     * Add a listener that listens to changes in the GPX track.
-     * @param l The listener
-     */
-    default void addListener(GpxTrackChangeListener l) {
-        // nop
-    }
-
-    /**
-     * Remove a listener that listens to changes in the GPX track.
-     * @param l The listener
-     */
-    default void removeListener(GpxTrackChangeListener l) {
-        // nop
+public class GpxTrack extends WithAttributes implements IGpxTrack {
+
+    private final List<IGpxTrackSegment> segments;
+    private final double length;
+    private final Bounds bounds;
+    private Color colorCache;
+    private final ListenerList<IGpxTrack.GpxTrackChangeListener> listeners = ListenerList.create();
+    private static final HashMap<Color, String> closestGarminColorCache = new HashMap<>();
+    private ColorFormat colorFormat;
+
+    /**
+     * Constructs a new {@code GpxTrack}.
+     * @param trackSegs track segments
+     * @param attributes track attributes
+     */
+    public GpxTrack(Collection<Collection<WayPoint>> trackSegs, Map<String, Object> attributes) {
+        List<IGpxTrackSegment> newSegments = new ArrayList<>();
+        for (Collection<WayPoint> trackSeg: trackSegs) {
+            if (trackSeg != null && !trackSeg.isEmpty()) {
+                newSegments.add(new GpxTrackSegment(trackSeg));
+            }
+        }
+        this.segments = Collections.unmodifiableList(newSegments);
+        this.length = calculateLength();
+        this.bounds = calculateBounds();
+        this.attr = new HashMap<>(attributes);
+    }
+
+    /**
+     * Constructs a new {@code GpxTrack} from {@code GpxTrackSegment} objects.
+     * @param trackSegs The segments to build the track from.  Input is not deep-copied,
+     *                 which means the caller may reuse the same segments to build
+     *                 multiple GpxTrack instances from.  This should not be
+     *                 a problem, since this object cannot modify {@code this.segments}.
+     * @param attributes Attributes for the GpxTrack, the input map is copied.
+     */
+    public GpxTrack(List<IGpxTrackSegment> trackSegs, Map<String, Object> attributes) {
+        this.attr = new HashMap<>(attributes);
+        this.segments = Collections.unmodifiableList(trackSegs);
+        this.length = calculateLength();
+        this.bounds = calculateBounds();
+    }
+
+    private double calculateLength() {
+        double result = 0.0; // in meters
+
+        for (IGpxTrackSegment trkseg : segments) {
+            result += trkseg.length();
+        }
+        return result;
+    }
+
+    private Bounds calculateBounds() {
+        Bounds result = null;
+        for (IGpxTrackSegment segment: segments) {
+            Bounds segBounds = segment.getBounds();
+            if (segBounds != null) {
+                if (result == null) {
+                    result = new Bounds(segBounds);
+                } else {
+                    result.extend(segBounds);
+                }
+            }
+        }
+        return result;
+    }
+
+    @Override
+    public void setColor(Color color) {
+        setColorExtension(color);
+        colorCache = color;
+    }
+
+    private void setColorExtension(Color color) {
+        getExtensions().findAndRemove("gpxx",  "DisplayColor");
+        if (color == null) {
+            getExtensions().findAndRemove("gpxd",  "color");
+        } else {
+            getExtensions().addOrUpdate("gpxd", "color", String.format("#%02X%02X%02X", color.getRed(), color.getGreen(), color.getBlue()));
+        }
+        fireInvalidate();
+    }
+
+    @Override
+    public Color getColor() {
+        if (colorCache == null) {
+            colorCache = getColorFromExtension();
+        }
+        return colorCache;
+    }
+
+    private Color getColorFromExtension() {
+        GpxExtension gpxd = getExtensions().find("gpxd", "color");
+        if (gpxd != null) {
+            colorFormat = ColorFormat.GPXD;
+            String cs = gpxd.getValue();
+            try {
+                return Color.decode(cs);
+            } catch (NumberFormatException ex) {
+                Logging.warn("Could not read gpxd color: " + cs);
+            }
+        } else {
+            GpxExtension gpxx = getExtensions().find("gpxx", "DisplayColor");
+            if (gpxx != null) {
+                colorFormat = ColorFormat.GPXX;
+                String cs = gpxx.getValue();
+                if (cs != null) {
+                    Color cc = GARMIN_COLORS.get(cs);
+                    if (cc != null) {
+                        return cc;
+                    }
+                }
+                Logging.warn("Could not read garmin color: " + cs);
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Converts the color to the given format, if present.
+     * @param cFormat can be a {@link GpxConstants.ColorFormat}
+     */
+    public void convertColor(ColorFormat cFormat) {
+        Color c = getColor();
+        if (c == null) return;
+
+        if (cFormat != this.colorFormat) {
+            if (cFormat == null) {
+                // just hide the extensions, don't actually remove them
+                Optional.ofNullable(getExtensions().find("gpxx", "DisplayColor")).ifPresent(GpxExtension::hide);
+                Optional.ofNullable(getExtensions().find("gpxd", "color")).ifPresent(GpxExtension::hide);
+            } else if (cFormat == ColorFormat.GPXX) {
+                getExtensions().findAndRemove("gpxd", "color");
+                String colorString = null;
+                if (closestGarminColorCache.containsKey(c)) {
+                    colorString = closestGarminColorCache.get(c);
+                } else {
+                    //find closest garmin color
+                    double closestDiff = -1;
+                    for (Entry<String, Color> e : GARMIN_COLORS.entrySet()) {
+                        double diff = colorDist(e.getValue(), c);
+                        if (closestDiff < 0 || diff < closestDiff) {
+                            colorString = e.getKey();
+                            closestDiff = diff;
+                            if (closestDiff == 0) break;
+                        }
+                    }
+                }
+                closestGarminColorCache.put(c, colorString);
+                getExtensions().addIfNotPresent("gpxx", "TrackExtensions").getExtensions().addOrUpdate("gpxx", "DisplayColor", colorString);
+            } else if (cFormat == ColorFormat.GPXD) {
+                setColor(c);
+            }
+            colorFormat = cFormat;
+        }
+    }
+
+    private double colorDist(Color c1, Color c2) {
+        // Simple Euclidean distance between two colors
+        return Math.sqrt(Math.pow(c1.getRed() - c2.getRed(), 2)
+                + Math.pow(c1.getGreen() - c2.getGreen(), 2)
+                + Math.pow(c1.getBlue() - c2.getBlue(), 2));
+    }
+
+    @Override
+    public void put(String key, Object value) {
+        super.put(key, value);
+        fireInvalidate();
+    }
+
+    private void fireInvalidate() {
+        listeners.fireEvent(l -> l.gpxDataChanged(new IGpxTrack.GpxTrackChangeEvent(this)));
+    }
+
+    @Override
+    public Bounds getBounds() {
+        return bounds == null ? null : new Bounds(bounds);
+    }
+
+    @Override
+    public double length() {
+        return length;
+    }
+
+    @Override
+    public Collection<IGpxTrackSegment> getSegments() {
+        return segments;
+    }
+
+    @Override
+    public int hashCode() {
+        return 31 * super.hashCode() + ((segments == null) ? 0 : segments.hashCode());
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (!super.equals(obj))
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        GpxTrack other = (GpxTrack) obj;
+        if (segments == null) {
+            if (other.segments != null)
+                return false;
+        } else if (!segments.equals(other.segments))
+            return false;
+        return true;
+    }
+
+    @Override
+    public void addListener(IGpxTrack.GpxTrackChangeListener l) {
+        listeners.addListener(l);
+    }
+
+    @Override
+    public void removeListener(IGpxTrack.GpxTrackChangeListener l) {
+        listeners.removeListener(l);
+    }
+
+    /**
+     * Resets the color cache
+     */
+    public void invalidate() {
+        colorCache = null;
     }
 
     /**
      * A listener that listens to GPX track changes.
-     * @author Michael Zangl
-     * @since 12156
-     */
+     * @deprecated use {@link IGpxTrack.GpxTrackChangeListener} instead
+     */
+    @Deprecated
     @FunctionalInterface
     interface GpxTrackChangeListener {
-        /**
-         * Called when the gpx data changed.
-         * @param e The event
-         */
         void gpxDataChanged(GpxTrackChangeEvent e);
     }
@@ -69,22 +263,12 @@
     /**
      * A track change event for the current track.
-     * @author Michael Zangl
-     * @since 12156
-     */
-    class GpxTrackChangeEvent {
-        private final GpxTrack source;
-
-        GpxTrackChangeEvent(GpxTrack source) {
-            super();
-            this.source = source;
-        }
-
-        /**
-         * Get the track that was changed.
-         * @return The track.
-         */
-        public GpxTrack getSource() {
-            return source;
-        }
-    }
+     * @deprecated use {@link IGpxTrack.GpxTrackChangeEvent} instead
+     */
+    @Deprecated
+    static class GpxTrackChangeEvent extends IGpxTrack.GpxTrackChangeEvent {
+        GpxTrackChangeEvent(IGpxTrack source) {
+            super(source);
+        }
+    }
+
 }
Index: /trunk/src/org/openstreetmap/josm/data/gpx/GpxTrackSegment.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/gpx/GpxTrackSegment.java	(revision 15495)
+++ /trunk/src/org/openstreetmap/josm/data/gpx/GpxTrackSegment.java	(revision 15496)
@@ -2,36 +2,103 @@
 package org.openstreetmap.josm.data.gpx;
 
+import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
 
 import org.openstreetmap.josm.data.Bounds;
 
 /**
- * Read-only gpx track segments. Implementations doesn't have to be immutable, but should always be thread safe.
- * @since 2907
+ * A gpx track segment consisting of multiple waypoints.
+ * @since 15496
  */
-public interface GpxTrackSegment {
+public class GpxTrackSegment extends WithAttributes implements IGpxTrackSegment {
+
+    private final List<WayPoint> wayPoints;
+    private final Bounds bounds;
+    private final double length;
 
     /**
-     * Returns the segment bounds.
-     * @return the segment bounds
+     * Constructs a new {@code GpxTrackSegment}.
+     * @param wayPoints list of waypoints
      */
-    Bounds getBounds();
+    public GpxTrackSegment(Collection<WayPoint> wayPoints) {
+        this.wayPoints = Collections.unmodifiableList(new ArrayList<>(wayPoints));
+        this.bounds = calculateBounds();
+        this.length = calculateLength();
+    }
 
-    /**
-     * Returns the segment waypoints.
-     * @return the segment waypoints
-     */
-    Collection<WayPoint> getWayPoints();
+    private Bounds calculateBounds() {
+        Bounds result = null;
+        for (WayPoint wpt: wayPoints) {
+            if (result == null) {
+                result = new Bounds(wpt.getCoor());
+            } else {
+                result.extend(wpt.getCoor());
+            }
+        }
+        return result;
+    }
 
-    /**
-     * Returns the segment length.
-     * @return the segment length
-     */
-    double length();
+    private double calculateLength() {
+        double result = 0.0; // in meters
+        WayPoint last = null;
+        for (WayPoint tpt : wayPoints) {
+            if (last != null) {
+                Double d = last.getCoor().greatCircleDistance(tpt.getCoor());
+                if (!d.isNaN() && !d.isInfinite()) {
+                    result += d;
+                }
+            }
+            last = tpt;
+        }
+        return result;
+    }
 
-    /**
-     * Returns the number of times this track has been changed
-     * @return Number of times this track has been changed. Always 0 for read-only segments
-     */
-    int getUpdateCount();
+    @Override
+    public Bounds getBounds() {
+        return bounds == null ? null : new Bounds(bounds);
+    }
+
+    @Override
+    public Collection<WayPoint> getWayPoints() {
+        return Collections.unmodifiableList(wayPoints);
+    }
+
+    @Override
+    public double length() {
+        return length;
+    }
+
+    @Override
+    public int getUpdateCount() {
+        return 0;
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = prime + super.hashCode();
+        result = prime * result + ((wayPoints == null) ? 0 : wayPoints.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (!super.equals(obj))
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        GpxTrackSegment other = (GpxTrackSegment) obj;
+        if (wayPoints == null) {
+            if (other.wayPoints != null)
+                return false;
+        } else if (!wayPoints.equals(other.wayPoints))
+            return false;
+        return true;
+    }
 }
Index: /trunk/src/org/openstreetmap/josm/data/gpx/IGpxTrack.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/gpx/IGpxTrack.java	(revision 15496)
+++ /trunk/src/org/openstreetmap/josm/data/gpx/IGpxTrack.java	(revision 15496)
@@ -0,0 +1,100 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.data.gpx;
+
+import java.awt.Color;
+import java.util.Collection;
+
+import org.openstreetmap.josm.data.Bounds;
+
+/**
+ * Gpx track. Implementations don't have to be immutable, but should always be thread safe.
+ * @since 15496
+ */
+public interface IGpxTrack extends IWithAttributes {
+
+    /**
+     * Returns the track segments.
+     * @return the track segments
+     */
+    Collection<IGpxTrackSegment> getSegments();
+
+    /**
+     * Returns the track bounds.
+     * @return the track bounds
+     */
+    Bounds getBounds();
+
+    /**
+     * Returns the track length.
+     * @return the track length
+     */
+    double length();
+
+    /**
+     * Gets the color of this track.
+     * @return The color, <code>null</code> if not set or not supported by the implementation.
+     * @since 15496
+     */
+    default Color getColor() {
+        return null;
+    }
+
+    /**
+     * Sets the color of this track. Not necessarily supported by all implementations.
+     * @param color
+     * @since 15496
+     */
+    default void setColor(Color color) {}
+
+    /**
+     * Add a listener that listens to changes in the GPX track.
+     * @param l The listener
+     */
+    default void addListener(GpxTrackChangeListener l) {
+        // nop
+    }
+
+    /**
+     * Remove a listener that listens to changes in the GPX track.
+     * @param l The listener
+     */
+    default void removeListener(GpxTrackChangeListener l) {
+        // nop
+    }
+
+    /**
+     * A listener that listens to GPX track changes.
+     * @author Michael Zangl
+     * @since 15496
+     */
+    @FunctionalInterface
+    interface GpxTrackChangeListener {
+        /**
+         * Called when the gpx data changed.
+         * @param e The event
+         */
+        void gpxDataChanged(GpxTrackChangeEvent e);
+    }
+
+    /**
+     * A track change event for the current track.
+     * @author Michael Zangl
+     * @since 15496
+     */
+    class GpxTrackChangeEvent {
+        private final IGpxTrack source;
+
+        GpxTrackChangeEvent(IGpxTrack source) {
+            super();
+            this.source = source;
+        }
+
+        /**
+         * Get the track that was changed.
+         * @return The track.
+         */
+        public IGpxTrack getSource() {
+            return source;
+        }
+    }
+}
Index: /trunk/src/org/openstreetmap/josm/data/gpx/IGpxTrackSegment.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/gpx/IGpxTrackSegment.java	(revision 15496)
+++ /trunk/src/org/openstreetmap/josm/data/gpx/IGpxTrackSegment.java	(revision 15496)
@@ -0,0 +1,37 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.data.gpx;
+
+import java.util.Collection;
+
+import org.openstreetmap.josm.data.Bounds;
+
+/**
+ * Read-only gpx track segments. Implementations don't have to be immutable, but should always be thread safe.
+ * @since 15496
+ */
+public interface IGpxTrackSegment extends IWithAttributes {
+
+    /**
+     * Returns the segment bounds.
+     * @return the segment bounds
+     */
+    Bounds getBounds();
+
+    /**
+     * Returns the segment waypoints.
+     * @return the segment waypoints
+     */
+    Collection<WayPoint> getWayPoints();
+
+    /**
+     * Returns the segment length.
+     * @return the segment length
+     */
+    double length();
+
+    /**
+     * Returns the number of times this track has been changed
+     * @return Number of times this track has been changed. Always 0 for read-only segments
+     */
+    int getUpdateCount();
+}
Index: /trunk/src/org/openstreetmap/josm/data/gpx/IWithAttributes.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/gpx/IWithAttributes.java	(revision 15495)
+++ /trunk/src/org/openstreetmap/josm/data/gpx/IWithAttributes.java	(revision 15496)
@@ -3,4 +3,5 @@
 
 import java.util.Collection;
+import java.util.Map;
 
 /**
@@ -51,10 +52,14 @@
 
     /**
-     * Add a key / value pair that is not part of the GPX schema as an extension.
-     *
-     * @param key the key
-     * @param value the value
+     * Returns the attributes
+     * @return the attributes
      */
-    void addExtension(String key, String value);
+    Map<String, Object> getAttributes();
+
+    /**
+     * Returns the extensions
+     * @return the extensions
+     */
+    GpxExtensionCollection getExtensions();
 
 }
Index: /trunk/src/org/openstreetmap/josm/data/gpx/ImmutableGpxTrack.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/gpx/ImmutableGpxTrack.java	(revision 15495)
+++ /trunk/src/org/openstreetmap/josm/data/gpx/ImmutableGpxTrack.java	(revision 15496)
@@ -2,22 +2,15 @@
 package org.openstreetmap.josm.data.gpx;
 
-import java.util.ArrayList;
 import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
-import org.openstreetmap.josm.data.Bounds;
-
 /**
- * Immutable GPX track.
+ * GPX track, NOT immutable
  * @since 2907
+ * @deprecated Use {@link GpxTrack} instead!
  */
-public class ImmutableGpxTrack extends WithAttributes implements GpxTrack {
-
-    private final List<GpxTrackSegment> segments;
-    private final double length;
-    private final Bounds bounds;
+@Deprecated
+public class ImmutableGpxTrack extends GpxTrack {
 
     /**
@@ -27,14 +20,5 @@
      */
     public ImmutableGpxTrack(Collection<Collection<WayPoint>> trackSegs, Map<String, Object> attributes) {
-        List<GpxTrackSegment> newSegments = new ArrayList<>();
-        for (Collection<WayPoint> trackSeg: trackSegs) {
-            if (trackSeg != null && !trackSeg.isEmpty()) {
-                newSegments.add(new ImmutableGpxTrackSegment(trackSeg));
-            }
-        }
-        this.attr = Collections.unmodifiableMap(new HashMap<>(attributes));
-        this.segments = Collections.unmodifiableList(newSegments);
-        this.length = calculateLength();
-        this.bounds = calculateBounds();
+        super(trackSegs, attributes);
     }
 
@@ -48,75 +32,6 @@
      * @since 13210
      */
-    public ImmutableGpxTrack(List<GpxTrackSegment> segments, Map<String, Object> attributes) {
-        this.attr = Collections.unmodifiableMap(new HashMap<>(attributes));
-        this.segments = Collections.unmodifiableList(segments);
-        this.length = calculateLength();
-        this.bounds = calculateBounds();
-    }
-
-    private double calculateLength() {
-        double result = 0.0; // in meters
-
-        for (GpxTrackSegment trkseg : segments) {
-            result += trkseg.length();
-        }
-        return result;
-    }
-
-    private Bounds calculateBounds() {
-        Bounds result = null;
-        for (GpxTrackSegment segment: segments) {
-            Bounds segBounds = segment.getBounds();
-            if (segBounds != null) {
-                if (result == null) {
-                    result = new Bounds(segBounds);
-                } else {
-                    result.extend(segBounds);
-                }
-            }
-        }
-        return result;
-    }
-
-    @Override
-    public Map<String, Object> getAttributes() {
-        return attr;
-    }
-
-    @Override
-    public Bounds getBounds() {
-        return bounds == null ? null : new Bounds(bounds);
-    }
-
-    @Override
-    public double length() {
-        return length;
-    }
-
-    @Override
-    public Collection<GpxTrackSegment> getSegments() {
-        return segments;
-    }
-
-    @Override
-    public int hashCode() {
-        return 31 * super.hashCode() + ((segments == null) ? 0 : segments.hashCode());
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (this == obj)
-            return true;
-        if (!super.equals(obj))
-            return false;
-        if (getClass() != obj.getClass())
-            return false;
-        ImmutableGpxTrack other = (ImmutableGpxTrack) obj;
-        if (segments == null) {
-            if (other.segments != null)
-                return false;
-        } else if (!segments.equals(other.segments))
-            return false;
-        return true;
+    public ImmutableGpxTrack(List<IGpxTrackSegment> segments, Map<String, Object> attributes) {
+        super(segments, attributes);
     }
 }
Index: /trunk/src/org/openstreetmap/josm/data/gpx/ImmutableGpxTrackSegment.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/gpx/ImmutableGpxTrackSegment.java	(revision 15495)
+++ /trunk/src/org/openstreetmap/josm/data/gpx/ImmutableGpxTrackSegment.java	(revision 15496)
@@ -2,19 +2,12 @@
 package org.openstreetmap.josm.data.gpx;
 
-import java.util.ArrayList;
 import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-
-import org.openstreetmap.josm.data.Bounds;
 
 /**
  * A gpx track segment consisting of multiple waypoints, that cannot be changed.
+ * @deprecated Use {@link GpxTrackSegment} instead!
  */
-public class ImmutableGpxTrackSegment implements GpxTrackSegment {
-
-    private final List<WayPoint> wayPoints;
-    private final Bounds bounds;
-    private final double length;
+@Deprecated
+public class ImmutableGpxTrackSegment extends GpxTrackSegment {
 
     /**
@@ -23,76 +16,5 @@
      */
     public ImmutableGpxTrackSegment(Collection<WayPoint> wayPoints) {
-        this.wayPoints = Collections.unmodifiableList(new ArrayList<>(wayPoints));
-        this.bounds = calculateBounds();
-        this.length = calculateLength();
-    }
-
-    private Bounds calculateBounds() {
-        Bounds result = null;
-        for (WayPoint wpt: wayPoints) {
-            if (result == null) {
-                result = new Bounds(wpt.getCoor());
-            } else {
-                result.extend(wpt.getCoor());
-            }
-        }
-        return result;
-    }
-
-    private double calculateLength() {
-        double result = 0.0; // in meters
-        WayPoint last = null;
-        for (WayPoint tpt : wayPoints) {
-            if (last != null) {
-                Double d = last.getCoor().greatCircleDistance(tpt.getCoor());
-                if (!d.isNaN() && !d.isInfinite()) {
-                    result += d;
-                }
-            }
-            last = tpt;
-        }
-        return result;
-    }
-
-    @Override
-    public Bounds getBounds() {
-        return bounds == null ? null : new Bounds(bounds);
-    }
-
-    @Override
-    public Collection<WayPoint> getWayPoints() {
-        return Collections.unmodifiableList(wayPoints);
-    }
-
-    @Override
-    public double length() {
-        return length;
-    }
-
-    @Override
-    public int getUpdateCount() {
-        return 0;
-    }
-
-    @Override
-    public int hashCode() {
-        return 31 + ((wayPoints == null) ? 0 : wayPoints.hashCode());
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (this == obj)
-            return true;
-        if (obj == null)
-            return false;
-        if (getClass() != obj.getClass())
-            return false;
-        ImmutableGpxTrackSegment other = (ImmutableGpxTrackSegment) obj;
-        if (wayPoints == null) {
-            if (other.wayPoints != null)
-                return false;
-        } else if (!wayPoints.equals(other.wayPoints))
-            return false;
-        return true;
+        super(wayPoints);
     }
 }
Index: /trunk/src/org/openstreetmap/josm/data/gpx/Line.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/gpx/Line.java	(revision 15495)
+++ /trunk/src/org/openstreetmap/josm/data/gpx/Line.java	(revision 15496)
@@ -2,4 +2,5 @@
 package org.openstreetmap.josm.data.gpx;
 
+import java.awt.Color;
 import java.util.Collection;
 import java.util.Iterator;
@@ -14,4 +15,5 @@
     private final Collection<WayPoint> waypoints;
     private final boolean unordered;
+    private final Color color;
 
     /**
@@ -19,6 +21,9 @@
      * @param waypoints collection of waypoints
      * @param attributes track/route attributes
+     * @param color color of the track
+     * @since 15496
      */
-    public Line(Collection<WayPoint> waypoints, Map<String, Object> attributes) {
+    public Line(Collection<WayPoint> waypoints, Map<String, Object> attributes, Color color) {
+        this.color = color;
         this.waypoints = Objects.requireNonNull(waypoints);
         unordered = attributes.isEmpty() && waypoints.stream().allMatch(x -> x.get(GpxConstants.PT_TIME) == null);
@@ -29,7 +34,9 @@
      * @param trackSegment track segment
      * @param trackAttributes track attributes
+     * @param color color of the track
+     * @since 15496
      */
-    public Line(GpxTrackSegment trackSegment, Map<String, Object> trackAttributes) {
-        this(trackSegment.getWayPoints(), trackAttributes);
+    public Line(IGpxTrackSegment trackSegment, Map<String, Object> trackAttributes, Color color) {
+        this(trackSegment.getWayPoints(), trackAttributes, color);
     }
 
@@ -39,5 +46,5 @@
      */
     public Line(GpxRoute route) {
-        this(route.routePoints, route.attr);
+        this(route.routePoints, route.attr, null);
     }
 
@@ -48,4 +55,13 @@
     public boolean isUnordered() {
         return unordered;
+    }
+
+    /**
+     * Returns the track/route color
+     * @return the color
+     * @since 15496
+     */
+    public Color getColor() {
+        return color;
     }
 
Index: /trunk/src/org/openstreetmap/josm/data/gpx/WithAttributes.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/gpx/WithAttributes.java	(revision 15495)
+++ /trunk/src/org/openstreetmap/josm/data/gpx/WithAttributes.java	(revision 15496)
@@ -5,4 +5,5 @@
 import java.util.HashMap;
 import java.util.Map;
+import java.util.Objects;
 
 /**
@@ -20,4 +21,9 @@
      */
     public Map<String, Object> attr = new HashMap<>(0);
+
+    /**
+     * The "exts" collection contains all extensions.
+     */
+    private final GpxExtensionCollection exts = new GpxExtensionCollection(this);
 
     /**
@@ -65,5 +71,4 @@
     /**
      * Put a key / value pair as a new attribute.
-     *
      * Overrides key / value pair with the same key (if present).
      *
@@ -76,22 +81,17 @@
     }
 
-    /**
-     * Add a key / value pair that is not part of the GPX schema as an extension.
-     *
-     * @param key the key
-     * @param value the value
-     */
     @Override
-    public void addExtension(String key, String value) {
-        if (!attr.containsKey(META_EXTENSIONS)) {
-            attr.put(META_EXTENSIONS, new Extensions());
-        }
-        Extensions ext = (Extensions) attr.get(META_EXTENSIONS);
-        ext.put(key, value);
+    public Map<String, Object> getAttributes() {
+        return attr;
+    }
+
+    @Override
+    public GpxExtensionCollection getExtensions() {
+        return exts;
     }
 
     @Override
     public int hashCode() {
-        return 31 + ((attr == null) ? 0 : attr.hashCode());
+        return Objects.hash(attr, exts);
     }
 
@@ -110,4 +110,9 @@
         } else if (!attr.equals(other.attr))
             return false;
+        if (exts == null) {
+            if (other.exts != null)
+                return false;
+        } else if (!exts.equals(other.exts))
+            return false;
         return true;
     }
Index: /trunk/src/org/openstreetmap/josm/data/osm/DataSet.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/osm/DataSet.java	(revision 15495)
+++ /trunk/src/org/openstreetmap/josm/data/osm/DataSet.java	(revision 15496)
@@ -33,4 +33,5 @@
 import org.openstreetmap.josm.data.coor.EastNorth;
 import org.openstreetmap.josm.data.coor.LatLon;
+import org.openstreetmap.josm.data.gpx.GpxData.XMLNamespace;
 import org.openstreetmap.josm.data.osm.DataSelectionListener.SelectionAddEvent;
 import org.openstreetmap.josm.data.osm.DataSelectionListener.SelectionChangeEvent;
@@ -171,4 +172,10 @@
 
     /**
+     * Used to temporarily store namespaces from the GPX file in case the user converts back and forth.
+     * Will not be saved to .osm files, but that's not necessary because GPX files won't automatically be overridden after that.
+     */
+    private List<XMLNamespace> GPXNamespaces;
+
+    /**
      * Constructs a new {@code DataSet}.
      */
@@ -1195,4 +1202,20 @@
 
     /**
+     * Gets the GPX (XML) namespaces if this DataSet was created from a GPX file
+     * @return the GPXNamespaces or <code>null</code>
+     */
+    public List<XMLNamespace> getGPXNamespaces() {
+        return GPXNamespaces;
+    }
+
+    /**
+     * Sets the GPX (XML) namespaces
+     * @param GPXNamespaces the GPXNamespaces to set
+     */
+    public void setGPXNamespaces(List<XMLNamespace> GPXNamespaces) {
+        this.GPXNamespaces = GPXNamespaces;
+    }
+
+    /**
      * @return true if this Dataset contains no primitives
      * @since 14835
Index: /trunk/src/org/openstreetmap/josm/data/preferences/NamedColorProperty.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/preferences/NamedColorProperty.java	(revision 15495)
+++ /trunk/src/org/openstreetmap/josm/data/preferences/NamedColorProperty.java	(revision 15496)
@@ -23,5 +23,4 @@
     public static final String COLOR_CATEGORY_GENERAL = "general";
     public static final String COLOR_CATEGORY_MAPPAINT = "mappaint";
-    public static final String COLOR_CATEGORY_LAYER = "layer";
 
     private final String category;
@@ -32,6 +31,5 @@
      * Construct a new {@code NamedColorProperty}.
      * @param category a category, can be any identifier, but the following values are recognized by
-     * the GUI preferences: {@link #COLOR_CATEGORY_GENERAL}, {@link #COLOR_CATEGORY_MAPPAINT} and
-     * {@link #COLOR_CATEGORY_LAYER}
+     * the GUI preferences: {@link #COLOR_CATEGORY_GENERAL} and {@link #COLOR_CATEGORY_MAPPAINT}
      * @param source a filename or similar associated with the color, can be null if not applicable
      * @param name a short description of the color
Index: /trunk/src/org/openstreetmap/josm/gui/dialogs/LayerListDialog.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/dialogs/LayerListDialog.java	(revision 15495)
+++ /trunk/src/org/openstreetmap/josm/gui/dialogs/LayerListDialog.java	(revision 15496)
@@ -4,5 +4,4 @@
 import static org.openstreetmap.josm.tools.I18n.tr;
 
-import java.awt.Color;
 import java.awt.Component;
 import java.awt.Dimension;
@@ -18,5 +17,5 @@
 import java.util.Arrays;
 import java.util.List;
-import java.util.Objects;
+import java.util.Optional;
 import java.util.concurrent.CopyOnWriteArrayList;
 
@@ -43,5 +42,4 @@
 import org.openstreetmap.josm.data.coor.EastNorth;
 import org.openstreetmap.josm.data.imagery.OffsetBookmark;
-import org.openstreetmap.josm.data.preferences.AbstractProperty;
 import org.openstreetmap.josm.data.preferences.AbstractProperty.ValueChangeListener;
 import org.openstreetmap.josm.data.preferences.BooleanProperty;
@@ -612,16 +610,7 @@
             }
             if (Config.getPref().getBoolean("dialog.layer.colorname", true)) {
-                AbstractProperty<Color> prop = layer.getColorProperty();
-                Color c = prop == null ? null : prop.get();
-                if (c == null || model.getLayers().stream()
-                        .map(Layer::getColorProperty)
-                        .filter(Objects::nonNull)
-                        .map(AbstractProperty::get)
-                        .noneMatch(oc -> oc != null && !oc.equals(c))) {
-                    /* not more than one color, don't use coloring */
-                    label.setForeground(UIManager.getColor(isSelected ? "Table.selectionForeground" : "Table.foreground"));
-                } else {
-                    label.setForeground(c);
-                }
+                label.setForeground(Optional
+                        .ofNullable(layer.getColor())
+                        .orElse(UIManager.getColor(isSelected ? "Table.selectionForeground" : "Table.foreground")));
             }
             label.setIcon(layer.getIcon());
Index: /trunk/src/org/openstreetmap/josm/gui/dialogs/layer/LayerVisibilityAction.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/dialogs/layer/LayerVisibilityAction.java	(revision 15495)
+++ /trunk/src/org/openstreetmap/josm/gui/dialogs/layer/LayerVisibilityAction.java	(revision 15496)
@@ -594,5 +594,5 @@
                     for (Layer l : layers) {
                         if (l instanceof GpxLayer) {
-                            l.getColorProperty().put(color);
+                            l.setColor(color);
                         }
                     }
@@ -603,5 +603,5 @@
             panels.put(color, colorPanel);
 
-            List<Color> colors = layerSupplier.get().stream().map(l -> l.getColorProperty().get()).distinct().collect(Collectors.toList());
+            List<Color> colors = layerSupplier.get().stream().map(l -> l.getColor()).distinct().collect(Collectors.toList());
             if (colors.size() == 1) {
                 highlightColor(colors.get(0));
@@ -612,5 +612,5 @@
         public void updateLayers(List<Layer> layers, boolean allVisible, boolean allHidden) {
             List<Color> colors = layers.stream().filter(l -> l instanceof GpxLayer)
-                    .map(l -> ((GpxLayer) l).getColorProperty().get())
+                    .map(l -> ((GpxLayer) l).getColor())
                     .distinct()
                     .collect(Collectors.toList());
Index: /trunk/src/org/openstreetmap/josm/gui/io/importexport/FileExporter.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/io/importexport/FileExporter.java	(revision 15495)
+++ /trunk/src/org/openstreetmap/josm/gui/io/importexport/FileExporter.java	(revision 15496)
@@ -56,4 +56,16 @@
 
     /**
+     * Execute the data export without prompting the user. (To be overridden by subclasses.)
+     *
+     * @param file target file
+     * @param layer the layer to export
+     * @throws IOException in case of an IO error
+     * @since 15496
+     */
+    public void exportDataQuiet(File file, Layer layer) throws IOException {
+        exportData(file, layer); //backwards compatibility
+    }
+
+    /**
      * Returns the enabled state of this {@code FileExporter}. When enabled, it is listed and usable in "File-&gt;Save" dialogs.
      * @return true if this {@code FileExporter} is enabled
Index: /trunk/src/org/openstreetmap/josm/gui/io/importexport/GpxExporter.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/io/importexport/GpxExporter.java	(revision 15495)
+++ /trunk/src/org/openstreetmap/josm/gui/io/importexport/GpxExporter.java	(revision 15496)
@@ -26,4 +26,5 @@
 import org.openstreetmap.josm.data.gpx.GpxConstants;
 import org.openstreetmap.josm.data.gpx.GpxData;
+import org.openstreetmap.josm.gui.ConditionalOptionPaneUtil;
 import org.openstreetmap.josm.gui.ExtendedDialog;
 import org.openstreetmap.josm.gui.MainApplication;
@@ -78,4 +79,13 @@
     @Override
     public void exportData(File file, Layer layer) throws IOException {
+        exportData(file, layer, false);
+    }
+
+    @Override
+    public void exportDataQuiet(File file, Layer layer) throws IOException {
+        exportData(file, layer, true);
+    }
+
+    private void exportData(File file, Layer layer, boolean quiet) throws IOException {
         CheckParameterUtil.ensureParameterNotNull(layer, "layer");
         if (!(layer instanceof OsmDataLayer) && !(layer instanceof GpxLayer))
@@ -90,8 +100,19 @@
         }
 
+        GpxData gpxData;
+        if (quiet) {
+            gpxData = getGpxData(layer, file);
+            try (OutputStream fo = Compression.getCompressedFileOutputStream(file)) {
+                GpxWriter w = new GpxWriter(fo);
+                w.write(gpxData);
+                w.close();
+                fo.flush();
+            }
+            return;
+        }
+
         // open the dialog asking for options
         JPanel p = new JPanel(new GridBagLayout());
 
-        GpxData gpxData;
         // At this moment, we only need to know the attributes of the GpxData,
         // conversion of OsmDataLayer (if needed) will be done after the dialog is closed.
@@ -147,5 +168,19 @@
         JosmTextField keywords = new JosmTextField();
         keywords.setText(gpxData.getString(META_KEYWORDS));
-        p.add(keywords, GBC.eop().fill(GBC.HORIZONTAL));
+        p.add(keywords, GBC.eol().fill(GBC.HORIZONTAL));
+
+        boolean sel = Config.getPref().getBoolean("gpx.export.colors", true);
+        JCheckBox colors = new JCheckBox(tr("Save track colors in GPX file"), sel);
+        p.add(colors, GBC.eol().fill(GBC.HORIZONTAL));
+        JCheckBox garmin = new JCheckBox(tr("Use Garmin compatible GPX extensions"),
+                Config.getPref().getBoolean("gpx.export.colors.garmin", false));
+        garmin.setEnabled(sel);
+        p.add(garmin, GBC.eol().fill(GBC.HORIZONTAL).insets(20, 0, 0, 0));
+
+        boolean hasPrefs = !gpxData.getLayerPrefs().isEmpty();
+        JCheckBox layerPrefs = new JCheckBox(tr("Save layer specific preferences"),
+                hasPrefs && Config.getPref().getBoolean("gpx.export.prefs", true));
+        layerPrefs.setEnabled(hasPrefs);
+        p.add(layerPrefs, GBC.eop().fill(GBC.HORIZONTAL));
 
         ExtendedDialog ed = new ExtendedDialog(MainApplication.getMainFrame(),
@@ -155,4 +190,22 @@
             .setContent(p);
 
+        colors.addActionListener(l -> {
+            garmin.setEnabled(colors.isSelected());
+        });
+
+        garmin.addActionListener(l -> {
+            if (garmin.isSelected() &&
+                    !ConditionalOptionPaneUtil.showConfirmationDialog(
+                            "gpx_color_garmin",
+                            ed,
+                            new JLabel(tr("<html>Garmin track extensions only support 16 colors.<br>If you continue, the closest supported track color will be used.</html>")),
+                            tr("Information"),
+                            JOptionPane.OK_CANCEL_OPTION,
+                            JOptionPane.INFORMATION_MESSAGE,
+                            JOptionPane.OK_OPTION)) {
+                garmin.setSelected(false);
+            }
+        });
+
         if (ed.showDialog().getValue() != 1) {
             setCanceled(true);
@@ -168,12 +221,15 @@
             Config.getPref().put("lastCopyright", copyright.getText());
         }
-
-        if (layer instanceof OsmDataLayer) {
-            gpxData = ((OsmDataLayer) layer).toGpxData();
-        } else if (layer instanceof GpxLayer) {
-            gpxData = ((GpxLayer) layer).data;
-        } else {
-            gpxData = OsmDataLayer.toGpxData(MainApplication.getLayerManager().getEditDataSet(), file);
-        }
+        Config.getPref().putBoolean("gpx.export.colors", colors.isSelected());
+        Config.getPref().putBoolean("gpx.export.colors.garmin", garmin.isSelected());
+        if (hasPrefs) {
+            Config.getPref().putBoolean("gpx.export.prefs", layerPrefs.isSelected());
+        }
+        ColorFormat cFormat = null;
+        if (colors.isSelected()) {
+            cFormat = garmin.isSelected() ? ColorFormat.GPXX : ColorFormat.GPXD;
+        }
+
+        gpxData = getGpxData(layer, file);
 
         // add author and copyright details to the gpx data
@@ -204,7 +260,19 @@
         }
 
-        try (OutputStream fo = Compression.getCompressedFileOutputStream(file); GpxWriter writer = new GpxWriter(fo)) {
-            writer.write(gpxData);
-        }
+        try (OutputStream fo = Compression.getCompressedFileOutputStream(file)) {
+            GpxWriter w = new GpxWriter(fo);
+            w.write(gpxData, cFormat, layerPrefs.isSelected());
+            w.close();
+            fo.flush();
+        }
+    }
+
+    private static GpxData getGpxData(Layer layer, File file) {
+        if (layer instanceof OsmDataLayer) {
+            return ((OsmDataLayer) layer).toGpxData();
+        } else if (layer instanceof GpxLayer) {
+            return ((GpxLayer) layer).data;
+        }
+        return OsmDataLayer.toGpxData(MainApplication.getLayerManager().getEditDataSet(), file);
     }
 
Index: /trunk/src/org/openstreetmap/josm/gui/io/importexport/GpxImporter.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/io/importexport/GpxImporter.java	(revision 15495)
+++ /trunk/src/org/openstreetmap/josm/gui/io/importexport/GpxImporter.java	(revision 15496)
@@ -150,4 +150,6 @@
             if (markerLayer.data.isEmpty()) {
                 markerLayer = null;
+            } else {
+                gpxLayer.setLinkedMarkerLayer(markerLayer);
             }
         }
Index: /trunk/src/org/openstreetmap/josm/gui/layer/CustomizeColor.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/layer/CustomizeColor.java	(revision 15495)
+++ /trunk/src/org/openstreetmap/josm/gui/layer/CustomizeColor.java	(revision 15496)
@@ -19,10 +19,8 @@
 import javax.swing.JOptionPane;
 
-import org.openstreetmap.josm.data.preferences.AbstractProperty;
 import org.openstreetmap.josm.gui.MainApplication;
 import org.openstreetmap.josm.gui.dialogs.LayerListDialog;
 import org.openstreetmap.josm.gui.layer.Layer.LayerAction;
 import org.openstreetmap.josm.gui.layer.Layer.MultiLayerAction;
-import org.openstreetmap.josm.tools.CheckParameterUtil;
 import org.openstreetmap.josm.tools.ImageProvider;
 
@@ -34,5 +32,5 @@
  */
 public class CustomizeColor extends AbstractAction implements LayerAction, MultiLayerAction {
-    private final transient List<AbstractProperty<Color>> colors;
+    private final transient List<Layer> colorLayers;
 
     /**
@@ -43,6 +41,5 @@
         super(tr("Customize Color"));
         new ImageProvider("colorchooser").getResource().attachImageIcon(this, true);
-        colors = l.stream().map(Layer::getColorProperty).collect(Collectors.toList());
-        CheckParameterUtil.ensureThat(colors.stream().allMatch(Objects::nonNull), "All layers must have colors.");
+        colorLayers = l.stream().filter(Objects::nonNull).filter(Layer::hasColor).collect(Collectors.toList());
         putValue("help", ht("/Action/LayerCustomizeColor"));
     }
@@ -58,5 +55,5 @@
     @Override
     public boolean supportLayers(List<Layer> layers) {
-        return layers.stream().allMatch(l -> l.getColorProperty() != null);
+        return layers.stream().allMatch(Layer::hasColor);
     }
 
@@ -73,5 +70,5 @@
     @Override
     public void actionPerformed(ActionEvent e) {
-        Color cl = colors.stream().map(AbstractProperty::get).filter(Objects::nonNull).findAny().orElse(Color.GRAY);
+        Color cl = colorLayers.stream().filter(Objects::nonNull).map(Layer::getColor).filter(Objects::nonNull).findAny().orElse(Color.GRAY);
         JColorChooser c = new JColorChooser(cl);
         Object[] options = new Object[]{tr("OK"), tr("Cancel"), tr("Default")};
@@ -88,10 +85,10 @@
         switch (answer) {
         case 0:
-            colors.stream().forEach(prop -> prop.put(c.getColor()));
+            colorLayers.stream().forEach(l -> l.setColor(c.getColor()));
             break;
         case 1:
             return;
         case 2:
-            colors.stream().forEach(prop -> prop.put(null));
+            colorLayers.stream().forEach(l -> l.setColor(null));
             break;
         }
Index: /trunk/src/org/openstreetmap/josm/gui/layer/GpxLayer.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/layer/GpxLayer.java	(revision 15495)
+++ /trunk/src/org/openstreetmap/josm/gui/layer/GpxLayer.java	(revision 15496)
@@ -5,4 +5,5 @@
 import static org.openstreetmap.josm.tools.I18n.trn;
 
+import java.awt.Color;
 import java.awt.Dimension;
 import java.awt.Graphics2D;
@@ -14,4 +15,5 @@
 import java.util.Date;
 import java.util.List;
+import java.util.stream.Collectors;
 
 import javax.swing.AbstractAction;
@@ -32,5 +34,4 @@
 import org.openstreetmap.josm.data.gpx.GpxTrack;
 import org.openstreetmap.josm.data.osm.visitor.BoundingXYVisitor;
-import org.openstreetmap.josm.data.preferences.NamedColorProperty;
 import org.openstreetmap.josm.data.projection.Projection;
 import org.openstreetmap.josm.gui.MapView;
@@ -47,6 +48,9 @@
 import org.openstreetmap.josm.gui.layer.gpx.ImportImagesAction;
 import org.openstreetmap.josm.gui.layer.gpx.MarkersFromNamedPointsAction;
+import org.openstreetmap.josm.gui.layer.markerlayer.MarkerLayer;
+import org.openstreetmap.josm.gui.preferences.display.GPXSettingsPanel;
 import org.openstreetmap.josm.gui.widgets.HtmlPanel;
 import org.openstreetmap.josm.tools.ImageProvider;
+import org.openstreetmap.josm.tools.Logging;
 import org.openstreetmap.josm.tools.Utils;
 import org.openstreetmap.josm.tools.date.DateUtils;
@@ -55,10 +59,11 @@
  * A layer that displays data from a Gpx file / the OSM gpx downloads.
  */
-public class GpxLayer extends Layer implements ExpertModeChangeListener {
+public class GpxLayer extends AbstractModifiableLayer implements ExpertModeChangeListener {
 
     /** GPX data */
     public GpxData data;
-    private final boolean isLocalFile;
+    private boolean isLocalFile;
     private boolean isExpertMode;
+
     /**
      * used by {@link ChooseTrackVisibilityAction} to determine which tracks to show/hide
@@ -73,4 +78,8 @@
      */
     private final GpxDataChangeListener dataChangeListener = e -> this.invalidate();
+    /**
+     * The MarkerLayer imported from the same file.
+     */
+    private MarkerLayer linkedMarkerLayer;
 
     /**
@@ -109,6 +118,22 @@
 
     @Override
-    protected NamedColorProperty getBaseColorProperty() {
-        return GpxDrawHelper.DEFAULT_COLOR;
+    public Color getColor() {
+        Color[] c = data.getTracks().stream().map(t -> t.getColor()).distinct().toArray(Color[]::new);
+        return c.length == 1 ? c[0] : null; //only return if exactly one distinct color present
+    }
+
+    @Override
+    public void setColor(Color color) {
+        data.beginUpdate();
+        for (GpxTrack trk : data.getTracks()) {
+            trk.setColor(color);
+        }
+        GPXSettingsPanel.putLayerPrefLocal(this, "colormode", "0");
+        data.endUpdate();
+    }
+
+    @Override
+    public boolean hasColor() {
+        return true;
     }
 
@@ -277,6 +302,13 @@
             .append(trn("{0} route, ", "{0} routes, ", data.getRoutes().size(), data.getRoutes().size()))
             .append(trn("{0} waypoint", "{0} waypoints", data.getWaypoints().size(), data.getWaypoints().size())).append("<br>")
-            .append(tr("Length: {0}", SystemOfMeasurement.getSystemOfMeasurement().getDistText(data.length())))
-            .append("<br></html>");
+            .append(tr("Length: {0}", SystemOfMeasurement.getSystemOfMeasurement().getDistText(data.length())));
+
+        if (Logging.isDebugEnabled() && !data.getLayerPrefs().isEmpty()) {
+            info.append("<br><br>")
+                .append(String.join("<br>", data.getLayerPrefs().entrySet().stream().map(e -> e.getKey() + "=" + e.getValue()).collect(Collectors.toList())));
+        }
+
+        info.append("<br></html>");
+
         return info.toString();
     }
@@ -340,4 +372,20 @@
     public void setAssociatedFile(File file) {
         data.storageFile = file;
+    }
+
+    /**
+     * @return the linked MarkerLayer (imported from the same file)
+     * @since 15496
+     */
+    public MarkerLayer getLinkedMarkerLayer() {
+        return linkedMarkerLayer;
+    }
+
+    /**
+     * @param linkedMarkerLayer the linked MarkerLayer
+     * @since 15496
+     */
+    public void setLinkedMarkerLayer(MarkerLayer linkedMarkerLayer) {
+        this.linkedMarkerLayer = linkedMarkerLayer;
     }
 
@@ -481,4 +529,21 @@
 
     @Override
+    public boolean isModified() {
+        return data.isModified();
+    }
+
+    @Override
+    public boolean requiresSaveToFile() {
+        return isModified() && isLocalFile();
+    }
+
+    @Override
+    public void onPostSaveToFile() {
+        isLocalFile = true;
+        data.invalidate();
+        data.setModified(false);
+    }
+
+    @Override
     public String getChangesetSourceTag() {
         // no i18n for international values
Index: /trunk/src/org/openstreetmap/josm/gui/layer/Layer.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/layer/Layer.java	(revision 15495)
+++ /trunk/src/org/openstreetmap/josm/gui/layer/Layer.java	(revision 15496)
@@ -26,7 +26,4 @@
 import org.openstreetmap.josm.data.ProjectionBounds;
 import org.openstreetmap.josm.data.osm.visitor.BoundingXYVisitor;
-import org.openstreetmap.josm.data.preferences.AbstractProperty;
-import org.openstreetmap.josm.data.preferences.AbstractProperty.ValueChangeListener;
-import org.openstreetmap.josm.data.preferences.NamedColorProperty;
 import org.openstreetmap.josm.data.projection.Projection;
 import org.openstreetmap.josm.data.projection.ProjectionChangeListener;
@@ -165,5 +162,4 @@
     private File associatedFile;
 
-    private final ValueChangeListener<Object> invalidateListener = change -> invalidate();
     private boolean isDestroyed;
 
@@ -199,38 +195,26 @@
 
     /**
-     * Gets the color property to use for this layer.
-     * @return The color property.
-     * @since 10824
-     */
-    public AbstractProperty<Color> getColorProperty() {
-        NamedColorProperty base = getBaseColorProperty();
-        if (base != null) {
-            return base.getChildColor(NamedColorProperty.COLOR_CATEGORY_LAYER, getName(), base.getName());
-        } else {
-            return null;
-        }
-    }
-
-    /**
-     * Gets the color property that stores the default color for this layer.
-     * @return The property or <code>null</code> if this layer is not colored.
-     * @since 10824
-     */
-    protected NamedColorProperty getBaseColorProperty() {
+     * @return whether the layer has / can handle colors.
+     * @since 15496
+     */
+    public boolean hasColor() {
+        return false;
+    }
+
+    /**
+     * Return the current color of the layer
+     * @return null when not present or not supported
+     * @since 15496
+     */
+    public Color getColor() {
         return null;
     }
 
-    private void addColorPropertyListener() {
-        AbstractProperty<Color> colorProperty = getColorProperty();
-        if (colorProperty != null) {
-            colorProperty.addListener(invalidateListener);
-        }
-    }
-
-    private void removeColorPropertyListener() {
-        AbstractProperty<Color> colorProperty = getColorProperty();
-        if (colorProperty != null) {
-            colorProperty.removeListener(invalidateListener);
-        }
+    /**
+     * Sets the color for this layer. Nothing happens if not supported by the layer
+     * @param color the color to be set, <code>null</code> for default
+     * @since 15496
+     */
+    public void setColor(Color color) {
     }
 
@@ -303,5 +287,4 @@
         isDestroyed = true;
         // Override in subclasses if needed
-        removeColorPropertyListener();
     }
 
@@ -340,7 +323,4 @@
      */
     public void setName(String name) {
-        if (this.name != null) {
-            removeColorPropertyListener();
-        }
         String oldValue = this.name;
         this.name = Optional.ofNullable(name).orElse("");
@@ -348,7 +328,4 @@
             propertyChangeSupport.firePropertyChange(NAME_PROP, oldValue, this.name);
         }
-
-        // re-add listener
-        addColorPropertyListener();
         invalidate();
     }
@@ -540,5 +517,5 @@
         @Override
         public void actionPerformed(ActionEvent e) {
-            SaveAction.getInstance().doSave(layer);
+            SaveAction.getInstance().doSave(layer, true);
         }
     }
Index: /trunk/src/org/openstreetmap/josm/gui/layer/OsmDataLayer.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/layer/OsmDataLayer.java	(revision 15495)
+++ /trunk/src/org/openstreetmap/josm/gui/layer/OsmDataLayer.java	(revision 15496)
@@ -32,4 +32,5 @@
 import java.util.List;
 import java.util.Map;
+import java.util.Map.Entry;
 import java.util.Optional;
 import java.util.Set;
@@ -61,6 +62,9 @@
 import org.openstreetmap.josm.data.gpx.GpxConstants;
 import org.openstreetmap.josm.data.gpx.GpxData;
+import org.openstreetmap.josm.data.gpx.GpxExtensionCollection;
 import org.openstreetmap.josm.data.gpx.GpxLink;
-import org.openstreetmap.josm.data.gpx.ImmutableGpxTrack;
+import org.openstreetmap.josm.data.gpx.GpxTrack;
+import org.openstreetmap.josm.data.gpx.GpxTrackSegment;
+import org.openstreetmap.josm.data.gpx.IGpxTrackSegment;
 import org.openstreetmap.josm.data.gpx.WayPoint;
 import org.openstreetmap.josm.data.osm.DataIntegrityProblemException;
@@ -758,4 +762,7 @@
     public static GpxData toGpxData(DataSet data, File file) {
         GpxData gpxData = new GpxData();
+        if (data.getGPXNamespaces() != null) {
+            gpxData.getNamespaces().addAll(data.getGPXNamespaces());
+        }
         gpxData.storageFile = file;
         Set<Node> doneNodes = new HashSet<>();
@@ -778,21 +785,40 @@
                 return;
             }
-            Collection<Collection<WayPoint>> trk = new ArrayList<>();
+            List<IGpxTrackSegment> trk = new ArrayList<>();
             Map<String, Object> trkAttr = new HashMap<>();
 
-            String name = gpxVal(w, "name");
-            if (name != null) {
-                trkAttr.put("name", name);
-            }
-
-            List<WayPoint> trkseg = null;
+            GpxExtensionCollection trkExts = new GpxExtensionCollection();
+            GpxExtensionCollection segExts = new GpxExtensionCollection();
+            for (Entry<String, String> e : w.getKeys().entrySet()) {
+                String k = e.getKey().startsWith(GpxConstants.GPX_PREFIX) ? e.getKey().substring(GpxConstants.GPX_PREFIX.length()) : e.getKey();
+                String v = e.getValue();
+                if (GpxConstants.RTE_TRK_KEYS.contains(k)) {
+                    trkAttr.put(k, v);
+                } else {
+                    k = GpxConstants.EXTENSION_ABBREVIATIONS.entrySet()
+                            .stream()
+                            .filter(s -> s.getValue().equals(e.getKey()))
+                            .map(s -> s.getKey().substring(GpxConstants.GPX_PREFIX.length()))
+                            .findAny()
+                            .orElse(k);
+                    if (k.startsWith("extension")) {
+                        String[] chain = k.split(":");
+                        if (chain.length >= 3 && "segment".equals(chain[2])) {
+                            segExts.addFlat(chain, v);
+                        } else {
+                            trkExts.addFlat(chain, v);
+                        }
+                    }
+
+                }
+            }
+            List<WayPoint> trkseg = new ArrayList<>();
             for (Node n : w.getNodes()) {
                 if (!n.isUsable()) {
-                    trkseg = null;
+                    if (!trkseg.isEmpty()) {
+                        trk.add(new GpxTrackSegment(trkseg));
+                        trkseg.clear();
+                    }
                     continue;
-                }
-                if (trkseg == null) {
-                    trkseg = new ArrayList<>();
-                    trk.add(trkseg);
                 }
                 if (!n.isTagged() || containsOnlyGpxTags(n)) {
@@ -801,6 +827,9 @@
                 trkseg.add(nodeToWayPoint(n));
             }
-
-            gpxData.addTrack(new ImmutableGpxTrack(trk, trkAttr));
+            trk.add(new GpxTrackSegment(trkseg));
+            trk.forEach(gpxseg -> gpxseg.getExtensions().addAll(segExts));
+            GpxTrack gpxtrk = new GpxTrack(trk, trkAttr);
+            gpxtrk.getExtensions().addAll(trkExts);
+            gpxData.addTrack(gpxtrk);
         });
     }
Index: /trunk/src/org/openstreetmap/josm/gui/layer/geoimage/CorrelateGpxWithImages.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/layer/geoimage/CorrelateGpxWithImages.java	(revision 15495)
+++ /trunk/src/org/openstreetmap/josm/gui/layer/geoimage/CorrelateGpxWithImages.java	(revision 15496)
@@ -71,5 +71,5 @@
 import org.openstreetmap.josm.data.gpx.GpxTimezone;
 import org.openstreetmap.josm.data.gpx.GpxTrack;
-import org.openstreetmap.josm.data.gpx.GpxTrackSegment;
+import org.openstreetmap.josm.data.gpx.IGpxTrackSegment;
 import org.openstreetmap.josm.data.gpx.WayPoint;
 import org.openstreetmap.josm.data.osm.visitor.BoundingXYVisitor;
@@ -1269,5 +1269,5 @@
         // Finds first GPX point
         outer: for (GpxTrack trk : gpx.tracks) {
-            for (GpxTrackSegment segment : trk.getSegments()) {
+            for (IGpxTrackSegment segment : trk.getSegments()) {
                 for (WayPoint curWp : segment.getWayPoints()) {
                     if (curWp.hasDate()) {
Index: /trunk/src/org/openstreetmap/josm/gui/layer/gpx/ChooseTrackVisibilityAction.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/layer/gpx/ChooseTrackVisibilityAction.java	(revision 15495)
+++ /trunk/src/org/openstreetmap/josm/gui/layer/gpx/ChooseTrackVisibilityAction.java	(revision 15496)
@@ -5,4 +5,5 @@
 import static org.openstreetmap.josm.tools.I18n.tr;
 
+import java.awt.Color;
 import java.awt.Component;
 import java.awt.Dimension;
@@ -13,12 +14,17 @@
 import java.awt.event.MouseListener;
 import java.io.Serializable;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Comparator;
+import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Optional;
 
 import javax.swing.AbstractAction;
+import javax.swing.JColorChooser;
 import javax.swing.JComponent;
 import javax.swing.JLabel;
+import javax.swing.JOptionPane;
 import javax.swing.JPanel;
 import javax.swing.JScrollPane;
@@ -26,8 +32,10 @@
 import javax.swing.JToggleButton;
 import javax.swing.ListSelectionModel;
+import javax.swing.event.TableModelEvent;
 import javax.swing.table.DefaultTableModel;
 import javax.swing.table.TableCellRenderer;
 import javax.swing.table.TableRowSorter;
 
+import org.apache.commons.jcs.access.exception.InvalidArgumentException;
 import org.openstreetmap.josm.data.SystemOfMeasurement;
 import org.openstreetmap.josm.data.gpx.GpxConstants;
@@ -36,4 +44,5 @@
 import org.openstreetmap.josm.gui.MainApplication;
 import org.openstreetmap.josm.gui.layer.GpxLayer;
+import org.openstreetmap.josm.gui.preferences.display.GPXSettingsPanel;
 import org.openstreetmap.josm.gui.util.WindowGeometry;
 import org.openstreetmap.josm.tools.GBC;
@@ -56,5 +65,5 @@
      */
     public ChooseTrackVisibilityAction(final GpxLayer layer) {
-        super(tr("Choose visible tracks"));
+        super(tr("Choose track visibility and colors"));
         new ImageProvider("dialogs/filter").getResource().attachImageIcon(this, true);
         this.layer = layer;
@@ -117,5 +126,5 @@
             TrackLength length = new TrackLength(trk.length());
             String url = (String) Optional.ofNullable(attr.get("url")).orElse("");
-            tracks[i] = new Object[]{name, desc, time, length, url};
+            tracks[i] = new Object[]{name, desc, time, length, url, trk};
             i++;
         }
@@ -123,6 +132,36 @@
     }
 
+    private void showColorDialog(List<GpxTrack> tracks) {
+        Color cl = tracks.stream().filter(Objects::nonNull)
+                .map(GpxTrack::getColor).filter(Objects::nonNull)
+                .findAny().orElse(GpxDrawHelper.DEFAULT_COLOR_PROPERTY.get());
+        JColorChooser c = new JColorChooser(cl);
+        Object[] options = new Object[]{tr("OK"), tr("Cancel"), tr("Default")};
+        int answer = JOptionPane.showOptionDialog(
+                MainApplication.getMainFrame(),
+                c,
+                tr("Choose a color"),
+                JOptionPane.OK_CANCEL_OPTION,
+                JOptionPane.PLAIN_MESSAGE,
+                null,
+                options,
+                options[0]
+        );
+        switch (answer) {
+        case 0:
+            tracks.stream().forEach(t -> t.setColor(c.getColor()));
+            GPXSettingsPanel.putLayerPrefLocal(layer, "colormode", "0"); //set Colormode to none
+            break;
+        case 1:
+            return;
+        case 2:
+            tracks.stream().forEach(t -> t.setColor(null));
+            break;
+        }
+        table.repaint();
+    }
+
     /**
-     * Builds an non-editable table whose 5th column will open a browser when double clicked.
+     * Builds an editable table whose 5th column will open a browser when double clicked.
      * The table will fill its parent.
      * @param content table data
@@ -139,4 +178,38 @@
                     JComponent jc = (JComponent) c;
                     jc.setToolTipText(getValueAt(row, col).toString());
+                    if (content.length > row
+                            && content[row].length > 5
+                            && content[row][5] instanceof GpxTrack) {
+                        Color color = ((GpxTrack) content[row][5]).getColor();
+                        if (color != null) {
+                            double brightness = Math.sqrt(Math.pow(color.getRed(), 2) * .241
+                                    + Math.pow(color.getGreen(), 2) * .691
+                                    + Math.pow(color.getBlue(), 2) * .068);
+                            if (brightness > 250) {
+                                color = color.darker();
+                            }
+                            if (isRowSelected(row)) {
+                                jc.setBackground(color);
+                                if (brightness <= 130) {
+                                    jc.setForeground(Color.WHITE);
+                                } else {
+                                    jc.setForeground(Color.BLACK);
+                                }
+                            } else {
+                                if (brightness > 200) {
+                                    color = color.darker(); //brightness >250 is darkened twice on purpose
+                                }
+                                jc.setForeground(color);
+                                jc.setBackground(Color.WHITE);
+                            }
+                        } else {
+                            jc.setForeground(Color.BLACK);
+                            if (isRowSelected(row)) {
+                                jc.setBackground(new Color(175, 210, 210));
+                            } else {
+                                jc.setBackground(Color.WHITE);
+                            }
+                        }
+                    }
                 }
                 return c;
@@ -145,5 +218,26 @@
             @Override
             public boolean isCellEditable(int rowIndex, int colIndex) {
-                return false;
+                return colIndex <= 1;
+            }
+
+            @Override
+            public void tableChanged(TableModelEvent e) {
+                super.tableChanged(e);
+                int col = e.getColumn();
+                int row = e.getFirstRow();
+                if (row >= 0 && row < content.length && col >= 0 && col <= 1) {
+                    Object t = content[row][5];
+                    String val = (String) getValueAt(row, col);
+                    if (t != null && t instanceof GpxTrack) {
+                        GpxTrack trk = (GpxTrack) t;
+                        if (col == 0) {
+                            trk.put("name", val);
+                        } else {
+                            trk.put("desc", val);
+                        }
+                    } else {
+                        throw new InvalidArgumentException("Invalid object in table, must be GpxTrack.");
+                    }
+                }
             }
         };
@@ -181,4 +275,5 @@
         t.addMouseListener(urlOpener);
         t.setFillsViewportHeight(true);
+        t.putClientProperty("terminateEditOnFocusLost", true);
         return t;
     }
@@ -250,9 +345,11 @@
         msg.add(new JLabel(tr("<html>Select all tracks that you want to be displayed. " +
                 "You can drag select a range of tracks or use CTRL+Click to select specific ones. " +
-                "The map is updated live in the background. Open the URLs by double clicking them.</html>")),
+                "The map is updated live in the background. Open the URLs by double clicking them, " +
+                "edit name and description by double clicking the cell.</html>")),
                 GBC.eop().fill(GBC.HORIZONTAL));
         // build table
         final boolean[] trackVisibilityBackup = layer.trackVisibility.clone();
-        table = buildTable(buildTableContents());
+        Object[][] content = buildTableContents();
+        table = buildTable(content);
         selectVisibleTracksInTable();
         listenToSelectionChanges();
@@ -263,7 +360,24 @@
         int v = 1;
         // build dialog
-        ExtendedDialog ed = new ExtendedDialog(MainApplication.getMainFrame(), tr("Set track visibility for {0}", layer.getName()),
-                tr("Show all"), tr("Show selected only"), tr("Cancel"));
-        ed.setButtonIcons("eye", "dialogs/filter", "cancel");
+        ExtendedDialog ed = new ExtendedDialog(MainApplication.getMainFrame(),
+                tr("Set track visibility for {0}", layer.getName()),
+                tr("Set color for selected tracks..."), tr("Show all"), tr("Show selected only"), tr("Close")) {
+            @Override
+            protected void buttonAction(int buttonIndex, ActionEvent evt) {
+                if (buttonIndex == 0) {
+                    List<GpxTrack> trks = new ArrayList<>();
+                    for (int i : table.getSelectedRows()) {
+                        Object trk = content[i][5];
+                        if (trk != null && trk instanceof GpxTrack) {
+                            trks.add((GpxTrack) trk);
+                        }
+                    }
+                    showColorDialog(trks);
+                } else {
+                    super.buttonAction(buttonIndex, evt);
+                }
+            }
+        };
+        ed.setButtonIcons("colorchooser", "eye", "dialogs/filter", "cancel");
         ed.setContent(msg, false);
         ed.setDefaultButton(2);
@@ -276,13 +390,13 @@
         v = ed.getValue();
         // cancel for unknown buttons and copy back original settings
-        if (v != 1 && v != 2) {
+        if (v != 2 && v != 3) {
             layer.trackVisibility = Arrays.copyOf(trackVisibilityBackup, layer.trackVisibility.length);
             MainApplication.getMap().repaint();
             return;
         }
-        // set visibility (1 = show all, 2 = filter). If no tracks are selected
+        // set visibility (2 = show all, 3 = filter). If no tracks are selected
         // set all of them visible and...
         ListSelectionModel s = table.getSelectionModel();
-        final boolean all = v == 1 || s.isSelectionEmpty();
+        final boolean all = v == 2 || s.isSelectionEmpty();
         for (int i = 0; i < layer.trackVisibility.length; i++) {
             layer.trackVisibility[table.convertRowIndexToModel(i)] = all || s.isSelectedIndex(i);
@@ -291,5 +405,5 @@
         layer.invalidate();
         // ...sync with layer visibility instead to avoid having two ways to hide everything
-        layer.setVisible(v == 1 || !s.isSelectionEmpty());
+        layer.setVisible(v == 2 || !s.isSelectionEmpty());
     }
 }
Index: /trunk/src/org/openstreetmap/josm/gui/layer/gpx/ConvertFromGpxLayerAction.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/layer/gpx/ConvertFromGpxLayerAction.java	(revision 15495)
+++ /trunk/src/org/openstreetmap/josm/gui/layer/gpx/ConvertFromGpxLayerAction.java	(revision 15496)
@@ -8,7 +8,7 @@
 import java.awt.event.ActionListener;
 import java.util.ArrayList;
-import java.util.Collection;
 import java.util.Date;
 import java.util.List;
+import java.util.Map;
 import java.util.Map.Entry;
 
@@ -21,9 +21,12 @@
 
 import org.openstreetmap.josm.data.gpx.GpxConstants;
-import org.openstreetmap.josm.data.gpx.GpxTrack;
-import org.openstreetmap.josm.data.gpx.GpxTrackSegment;
+import org.openstreetmap.josm.data.gpx.GpxExtension;
+import org.openstreetmap.josm.data.gpx.GpxExtensionCollection;
+import org.openstreetmap.josm.data.gpx.IGpxTrack;
+import org.openstreetmap.josm.data.gpx.IGpxTrackSegment;
 import org.openstreetmap.josm.data.gpx.WayPoint;
 import org.openstreetmap.josm.data.osm.DataSet;
 import org.openstreetmap.josm.data.osm.Node;
+import org.openstreetmap.josm.data.osm.OsmPrimitive;
 import org.openstreetmap.josm.data.osm.Way;
 import org.openstreetmap.josm.gui.ExtendedDialog;
@@ -54,4 +57,5 @@
     public DataSet convert() {
         final DataSet ds = new DataSet();
+        ds.setGPXNamespaces(layer.data.getNamespaces());
 
         List<String> keys = new ArrayList<>(); // note that items in this list don't have the GPX_PREFIX
@@ -60,26 +64,12 @@
         boolean none = "no".equals(convertTags); // no need to convert tags when no dialog will be shown anyways
 
-        for (GpxTrack trk : layer.data.getTracks()) {
-            for (GpxTrackSegment segment : trk.getSegments()) {
+        for (IGpxTrack trk : layer.data.getTracks()) {
+            for (IGpxTrackSegment segment : trk.getSegments()) {
                 List<Node> nodes = new ArrayList<>();
                 for (WayPoint p : segment.getWayPoints()) {
                     Node n = new Node(p.getCoor());
-                    for (Entry<String, Object> entry : p.attr.entrySet()) {
-                        String key = entry.getKey();
-                        Object obj = p.get(key);
-                        if (check && !keys.contains(key) && (obj instanceof String || obj instanceof Number || obj instanceof Date)) {
-                            keys.add(key);
-                        }
-                        if (!none && (obj instanceof String || obj instanceof Number)) {
-                            // only convert when required
-                            n.put(GpxConstants.GPX_PREFIX + key, obj.toString());
-                        } else if (obj instanceof Date && GpxConstants.PT_TIME.equals(key)) {
-                            // timestamps should always be converted
-                            Date date = (Date) obj;
-                            if (!none) { //... but the tag will only be set when required
-                                n.put(GpxConstants.GPX_PREFIX + key, DateUtils.fromDate(date));
-                            }
-                            n.setTimestamp(date);
-                        }
+                    addAttributes(p.getAttributes(), n, keys, check, none);
+                    if (!none) {
+                        addExtensions(p.getExtensions(), n, false, keys, check);
                     }
                     ds.addPrimitive(n);
@@ -88,4 +78,10 @@
                 Way w = new Way();
                 w.setNodes(nodes);
+                addAttributes(trk.getAttributes(), w, keys, check, none);
+                addAttributes(segment.getAttributes(), w, keys, check, none);
+                if (!none) {
+                    addExtensions(trk.getExtensions(), w, false, keys, check);
+                    addExtensions(segment.getExtensions(), w, true, keys, check);
+                }
                 ds.addPrimitive(w);
             }
@@ -123,4 +119,49 @@
     }
 
+    private static void addAttributes(Map<String, Object> attr, OsmPrimitive p, List<String> keys, boolean check, boolean none) {
+        for (Entry<String, Object> entry : attr.entrySet()) {
+            String key = entry.getKey();
+            Object obj = entry.getValue();
+            if (check && !keys.contains(key) && (obj instanceof String || obj instanceof Number || obj instanceof Date)) {
+                keys.add(key);
+            }
+            if (!none && (obj instanceof String || obj instanceof Number)) {
+                // only convert when required
+                p.put(GpxConstants.GPX_PREFIX + key, obj.toString());
+            } else if (obj instanceof Date && GpxConstants.PT_TIME.equals(key)) {
+                // timestamps should always be converted
+                Date date = (Date) obj;
+                if (!none) { //... but the tag will only be set when required
+                    p.put(GpxConstants.GPX_PREFIX + key, DateUtils.fromDate(date));
+                }
+                p.setTimestamp(date);
+            }
+        }
+    }
+
+    private static void addExtensions(GpxExtensionCollection exts, OsmPrimitive p, boolean seg, List<String> keys, boolean check) {
+        for (GpxExtension ext : exts) {
+            String value = ext.getValue();
+            if (value != null && !value.isEmpty()) {
+                String extpre = "extension:";
+                String pre = ext.getPrefix();
+                if (pre == null || pre.isEmpty()) {
+                    pre = "other";
+                }
+                String segpre = seg ? "segment:" : ""; //needs to be distinguished since both track and segment extensions are applied to the resulting way
+                String key = ext.getFlatKey();
+                String fullkey = GpxConstants.GPX_PREFIX + extpre + pre + ":" + segpre + key;
+                if (GpxConstants.EXTENSION_ABBREVIATIONS.containsKey(fullkey)) {
+                    fullkey = GpxConstants.EXTENSION_ABBREVIATIONS.get(fullkey);
+                }
+                if (check && !keys.contains(fullkey)) {
+                    keys.add(fullkey);
+                }
+                p.put(fullkey, value);
+            }
+            addExtensions(ext.getExtensions(), p, seg, keys, check);
+        }
+    }
+
     /**
      * Filters the tags of the given {@link DataSet}
@@ -131,9 +172,14 @@
      */
     public DataSet filterDataSet(DataSet ds, List<String> listPos) {
-        Collection<Node> nodes = ds.getNodes();
-        for (Node n : nodes) {
-            for (String key : n.keySet()) {
-                if (listPos == null || !listPos.contains(key.substring(GpxConstants.GPX_PREFIX.length()))) {
-                    n.put(key, null);
+        for (OsmPrimitive p : ds.getPrimitives(p -> p instanceof Node || p instanceof Way)) {
+            for (String key : p.keySet()) {
+                String listkey;
+                if (listPos != null && key.startsWith(GpxConstants.GPX_PREFIX)) {
+                    listkey = key.substring(GpxConstants.GPX_PREFIX.length());
+                } else {
+                    listkey = key;
+                }
+                if (listPos == null || !listPos.contains(listkey)) {
+                   p.put(key, null);
                 }
             }
Index: /trunk/src/org/openstreetmap/josm/gui/layer/gpx/CustomizeDrawingAction.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/layer/gpx/CustomizeDrawingAction.java	(revision 15495)
+++ /trunk/src/org/openstreetmap/josm/gui/layer/gpx/CustomizeDrawingAction.java	(revision 15496)
@@ -10,4 +10,5 @@
 import java.util.LinkedList;
 import java.util.List;
+import java.util.stream.Collectors;
 
 import javax.swing.AbstractAction;
@@ -60,10 +61,5 @@
     @Override
     public boolean supportLayers(List<Layer> layers) {
-        for (Layer layer : layers) {
-            if (!(layer instanceof GpxLayer)) {
-                return false;
-            }
-        }
-        return true;
+        return layers.stream().allMatch(l -> l instanceof GpxLayer);
     }
 
@@ -80,16 +76,5 @@
     @Override
     public void actionPerformed(ActionEvent e) {
-        boolean hasLocal = false;
-        boolean hasNonlocal = false;
-        for (Layer layer : layers) {
-            if (layer instanceof GpxLayer) {
-                if (((GpxLayer) layer).isLocalFile()) {
-                    hasLocal = true;
-                } else {
-                    hasNonlocal = true;
-                }
-            }
-        }
-        GPXSettingsPanel panel = new GPXSettingsPanel(layers.get(0).getName(), hasLocal, hasNonlocal);
+        GPXSettingsPanel panel = new GPXSettingsPanel(layers.stream().filter(l -> l instanceof GpxLayer).map(l -> (GpxLayer) l).collect(Collectors.toList()));
         JScrollPane scrollpane = GuiHelper.embedInVerticalScrollPane(panel);
         scrollpane.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
@@ -104,13 +89,7 @@
             return;
         }
-        for (Layer layer : layers) {
-            // save preferences for all layers
-            boolean f = false;
-            if (layer instanceof GpxLayer) {
-                f = ((GpxLayer) layer).isLocalFile();
-            }
-            panel.savePreferences(layer.getName(), f);
-        }
-        MainApplication.getMap().repaint();
+        panel.savePreferences();
+        MainApplication.getMainPanel().repaint();
+        layers.stream().forEach(Layer::invalidate);
     }
 
Index: /trunk/src/org/openstreetmap/josm/gui/layer/gpx/DownloadAlongTrackAction.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/layer/gpx/DownloadAlongTrackAction.java	(revision 15495)
+++ /trunk/src/org/openstreetmap/josm/gui/layer/gpx/DownloadAlongTrackAction.java	(revision 15496)
@@ -9,5 +9,5 @@
 import org.openstreetmap.josm.data.gpx.GpxData;
 import org.openstreetmap.josm.data.gpx.GpxTrack;
-import org.openstreetmap.josm.data.gpx.GpxTrackSegment;
+import org.openstreetmap.josm.data.gpx.IGpxTrackSegment;
 import org.openstreetmap.josm.data.gpx.WayPoint;
 import org.openstreetmap.josm.gui.PleaseWaitRunnable;
@@ -61,5 +61,5 @@
         if (near == NEAR_TRACK || near == NEAR_BOTH) {
             for (GpxTrack trk : data.tracks) {
-                for (GpxTrackSegment segment : trk.getSegments()) {
+                for (IGpxTrackSegment segment : trk.getSegments()) {
                     boolean first = true;
                     for (WayPoint p : segment.getWayPoints()) {
Index: /trunk/src/org/openstreetmap/josm/gui/layer/gpx/DownloadWmsAlongTrackAction.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/layer/gpx/DownloadWmsAlongTrackAction.java	(revision 15495)
+++ /trunk/src/org/openstreetmap/josm/gui/layer/gpx/DownloadWmsAlongTrackAction.java	(revision 15496)
@@ -17,5 +17,5 @@
 import org.openstreetmap.josm.data.gpx.GpxData;
 import org.openstreetmap.josm.data.gpx.GpxTrack;
-import org.openstreetmap.josm.data.gpx.GpxTrackSegment;
+import org.openstreetmap.josm.data.gpx.IGpxTrackSegment;
 import org.openstreetmap.josm.data.gpx.WayPoint;
 import org.openstreetmap.josm.gui.MainApplication;
@@ -93,5 +93,5 @@
         List<LatLon> points = new ArrayList<>();
         for (GpxTrack trk : data.tracks) {
-            for (GpxTrackSegment segment : trk.getSegments()) {
+            for (IGpxTrackSegment segment : trk.getSegments()) {
                 for (WayPoint p : segment.getWayPoints()) {
                     points.add(p.getCoor());
Index: /trunk/src/org/openstreetmap/josm/gui/layer/gpx/GpxDrawHelper.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/layer/gpx/GpxDrawHelper.java	(revision 15495)
+++ /trunk/src/org/openstreetmap/josm/gui/layer/gpx/GpxDrawHelper.java	(revision 15496)
@@ -28,4 +28,5 @@
 import java.util.LinkedList;
 import java.util.List;
+import java.util.Objects;
 import java.util.Random;
 
@@ -33,5 +34,4 @@
 
 import org.openstreetmap.josm.data.Bounds;
-import org.openstreetmap.josm.data.PreferencesUtils;
 import org.openstreetmap.josm.data.SystemOfMeasurement;
 import org.openstreetmap.josm.data.SystemOfMeasurement.SoMChangeListener;
@@ -52,4 +52,5 @@
 import org.openstreetmap.josm.gui.layer.MapViewPaintable.PaintableInvalidationEvent;
 import org.openstreetmap.josm.gui.layer.MapViewPaintable.PaintableInvalidationListener;
+import org.openstreetmap.josm.gui.preferences.display.GPXSettingsPanel;
 import org.openstreetmap.josm.io.CachedFile;
 import org.openstreetmap.josm.spi.preferences.Config;
@@ -66,8 +67,8 @@
 
     /**
-     * The color that is used for drawing GPX points.
-     * @since 10824
-     */
-    public static final NamedColorProperty DEFAULT_COLOR = new NamedColorProperty(marktr("gps point"), Color.magenta);
+     * The default color property that is used for drawing GPX points.
+     * @since 15496
+     */
+    public static final NamedColorProperty DEFAULT_COLOR_PROPERTY = new NamedColorProperty(marktr("gps point"), Color.magenta);
 
     private final GpxData data;
@@ -79,5 +80,5 @@
     private boolean alphaLines;
     // draw direction arrows on the lines
-    private boolean direction;
+    private boolean arrows;
     /** width of line for paint **/
     private int lineWidth;
@@ -91,7 +92,7 @@
     private boolean hdopCircle;
     /** paint direction arrow with alternate math. may be faster **/
-    private boolean alternateDirection;
+    private boolean arrowsFast;
     /** don't draw arrows nearer to each other than this **/
-    private int delta;
+    private int arrowsDelta;
     private double minTrackDurationForTimeColoring;
 
@@ -107,5 +108,5 @@
     private boolean computeCacheColorDynamic;
     private ColorMode computeCacheColored;
-    private int computeCacheColorTracksTune;
+    private int computeCacheVelocityTune;
     private int computeCacheHeatMapDrawColorTableIdx;
     private boolean computeCacheHeatMapDrawPointMode;
@@ -113,9 +114,12 @@
     private int computeCacheHeatMapDrawLowerLimit;
 
+    private Color colorCache;
+    private Color colorCacheTransparent;
+
     //// Color-related fields
     /** Mode of the line coloring **/
     private ColorMode colored;
     /** max speed for coloring - allows to tweak line coloring for different speed levels. **/
-    private int colorTracksTune;
+    private int velocityTune;
     private boolean colorModeDynamic;
     private Color neutralColor;
@@ -146,6 +150,4 @@
     /** heat map parameters **/
 
-    // enabled or not (override by settings)
-    private boolean heatMapEnabled;
     // draw small extra line
     private boolean heatMapDrawExtraLine;
@@ -269,33 +271,12 @@
     }
 
-    private static String specName(String layerName) {
-        return "layer " + layerName;
-    }
-
-    /**
-     * Get the default color for gps tracks for specified layer
-     * @param layerName name of the GpxLayer
-     * @param ignoreCustom do not use preferences
-     * @return the color or null if the color is not constant
-     */
-    public Color getColor(String layerName, boolean ignoreCustom) {
-        if (ignoreCustom || getColorMode(layerName) == ColorMode.NONE) {
-            return DEFAULT_COLOR.getChildColor(
-                    NamedColorProperty.COLOR_CATEGORY_LAYER,
-                    layerName,
-                    DEFAULT_COLOR.getName()).get();
-        } else {
-            return null;
-        }
-    }
-
     /**
      * Read coloring mode for specified layer from preferences
-     * @param layerName name of the GpxLayer
      * @return coloring mode
      */
-    public ColorMode getColorMode(String layerName) {
+    public ColorMode getColorMode() {
         try {
-            int i = PreferencesUtils.getInteger(Config.getPref(), "draw.rawgps.colors", specName(layerName), 0);
+            int i = optInt("colormode");
+            if (i == -1) i = 0; //global
             return ColorMode.fromIndex(i);
         } catch (IndexOutOfBoundsException e) {
@@ -305,54 +286,56 @@
     }
 
-    /** Reads generic color from preferences (usually gray)
-     * @return the color
+    private String opt(String key) {
+        return GPXSettingsPanel.getLayerPref(layer, key);
+    }
+
+    private boolean optBool(String key) {
+        return Boolean.parseBoolean(opt(key));
+    }
+
+    private int optInt(String key) {
+        return GPXSettingsPanel.getLayerPrefInt(layer, key);
+    }
+
+    /**
+     * Read all drawing-related settings from preferences
      **/
-    public static Color getGenericColor() {
-        return DEFAULT_COLOR.get();
-    }
-
-    /**
-     * Read all drawing-related settings from preferences
-     * @param layerName layer name used to access its specific preferences
-     **/
-    public void readPreferences(String layerName) {
-        String spec = specName(layerName);
-        forceLines = PreferencesUtils.getBoolean(Config.getPref(), "draw.rawgps.lines.force", spec, false);
-        direction = PreferencesUtils.getBoolean(Config.getPref(), "draw.rawgps.direction", spec, false);
-        lineWidth = PreferencesUtils.getInteger(Config.getPref(), "draw.rawgps.linewidth", spec, 0);
-        alphaLines = PreferencesUtils.getBoolean(Config.getPref(), "draw.rawgps.lines.alpha-blend", spec, false);
-
+    public void readPreferences() {
+        forceLines = optBool("lines.force");
+        arrows = optBool("lines.arrows");
+        arrowsFast = optBool("lines.arrows.fast");
+        arrowsDelta = optInt("lines.arrows.min-distance");
+        lineWidth = optInt("lines.width");
+        alphaLines = optBool("lines.alpha-blend");
+
+        int l = optInt("lines");
         if (!data.fromServer) {
-            maxLineLength = PreferencesUtils.getInteger(Config.getPref(), "draw.rawgps.max-line-length.local", spec, -1);
-            lines = PreferencesUtils.getBoolean(Config.getPref(), "draw.rawgps.lines.local", spec, true);
+            maxLineLength = optInt("lines.max-length.local");
+            lines = l != 0; //draw for -1 (default), 1 (local) and 2 (all)
         } else {
-            maxLineLength = PreferencesUtils.getInteger(Config.getPref(), "draw.rawgps.max-line-length", spec, 200);
-            lines = PreferencesUtils.getBoolean(Config.getPref(), "draw.rawgps.lines", spec, true);
-        }
-        large = PreferencesUtils.getBoolean(Config.getPref(), "draw.rawgps.large", spec, false);
-        largesize = PreferencesUtils.getInteger(Config.getPref(), "draw.rawgps.large.size", spec, 3);
-        hdopCircle = PreferencesUtils.getBoolean(Config.getPref(), "draw.rawgps.hdopcircle", spec, false);
-        colored = getColorMode(layerName);
-        alternateDirection = PreferencesUtils.getBoolean(Config.getPref(), "draw.rawgps.alternatedirection", spec, false);
-        delta = PreferencesUtils.getInteger(Config.getPref(), "draw.rawgps.min-arrow-distance", spec, 40);
-        colorTracksTune = PreferencesUtils.getInteger(Config.getPref(), "draw.rawgps.colorTracksTune", spec, 45);
-        colorModeDynamic = PreferencesUtils.getBoolean(Config.getPref(), "draw.rawgps.colors.dynamic", spec, false);
+            maxLineLength = optInt("lines.max-length");
+            lines = l == 2; //draw only for 2 (all)
+        }
+        large = optBool("points.large");
+        largesize = optInt("points.large.size");
+        hdopCircle = optBool("points.hdopcircle");
+        colored = getColorMode();
+        velocityTune = optInt("colormode.velocity.tune");
+        colorModeDynamic = optBool("colormode.dynamic-range");
         /* good HDOP's are between 1 and 3, very bad HDOP's go into 3 digit values */
         hdoprange = Config.getPref().getInt("hdop.range", 7);
-        minTrackDurationForTimeColoring = Config.getPref().getInt("draw.rawgps.date-coloring-min-dt", 60);
-        largePointAlpha = Config.getPref().getInt("draw.rawgps.large.alpha", -1) & 0xFF;
+        minTrackDurationForTimeColoring = optInt("colormode.time.min-distance");
+        largePointAlpha = optInt("points.large.alpha") & 0xFF;
 
         // get heatmap parameters
-        heatMapEnabled = PreferencesUtils.getBoolean(Config.getPref(), "draw.rawgps.heatmap.enabled", spec, false);
-        heatMapDrawExtraLine = PreferencesUtils.getBoolean(Config.getPref(), "draw.rawgps.heatmap.line-extra", spec, false);
-        heatMapDrawColorTableIdx = PreferencesUtils.getInteger(Config.getPref(), "draw.rawgps.heatmap.colormap", spec, 0);
-        heatMapDrawPointMode = PreferencesUtils.getBoolean(Config.getPref(), "draw.rawgps.heatmap.use-points", spec, false);
-        heatMapDrawGain = PreferencesUtils.getInteger(Config.getPref(), "draw.rawgps.heatmap.gain", spec, 0);
-        heatMapDrawLowerLimit = PreferencesUtils.getInteger(Config.getPref(), "draw.rawgps.heatmap.lower-limit", spec, 0);
+        heatMapDrawExtraLine = optBool("colormode.heatmap.line-extra");
+        heatMapDrawColorTableIdx = optInt("colormode.heatmap.colormap");
+        heatMapDrawPointMode = optBool("colormode.heatmap.use-points");
+        heatMapDrawGain = optInt("colormode.heatmap.gain");
+        heatMapDrawLowerLimit = optInt("colormode.heatmap.lower-limit");
 
         // shrink to range
         heatMapDrawGain = Utils.clamp(heatMapDrawGain, -10, 10);
-
-        neutralColor = getColor(layerName, true);
+        neutralColor = DEFAULT_COLOR_PROPERTY.get();
         velocityScale.setNoDataColor(neutralColor);
         dateScale.setNoDataColor(neutralColor);
@@ -369,5 +352,5 @@
         List<WayPoint> visibleSegments = listVisibleSegments(clipBounds);
         if (!visibleSegments.isEmpty()) {
-            readPreferences(layer.getName());
+            readPreferences();
             drawAll(graphics.getDefaultGraphics(), graphics.getMapView(), visibleSegments, clipBounds);
             if (graphics.getMapView().getLayerManager().getActiveLayer() == layer) {
@@ -431,5 +414,4 @@
      * @since 14748 : new parameter clipBounds
      */
-
     public void drawAll(Graphics2D g, MapView mv, List<WayPoint> visibleSegments, Bounds clipBounds) {
 
@@ -463,5 +445,5 @@
 
         // global enabled or select via color
-        boolean useHeatMap = heatMapEnabled || ColorMode.HEATMAP == colored;
+        boolean useHeatMap = ColorMode.HEATMAP == colored;
 
         // default global alpha level
@@ -571,5 +553,5 @@
             oldWp = null;
         } else { // color mode not dynamic
-            velocityScale.setRange(0, colorTracksTune);
+            velocityScale.setRange(0, velocityTune);
             hdopScale.setRange(0, hdoprange);
             qualityScale.setRange(1, rtkLibQualityColors.length);
@@ -595,5 +577,5 @@
             for (WayPoint trkPnt : segment) {
                 LatLon c = trkPnt.getCoor();
-                trkPnt.customColoring = neutralColor;
+                trkPnt.customColoring = segment.getColor();
                 if (Double.isNaN(c.lat()) || Double.isNaN(c.lon())) {
                     continue;
@@ -643,5 +625,5 @@
                 } else { // make sure we reset outdated data
                     trkPnt.drawLine = false;
-                    color = neutralColor;
+                    color = segment.getColor();
                 }
                 if (color != null) {
@@ -701,5 +683,5 @@
          ********** STEP 3b - DRAW NICE ARROWS **************************
          ****************************************************************/
-        if (lines && direction && !alternateDirection) {
+        if (lines && arrows && !arrowsFast) {
             Point old = null;
             Point oldA = null; // last arrow painted
@@ -713,6 +695,6 @@
                     // skip points that are on the same screenposition
                     if (old != null
-                            && (oldA == null || screen.x < oldA.x - delta || screen.x > oldA.x + delta
-                            || screen.y < oldA.y - delta || screen.y > oldA.y + delta)) {
+                            && (oldA == null || screen.x < oldA.x - arrowsDelta || screen.x > oldA.x + arrowsDelta
+                            || screen.y < oldA.y - arrowsDelta || screen.y > oldA.y + arrowsDelta)) {
                         g.setColor(trkPnt.customColoring);
                         double t = Math.atan2((double) screen.y - old.y, (double) screen.x - old.x) + Math.PI;
@@ -731,5 +713,5 @@
          ********** STEP 3c - DRAW FAST ARROWS **************************
          ****************************************************************/
-        if (lines && direction && alternateDirection) {
+        if (lines && arrows && arrowsFast) {
             Point old = null;
             Point oldA = null; // last arrow painted
@@ -743,6 +725,6 @@
                     // skip points that are on the same screenposition
                     if (old != null
-                            && (oldA == null || screen.x < oldA.x - delta || screen.x > oldA.x + delta
-                            || screen.y < oldA.y - delta || screen.y > oldA.y + delta)) {
+                            && (oldA == null || screen.x < oldA.x - arrowsDelta || screen.x > oldA.x + arrowsDelta
+                            || screen.y < oldA.y - arrowsDelta || screen.y > oldA.y + arrowsDelta)) {
                         g.setColor(trkPnt.customColoring);
                         g.drawLine(screen.x, screen.y, screen.x + dir[trkPnt.dir][0], screen.y
@@ -795,8 +777,14 @@
                     // color the large GPS points like the gps lines
                     if (trkPnt.customColoring != null) {
-                        Color customColoringTransparent = largePointAlpha < 0 ? trkPnt.customColoring :
-                            new Color((trkPnt.customColoring.getRGB() & 0x00ffffff) | (largePointAlpha << 24), true);
-
-                        g.setColor(customColoringTransparent);
+                        if (trkPnt.customColoring.equals(colorCache) && colorCacheTransparent != null) {
+                            g.setColor(colorCacheTransparent);
+                        } else {
+                            Color customColoringTransparent = largePointAlpha < 0 ? trkPnt.customColoring :
+                                new Color((trkPnt.customColoring.getRGB() & 0x00ffffff) | (largePointAlpha << 24), true);
+
+                            g.setColor(customColoringTransparent);
+                            colorCache = trkPnt.customColoring;
+                            colorCacheTransparent = customColoringTransparent;
+                        }
                     }
                     g.fillRect(screen.x-halfSize, screen.y-halfSize, largesize, largesize);
@@ -816,4 +804,5 @@
                 }
                 if (!trkPnt.drawLine) {
+                    g.setColor(trkPnt.customColoring);
                     Point screen = mv.getPoint(trkPnt);
                     g.drawRect(screen.x, screen.y, 0, 0);
@@ -1481,10 +1470,10 @@
         if ((computeCacheMaxLineLengthUsed != maxLineLength)
                 || (computeCacheColored != colored)
-                || (computeCacheColorTracksTune != colorTracksTune)
+                || (computeCacheVelocityTune != velocityTune)
                 || (computeCacheColorDynamic != colorModeDynamic)
                 || (computeCacheHeatMapDrawColorTableIdx != heatMapDrawColorTableIdx)
-                || (!neutralColor.equals(computeCacheColorUsed)
+                || !Objects.equals(neutralColor, computeCacheColorUsed)
                 || (computeCacheHeatMapDrawPointMode != heatMapDrawPointMode)
-                || (computeCacheHeatMapDrawGain != heatMapDrawGain))
+                || (computeCacheHeatMapDrawGain != heatMapDrawGain)
                 || (computeCacheHeatMapDrawLowerLimit != heatMapDrawLowerLimit)
         ) {
@@ -1494,5 +1483,5 @@
             computeCacheColorUsed = neutralColor;
             computeCacheColored = colored;
-            computeCacheColorTracksTune = colorTracksTune;
+            computeCacheVelocityTune = velocityTune;
             computeCacheColorDynamic = colorModeDynamic;
             computeCacheHeatMapDrawColorTableIdx = heatMapDrawColorTableIdx;
Index: /trunk/src/org/openstreetmap/josm/gui/layer/gpx/ImportAudioAction.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/layer/gpx/ImportAudioAction.java	(revision 15495)
+++ /trunk/src/org/openstreetmap/josm/gui/layer/gpx/ImportAudioAction.java	(revision 15496)
@@ -22,5 +22,5 @@
 import org.openstreetmap.josm.data.gpx.GpxData;
 import org.openstreetmap.josm.data.gpx.GpxTrack;
-import org.openstreetmap.josm.data.gpx.GpxTrackSegment;
+import org.openstreetmap.josm.data.gpx.IGpxTrackSegment;
 import org.openstreetmap.josm.data.gpx.WayPoint;
 import org.openstreetmap.josm.data.projection.ProjectionRegistry;
@@ -148,5 +148,5 @@
         if (hasTracks) {
             for (GpxTrack track : layer.data.tracks) {
-                for (GpxTrackSegment seg : track.getSegments()) {
+                for (IGpxTrackSegment seg : track.getSegments()) {
                     for (WayPoint w : seg.getWayPoints()) {
                         firstTime = w.getTime();
@@ -207,5 +207,5 @@
                 && !layer.data.tracks.isEmpty()) {
             for (GpxTrack track : layer.data.tracks) {
-                for (GpxTrackSegment seg : track.getSegments()) {
+                for (IGpxTrackSegment seg : track.getSegments()) {
                     for (WayPoint w : seg.getWayPoints()) {
                         if (w.attr.containsKey(GpxConstants.GPX_NAME) || w.attr.containsKey(GpxConstants.GPX_DESC)) {
@@ -228,5 +228,5 @@
 
             for (GpxTrack track : layer.data.tracks) {
-                for (GpxTrackSegment seg : track.getSegments()) {
+                for (IGpxTrackSegment seg : track.getSegments()) {
                     for (WayPoint w : seg.getWayPoints()) {
                         if (startTime < w.getTime()) {
@@ -264,5 +264,5 @@
             boolean gotOne = false;
             for (GpxTrack track : layer.data.tracks) {
-                for (GpxTrackSegment seg : track.getSegments()) {
+                for (IGpxTrackSegment seg : track.getSegments()) {
                     for (WayPoint w : seg.getWayPoints()) {
                         WayPoint wStart = new WayPoint(w.getCoor());
Index: /trunk/src/org/openstreetmap/josm/gui/layer/markerlayer/AudioMarker.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/layer/markerlayer/AudioMarker.java	(revision 15495)
+++ /trunk/src/org/openstreetmap/josm/gui/layer/markerlayer/AudioMarker.java	(revision 15496)
@@ -94,6 +94,6 @@
 
     @Override
-    protected TemplateEntryProperty getTextTemplate() {
-        return TemplateEntryProperty.forAudioMarker(parentLayer.getName());
+    protected String getTextTemplateKey() {
+        return "markers.audio.pattern";
     }
 
@@ -104,6 +104,6 @@
         link.type = "audio";
         wpt.put(GpxConstants.META_LINKS, Collections.singleton(link));
-        wpt.addExtension("offset", Double.toString(offset));
-        wpt.addExtension("sync-offset", Double.toString(syncOffset));
+        wpt.getExtensions().add("josm", "offset", Double.toString(offset));
+        wpt.getExtensions().add("josm", "sync-offset", Double.toString(syncOffset));
         return wpt;
     }
Index: /trunk/src/org/openstreetmap/josm/gui/layer/markerlayer/DefaultMarkerProducers.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/layer/markerlayer/DefaultMarkerProducers.java	(revision 15495)
+++ /trunk/src/org/openstreetmap/josm/gui/layer/markerlayer/DefaultMarkerProducers.java	(revision 15496)
@@ -10,6 +10,6 @@
 import java.util.Optional;
 
-import org.openstreetmap.josm.data.gpx.Extensions;
 import org.openstreetmap.josm.data.gpx.GpxConstants;
+import org.openstreetmap.josm.data.gpx.GpxExtension;
 import org.openstreetmap.josm.data.gpx.GpxLink;
 import org.openstreetmap.josm.data.gpx.WayPoint;
@@ -46,8 +46,8 @@
         } else if (Utils.hasExtension(urlStr, "wav", "mp3", "aac", "aif", "aiff")) {
             final AudioMarker audioMarker = new AudioMarker(wpt.getCoor(), wpt, url, parentLayer, time, offset);
-            Extensions exts = (Extensions) wpt.get(GpxConstants.META_EXTENSIONS);
-            if (exts != null && exts.containsKey("offset")) {
+            GpxExtension offsetExt = wpt.getExtensions().get("josm", "sync-offset");
+            if (offsetExt != null && offsetExt.getValue() != null) {
                 try {
-                    audioMarker.syncOffset = Double.parseDouble(exts.get("sync-offset"));
+                    audioMarker.syncOffset = Double.parseDouble(offsetExt.getValue());
                 } catch (NumberFormatException nfe) {
                     Logging.warn(nfe);
Index: /trunk/src/org/openstreetmap/josm/gui/layer/markerlayer/Marker.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/layer/markerlayer/Marker.java	(revision 15495)
+++ /trunk/src/org/openstreetmap/josm/gui/layer/markerlayer/Marker.java	(revision 15496)
@@ -19,4 +19,5 @@
 import javax.swing.ImageIcon;
 
+import org.openstreetmap.josm.data.Preferences;
 import org.openstreetmap.josm.data.coor.CachedLatLon;
 import org.openstreetmap.josm.data.coor.EastNorth;
@@ -26,7 +27,7 @@
 import org.openstreetmap.josm.data.gpx.WayPoint;
 import org.openstreetmap.josm.data.osm.search.SearchCompiler.Match;
-import org.openstreetmap.josm.data.preferences.CachedProperty;
 import org.openstreetmap.josm.gui.MapView;
-import org.openstreetmap.josm.spi.preferences.PreferenceChangeEvent;
+import org.openstreetmap.josm.gui.layer.GpxLayer;
+import org.openstreetmap.josm.gui.preferences.display.GPXSettingsPanel;
 import org.openstreetmap.josm.tools.ImageProvider;
 import org.openstreetmap.josm.tools.Logging;
@@ -73,78 +74,4 @@
 public class Marker implements TemplateEngineDataProvider, ILatLon {
 
-    public static final class TemplateEntryProperty extends CachedProperty<TemplateEntry> {
-        // This class is a bit complicated because it supports both global and per layer settings. I've added per layer settings because
-        // GPXSettingsPanel had possibility to set waypoint label but then I've realized that markers use different layer then gpx data
-        // so per layer settings is useless. Anyway it's possible to specify marker layer pattern in Einstein preferences and maybe somebody
-        // will make gui for it so I'm keeping it here
-
-        private static final Map<String, TemplateEntryProperty> CACHE = new HashMap<>();
-
-        public static TemplateEntryProperty forMarker(String layerName) {
-            String key = "draw.rawgps.layer.wpt.pattern";
-            if (layerName != null) {
-                key += '.' + layerName;
-            }
-            TemplateEntryProperty result = CACHE.get(key);
-            if (result == null) {
-                String defaultValue = layerName == null ? LABEL_PATTERN_AUTO : "";
-                TemplateEntryProperty parent = layerName == null ? null : forMarker(null);
-                result = new TemplateEntryProperty(key, defaultValue, parent);
-                CACHE.put(key, result);
-            }
-            return result;
-        }
-
-        public static TemplateEntryProperty forAudioMarker(String layerName) {
-            String key = "draw.rawgps.layer.audiowpt.pattern";
-            if (layerName != null) {
-                key += '.' + layerName;
-            }
-            TemplateEntryProperty result = CACHE.get(key);
-            if (result == null) {
-                String defaultValue = layerName == null ? "?{ '{name}' | '{desc}' | '{" + Marker.MARKER_FORMATTED_OFFSET + "}' }" : "";
-                TemplateEntryProperty parent = layerName == null ? null : forAudioMarker(null);
-                result = new TemplateEntryProperty(key, defaultValue, parent);
-                CACHE.put(key, result);
-            }
-            return result;
-        }
-
-        private final TemplateEntryProperty parent;
-
-        private TemplateEntryProperty(String key, String defaultValue, TemplateEntryProperty parent) {
-            super(key, defaultValue);
-            this.parent = parent;
-            updateValue(); // Needs to be called because parent wasn't know in super constructor
-        }
-
-        @Override
-        protected TemplateEntry fromString(String s) {
-            try {
-                return new TemplateParser(s).parse();
-            } catch (ParseError e) {
-                Logging.debug(e);
-                Logging.warn("Unable to parse template engine pattern ''{0}'' for property {1}. Using default (''{2}'') instead",
-                        s, getKey(), super.getDefaultValueAsString());
-                return getDefaultValue();
-            }
-        }
-
-        @Override
-        public String getDefaultValueAsString() {
-            if (parent == null)
-                return super.getDefaultValueAsString();
-            else
-                return parent.getAsString();
-        }
-
-        @Override
-        public void preferenceChanged(PreferenceChangeEvent e) {
-            if (e.getKey().equals(key) || (parent != null && e.getKey().equals(parent.getKey()))) {
-                updateValue();
-            }
-        }
-    }
-
     /**
      * Plugins can add their Marker creation stuff at the bottom or top of this list
@@ -217,5 +144,7 @@
 
     private String cachedText;
-    private int textVersion = -1;
+    private static Map<GpxLayer, String> cachedTemplates = new HashMap<>();
+    private String cachedDefaultTemplate;
+
     private CachedLatLon coor;
 
@@ -245,4 +174,6 @@
         this.dataProvider = dataProvider;
         this.text = text;
+
+        Preferences.main().addKeyPreferenceChangeListener("draw.rawgps." + getTextTemplateKey(), l -> updateText());
     }
 
@@ -258,5 +189,5 @@
         wpt.setTimeInMillis((long) (time * 1000));
         if (text != null) {
-            wpt.addExtension("text", text);
+            wpt.getExtensions().add("josm", "text", text);
         } else if (dataProvider != null) {
             for (String key : dataProvider.getTemplateKeys()) {
@@ -373,6 +304,24 @@
     }
 
-    protected TemplateEntryProperty getTextTemplate() {
-        return TemplateEntryProperty.forMarker(parentLayer.getName());
+    protected String getTextTemplateKey() {
+        return "markers.pattern";
+    }
+
+    private String getTextTemplate() {
+        String tmpl;
+        if (cachedTemplates.containsKey(parentLayer.fromLayer)) {
+            tmpl = cachedTemplates.get(parentLayer.fromLayer);
+        } else {
+            tmpl = GPXSettingsPanel.getLayerPref(parentLayer.fromLayer, getTextTemplateKey());
+            cachedTemplates.put(parentLayer.fromLayer, tmpl);
+        }
+        return tmpl;
+    }
+
+    private String getDefaultTextTemplate() {
+        if (cachedDefaultTemplate == null) {
+            cachedDefaultTemplate = GPXSettingsPanel.getLayerPref(null,  getTextTemplateKey());
+        }
+        return cachedDefaultTemplate;
     }
 
@@ -382,18 +331,39 @@
      */
     public String getText() {
-        if (text != null)
+        if (text != null) {
             return text;
-        else {
-            TemplateEntryProperty property = getTextTemplate();
-            if (property.getUpdateCount() != textVersion) {
-                TemplateEntry templateEntry = property.get();
-                StringBuilder sb = new StringBuilder();
-                templateEntry.appendText(sb, this);
-
-                cachedText = sb.toString();
-                textVersion = property.getUpdateCount();
+        } else if (cachedText == null) {
+            TemplateEntry template;
+            String templateString = getTextTemplate();
+            try {
+                template = new TemplateParser(templateString).parse();
+            } catch (ParseError e) {
+                Logging.debug(e);
+                String def = getDefaultTextTemplate();
+                Logging.warn("Unable to parse template engine pattern ''{0}'' for property {1}. Using default (''{2}'') instead",
+                        templateString, getTextTemplateKey(), def);
+                try {
+                    template = new TemplateParser(def).parse();
+                } catch (ParseError e1) {
+                    Logging.error(e1);
+                    cachedText = "";
+                    return "";
+                }
             }
-            return cachedText;
-        }
+            StringBuilder sb = new StringBuilder();
+            template.appendText(sb, this);
+            cachedText = sb.toString();
+
+        }
+        return cachedText;
+    }
+
+    /**
+     * Called when the template changes
+     */
+    public void updateText() {
+        cachedText = null;
+        cachedDefaultTemplate = null;
+        cachedTemplates = new HashMap<>();
     }
 
Index: /trunk/src/org/openstreetmap/josm/gui/layer/markerlayer/MarkerLayer.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/layer/markerlayer/MarkerLayer.java	(revision 15495)
+++ /trunk/src/org/openstreetmap/josm/gui/layer/markerlayer/MarkerLayer.java	(revision 15496)
@@ -21,4 +21,5 @@
 import java.util.Comparator;
 import java.util.List;
+import java.util.Optional;
 
 import javax.swing.AbstractAction;
@@ -31,7 +32,7 @@
 import org.openstreetmap.josm.data.Bounds;
 import org.openstreetmap.josm.data.coor.LatLon;
-import org.openstreetmap.josm.data.gpx.Extensions;
 import org.openstreetmap.josm.data.gpx.GpxConstants;
 import org.openstreetmap.josm.data.gpx.GpxData;
+import org.openstreetmap.josm.data.gpx.GpxExtension;
 import org.openstreetmap.josm.data.gpx.GpxLink;
 import org.openstreetmap.josm.data.gpx.WayPoint;
@@ -49,4 +50,5 @@
 import org.openstreetmap.josm.gui.layer.Layer;
 import org.openstreetmap.josm.gui.layer.gpx.ConvertFromMarkerLayerAction;
+import org.openstreetmap.josm.gui.preferences.display.GPXSettingsPanel;
 import org.openstreetmap.josm.io.audio.AudioPlayer;
 import org.openstreetmap.josm.spi.preferences.Config;
@@ -76,7 +78,10 @@
     private Marker currentMarker;
     public AudioMarker syncAudioMarker;
-
-    private static final Color DEFAULT_COLOR = Color.magenta;
-    private static final NamedColorProperty COLOR_PROPERTY = new NamedColorProperty(marktr("gps marker"), DEFAULT_COLOR);
+    private Color color, realcolor;
+
+    /**
+     * The default color that is used for drawing markers.
+     */
+    public static final NamedColorProperty DEFAULT_COLOR_PROPERTY = new NamedColorProperty(marktr("gps marker"), Color.magenta);
 
     /**
@@ -95,4 +100,15 @@
         String lastLinkedFile = "";
 
+        Color c = null;
+        String cs = GPXSettingsPanel.tryGetLayerPrefLocal(indata, "markers.color");
+        if (cs != null) {
+            try {
+                c = Color.decode(cs);
+            } catch (NumberFormatException ex) {
+                Logging.warn("Could not read marker color: " + cs);
+            }
+        }
+        setPrivateColors(c);
+
         for (WayPoint wpt : indata.waypoints) {
             /* calculate time differences in waypoints */
@@ -124,8 +140,8 @@
             // that group. This way the user can jump to the corresponding
             // playback positions in a long audio track.
-            Extensions exts = (Extensions) wpt.get(GpxConstants.META_EXTENSIONS);
-            if (exts != null && exts.containsKey("offset")) {
+            GpxExtension offsetExt = wpt.getExtensions().get("josm", "offset");
+            if (offsetExt != null && offsetExt.getValue() != null) {
                 try {
-                    offset = Double.valueOf(exts.get("offset"));
+                    offset = Double.valueOf(offsetExt.getValue());
                 } catch (NumberFormatException nfe) {
                     Logging.warn(nfe);
@@ -174,18 +190,7 @@
 
     @Override
-    protected NamedColorProperty getBaseColorProperty() {
-        return COLOR_PROPERTY;
-    }
-
-    /* for preferences */
-    public static Color getGenericColor() {
-        return COLOR_PROPERTY.get();
-    }
-
-    @Override
     public void paint(Graphics2D g, MapView mv, Bounds box) {
         boolean showTextOrIcon = isTextOrIconShown();
-        g.setColor(getColorProperty().get());
-
+        g.setColor(realcolor);
         if (mousePressed) {
             boolean mousePressedTmp = mousePressed;
@@ -451,6 +456,33 @@
      */
     private boolean isTextOrIconShown() {
-        String current = Config.getPref().get("marker.show "+getName(), "show");
-        return "show".equalsIgnoreCase(current);
+        return Boolean.parseBoolean(GPXSettingsPanel.getLayerPref(fromLayer, "markers.show-text"));
+    }
+
+    @Override
+    public boolean hasColor() {
+        return true;
+    }
+
+    @Override
+    public Color getColor() {
+        return color;
+    }
+
+    @Override
+    public void setColor(Color color) {
+        setPrivateColors(color);
+        if (fromLayer != null) {
+            String cs = null;
+            if (color != null) {
+                cs = String.format("#%02X%02X%02X", color.getRed(), color.getGreen(), color.getBlue());
+            }
+            GPXSettingsPanel.putLayerPrefLocal(fromLayer, "markers.color", cs);
+        }
+        invalidate();
+    }
+
+    private void setPrivateColors(Color color) {
+        this.color = color;
+        this.realcolor = Optional.ofNullable(color).orElse(DEFAULT_COLOR_PROPERTY.get());
     }
 
@@ -504,5 +536,5 @@
         @Override
         public void actionPerformed(ActionEvent e) {
-            Config.getPref().put("marker.show "+layer.getName(), layer.isTextOrIconShown() ? "hide" : "show");
+            GPXSettingsPanel.putLayerPrefLocal(layer.fromLayer, "markers.show-text", Boolean.toString(!layer.isTextOrIconShown()));
             layer.invalidate();
         }
Index: /trunk/src/org/openstreetmap/josm/gui/layer/markerlayer/PlayHeadMarker.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/layer/markerlayer/PlayHeadMarker.java	(revision 15495)
+++ /trunk/src/org/openstreetmap/josm/gui/layer/markerlayer/PlayHeadMarker.java	(revision 15496)
@@ -19,5 +19,5 @@
 import org.openstreetmap.josm.data.coor.LatLon;
 import org.openstreetmap.josm.data.gpx.GpxTrack;
-import org.openstreetmap.josm.data.gpx.GpxTrackSegment;
+import org.openstreetmap.josm.data.gpx.IGpxTrackSegment;
 import org.openstreetmap.josm.data.gpx.WayPoint;
 import org.openstreetmap.josm.data.projection.ProjectionRegistry;
@@ -328,5 +328,5 @@
 
         for (GpxTrack track : trackLayer.data.getTracks()) {
-            for (GpxTrackSegment trackseg : track.getSegments()) {
+            for (IGpxTrackSegment trackseg : track.getSegments()) {
                 for (WayPoint w: trackseg.getWayPoints()) {
                     if (audioTime < w.getTime()) {
Index: /trunk/src/org/openstreetmap/josm/gui/preferences/display/ColorPreference.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/preferences/display/ColorPreference.java	(revision 15495)
+++ /trunk/src/org/openstreetmap/josm/gui/preferences/display/ColorPreference.java	(revision 15496)
@@ -101,17 +101,4 @@
         public String getDisplay() {
             switch (info.getCategory()) {
-                case NamedColorProperty.COLOR_CATEGORY_LAYER:
-                    String v = null;
-                    if (info.getSource() != null) {
-                        v = info.getSource();
-                    }
-                    if (!info.getName().isEmpty()) {
-                        if (v == null) {
-                            v = tr(I18n.escape(info.getName()));
-                        } else {
-                            v += " - " + tr(I18n.escape(info.getName()));
-                        }
-                    }
-                    return tr("Layer: {0}", v);
                 case NamedColorProperty.COLOR_CATEGORY_MAPPAINT:
                     if (info.getSource() != null)
@@ -252,6 +239,5 @@
             case NamedColorProperty.COLOR_CATEGORY_GENERAL: return 1;
             case NamedColorProperty.COLOR_CATEGORY_MAPPAINT: return 2;
-            case NamedColorProperty.COLOR_CATEGORY_LAYER: return 3;
-            default: return 4;
+            default: return 3;
         }
     }
@@ -380,6 +366,10 @@
     }
 
+    @SuppressWarnings("PMD.UnusedFormalParameter")
     private static boolean isRemoveColor(ColorEntry ce) {
-        return NamedColorProperty.COLOR_CATEGORY_LAYER.equals(ce.info.getCategory());
+        return false;
+        //COLOR_CATEGORY_LAYER is no longer supported and was the only one that could be removed.
+        //Maybe this is useful for other categories in the future.
+        //return NamedColorProperty.COLOR_CATEGORY_LAYER.equals(ce.info.getCategory());
     }
 
@@ -391,6 +381,6 @@
         ConflictColors.getColors();
         Severity.getColors();
-        MarkerLayer.getGenericColor();
-        GpxDrawHelper.getGenericColor();
+        MarkerLayer.DEFAULT_COLOR_PROPERTY.get();
+        GpxDrawHelper.DEFAULT_COLOR_PROPERTY.get();
         OsmDataLayer.getOutsideColor();
         MapScaler.getColor();
Index: /trunk/src/org/openstreetmap/josm/gui/preferences/display/GPXSettingsPanel.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/preferences/display/GPXSettingsPanel.java	(revision 15495)
+++ /trunk/src/org/openstreetmap/josm/gui/preferences/display/GPXSettingsPanel.java	(revision 15496)
@@ -5,10 +5,14 @@
 import static org.openstreetmap.josm.tools.I18n.trc;
 
-import java.awt.Color;
 import java.awt.Component;
 import java.awt.Dimension;
 import java.awt.GridBagLayout;
 import java.awt.event.ActionListener;
+import java.util.Collections;
 import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
 
 import javax.swing.AbstractButton;
@@ -23,11 +27,11 @@
 import javax.swing.JSlider;
 
+import org.apache.commons.jcs.access.exception.InvalidArgumentException;
 import org.openstreetmap.josm.actions.ExpertToggleAction;
-import org.openstreetmap.josm.data.PreferencesUtils;
-import org.openstreetmap.josm.data.preferences.NamedColorProperty;
+import org.openstreetmap.josm.data.gpx.GpxData;
 import org.openstreetmap.josm.gui.MainApplication;
+import org.openstreetmap.josm.gui.layer.GpxLayer;
 import org.openstreetmap.josm.gui.layer.gpx.GpxDrawHelper;
 import org.openstreetmap.josm.gui.layer.markerlayer.Marker;
-import org.openstreetmap.josm.gui.layer.markerlayer.Marker.TemplateEntryProperty;
 import org.openstreetmap.josm.gui.preferences.PreferenceTabbedPane.ValidationListener;
 import org.openstreetmap.josm.gui.widgets.JosmComboBox;
@@ -68,5 +72,5 @@
     private final JRadioButton colorTypeTime = new JRadioButton(tr("Track date"));
     private final JRadioButton colorTypeHeatMap = new JRadioButton(tr("Heat Map (dark = few, bright = many)"));
-    private final JRadioButton colorTypeNone = new JRadioButton(tr("Single Color (can be customized for named layers)"));
+    private final JRadioButton colorTypeNone = new JRadioButton(tr("Single Color (can be customized in the layer manager)"));
     private final JRadioButton colorTypeGlobal = new JRadioButton(tr("Use global settings"));
     private final JosmComboBox<String> colorTypeVelocityTune = new JosmComboBox<>(new String[] {tr("Car"), tr("Bicycle"), tr("Foot")});
@@ -94,19 +98,57 @@
     private final JCheckBox drawLineWithAlpha = new JCheckBox(tr("Draw with Opacity (alpha blending) "));
 
-    private String layerName;
-    private final boolean local; // flag to display LocalOnly checkbox
-    private final boolean nonlocal; // flag to display AllLines checkbox
-
-    /**
-     * Constructs a new {@code GPXSettingsPanel} for a given layer name.
-     * @param layerName The GPX layer name
-     * @param local flag to display LocalOnly checkbox
-     * @param nonlocal flag to display AllLines checkbox
-     */
-    public GPXSettingsPanel(String layerName, boolean local, boolean nonlocal) {
+    private final List<GpxLayer> layers;
+    private final GpxLayer firstLayer;
+    private final boolean global; // global settings vs. layer specific settings
+    private final boolean hasLocalFile; // flag to display LocalOnly checkbooks
+    private final boolean hasNonLocalFile; // flag to display AllLines checkbox
+
+    private final static Map<String, Object> DEFAULT_PREFS = getDefaultPrefs();
+
+    private static Map<String, Object> getDefaultPrefs() {
+        HashMap<String, Object> m = new HashMap<>();
+        m.put("colormode", -1);
+        m.put("colormode.dynamic-range", false);
+        m.put("colormode.heatmap.colormap", 0);
+        m.put("colormode.heatmap.gain", 0);
+        m.put("colormode.heatmap.line-extra", false); //Einstein only
+        m.put("colormode.heatmap.lower-limit", 0);
+        m.put("colormode.heatmap.use-points", false);
+        m.put("colormode.time.min-distance", 60); //Einstein only
+        m.put("colormode.velocity.tune", 45);
+        m.put("lines", -1);
+        m.put("lines.alpha-blend", false);
+        m.put("lines.arrows", false);
+        m.put("lines.arrows.fast", false);
+        m.put("lines.arrows.min-distance", 40);
+        m.put("lines.force", false);
+        m.put("lines.max-length", 200);
+        m.put("lines.max-length.local", -1);
+        m.put("lines.width", 0);
+        m.put("markers.color", "");
+        m.put("markers.show-text", true);
+        m.put("markers.pattern", Marker.LABEL_PATTERN_AUTO);
+        m.put("markers.audio.pattern", "?{ '{name}' | '{desc}' | '{" + Marker.MARKER_FORMATTED_OFFSET + "}' }");
+        m.put("points.hdopcircle", false);
+        m.put("points.large", false);
+        m.put("points.large.alpha", -1); //Einstein only
+        m.put("points.large.size", 3); //Einstein only
+        return Collections.unmodifiableMap(m);
+    }
+
+    /**
+     * Constructs a new {@code GPXSettingsPanel} for the given layers.
+     * @param layers the GPX layers
+     */
+    public GPXSettingsPanel(List<GpxLayer> layers) {
         super(new GridBagLayout());
-        this.local = local;
-        this.nonlocal = nonlocal;
-        this.layerName = "layer "+layerName;
+        this.layers = layers;
+        if (layers == null || layers.isEmpty()) {
+            throw new InvalidArgumentException("At least one layer required");
+        }
+        firstLayer = layers.get(0);
+        global = false;
+        hasLocalFile = layers.stream().anyMatch(GpxLayer::isLocalFile);
+        hasNonLocalFile = layers.stream().anyMatch(l -> !l.isLocalFile());
         initComponents();
         loadPreferences();
@@ -118,8 +160,137 @@
     public GPXSettingsPanel() {
         super(new GridBagLayout());
+        layers = null;
+        firstLayer = null;
+        global = hasLocalFile = hasNonLocalFile = true;
         initComponents();
-        local = false;
-        nonlocal = false;
         loadPreferences(); // preferences -> controls
+    }
+
+    /**
+     * Reads the preference for the given layer or the default preference if not available
+     * @param layer the GpxLayer. Can be <code>null</code>, default preference will be returned then
+     * @param key the drawing key to be read, without "draw.rawgps."
+     * @return the value
+     */
+    public static String getLayerPref(GpxLayer layer, String key) {
+        Object d = DEFAULT_PREFS.get(key);
+        String ds;
+        if (d != null) {
+            ds = d.toString();
+        } else {
+            Logging.warn("No default value found for layer preference \"" + key + "\".");
+            ds = null;
+        }
+        return Optional.ofNullable(tryGetLayerPrefLocal(layer, key)).orElse(Config.getPref().get("draw.rawgps." + key, ds));
+    }
+
+    /**
+     * Reads the integer preference for the given layer or the default preference if not available
+     * @param layer the GpxLayer. Can be <code>null</code>, default preference will be returned then
+     * @param key the drawing key to be read, without "draw.rawgps."
+     * @return the integer value
+     */
+    public static int getLayerPrefInt(GpxLayer layer, String key) {
+        String s = getLayerPref(layer, key);
+        if (s != null) {
+            try {
+                return Integer.parseInt(s);
+            } catch (NumberFormatException ex) {
+                Object d = DEFAULT_PREFS.get(key);
+                if (d instanceof Integer) {
+                    return (int) d;
+                } else {
+                    Logging.warn("No valid default value found for layer preference \"" + key + "\".");
+                }
+            }
+        }
+        return 0;
+    }
+
+    /**
+     * Try to read the preference for the given layer
+     * @param layer the GpxLayer
+     * @param key the drawing key to be read, without "draw.rawgps."
+     * @return the value or <code>null</code> if not found
+     */
+    public static String tryGetLayerPrefLocal(GpxLayer layer, String key) {
+        return layer != null ? tryGetLayerPrefLocal(layer.data, key) : null;
+    }
+
+    /**
+     * Try to read the preference for the given GpxData
+     * @param data the GpxData
+     * @param key the drawing key to be read, without "draw.rawgps."
+     * @return the value or <code>null</code> if not found
+     */
+    public static String tryGetLayerPrefLocal(GpxData data, String key) {
+        return data != null ? data.getLayerPrefs().get(key) : null;
+    }
+
+    /**
+     * Puts the preference for the given layers or the default preference if layers is <code>null</code>
+     * @param layers List of <code>GpxLayer</code> to put the drawingOptions
+     * @param key the drawing key to be written, without "draw.rawgps."
+     * @param value (can be <code>null</code> to remove option)
+     */
+    public static void putLayerPref(List<GpxLayer> layers, String key, Object value) {
+        String v = value == null ? null : value.toString();
+        if (layers != null) {
+            for (GpxLayer l : layers) {
+                putLayerPrefLocal(l.data, key, v);
+            }
+        } else {
+            Config.getPref().put("draw.rawgps." + key, v);
+        }
+    }
+
+    /**
+     * Puts the preference for the given layer
+     * @param layer <code>GpxLayer</code> to put the drawingOptions
+     * @param key the drawing key to be written, without "draw.rawgps."
+     * @param value the value or <code>null</code> to remove key
+     */
+    public static void putLayerPrefLocal(GpxLayer layer, String key, String value) {
+        if (layer == null) return;
+        putLayerPrefLocal(layer.data, key, value);
+    }
+
+    /**
+     * Puts the preference for the given layer
+     * @param data <code>GpxData</code> to put the drawingOptions. Must not be <code>null</code>
+     * @param key the drawing key to be written, without "draw.rawgps."
+     * @param value the value or <code>null</code> to remove key
+     */
+    public static void putLayerPrefLocal(GpxData data, String key, String value) {
+        if (value == null || value.trim().isEmpty() || (getLayerPref(null, key).equals(value) && DEFAULT_PREFS.get(key) != null && DEFAULT_PREFS.get(key).toString().equals(value))) {
+            data.getLayerPrefs().remove(key);
+        } else {
+            data.getLayerPrefs().put(key, value);
+        }
+    }
+
+    private String pref(String key) {
+        return getLayerPref(firstLayer, key);
+    }
+
+    private boolean prefBool(String key) {
+        return Boolean.parseBoolean(pref(key));
+    }
+
+    private int prefInt(String key) {
+        return getLayerPrefInt(firstLayer, key);
+    }
+
+    private int prefIntLocal(String key) {
+        try {
+            return Integer.parseInt(tryGetLayerPrefLocal(firstLayer, key));
+        } catch (NumberFormatException ex) {
+            return -1;
+        }
+
+    }
+
+    private void putPref(String key, Object value) {
+        putLayerPref(layers, key, value);
     }
 
@@ -128,12 +299,14 @@
         setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
 
-        // makeAutoMarkers
-        makeAutoMarkers.setToolTipText(tr("Automatically make a marker layer from any waypoints when opening a GPX layer."));
-        ExpertToggleAction.addVisibilitySwitcher(makeAutoMarkers);
-        add(makeAutoMarkers, GBC.eol().insets(20, 0, 0, 5));
+        if (global) {
+            // makeAutoMarkers
+            makeAutoMarkers.setToolTipText(tr("Automatically make a marker layer from any waypoints when opening a GPX layer."));
+            ExpertToggleAction.addVisibilitySwitcher(makeAutoMarkers);
+            add(makeAutoMarkers, GBC.eol().insets(20, 0, 0, 5));
+        }
 
         // drawRawGpsLines
         ButtonGroup gpsLinesGroup = new ButtonGroup();
-        if (layerName != null) {
+        if (!global) {
             gpsLinesGroup.add(drawRawGpsLinesGlobal);
         }
@@ -146,12 +319,12 @@
         JLabel label = new JLabel(tr("Draw lines between raw GPS points"));
         add(label, GBC.eol().insets(20, 0, 0, 0));
-        if (layerName != null) {
+        if (!global) {
             add(drawRawGpsLinesGlobal, GBC.eol().insets(40, 0, 0, 0));
         }
         add(drawRawGpsLinesNone, GBC.eol().insets(40, 0, 0, 0));
-        if (layerName == null || local) {
+        if (hasLocalFile) {
             add(drawRawGpsLinesLocal, GBC.eol().insets(40, 0, 0, 0));
         }
-        if (layerName == null || nonlocal) {
+        if (hasNonLocalFile) {
             add(drawRawGpsLinesAll, GBC.eol().insets(40, 0, 0, 0));
         }
@@ -243,5 +416,5 @@
         // colorTracks
         ButtonGroup colorGroup = new ButtonGroup();
-        if (layerName != null) {
+        if (!global) {
             colorGroup.add(colorTypeGlobal);
         }
@@ -254,5 +427,5 @@
         colorGroup.add(colorTypeHeatMap);
 
-        colorTypeNone.setToolTipText(tr("All points and track segments will have the same color. Can be customized in Layer Manager."));
+        colorTypeNone.setToolTipText(tr("All points and track segments will have their own color. Can be customized in Layer Manager."));
         colorTypeVelocity.setToolTipText(tr("Colors points and track segments by velocity."));
         colorTypeDirection.setToolTipText(tr("Colors points and track segments by direction."));
@@ -273,5 +446,5 @@
 
         add(new JLabel(tr("Track and Point Coloring")), GBC.eol().insets(20, 0, 0, 0));
-        if (layerName != null) {
+        if (!global) {
             add(colorTypeGlobal, GBC.eol().insets(40, 0, 0, 0));
         }
@@ -332,13 +505,8 @@
                 // get image size of environment
                 final int iconSize = (int) dim.getHeight();
-                final Color color;
-                // ask the GPX draw for the correct color of that layer ( if there is one )
-                if (null != layerName) {
-                    color = GpxDrawHelper.DEFAULT_COLOR.getChildColor(
-                            NamedColorProperty.COLOR_CATEGORY_LAYER, layerName, GpxDrawHelper.DEFAULT_COLOR.getName()).get();
-                } else {
-                    color = GpxDrawHelper.DEFAULT_COLOR.getDefaultValue();
-                }
-                colorTypeHeatIconLabel.setIcon(GpxDrawHelper.getColorMapImageIcon(color, colorTypeHeatMapTune.getSelectedIndex(), iconSize));
+                colorTypeHeatIconLabel.setIcon(GpxDrawHelper.getColorMapImageIcon(
+                        GpxDrawHelper.DEFAULT_COLOR_PROPERTY.get(),
+                        colorTypeHeatMapTune.getSelectedIndex(),
+                        iconSize));
             }
         });
@@ -354,5 +522,5 @@
         ExpertToggleAction.addVisibilitySwitcher(colorDynamic);
 
-        if (layerName == null) {
+        if (global) {
             // Setting waypoints for gpx layer doesn't make sense - waypoints are shown in marker layer that has different name - so show
             // this only for global config
@@ -364,5 +532,4 @@
             add(waypointLabel, GBC.eol().fill(GBC.HORIZONTAL).insets(5, 0, 0, 5));
             waypointLabel.addActionListener(e -> updateWaypointPattern(waypointLabel, waypointLabelPattern));
-            updateWaypointLabelCombobox(waypointLabel, waypointLabelPattern, TemplateEntryProperty.forMarker(layerName));
             add(waypointLabelPattern, GBC.eol().fill(GBC.HORIZONTAL).insets(20, 0, 0, 5));
             ExpertToggleAction.addVisibilitySwitcher(label);
@@ -380,5 +547,4 @@
             add(audioWaypointLabel, GBC.eol().fill(GBC.HORIZONTAL).insets(5, 0, 0, 5));
             audioWaypointLabel.addActionListener(e -> updateWaypointPattern(audioWaypointLabel, audioWaypointLabelPattern));
-            updateWaypointLabelCombobox(audioWaypointLabel, audioWaypointLabelPattern, TemplateEntryProperty.forAudioMarker(layerName));
             add(audioWaypointLabelPattern, GBC.eol().fill(GBC.HORIZONTAL).insets(20, 0, 0, 5));
             ExpertToggleAction.addVisibilitySwitcher(label);
@@ -396,44 +562,30 @@
     public final void loadPreferences() {
         makeAutoMarkers.setSelected(Config.getPref().getBoolean("marker.makeautomarkers", true));
-        if (layerName != null && Config.getPref().get("draw.rawgps.lines."+layerName).isEmpty()
-                && Config.getPref().get("draw.rawgps.lines.local."+layerName).isEmpty()) {
-            // no line preferences for layer is found
+        int lines = global ? prefInt("lines") : prefIntLocal("lines");
+        if (lines == 2 && hasNonLocalFile) {
+            drawRawGpsLinesAll.setSelected(true);
+        } else if ((lines == 1 && hasLocalFile) || (lines == -1 && global)) {
+            drawRawGpsLinesLocal.setSelected(true);
+        } else if (lines == 0) {
+            drawRawGpsLinesNone.setSelected(true);
+        } else if (lines == -1) {
             drawRawGpsLinesGlobal.setSelected(true);
         } else {
-            Boolean lf = PreferencesUtils.getBoolean(Config.getPref(), "draw.rawgps.lines.local", layerName, true);
-            if (PreferencesUtils.getBoolean(Config.getPref(), "draw.rawgps.lines", layerName, true)) {
-                drawRawGpsLinesAll.setSelected(true);
-            } else if (lf) {
-                drawRawGpsLinesLocal.setSelected(true);
-            } else {
-                drawRawGpsLinesNone.setSelected(true);
-            }
-        }
-
-        drawRawGpsMaxLineLengthLocal.setText(Integer.toString(PreferencesUtils.getInteger(Config.getPref(),
-                "draw.rawgps.max-line-length.local", layerName, -1)));
-        drawRawGpsMaxLineLength.setText(Integer.toString(PreferencesUtils.getInteger(Config.getPref(),
-                "draw.rawgps.max-line-length", layerName, 200)));
-        drawLineWidth.setText(Integer.toString(PreferencesUtils.getInteger(Config.getPref(),
-                "draw.rawgps.linewidth", layerName, 0)));
-        drawLineWithAlpha.setSelected(PreferencesUtils.getBoolean(Config.getPref(),
-                "draw.rawgps.lines.alpha-blend", layerName, false));
-        forceRawGpsLines.setSelected(PreferencesUtils.getBoolean(Config.getPref(),
-                "draw.rawgps.lines.force", layerName, false));
-        drawGpsArrows.setSelected(PreferencesUtils.getBoolean(Config.getPref(),
-                "draw.rawgps.direction", layerName, false));
-        drawGpsArrowsFast.setSelected(PreferencesUtils.getBoolean(Config.getPref(),
-                "draw.rawgps.alternatedirection", layerName, false));
-        drawGpsArrowsMinDist.setText(Integer.toString(PreferencesUtils.getInteger(Config.getPref(),
-                "draw.rawgps.min-arrow-distance", layerName, 40)));
-        hdopCircleGpsPoints.setSelected(PreferencesUtils.getBoolean(Config.getPref(),
-                "draw.rawgps.hdopcircle", layerName, false));
-        largeGpsPoints.setSelected(PreferencesUtils.getBoolean(Config.getPref(),
-                "draw.rawgps.large", layerName, false));
+            Logging.warn("Unknown line type: " + lines);
+        }
+        drawRawGpsMaxLineLengthLocal.setText(pref("lines.max-length.local"));
+        drawRawGpsMaxLineLength.setText(pref("lines.max-length"));
+        drawLineWidth.setText(pref("lines.width"));
+        drawLineWithAlpha.setSelected(prefBool("lines.alpha-blend"));
+        forceRawGpsLines.setSelected(prefBool("lines.force"));
+        drawGpsArrows.setSelected(prefBool("lines.arrows"));
+        drawGpsArrowsFast.setSelected(prefBool("lines.arrows.fast"));
+        drawGpsArrowsMinDist.setText(pref("lines.arrows.min-distance"));
+        hdopCircleGpsPoints.setSelected(prefBool("points.hdopcircle"));
+        largeGpsPoints.setSelected(prefBool("points.large"));
         useGpsAntialiasing.setSelected(Config.getPref().getBoolean("mappaint.gpx.use-antialiasing", false));
 
         drawRawGpsLinesActionListener.actionPerformed(null);
-
-        if (layerName != null && Config.getPref().get("draw.rawgps.colors."+layerName).isEmpty()) {
+        if (!global && prefIntLocal("colormode") == -1) {
             colorTypeGlobal.setSelected(true);
             colorDynamic.setSelected(false);
@@ -443,7 +595,7 @@
             colorTypeHeatMapLowerLimit.setValue(0);
         } else {
-            int colorType = PreferencesUtils.getInteger(Config.getPref(), "draw.rawgps.colors", layerName, 0);
+            int colorType = prefInt("colormode");
             switch (colorType) {
-            case 0: colorTypeNone.setSelected(true); break;
+            case -1: case 0: colorTypeNone.setSelected(true); break;
             case 1: colorTypeVelocity.setSelected(true); break;
             case 2: colorTypeDilution.setSelected(true); break;
@@ -454,108 +606,97 @@
             default: Logging.warn("Unknown color type: " + colorType);
             }
-            int ccts = PreferencesUtils.getInteger(Config.getPref(), "draw.rawgps.colorTracksTune", layerName, 45);
+            int ccts = prefInt("colormode.velocity.tune");
             colorTypeVelocityTune.setSelectedIndex(ccts == 10 ? 2 : (ccts == 20 ? 1 : 0));
-            colorTypeHeatMapTune.setSelectedIndex(PreferencesUtils.getInteger(Config.getPref(),
-                    "draw.rawgps.heatmap.colormap", layerName, 0));
-            colorDynamic.setSelected(PreferencesUtils.getBoolean(Config.getPref(),
-                    "draw.rawgps.colors.dynamic", layerName, false));
-            colorTypeHeatMapPoints.setSelected(PreferencesUtils.getBoolean(Config.getPref(),
-                    "draw.rawgps.heatmap.use-points", layerName, false));
-            colorTypeHeatMapGain.setValue(PreferencesUtils.getInteger(Config.getPref(),
-                    "draw.rawgps.heatmap.gain", layerName, 0));
-            colorTypeHeatMapLowerLimit.setValue(PreferencesUtils.getInteger(Config.getPref(),
-                    "draw.rawgps.heatmap.lower-limit", layerName, 0));
-        }
-    }
-
-    /**
-     * Save preferences from UI controls, globally or for a specified layer.
-     * @param layerName The GPX layer name. Can be {@code null}, in that case, global preferences are written
-     * @param locLayer {@code true} if the GPX layer is a local one. Ignored if {@code layerName} is null
+            colorTypeHeatMapTune.setSelectedIndex(prefInt("colormode.heatmap.colormap"));
+            colorDynamic.setSelected(prefBool("colormode.dynamic-range"));
+            colorTypeHeatMapPoints.setSelected(prefBool("colormode.heatmap.use-points"));
+            colorTypeHeatMapGain.setValue(prefInt("colormode.heatmap.gain"));
+            colorTypeHeatMapLowerLimit.setValue(prefInt("colormode.heatmap.lower-limit"));
+        }
+        updateWaypointLabelCombobox(waypointLabel, waypointLabelPattern, pref("markers.pattern"));
+        updateWaypointLabelCombobox(audioWaypointLabel, audioWaypointLabelPattern, pref("markers.audio.pattern"));
+
+    }
+
+    /**
+     * Save preferences from UI controls, globally or for the specified layers.
      * @return {@code true} when restart is required, {@code false} otherwise
      */
-    public boolean savePreferences(String layerName, boolean locLayer) {
-        String layerNameDot = ".layer "+layerName;
-        if (layerName == null) {
-            layerNameDot = "";
-        }
-        Config.getPref().putBoolean("marker.makeautomarkers"+layerNameDot, makeAutoMarkers.isSelected());
-        if (drawRawGpsLinesGlobal.isSelected()) {
-            Config.getPref().put("draw.rawgps.lines" + layerNameDot, null);
-            Config.getPref().put("draw.rawgps.max-line-length" + layerNameDot, null);
-            Config.getPref().put("draw.rawgps.lines.local" + layerNameDot, null);
-            Config.getPref().put("draw.rawgps.max-line-length.local" + layerNameDot, null);
-            Config.getPref().put("draw.rawgps.lines.force"+layerNameDot, null);
-            Config.getPref().put("draw.rawgps.direction"+layerNameDot, null);
-            Config.getPref().put("draw.rawgps.alternatedirection"+layerNameDot, null);
-            Config.getPref().put("draw.rawgps.min-arrow-distance"+layerNameDot, null);
+    public boolean savePreferences() {
+        if (global) {
+            Config.getPref().putBoolean("marker.makeautomarkers", makeAutoMarkers.isSelected());
+            putPref("markers.pattern", waypointLabelPattern.getText());
+            putPref("markers.audio.pattern", audioWaypointLabelPattern.getText());
+        }
+        boolean g;
+        if (!global && ((g = drawRawGpsLinesGlobal.isSelected()) || drawRawGpsLinesNone.isSelected())) {
+            if (g) {
+                putPref("lines", null);
+            } else {
+                putPref("lines", 0);
+            }
+            putPref("lines.max-length", null);
+            putPref("lines.max-length.local", null);
+            putPref("lines.force", null);
+            putPref("lines.arrows", null);
+            putPref("lines.arrows.fast", null);
+            putPref("lines.arrows.min-distance", null);
         } else {
-            if (layerName == null || !locLayer) {
-                Config.getPref().putBoolean("draw.rawgps.lines" + layerNameDot, drawRawGpsLinesAll.isSelected());
-                Config.getPref().put("draw.rawgps.max-line-length" + layerNameDot, drawRawGpsMaxLineLength.getText());
+            if (drawRawGpsLinesLocal.isSelected()) {
+                putPref("lines", 1);
+            } else if (drawRawGpsLinesAll.isSelected()) {
+                putPref("lines", 2);
             }
-            if (layerName == null || locLayer) {
-                Config.getPref().putBoolean("draw.rawgps.lines.local" + layerNameDot,
-                        drawRawGpsLinesAll.isSelected() || drawRawGpsLinesLocal.isSelected());
-                Config.getPref().put("draw.rawgps.max-line-length.local" + layerNameDot,
-                        drawRawGpsMaxLineLengthLocal.getText());
-            }
-            Config.getPref().putBoolean("draw.rawgps.lines.force"+layerNameDot, forceRawGpsLines.isSelected());
-            Config.getPref().putBoolean("draw.rawgps.direction"+layerNameDot, drawGpsArrows.isSelected());
-            Config.getPref().putBoolean("draw.rawgps.alternatedirection"+layerNameDot, drawGpsArrowsFast.isSelected());
-            Config.getPref().put("draw.rawgps.min-arrow-distance"+layerNameDot, drawGpsArrowsMinDist.getText());
-        }
-
-        Config.getPref().putBoolean("draw.rawgps.hdopcircle"+layerNameDot, hdopCircleGpsPoints.isSelected());
-        Config.getPref().putBoolean("draw.rawgps.large"+layerNameDot, largeGpsPoints.isSelected());
-        Config.getPref().put("draw.rawgps.linewidth"+layerNameDot, drawLineWidth.getText());
-        Config.getPref().putBoolean("draw.rawgps.lines.alpha-blend"+layerNameDot, drawLineWithAlpha.isSelected());
+            putPref("lines.max-length", drawRawGpsMaxLineLength.getText());
+            putPref("lines.max-length.local", drawRawGpsMaxLineLengthLocal.getText());
+            putPref("lines.force", forceRawGpsLines.isSelected());
+            putPref("lines.arrows", drawGpsArrows.isSelected());
+            putPref("lines.arrows.fast", drawGpsArrowsFast.isSelected());
+            putPref("lines.arrows.min-distance", drawGpsArrowsMinDist.getText());
+        }
+
+        putPref("points.hdopcircle", hdopCircleGpsPoints.isSelected());
+        putPref("points.large", largeGpsPoints.isSelected());
+        putPref("lines.width", drawLineWidth.getText());
+        putPref("lines.alpha-blend", drawLineWithAlpha.isSelected());
 
         Config.getPref().putBoolean("mappaint.gpx.use-antialiasing", useGpsAntialiasing.isSelected());
 
-        TemplateEntryProperty.forMarker(layerName).put(waypointLabelPattern.getText());
-        TemplateEntryProperty.forAudioMarker(layerName).put(audioWaypointLabelPattern.getText());
-
         if (colorTypeGlobal.isSelected()) {
-            Config.getPref().put("draw.rawgps.colors"+layerNameDot, null);
-            Config.getPref().put("draw.rawgps.colors.dynamic"+layerNameDot, null);
-            Config.getPref().put("draw.rawgps.colorTracksTunec"+layerNameDot, null);
+            putPref("colormode", null);
+            putPref("colormode.dynamic-range", null);
+            putPref("colormode.velocity.tune", null);
             return false;
         } else if (colorTypeVelocity.isSelected()) {
-            Config.getPref().putInt("draw.rawgps.colors"+layerNameDot, 1);
+            putPref("colormode", 1);
         } else if (colorTypeDilution.isSelected()) {
-            Config.getPref().putInt("draw.rawgps.colors"+layerNameDot, 2);
+            putPref("colormode", 2);
         } else if (colorTypeDirection.isSelected()) {
-            Config.getPref().putInt("draw.rawgps.colors"+layerNameDot, 3);
+            putPref("colormode", 3);
         } else if (colorTypeTime.isSelected()) {
-            Config.getPref().putInt("draw.rawgps.colors"+layerNameDot, 4);
+            putPref("colormode", 4);
         } else if (colorTypeHeatMap.isSelected()) {
-            Config.getPref().putInt("draw.rawgps.colors"+layerNameDot, 5);
+            putPref("colormode", 5);
         } else if (colorTypeQuality.isSelected()) {
-            Config.getPref().putInt("draw.rawgps.colors"+layerNameDot, 6);
+            putPref("colormode", 6);
         } else {
-            Config.getPref().putInt("draw.rawgps.colors"+layerNameDot, 0);
-        }
-        Config.getPref().putBoolean("draw.rawgps.colors.dynamic"+layerNameDot, colorDynamic.isSelected());
+            putPref("colormode", 0);
+        }
+        putPref("colormode.dynamic-range", colorDynamic.isSelected());
         int ccti = colorTypeVelocityTune.getSelectedIndex();
-        Config.getPref().putInt("draw.rawgps.colorTracksTune"+layerNameDot, ccti == 2 ? 10 : (ccti == 1 ? 20 : 45));
-        Config.getPref().putInt("draw.rawgps.heatmap.colormap"+layerNameDot, colorTypeHeatMapTune.getSelectedIndex());
-        Config.getPref().putBoolean("draw.rawgps.heatmap.use-points"+layerNameDot, colorTypeHeatMapPoints.isSelected());
-        Config.getPref().putInt("draw.rawgps.heatmap.gain"+layerNameDot, colorTypeHeatMapGain.getValue());
-        Config.getPref().putInt("draw.rawgps.heatmap.lower-limit"+layerNameDot, colorTypeHeatMapLowerLimit.getValue());
+        putPref("colormode.velocity.tune", ccti == 2 ? 10 : (ccti == 1 ? 20 : 45));
+        putPref("colormode.heatmap.colormap", colorTypeHeatMapTune.getSelectedIndex());
+        putPref("colormode.heatmap.use-points", colorTypeHeatMapPoints.isSelected());
+        putPref("colormode.heatmap.gain", colorTypeHeatMapGain.getValue());
+        putPref("colormode.heatmap.lower-limit", colorTypeHeatMapLowerLimit.getValue());
+
+        if (!global && layers != null && !layers.isEmpty()) {
+            layers.forEach(l -> l.data.invalidate());
+        }
 
         return false;
     }
 
-    /**
-     * Save preferences from UI controls for initial layer or globally
-     * @return {@code true} when restart is required, {@code false} otherwise
-     */
-    public boolean savePreferences() {
-        return savePreferences(null, false);
-    }
-
-    private static void updateWaypointLabelCombobox(JosmComboBox<String> cb, JosmTextField tf, TemplateEntryProperty property) {
-        String labelPattern = property.getAsString();
+    private static void updateWaypointLabelCombobox(JosmComboBox<String> cb, JosmTextField tf, String labelPattern) {
         boolean found = false;
         for (int i = 0; i < LABEL_PATTERN_TEMPLATE.length; i++) {
Index: /trunk/src/org/openstreetmap/josm/io/GpxReader.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/io/GpxReader.java	(revision 15495)
+++ /trunk/src/org/openstreetmap/josm/io/GpxReader.java	(revision 15496)
@@ -19,10 +19,13 @@
 import org.openstreetmap.josm.data.Bounds;
 import org.openstreetmap.josm.data.coor.LatLon;
-import org.openstreetmap.josm.data.gpx.Extensions;
 import org.openstreetmap.josm.data.gpx.GpxConstants;
 import org.openstreetmap.josm.data.gpx.GpxData;
+import org.openstreetmap.josm.data.gpx.GpxData.XMLNamespace;
+import org.openstreetmap.josm.data.gpx.GpxExtensionCollection;
 import org.openstreetmap.josm.data.gpx.GpxLink;
 import org.openstreetmap.josm.data.gpx.GpxRoute;
-import org.openstreetmap.josm.data.gpx.ImmutableGpxTrack;
+import org.openstreetmap.josm.data.gpx.GpxTrack;
+import org.openstreetmap.josm.data.gpx.GpxTrackSegment;
+import org.openstreetmap.josm.data.gpx.IGpxTrackSegment;
 import org.openstreetmap.josm.data.gpx.WayPoint;
 import org.openstreetmap.josm.tools.Logging;
@@ -68,5 +71,5 @@
 
         private GpxData data;
-        private Collection<Collection<WayPoint>> currentTrack;
+        private Collection<IGpxTrackSegment> currentTrack;
         private Map<String, Object> currentTrackAttr;
         private Collection<WayPoint> currentTrackSeg;
@@ -77,5 +80,6 @@
 
         private GpxLink currentLink;
-        private Extensions currentExtensions;
+        private GpxExtensionCollection currentExtensionCollection;
+        private GpxExtensionCollection currentTrackExtensionCollection;
         private Stack<State> states;
         private final Stack<String> elements = new Stack<>();
@@ -89,5 +93,12 @@
             accumulator = new StringBuilder();
             states = new Stack<>();
-            data = new GpxData();
+            data = new GpxData(true);
+            currentExtensionCollection = new GpxExtensionCollection();
+            currentTrackExtensionCollection = new GpxExtensionCollection();
+        }
+
+        @Override
+        public void startPrefixMapping(String prefix, String uri) throws SAXException {
+            data.getNamespaces().add(new XMLNamespace(prefix, uri));
         }
 
@@ -134,4 +145,15 @@
                     version = "1.1";
                 }
+                String schemaLocation = atts.getValue(GpxConstants.XML_URI_XSD, "schemaLocation");
+                if (schemaLocation != null) {
+                    String[] schemaLocations = schemaLocation.split(" ");
+                    for (int i = 0; i < schemaLocations.length - 1; i += 2) {
+                        final String schemaURI = schemaLocations[i];
+                        final String schemaXSD = schemaLocations[i + 1];
+                        data.getNamespaces().stream().filter(xml -> xml.getURI().equals(schemaURI)).forEach(xml -> {
+                            xml.setLocation(schemaXSD);
+                        });
+                    }
+                }
                 break;
             case GPX:
@@ -160,5 +182,4 @@
                     states.push(currentState);
                     currentState = State.EXT;
-                    currentExtensions = new Extensions();
                     break;
                 case "gpx":
@@ -179,5 +200,4 @@
                     states.push(currentState);
                     currentState = State.EXT;
-                    currentExtensions = new Extensions();
                     break;
                 case "copyright":
@@ -229,5 +249,4 @@
                     states.push(currentState);
                     currentState = State.EXT;
-                    currentExtensions = new Extensions();
                     break;
                 default: // Do nothing
@@ -235,8 +254,14 @@
                 break;
             case TRKSEG:
-                if ("trkpt".equals(localName)) {
+                switch (localName) {
+                case "trkpt":
                     states.push(currentState);
                     currentState = State.WPT;
                     currentWayPoint = new WayPoint(parseLatLon(atts));
+                    break;
+                case "extensions":
+                    states.push(currentState);
+                    currentState = State.EXT;
+                    break;
                 }
                 break;
@@ -251,5 +276,4 @@
                     states.push(currentState);
                     currentState = State.EXT;
-                    currentExtensions = new Extensions();
                     break;
                 default: // Do nothing
@@ -271,7 +295,13 @@
                     states.push(currentState);
                     currentState = State.EXT;
-                    currentExtensions = new Extensions();
-                    break;
-                default: // Do nothing
+                    break;
+                default: // Do nothing
+                }
+                break;
+            case EXT:
+                if (states.lastElement() == State.TRK) {
+                    currentTrackExtensionCollection.openChild(namespaceURI, qName, atts);
+                } else {
+                    currentExtensionCollection.openChild(namespaceURI, qName, atts);
                 }
                 break;
@@ -350,7 +380,6 @@
                         (currentState == State.GPX && "gpx".equals(localName))) {
                         convertUrlToLink(data.attr);
-                        if (currentExtensions != null && !currentExtensions.isEmpty()) {
-                            data.put(META_EXTENSIONS, currentExtensions);
-                        }
+                        data.getExtensions().addAll(currentExtensionCollection);
+                        currentExtensionCollection.clear();
                         currentState = states.pop();
                     }
@@ -360,5 +389,4 @@
                     break;
                 default:
-                    //TODO: parse extensions
                 }
                 break;
@@ -465,8 +493,7 @@
                     currentState = states.pop();
                     convertUrlToLink(currentWayPoint.attr);
-                    if (currentExtensions != null && !currentExtensions.isEmpty()) {
-                        currentWayPoint.put(META_EXTENSIONS, currentExtensions);
-                    }
+                    currentWayPoint.getExtensions().addAll(currentExtensionCollection);
                     data.waypoints.add(currentWayPoint);
+                    currentExtensionCollection.clear();
                     break;
                 default: // Do nothing
@@ -476,5 +503,10 @@
                 if ("trkseg".equals(localName)) {
                     currentState = states.pop();
-                    currentTrack.add(currentTrackSeg);
+                    if (!currentTrackSeg.isEmpty()) {
+                        GpxTrackSegment seg = new GpxTrackSegment(currentTrackSeg);
+                        seg.getExtensions().addAll(currentExtensionCollection);
+                        currentTrack.add(seg);
+                    }
+                    currentExtensionCollection.clear();
                 }
                 break;
@@ -484,5 +516,8 @@
                     currentState = states.pop();
                     convertUrlToLink(currentTrackAttr);
-                    data.addTrack(new ImmutableGpxTrack(currentTrack, currentTrackAttr));
+                    GpxTrack trk = new GpxTrack(new ArrayList<>(currentTrack), currentTrackAttr);
+                    trk.getExtensions().addAll(currentTrackExtensionCollection);
+                    data.addTrack(trk);
+                    currentTrackExtensionCollection.clear();
                     break;
                 case "name":
@@ -502,7 +537,11 @@
                 if ("extensions".equals(localName)) {
                     currentState = states.pop();
-                } else if (JOSM_EXTENSIONS_NAMESPACE_URI.equals(namespaceURI)) {
-                    // only interested in extensions written by JOSM
-                    currentExtensions.put(localName, accumulator.toString());
+                } else if (currentExtensionCollection != null) {
+                    String acc = accumulator.toString().trim();
+                    if (states.lastElement() == State.TRK) {
+                        currentTrackExtensionCollection.closeChild(qName, acc); //a segment inside the track can have an extension too
+                    } else {
+                        currentExtensionCollection.closeChild(qName, acc);
+                    }
                 }
                 break;
@@ -520,4 +559,5 @@
                 }
             }
+            accumulator.setLength(0);
         }
 
@@ -526,8 +566,19 @@
             if (!states.empty())
                 throw new SAXException(tr("Parse error: invalid document structure for GPX document."));
-            Extensions metaExt = (Extensions) data.get(META_EXTENSIONS);
-            if (metaExt != null && "true".equals(metaExt.get("from-server"))) {
-                data.fromServer = true;
-            }
+
+            data.getExtensions().stream("josm", "from-server").findAny().ifPresent(ext -> {
+                data.fromServer = "true".equals(ext.getValue());
+            });
+
+            data.getExtensions().stream("josm", "layerPreferences").forEach(prefs -> {
+                prefs.getExtensions().stream("josm", "entry").forEach(prefEntry -> {
+                    Object key = prefEntry.get("key");
+                    Object val = prefEntry.get("value");
+                    if (key != null && val != null) {
+                        data.getLayerPrefs().put(key.toString(), val.toString());
+                    }
+                });
+            });
+            data.endUpdate();
             gpxData = data;
         }
Index: /trunk/src/org/openstreetmap/josm/io/GpxWriter.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/io/GpxWriter.java	(revision 15495)
+++ /trunk/src/org/openstreetmap/josm/io/GpxWriter.java	(revision 15496)
@@ -9,9 +9,11 @@
 import java.io.PrintWriter;
 import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Date;
 import java.util.List;
 import java.util.Map;
-import java.util.Map.Entry;
+import java.util.Objects;
+import java.util.stream.Collectors;
 
 import javax.xml.XMLConstants;
@@ -19,11 +21,13 @@
 import org.openstreetmap.josm.data.Bounds;
 import org.openstreetmap.josm.data.coor.LatLon;
-import org.openstreetmap.josm.data.gpx.Extensions;
 import org.openstreetmap.josm.data.gpx.GpxConstants;
 import org.openstreetmap.josm.data.gpx.GpxData;
+import org.openstreetmap.josm.data.gpx.GpxData.XMLNamespace;
+import org.openstreetmap.josm.data.gpx.GpxExtension;
+import org.openstreetmap.josm.data.gpx.GpxExtensionCollection;
 import org.openstreetmap.josm.data.gpx.GpxLink;
 import org.openstreetmap.josm.data.gpx.GpxRoute;
 import org.openstreetmap.josm.data.gpx.GpxTrack;
-import org.openstreetmap.josm.data.gpx.GpxTrackSegment;
+import org.openstreetmap.josm.data.gpx.IGpxTrackSegment;
 import org.openstreetmap.josm.data.gpx.IWithAttributes;
 import org.openstreetmap.josm.data.gpx.WayPoint;
@@ -55,4 +59,5 @@
     private GpxData data;
     private String indent = "";
+    private List<String> validprefixes;
 
     private static final int WAY_POINT = 0;
@@ -65,27 +70,75 @@
      */
     public void write(GpxData data) {
+        write(data, ColorFormat.GPXD, true);
+    }
+
+    /**
+     * Writes the given GPX data.
+     *
+     * @param data The data to write
+     * @param colorFormat determines if colors are saved and which extension is to be used
+     * @param savePrefs whether layer specific preferences are saved
+     */
+    public void write(GpxData data, ColorFormat colorFormat, boolean savePrefs) {
         this.data = data;
-        // We write JOSM specific meta information into gpx 'extensions' elements.
-        // In particular it is noted whether the gpx data is from the OSM server
-        // (so the rendering of clouds of anonymous TrackPoints can be improved)
-        // and some extra synchronization info for export of AudioMarkers.
-        // It is checked in advance, if any extensions are used, so we know whether
-        // a namespace declaration is necessary.
-        boolean hasExtensions = data.fromServer;
-        if (!hasExtensions) {
-            for (WayPoint wpt : data.waypoints) {
-                Extensions extensions = (Extensions) wpt.get(META_EXTENSIONS);
-                if (extensions != null && !extensions.isEmpty()) {
-                    hasExtensions = true;
-                    break;
-                }
-            }
-        }
+
+        //Prepare extensions for writing
+        data.beginUpdate();
+        data.getTracks().forEach(trk -> trk.convertColor(colorFormat));
+        data.getExtensions().removeAllWithPrefix("josm");
+        if (data.fromServer) {
+            data.getExtensions().add("josm", "from-server", "true");
+        }
+        if (savePrefs && !data.getLayerPrefs().isEmpty()) {
+            GpxExtensionCollection layerExts = data.getExtensions().add("josm", "layerPreferences").getExtensions();
+            data.getLayerPrefs().entrySet()
+            .stream()
+            .sorted((e1, e2) -> e1.getKey().compareTo(e2.getKey()))
+            .forEach(entry -> {
+                GpxExtension e = layerExts.add("josm", "entry");
+                e.put("key", entry.getKey());
+                e.put("value", entry.getValue());
+            });
+        }
+        data.endUpdate();
+
+        Collection<IWithAttributes> all = new ArrayList<>();
+
+        all.add(data);
+        all.addAll(data.getWaypoints());
+        all.addAll(data.getRoutes());
+        all.addAll(data.getTracks());
+        all.addAll(data.getTrackSegmentsStream().collect(Collectors.toList()));
+
+        List<XMLNamespace> namespaces = all
+                .stream()
+                .flatMap(w -> w.getExtensions().getPrefixesStream())
+                .distinct()
+                .map(p -> data.getNamespaces()
+                        .stream()
+                        .filter(s -> s.getPrefix().equals(p))
+                        .findAny()
+                        .orElse(GpxExtension.findNamespace(p)))
+                .filter(Objects::nonNull)
+                .collect(Collectors.toList());
+
+        validprefixes = namespaces.stream().map(n -> n.getPrefix()).collect(Collectors.toList());
 
         out.println("<?xml version='1.0' encoding='UTF-8'?>");
         out.println("<gpx version=\"1.1\" creator=\"JOSM GPX export\" xmlns=\"http://www.topografix.com/GPX/1/1\"");
-        out.println((hasExtensions ? String.format("    xmlns:josm=\"%s\"%n", JOSM_EXTENSIONS_NAMESPACE_URI) : "") +
-                    "    xmlns:xsi=\""+XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI+"\"");
-        out.println("    xsi:schemaLocation=\"http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd\">");
+
+        String schemaLocations = "http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd";
+
+        for (XMLNamespace n : namespaces) {
+            if (n.getURI() != null && n.getPrefix() != null && !n.getPrefix().isEmpty()) {
+                out.println(String.format("    xmlns:%s=\"%s\"", n.getPrefix(), n.getURI()));
+                if (n.getLocation() != null) {
+                    schemaLocations += " " + n.getURI() + " " + n.getLocation();
+                }
+            }
+        }
+
+        out.println("    xmlns:xsi=\""+XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI+"\"");
+        out.println(String.format("    xsi:schemaLocation=\"%s\">", schemaLocations));
         indent = "  ";
         writeMetaData();
@@ -105,9 +158,4 @@
                         gpxLink(link);
                     }
-                }
-            } else if (META_EXTENSIONS.equals(key)) {
-                Extensions extensions = (Extensions) obj.get(key);
-                if (extensions != null) {
-                    gpxExtensions(extensions);
                 }
             } else {
@@ -148,5 +196,5 @@
                 String[] tmp = data.getString(META_AUTHOR_EMAIL).split("@");
                 if (tmp.length == 2) {
-                    inline("email", "id=\"" + tmp[0] + "\" domain=\""+tmp[1]+'\"');
+                    inline("email", "id=\"" + encode(tmp[0]) + "\" domain=\"" + encode(tmp[1]) +'\"');
                 }
             }
@@ -159,5 +207,5 @@
         if (attr.containsKey(META_COPYRIGHT_LICENSE)
                 || attr.containsKey(META_COPYRIGHT_YEAR)) {
-            openAtt("copyright", "author=\""+ data.get(META_COPYRIGHT_AUTHOR) +'\"');
+            openln("copyright", "author=\""+ encode(data.get(META_COPYRIGHT_AUTHOR).toString()) +'\"');
             if (attr.containsKey(META_COPYRIGHT_YEAR)) {
                 simpleTag("year", (String) data.get(META_COPYRIGHT_YEAR));
@@ -188,10 +236,5 @@
         }
 
-        if (data.fromServer) {
-            openln("extensions");
-            simpleTag("josm:from-server", "true");
-            closeln("extensions");
-        }
-
+        gpxExtensions(data.getExtensions());
         closeln("metadata");
     }
@@ -207,4 +250,5 @@
             openln("rte");
             writeAttr(rte, RTE_TRK_KEYS);
+            gpxExtensions(rte.getExtensions());
             for (WayPoint pnt : rte.routePoints) {
                 wayPoint(pnt, ROUTE_POINT);
@@ -218,6 +262,8 @@
             openln("trk");
             writeAttr(trk, RTE_TRK_KEYS);
-            for (GpxTrackSegment seg : trk.getSegments()) {
+            gpxExtensions(trk.getExtensions());
+            for (IGpxTrackSegment seg : trk.getSegments()) {
                 openln("trkseg");
+                gpxExtensions(seg.getExtensions());
                 for (WayPoint pnt : seg.getWayPoints()) {
                     wayPoint(pnt, TRACK_POINT);
@@ -234,4 +280,9 @@
     }
 
+    private void openln(String tag, String attributes) {
+        open(tag, attributes);
+        out.println();
+    }
+
     private void open(String tag) {
         out.print(indent + '<' + tag + '>');
@@ -239,11 +290,11 @@
     }
 
-    private void openAtt(String tag, String attributes) {
-        out.println(indent + '<' + tag + ' ' + attributes + '>');
+    private void open(String tag, String attributes) {
+        out.print(indent + '<' + tag + (attributes.isEmpty() ? "" : ' ') + attributes + '>');
         indent += "  ";
     }
 
     private void inline(String tag, String attributes) {
-        out.println(indent + '<' + tag + ' ' + attributes + "/>");
+        out.println(indent + '<' + tag + (attributes.isEmpty() ? "" : ' ') + attributes + "/>");
     }
 
@@ -273,4 +324,13 @@
     }
 
+    private void simpleTag(String tag, String content, String attributes) {
+        if (content != null && !content.isEmpty()) {
+            open(tag, attributes);
+            out.print(encode(content));
+            out.println("</" + tag + '>');
+            indent = indent.substring(2);
+        }
+    }
+
     /**
      * output link
@@ -279,5 +339,5 @@
     private void gpxLink(GpxLink link) {
         if (link != null) {
-            openAtt("link", "href=\"" + link.uri + '\"');
+            openln("link", "href=\"" + encode(link.uri) + '\"');
             simpleTag("text", link.text);
             simpleTag("type", link.type);
@@ -309,9 +369,10 @@
             LatLon c = pnt.getCoor();
             String coordAttr = "lat=\"" + c.lat() + "\" lon=\"" + c.lon() + '\"';
-            if (pnt.attr.isEmpty()) {
+            if (pnt.attr.isEmpty() && pnt.getExtensions().isEmpty()) {
                 inline(type, coordAttr);
             } else {
-                openAtt(type, coordAttr);
+                openln(type, coordAttr);
                 writeAttr(pnt, WPT_KEYS);
+                gpxExtensions(pnt.getExtensions());
                 closeln(type);
             }
@@ -319,12 +380,33 @@
     }
 
-    private void gpxExtensions(Extensions extensions) {
-        if (extensions != null && !extensions.isEmpty()) {
+    private void gpxExtensions(GpxExtensionCollection allExtensions) {
+        if (allExtensions.isVisible()) {
             openln("extensions");
-            for (Entry<String, String> e : extensions.entrySet()) {
-                simpleTag("josm:" + e.getKey(), e.getValue());
-            }
+            writeExtension(allExtensions);
             closeln("extensions");
         }
     }
+
+    private void writeExtension(List<GpxExtension> extensions) {
+        for (GpxExtension e : extensions) {
+            if (validprefixes.contains(e.getPrefix()) && e.isVisible()) {
+                // this might lead to loss of an unknown extension *after* the file was saved as .osm,
+                // but otherwise the file is invalid and can't even be parsed by SAX anymore
+                String k = (e.getPrefix().isEmpty() ? "" : e.getPrefix() + ":") + e.getKey();
+                String attr = String.join(" ", e.getAttributes().entrySet().stream().map(a -> encode(a.getKey()) + "=\"" + encode(a.getValue().toString()) + "\"").sorted().collect(Collectors.toList()));
+                if (e.getValue() == null && e.getExtensions().isEmpty()) {
+                    inline(k, attr);
+                } else if (e.getExtensions().isEmpty()) {
+                    simpleTag(k, e.getValue(), attr);
+                } else {
+                    openln(k, attr);
+                    if (e.getValue() != null) {
+                        out.print(encode(e.getValue()));
+                    }
+                    writeExtension(e.getExtensions());
+                    closeln(k);
+                }
+            }
+        }
+    }
 }
Index: /trunk/src/org/openstreetmap/josm/io/nmea/NmeaReader.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/io/nmea/NmeaReader.java	(revision 15495)
+++ /trunk/src/org/openstreetmap/josm/io/nmea/NmeaReader.java	(revision 15496)
@@ -21,5 +21,5 @@
 import org.openstreetmap.josm.data.gpx.GpxConstants;
 import org.openstreetmap.josm.data.gpx.GpxData;
-import org.openstreetmap.josm.data.gpx.ImmutableGpxTrack;
+import org.openstreetmap.josm.data.gpx.GpxTrack;
 import org.openstreetmap.josm.data.gpx.WayPoint;
 import org.openstreetmap.josm.io.IGpxReader;
@@ -265,5 +265,5 @@
             }
             currentTrack.add(ps.waypoints);
-            data.tracks.add(new ImmutableGpxTrack(currentTrack, Collections.<String, Object>emptyMap()));
+            data.tracks.add(new GpxTrack(currentTrack, Collections.<String, Object>emptyMap()));
 
         } catch (IllegalDataException e) {
Index: /trunk/src/org/openstreetmap/josm/io/rtklib/RtkLibPosReader.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/io/rtklib/RtkLibPosReader.java	(revision 15495)
+++ /trunk/src/org/openstreetmap/josm/io/rtklib/RtkLibPosReader.java	(revision 15496)
@@ -19,5 +19,5 @@
 import org.openstreetmap.josm.data.gpx.GpxConstants;
 import org.openstreetmap.josm.data.gpx.GpxData;
-import org.openstreetmap.josm.data.gpx.ImmutableGpxTrack;
+import org.openstreetmap.josm.data.gpx.GpxTrack;
 import org.openstreetmap.josm.data.gpx.WayPoint;
 import org.openstreetmap.josm.io.IGpxReader;
@@ -115,5 +115,5 @@
         }
         currentTrack.add(waypoints);
-        data.tracks.add(new ImmutableGpxTrack(currentTrack, Collections.<String, Object>emptyMap()));
+        data.tracks.add(new GpxTrack(currentTrack, Collections.<String, Object>emptyMap()));
         return true;
     }
Index: /trunk/src/org/openstreetmap/josm/io/session/GenericSessionExporter.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/io/session/GenericSessionExporter.java	(revision 15495)
+++ /trunk/src/org/openstreetmap/josm/io/session/GenericSessionExporter.java	(revision 15496)
@@ -82,5 +82,5 @@
         @Override
         public void actionPerformed(ActionEvent e) {
-            SaveAction.getInstance().doSave(layer);
+            SaveAction.getInstance().doSave(layer, true);
             updateEnabledState();
         }
Index: /trunk/test/data/tracks/tracks-extensions.gpx
===================================================================
--- /trunk/test/data/tracks/tracks-extensions.gpx	(revision 15496)
+++ /trunk/test/data/tracks/tracks-extensions.gpx	(revision 15496)
@@ -0,0 +1,1378 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<gpx version="1.1" creator="JOSM GPX export" xmlns="http://www.topografix.com/GPX/1/1"
+    xmlns:josm="http://josm.openstreetmap.de/gpx-extensions-1.1"
+    xmlns:gpxd="http://josm.openstreetmap.de/gpx-drawing-extensions-1.0"
+    xmlns:gpxx="http://www.garmin.com/xmlschemas/GpxExtensions/v3"
+    xmlns:test="TestExtensionNamespace"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd http://josm.openstreetmap.de/gpx-extensions-1.1 http://josm.openstreetmap.de/gpx-extensions-1.1.xsd http://josm.openstreetmap.de/gpx-drawing-extensions-1.0 http://josm.openstreetmap.de/gpx-drawing-extensions-1.0.xsd http://www.garmin.com/xmlschemas/GpxExtensions/v3 http://www.garmin.com/xmlschemas/GpxExtensionsv3.xsd TestExtensionNamespace http://example.com">
+  <metadata>
+    <bounds minlat="47.1849004" minlon="8.7719297" maxlat="47.2014997" maxlon="8.7984188"/>
+    <extensions>
+      <josm:layerPreferences>
+        <josm:entry key="colors" value="0"/>
+      </josm:layerPreferences>
+    </extensions>
+  </metadata>
+  <trk>
+    <extensions>
+      <test:tag>Track extension</test:tag>
+      <gpxx:TrackExtensions>
+        <gpxx:DisplayColor>Red</gpxx:DisplayColor>
+      </gpxx:TrackExtensions>
+    </extensions>
+    <trkseg>
+      <extensions>
+        <test:tag>Segment extension</test:tag>
+      </extensions>
+      <trkpt lat="47.19286847859621" lon="8.79732714034617">
+        <ele>471.86000000000001</ele>
+        <time>2016-01-03T11:59:58Z</time>
+      </trkpt>
+      <trkpt lat="47.192921955138445" lon="8.797342479228973">
+        <ele>471.43000000000001</ele>
+        <time>2016-01-03T11:59:59Z</time>
+      </trkpt>
+      <trkpt lat="47.19297501258552" lon="8.79734423942864">
+        <ele>470.69</ele>
+        <time>2016-01-03T12:00:00Z</time>
+      </trkpt>
+      <trkpt lat="47.19302739948034" lon="8.797332588583231">
+        <ele>470.94</ele>
+        <time>2016-01-03T12:00:01Z</time>
+      </trkpt>
+      <trkpt lat="47.193073416128755" lon="8.797307442873716">
+        <ele>471.5</ele>
+        <time>2016-01-03T12:00:02Z</time>
+      </trkpt>
+      <trkpt lat="47.193113481625915" lon="8.797272993251681">
+        <ele>471.67000000000002</ele>
+        <time>2016-01-03T12:00:03Z</time>
+      </trkpt>
+      <trkpt lat="47.19313560985029" lon="8.797232424840331">
+        <ele>471.58999999999997</ele>
+        <time>2016-01-03T12:00:04Z</time>
+      </trkpt>
+      <trkpt lat="47.19333660788834" lon="8.796738646924496">
+        <ele>472.44999999999999</ele>
+        <time>2016-01-03T12:00:15Z</time>
+      </trkpt>
+      <trkpt lat="47.193504832684994" lon="8.796404711902142">
+        <ele>472.54000000000002</ele>
+        <time>2016-01-03T12:00:22Z</time>
+      </trkpt>
+      <trkpt lat="47.19353936612606" lon="8.79635970108211">
+        <ele>472.45999999999998</ele>
+        <time>2016-01-03T12:00:23Z</time>
+      </trkpt>
+      <trkpt lat="47.19381898641586" lon="8.796017384156585">
+        <ele>471.38</ele>
+        <time>2016-01-03T12:00:30Z</time>
+      </trkpt>
+      <trkpt lat="47.19386676326394" lon="8.795985281467438">
+        <ele>471.26999999999998</ele>
+        <time>2016-01-03T12:00:31Z</time>
+      </trkpt>
+      <trkpt lat="47.19391797669232" lon="8.795968098565936">
+        <ele>471.36000000000001</ele>
+        <time>2016-01-03T12:00:32Z</time>
+      </trkpt>
+      <trkpt lat="47.19474418088794" lon="8.795836586505175">
+        <ele>473.19999999999999</ele>
+        <time>2016-01-03T12:00:50Z</time>
+      </trkpt>
+      <trkpt lat="47.195586981251836" lon="8.795750420540571">
+        <ele>475.06</ele>
+        <time>2016-01-03T12:01:09Z</time>
+      </trkpt>
+      <trkpt lat="47.19563358463347" lon="8.795769028365612">
+        <ele>474.75</ele>
+        <time>2016-01-03T12:01:10Z</time>
+      </trkpt>
+      <trkpt lat="47.19567717052996" lon="8.795795682817698">
+        <ele>474.62</ele>
+        <time>2016-01-03T12:01:11Z</time>
+      </trkpt>
+      <trkpt lat="47.195715978741646" lon="8.79583046771586">
+        <ele>474.74000000000001</ele>
+        <time>2016-01-03T12:01:12Z</time>
+      </trkpt>
+      <trkpt lat="47.19575093127787" lon="8.79587598145008">
+        <ele>474.06</ele>
+        <time>2016-01-03T12:01:13Z</time>
+      </trkpt>
+      <trkpt lat="47.19578169286251" lon="8.795927111059427">
+        <ele>474</ele>
+        <time>2016-01-03T12:01:14Z</time>
+      </trkpt>
+      <trkpt lat="47.195808347314596" lon="8.795980839058757">
+        <ele>474.58999999999997</ele>
+        <time>2016-01-03T12:01:15Z</time>
+      </trkpt>
+      <trkpt lat="47.195833241567016" lon="8.796036075800657">
+        <ele>474.81999999999999</ele>
+        <time>2016-01-03T12:01:16Z</time>
+      </trkpt>
+      <trkpt lat="47.19628603197634" lon="8.797110635787249">
+        <ele>476.29000000000002</ele>
+        <time>2016-01-03T12:01:35Z</time>
+      </trkpt>
+      <trkpt lat="47.19658995978534" lon="8.797826115041971">
+        <ele>478.48000000000002</ele>
+        <time>2016-01-03T12:01:50Z</time>
+      </trkpt>
+      <trkpt lat="47.19703386537731" lon="8.798356018960476">
+        <ele>481.02999999999997</ele>
+        <time>2016-01-03T12:02:06Z</time>
+      </trkpt>
+      <trkpt lat="47.19723687507212" lon="8.79841879941523">
+        <ele>480</ele>
+        <time>2016-01-03T12:02:12Z</time>
+      </trkpt>
+      <trkpt lat="47.19727886840701" lon="8.79838845692575">
+        <ele>479.58999999999997</ele>
+        <time>2016-01-03T12:02:13Z</time>
+      </trkpt>
+      <trkpt lat="47.19731541350484" lon="8.798339758068323">
+        <ele>478.99000000000001</ele>
+        <time>2016-01-03T12:02:14Z</time>
+      </trkpt>
+      <trkpt lat="47.197333350777626" lon="8.798282761126757">
+        <ele>479.58999999999997</ele>
+        <time>2016-01-03T12:02:15Z</time>
+      </trkpt>
+      <trkpt lat="47.19734919257462" lon="8.798161642625928">
+        <ele>481.18000000000001</ele>
+        <time>2016-01-03T12:02:18Z</time>
+      </trkpt>
+      <trkpt lat="47.19734827056527" lon="8.798118894919753">
+        <ele>481.88</ele>
+        <time>2016-01-03T12:02:20Z</time>
+      </trkpt>
+      <trkpt lat="47.19730585813522" lon="8.79802887327969">
+        <ele>483.11000000000001</ele>
+        <time>2016-01-03T12:02:24Z</time>
+      </trkpt>
+      <trkpt lat="47.19727643765509" lon="8.79797455854714">
+        <ele>484.49000000000001</ele>
+        <time>2016-01-03T12:02:27Z</time>
+      </trkpt>
+      <trkpt lat="47.19720158725977" lon="8.797768447548151">
+        <ele>486.88</ele>
+        <time>2016-01-03T12:02:35Z</time>
+      </trkpt>
+      <trkpt lat="47.19708633609116" lon="8.79746401682496">
+        <ele>488.05000000000001</ele>
+        <time>2016-01-03T12:02:48Z</time>
+      </trkpt>
+      <trkpt lat="47.19707007519901" lon="8.79741758108139">
+        <ele>487.76999999999998</ele>
+        <time>2016-01-03T12:02:51Z</time>
+      </trkpt>
+      <trkpt lat="47.19702917151153" lon="8.797250529751182">
+        <ele>488.95999999999998</ele>
+        <time>2016-01-03T12:02:57Z</time>
+      </trkpt>
+      <trkpt lat="47.19699899666011" lon="8.797172158956528">
+        <ele>488.36000000000001</ele>
+        <time>2016-01-03T12:03:01Z</time>
+      </trkpt>
+      <trkpt lat="47.19691224396229" lon="8.796978034079075">
+        <ele>488.35000000000002</ele>
+        <time>2016-01-03T12:03:09Z</time>
+      </trkpt>
+      <trkpt lat="47.19690545462072" lon="8.796931263059378">
+        <ele>487.19</ele>
+        <time>2016-01-03T12:03:10Z</time>
+      </trkpt>
+      <trkpt lat="47.19690595753491" lon="8.796886671334505">
+        <ele>487.63999999999999</ele>
+        <time>2016-01-03T12:03:11Z</time>
+      </trkpt>
+      <trkpt lat="47.19690511934459" lon="8.796837385743856">
+        <ele>487.55000000000001</ele>
+        <time>2016-01-03T12:03:12Z</time>
+      </trkpt>
+      <trkpt lat="47.19690562225878" lon="8.796793716028333">
+        <ele>488.39999999999998</ele>
+        <time>2016-01-03T12:03:13Z</time>
+      </trkpt>
+      <trkpt lat="47.196887601166964" lon="8.796751135960221">
+        <ele>489.18000000000001</ele>
+        <time>2016-01-03T12:03:15Z</time>
+      </trkpt>
+      <trkpt lat="47.1968892775476" lon="8.796689361333847">
+        <ele>490.73000000000002</ele>
+        <time>2016-01-03T12:03:18Z</time>
+      </trkpt>
+      <trkpt lat="47.196868155151606" lon="8.79647453315556">
+        <ele>491.24000000000001</ele>
+        <time>2016-01-03T12:03:33Z</time>
+      </trkpt>
+      <trkpt lat="47.19686932861805" lon="8.796442430466413">
+        <ele>490.25</ele>
+        <time>2016-01-03T12:03:34Z</time>
+      </trkpt>
+      <trkpt lat="47.19686849042773" lon="8.796406639739871">
+        <ele>490.00999999999999</ele>
+        <time>2016-01-03T12:03:35Z</time>
+      </trkpt>
+      <trkpt lat="47.196873016655445" lon="8.796368166804314">
+        <ele>489.54000000000002</ele>
+        <time>2016-01-03T12:03:36Z</time>
+      </trkpt>
+      <trkpt lat="47.19687905162573" lon="8.796329610049725">
+        <ele>489.66000000000003</ele>
+        <time>2016-01-03T12:03:37Z</time>
+      </trkpt>
+      <trkpt lat="47.196886762976646" lon="8.796280743554235">
+        <ele>489.06</ele>
+        <time>2016-01-03T12:03:38Z</time>
+      </trkpt>
+      <trkpt lat="47.19695775769651" lon="8.795829126611352">
+        <ele>490.08999999999997</ele>
+        <time>2016-01-03T12:03:48Z</time>
+      </trkpt>
+      <trkpt lat="47.1969928778708" lon="8.795709516853094">
+        <ele>489.41000000000003</ele>
+        <time>2016-01-03T12:03:52Z</time>
+      </trkpt>
+      <trkpt lat="47.19698550179601" lon="8.795667607337236">
+        <ele>489.17000000000002</ele>
+        <time>2016-01-03T12:03:53Z</time>
+      </trkpt>
+      <trkpt lat="47.19697644934058" lon="8.795624608173966">
+        <ele>488.87</ele>
+        <time>2016-01-03T12:03:54Z</time>
+      </trkpt>
+      <trkpt lat="47.19696890562773" lon="8.795590326189995">
+        <ele>489.37</ele>
+        <time>2016-01-03T12:03:55Z</time>
+      </trkpt>
+      <trkpt lat="47.19696664251387" lon="8.795558391138911">
+        <ele>488.94999999999999</ele>
+        <time>2016-01-03T12:03:56Z</time>
+      </trkpt>
+      <trkpt lat="47.19695256091654" lon="8.795536765828729">
+        <ele>488.93000000000001</ele>
+        <time>2016-01-03T12:03:57Z</time>
+      </trkpt>
+      <trkpt lat="47.196956500411034" lon="8.795507680624723">
+        <ele>488.88999999999999</ele>
+        <time>2016-01-03T12:03:58Z</time>
+      </trkpt>
+      <trkpt lat="47.19695859588683" lon="8.79548110999167">
+        <ele>488.86000000000001</ele>
+        <time>2016-01-03T12:03:59Z</time>
+      </trkpt>
+      <trkpt lat="47.19696907326579" lon="8.795452527701855">
+        <ele>489.19999999999999</ele>
+        <time>2016-01-03T12:04:00Z</time>
+      </trkpt>
+      <trkpt lat="47.19697988592088" lon="8.79541271366179">
+        <ele>489.29000000000002</ele>
+        <time>2016-01-03T12:04:01Z</time>
+      </trkpt>
+      <trkpt lat="47.19698726199567" lon="8.795355297625065">
+        <ele>488.95999999999998</ele>
+        <time>2016-01-03T12:04:02Z</time>
+      </trkpt>
+      <trkpt lat="47.19698960892856" lon="8.795302575454116">
+        <ele>489.10000000000002</ele>
+        <time>2016-01-03T12:04:03Z</time>
+      </trkpt>
+      <trkpt lat="47.19690981321037" lon="8.79494265653193">
+        <ele>492.19</ele>
+        <time>2016-01-03T12:04:14Z</time>
+      </trkpt>
+      <trkpt lat="47.19696622341871" lon="8.794532027095556">
+        <ele>492.12</ele>
+        <time>2016-01-03T12:04:25Z</time>
+      </trkpt>
+      <trkpt lat="47.19697737134993" lon="8.79450285807252">
+        <ele>493.06999999999999</ele>
+        <time>2016-01-03T12:04:26Z</time>
+      </trkpt>
+      <trkpt lat="47.19699212349951" lon="8.794450974091887">
+        <ele>492.58999999999997</ele>
+        <time>2016-01-03T12:04:27Z</time>
+      </trkpt>
+      <trkpt lat="47.19699405133724" lon="8.794399006292224">
+        <ele>492.38999999999999</ele>
+        <time>2016-01-03T12:04:28Z</time>
+      </trkpt>
+      <trkpt lat="47.19698860310018" lon="8.794350139796734">
+        <ele>492.94</ele>
+        <time>2016-01-03T12:04:29Z</time>
+      </trkpt>
+      <trkpt lat="47.19698214903474" lon="8.794298926368356">
+        <ele>492.47000000000003</ele>
+        <time>2016-01-03T12:04:30Z</time>
+      </trkpt>
+      <trkpt lat="47.19697737134993" lon="8.794246790930629">
+        <ele>492.50999999999999</ele>
+        <time>2016-01-03T12:04:31Z</time>
+      </trkpt>
+      <trkpt lat="47.19698206521571" lon="8.794189291074872">
+        <ele>492.73000000000002</ele>
+        <time>2016-01-03T12:04:32Z</time>
+      </trkpt>
+      <trkpt lat="47.196985417976975" lon="8.794133719056845">
+        <ele>492.63</ele>
+        <time>2016-01-03T12:04:33Z</time>
+      </trkpt>
+      <trkpt lat="47.19698768109083" lon="8.794077644124627">
+        <ele>493</ele>
+        <time>2016-01-03T12:04:34Z</time>
+      </trkpt>
+      <trkpt lat="47.19699136912823" lon="8.794022323563695">
+        <ele>493.00999999999999</ele>
+        <time>2016-01-03T12:04:35Z</time>
+      </trkpt>
+      <trkpt lat="47.196987848728895" lon="8.793976558372378">
+        <ele>493.19999999999999</ele>
+        <time>2016-01-03T12:04:36Z</time>
+      </trkpt>
+      <trkpt lat="47.19698550179601" lon="8.793926937505603">
+        <ele>493.18000000000001</ele>
+        <time>2016-01-03T12:04:37Z</time>
+      </trkpt>
+      <trkpt lat="47.196980556473136" lon="8.793885698541999">
+        <ele>493</ele>
+        <time>2016-01-03T12:04:38Z</time>
+      </trkpt>
+      <trkpt lat="47.19698307104409" lon="8.793837334960699">
+        <ele>493.20999999999998</ele>
+        <time>2016-01-03T12:04:39Z</time>
+      </trkpt>
+      <trkpt lat="47.196992291137576" lon="8.793786959722638">
+        <ele>493.11000000000001</ele>
+        <time>2016-01-03T12:04:40Z</time>
+      </trkpt>
+      <trkpt lat="47.19699547626078" lon="8.793743625283241">
+        <ele>493.30000000000001</ele>
+        <time>2016-01-03T12:04:41Z</time>
+      </trkpt>
+      <trkpt lat="47.19700268469751" lon="8.793694507330656">
+        <ele>493.50999999999999</ele>
+        <time>2016-01-03T12:04:42Z</time>
+      </trkpt>
+      <trkpt lat="47.19700511544943" lon="8.793357806280255">
+        <ele>493</ele>
+        <time>2016-01-03T12:04:50Z</time>
+      </trkpt>
+      <trkpt lat="47.19702162779868" lon="8.793316148221493">
+        <ele>492.37</ele>
+        <time>2016-01-03T12:04:51Z</time>
+      </trkpt>
+      <trkpt lat="47.19704459421337" lon="8.793262336403131">
+        <ele>492.30000000000001</ele>
+        <time>2016-01-03T12:04:52Z</time>
+      </trkpt>
+      <trkpt lat="47.19706906937063" lon="8.793201064690948">
+        <ele>492.04000000000002</ele>
+        <time>2016-01-03T12:04:53Z</time>
+      </trkpt>
+      <trkpt lat="47.19708985649049" lon="8.793123783543706">
+        <ele>491.37</ele>
+        <time>2016-01-03T12:04:54Z</time>
+      </trkpt>
+      <trkpt lat="47.19710913486779" lon="8.79304625093937">
+        <ele>491.06999999999999</ele>
+        <time>2016-01-03T12:04:55Z</time>
+      </trkpt>
+      <trkpt lat="47.19713117927313" lon="8.792974585667253">
+        <ele>490.39999999999998</ele>
+        <time>2016-01-03T12:04:56Z</time>
+      </trkpt>
+      <trkpt lat="47.197186248376966" lon="8.792809881269932">
+        <ele>489.75</ele>
+        <time>2016-01-03T12:04:58Z</time>
+      </trkpt>
+      <trkpt lat="47.19720753841102" lon="8.79271550104022">
+        <ele>489.87</ele>
+        <time>2016-01-03T12:04:59Z</time>
+      </trkpt>
+      <trkpt lat="47.19722296111286" lon="8.792620282620192">
+        <ele>488.95999999999998</ele>
+        <time>2016-01-03T12:05:00Z</time>
+      </trkpt>
+      <trkpt lat="47.19733930192888" lon="8.792043440043926">
+        <ele>485.85000000000002</ele>
+        <time>2016-01-03T12:05:06Z</time>
+      </trkpt>
+      <trkpt lat="47.1974522061646" lon="8.791516218334436">
+        <ele>482.81</ele>
+        <time>2016-01-03T12:05:11Z</time>
+      </trkpt>
+      <trkpt lat="47.197455475106835" lon="8.79138101823628">
+        <ele>481.99000000000001</ele>
+        <time>2016-01-03T12:05:12Z</time>
+      </trkpt>
+      <trkpt lat="47.197490092366934" lon="8.79095789976418">
+        <ele>478.92</ele>
+      </trkpt>
+      <trkpt lat="47.19753225333989" lon="8.790533943101764">
+        <ele>476</ele>
+      </trkpt>
+      <trkpt lat="47.19762864522636" lon="8.789889458566904">
+        <ele>474.38</ele>
+        <time>2016-01-03T12:05:23Z</time>
+      </trkpt>
+      <trkpt lat="47.19763744622469" lon="8.789792899042368">
+        <ele>474.35000000000002</ele>
+        <time>2016-01-03T12:05:24Z</time>
+      </trkpt>
+      <trkpt lat="47.1976438164711" lon="8.789720982313156">
+        <ele>474.12</ele>
+        <time>2016-01-03T12:05:25Z</time>
+      </trkpt>
+      <trkpt lat="47.19764859415591" lon="8.789367768913507">
+        <ele>472.52999999999997</ele>
+        <time>2016-01-03T12:05:33Z</time>
+      </trkpt>
+      <trkpt lat="47.19765613786876" lon="8.78931068815291">
+        <ele>472.75</ele>
+        <time>2016-01-03T12:05:34Z</time>
+      </trkpt>
+      <trkpt lat="47.1976903360337" lon="8.789105415344238">
+        <ele>472.19</ele>
+        <time>2016-01-03T12:05:37Z</time>
+      </trkpt>
+      <trkpt lat="47.197700729593635" lon="8.78903266042471">
+        <ele>471.92000000000002</ele>
+        <time>2016-01-03T12:05:38Z</time>
+      </trkpt>
+      <trkpt lat="47.197715900838375" lon="8.78876687027514">
+        <ele>471.98000000000002</ele>
+        <time>2016-01-03T12:05:41Z</time>
+      </trkpt>
+      <trkpt lat="47.19775462523103" lon="8.788432851433754">
+        <ele>473.49000000000001</ele>
+        <time>2016-01-03T12:05:47Z</time>
+      </trkpt>
+      <trkpt lat="47.197777507826686" lon="8.78841600380838">
+        <ele>473.44999999999999</ele>
+        <time>2016-01-03T12:05:48Z</time>
+      </trkpt>
+      <trkpt lat="47.19780064187944" lon="8.788405358791351">
+        <ele>473.45999999999998</ele>
+        <time>2016-01-03T12:05:49Z</time>
+      </trkpt>
+      <trkpt lat="47.197963669896126" lon="8.788386499509215">
+        <ele>470.27999999999997</ele>
+        <time>2016-01-03T12:05:53Z</time>
+      </trkpt>
+      <trkpt lat="47.1981308888644" lon="8.788295891135931">
+        <ele>467.20999999999998</ele>
+        <time>2016-01-03T12:05:57Z</time>
+      </trkpt>
+      <trkpt lat="47.19813633710146" lon="8.788262866437435">
+        <ele>466.89999999999998</ele>
+        <time>2016-01-03T12:05:58Z</time>
+      </trkpt>
+      <trkpt lat="47.19812661409378" lon="8.788229255005717">
+        <ele>466.76999999999998</ele>
+        <time>2016-01-03T12:05:59Z</time>
+      </trkpt>
+      <trkpt lat="47.19810306094587" lon="8.788186172023416">
+        <ele>466.25</ele>
+        <time>2016-01-03T12:06:00Z</time>
+      </trkpt>
+      <trkpt lat="47.19808369874954" lon="8.788127414882183">
+        <ele>465.23000000000002</ele>
+        <time>2016-01-03T12:06:01Z</time>
+      </trkpt>
+      <trkpt lat="47.19807816669345" lon="8.788059940561652">
+        <ele>464.12</ele>
+        <time>2016-01-03T12:06:02Z</time>
+      </trkpt>
+      <trkpt lat="47.19808881171048" lon="8.787991376593709">
+        <ele>463.68000000000001</ele>
+        <time>2016-01-03T12:06:03Z</time>
+      </trkpt>
+      <trkpt lat="47.19811093993485" lon="8.787914346903563">
+        <ele>462.5</ele>
+        <time>2016-01-03T12:06:04Z</time>
+      </trkpt>
+      <trkpt lat="47.19815100543201" lon="8.78783798776567">
+        <ele>462.45999999999998</ele>
+        <time>2016-01-03T12:06:05Z</time>
+      </trkpt>
+      <trkpt lat="47.19819492660463" lon="8.787756934762001">
+        <ele>461.56999999999999</ele>
+        <time>2016-01-03T12:06:06Z</time>
+      </trkpt>
+      <trkpt lat="47.1982860378921" lon="8.787589464336634">
+        <ele>461.14999999999998</ele>
+        <time>2016-01-03T12:06:08Z</time>
+      </trkpt>
+      <trkpt lat="47.19831814058125" lon="8.7874944973737">
+        <ele>460.19</ele>
+        <time>2016-01-03T12:06:09Z</time>
+      </trkpt>
+      <trkpt lat="47.1983309648931" lon="8.787389053031802">
+        <ele>459.83999999999997</ele>
+        <time>2016-01-03T12:06:10Z</time>
+      </trkpt>
+      <trkpt lat="47.198331551626325" lon="8.787284530699253">
+        <ele>460.49000000000001</ele>
+        <time>2016-01-03T12:06:11Z</time>
+      </trkpt>
+      <trkpt lat="47.198325265198946" lon="8.787185624241829">
+        <ele>460.23000000000002</ele>
+        <time>2016-01-03T12:06:12Z</time>
+      </trkpt>
+      <trkpt lat="47.19824245199561" lon="8.78635254688561">
+        <ele>460.56999999999999</ele>
+        <time>2016-01-03T12:06:22Z</time>
+      </trkpt>
+      <trkpt lat="47.198192747309804" lon="8.78586145117879">
+        <ele>457.79000000000002</ele>
+        <time>2016-01-03T12:06:27Z</time>
+      </trkpt>
+      <trkpt lat="47.19819249585271" lon="8.78536943346262">
+        <ele>454.66000000000003</ele>
+        <time>2016-01-03T12:06:31Z</time>
+      </trkpt>
+    </trkseg>
+  </trk>
+  <trk>
+    <extensions>
+      <gpxd:color>#0000FF</gpxd:color>
+    </extensions>
+    <trkseg>
+      <trkpt lat="47.18660652637482" lon="8.796921372413635">
+        <ele>624.7421875</ele>
+      </trkpt>
+      <trkpt lat="47.186644077301025" lon="8.7968248128891">
+        <ele>626.015625</ele>
+      </trkpt>
+      <trkpt lat="47.18669772148132" lon="8.796712160110474">
+        <ele>627.0625</ele>
+      </trkpt>
+      <trkpt lat="47.18676209449768" lon="8.796610236167908">
+        <ele>627.3671875</ele>
+      </trkpt>
+      <trkpt lat="47.1868371963501" lon="8.796519041061401">
+        <ele>626.90234375</ele>
+      </trkpt>
+      <trkpt lat="47.186912298202515" lon="8.796401023864746">
+        <ele>626.11328125</ele>
+      </trkpt>
+      <trkpt lat="47.18698740005493" lon="8.796277642250061">
+        <ele>625.33203125</ele>
+      </trkpt>
+      <trkpt lat="47.18707859516144" lon="8.796148896217346">
+        <ele>623.90625</ele>
+      </trkpt>
+      <trkpt lat="47.18710541725159" lon="8.796095252037048">
+        <ele>623.66796875</ele>
+      </trkpt>
+      <trkpt lat="47.187126874923706" lon="8.796030879020691">
+        <ele>623.71484375</ele>
+      </trkpt>
+      <trkpt lat="47.187132239341736" lon="8.795977234840393">
+        <ele>623.75</ele>
+      </trkpt>
+      <trkpt lat="47.187132239341736" lon="8.795923590660095">
+        <ele>623.9375</ele>
+      </trkpt>
+      <trkpt lat="47.187132239341736" lon="8.795859217643738">
+        <ele>624.1640625</ele>
+      </trkpt>
+      <trkpt lat="47.18711078166962" lon="8.795735836029053">
+        <ele>625.234375</ele>
+      </trkpt>
+      <trkpt lat="47.18710005283356" lon="8.795607089996338">
+        <ele>626</ele>
+      </trkpt>
+      <trkpt lat="47.18709468841553" lon="8.795521259307861">
+        <ele>626.3515625</ele>
+      </trkpt>
+      <trkpt lat="47.18710541725159" lon="8.795440793037415">
+        <ele>626.14453125</ele>
+      </trkpt>
+      <trkpt lat="47.187126874923706" lon="8.795360326766968">
+        <ele>625.6640625</ele>
+      </trkpt>
+      <trkpt lat="47.187164425849915" lon="8.79528522491455">
+        <ele>624.7890625</ele>
+      </trkpt>
+      <trkpt lat="47.1872341632843" lon="8.795183300971985">
+        <ele>623.23046875</ele>
+      </trkpt>
+      <trkpt lat="47.18729317188263" lon="8.795086741447449">
+        <ele>622.09375</ele>
+      </trkpt>
+      <trkpt lat="47.18736290931702" lon="8.794984817504883">
+        <ele>620.9765625</ele>
+      </trkpt>
+      <trkpt lat="47.187416553497314" lon="8.794904351234436">
+        <ele>620.23828125</ele>
+      </trkpt>
+      <trkpt lat="47.18746483325958" lon="8.794845342636108">
+        <ele>619.42578125</ele>
+      </trkpt>
+      <trkpt lat="47.18752384185791" lon="8.79479706287384">
+        <ele>617.7734375</ele>
+      </trkpt>
+      <trkpt lat="47.18756139278412" lon="8.794743418693542">
+        <ele>616.8671875</ele>
+      </trkpt>
+      <trkpt lat="47.1875935792923" lon="8.794695138931274">
+        <ele>616.09765625</ele>
+      </trkpt>
+      <trkpt lat="47.18760967254639" lon="8.794630765914917">
+        <ele>615.87890625</ele>
+      </trkpt>
+      <trkpt lat="47.187620401382446" lon="8.7945556640625">
+        <ele>615.3984375</ele>
+      </trkpt>
+      <trkpt lat="47.187636494636536" lon="8.794485926628113">
+        <ele>614.76953125</ele>
+      </trkpt>
+      <trkpt lat="47.187674045562744" lon="8.794400095939636">
+        <ele>613.47265625</ele>
+      </trkpt>
+      <trkpt lat="47.18769550323486" lon="8.79430890083313">
+        <ele>612.72265625</ele>
+      </trkpt>
+      <trkpt lat="47.18770086765289" lon="8.794185519218445">
+        <ele>612.4609375</ele>
+      </trkpt>
+      <trkpt lat="47.18770086765289" lon="8.79407823085785">
+        <ele>611.85546875</ele>
+      </trkpt>
+      <trkpt lat="47.187684774398804" lon="8.793997764587402">
+        <ele>611.90625</ele>
+      </trkpt>
+      <trkpt lat="47.187663316726685" lon="8.793933391571045">
+        <ele>612.27734375</ele>
+      </trkpt>
+      <trkpt lat="47.18761503696442" lon="8.793869018554688">
+        <ele>613.66796875</ele>
+      </trkpt>
+      <trkpt lat="47.18758285045624" lon="8.79381537437439">
+        <ele>614.62890625</ele>
+      </trkpt>
+      <trkpt lat="47.18756675720215" lon="8.793767094612122">
+        <ele>615.0703125</ele>
+      </trkpt>
+      <trkpt lat="47.18757212162018" lon="8.793713450431824">
+        <ele>614.72265625</ele>
+      </trkpt>
+      <trkpt lat="47.18758821487427" lon="8.793681263923645">
+        <ele>614.26171875</ele>
+      </trkpt>
+      <trkpt lat="47.187641859054565" lon="8.793681263923645">
+        <ele>612.06640625</ele>
+      </trkpt>
+      <trkpt lat="47.18770086765289" lon="8.793708086013794">
+        <ele>609.6875</ele>
+      </trkpt>
+      <trkpt lat="47.18778133392334" lon="8.793751001358032">
+        <ele>606.83984375</ele>
+      </trkpt>
+      <trkpt lat="47.18785107135773" lon="8.79380464553833">
+        <ele>604.671875</ele>
+      </trkpt>
+      <trkpt lat="47.187920808792114" lon="8.793842196464539">
+        <ele>602.52734375</ele>
+      </trkpt>
+      <trkpt lat="47.18800127506256" lon="8.793911933898926">
+        <ele>600.78515625</ele>
+      </trkpt>
+      <trkpt lat="47.18811392784119" lon="8.794013857841492">
+        <ele>598.078125</ele>
+      </trkpt>
+      <trkpt lat="47.188151478767395" lon="8.79406213760376">
+        <ele>597.1953125</ele>
+      </trkpt>
+      <trkpt lat="47.1881890296936" lon="8.794153332710266">
+        <ele>596.5234375</ele>
+      </trkpt>
+      <trkpt lat="47.18821585178375" lon="8.794239163398743">
+        <ele>595.74609375</ele>
+      </trkpt>
+      <trkpt lat="47.1882426738739" lon="8.794351816177368">
+        <ele>594.82421875</ele>
+      </trkpt>
+      <trkpt lat="47.18826413154602" lon="8.794426918029785">
+        <ele>594.10546875</ele>
+      </trkpt>
+      <trkpt lat="47.18829095363617" lon="8.794475197792053">
+        <ele>593.2109375</ele>
+      </trkpt>
+      <trkpt lat="47.18830704689026" lon="8.794523477554321">
+        <ele>592.6875</ele>
+      </trkpt>
+      <trkpt lat="47.18831241130829" lon="8.794614672660828">
+        <ele>592.5390625</ele>
+      </trkpt>
+      <trkpt lat="47.18830704689026" lon="8.79479706287384">
+        <ele>592.7578125</ele>
+      </trkpt>
+      <trkpt lat="47.18830704689026" lon="8.794888257980347">
+        <ele>592.77734375</ele>
+      </trkpt>
+      <trkpt lat="47.18831241130829" lon="8.794941902160645">
+        <ele>592.63671875</ele>
+      </trkpt>
+      <trkpt lat="47.18833386898041" lon="8.794995546340942">
+        <ele>592.06640625</ele>
+      </trkpt>
+      <trkpt lat="47.188366055488586" lon="8.7950599193573">
+        <ele>591.2578125</ele>
+      </trkpt>
+      <trkpt lat="47.188403606414795" lon="8.795113563537598">
+        <ele>590.46875</ele>
+      </trkpt>
+      <trkpt lat="47.188435792922974" lon="8.795167207717896">
+        <ele>589.7578125</ele>
+      </trkpt>
+      <trkpt lat="47.18845188617706" lon="8.795226216316223">
+        <ele>589.359375</ele>
+      </trkpt>
+      <trkpt lat="47.18846261501312" lon="8.79529058933258">
+        <ele>589.05859375</ele>
+      </trkpt>
+      <trkpt lat="47.18845188617706" lon="8.795354962348938">
+        <ele>589.21875</ele>
+      </trkpt>
+      <trkpt lat="47.188430428504944" lon="8.795451521873474">
+        <ele>589.59375</ele>
+      </trkpt>
+      <trkpt lat="47.188408970832825" lon="8.7955641746521">
+        <ele>589.98046875</ele>
+      </trkpt>
+      <trkpt lat="47.188403606414795" lon="8.795655369758606">
+        <ele>589.51953125</ele>
+      </trkpt>
+      <trkpt lat="47.188408970832825" lon="8.795746564865112">
+        <ele>588.796875</ele>
+      </trkpt>
+      <trkpt lat="47.188435792922974" lon="8.795859217643738">
+        <ele>587.4375</ele>
+      </trkpt>
+      <trkpt lat="47.18847870826721" lon="8.795971870422363">
+        <ele>585.70703125</ele>
+      </trkpt>
+      <trkpt lat="47.18850553035736" lon="8.79605233669281">
+        <ele>584.48046875</ele>
+      </trkpt>
+      <trkpt lat="47.18852162361145" lon="8.796132802963257">
+        <ele>583.328125</ele>
+      </trkpt>
+      <trkpt lat="47.18852162361145" lon="8.796197175979614">
+        <ele>582.69921875</ele>
+      </trkpt>
+      <trkpt lat="47.18851625919342" lon="8.79628300666809">
+        <ele>581.96875</ele>
+      </trkpt>
+      <trkpt lat="47.18850016593933" lon="8.796379566192627">
+        <ele>581.3359375</ele>
+      </trkpt>
+      <trkpt lat="47.18848943710327" lon="8.796465396881104">
+        <ele>580.6796875</ele>
+      </trkpt>
+      <trkpt lat="47.18848943710327" lon="8.796524405479431">
+        <ele>580.33984375</ele>
+      </trkpt>
+      <trkpt lat="47.18850016593933" lon="8.796578049659729">
+        <ele>580.0234375</ele>
+      </trkpt>
+      <trkpt lat="47.18852162361145" lon="8.796631693840027">
+        <ele>579.5078125</ele>
+      </trkpt>
+      <trkpt lat="47.1885484457016" lon="8.796685338020325">
+        <ele>578.890625</ele>
+      </trkpt>
+      <trkpt lat="47.18856990337372" lon="8.796749711036682">
+        <ele>578.34375</ele>
+      </trkpt>
+      <trkpt lat="47.18858063220978" lon="8.79681944847107">
+        <ele>577.984375</ele>
+      </trkpt>
+      <trkpt lat="47.18857526779175" lon="8.796899914741516">
+        <ele>577.90234375</ele>
+      </trkpt>
+      <trkpt lat="47.18858599662781" lon="8.796991109848022">
+        <ele>577.50390625</ele>
+      </trkpt>
+      <trkpt lat="47.18859672546387" lon="8.79704475402832">
+        <ele>577.20703125</ele>
+      </trkpt>
+      <trkpt lat="47.188623547554016" lon="8.797119855880737">
+        <ele>576.6171875</ele>
+      </trkpt>
+      <trkpt lat="47.188666462898254" lon="8.797189593315125">
+        <ele>575.82421875</ele>
+      </trkpt>
+      <trkpt lat="47.18870937824249" lon="8.797211050987244">
+        <ele>575.125</ele>
+      </trkpt>
+      <trkpt lat="47.18871474266052" lon="8.797157406806946">
+        <ele>575.0546875</ele>
+      </trkpt>
+      <trkpt lat="47.18872547149658" lon="8.79705548286438">
+        <ele>574.89453125</ele>
+      </trkpt>
+      <trkpt lat="47.18873620033264" lon="8.796937465667725">
+        <ele>574.75</ele>
+      </trkpt>
+      <trkpt lat="47.18875765800476" lon="8.79681408405304">
+        <ele>574.6484375</ele>
+      </trkpt>
+      <trkpt lat="47.18879520893097" lon="8.796685338020325">
+        <ele>574.26953125</ele>
+      </trkpt>
+      <trkpt lat="47.18883812427521" lon="8.796588778495789">
+        <ele>573.72265625</ele>
+      </trkpt>
+      <trkpt lat="47.188907861709595" lon="8.796438574790955">
+        <ele>572.4296875</ele>
+      </trkpt>
+      <trkpt lat="47.18901515007019" lon="8.796240091323853">
+        <ele>570.828125</ele>
+      </trkpt>
+      <trkpt lat="47.18906342983246" lon="8.796154260635376">
+        <ele>570.1015625</ele>
+      </trkpt>
+      <trkpt lat="47.189154624938965" lon="8.795987963676453">
+        <ele>568.7734375</ele>
+      </trkpt>
+      <trkpt lat="47.18921899795532" lon="8.795869946479797">
+        <ele>567.8125</ele>
+      </trkpt>
+      <trkpt lat="47.18926191329956" lon="8.795778751373291">
+        <ele>567.25390625</ele>
+      </trkpt>
+      <trkpt lat="47.18928337097168" lon="8.795714378356934">
+        <ele>567.09765625</ele>
+      </trkpt>
+      <trkpt lat="47.18929409980774" lon="8.795660734176636">
+        <ele>567.1640625</ele>
+      </trkpt>
+      <trkpt lat="47.18929946422577" lon="8.795580267906189">
+        <ele>567.546875</ele>
+      </trkpt>
+      <trkpt lat="47.18929946422577" lon="8.795451521873474">
+        <ele>567.86328125</ele>
+      </trkpt>
+      <trkpt lat="47.18929409980774" lon="8.7953120470047">
+        <ele>568.2890625</ele>
+      </trkpt>
+      <trkpt lat="47.18929409980774" lon="8.795210123062134">
+        <ele>568.49609375</ele>
+      </trkpt>
+      <trkpt lat="47.1893048286438" lon="8.795135021209717">
+        <ele>568.33203125</ele>
+      </trkpt>
+      <trkpt lat="47.18934237957001" lon="8.794904351234436">
+        <ele>566.84765625</ele>
+      </trkpt>
+      <trkpt lat="47.18934774398804" lon="8.794845342636108">
+        <ele>566.609375</ele>
+      </trkpt>
+      <trkpt lat="47.18933701515198" lon="8.794738054275513">
+        <ele>566.94140625</ele>
+      </trkpt>
+      <trkpt lat="47.18933701515198" lon="8.794657588005066">
+        <ele>566.88671875</ele>
+      </trkpt>
+      <trkpt lat="47.18935310840607" lon="8.79457712173462">
+        <ele>566.27734375</ele>
+      </trkpt>
+      <trkpt lat="47.189374566078186" lon="8.794502019882202">
+        <ele>565.48046875</ele>
+      </trkpt>
+      <trkpt lat="47.189428210258484" lon="8.794384002685547">
+        <ele>563.5</ele>
+      </trkpt>
+      <trkpt lat="47.18945503234863" lon="8.7943035364151">
+        <ele>562.51953125</ele>
+      </trkpt>
+      <trkpt lat="47.18947112560272" lon="8.794206976890564">
+        <ele>561.9453125</ele>
+      </trkpt>
+      <trkpt lat="47.18948185443878" lon="8.79407286643982">
+        <ele>561.85546875</ele>
+      </trkpt>
+      <trkpt lat="47.18949794769287" lon="8.793911933898926">
+        <ele>561.7578125</ele>
+      </trkpt>
+      <trkpt lat="47.18950867652893" lon="8.79378855228424">
+        <ele>561.765625</ele>
+      </trkpt>
+      <trkpt lat="47.18952476978302" lon="8.793686628341675">
+        <ele>561.453125</ele>
+      </trkpt>
+      <trkpt lat="47.18955159187317" lon="8.79356861114502">
+        <ele>560.6015625</ele>
+      </trkpt>
+      <trkpt lat="47.18958377838135" lon="8.793466687202454">
+        <ele>559.65234375</ele>
+      </trkpt>
+      <trkpt lat="47.189615964889526" lon="8.793386220932007">
+        <ele>558.7578125</ele>
+      </trkpt>
+      <trkpt lat="47.189658880233765" lon="8.793278932571411">
+        <ele>557.66015625</ele>
+      </trkpt>
+      <trkpt lat="47.18971252441406" lon="8.793187737464905">
+        <ele>556.35546875</ele>
+      </trkpt>
+      <trkpt lat="47.18976080417633" lon="8.793118000030518">
+        <ele>555.2265625</ele>
+      </trkpt>
+      <trkpt lat="47.18983054161072" lon="8.79304826259613">
+        <ele>553.53125</ele>
+      </trkpt>
+      <trkpt lat="47.189921736717224" lon="8.792962431907654">
+        <ele>551.265625</ele>
+      </trkpt>
+      <trkpt lat="47.18997538089752" lon="8.792903423309326">
+        <ele>549.92578125</ele>
+      </trkpt>
+      <trkpt lat="47.1900075674057" lon="8.792855143547058">
+        <ele>549.140625</ele>
+      </trkpt>
+      <trkpt lat="47.19003438949585" lon="8.792780041694641">
+        <ele>548.48828125</ele>
+      </trkpt>
+      <trkpt lat="47.19004511833191" lon="8.792726397514343">
+        <ele>548.0078125</ele>
+      </trkpt>
+      <trkpt lat="47.19005584716797" lon="8.792635202407837">
+        <ele>547.39453125</ele>
+      </trkpt>
+      <trkpt lat="47.19005584716797" lon="8.79256546497345">
+        <ele>547.15234375</ele>
+      </trkpt>
+      <trkpt lat="47.19005048274994" lon="8.792501091957092">
+        <ele>547.08203125</ele>
+      </trkpt>
+      <trkpt lat="47.19001829624176" lon="8.792366981506348">
+        <ele>547.55078125</ele>
+      </trkpt>
+      <trkpt lat="47.18994319438934" lon="8.792104125022888">
+        <ele>548.69921875</ele>
+      </trkpt>
+      <trkpt lat="47.189932465553284" lon="8.792034387588501">
+        <ele>548.76953125</ele>
+      </trkpt>
+      <trkpt lat="47.189932465553284" lon="8.791970014572144">
+        <ele>548.51953125</ele>
+      </trkpt>
+      <trkpt lat="47.18994319438934" lon="8.791900277137756">
+        <ele>547.88671875</ele>
+      </trkpt>
+      <trkpt lat="47.18997001647949" lon="8.79183053970337">
+        <ele>546.7265625</ele>
+      </trkpt>
+      <trkpt lat="47.19000220298767" lon="8.791755437850952">
+        <ele>545.3984375</ele>
+      </trkpt>
+      <trkpt lat="47.19003975391388" lon="8.791680335998535">
+        <ele>543.87890625</ele>
+      </trkpt>
+      <trkpt lat="47.190120220184326" lon="8.791535496711731">
+        <ele>540.6484375</ele>
+      </trkpt>
+      <trkpt lat="47.19023287296295" lon="8.79129409790039">
+        <ele>536.4296875</ele>
+      </trkpt>
+      <trkpt lat="47.19025433063507" lon="8.791224360466003">
+        <ele>536.046875</ele>
+      </trkpt>
+      <trkpt lat="47.19027042388916" lon="8.791149258613586">
+        <ele>535.765625</ele>
+      </trkpt>
+      <trkpt lat="47.19027578830719" lon="8.791015148162842">
+        <ele>535.71875</ele>
+      </trkpt>
+      <trkpt lat="47.19027578830719" lon="8.790768384933472">
+        <ele>535.55859375</ele>
+      </trkpt>
+      <trkpt lat="47.19026505947113" lon="8.790435791015625">
+        <ele>535.359375</ele>
+      </trkpt>
+      <trkpt lat="47.1902596950531" lon="8.790162205696106">
+        <ele>534.5234375</ele>
+      </trkpt>
+      <trkpt lat="47.1902596950531" lon="8.789920806884766">
+        <ele>534.2578125</ele>
+      </trkpt>
+      <trkpt lat="47.19025433063507" lon="8.789674043655396">
+        <ele>535.1328125</ele>
+      </trkpt>
+      <trkpt lat="47.19025433063507" lon="8.78955602645874">
+        <ele>535.46875</ele>
+      </trkpt>
+      <trkpt lat="47.19025433063507" lon="8.789491653442383">
+        <ele>535.04296875</ele>
+      </trkpt>
+      <trkpt lat="47.19027042388916" lon="8.789438009262085">
+        <ele>534.04296875</ele>
+      </trkpt>
+      <trkpt lat="47.19030797481537" lon="8.789384365081787">
+        <ele>532.234375</ele>
+      </trkpt>
+      <trkpt lat="47.19035625457764" lon="8.789357542991638">
+        <ele>530.2109375</ele>
+      </trkpt>
+      <trkpt lat="47.190393805503845" lon="8.789357542991638">
+        <ele>528.7890625</ele>
+      </trkpt>
+      <trkpt lat="47.190425992012024" lon="8.789373636245728">
+        <ele>527.69140625</ele>
+      </trkpt>
+      <trkpt lat="47.1904581785202" lon="8.789411187171936">
+        <ele>526.76171875</ele>
+      </trkpt>
+      <trkpt lat="47.19048500061035" lon="8.789459466934204">
+        <ele>526.1171875</ele>
+      </trkpt>
+      <trkpt lat="47.19050645828247" lon="8.789529204368591">
+        <ele>525.83984375</ele>
+      </trkpt>
+      <trkpt lat="47.19052255153656" lon="8.789609670639038">
+        <ele>525.51171875</ele>
+      </trkpt>
+      <trkpt lat="47.19053328037262" lon="8.789727687835693">
+        <ele>525.34375</ele>
+      </trkpt>
+      <trkpt lat="47.19054400920868" lon="8.78982961177826">
+        <ele>525.18359375</ele>
+      </trkpt>
+      <trkpt lat="47.19058692455292" lon="8.790022730827332">
+        <ele>524.3515625</ele>
+      </trkpt>
+      <trkpt lat="47.190635204315186" lon="8.790242671966553">
+        <ele>524.41015625</ele>
+      </trkpt>
+      <trkpt lat="47.190672755241394" lon="8.790398240089417">
+        <ele>524.47265625</ele>
+      </trkpt>
+      <trkpt lat="47.19072639942169" lon="8.79054844379425">
+        <ele>524.02734375</ele>
+      </trkpt>
+      <trkpt lat="47.19078004360199" lon="8.790677189826965">
+        <ele>523.09375</ele>
+      </trkpt>
+      <trkpt lat="47.19083368778229" lon="8.79082202911377">
+        <ele>521.92578125</ele>
+      </trkpt>
+      <trkpt lat="47.190876603126526" lon="8.790961503982544">
+        <ele>520.87109375</ele>
+      </trkpt>
+      <trkpt lat="47.190908789634705" lon="8.791095614433289">
+        <ele>520.51953125</ele>
+      </trkpt>
+      <trkpt lat="47.19093561172485" lon="8.791192173957825">
+        <ele>520.2578125</ele>
+      </trkpt>
+      <trkpt lat="47.19097316265106" lon="8.791267275810242">
+        <ele>519.6640625</ele>
+      </trkpt>
+      <trkpt lat="47.19103217124939" lon="8.791337013244629">
+        <ele>518.5703125</ele>
+      </trkpt>
+      <trkpt lat="47.191112637519836" lon="8.791401386260986">
+        <ele>517.04296875</ele>
+      </trkpt>
+      <trkpt lat="47.19128429889679" lon="8.791524767875671">
+        <ele>513.03125</ele>
+      </trkpt>
+      <trkpt lat="47.191407680511475" lon="8.791610598564148">
+        <ele>510.19921875</ele>
+      </trkpt>
+      <trkpt lat="47.19148814678192" lon="8.791669607162476">
+        <ele>508.5</ele>
+      </trkpt>
+      <trkpt lat="47.1915203332901" lon="8.791696429252625">
+        <ele>507.8828125</ele>
+      </trkpt>
+      <trkpt lat="47.19157934188843" lon="8.791739344596863">
+        <ele>506.71875</ele>
+      </trkpt>
+      <trkpt lat="47.191627621650696" lon="8.79179835319519">
+        <ele>506.03125</ele>
+      </trkpt>
+      <trkpt lat="47.191659808158875" lon="8.791851997375488">
+        <ele>505.5390625</ele>
+      </trkpt>
+      <trkpt lat="47.19168663024902" lon="8.791916370391846">
+        <ele>504.96875</ele>
+      </trkpt>
+      <trkpt lat="47.1917188167572" lon="8.792018294334412">
+        <ele>504.28125</ele>
+      </trkpt>
+      <trkpt lat="47.19175100326538" lon="8.792141675949097">
+        <ele>503.6640625</ele>
+      </trkpt>
+      <trkpt lat="47.19179928302765" lon="8.79229724407196">
+        <ele>502.578125</ele>
+      </trkpt>
+      <trkpt lat="47.19184219837189" lon="8.792458176612854">
+        <ele>500.921875</ele>
+      </trkpt>
+      <trkpt lat="47.191869020462036" lon="8.79257082939148">
+        <ele>499.85546875</ele>
+      </trkpt>
+      <trkpt lat="47.191879749298096" lon="8.792662024497986">
+        <ele>499.40234375</ele>
+      </trkpt>
+      <trkpt lat="47.191890478134155" lon="8.792763948440552">
+        <ele>498.96875</ele>
+      </trkpt>
+      <trkpt lat="47.191895842552185" lon="8.792887330055237">
+        <ele>497.8828125</ele>
+      </trkpt>
+      <trkpt lat="47.191895842552185" lon="8.79306435585022">
+        <ele>496.2265625</ele>
+      </trkpt>
+      <trkpt lat="47.191901206970215" lon="8.793182373046875">
+        <ele>494.9609375</ele>
+      </trkpt>
+      <trkpt lat="47.191906571388245" lon="8.793257474899292">
+        <ele>494.13671875</ele>
+      </trkpt>
+      <trkpt lat="47.191928029060364" lon="8.793343305587769">
+        <ele>493.6015625</ele>
+      </trkpt>
+      <trkpt lat="47.19196021556854" lon="8.793472051620483">
+        <ele>492.828125</ele>
+      </trkpt>
+      <trkpt lat="47.19199282117188" lon="8.793616723269224">
+        <ele>492.1015625</ele>
+      </trkpt>
+      <trkpt lat="47.19200849533081" lon="8.793686628341675">
+        <ele>491.76953125</ele>
+      </trkpt>
+      <trkpt lat="47.19204068183899" lon="8.793852925300598">
+        <ele>490.83984375</ele>
+      </trkpt>
+      <trkpt lat="47.19206213951111" lon="8.793992400169373">
+        <ele>490.23828125</ele>
+      </trkpt>
+      <trkpt lat="47.19207286834717" lon="8.7940514087677">
+        <ele>489.96484375</ele>
+      </trkpt>
+      <trkpt lat="47.19208359718323" lon="8.794147968292236">
+        <ele>489.703125</ele>
+      </trkpt>
+      <trkpt lat="47.192121148109436" lon="8.795000910758972">
+        <ele>484.7109375</ele>
+      </trkpt>
+      <trkpt lat="47.192137241363525" lon="8.79530131816864">
+        <ele>482.328125</ele>
+      </trkpt>
+      <trkpt lat="47.192137241363525" lon="8.795451521873474">
+        <ele>481.04296875</ele>
+      </trkpt>
+      <trkpt lat="47.192137241363525" lon="8.79553735256195">
+        <ele>480.3046875</ele>
+      </trkpt>
+      <trkpt lat="47.192126512527466" lon="8.795607089996338">
+        <ele>479.70703125</ele>
+      </trkpt>
+      <trkpt lat="47.19211041927338" lon="8.795682191848755">
+        <ele>478.984375</ele>
+      </trkpt>
+      <trkpt lat="47.19208896160126" lon="8.795746564865112">
+        <ele>478.4609375</ele>
+      </trkpt>
+      <trkpt lat="47.19203531742096" lon="8.795832395553589">
+        <ele>479.1015625</ele>
+      </trkpt>
+      <trkpt lat="47.19198167324066" lon="8.795896768569946">
+        <ele>480.359375</ele>
+      </trkpt>
+      <trkpt lat="47.19194948673248" lon="8.795934319496155">
+        <ele>481.19140625</ele>
+      </trkpt>
+      <trkpt lat="47.191906571388245" lon="8.795993328094482">
+        <ele>482.2890625</ele>
+      </trkpt>
+      <trkpt lat="47.191869020462036" lon="8.79606306552887">
+        <ele>483.28125</ele>
+      </trkpt>
+      <trkpt lat="47.19184756278992" lon="8.796138167381287">
+        <ele>483.69921875</ele>
+      </trkpt>
+      <trkpt lat="47.19184219837189" lon="8.796213269233704">
+        <ele>483.4609375</ele>
+      </trkpt>
+      <trkpt lat="47.19184219837189" lon="8.79628300666809">
+        <ele>483.0390625</ele>
+      </trkpt>
+      <trkpt lat="47.19185829162598" lon="8.796374201774597">
+        <ele>481.9140625</ele>
+      </trkpt>
+      <trkpt lat="47.191885113716125" lon="8.796454668045044">
+        <ele>480.515625</ele>
+      </trkpt>
+      <trkpt lat="47.191917300224304" lon="8.796513676643372">
+        <ele>479.16796875</ele>
+      </trkpt>
+      <trkpt lat="47.19198703765869" lon="8.796631693840027">
+        <ele>476.74609375</ele>
+      </trkpt>
+      <trkpt lat="47.19206750392914" lon="8.796760439872742">
+        <ele>474.3515625</ele>
+      </trkpt>
+      <trkpt lat="47.192131876945496" lon="8.796835541725159">
+        <ele>473.28515625</ele>
+      </trkpt>
+      <trkpt lat="47.19219088554382" lon="8.796894550323486">
+        <ele>472.39453125</ele>
+      </trkpt>
+      <trkpt lat="47.19225525856018" lon="8.796948194503784">
+        <ele>471.3671875</ele>
+      </trkpt>
+      <trkpt lat="47.19234645366669" lon="8.797001838684082">
+        <ele>470.0390625</ele>
+      </trkpt>
+      <trkpt lat="47.192426919937134" lon="8.79704475402832">
+        <ele>468.76171875</ele>
+      </trkpt>
+      <trkpt lat="47.19250738620758" lon="8.797082304954529">
+        <ele>467.3671875</ele>
+      </trkpt>
+      <trkpt lat="47.19255566596985" lon="8.797114491462708">
+        <ele>466.60546875</ele>
+      </trkpt>
+      <trkpt lat="47.1927273273468" lon="8.797253966331482">
+        <ele>464.65625</ele>
+      </trkpt>
+      <trkpt lat="47.19280779361725" lon="8.79730761051178">
+        <ele>463.62109375</ele>
+      </trkpt>
+      <trkpt lat="47.19286604784429" lon="8.79733837209642">
+        <ele>462.84375</ele>
+      </trkpt>
+      <trkpt lat="47.19286596402526" lon="8.797338204458356">
+        <ele>462.84765625</ele>
+      </trkpt>
+    </trkseg>
+  </trk>
+  <trk>
+    <extensions>
+      <gpxd:color>#00FF00</gpxd:color>
+    </extensions>
+    <trkseg>
+      <trkpt lat="47.18561486341059" lon="8.796475538983941">
+        <ele>647.81640625</ele>
+      </trkpt>
+      <trkpt lat="47.185668759047985" lon="8.796514933928847">
+        <ele>646.87109375</ele>
+      </trkpt>
+      <trkpt lat="47.18571729026735" lon="8.796522812917829">
+        <ele>646.1953125</ele>
+      </trkpt>
+      <trkpt lat="47.185757691040635" lon="8.796562207862735">
+        <ele>645.5859375</ele>
+      </trkpt>
+      <trkpt lat="47.18580354005098" lon="8.796577882021666">
+        <ele>644.8203125</ele>
+      </trkpt>
+      <trkpt lat="47.185914013534784" lon="8.796581821516156">
+        <ele>642.9765625</ele>
+      </trkpt>
+      <trkpt lat="47.18596254475415" lon="8.796625155955553">
+        <ele>641.796875</ele>
+      </trkpt>
+      <trkpt lat="47.186081148684025" lon="8.796644853428006">
+        <ele>639.4296875</ele>
+      </trkpt>
+      <trkpt lat="47.186186257749796" lon="8.7967315223068">
+        <ele>636.4921875</ele>
+      </trkpt>
+      <trkpt lat="47.186264377087355" lon="8.796790530905128">
+        <ele>634.1328125</ele>
+      </trkpt>
+      <trkpt lat="47.18639915809035" lon="8.796892957761884">
+        <ele>629.55859375</ele>
+      </trkpt>
+      <trkpt lat="47.186458418145776" lon="8.7969284132123">
+        <ele>627.55078125</ele>
+      </trkpt>
+      <trkpt lat="47.18660661019385" lon="8.796955989673734">
+        <ele>624.0234375</ele>
+      </trkpt>
+    </trkseg>
+  </trk>
+  <trk>
+    <trkseg>
+      <trkpt lat="47.18490038998425" lon="8.796944171190262">
+        <ele>663.90234375</ele>
+      </trkpt>
+      <trkpt lat="47.18495160341263" lon="8.796790530905128">
+        <ele>662.74609375</ele>
+      </trkpt>
+      <trkpt lat="47.18495696783066" lon="8.796640913933516">
+        <ele>662.1328125</ele>
+      </trkpt>
+      <trkpt lat="47.184981275349855" lon="8.796550389379263">
+        <ele>661.39453125</ele>
+      </trkpt>
+      <trkpt lat="47.18511060811579" lon="8.796479478478432">
+        <ele>658.98828125</ele>
+      </trkpt>
+      <trkpt lat="47.18521839939058" lon="8.7964085675776">
+        <ele>657.47265625</ele>
+      </trkpt>
+      <trkpt lat="47.18536122702062" lon="8.796420386061072">
+        <ele>654.22265625</ele>
+      </trkpt>
+      <trkpt lat="47.18553640879691" lon="8.796440083533525">
+        <ele>650.0703125</ele>
+      </trkpt>
+      <trkpt lat="47.185609163716435" lon="8.796475538983941">
+        <ele>647.890625</ele>
+      </trkpt>
+    </trkseg>
+  </trk>
+  <trk>
+    <trkseg>
+      <trkpt lat="47.20138901844621" lon="8.774476982653141">
+        <ele>421.52999999999997</ele>
+        <time>2016-01-03T12:08:53Z</time>
+      </trkpt>
+      <trkpt lat="47.201492534950376" lon="8.773281471803784">
+        <ele>423.57999999999998</ele>
+        <time>2016-01-03T12:09:10Z</time>
+      </trkpt>
+      <trkpt lat="47.2014878410846" lon="8.772208672016859">
+        <ele>423</ele>
+        <time>2016-01-03T12:09:26Z</time>
+      </trkpt>
+      <trkpt lat="47.2014997433871" lon="8.772082105278969">
+        <ele>423.07999999999998</ele>
+        <time>2016-01-03T12:09:28Z</time>
+      </trkpt>
+      <trkpt lat="47.2014896851033" lon="8.772034915164113">
+        <ele>423.02999999999997</ele>
+        <time>2016-01-03T12:09:29Z</time>
+      </trkpt>
+      <trkpt lat="47.20144324935973" lon="8.77200884744525">
+        <ele>422.26999999999998</ele>
+        <time>2016-01-03T12:09:31Z</time>
+      </trkpt>
+      <trkpt lat="47.201405949890614" lon="8.7720338255167">
+        <ele>421.35000000000002</ele>
+        <time>2016-01-03T12:09:42Z</time>
+      </trkpt>
+      <trkpt lat="47.20132657326758" lon="8.771982276812196">
+        <ele>421.75</ele>
+        <time>2016-01-03T12:10:04Z</time>
+      </trkpt>
+      <trkpt lat="47.20126815140247" lon="8.77192972227931">
+        <ele>421.48000000000002</ele>
+        <time>2016-01-03T12:10:23Z</time>
+      </trkpt>
+    </trkseg>
+  </trk>
+</gpx>
Index: /trunk/test/data/tracks/tracks-extensions.osm
===================================================================
--- /trunk/test/data/tracks/tracks-extensions.osm	(revision 15496)
+++ /trunk/test/data/tracks/tracks-extensions.osm	(revision 15496)
@@ -0,0 +1,1741 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version='0.6' upload='false' generator='JOSM'>
+  <node id='-102235' timestamp='2016-01-03T11:59:58Z' lat='47.1928684786' lon='8.79732714035'>
+    <tag k='gpx:ele' v='471.86000000000001' />
+    <tag k='gpx:time' v='2016-01-03T11:59:58Z' />
+  </node>
+  <node id='-102236' timestamp='2016-01-03T11:59:59Z' lat='47.19292195514' lon='8.79734247923'>
+    <tag k='gpx:ele' v='471.43000000000001' />
+    <tag k='gpx:time' v='2016-01-03T11:59:59Z' />
+  </node>
+  <node id='-102237' timestamp='2016-01-03T12:00:00Z' lat='47.19297501259' lon='8.79734423943'>
+    <tag k='gpx:ele' v='470.69' />
+    <tag k='gpx:time' v='2016-01-03T12:00:00Z' />
+  </node>
+  <node id='-102238' timestamp='2016-01-03T12:00:01Z' lat='47.19302739948' lon='8.79733258858'>
+    <tag k='gpx:ele' v='470.94' />
+    <tag k='gpx:time' v='2016-01-03T12:00:01Z' />
+  </node>
+  <node id='-102239' timestamp='2016-01-03T12:00:02Z' lat='47.19307341613' lon='8.79730744287'>
+    <tag k='gpx:ele' v='471.5' />
+    <tag k='gpx:time' v='2016-01-03T12:00:02Z' />
+  </node>
+  <node id='-102240' timestamp='2016-01-03T12:00:03Z' lat='47.19311348163' lon='8.79727299325'>
+    <tag k='gpx:ele' v='471.67000000000002' />
+    <tag k='gpx:time' v='2016-01-03T12:00:03Z' />
+  </node>
+  <node id='-102241' timestamp='2016-01-03T12:00:04Z' lat='47.19313560985' lon='8.79723242484'>
+    <tag k='gpx:ele' v='471.58999999999997' />
+    <tag k='gpx:time' v='2016-01-03T12:00:04Z' />
+  </node>
+  <node id='-102242' timestamp='2016-01-03T12:00:15Z' lat='47.19333660789' lon='8.79673864692'>
+    <tag k='gpx:ele' v='472.44999999999999' />
+    <tag k='gpx:time' v='2016-01-03T12:00:15Z' />
+  </node>
+  <node id='-102243' timestamp='2016-01-03T12:00:22Z' lat='47.19350483268' lon='8.7964047119'>
+    <tag k='gpx:ele' v='472.54000000000002' />
+    <tag k='gpx:time' v='2016-01-03T12:00:22Z' />
+  </node>
+  <node id='-102244' timestamp='2016-01-03T12:00:23Z' lat='47.19353936613' lon='8.79635970108'>
+    <tag k='gpx:ele' v='472.45999999999998' />
+    <tag k='gpx:time' v='2016-01-03T12:00:23Z' />
+  </node>
+  <node id='-102245' timestamp='2016-01-03T12:00:30Z' lat='47.19381898642' lon='8.79601738416'>
+    <tag k='gpx:ele' v='471.38' />
+    <tag k='gpx:time' v='2016-01-03T12:00:30Z' />
+  </node>
+  <node id='-102246' timestamp='2016-01-03T12:00:31Z' lat='47.19386676326' lon='8.79598528147'>
+    <tag k='gpx:ele' v='471.26999999999998' />
+    <tag k='gpx:time' v='2016-01-03T12:00:31Z' />
+  </node>
+  <node id='-102247' timestamp='2016-01-03T12:00:32Z' lat='47.19391797669' lon='8.79596809857'>
+    <tag k='gpx:ele' v='471.36000000000001' />
+    <tag k='gpx:time' v='2016-01-03T12:00:32Z' />
+  </node>
+  <node id='-102248' timestamp='2016-01-03T12:00:50Z' lat='47.19474418089' lon='8.79583658651'>
+    <tag k='gpx:ele' v='473.19999999999999' />
+    <tag k='gpx:time' v='2016-01-03T12:00:50Z' />
+  </node>
+  <node id='-102249' timestamp='2016-01-03T12:01:09Z' lat='47.19558698125' lon='8.79575042054'>
+    <tag k='gpx:ele' v='475.06' />
+    <tag k='gpx:time' v='2016-01-03T12:01:09Z' />
+  </node>
+  <node id='-102250' timestamp='2016-01-03T12:01:10Z' lat='47.19563358463' lon='8.79576902837'>
+    <tag k='gpx:ele' v='474.75' />
+    <tag k='gpx:time' v='2016-01-03T12:01:10Z' />
+  </node>
+  <node id='-102251' timestamp='2016-01-03T12:01:11Z' lat='47.19567717053' lon='8.79579568282'>
+    <tag k='gpx:ele' v='474.62' />
+    <tag k='gpx:time' v='2016-01-03T12:01:11Z' />
+  </node>
+  <node id='-102252' timestamp='2016-01-03T12:01:12Z' lat='47.19571597874' lon='8.79583046772'>
+    <tag k='gpx:ele' v='474.74000000000001' />
+    <tag k='gpx:time' v='2016-01-03T12:01:12Z' />
+  </node>
+  <node id='-102253' timestamp='2016-01-03T12:01:13Z' lat='47.19575093128' lon='8.79587598145'>
+    <tag k='gpx:ele' v='474.06' />
+    <tag k='gpx:time' v='2016-01-03T12:01:13Z' />
+  </node>
+  <node id='-102254' timestamp='2016-01-03T12:01:14Z' lat='47.19578169286' lon='8.79592711106'>
+    <tag k='gpx:ele' v='474' />
+    <tag k='gpx:time' v='2016-01-03T12:01:14Z' />
+  </node>
+  <node id='-102255' timestamp='2016-01-03T12:01:15Z' lat='47.19580834731' lon='8.79598083906'>
+    <tag k='gpx:ele' v='474.58999999999997' />
+    <tag k='gpx:time' v='2016-01-03T12:01:15Z' />
+  </node>
+  <node id='-102256' timestamp='2016-01-03T12:01:16Z' lat='47.19583324157' lon='8.7960360758'>
+    <tag k='gpx:ele' v='474.81999999999999' />
+    <tag k='gpx:time' v='2016-01-03T12:01:16Z' />
+  </node>
+  <node id='-102257' timestamp='2016-01-03T12:01:35Z' lat='47.19628603198' lon='8.79711063579'>
+    <tag k='gpx:ele' v='476.29000000000002' />
+    <tag k='gpx:time' v='2016-01-03T12:01:35Z' />
+  </node>
+  <node id='-102258' timestamp='2016-01-03T12:01:50Z' lat='47.19658995979' lon='8.79782611504'>
+    <tag k='gpx:ele' v='478.48000000000002' />
+    <tag k='gpx:time' v='2016-01-03T12:01:50Z' />
+  </node>
+  <node id='-102259' timestamp='2016-01-03T12:02:06Z' lat='47.19703386538' lon='8.79835601896'>
+    <tag k='gpx:ele' v='481.02999999999997' />
+    <tag k='gpx:time' v='2016-01-03T12:02:06Z' />
+  </node>
+  <node id='-102260' timestamp='2016-01-03T12:02:12Z' lat='47.19723687507' lon='8.79841879942'>
+    <tag k='gpx:ele' v='480' />
+    <tag k='gpx:time' v='2016-01-03T12:02:12Z' />
+  </node>
+  <node id='-102261' timestamp='2016-01-03T12:02:13Z' lat='47.19727886841' lon='8.79838845693'>
+    <tag k='gpx:ele' v='479.58999999999997' />
+    <tag k='gpx:time' v='2016-01-03T12:02:13Z' />
+  </node>
+  <node id='-102262' timestamp='2016-01-03T12:02:14Z' lat='47.1973154135' lon='8.79833975807'>
+    <tag k='gpx:ele' v='478.99000000000001' />
+    <tag k='gpx:time' v='2016-01-03T12:02:14Z' />
+  </node>
+  <node id='-102263' timestamp='2016-01-03T12:02:15Z' lat='47.19733335078' lon='8.79828276113'>
+    <tag k='gpx:ele' v='479.58999999999997' />
+    <tag k='gpx:time' v='2016-01-03T12:02:15Z' />
+  </node>
+  <node id='-102264' timestamp='2016-01-03T12:02:18Z' lat='47.19734919257' lon='8.79816164263'>
+    <tag k='gpx:ele' v='481.18000000000001' />
+    <tag k='gpx:time' v='2016-01-03T12:02:18Z' />
+  </node>
+  <node id='-102265' timestamp='2016-01-03T12:02:20Z' lat='47.19734827057' lon='8.79811889492'>
+    <tag k='gpx:ele' v='481.88' />
+    <tag k='gpx:time' v='2016-01-03T12:02:20Z' />
+  </node>
+  <node id='-102266' timestamp='2016-01-03T12:02:24Z' lat='47.19730585814' lon='8.79802887328'>
+    <tag k='gpx:ele' v='483.11000000000001' />
+    <tag k='gpx:time' v='2016-01-03T12:02:24Z' />
+  </node>
+  <node id='-102267' timestamp='2016-01-03T12:02:27Z' lat='47.19727643766' lon='8.79797455855'>
+    <tag k='gpx:ele' v='484.49000000000001' />
+    <tag k='gpx:time' v='2016-01-03T12:02:27Z' />
+  </node>
+  <node id='-102268' timestamp='2016-01-03T12:02:35Z' lat='47.19720158726' lon='8.79776844755'>
+    <tag k='gpx:ele' v='486.88' />
+    <tag k='gpx:time' v='2016-01-03T12:02:35Z' />
+  </node>
+  <node id='-102269' timestamp='2016-01-03T12:02:48Z' lat='47.19708633609' lon='8.79746401682'>
+    <tag k='gpx:ele' v='488.05000000000001' />
+    <tag k='gpx:time' v='2016-01-03T12:02:48Z' />
+  </node>
+  <node id='-102270' timestamp='2016-01-03T12:02:51Z' lat='47.1970700752' lon='8.79741758108'>
+    <tag k='gpx:ele' v='487.76999999999998' />
+    <tag k='gpx:time' v='2016-01-03T12:02:51Z' />
+  </node>
+  <node id='-102271' timestamp='2016-01-03T12:02:57Z' lat='47.19702917151' lon='8.79725052975'>
+    <tag k='gpx:ele' v='488.95999999999998' />
+    <tag k='gpx:time' v='2016-01-03T12:02:57Z' />
+  </node>
+  <node id='-102272' timestamp='2016-01-03T12:03:01Z' lat='47.19699899666' lon='8.79717215896'>
+    <tag k='gpx:ele' v='488.36000000000001' />
+    <tag k='gpx:time' v='2016-01-03T12:03:01Z' />
+  </node>
+  <node id='-102273' timestamp='2016-01-03T12:03:09Z' lat='47.19691224396' lon='8.79697803408'>
+    <tag k='gpx:ele' v='488.35000000000002' />
+    <tag k='gpx:time' v='2016-01-03T12:03:09Z' />
+  </node>
+  <node id='-102274' timestamp='2016-01-03T12:03:10Z' lat='47.19690545462' lon='8.79693126306'>
+    <tag k='gpx:ele' v='487.19' />
+    <tag k='gpx:time' v='2016-01-03T12:03:10Z' />
+  </node>
+  <node id='-102275' timestamp='2016-01-03T12:03:11Z' lat='47.19690595753' lon='8.79688667133'>
+    <tag k='gpx:ele' v='487.63999999999999' />
+    <tag k='gpx:time' v='2016-01-03T12:03:11Z' />
+  </node>
+  <node id='-102276' timestamp='2016-01-03T12:03:12Z' lat='47.19690511934' lon='8.79683738574'>
+    <tag k='gpx:ele' v='487.55000000000001' />
+    <tag k='gpx:time' v='2016-01-03T12:03:12Z' />
+  </node>
+  <node id='-102277' timestamp='2016-01-03T12:03:13Z' lat='47.19690562226' lon='8.79679371603'>
+    <tag k='gpx:ele' v='488.39999999999998' />
+    <tag k='gpx:time' v='2016-01-03T12:03:13Z' />
+  </node>
+  <node id='-102278' timestamp='2016-01-03T12:03:15Z' lat='47.19688760117' lon='8.79675113596'>
+    <tag k='gpx:ele' v='489.18000000000001' />
+    <tag k='gpx:time' v='2016-01-03T12:03:15Z' />
+  </node>
+  <node id='-102279' timestamp='2016-01-03T12:03:18Z' lat='47.19688927755' lon='8.79668936133'>
+    <tag k='gpx:ele' v='490.73000000000002' />
+    <tag k='gpx:time' v='2016-01-03T12:03:18Z' />
+  </node>
+  <node id='-102280' timestamp='2016-01-03T12:03:33Z' lat='47.19686815515' lon='8.79647453316'>
+    <tag k='gpx:ele' v='491.24000000000001' />
+    <tag k='gpx:time' v='2016-01-03T12:03:33Z' />
+  </node>
+  <node id='-102281' timestamp='2016-01-03T12:03:34Z' lat='47.19686932862' lon='8.79644243047'>
+    <tag k='gpx:ele' v='490.25' />
+    <tag k='gpx:time' v='2016-01-03T12:03:34Z' />
+  </node>
+  <node id='-102282' timestamp='2016-01-03T12:03:35Z' lat='47.19686849043' lon='8.79640663974'>
+    <tag k='gpx:ele' v='490.00999999999999' />
+    <tag k='gpx:time' v='2016-01-03T12:03:35Z' />
+  </node>
+  <node id='-102283' timestamp='2016-01-03T12:03:36Z' lat='47.19687301666' lon='8.7963681668'>
+    <tag k='gpx:ele' v='489.54000000000002' />
+    <tag k='gpx:time' v='2016-01-03T12:03:36Z' />
+  </node>
+  <node id='-102284' timestamp='2016-01-03T12:03:37Z' lat='47.19687905163' lon='8.79632961005'>
+    <tag k='gpx:ele' v='489.66000000000003' />
+    <tag k='gpx:time' v='2016-01-03T12:03:37Z' />
+  </node>
+  <node id='-102285' timestamp='2016-01-03T12:03:38Z' lat='47.19688676298' lon='8.79628074355'>
+    <tag k='gpx:ele' v='489.06' />
+    <tag k='gpx:time' v='2016-01-03T12:03:38Z' />
+  </node>
+  <node id='-102286' timestamp='2016-01-03T12:03:48Z' lat='47.1969577577' lon='8.79582912661'>
+    <tag k='gpx:ele' v='490.08999999999997' />
+    <tag k='gpx:time' v='2016-01-03T12:03:48Z' />
+  </node>
+  <node id='-102287' timestamp='2016-01-03T12:03:52Z' lat='47.19699287787' lon='8.79570951685'>
+    <tag k='gpx:ele' v='489.41000000000003' />
+    <tag k='gpx:time' v='2016-01-03T12:03:52Z' />
+  </node>
+  <node id='-102288' timestamp='2016-01-03T12:03:53Z' lat='47.1969855018' lon='8.79566760734'>
+    <tag k='gpx:ele' v='489.17000000000002' />
+    <tag k='gpx:time' v='2016-01-03T12:03:53Z' />
+  </node>
+  <node id='-102289' timestamp='2016-01-03T12:03:54Z' lat='47.19697644934' lon='8.79562460817'>
+    <tag k='gpx:ele' v='488.87' />
+    <tag k='gpx:time' v='2016-01-03T12:03:54Z' />
+  </node>
+  <node id='-102290' timestamp='2016-01-03T12:03:55Z' lat='47.19696890563' lon='8.79559032619'>
+    <tag k='gpx:ele' v='489.37' />
+    <tag k='gpx:time' v='2016-01-03T12:03:55Z' />
+  </node>
+  <node id='-102291' timestamp='2016-01-03T12:03:56Z' lat='47.19696664251' lon='8.79555839114'>
+    <tag k='gpx:ele' v='488.94999999999999' />
+    <tag k='gpx:time' v='2016-01-03T12:03:56Z' />
+  </node>
+  <node id='-102292' timestamp='2016-01-03T12:03:57Z' lat='47.19695256092' lon='8.79553676583'>
+    <tag k='gpx:ele' v='488.93000000000001' />
+    <tag k='gpx:time' v='2016-01-03T12:03:57Z' />
+  </node>
+  <node id='-102293' timestamp='2016-01-03T12:03:58Z' lat='47.19695650041' lon='8.79550768062'>
+    <tag k='gpx:ele' v='488.88999999999999' />
+    <tag k='gpx:time' v='2016-01-03T12:03:58Z' />
+  </node>
+  <node id='-102294' timestamp='2016-01-03T12:03:59Z' lat='47.19695859589' lon='8.79548110999'>
+    <tag k='gpx:ele' v='488.86000000000001' />
+    <tag k='gpx:time' v='2016-01-03T12:03:59Z' />
+  </node>
+  <node id='-102295' timestamp='2016-01-03T12:04:00Z' lat='47.19696907327' lon='8.7954525277'>
+    <tag k='gpx:ele' v='489.19999999999999' />
+    <tag k='gpx:time' v='2016-01-03T12:04:00Z' />
+  </node>
+  <node id='-102296' timestamp='2016-01-03T12:04:01Z' lat='47.19697988592' lon='8.79541271366'>
+    <tag k='gpx:ele' v='489.29000000000002' />
+    <tag k='gpx:time' v='2016-01-03T12:04:01Z' />
+  </node>
+  <node id='-102297' timestamp='2016-01-03T12:04:02Z' lat='47.196987262' lon='8.79535529763'>
+    <tag k='gpx:ele' v='488.95999999999998' />
+    <tag k='gpx:time' v='2016-01-03T12:04:02Z' />
+  </node>
+  <node id='-102298' timestamp='2016-01-03T12:04:03Z' lat='47.19698960893' lon='8.79530257545'>
+    <tag k='gpx:ele' v='489.10000000000002' />
+    <tag k='gpx:time' v='2016-01-03T12:04:03Z' />
+  </node>
+  <node id='-102299' timestamp='2016-01-03T12:04:14Z' lat='47.19690981321' lon='8.79494265653'>
+    <tag k='gpx:ele' v='492.19' />
+    <tag k='gpx:time' v='2016-01-03T12:04:14Z' />
+  </node>
+  <node id='-102300' timestamp='2016-01-03T12:04:25Z' lat='47.19696622342' lon='8.7945320271'>
+    <tag k='gpx:ele' v='492.12' />
+    <tag k='gpx:time' v='2016-01-03T12:04:25Z' />
+  </node>
+  <node id='-102301' timestamp='2016-01-03T12:04:26Z' lat='47.19697737135' lon='8.79450285807'>
+    <tag k='gpx:ele' v='493.06999999999999' />
+    <tag k='gpx:time' v='2016-01-03T12:04:26Z' />
+  </node>
+  <node id='-102302' timestamp='2016-01-03T12:04:27Z' lat='47.1969921235' lon='8.79445097409'>
+    <tag k='gpx:ele' v='492.58999999999997' />
+    <tag k='gpx:time' v='2016-01-03T12:04:27Z' />
+  </node>
+  <node id='-102303' timestamp='2016-01-03T12:04:28Z' lat='47.19699405134' lon='8.79439900629'>
+    <tag k='gpx:ele' v='492.38999999999999' />
+    <tag k='gpx:time' v='2016-01-03T12:04:28Z' />
+  </node>
+  <node id='-102304' timestamp='2016-01-03T12:04:29Z' lat='47.1969886031' lon='8.7943501398'>
+    <tag k='gpx:ele' v='492.94' />
+    <tag k='gpx:time' v='2016-01-03T12:04:29Z' />
+  </node>
+  <node id='-102305' timestamp='2016-01-03T12:04:30Z' lat='47.19698214903' lon='8.79429892637'>
+    <tag k='gpx:ele' v='492.47000000000003' />
+    <tag k='gpx:time' v='2016-01-03T12:04:30Z' />
+  </node>
+  <node id='-102306' timestamp='2016-01-03T12:04:31Z' lat='47.19697737135' lon='8.79424679093'>
+    <tag k='gpx:ele' v='492.50999999999999' />
+    <tag k='gpx:time' v='2016-01-03T12:04:31Z' />
+  </node>
+  <node id='-102307' timestamp='2016-01-03T12:04:32Z' lat='47.19698206522' lon='8.79418929107'>
+    <tag k='gpx:ele' v='492.73000000000002' />
+    <tag k='gpx:time' v='2016-01-03T12:04:32Z' />
+  </node>
+  <node id='-102308' timestamp='2016-01-03T12:04:33Z' lat='47.19698541798' lon='8.79413371906'>
+    <tag k='gpx:ele' v='492.63' />
+    <tag k='gpx:time' v='2016-01-03T12:04:33Z' />
+  </node>
+  <node id='-102309' timestamp='2016-01-03T12:04:34Z' lat='47.19698768109' lon='8.79407764412'>
+    <tag k='gpx:ele' v='493' />
+    <tag k='gpx:time' v='2016-01-03T12:04:34Z' />
+  </node>
+  <node id='-102310' timestamp='2016-01-03T12:04:35Z' lat='47.19699136913' lon='8.79402232356'>
+    <tag k='gpx:ele' v='493.00999999999999' />
+    <tag k='gpx:time' v='2016-01-03T12:04:35Z' />
+  </node>
+  <node id='-102311' timestamp='2016-01-03T12:04:36Z' lat='47.19698784873' lon='8.79397655837'>
+    <tag k='gpx:ele' v='493.19999999999999' />
+    <tag k='gpx:time' v='2016-01-03T12:04:36Z' />
+  </node>
+  <node id='-102312' timestamp='2016-01-03T12:04:37Z' lat='47.1969855018' lon='8.79392693751'>
+    <tag k='gpx:ele' v='493.18000000000001' />
+    <tag k='gpx:time' v='2016-01-03T12:04:37Z' />
+  </node>
+  <node id='-102313' timestamp='2016-01-03T12:04:38Z' lat='47.19698055647' lon='8.79388569854'>
+    <tag k='gpx:ele' v='493' />
+    <tag k='gpx:time' v='2016-01-03T12:04:38Z' />
+  </node>
+  <node id='-102314' timestamp='2016-01-03T12:04:39Z' lat='47.19698307104' lon='8.79383733496'>
+    <tag k='gpx:ele' v='493.20999999999998' />
+    <tag k='gpx:time' v='2016-01-03T12:04:39Z' />
+  </node>
+  <node id='-102315' timestamp='2016-01-03T12:04:40Z' lat='47.19699229114' lon='8.79378695972'>
+    <tag k='gpx:ele' v='493.11000000000001' />
+    <tag k='gpx:time' v='2016-01-03T12:04:40Z' />
+  </node>
+  <node id='-102316' timestamp='2016-01-03T12:04:41Z' lat='47.19699547626' lon='8.79374362528'>
+    <tag k='gpx:ele' v='493.30000000000001' />
+    <tag k='gpx:time' v='2016-01-03T12:04:41Z' />
+  </node>
+  <node id='-102317' timestamp='2016-01-03T12:04:42Z' lat='47.1970026847' lon='8.79369450733'>
+    <tag k='gpx:ele' v='493.50999999999999' />
+    <tag k='gpx:time' v='2016-01-03T12:04:42Z' />
+  </node>
+  <node id='-102318' timestamp='2016-01-03T12:04:50Z' lat='47.19700511545' lon='8.79335780628'>
+    <tag k='gpx:ele' v='493' />
+    <tag k='gpx:time' v='2016-01-03T12:04:50Z' />
+  </node>
+  <node id='-102319' timestamp='2016-01-03T12:04:51Z' lat='47.1970216278' lon='8.79331614822'>
+    <tag k='gpx:ele' v='492.37' />
+    <tag k='gpx:time' v='2016-01-03T12:04:51Z' />
+  </node>
+  <node id='-102320' timestamp='2016-01-03T12:04:52Z' lat='47.19704459421' lon='8.7932623364'>
+    <tag k='gpx:ele' v='492.30000000000001' />
+    <tag k='gpx:time' v='2016-01-03T12:04:52Z' />
+  </node>
+  <node id='-102321' timestamp='2016-01-03T12:04:53Z' lat='47.19706906937' lon='8.79320106469'>
+    <tag k='gpx:ele' v='492.04000000000002' />
+    <tag k='gpx:time' v='2016-01-03T12:04:53Z' />
+  </node>
+  <node id='-102322' timestamp='2016-01-03T12:04:54Z' lat='47.19708985649' lon='8.79312378354'>
+    <tag k='gpx:ele' v='491.37' />
+    <tag k='gpx:time' v='2016-01-03T12:04:54Z' />
+  </node>
+  <node id='-102323' timestamp='2016-01-03T12:04:55Z' lat='47.19710913487' lon='8.79304625094'>
+    <tag k='gpx:ele' v='491.06999999999999' />
+    <tag k='gpx:time' v='2016-01-03T12:04:55Z' />
+  </node>
+  <node id='-102324' timestamp='2016-01-03T12:04:56Z' lat='47.19713117927' lon='8.79297458567'>
+    <tag k='gpx:ele' v='490.39999999999998' />
+    <tag k='gpx:time' v='2016-01-03T12:04:56Z' />
+  </node>
+  <node id='-102325' timestamp='2016-01-03T12:04:58Z' lat='47.19718624838' lon='8.79280988127'>
+    <tag k='gpx:ele' v='489.75' />
+    <tag k='gpx:time' v='2016-01-03T12:04:58Z' />
+  </node>
+  <node id='-102326' timestamp='2016-01-03T12:04:59Z' lat='47.19720753841' lon='8.79271550104'>
+    <tag k='gpx:ele' v='489.87' />
+    <tag k='gpx:time' v='2016-01-03T12:04:59Z' />
+  </node>
+  <node id='-102327' timestamp='2016-01-03T12:05:00Z' lat='47.19722296111' lon='8.79262028262'>
+    <tag k='gpx:ele' v='488.95999999999998' />
+    <tag k='gpx:time' v='2016-01-03T12:05:00Z' />
+  </node>
+  <node id='-102328' timestamp='2016-01-03T12:05:06Z' lat='47.19733930193' lon='8.79204344004'>
+    <tag k='gpx:ele' v='485.85000000000002' />
+    <tag k='gpx:time' v='2016-01-03T12:05:06Z' />
+  </node>
+  <node id='-102329' timestamp='2016-01-03T12:05:11Z' lat='47.19745220616' lon='8.79151621833'>
+    <tag k='gpx:ele' v='482.81' />
+    <tag k='gpx:time' v='2016-01-03T12:05:11Z' />
+  </node>
+  <node id='-102330' timestamp='2016-01-03T12:05:12Z' lat='47.19745547511' lon='8.79138101824'>
+    <tag k='gpx:ele' v='481.99000000000001' />
+    <tag k='gpx:time' v='2016-01-03T12:05:12Z' />
+  </node>
+  <node id='-102331' lat='47.19749009237' lon='8.79095789976'>
+    <tag k='gpx:ele' v='478.92' />
+  </node>
+  <node id='-102332' lat='47.19753225334' lon='8.7905339431'>
+    <tag k='gpx:ele' v='476' />
+  </node>
+  <node id='-102333' timestamp='2016-01-03T12:05:23Z' lat='47.19762864523' lon='8.78988945857'>
+    <tag k='gpx:ele' v='474.38' />
+    <tag k='gpx:time' v='2016-01-03T12:05:23Z' />
+  </node>
+  <node id='-102334' timestamp='2016-01-03T12:05:24Z' lat='47.19763744622' lon='8.78979289904'>
+    <tag k='gpx:ele' v='474.35000000000002' />
+    <tag k='gpx:time' v='2016-01-03T12:05:24Z' />
+  </node>
+  <node id='-102335' timestamp='2016-01-03T12:05:25Z' lat='47.19764381647' lon='8.78972098231'>
+    <tag k='gpx:ele' v='474.12' />
+    <tag k='gpx:time' v='2016-01-03T12:05:25Z' />
+  </node>
+  <node id='-102336' timestamp='2016-01-03T12:05:33Z' lat='47.19764859416' lon='8.78936776891'>
+    <tag k='gpx:ele' v='472.52999999999997' />
+    <tag k='gpx:time' v='2016-01-03T12:05:33Z' />
+  </node>
+  <node id='-102337' timestamp='2016-01-03T12:05:34Z' lat='47.19765613787' lon='8.78931068815'>
+    <tag k='gpx:ele' v='472.75' />
+    <tag k='gpx:time' v='2016-01-03T12:05:34Z' />
+  </node>
+  <node id='-102338' timestamp='2016-01-03T12:05:37Z' lat='47.19769033603' lon='8.78910541534'>
+    <tag k='gpx:ele' v='472.19' />
+    <tag k='gpx:time' v='2016-01-03T12:05:37Z' />
+  </node>
+  <node id='-102339' timestamp='2016-01-03T12:05:38Z' lat='47.19770072959' lon='8.78903266042'>
+    <tag k='gpx:ele' v='471.92000000000002' />
+    <tag k='gpx:time' v='2016-01-03T12:05:38Z' />
+  </node>
+  <node id='-102340' timestamp='2016-01-03T12:05:41Z' lat='47.19771590084' lon='8.78876687028'>
+    <tag k='gpx:ele' v='471.98000000000002' />
+    <tag k='gpx:time' v='2016-01-03T12:05:41Z' />
+  </node>
+  <node id='-102341' timestamp='2016-01-03T12:05:47Z' lat='47.19775462523' lon='8.78843285143'>
+    <tag k='gpx:ele' v='473.49000000000001' />
+    <tag k='gpx:time' v='2016-01-03T12:05:47Z' />
+  </node>
+  <node id='-102342' timestamp='2016-01-03T12:05:48Z' lat='47.19777750783' lon='8.78841600381'>
+    <tag k='gpx:ele' v='473.44999999999999' />
+    <tag k='gpx:time' v='2016-01-03T12:05:48Z' />
+  </node>
+  <node id='-102343' timestamp='2016-01-03T12:05:49Z' lat='47.19780064188' lon='8.78840535879'>
+    <tag k='gpx:ele' v='473.45999999999998' />
+    <tag k='gpx:time' v='2016-01-03T12:05:49Z' />
+  </node>
+  <node id='-102344' timestamp='2016-01-03T12:05:53Z' lat='47.1979636699' lon='8.78838649951'>
+    <tag k='gpx:ele' v='470.27999999999997' />
+    <tag k='gpx:time' v='2016-01-03T12:05:53Z' />
+  </node>
+  <node id='-102345' timestamp='2016-01-03T12:05:57Z' lat='47.19813088886' lon='8.78829589114'>
+    <tag k='gpx:ele' v='467.20999999999998' />
+    <tag k='gpx:time' v='2016-01-03T12:05:57Z' />
+  </node>
+  <node id='-102346' timestamp='2016-01-03T12:05:58Z' lat='47.1981363371' lon='8.78826286644'>
+    <tag k='gpx:ele' v='466.89999999999998' />
+    <tag k='gpx:time' v='2016-01-03T12:05:58Z' />
+  </node>
+  <node id='-102347' timestamp='2016-01-03T12:05:59Z' lat='47.19812661409' lon='8.78822925501'>
+    <tag k='gpx:ele' v='466.76999999999998' />
+    <tag k='gpx:time' v='2016-01-03T12:05:59Z' />
+  </node>
+  <node id='-102348' timestamp='2016-01-03T12:06:00Z' lat='47.19810306095' lon='8.78818617202'>
+    <tag k='gpx:ele' v='466.25' />
+    <tag k='gpx:time' v='2016-01-03T12:06:00Z' />
+  </node>
+  <node id='-102349' timestamp='2016-01-03T12:06:01Z' lat='47.19808369875' lon='8.78812741488'>
+    <tag k='gpx:ele' v='465.23000000000002' />
+    <tag k='gpx:time' v='2016-01-03T12:06:01Z' />
+  </node>
+  <node id='-102350' timestamp='2016-01-03T12:06:02Z' lat='47.19807816669' lon='8.78805994056'>
+    <tag k='gpx:ele' v='464.12' />
+    <tag k='gpx:time' v='2016-01-03T12:06:02Z' />
+  </node>
+  <node id='-102351' timestamp='2016-01-03T12:06:03Z' lat='47.19808881171' lon='8.78799137659'>
+    <tag k='gpx:ele' v='463.68000000000001' />
+    <tag k='gpx:time' v='2016-01-03T12:06:03Z' />
+  </node>
+  <node id='-102352' timestamp='2016-01-03T12:06:04Z' lat='47.19811093993' lon='8.7879143469'>
+    <tag k='gpx:ele' v='462.5' />
+    <tag k='gpx:time' v='2016-01-03T12:06:04Z' />
+  </node>
+  <node id='-102353' timestamp='2016-01-03T12:06:05Z' lat='47.19815100543' lon='8.78783798777'>
+    <tag k='gpx:ele' v='462.45999999999998' />
+    <tag k='gpx:time' v='2016-01-03T12:06:05Z' />
+  </node>
+  <node id='-102354' timestamp='2016-01-03T12:06:06Z' lat='47.1981949266' lon='8.78775693476'>
+    <tag k='gpx:ele' v='461.56999999999999' />
+    <tag k='gpx:time' v='2016-01-03T12:06:06Z' />
+  </node>
+  <node id='-102355' timestamp='2016-01-03T12:06:08Z' lat='47.19828603789' lon='8.78758946434'>
+    <tag k='gpx:ele' v='461.14999999999998' />
+    <tag k='gpx:time' v='2016-01-03T12:06:08Z' />
+  </node>
+  <node id='-102356' timestamp='2016-01-03T12:06:09Z' lat='47.19831814058' lon='8.78749449737'>
+    <tag k='gpx:ele' v='460.19' />
+    <tag k='gpx:time' v='2016-01-03T12:06:09Z' />
+  </node>
+  <node id='-102357' timestamp='2016-01-03T12:06:10Z' lat='47.19833096489' lon='8.78738905303'>
+    <tag k='gpx:ele' v='459.83999999999997' />
+    <tag k='gpx:time' v='2016-01-03T12:06:10Z' />
+  </node>
+  <node id='-102358' timestamp='2016-01-03T12:06:11Z' lat='47.19833155163' lon='8.7872845307'>
+    <tag k='gpx:ele' v='460.49000000000001' />
+    <tag k='gpx:time' v='2016-01-03T12:06:11Z' />
+  </node>
+  <node id='-102359' timestamp='2016-01-03T12:06:12Z' lat='47.1983252652' lon='8.78718562424'>
+    <tag k='gpx:ele' v='460.23000000000002' />
+    <tag k='gpx:time' v='2016-01-03T12:06:12Z' />
+  </node>
+  <node id='-102360' timestamp='2016-01-03T12:06:22Z' lat='47.198242452' lon='8.78635254689'>
+    <tag k='gpx:ele' v='460.56999999999999' />
+    <tag k='gpx:time' v='2016-01-03T12:06:22Z' />
+  </node>
+  <node id='-102361' timestamp='2016-01-03T12:06:27Z' lat='47.19819274731' lon='8.78586145118'>
+    <tag k='gpx:ele' v='457.79000000000002' />
+    <tag k='gpx:time' v='2016-01-03T12:06:27Z' />
+  </node>
+  <node id='-102362' timestamp='2016-01-03T12:06:31Z' lat='47.19819249585' lon='8.78536943346'>
+    <tag k='gpx:ele' v='454.66000000000003' />
+    <tag k='gpx:time' v='2016-01-03T12:06:31Z' />
+  </node>
+  <node id='-102364' lat='47.18660652637' lon='8.79692137241'>
+    <tag k='gpx:ele' v='624.7421875' />
+  </node>
+  <node id='-102365' lat='47.1866440773' lon='8.79682481289'>
+    <tag k='gpx:ele' v='626.015625' />
+  </node>
+  <node id='-102366' lat='47.18669772148' lon='8.79671216011'>
+    <tag k='gpx:ele' v='627.0625' />
+  </node>
+  <node id='-102367' lat='47.1867620945' lon='8.79661023617'>
+    <tag k='gpx:ele' v='627.3671875' />
+  </node>
+  <node id='-102368' lat='47.18683719635' lon='8.79651904106'>
+    <tag k='gpx:ele' v='626.90234375' />
+  </node>
+  <node id='-102369' lat='47.1869122982' lon='8.79640102386'>
+    <tag k='gpx:ele' v='626.11328125' />
+  </node>
+  <node id='-102370' lat='47.18698740005' lon='8.79627764225'>
+    <tag k='gpx:ele' v='625.33203125' />
+  </node>
+  <node id='-102371' lat='47.18707859516' lon='8.79614889622'>
+    <tag k='gpx:ele' v='623.90625' />
+  </node>
+  <node id='-102372' lat='47.18710541725' lon='8.79609525204'>
+    <tag k='gpx:ele' v='623.66796875' />
+  </node>
+  <node id='-102373' lat='47.18712687492' lon='8.79603087902'>
+    <tag k='gpx:ele' v='623.71484375' />
+  </node>
+  <node id='-102374' lat='47.18713223934' lon='8.79597723484'>
+    <tag k='gpx:ele' v='623.75' />
+  </node>
+  <node id='-102375' lat='47.18713223934' lon='8.79592359066'>
+    <tag k='gpx:ele' v='623.9375' />
+  </node>
+  <node id='-102376' lat='47.18713223934' lon='8.79585921764'>
+    <tag k='gpx:ele' v='624.1640625' />
+  </node>
+  <node id='-102377' lat='47.18711078167' lon='8.79573583603'>
+    <tag k='gpx:ele' v='625.234375' />
+  </node>
+  <node id='-102378' lat='47.18710005283' lon='8.79560709'>
+    <tag k='gpx:ele' v='626' />
+  </node>
+  <node id='-102379' lat='47.18709468842' lon='8.79552125931'>
+    <tag k='gpx:ele' v='626.3515625' />
+  </node>
+  <node id='-102380' lat='47.18710541725' lon='8.79544079304'>
+    <tag k='gpx:ele' v='626.14453125' />
+  </node>
+  <node id='-102381' lat='47.18712687492' lon='8.79536032677'>
+    <tag k='gpx:ele' v='625.6640625' />
+  </node>
+  <node id='-102382' lat='47.18716442585' lon='8.79528522491'>
+    <tag k='gpx:ele' v='624.7890625' />
+  </node>
+  <node id='-102383' lat='47.18723416328' lon='8.79518330097'>
+    <tag k='gpx:ele' v='623.23046875' />
+  </node>
+  <node id='-102384' lat='47.18729317188' lon='8.79508674145'>
+    <tag k='gpx:ele' v='622.09375' />
+  </node>
+  <node id='-102385' lat='47.18736290932' lon='8.7949848175'>
+    <tag k='gpx:ele' v='620.9765625' />
+  </node>
+  <node id='-102386' lat='47.1874165535' lon='8.79490435123'>
+    <tag k='gpx:ele' v='620.23828125' />
+  </node>
+  <node id='-102387' lat='47.18746483326' lon='8.79484534264'>
+    <tag k='gpx:ele' v='619.42578125' />
+  </node>
+  <node id='-102388' lat='47.18752384186' lon='8.79479706287'>
+    <tag k='gpx:ele' v='617.7734375' />
+  </node>
+  <node id='-102389' lat='47.18756139278' lon='8.79474341869'>
+    <tag k='gpx:ele' v='616.8671875' />
+  </node>
+  <node id='-102390' lat='47.18759357929' lon='8.79469513893'>
+    <tag k='gpx:ele' v='616.09765625' />
+  </node>
+  <node id='-102391' lat='47.18760967255' lon='8.79463076591'>
+    <tag k='gpx:ele' v='615.87890625' />
+  </node>
+  <node id='-102392' lat='47.18762040138' lon='8.79455566406'>
+    <tag k='gpx:ele' v='615.3984375' />
+  </node>
+  <node id='-102393' lat='47.18763649464' lon='8.79448592663'>
+    <tag k='gpx:ele' v='614.76953125' />
+  </node>
+  <node id='-102394' lat='47.18767404556' lon='8.79440009594'>
+    <tag k='gpx:ele' v='613.47265625' />
+  </node>
+  <node id='-102395' lat='47.18769550323' lon='8.79430890083'>
+    <tag k='gpx:ele' v='612.72265625' />
+  </node>
+  <node id='-102396' lat='47.18770086765' lon='8.79418551922'>
+    <tag k='gpx:ele' v='612.4609375' />
+  </node>
+  <node id='-102397' lat='47.18770086765' lon='8.79407823086'>
+    <tag k='gpx:ele' v='611.85546875' />
+  </node>
+  <node id='-102398' lat='47.1876847744' lon='8.79399776459'>
+    <tag k='gpx:ele' v='611.90625' />
+  </node>
+  <node id='-102399' lat='47.18766331673' lon='8.79393339157'>
+    <tag k='gpx:ele' v='612.27734375' />
+  </node>
+  <node id='-102400' lat='47.18761503696' lon='8.79386901855'>
+    <tag k='gpx:ele' v='613.66796875' />
+  </node>
+  <node id='-102401' lat='47.18758285046' lon='8.79381537437'>
+    <tag k='gpx:ele' v='614.62890625' />
+  </node>
+  <node id='-102402' lat='47.1875667572' lon='8.79376709461'>
+    <tag k='gpx:ele' v='615.0703125' />
+  </node>
+  <node id='-102403' lat='47.18757212162' lon='8.79371345043'>
+    <tag k='gpx:ele' v='614.72265625' />
+  </node>
+  <node id='-102404' lat='47.18758821487' lon='8.79368126392'>
+    <tag k='gpx:ele' v='614.26171875' />
+  </node>
+  <node id='-102405' lat='47.18764185905' lon='8.79368126392'>
+    <tag k='gpx:ele' v='612.06640625' />
+  </node>
+  <node id='-102406' lat='47.18770086765' lon='8.79370808601'>
+    <tag k='gpx:ele' v='609.6875' />
+  </node>
+  <node id='-102407' lat='47.18778133392' lon='8.79375100136'>
+    <tag k='gpx:ele' v='606.83984375' />
+  </node>
+  <node id='-102408' lat='47.18785107136' lon='8.79380464554'>
+    <tag k='gpx:ele' v='604.671875' />
+  </node>
+  <node id='-102409' lat='47.18792080879' lon='8.79384219646'>
+    <tag k='gpx:ele' v='602.52734375' />
+  </node>
+  <node id='-102410' lat='47.18800127506' lon='8.7939119339'>
+    <tag k='gpx:ele' v='600.78515625' />
+  </node>
+  <node id='-102411' lat='47.18811392784' lon='8.79401385784'>
+    <tag k='gpx:ele' v='598.078125' />
+  </node>
+  <node id='-102412' lat='47.18815147877' lon='8.7940621376'>
+    <tag k='gpx:ele' v='597.1953125' />
+  </node>
+  <node id='-102413' lat='47.18818902969' lon='8.79415333271'>
+    <tag k='gpx:ele' v='596.5234375' />
+  </node>
+  <node id='-102414' lat='47.18821585178' lon='8.7942391634'>
+    <tag k='gpx:ele' v='595.74609375' />
+  </node>
+  <node id='-102415' lat='47.18824267387' lon='8.79435181618'>
+    <tag k='gpx:ele' v='594.82421875' />
+  </node>
+  <node id='-102416' lat='47.18826413155' lon='8.79442691803'>
+    <tag k='gpx:ele' v='594.10546875' />
+  </node>
+  <node id='-102417' lat='47.18829095364' lon='8.79447519779'>
+    <tag k='gpx:ele' v='593.2109375' />
+  </node>
+  <node id='-102418' lat='47.18830704689' lon='8.79452347755'>
+    <tag k='gpx:ele' v='592.6875' />
+  </node>
+  <node id='-102419' lat='47.18831241131' lon='8.79461467266'>
+    <tag k='gpx:ele' v='592.5390625' />
+  </node>
+  <node id='-102420' lat='47.18830704689' lon='8.79479706287'>
+    <tag k='gpx:ele' v='592.7578125' />
+  </node>
+  <node id='-102421' lat='47.18830704689' lon='8.79488825798'>
+    <tag k='gpx:ele' v='592.77734375' />
+  </node>
+  <node id='-102422' lat='47.18831241131' lon='8.79494190216'>
+    <tag k='gpx:ele' v='592.63671875' />
+  </node>
+  <node id='-102423' lat='47.18833386898' lon='8.79499554634'>
+    <tag k='gpx:ele' v='592.06640625' />
+  </node>
+  <node id='-102424' lat='47.18836605549' lon='8.79505991936'>
+    <tag k='gpx:ele' v='591.2578125' />
+  </node>
+  <node id='-102425' lat='47.18840360641' lon='8.79511356354'>
+    <tag k='gpx:ele' v='590.46875' />
+  </node>
+  <node id='-102426' lat='47.18843579292' lon='8.79516720772'>
+    <tag k='gpx:ele' v='589.7578125' />
+  </node>
+  <node id='-102427' lat='47.18845188618' lon='8.79522621632'>
+    <tag k='gpx:ele' v='589.359375' />
+  </node>
+  <node id='-102428' lat='47.18846261501' lon='8.79529058933'>
+    <tag k='gpx:ele' v='589.05859375' />
+  </node>
+  <node id='-102429' lat='47.18845188618' lon='8.79535496235'>
+    <tag k='gpx:ele' v='589.21875' />
+  </node>
+  <node id='-102430' lat='47.1884304285' lon='8.79545152187'>
+    <tag k='gpx:ele' v='589.59375' />
+  </node>
+  <node id='-102431' lat='47.18840897083' lon='8.79556417465'>
+    <tag k='gpx:ele' v='589.98046875' />
+  </node>
+  <node id='-102432' lat='47.18840360641' lon='8.79565536976'>
+    <tag k='gpx:ele' v='589.51953125' />
+  </node>
+  <node id='-102433' lat='47.18840897083' lon='8.79574656487'>
+    <tag k='gpx:ele' v='588.796875' />
+  </node>
+  <node id='-102434' lat='47.18843579292' lon='8.79585921764'>
+    <tag k='gpx:ele' v='587.4375' />
+  </node>
+  <node id='-102435' lat='47.18847870827' lon='8.79597187042'>
+    <tag k='gpx:ele' v='585.70703125' />
+  </node>
+  <node id='-102436' lat='47.18850553036' lon='8.79605233669'>
+    <tag k='gpx:ele' v='584.48046875' />
+  </node>
+  <node id='-102437' lat='47.18852162361' lon='8.79613280296'>
+    <tag k='gpx:ele' v='583.328125' />
+  </node>
+  <node id='-102438' lat='47.18852162361' lon='8.79619717598'>
+    <tag k='gpx:ele' v='582.69921875' />
+  </node>
+  <node id='-102439' lat='47.18851625919' lon='8.79628300667'>
+    <tag k='gpx:ele' v='581.96875' />
+  </node>
+  <node id='-102440' lat='47.18850016594' lon='8.79637956619'>
+    <tag k='gpx:ele' v='581.3359375' />
+  </node>
+  <node id='-102441' lat='47.1884894371' lon='8.79646539688'>
+    <tag k='gpx:ele' v='580.6796875' />
+  </node>
+  <node id='-102442' lat='47.1884894371' lon='8.79652440548'>
+    <tag k='gpx:ele' v='580.33984375' />
+  </node>
+  <node id='-102443' lat='47.18850016594' lon='8.79657804966'>
+    <tag k='gpx:ele' v='580.0234375' />
+  </node>
+  <node id='-102444' lat='47.18852162361' lon='8.79663169384'>
+    <tag k='gpx:ele' v='579.5078125' />
+  </node>
+  <node id='-102445' lat='47.1885484457' lon='8.79668533802'>
+    <tag k='gpx:ele' v='578.890625' />
+  </node>
+  <node id='-102446' lat='47.18856990337' lon='8.79674971104'>
+    <tag k='gpx:ele' v='578.34375' />
+  </node>
+  <node id='-102447' lat='47.18858063221' lon='8.79681944847'>
+    <tag k='gpx:ele' v='577.984375' />
+  </node>
+  <node id='-102448' lat='47.18857526779' lon='8.79689991474'>
+    <tag k='gpx:ele' v='577.90234375' />
+  </node>
+  <node id='-102449' lat='47.18858599663' lon='8.79699110985'>
+    <tag k='gpx:ele' v='577.50390625' />
+  </node>
+  <node id='-102450' lat='47.18859672546' lon='8.79704475403'>
+    <tag k='gpx:ele' v='577.20703125' />
+  </node>
+  <node id='-102451' lat='47.18862354755' lon='8.79711985588'>
+    <tag k='gpx:ele' v='576.6171875' />
+  </node>
+  <node id='-102452' lat='47.1886664629' lon='8.79718959332'>
+    <tag k='gpx:ele' v='575.82421875' />
+  </node>
+  <node id='-102453' lat='47.18870937824' lon='8.79721105099'>
+    <tag k='gpx:ele' v='575.125' />
+  </node>
+  <node id='-102454' lat='47.18871474266' lon='8.79715740681'>
+    <tag k='gpx:ele' v='575.0546875' />
+  </node>
+  <node id='-102455' lat='47.1887254715' lon='8.79705548286'>
+    <tag k='gpx:ele' v='574.89453125' />
+  </node>
+  <node id='-102456' lat='47.18873620033' lon='8.79693746567'>
+    <tag k='gpx:ele' v='574.75' />
+  </node>
+  <node id='-102457' lat='47.188757658' lon='8.79681408405'>
+    <tag k='gpx:ele' v='574.6484375' />
+  </node>
+  <node id='-102458' lat='47.18879520893' lon='8.79668533802'>
+    <tag k='gpx:ele' v='574.26953125' />
+  </node>
+  <node id='-102459' lat='47.18883812428' lon='8.7965887785'>
+    <tag k='gpx:ele' v='573.72265625' />
+  </node>
+  <node id='-102460' lat='47.18890786171' lon='8.79643857479'>
+    <tag k='gpx:ele' v='572.4296875' />
+  </node>
+  <node id='-102461' lat='47.18901515007' lon='8.79624009132'>
+    <tag k='gpx:ele' v='570.828125' />
+  </node>
+  <node id='-102462' lat='47.18906342983' lon='8.79615426064'>
+    <tag k='gpx:ele' v='570.1015625' />
+  </node>
+  <node id='-102463' lat='47.18915462494' lon='8.79598796368'>
+    <tag k='gpx:ele' v='568.7734375' />
+  </node>
+  <node id='-102464' lat='47.18921899796' lon='8.79586994648'>
+    <tag k='gpx:ele' v='567.8125' />
+  </node>
+  <node id='-102465' lat='47.1892619133' lon='8.79577875137'>
+    <tag k='gpx:ele' v='567.25390625' />
+  </node>
+  <node id='-102466' lat='47.18928337097' lon='8.79571437836'>
+    <tag k='gpx:ele' v='567.09765625' />
+  </node>
+  <node id='-102467' lat='47.18929409981' lon='8.79566073418'>
+    <tag k='gpx:ele' v='567.1640625' />
+  </node>
+  <node id='-102468' lat='47.18929946423' lon='8.79558026791'>
+    <tag k='gpx:ele' v='567.546875' />
+  </node>
+  <node id='-102469' lat='47.18929946423' lon='8.79545152187'>
+    <tag k='gpx:ele' v='567.86328125' />
+  </node>
+  <node id='-102470' lat='47.18929409981' lon='8.795312047'>
+    <tag k='gpx:ele' v='568.2890625' />
+  </node>
+  <node id='-102471' lat='47.18929409981' lon='8.79521012306'>
+    <tag k='gpx:ele' v='568.49609375' />
+  </node>
+  <node id='-102472' lat='47.18930482864' lon='8.79513502121'>
+    <tag k='gpx:ele' v='568.33203125' />
+  </node>
+  <node id='-102473' lat='47.18934237957' lon='8.79490435123'>
+    <tag k='gpx:ele' v='566.84765625' />
+  </node>
+  <node id='-102474' lat='47.18934774399' lon='8.79484534264'>
+    <tag k='gpx:ele' v='566.609375' />
+  </node>
+  <node id='-102475' lat='47.18933701515' lon='8.79473805428'>
+    <tag k='gpx:ele' v='566.94140625' />
+  </node>
+  <node id='-102476' lat='47.18933701515' lon='8.79465758801'>
+    <tag k='gpx:ele' v='566.88671875' />
+  </node>
+  <node id='-102477' lat='47.18935310841' lon='8.79457712173'>
+    <tag k='gpx:ele' v='566.27734375' />
+  </node>
+  <node id='-102478' lat='47.18937456608' lon='8.79450201988'>
+    <tag k='gpx:ele' v='565.48046875' />
+  </node>
+  <node id='-102479' lat='47.18942821026' lon='8.79438400269'>
+    <tag k='gpx:ele' v='563.5' />
+  </node>
+  <node id='-102480' lat='47.18945503235' lon='8.79430353642'>
+    <tag k='gpx:ele' v='562.51953125' />
+  </node>
+  <node id='-102481' lat='47.1894711256' lon='8.79420697689'>
+    <tag k='gpx:ele' v='561.9453125' />
+  </node>
+  <node id='-102482' lat='47.18948185444' lon='8.79407286644'>
+    <tag k='gpx:ele' v='561.85546875' />
+  </node>
+  <node id='-102483' lat='47.18949794769' lon='8.7939119339'>
+    <tag k='gpx:ele' v='561.7578125' />
+  </node>
+  <node id='-102484' lat='47.18950867653' lon='8.79378855228'>
+    <tag k='gpx:ele' v='561.765625' />
+  </node>
+  <node id='-102485' lat='47.18952476978' lon='8.79368662834'>
+    <tag k='gpx:ele' v='561.453125' />
+  </node>
+  <node id='-102486' lat='47.18955159187' lon='8.79356861115'>
+    <tag k='gpx:ele' v='560.6015625' />
+  </node>
+  <node id='-102487' lat='47.18958377838' lon='8.7934666872'>
+    <tag k='gpx:ele' v='559.65234375' />
+  </node>
+  <node id='-102488' lat='47.18961596489' lon='8.79338622093'>
+    <tag k='gpx:ele' v='558.7578125' />
+  </node>
+  <node id='-102489' lat='47.18965888023' lon='8.79327893257'>
+    <tag k='gpx:ele' v='557.66015625' />
+  </node>
+  <node id='-102490' lat='47.18971252441' lon='8.79318773746'>
+    <tag k='gpx:ele' v='556.35546875' />
+  </node>
+  <node id='-102491' lat='47.18976080418' lon='8.79311800003'>
+    <tag k='gpx:ele' v='555.2265625' />
+  </node>
+  <node id='-102492' lat='47.18983054161' lon='8.7930482626'>
+    <tag k='gpx:ele' v='553.53125' />
+  </node>
+  <node id='-102493' lat='47.18992173672' lon='8.79296243191'>
+    <tag k='gpx:ele' v='551.265625' />
+  </node>
+  <node id='-102494' lat='47.1899753809' lon='8.79290342331'>
+    <tag k='gpx:ele' v='549.92578125' />
+  </node>
+  <node id='-102495' lat='47.19000756741' lon='8.79285514355'>
+    <tag k='gpx:ele' v='549.140625' />
+  </node>
+  <node id='-102496' lat='47.1900343895' lon='8.79278004169'>
+    <tag k='gpx:ele' v='548.48828125' />
+  </node>
+  <node id='-102497' lat='47.19004511833' lon='8.79272639751'>
+    <tag k='gpx:ele' v='548.0078125' />
+  </node>
+  <node id='-102498' lat='47.19005584717' lon='8.79263520241'>
+    <tag k='gpx:ele' v='547.39453125' />
+  </node>
+  <node id='-102499' lat='47.19005584717' lon='8.79256546497'>
+    <tag k='gpx:ele' v='547.15234375' />
+  </node>
+  <node id='-102500' lat='47.19005048275' lon='8.79250109196'>
+    <tag k='gpx:ele' v='547.08203125' />
+  </node>
+  <node id='-102501' lat='47.19001829624' lon='8.79236698151'>
+    <tag k='gpx:ele' v='547.55078125' />
+  </node>
+  <node id='-102502' lat='47.18994319439' lon='8.79210412502'>
+    <tag k='gpx:ele' v='548.69921875' />
+  </node>
+  <node id='-102503' lat='47.18993246555' lon='8.79203438759'>
+    <tag k='gpx:ele' v='548.76953125' />
+  </node>
+  <node id='-102504' lat='47.18993246555' lon='8.79197001457'>
+    <tag k='gpx:ele' v='548.51953125' />
+  </node>
+  <node id='-102505' lat='47.18994319439' lon='8.79190027714'>
+    <tag k='gpx:ele' v='547.88671875' />
+  </node>
+  <node id='-102506' lat='47.18997001648' lon='8.7918305397'>
+    <tag k='gpx:ele' v='546.7265625' />
+  </node>
+  <node id='-102507' lat='47.19000220299' lon='8.79175543785'>
+    <tag k='gpx:ele' v='545.3984375' />
+  </node>
+  <node id='-102508' lat='47.19003975391' lon='8.791680336'>
+    <tag k='gpx:ele' v='543.87890625' />
+  </node>
+  <node id='-102509' lat='47.19012022018' lon='8.79153549671'>
+    <tag k='gpx:ele' v='540.6484375' />
+  </node>
+  <node id='-102510' lat='47.19023287296' lon='8.7912940979'>
+    <tag k='gpx:ele' v='536.4296875' />
+  </node>
+  <node id='-102511' lat='47.19025433064' lon='8.79122436047'>
+    <tag k='gpx:ele' v='536.046875' />
+  </node>
+  <node id='-102512' lat='47.19027042389' lon='8.79114925861'>
+    <tag k='gpx:ele' v='535.765625' />
+  </node>
+  <node id='-102513' lat='47.19027578831' lon='8.79101514816'>
+    <tag k='gpx:ele' v='535.71875' />
+  </node>
+  <node id='-102514' lat='47.19027578831' lon='8.79076838493'>
+    <tag k='gpx:ele' v='535.55859375' />
+  </node>
+  <node id='-102515' lat='47.19026505947' lon='8.79043579102'>
+    <tag k='gpx:ele' v='535.359375' />
+  </node>
+  <node id='-102516' lat='47.19025969505' lon='8.7901622057'>
+    <tag k='gpx:ele' v='534.5234375' />
+  </node>
+  <node id='-102517' lat='47.19025969505' lon='8.78992080688'>
+    <tag k='gpx:ele' v='534.2578125' />
+  </node>
+  <node id='-102518' lat='47.19025433064' lon='8.78967404366'>
+    <tag k='gpx:ele' v='535.1328125' />
+  </node>
+  <node id='-102519' lat='47.19025433064' lon='8.78955602646'>
+    <tag k='gpx:ele' v='535.46875' />
+  </node>
+  <node id='-102520' lat='47.19025433064' lon='8.78949165344'>
+    <tag k='gpx:ele' v='535.04296875' />
+  </node>
+  <node id='-102521' lat='47.19027042389' lon='8.78943800926'>
+    <tag k='gpx:ele' v='534.04296875' />
+  </node>
+  <node id='-102522' lat='47.19030797482' lon='8.78938436508'>
+    <tag k='gpx:ele' v='532.234375' />
+  </node>
+  <node id='-102523' lat='47.19035625458' lon='8.78935754299'>
+    <tag k='gpx:ele' v='530.2109375' />
+  </node>
+  <node id='-102524' lat='47.1903938055' lon='8.78935754299'>
+    <tag k='gpx:ele' v='528.7890625' />
+  </node>
+  <node id='-102525' lat='47.19042599201' lon='8.78937363625'>
+    <tag k='gpx:ele' v='527.69140625' />
+  </node>
+  <node id='-102526' lat='47.19045817852' lon='8.78941118717'>
+    <tag k='gpx:ele' v='526.76171875' />
+  </node>
+  <node id='-102527' lat='47.19048500061' lon='8.78945946693'>
+    <tag k='gpx:ele' v='526.1171875' />
+  </node>
+  <node id='-102528' lat='47.19050645828' lon='8.78952920437'>
+    <tag k='gpx:ele' v='525.83984375' />
+  </node>
+  <node id='-102529' lat='47.19052255154' lon='8.78960967064'>
+    <tag k='gpx:ele' v='525.51171875' />
+  </node>
+  <node id='-102530' lat='47.19053328037' lon='8.78972768784'>
+    <tag k='gpx:ele' v='525.34375' />
+  </node>
+  <node id='-102531' lat='47.19054400921' lon='8.78982961178'>
+    <tag k='gpx:ele' v='525.18359375' />
+  </node>
+  <node id='-102532' lat='47.19058692455' lon='8.79002273083'>
+    <tag k='gpx:ele' v='524.3515625' />
+  </node>
+  <node id='-102533' lat='47.19063520432' lon='8.79024267197'>
+    <tag k='gpx:ele' v='524.41015625' />
+  </node>
+  <node id='-102534' lat='47.19067275524' lon='8.79039824009'>
+    <tag k='gpx:ele' v='524.47265625' />
+  </node>
+  <node id='-102535' lat='47.19072639942' lon='8.79054844379'>
+    <tag k='gpx:ele' v='524.02734375' />
+  </node>
+  <node id='-102536' lat='47.1907800436' lon='8.79067718983'>
+    <tag k='gpx:ele' v='523.09375' />
+  </node>
+  <node id='-102537' lat='47.19083368778' lon='8.79082202911'>
+    <tag k='gpx:ele' v='521.92578125' />
+  </node>
+  <node id='-102538' lat='47.19087660313' lon='8.79096150398'>
+    <tag k='gpx:ele' v='520.87109375' />
+  </node>
+  <node id='-102539' lat='47.19090878963' lon='8.79109561443'>
+    <tag k='gpx:ele' v='520.51953125' />
+  </node>
+  <node id='-102540' lat='47.19093561172' lon='8.79119217396'>
+    <tag k='gpx:ele' v='520.2578125' />
+  </node>
+  <node id='-102541' lat='47.19097316265' lon='8.79126727581'>
+    <tag k='gpx:ele' v='519.6640625' />
+  </node>
+  <node id='-102542' lat='47.19103217125' lon='8.79133701324'>
+    <tag k='gpx:ele' v='518.5703125' />
+  </node>
+  <node id='-102543' lat='47.19111263752' lon='8.79140138626'>
+    <tag k='gpx:ele' v='517.04296875' />
+  </node>
+  <node id='-102544' lat='47.1912842989' lon='8.79152476788'>
+    <tag k='gpx:ele' v='513.03125' />
+  </node>
+  <node id='-102545' lat='47.19140768051' lon='8.79161059856'>
+    <tag k='gpx:ele' v='510.19921875' />
+  </node>
+  <node id='-102546' lat='47.19148814678' lon='8.79166960716'>
+    <tag k='gpx:ele' v='508.5' />
+  </node>
+  <node id='-102547' lat='47.19152033329' lon='8.79169642925'>
+    <tag k='gpx:ele' v='507.8828125' />
+  </node>
+  <node id='-102548' lat='47.19157934189' lon='8.7917393446'>
+    <tag k='gpx:ele' v='506.71875' />
+  </node>
+  <node id='-102549' lat='47.19162762165' lon='8.7917983532'>
+    <tag k='gpx:ele' v='506.03125' />
+  </node>
+  <node id='-102550' lat='47.19165980816' lon='8.79185199738'>
+    <tag k='gpx:ele' v='505.5390625' />
+  </node>
+  <node id='-102551' lat='47.19168663025' lon='8.79191637039'>
+    <tag k='gpx:ele' v='504.96875' />
+  </node>
+  <node id='-102552' lat='47.19171881676' lon='8.79201829433'>
+    <tag k='gpx:ele' v='504.28125' />
+  </node>
+  <node id='-102553' lat='47.19175100327' lon='8.79214167595'>
+    <tag k='gpx:ele' v='503.6640625' />
+  </node>
+  <node id='-102554' lat='47.19179928303' lon='8.79229724407'>
+    <tag k='gpx:ele' v='502.578125' />
+  </node>
+  <node id='-102555' lat='47.19184219837' lon='8.79245817661'>
+    <tag k='gpx:ele' v='500.921875' />
+  </node>
+  <node id='-102556' lat='47.19186902046' lon='8.79257082939'>
+    <tag k='gpx:ele' v='499.85546875' />
+  </node>
+  <node id='-102557' lat='47.1918797493' lon='8.7926620245'>
+    <tag k='gpx:ele' v='499.40234375' />
+  </node>
+  <node id='-102558' lat='47.19189047813' lon='8.79276394844'>
+    <tag k='gpx:ele' v='498.96875' />
+  </node>
+  <node id='-102559' lat='47.19189584255' lon='8.79288733006'>
+    <tag k='gpx:ele' v='497.8828125' />
+  </node>
+  <node id='-102560' lat='47.19189584255' lon='8.79306435585'>
+    <tag k='gpx:ele' v='496.2265625' />
+  </node>
+  <node id='-102561' lat='47.19190120697' lon='8.79318237305'>
+    <tag k='gpx:ele' v='494.9609375' />
+  </node>
+  <node id='-102562' lat='47.19190657139' lon='8.7932574749'>
+    <tag k='gpx:ele' v='494.13671875' />
+  </node>
+  <node id='-102563' lat='47.19192802906' lon='8.79334330559'>
+    <tag k='gpx:ele' v='493.6015625' />
+  </node>
+  <node id='-102564' lat='47.19196021557' lon='8.79347205162'>
+    <tag k='gpx:ele' v='492.828125' />
+  </node>
+  <node id='-102565' lat='47.19199282117' lon='8.79361672327'>
+    <tag k='gpx:ele' v='492.1015625' />
+  </node>
+  <node id='-102566' lat='47.19200849533' lon='8.79368662834'>
+    <tag k='gpx:ele' v='491.76953125' />
+  </node>
+  <node id='-102567' lat='47.19204068184' lon='8.7938529253'>
+    <tag k='gpx:ele' v='490.83984375' />
+  </node>
+  <node id='-102568' lat='47.19206213951' lon='8.79399240017'>
+    <tag k='gpx:ele' v='490.23828125' />
+  </node>
+  <node id='-102569' lat='47.19207286835' lon='8.79405140877'>
+    <tag k='gpx:ele' v='489.96484375' />
+  </node>
+  <node id='-102570' lat='47.19208359718' lon='8.79414796829'>
+    <tag k='gpx:ele' v='489.703125' />
+  </node>
+  <node id='-102571' lat='47.19212114811' lon='8.79500091076'>
+    <tag k='gpx:ele' v='484.7109375' />
+  </node>
+  <node id='-102572' lat='47.19213724136' lon='8.79530131817'>
+    <tag k='gpx:ele' v='482.328125' />
+  </node>
+  <node id='-102573' lat='47.19213724136' lon='8.79545152187'>
+    <tag k='gpx:ele' v='481.04296875' />
+  </node>
+  <node id='-102574' lat='47.19213724136' lon='8.79553735256'>
+    <tag k='gpx:ele' v='480.3046875' />
+  </node>
+  <node id='-102575' lat='47.19212651253' lon='8.79560709'>
+    <tag k='gpx:ele' v='479.70703125' />
+  </node>
+  <node id='-102576' lat='47.19211041927' lon='8.79568219185'>
+    <tag k='gpx:ele' v='478.984375' />
+  </node>
+  <node id='-102577' lat='47.1920889616' lon='8.79574656487'>
+    <tag k='gpx:ele' v='478.4609375' />
+  </node>
+  <node id='-102578' lat='47.19203531742' lon='8.79583239555'>
+    <tag k='gpx:ele' v='479.1015625' />
+  </node>
+  <node id='-102579' lat='47.19198167324' lon='8.79589676857'>
+    <tag k='gpx:ele' v='480.359375' />
+  </node>
+  <node id='-102580' lat='47.19194948673' lon='8.7959343195'>
+    <tag k='gpx:ele' v='481.19140625' />
+  </node>
+  <node id='-102581' lat='47.19190657139' lon='8.79599332809'>
+    <tag k='gpx:ele' v='482.2890625' />
+  </node>
+  <node id='-102582' lat='47.19186902046' lon='8.79606306553'>
+    <tag k='gpx:ele' v='483.28125' />
+  </node>
+  <node id='-102583' lat='47.19184756279' lon='8.79613816738'>
+    <tag k='gpx:ele' v='483.69921875' />
+  </node>
+  <node id='-102584' lat='47.19184219837' lon='8.79621326923'>
+    <tag k='gpx:ele' v='483.4609375' />
+  </node>
+  <node id='-102585' lat='47.19184219837' lon='8.79628300667'>
+    <tag k='gpx:ele' v='483.0390625' />
+  </node>
+  <node id='-102586' lat='47.19185829163' lon='8.79637420177'>
+    <tag k='gpx:ele' v='481.9140625' />
+  </node>
+  <node id='-102587' lat='47.19188511372' lon='8.79645466805'>
+    <tag k='gpx:ele' v='480.515625' />
+  </node>
+  <node id='-102588' lat='47.19191730022' lon='8.79651367664'>
+    <tag k='gpx:ele' v='479.16796875' />
+  </node>
+  <node id='-102589' lat='47.19198703766' lon='8.79663169384'>
+    <tag k='gpx:ele' v='476.74609375' />
+  </node>
+  <node id='-102590' lat='47.19206750393' lon='8.79676043987'>
+    <tag k='gpx:ele' v='474.3515625' />
+  </node>
+  <node id='-102591' lat='47.19213187695' lon='8.79683554173'>
+    <tag k='gpx:ele' v='473.28515625' />
+  </node>
+  <node id='-102592' lat='47.19219088554' lon='8.79689455032'>
+    <tag k='gpx:ele' v='472.39453125' />
+  </node>
+  <node id='-102593' lat='47.19225525856' lon='8.7969481945'>
+    <tag k='gpx:ele' v='471.3671875' />
+  </node>
+  <node id='-102594' lat='47.19234645367' lon='8.79700183868'>
+    <tag k='gpx:ele' v='470.0390625' />
+  </node>
+  <node id='-102595' lat='47.19242691994' lon='8.79704475403'>
+    <tag k='gpx:ele' v='468.76171875' />
+  </node>
+  <node id='-102596' lat='47.19250738621' lon='8.79708230495'>
+    <tag k='gpx:ele' v='467.3671875' />
+  </node>
+  <node id='-102597' lat='47.19255566597' lon='8.79711449146'>
+    <tag k='gpx:ele' v='466.60546875' />
+  </node>
+  <node id='-102598' lat='47.19272732735' lon='8.79725396633'>
+    <tag k='gpx:ele' v='464.65625' />
+  </node>
+  <node id='-102599' lat='47.19280779362' lon='8.79730761051'>
+    <tag k='gpx:ele' v='463.62109375' />
+  </node>
+  <node id='-102600' lat='47.19286604784' lon='8.7973383721'>
+    <tag k='gpx:ele' v='462.84375' />
+  </node>
+  <node id='-102601' lat='47.19286596403' lon='8.79733820446'>
+    <tag k='gpx:ele' v='462.84765625' />
+  </node>
+  <node id='-102603' lat='47.18561486341' lon='8.79647553898'>
+    <tag k='gpx:ele' v='647.81640625' />
+  </node>
+  <node id='-102604' lat='47.18566875905' lon='8.79651493393'>
+    <tag k='gpx:ele' v='646.87109375' />
+  </node>
+  <node id='-102605' lat='47.18571729027' lon='8.79652281292'>
+    <tag k='gpx:ele' v='646.1953125' />
+  </node>
+  <node id='-102606' lat='47.18575769104' lon='8.79656220786'>
+    <tag k='gpx:ele' v='645.5859375' />
+  </node>
+  <node id='-102607' lat='47.18580354005' lon='8.79657788202'>
+    <tag k='gpx:ele' v='644.8203125' />
+  </node>
+  <node id='-102608' lat='47.18591401353' lon='8.79658182152'>
+    <tag k='gpx:ele' v='642.9765625' />
+  </node>
+  <node id='-102609' lat='47.18596254475' lon='8.79662515596'>
+    <tag k='gpx:ele' v='641.796875' />
+  </node>
+  <node id='-102610' lat='47.18608114868' lon='8.79664485343'>
+    <tag k='gpx:ele' v='639.4296875' />
+  </node>
+  <node id='-102611' lat='47.18618625775' lon='8.79673152231'>
+    <tag k='gpx:ele' v='636.4921875' />
+  </node>
+  <node id='-102612' lat='47.18626437709' lon='8.79679053091'>
+    <tag k='gpx:ele' v='634.1328125' />
+  </node>
+  <node id='-102613' lat='47.18639915809' lon='8.79689295776'>
+    <tag k='gpx:ele' v='629.55859375' />
+  </node>
+  <node id='-102614' lat='47.18645841815' lon='8.79692841321'>
+    <tag k='gpx:ele' v='627.55078125' />
+  </node>
+  <node id='-102615' lat='47.18660661019' lon='8.79695598967'>
+    <tag k='gpx:ele' v='624.0234375' />
+  </node>
+  <node id='-102617' lat='47.18490038998' lon='8.79694417119'>
+    <tag k='gpx:ele' v='663.90234375' />
+  </node>
+  <node id='-102618' lat='47.18495160341' lon='8.79679053091'>
+    <tag k='gpx:ele' v='662.74609375' />
+  </node>
+  <node id='-102619' lat='47.18495696783' lon='8.79664091393'>
+    <tag k='gpx:ele' v='662.1328125' />
+  </node>
+  <node id='-102620' lat='47.18498127535' lon='8.79655038938'>
+    <tag k='gpx:ele' v='661.39453125' />
+  </node>
+  <node id='-102621' lat='47.18511060812' lon='8.79647947848'>
+    <tag k='gpx:ele' v='658.98828125' />
+  </node>
+  <node id='-102622' lat='47.18521839939' lon='8.79640856758'>
+    <tag k='gpx:ele' v='657.47265625' />
+  </node>
+  <node id='-102623' lat='47.18536122702' lon='8.79642038606'>
+    <tag k='gpx:ele' v='654.22265625' />
+  </node>
+  <node id='-102624' lat='47.1855364088' lon='8.79644008353'>
+    <tag k='gpx:ele' v='650.0703125' />
+  </node>
+  <node id='-102625' lat='47.18560916372' lon='8.79647553898'>
+    <tag k='gpx:ele' v='647.890625' />
+  </node>
+  <node id='-102627' timestamp='2016-01-03T12:08:53Z' lat='47.20138901845' lon='8.77447698265'>
+    <tag k='gpx:ele' v='421.52999999999997' />
+    <tag k='gpx:time' v='2016-01-03T12:08:53Z' />
+  </node>
+  <node id='-102628' timestamp='2016-01-03T12:09:10Z' lat='47.20149253495' lon='8.7732814718'>
+    <tag k='gpx:ele' v='423.57999999999998' />
+    <tag k='gpx:time' v='2016-01-03T12:09:10Z' />
+  </node>
+  <node id='-102629' timestamp='2016-01-03T12:09:26Z' lat='47.20148784108' lon='8.77220867202'>
+    <tag k='gpx:ele' v='423' />
+    <tag k='gpx:time' v='2016-01-03T12:09:26Z' />
+  </node>
+  <node id='-102630' timestamp='2016-01-03T12:09:28Z' lat='47.20149974339' lon='8.77208210528'>
+    <tag k='gpx:ele' v='423.07999999999998' />
+    <tag k='gpx:time' v='2016-01-03T12:09:28Z' />
+  </node>
+  <node id='-102631' timestamp='2016-01-03T12:09:29Z' lat='47.2014896851' lon='8.77203491516'>
+    <tag k='gpx:ele' v='423.02999999999997' />
+    <tag k='gpx:time' v='2016-01-03T12:09:29Z' />
+  </node>
+  <node id='-102632' timestamp='2016-01-03T12:09:31Z' lat='47.20144324936' lon='8.77200884745'>
+    <tag k='gpx:ele' v='422.26999999999998' />
+    <tag k='gpx:time' v='2016-01-03T12:09:31Z' />
+  </node>
+  <node id='-102633' timestamp='2016-01-03T12:09:42Z' lat='47.20140594989' lon='8.77203382552'>
+    <tag k='gpx:ele' v='421.35000000000002' />
+    <tag k='gpx:time' v='2016-01-03T12:09:42Z' />
+  </node>
+  <node id='-102634' timestamp='2016-01-03T12:10:04Z' lat='47.20132657327' lon='8.77198227681'>
+    <tag k='gpx:ele' v='421.75' />
+    <tag k='gpx:time' v='2016-01-03T12:10:04Z' />
+  </node>
+  <node id='-102635' timestamp='2016-01-03T12:10:23Z' lat='47.2012681514' lon='8.77192972228'>
+    <tag k='gpx:ele' v='421.48000000000002' />
+    <tag k='gpx:time' v='2016-01-03T12:10:23Z' />
+  </node>
+  <way id='-102363'>
+    <nd ref='-102235' />
+    <nd ref='-102236' />
+    <nd ref='-102237' />
+    <nd ref='-102238' />
+    <nd ref='-102239' />
+    <nd ref='-102240' />
+    <nd ref='-102241' />
+    <nd ref='-102242' />
+    <nd ref='-102243' />
+    <nd ref='-102244' />
+    <nd ref='-102245' />
+    <nd ref='-102246' />
+    <nd ref='-102247' />
+    <nd ref='-102248' />
+    <nd ref='-102249' />
+    <nd ref='-102250' />
+    <nd ref='-102251' />
+    <nd ref='-102252' />
+    <nd ref='-102253' />
+    <nd ref='-102254' />
+    <nd ref='-102255' />
+    <nd ref='-102256' />
+    <nd ref='-102257' />
+    <nd ref='-102258' />
+    <nd ref='-102259' />
+    <nd ref='-102260' />
+    <nd ref='-102261' />
+    <nd ref='-102262' />
+    <nd ref='-102263' />
+    <nd ref='-102264' />
+    <nd ref='-102265' />
+    <nd ref='-102266' />
+    <nd ref='-102267' />
+    <nd ref='-102268' />
+    <nd ref='-102269' />
+    <nd ref='-102270' />
+    <nd ref='-102271' />
+    <nd ref='-102272' />
+    <nd ref='-102273' />
+    <nd ref='-102274' />
+    <nd ref='-102275' />
+    <nd ref='-102276' />
+    <nd ref='-102277' />
+    <nd ref='-102278' />
+    <nd ref='-102279' />
+    <nd ref='-102280' />
+    <nd ref='-102281' />
+    <nd ref='-102282' />
+    <nd ref='-102283' />
+    <nd ref='-102284' />
+    <nd ref='-102285' />
+    <nd ref='-102286' />
+    <nd ref='-102287' />
+    <nd ref='-102288' />
+    <nd ref='-102289' />
+    <nd ref='-102290' />
+    <nd ref='-102291' />
+    <nd ref='-102292' />
+    <nd ref='-102293' />
+    <nd ref='-102294' />
+    <nd ref='-102295' />
+    <nd ref='-102296' />
+    <nd ref='-102297' />
+    <nd ref='-102298' />
+    <nd ref='-102299' />
+    <nd ref='-102300' />
+    <nd ref='-102301' />
+    <nd ref='-102302' />
+    <nd ref='-102303' />
+    <nd ref='-102304' />
+    <nd ref='-102305' />
+    <nd ref='-102306' />
+    <nd ref='-102307' />
+    <nd ref='-102308' />
+    <nd ref='-102309' />
+    <nd ref='-102310' />
+    <nd ref='-102311' />
+    <nd ref='-102312' />
+    <nd ref='-102313' />
+    <nd ref='-102314' />
+    <nd ref='-102315' />
+    <nd ref='-102316' />
+    <nd ref='-102317' />
+    <nd ref='-102318' />
+    <nd ref='-102319' />
+    <nd ref='-102320' />
+    <nd ref='-102321' />
+    <nd ref='-102322' />
+    <nd ref='-102323' />
+    <nd ref='-102324' />
+    <nd ref='-102325' />
+    <nd ref='-102326' />
+    <nd ref='-102327' />
+    <nd ref='-102328' />
+    <nd ref='-102329' />
+    <nd ref='-102330' />
+    <nd ref='-102331' />
+    <nd ref='-102332' />
+    <nd ref='-102333' />
+    <nd ref='-102334' />
+    <nd ref='-102335' />
+    <nd ref='-102336' />
+    <nd ref='-102337' />
+    <nd ref='-102338' />
+    <nd ref='-102339' />
+    <nd ref='-102340' />
+    <nd ref='-102341' />
+    <nd ref='-102342' />
+    <nd ref='-102343' />
+    <nd ref='-102344' />
+    <nd ref='-102345' />
+    <nd ref='-102346' />
+    <nd ref='-102347' />
+    <nd ref='-102348' />
+    <nd ref='-102349' />
+    <nd ref='-102350' />
+    <nd ref='-102351' />
+    <nd ref='-102352' />
+    <nd ref='-102353' />
+    <nd ref='-102354' />
+    <nd ref='-102355' />
+    <nd ref='-102356' />
+    <nd ref='-102357' />
+    <nd ref='-102358' />
+    <nd ref='-102359' />
+    <nd ref='-102360' />
+    <nd ref='-102361' />
+    <nd ref='-102362' />
+    <tag k='gpx:extension:test:segment:tag' v='Segment extension' />
+    <tag k='gpx:extension:test:tag' v='Track extension' />
+    <tag k='gpxx:DisplayColor' v='Red' />
+  </way>
+  <way id='-102602'>
+    <nd ref='-102364' />
+    <nd ref='-102365' />
+    <nd ref='-102366' />
+    <nd ref='-102367' />
+    <nd ref='-102368' />
+    <nd ref='-102369' />
+    <nd ref='-102370' />
+    <nd ref='-102371' />
+    <nd ref='-102372' />
+    <nd ref='-102373' />
+    <nd ref='-102374' />
+    <nd ref='-102375' />
+    <nd ref='-102376' />
+    <nd ref='-102377' />
+    <nd ref='-102378' />
+    <nd ref='-102379' />
+    <nd ref='-102380' />
+    <nd ref='-102381' />
+    <nd ref='-102382' />
+    <nd ref='-102383' />
+    <nd ref='-102384' />
+    <nd ref='-102385' />
+    <nd ref='-102386' />
+    <nd ref='-102387' />
+    <nd ref='-102388' />
+    <nd ref='-102389' />
+    <nd ref='-102390' />
+    <nd ref='-102391' />
+    <nd ref='-102392' />
+    <nd ref='-102393' />
+    <nd ref='-102394' />
+    <nd ref='-102395' />
+    <nd ref='-102396' />
+    <nd ref='-102397' />
+    <nd ref='-102398' />
+    <nd ref='-102399' />
+    <nd ref='-102400' />
+    <nd ref='-102401' />
+    <nd ref='-102402' />
+    <nd ref='-102403' />
+    <nd ref='-102404' />
+    <nd ref='-102405' />
+    <nd ref='-102406' />
+    <nd ref='-102407' />
+    <nd ref='-102408' />
+    <nd ref='-102409' />
+    <nd ref='-102410' />
+    <nd ref='-102411' />
+    <nd ref='-102412' />
+    <nd ref='-102413' />
+    <nd ref='-102414' />
+    <nd ref='-102415' />
+    <nd ref='-102416' />
+    <nd ref='-102417' />
+    <nd ref='-102418' />
+    <nd ref='-102419' />
+    <nd ref='-102420' />
+    <nd ref='-102421' />
+    <nd ref='-102422' />
+    <nd ref='-102423' />
+    <nd ref='-102424' />
+    <nd ref='-102425' />
+    <nd ref='-102426' />
+    <nd ref='-102427' />
+    <nd ref='-102428' />
+    <nd ref='-102429' />
+    <nd ref='-102430' />
+    <nd ref='-102431' />
+    <nd ref='-102432' />
+    <nd ref='-102433' />
+    <nd ref='-102434' />
+    <nd ref='-102435' />
+    <nd ref='-102436' />
+    <nd ref='-102437' />
+    <nd ref='-102438' />
+    <nd ref='-102439' />
+    <nd ref='-102440' />
+    <nd ref='-102441' />
+    <nd ref='-102442' />
+    <nd ref='-102443' />
+    <nd ref='-102444' />
+    <nd ref='-102445' />
+    <nd ref='-102446' />
+    <nd ref='-102447' />
+    <nd ref='-102448' />
+    <nd ref='-102449' />
+    <nd ref='-102450' />
+    <nd ref='-102451' />
+    <nd ref='-102452' />
+    <nd ref='-102453' />
+    <nd ref='-102454' />
+    <nd ref='-102455' />
+    <nd ref='-102456' />
+    <nd ref='-102457' />
+    <nd ref='-102458' />
+    <nd ref='-102459' />
+    <nd ref='-102460' />
+    <nd ref='-102461' />
+    <nd ref='-102462' />
+    <nd ref='-102463' />
+    <nd ref='-102464' />
+    <nd ref='-102465' />
+    <nd ref='-102466' />
+    <nd ref='-102467' />
+    <nd ref='-102468' />
+    <nd ref='-102469' />
+    <nd ref='-102470' />
+    <nd ref='-102471' />
+    <nd ref='-102472' />
+    <nd ref='-102473' />
+    <nd ref='-102474' />
+    <nd ref='-102475' />
+    <nd ref='-102476' />
+    <nd ref='-102477' />
+    <nd ref='-102478' />
+    <nd ref='-102479' />
+    <nd ref='-102480' />
+    <nd ref='-102481' />
+    <nd ref='-102482' />
+    <nd ref='-102483' />
+    <nd ref='-102484' />
+    <nd ref='-102485' />
+    <nd ref='-102486' />
+    <nd ref='-102487' />
+    <nd ref='-102488' />
+    <nd ref='-102489' />
+    <nd ref='-102490' />
+    <nd ref='-102491' />
+    <nd ref='-102492' />
+    <nd ref='-102493' />
+    <nd ref='-102494' />
+    <nd ref='-102495' />
+    <nd ref='-102496' />
+    <nd ref='-102497' />
+    <nd ref='-102498' />
+    <nd ref='-102499' />
+    <nd ref='-102500' />
+    <nd ref='-102501' />
+    <nd ref='-102502' />
+    <nd ref='-102503' />
+    <nd ref='-102504' />
+    <nd ref='-102505' />
+    <nd ref='-102506' />
+    <nd ref='-102507' />
+    <nd ref='-102508' />
+    <nd ref='-102509' />
+    <nd ref='-102510' />
+    <nd ref='-102511' />
+    <nd ref='-102512' />
+    <nd ref='-102513' />
+    <nd ref='-102514' />
+    <nd ref='-102515' />
+    <nd ref='-102516' />
+    <nd ref='-102517' />
+    <nd ref='-102518' />
+    <nd ref='-102519' />
+    <nd ref='-102520' />
+    <nd ref='-102521' />
+    <nd ref='-102522' />
+    <nd ref='-102523' />
+    <nd ref='-102524' />
+    <nd ref='-102525' />
+    <nd ref='-102526' />
+    <nd ref='-102527' />
+    <nd ref='-102528' />
+    <nd ref='-102529' />
+    <nd ref='-102530' />
+    <nd ref='-102531' />
+    <nd ref='-102532' />
+    <nd ref='-102533' />
+    <nd ref='-102534' />
+    <nd ref='-102535' />
+    <nd ref='-102536' />
+    <nd ref='-102537' />
+    <nd ref='-102538' />
+    <nd ref='-102539' />
+    <nd ref='-102540' />
+    <nd ref='-102541' />
+    <nd ref='-102542' />
+    <nd ref='-102543' />
+    <nd ref='-102544' />
+    <nd ref='-102545' />
+    <nd ref='-102546' />
+    <nd ref='-102547' />
+    <nd ref='-102548' />
+    <nd ref='-102549' />
+    <nd ref='-102550' />
+    <nd ref='-102551' />
+    <nd ref='-102552' />
+    <nd ref='-102553' />
+    <nd ref='-102554' />
+    <nd ref='-102555' />
+    <nd ref='-102556' />
+    <nd ref='-102557' />
+    <nd ref='-102558' />
+    <nd ref='-102559' />
+    <nd ref='-102560' />
+    <nd ref='-102561' />
+    <nd ref='-102562' />
+    <nd ref='-102563' />
+    <nd ref='-102564' />
+    <nd ref='-102565' />
+    <nd ref='-102566' />
+    <nd ref='-102567' />
+    <nd ref='-102568' />
+    <nd ref='-102569' />
+    <nd ref='-102570' />
+    <nd ref='-102571' />
+    <nd ref='-102572' />
+    <nd ref='-102573' />
+    <nd ref='-102574' />
+    <nd ref='-102575' />
+    <nd ref='-102576' />
+    <nd ref='-102577' />
+    <nd ref='-102578' />
+    <nd ref='-102579' />
+    <nd ref='-102580' />
+    <nd ref='-102581' />
+    <nd ref='-102582' />
+    <nd ref='-102583' />
+    <nd ref='-102584' />
+    <nd ref='-102585' />
+    <nd ref='-102586' />
+    <nd ref='-102587' />
+    <nd ref='-102588' />
+    <nd ref='-102589' />
+    <nd ref='-102590' />
+    <nd ref='-102591' />
+    <nd ref='-102592' />
+    <nd ref='-102593' />
+    <nd ref='-102594' />
+    <nd ref='-102595' />
+    <nd ref='-102596' />
+    <nd ref='-102597' />
+    <nd ref='-102598' />
+    <nd ref='-102599' />
+    <nd ref='-102600' />
+    <nd ref='-102601' />
+    <tag k='gpxd:color' v='#0000FF' />
+  </way>
+  <way id='-102616'>
+    <nd ref='-102603' />
+    <nd ref='-102604' />
+    <nd ref='-102605' />
+    <nd ref='-102606' />
+    <nd ref='-102607' />
+    <nd ref='-102608' />
+    <nd ref='-102609' />
+    <nd ref='-102610' />
+    <nd ref='-102611' />
+    <nd ref='-102612' />
+    <nd ref='-102613' />
+    <nd ref='-102614' />
+    <nd ref='-102615' />
+    <tag k='gpxd:color' v='#00FF00' />
+  </way>
+  <way id='-102626'>
+    <nd ref='-102617' />
+    <nd ref='-102618' />
+    <nd ref='-102619' />
+    <nd ref='-102620' />
+    <nd ref='-102621' />
+    <nd ref='-102622' />
+    <nd ref='-102623' />
+    <nd ref='-102624' />
+    <nd ref='-102625' />
+  </way>
+  <way id='-102636'>
+    <nd ref='-102627' />
+    <nd ref='-102628' />
+    <nd ref='-102629' />
+    <nd ref='-102630' />
+    <nd ref='-102631' />
+    <nd ref='-102632' />
+    <nd ref='-102633' />
+    <nd ref='-102634' />
+    <nd ref='-102635' />
+  </way>
+</osm>
Index: /trunk/test/data/tracks/tracks-layerprefs.gpx
===================================================================
--- /trunk/test/data/tracks/tracks-layerprefs.gpx	(revision 15496)
+++ /trunk/test/data/tracks/tracks-layerprefs.gpx	(revision 15496)
@@ -0,0 +1,1384 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<gpx version="1.1" creator="JOSM GPX export" xmlns="http://www.topografix.com/GPX/1/1"
+    xmlns:josm="http://josm.openstreetmap.de/gpx-extensions-1.1"
+    xmlns:gpxx="http://www.garmin.com/xmlschemas/GpxExtensions/v3"
+    xmlns:gpxd="http://josm.openstreetmap.de/gpx-drawing-extensions-1.0"
+    xmlns:test="TestExtensionNamespace"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd http://josm.openstreetmap.de/gpx-extensions-1.1 http://josm.openstreetmap.de/gpx-extensions-1.1.xsd http://www.garmin.com/xmlschemas/GpxExtensions/v3 http://www.garmin.com/xmlschemas/GpxExtensionsv3.xsd http://josm.openstreetmap.de/gpx-drawing-extensions-1.0 http://josm.openstreetmap.de/gpx-drawing-extensions-1.0.xsd TestExtensionNamespace http://example.com">
+  <metadata>
+    <bounds minlat="47.1849004" minlon="8.7719297" maxlat="47.2014997" maxlon="8.7984188"/>
+    <extensions>
+      <josm:layerPreferences>
+        <josm:entry key="colormode" value="1"/>
+        <josm:entry key="colormode.dynamic-range" value="true"/>
+        <josm:entry key="colormode.velocity.tune" value="10"/>
+        <josm:entry key="colors" value="0"/>
+        <josm:entry key="lines" value="1"/>
+        <josm:entry key="lines.arrows" value="true"/>
+        <josm:entry key="lines.arrows.min-distance" value="20"/>
+      </josm:layerPreferences>
+    </extensions>
+  </metadata>
+  <trk>
+    <extensions>
+      <gpxd:color>#FF0000</gpxd:color>
+    </extensions>
+    <trkseg>
+      <extensions>
+        <test:tag>Segment extension</test:tag>
+      </extensions>
+      <trkpt lat="47.19286847859621" lon="8.79732714034617">
+        <ele>471.86000000000001</ele>
+        <time>2016-01-03T11:59:58Z</time>
+      </trkpt>
+      <trkpt lat="47.192921955138445" lon="8.797342479228973">
+        <ele>471.43000000000001</ele>
+        <time>2016-01-03T11:59:59Z</time>
+      </trkpt>
+      <trkpt lat="47.19297501258552" lon="8.79734423942864">
+        <ele>470.69</ele>
+        <time>2016-01-03T12:00:00Z</time>
+      </trkpt>
+      <trkpt lat="47.19302739948034" lon="8.797332588583231">
+        <ele>470.94</ele>
+        <time>2016-01-03T12:00:01Z</time>
+      </trkpt>
+      <trkpt lat="47.193073416128755" lon="8.797307442873716">
+        <ele>471.5</ele>
+        <time>2016-01-03T12:00:02Z</time>
+      </trkpt>
+      <trkpt lat="47.193113481625915" lon="8.797272993251681">
+        <ele>471.67000000000002</ele>
+        <time>2016-01-03T12:00:03Z</time>
+      </trkpt>
+      <trkpt lat="47.19313560985029" lon="8.797232424840331">
+        <ele>471.58999999999997</ele>
+        <time>2016-01-03T12:00:04Z</time>
+      </trkpt>
+      <trkpt lat="47.19333660788834" lon="8.796738646924496">
+        <ele>472.44999999999999</ele>
+        <time>2016-01-03T12:00:15Z</time>
+      </trkpt>
+      <trkpt lat="47.193504832684994" lon="8.796404711902142">
+        <ele>472.54000000000002</ele>
+        <time>2016-01-03T12:00:22Z</time>
+      </trkpt>
+      <trkpt lat="47.19353936612606" lon="8.79635970108211">
+        <ele>472.45999999999998</ele>
+        <time>2016-01-03T12:00:23Z</time>
+      </trkpt>
+      <trkpt lat="47.19381898641586" lon="8.796017384156585">
+        <ele>471.38</ele>
+        <time>2016-01-03T12:00:30Z</time>
+      </trkpt>
+      <trkpt lat="47.19386676326394" lon="8.795985281467438">
+        <ele>471.26999999999998</ele>
+        <time>2016-01-03T12:00:31Z</time>
+      </trkpt>
+      <trkpt lat="47.19391797669232" lon="8.795968098565936">
+        <ele>471.36000000000001</ele>
+        <time>2016-01-03T12:00:32Z</time>
+      </trkpt>
+      <trkpt lat="47.19474418088794" lon="8.795836586505175">
+        <ele>473.19999999999999</ele>
+        <time>2016-01-03T12:00:50Z</time>
+      </trkpt>
+      <trkpt lat="47.195586981251836" lon="8.795750420540571">
+        <ele>475.06</ele>
+        <time>2016-01-03T12:01:09Z</time>
+      </trkpt>
+      <trkpt lat="47.19563358463347" lon="8.795769028365612">
+        <ele>474.75</ele>
+        <time>2016-01-03T12:01:10Z</time>
+      </trkpt>
+      <trkpt lat="47.19567717052996" lon="8.795795682817698">
+        <ele>474.62</ele>
+        <time>2016-01-03T12:01:11Z</time>
+      </trkpt>
+      <trkpt lat="47.195715978741646" lon="8.79583046771586">
+        <ele>474.74000000000001</ele>
+        <time>2016-01-03T12:01:12Z</time>
+      </trkpt>
+      <trkpt lat="47.19575093127787" lon="8.79587598145008">
+        <ele>474.06</ele>
+        <time>2016-01-03T12:01:13Z</time>
+      </trkpt>
+      <trkpt lat="47.19578169286251" lon="8.795927111059427">
+        <ele>474</ele>
+        <time>2016-01-03T12:01:14Z</time>
+      </trkpt>
+      <trkpt lat="47.195808347314596" lon="8.795980839058757">
+        <ele>474.58999999999997</ele>
+        <time>2016-01-03T12:01:15Z</time>
+      </trkpt>
+      <trkpt lat="47.195833241567016" lon="8.796036075800657">
+        <ele>474.81999999999999</ele>
+        <time>2016-01-03T12:01:16Z</time>
+      </trkpt>
+      <trkpt lat="47.19628603197634" lon="8.797110635787249">
+        <ele>476.29000000000002</ele>
+        <time>2016-01-03T12:01:35Z</time>
+      </trkpt>
+      <trkpt lat="47.19658995978534" lon="8.797826115041971">
+        <ele>478.48000000000002</ele>
+        <time>2016-01-03T12:01:50Z</time>
+      </trkpt>
+      <trkpt lat="47.19703386537731" lon="8.798356018960476">
+        <ele>481.02999999999997</ele>
+        <time>2016-01-03T12:02:06Z</time>
+      </trkpt>
+      <trkpt lat="47.19723687507212" lon="8.79841879941523">
+        <ele>480</ele>
+        <time>2016-01-03T12:02:12Z</time>
+      </trkpt>
+      <trkpt lat="47.19727886840701" lon="8.79838845692575">
+        <ele>479.58999999999997</ele>
+        <time>2016-01-03T12:02:13Z</time>
+      </trkpt>
+      <trkpt lat="47.19731541350484" lon="8.798339758068323">
+        <ele>478.99000000000001</ele>
+        <time>2016-01-03T12:02:14Z</time>
+      </trkpt>
+      <trkpt lat="47.197333350777626" lon="8.798282761126757">
+        <ele>479.58999999999997</ele>
+        <time>2016-01-03T12:02:15Z</time>
+      </trkpt>
+      <trkpt lat="47.19734919257462" lon="8.798161642625928">
+        <ele>481.18000000000001</ele>
+        <time>2016-01-03T12:02:18Z</time>
+      </trkpt>
+      <trkpt lat="47.19734827056527" lon="8.798118894919753">
+        <ele>481.88</ele>
+        <time>2016-01-03T12:02:20Z</time>
+      </trkpt>
+      <trkpt lat="47.19730585813522" lon="8.79802887327969">
+        <ele>483.11000000000001</ele>
+        <time>2016-01-03T12:02:24Z</time>
+      </trkpt>
+      <trkpt lat="47.19727643765509" lon="8.79797455854714">
+        <ele>484.49000000000001</ele>
+        <time>2016-01-03T12:02:27Z</time>
+      </trkpt>
+      <trkpt lat="47.19720158725977" lon="8.797768447548151">
+        <ele>486.88</ele>
+        <time>2016-01-03T12:02:35Z</time>
+      </trkpt>
+      <trkpt lat="47.19708633609116" lon="8.79746401682496">
+        <ele>488.05000000000001</ele>
+        <time>2016-01-03T12:02:48Z</time>
+      </trkpt>
+      <trkpt lat="47.19707007519901" lon="8.79741758108139">
+        <ele>487.76999999999998</ele>
+        <time>2016-01-03T12:02:51Z</time>
+      </trkpt>
+      <trkpt lat="47.19702917151153" lon="8.797250529751182">
+        <ele>488.95999999999998</ele>
+        <time>2016-01-03T12:02:57Z</time>
+      </trkpt>
+      <trkpt lat="47.19699899666011" lon="8.797172158956528">
+        <ele>488.36000000000001</ele>
+        <time>2016-01-03T12:03:01Z</time>
+      </trkpt>
+      <trkpt lat="47.19691224396229" lon="8.796978034079075">
+        <ele>488.35000000000002</ele>
+        <time>2016-01-03T12:03:09Z</time>
+      </trkpt>
+      <trkpt lat="47.19690545462072" lon="8.796931263059378">
+        <ele>487.19</ele>
+        <time>2016-01-03T12:03:10Z</time>
+      </trkpt>
+      <trkpt lat="47.19690595753491" lon="8.796886671334505">
+        <ele>487.63999999999999</ele>
+        <time>2016-01-03T12:03:11Z</time>
+      </trkpt>
+      <trkpt lat="47.19690511934459" lon="8.796837385743856">
+        <ele>487.55000000000001</ele>
+        <time>2016-01-03T12:03:12Z</time>
+      </trkpt>
+      <trkpt lat="47.19690562225878" lon="8.796793716028333">
+        <ele>488.39999999999998</ele>
+        <time>2016-01-03T12:03:13Z</time>
+      </trkpt>
+      <trkpt lat="47.196887601166964" lon="8.796751135960221">
+        <ele>489.18000000000001</ele>
+        <time>2016-01-03T12:03:15Z</time>
+      </trkpt>
+      <trkpt lat="47.1968892775476" lon="8.796689361333847">
+        <ele>490.73000000000002</ele>
+        <time>2016-01-03T12:03:18Z</time>
+      </trkpt>
+      <trkpt lat="47.196868155151606" lon="8.79647453315556">
+        <ele>491.24000000000001</ele>
+        <time>2016-01-03T12:03:33Z</time>
+      </trkpt>
+      <trkpt lat="47.19686932861805" lon="8.796442430466413">
+        <ele>490.25</ele>
+        <time>2016-01-03T12:03:34Z</time>
+      </trkpt>
+      <trkpt lat="47.19686849042773" lon="8.796406639739871">
+        <ele>490.00999999999999</ele>
+        <time>2016-01-03T12:03:35Z</time>
+      </trkpt>
+      <trkpt lat="47.196873016655445" lon="8.796368166804314">
+        <ele>489.54000000000002</ele>
+        <time>2016-01-03T12:03:36Z</time>
+      </trkpt>
+      <trkpt lat="47.19687905162573" lon="8.796329610049725">
+        <ele>489.66000000000003</ele>
+        <time>2016-01-03T12:03:37Z</time>
+      </trkpt>
+      <trkpt lat="47.196886762976646" lon="8.796280743554235">
+        <ele>489.06</ele>
+        <time>2016-01-03T12:03:38Z</time>
+      </trkpt>
+      <trkpt lat="47.19695775769651" lon="8.795829126611352">
+        <ele>490.08999999999997</ele>
+        <time>2016-01-03T12:03:48Z</time>
+      </trkpt>
+      <trkpt lat="47.1969928778708" lon="8.795709516853094">
+        <ele>489.41000000000003</ele>
+        <time>2016-01-03T12:03:52Z</time>
+      </trkpt>
+      <trkpt lat="47.19698550179601" lon="8.795667607337236">
+        <ele>489.17000000000002</ele>
+        <time>2016-01-03T12:03:53Z</time>
+      </trkpt>
+      <trkpt lat="47.19697644934058" lon="8.795624608173966">
+        <ele>488.87</ele>
+        <time>2016-01-03T12:03:54Z</time>
+      </trkpt>
+      <trkpt lat="47.19696890562773" lon="8.795590326189995">
+        <ele>489.37</ele>
+        <time>2016-01-03T12:03:55Z</time>
+      </trkpt>
+      <trkpt lat="47.19696664251387" lon="8.795558391138911">
+        <ele>488.94999999999999</ele>
+        <time>2016-01-03T12:03:56Z</time>
+      </trkpt>
+      <trkpt lat="47.19695256091654" lon="8.795536765828729">
+        <ele>488.93000000000001</ele>
+        <time>2016-01-03T12:03:57Z</time>
+      </trkpt>
+      <trkpt lat="47.196956500411034" lon="8.795507680624723">
+        <ele>488.88999999999999</ele>
+        <time>2016-01-03T12:03:58Z</time>
+      </trkpt>
+      <trkpt lat="47.19695859588683" lon="8.79548110999167">
+        <ele>488.86000000000001</ele>
+        <time>2016-01-03T12:03:59Z</time>
+      </trkpt>
+      <trkpt lat="47.19696907326579" lon="8.795452527701855">
+        <ele>489.19999999999999</ele>
+        <time>2016-01-03T12:04:00Z</time>
+      </trkpt>
+      <trkpt lat="47.19697988592088" lon="8.79541271366179">
+        <ele>489.29000000000002</ele>
+        <time>2016-01-03T12:04:01Z</time>
+      </trkpt>
+      <trkpt lat="47.19698726199567" lon="8.795355297625065">
+        <ele>488.95999999999998</ele>
+        <time>2016-01-03T12:04:02Z</time>
+      </trkpt>
+      <trkpt lat="47.19698960892856" lon="8.795302575454116">
+        <ele>489.10000000000002</ele>
+        <time>2016-01-03T12:04:03Z</time>
+      </trkpt>
+      <trkpt lat="47.19690981321037" lon="8.79494265653193">
+        <ele>492.19</ele>
+        <time>2016-01-03T12:04:14Z</time>
+      </trkpt>
+      <trkpt lat="47.19696622341871" lon="8.794532027095556">
+        <ele>492.12</ele>
+        <time>2016-01-03T12:04:25Z</time>
+      </trkpt>
+      <trkpt lat="47.19697737134993" lon="8.79450285807252">
+        <ele>493.06999999999999</ele>
+        <time>2016-01-03T12:04:26Z</time>
+      </trkpt>
+      <trkpt lat="47.19699212349951" lon="8.794450974091887">
+        <ele>492.58999999999997</ele>
+        <time>2016-01-03T12:04:27Z</time>
+      </trkpt>
+      <trkpt lat="47.19699405133724" lon="8.794399006292224">
+        <ele>492.38999999999999</ele>
+        <time>2016-01-03T12:04:28Z</time>
+      </trkpt>
+      <trkpt lat="47.19698860310018" lon="8.794350139796734">
+        <ele>492.94</ele>
+        <time>2016-01-03T12:04:29Z</time>
+      </trkpt>
+      <trkpt lat="47.19698214903474" lon="8.794298926368356">
+        <ele>492.47000000000003</ele>
+        <time>2016-01-03T12:04:30Z</time>
+      </trkpt>
+      <trkpt lat="47.19697737134993" lon="8.794246790930629">
+        <ele>492.50999999999999</ele>
+        <time>2016-01-03T12:04:31Z</time>
+      </trkpt>
+      <trkpt lat="47.19698206521571" lon="8.794189291074872">
+        <ele>492.73000000000002</ele>
+        <time>2016-01-03T12:04:32Z</time>
+      </trkpt>
+      <trkpt lat="47.196985417976975" lon="8.794133719056845">
+        <ele>492.63</ele>
+        <time>2016-01-03T12:04:33Z</time>
+      </trkpt>
+      <trkpt lat="47.19698768109083" lon="8.794077644124627">
+        <ele>493</ele>
+        <time>2016-01-03T12:04:34Z</time>
+      </trkpt>
+      <trkpt lat="47.19699136912823" lon="8.794022323563695">
+        <ele>493.00999999999999</ele>
+        <time>2016-01-03T12:04:35Z</time>
+      </trkpt>
+      <trkpt lat="47.196987848728895" lon="8.793976558372378">
+        <ele>493.19999999999999</ele>
+        <time>2016-01-03T12:04:36Z</time>
+      </trkpt>
+      <trkpt lat="47.19698550179601" lon="8.793926937505603">
+        <ele>493.18000000000001</ele>
+        <time>2016-01-03T12:04:37Z</time>
+      </trkpt>
+      <trkpt lat="47.196980556473136" lon="8.793885698541999">
+        <ele>493</ele>
+        <time>2016-01-03T12:04:38Z</time>
+      </trkpt>
+      <trkpt lat="47.19698307104409" lon="8.793837334960699">
+        <ele>493.20999999999998</ele>
+        <time>2016-01-03T12:04:39Z</time>
+      </trkpt>
+      <trkpt lat="47.196992291137576" lon="8.793786959722638">
+        <ele>493.11000000000001</ele>
+        <time>2016-01-03T12:04:40Z</time>
+      </trkpt>
+      <trkpt lat="47.19699547626078" lon="8.793743625283241">
+        <ele>493.30000000000001</ele>
+        <time>2016-01-03T12:04:41Z</time>
+      </trkpt>
+      <trkpt lat="47.19700268469751" lon="8.793694507330656">
+        <ele>493.50999999999999</ele>
+        <time>2016-01-03T12:04:42Z</time>
+      </trkpt>
+      <trkpt lat="47.19700511544943" lon="8.793357806280255">
+        <ele>493</ele>
+        <time>2016-01-03T12:04:50Z</time>
+      </trkpt>
+      <trkpt lat="47.19702162779868" lon="8.793316148221493">
+        <ele>492.37</ele>
+        <time>2016-01-03T12:04:51Z</time>
+      </trkpt>
+      <trkpt lat="47.19704459421337" lon="8.793262336403131">
+        <ele>492.30000000000001</ele>
+        <time>2016-01-03T12:04:52Z</time>
+      </trkpt>
+      <trkpt lat="47.19706906937063" lon="8.793201064690948">
+        <ele>492.04000000000002</ele>
+        <time>2016-01-03T12:04:53Z</time>
+      </trkpt>
+      <trkpt lat="47.19708985649049" lon="8.793123783543706">
+        <ele>491.37</ele>
+        <time>2016-01-03T12:04:54Z</time>
+      </trkpt>
+      <trkpt lat="47.19710913486779" lon="8.79304625093937">
+        <ele>491.06999999999999</ele>
+        <time>2016-01-03T12:04:55Z</time>
+      </trkpt>
+      <trkpt lat="47.19713117927313" lon="8.792974585667253">
+        <ele>490.39999999999998</ele>
+        <time>2016-01-03T12:04:56Z</time>
+      </trkpt>
+      <trkpt lat="47.197186248376966" lon="8.792809881269932">
+        <ele>489.75</ele>
+        <time>2016-01-03T12:04:58Z</time>
+      </trkpt>
+      <trkpt lat="47.19720753841102" lon="8.79271550104022">
+        <ele>489.87</ele>
+        <time>2016-01-03T12:04:59Z</time>
+      </trkpt>
+      <trkpt lat="47.19722296111286" lon="8.792620282620192">
+        <ele>488.95999999999998</ele>
+        <time>2016-01-03T12:05:00Z</time>
+      </trkpt>
+      <trkpt lat="47.19733930192888" lon="8.792043440043926">
+        <ele>485.85000000000002</ele>
+        <time>2016-01-03T12:05:06Z</time>
+      </trkpt>
+      <trkpt lat="47.1974522061646" lon="8.791516218334436">
+        <ele>482.81</ele>
+        <time>2016-01-03T12:05:11Z</time>
+      </trkpt>
+      <trkpt lat="47.197455475106835" lon="8.79138101823628">
+        <ele>481.99000000000001</ele>
+        <time>2016-01-03T12:05:12Z</time>
+      </trkpt>
+      <trkpt lat="47.197490092366934" lon="8.79095789976418">
+        <ele>478.92</ele>
+      </trkpt>
+      <trkpt lat="47.19753225333989" lon="8.790533943101764">
+        <ele>476</ele>
+      </trkpt>
+      <trkpt lat="47.19762864522636" lon="8.789889458566904">
+        <ele>474.38</ele>
+        <time>2016-01-03T12:05:23Z</time>
+      </trkpt>
+      <trkpt lat="47.19763744622469" lon="8.789792899042368">
+        <ele>474.35000000000002</ele>
+        <time>2016-01-03T12:05:24Z</time>
+      </trkpt>
+      <trkpt lat="47.1976438164711" lon="8.789720982313156">
+        <ele>474.12</ele>
+        <time>2016-01-03T12:05:25Z</time>
+      </trkpt>
+      <trkpt lat="47.19764859415591" lon="8.789367768913507">
+        <ele>472.52999999999997</ele>
+        <time>2016-01-03T12:05:33Z</time>
+      </trkpt>
+      <trkpt lat="47.19765613786876" lon="8.78931068815291">
+        <ele>472.75</ele>
+        <time>2016-01-03T12:05:34Z</time>
+      </trkpt>
+      <trkpt lat="47.1976903360337" lon="8.789105415344238">
+        <ele>472.19</ele>
+        <time>2016-01-03T12:05:37Z</time>
+      </trkpt>
+      <trkpt lat="47.197700729593635" lon="8.78903266042471">
+        <ele>471.92000000000002</ele>
+        <time>2016-01-03T12:05:38Z</time>
+      </trkpt>
+      <trkpt lat="47.197715900838375" lon="8.78876687027514">
+        <ele>471.98000000000002</ele>
+        <time>2016-01-03T12:05:41Z</time>
+      </trkpt>
+      <trkpt lat="47.19775462523103" lon="8.788432851433754">
+        <ele>473.49000000000001</ele>
+        <time>2016-01-03T12:05:47Z</time>
+      </trkpt>
+      <trkpt lat="47.197777507826686" lon="8.78841600380838">
+        <ele>473.44999999999999</ele>
+        <time>2016-01-03T12:05:48Z</time>
+      </trkpt>
+      <trkpt lat="47.19780064187944" lon="8.788405358791351">
+        <ele>473.45999999999998</ele>
+        <time>2016-01-03T12:05:49Z</time>
+      </trkpt>
+      <trkpt lat="47.197963669896126" lon="8.788386499509215">
+        <ele>470.27999999999997</ele>
+        <time>2016-01-03T12:05:53Z</time>
+      </trkpt>
+      <trkpt lat="47.1981308888644" lon="8.788295891135931">
+        <ele>467.20999999999998</ele>
+        <time>2016-01-03T12:05:57Z</time>
+      </trkpt>
+      <trkpt lat="47.19813633710146" lon="8.788262866437435">
+        <ele>466.89999999999998</ele>
+        <time>2016-01-03T12:05:58Z</time>
+      </trkpt>
+      <trkpt lat="47.19812661409378" lon="8.788229255005717">
+        <ele>466.76999999999998</ele>
+        <time>2016-01-03T12:05:59Z</time>
+      </trkpt>
+      <trkpt lat="47.19810306094587" lon="8.788186172023416">
+        <ele>466.25</ele>
+        <time>2016-01-03T12:06:00Z</time>
+      </trkpt>
+      <trkpt lat="47.19808369874954" lon="8.788127414882183">
+        <ele>465.23000000000002</ele>
+        <time>2016-01-03T12:06:01Z</time>
+      </trkpt>
+      <trkpt lat="47.19807816669345" lon="8.788059940561652">
+        <ele>464.12</ele>
+        <time>2016-01-03T12:06:02Z</time>
+      </trkpt>
+      <trkpt lat="47.19808881171048" lon="8.787991376593709">
+        <ele>463.68000000000001</ele>
+        <time>2016-01-03T12:06:03Z</time>
+      </trkpt>
+      <trkpt lat="47.19811093993485" lon="8.787914346903563">
+        <ele>462.5</ele>
+        <time>2016-01-03T12:06:04Z</time>
+      </trkpt>
+      <trkpt lat="47.19815100543201" lon="8.78783798776567">
+        <ele>462.45999999999998</ele>
+        <time>2016-01-03T12:06:05Z</time>
+      </trkpt>
+      <trkpt lat="47.19819492660463" lon="8.787756934762001">
+        <ele>461.56999999999999</ele>
+        <time>2016-01-03T12:06:06Z</time>
+      </trkpt>
+      <trkpt lat="47.1982860378921" lon="8.787589464336634">
+        <ele>461.14999999999998</ele>
+        <time>2016-01-03T12:06:08Z</time>
+      </trkpt>
+      <trkpt lat="47.19831814058125" lon="8.7874944973737">
+        <ele>460.19</ele>
+        <time>2016-01-03T12:06:09Z</time>
+      </trkpt>
+      <trkpt lat="47.1983309648931" lon="8.787389053031802">
+        <ele>459.83999999999997</ele>
+        <time>2016-01-03T12:06:10Z</time>
+      </trkpt>
+      <trkpt lat="47.198331551626325" lon="8.787284530699253">
+        <ele>460.49000000000001</ele>
+        <time>2016-01-03T12:06:11Z</time>
+      </trkpt>
+      <trkpt lat="47.198325265198946" lon="8.787185624241829">
+        <ele>460.23000000000002</ele>
+        <time>2016-01-03T12:06:12Z</time>
+      </trkpt>
+      <trkpt lat="47.19824245199561" lon="8.78635254688561">
+        <ele>460.56999999999999</ele>
+        <time>2016-01-03T12:06:22Z</time>
+      </trkpt>
+      <trkpt lat="47.198192747309804" lon="8.78586145117879">
+        <ele>457.79000000000002</ele>
+        <time>2016-01-03T12:06:27Z</time>
+      </trkpt>
+      <trkpt lat="47.19819249585271" lon="8.78536943346262">
+        <ele>454.66000000000003</ele>
+        <time>2016-01-03T12:06:31Z</time>
+      </trkpt>
+    </trkseg>
+  </trk>
+  <trk>
+    <extensions>
+      <gpxd:color>#0000FF</gpxd:color>
+    </extensions>
+    <trkseg>
+      <trkpt lat="47.18660652637482" lon="8.796921372413635">
+        <ele>624.7421875</ele>
+      </trkpt>
+      <trkpt lat="47.186644077301025" lon="8.7968248128891">
+        <ele>626.015625</ele>
+      </trkpt>
+      <trkpt lat="47.18669772148132" lon="8.796712160110474">
+        <ele>627.0625</ele>
+      </trkpt>
+      <trkpt lat="47.18676209449768" lon="8.796610236167908">
+        <ele>627.3671875</ele>
+      </trkpt>
+      <trkpt lat="47.1868371963501" lon="8.796519041061401">
+        <ele>626.90234375</ele>
+      </trkpt>
+      <trkpt lat="47.186912298202515" lon="8.796401023864746">
+        <ele>626.11328125</ele>
+      </trkpt>
+      <trkpt lat="47.18698740005493" lon="8.796277642250061">
+        <ele>625.33203125</ele>
+      </trkpt>
+      <trkpt lat="47.18707859516144" lon="8.796148896217346">
+        <ele>623.90625</ele>
+      </trkpt>
+      <trkpt lat="47.18710541725159" lon="8.796095252037048">
+        <ele>623.66796875</ele>
+      </trkpt>
+      <trkpt lat="47.187126874923706" lon="8.796030879020691">
+        <ele>623.71484375</ele>
+      </trkpt>
+      <trkpt lat="47.187132239341736" lon="8.795977234840393">
+        <ele>623.75</ele>
+      </trkpt>
+      <trkpt lat="47.187132239341736" lon="8.795923590660095">
+        <ele>623.9375</ele>
+      </trkpt>
+      <trkpt lat="47.187132239341736" lon="8.795859217643738">
+        <ele>624.1640625</ele>
+      </trkpt>
+      <trkpt lat="47.18711078166962" lon="8.795735836029053">
+        <ele>625.234375</ele>
+      </trkpt>
+      <trkpt lat="47.18710005283356" lon="8.795607089996338">
+        <ele>626</ele>
+      </trkpt>
+      <trkpt lat="47.18709468841553" lon="8.795521259307861">
+        <ele>626.3515625</ele>
+      </trkpt>
+      <trkpt lat="47.18710541725159" lon="8.795440793037415">
+        <ele>626.14453125</ele>
+      </trkpt>
+      <trkpt lat="47.187126874923706" lon="8.795360326766968">
+        <ele>625.6640625</ele>
+      </trkpt>
+      <trkpt lat="47.187164425849915" lon="8.79528522491455">
+        <ele>624.7890625</ele>
+      </trkpt>
+      <trkpt lat="47.1872341632843" lon="8.795183300971985">
+        <ele>623.23046875</ele>
+      </trkpt>
+      <trkpt lat="47.18729317188263" lon="8.795086741447449">
+        <ele>622.09375</ele>
+      </trkpt>
+      <trkpt lat="47.18736290931702" lon="8.794984817504883">
+        <ele>620.9765625</ele>
+      </trkpt>
+      <trkpt lat="47.187416553497314" lon="8.794904351234436">
+        <ele>620.23828125</ele>
+      </trkpt>
+      <trkpt lat="47.18746483325958" lon="8.794845342636108">
+        <ele>619.42578125</ele>
+      </trkpt>
+      <trkpt lat="47.18752384185791" lon="8.79479706287384">
+        <ele>617.7734375</ele>
+      </trkpt>
+      <trkpt lat="47.18756139278412" lon="8.794743418693542">
+        <ele>616.8671875</ele>
+      </trkpt>
+      <trkpt lat="47.1875935792923" lon="8.794695138931274">
+        <ele>616.09765625</ele>
+      </trkpt>
+      <trkpt lat="47.18760967254639" lon="8.794630765914917">
+        <ele>615.87890625</ele>
+      </trkpt>
+      <trkpt lat="47.187620401382446" lon="8.7945556640625">
+        <ele>615.3984375</ele>
+      </trkpt>
+      <trkpt lat="47.187636494636536" lon="8.794485926628113">
+        <ele>614.76953125</ele>
+      </trkpt>
+      <trkpt lat="47.187674045562744" lon="8.794400095939636">
+        <ele>613.47265625</ele>
+      </trkpt>
+      <trkpt lat="47.18769550323486" lon="8.79430890083313">
+        <ele>612.72265625</ele>
+      </trkpt>
+      <trkpt lat="47.18770086765289" lon="8.794185519218445">
+        <ele>612.4609375</ele>
+      </trkpt>
+      <trkpt lat="47.18770086765289" lon="8.79407823085785">
+        <ele>611.85546875</ele>
+      </trkpt>
+      <trkpt lat="47.187684774398804" lon="8.793997764587402">
+        <ele>611.90625</ele>
+      </trkpt>
+      <trkpt lat="47.187663316726685" lon="8.793933391571045">
+        <ele>612.27734375</ele>
+      </trkpt>
+      <trkpt lat="47.18761503696442" lon="8.793869018554688">
+        <ele>613.66796875</ele>
+      </trkpt>
+      <trkpt lat="47.18758285045624" lon="8.79381537437439">
+        <ele>614.62890625</ele>
+      </trkpt>
+      <trkpt lat="47.18756675720215" lon="8.793767094612122">
+        <ele>615.0703125</ele>
+      </trkpt>
+      <trkpt lat="47.18757212162018" lon="8.793713450431824">
+        <ele>614.72265625</ele>
+      </trkpt>
+      <trkpt lat="47.18758821487427" lon="8.793681263923645">
+        <ele>614.26171875</ele>
+      </trkpt>
+      <trkpt lat="47.187641859054565" lon="8.793681263923645">
+        <ele>612.06640625</ele>
+      </trkpt>
+      <trkpt lat="47.18770086765289" lon="8.793708086013794">
+        <ele>609.6875</ele>
+      </trkpt>
+      <trkpt lat="47.18778133392334" lon="8.793751001358032">
+        <ele>606.83984375</ele>
+      </trkpt>
+      <trkpt lat="47.18785107135773" lon="8.79380464553833">
+        <ele>604.671875</ele>
+      </trkpt>
+      <trkpt lat="47.187920808792114" lon="8.793842196464539">
+        <ele>602.52734375</ele>
+      </trkpt>
+      <trkpt lat="47.18800127506256" lon="8.793911933898926">
+        <ele>600.78515625</ele>
+      </trkpt>
+      <trkpt lat="47.18811392784119" lon="8.794013857841492">
+        <ele>598.078125</ele>
+      </trkpt>
+      <trkpt lat="47.188151478767395" lon="8.79406213760376">
+        <ele>597.1953125</ele>
+      </trkpt>
+      <trkpt lat="47.1881890296936" lon="8.794153332710266">
+        <ele>596.5234375</ele>
+      </trkpt>
+      <trkpt lat="47.18821585178375" lon="8.794239163398743">
+        <ele>595.74609375</ele>
+      </trkpt>
+      <trkpt lat="47.1882426738739" lon="8.794351816177368">
+        <ele>594.82421875</ele>
+      </trkpt>
+      <trkpt lat="47.18826413154602" lon="8.794426918029785">
+        <ele>594.10546875</ele>
+      </trkpt>
+      <trkpt lat="47.18829095363617" lon="8.794475197792053">
+        <ele>593.2109375</ele>
+      </trkpt>
+      <trkpt lat="47.18830704689026" lon="8.794523477554321">
+        <ele>592.6875</ele>
+      </trkpt>
+      <trkpt lat="47.18831241130829" lon="8.794614672660828">
+        <ele>592.5390625</ele>
+      </trkpt>
+      <trkpt lat="47.18830704689026" lon="8.79479706287384">
+        <ele>592.7578125</ele>
+      </trkpt>
+      <trkpt lat="47.18830704689026" lon="8.794888257980347">
+        <ele>592.77734375</ele>
+      </trkpt>
+      <trkpt lat="47.18831241130829" lon="8.794941902160645">
+        <ele>592.63671875</ele>
+      </trkpt>
+      <trkpt lat="47.18833386898041" lon="8.794995546340942">
+        <ele>592.06640625</ele>
+      </trkpt>
+      <trkpt lat="47.188366055488586" lon="8.7950599193573">
+        <ele>591.2578125</ele>
+      </trkpt>
+      <trkpt lat="47.188403606414795" lon="8.795113563537598">
+        <ele>590.46875</ele>
+      </trkpt>
+      <trkpt lat="47.188435792922974" lon="8.795167207717896">
+        <ele>589.7578125</ele>
+      </trkpt>
+      <trkpt lat="47.18845188617706" lon="8.795226216316223">
+        <ele>589.359375</ele>
+      </trkpt>
+      <trkpt lat="47.18846261501312" lon="8.79529058933258">
+        <ele>589.05859375</ele>
+      </trkpt>
+      <trkpt lat="47.18845188617706" lon="8.795354962348938">
+        <ele>589.21875</ele>
+      </trkpt>
+      <trkpt lat="47.188430428504944" lon="8.795451521873474">
+        <ele>589.59375</ele>
+      </trkpt>
+      <trkpt lat="47.188408970832825" lon="8.7955641746521">
+        <ele>589.98046875</ele>
+      </trkpt>
+      <trkpt lat="47.188403606414795" lon="8.795655369758606">
+        <ele>589.51953125</ele>
+      </trkpt>
+      <trkpt lat="47.188408970832825" lon="8.795746564865112">
+        <ele>588.796875</ele>
+      </trkpt>
+      <trkpt lat="47.188435792922974" lon="8.795859217643738">
+        <ele>587.4375</ele>
+      </trkpt>
+      <trkpt lat="47.18847870826721" lon="8.795971870422363">
+        <ele>585.70703125</ele>
+      </trkpt>
+      <trkpt lat="47.18850553035736" lon="8.79605233669281">
+        <ele>584.48046875</ele>
+      </trkpt>
+      <trkpt lat="47.18852162361145" lon="8.796132802963257">
+        <ele>583.328125</ele>
+      </trkpt>
+      <trkpt lat="47.18852162361145" lon="8.796197175979614">
+        <ele>582.69921875</ele>
+      </trkpt>
+      <trkpt lat="47.18851625919342" lon="8.79628300666809">
+        <ele>581.96875</ele>
+      </trkpt>
+      <trkpt lat="47.18850016593933" lon="8.796379566192627">
+        <ele>581.3359375</ele>
+      </trkpt>
+      <trkpt lat="47.18848943710327" lon="8.796465396881104">
+        <ele>580.6796875</ele>
+      </trkpt>
+      <trkpt lat="47.18848943710327" lon="8.796524405479431">
+        <ele>580.33984375</ele>
+      </trkpt>
+      <trkpt lat="47.18850016593933" lon="8.796578049659729">
+        <ele>580.0234375</ele>
+      </trkpt>
+      <trkpt lat="47.18852162361145" lon="8.796631693840027">
+        <ele>579.5078125</ele>
+      </trkpt>
+      <trkpt lat="47.1885484457016" lon="8.796685338020325">
+        <ele>578.890625</ele>
+      </trkpt>
+      <trkpt lat="47.18856990337372" lon="8.796749711036682">
+        <ele>578.34375</ele>
+      </trkpt>
+      <trkpt lat="47.18858063220978" lon="8.79681944847107">
+        <ele>577.984375</ele>
+      </trkpt>
+      <trkpt lat="47.18857526779175" lon="8.796899914741516">
+        <ele>577.90234375</ele>
+      </trkpt>
+      <trkpt lat="47.18858599662781" lon="8.796991109848022">
+        <ele>577.50390625</ele>
+      </trkpt>
+      <trkpt lat="47.18859672546387" lon="8.79704475402832">
+        <ele>577.20703125</ele>
+      </trkpt>
+      <trkpt lat="47.188623547554016" lon="8.797119855880737">
+        <ele>576.6171875</ele>
+      </trkpt>
+      <trkpt lat="47.188666462898254" lon="8.797189593315125">
+        <ele>575.82421875</ele>
+      </trkpt>
+      <trkpt lat="47.18870937824249" lon="8.797211050987244">
+        <ele>575.125</ele>
+      </trkpt>
+      <trkpt lat="47.18871474266052" lon="8.797157406806946">
+        <ele>575.0546875</ele>
+      </trkpt>
+      <trkpt lat="47.18872547149658" lon="8.79705548286438">
+        <ele>574.89453125</ele>
+      </trkpt>
+      <trkpt lat="47.18873620033264" lon="8.796937465667725">
+        <ele>574.75</ele>
+      </trkpt>
+      <trkpt lat="47.18875765800476" lon="8.79681408405304">
+        <ele>574.6484375</ele>
+      </trkpt>
+      <trkpt lat="47.18879520893097" lon="8.796685338020325">
+        <ele>574.26953125</ele>
+      </trkpt>
+      <trkpt lat="47.18883812427521" lon="8.796588778495789">
+        <ele>573.72265625</ele>
+      </trkpt>
+      <trkpt lat="47.188907861709595" lon="8.796438574790955">
+        <ele>572.4296875</ele>
+      </trkpt>
+      <trkpt lat="47.18901515007019" lon="8.796240091323853">
+        <ele>570.828125</ele>
+      </trkpt>
+      <trkpt lat="47.18906342983246" lon="8.796154260635376">
+        <ele>570.1015625</ele>
+      </trkpt>
+      <trkpt lat="47.189154624938965" lon="8.795987963676453">
+        <ele>568.7734375</ele>
+      </trkpt>
+      <trkpt lat="47.18921899795532" lon="8.795869946479797">
+        <ele>567.8125</ele>
+      </trkpt>
+      <trkpt lat="47.18926191329956" lon="8.795778751373291">
+        <ele>567.25390625</ele>
+      </trkpt>
+      <trkpt lat="47.18928337097168" lon="8.795714378356934">
+        <ele>567.09765625</ele>
+      </trkpt>
+      <trkpt lat="47.18929409980774" lon="8.795660734176636">
+        <ele>567.1640625</ele>
+      </trkpt>
+      <trkpt lat="47.18929946422577" lon="8.795580267906189">
+        <ele>567.546875</ele>
+      </trkpt>
+      <trkpt lat="47.18929946422577" lon="8.795451521873474">
+        <ele>567.86328125</ele>
+      </trkpt>
+      <trkpt lat="47.18929409980774" lon="8.7953120470047">
+        <ele>568.2890625</ele>
+      </trkpt>
+      <trkpt lat="47.18929409980774" lon="8.795210123062134">
+        <ele>568.49609375</ele>
+      </trkpt>
+      <trkpt lat="47.1893048286438" lon="8.795135021209717">
+        <ele>568.33203125</ele>
+      </trkpt>
+      <trkpt lat="47.18934237957001" lon="8.794904351234436">
+        <ele>566.84765625</ele>
+      </trkpt>
+      <trkpt lat="47.18934774398804" lon="8.794845342636108">
+        <ele>566.609375</ele>
+      </trkpt>
+      <trkpt lat="47.18933701515198" lon="8.794738054275513">
+        <ele>566.94140625</ele>
+      </trkpt>
+      <trkpt lat="47.18933701515198" lon="8.794657588005066">
+        <ele>566.88671875</ele>
+      </trkpt>
+      <trkpt lat="47.18935310840607" lon="8.79457712173462">
+        <ele>566.27734375</ele>
+      </trkpt>
+      <trkpt lat="47.189374566078186" lon="8.794502019882202">
+        <ele>565.48046875</ele>
+      </trkpt>
+      <trkpt lat="47.189428210258484" lon="8.794384002685547">
+        <ele>563.5</ele>
+      </trkpt>
+      <trkpt lat="47.18945503234863" lon="8.7943035364151">
+        <ele>562.51953125</ele>
+      </trkpt>
+      <trkpt lat="47.18947112560272" lon="8.794206976890564">
+        <ele>561.9453125</ele>
+      </trkpt>
+      <trkpt lat="47.18948185443878" lon="8.79407286643982">
+        <ele>561.85546875</ele>
+      </trkpt>
+      <trkpt lat="47.18949794769287" lon="8.793911933898926">
+        <ele>561.7578125</ele>
+      </trkpt>
+      <trkpt lat="47.18950867652893" lon="8.79378855228424">
+        <ele>561.765625</ele>
+      </trkpt>
+      <trkpt lat="47.18952476978302" lon="8.793686628341675">
+        <ele>561.453125</ele>
+      </trkpt>
+      <trkpt lat="47.18955159187317" lon="8.79356861114502">
+        <ele>560.6015625</ele>
+      </trkpt>
+      <trkpt lat="47.18958377838135" lon="8.793466687202454">
+        <ele>559.65234375</ele>
+      </trkpt>
+      <trkpt lat="47.189615964889526" lon="8.793386220932007">
+        <ele>558.7578125</ele>
+      </trkpt>
+      <trkpt lat="47.189658880233765" lon="8.793278932571411">
+        <ele>557.66015625</ele>
+      </trkpt>
+      <trkpt lat="47.18971252441406" lon="8.793187737464905">
+        <ele>556.35546875</ele>
+      </trkpt>
+      <trkpt lat="47.18976080417633" lon="8.793118000030518">
+        <ele>555.2265625</ele>
+      </trkpt>
+      <trkpt lat="47.18983054161072" lon="8.79304826259613">
+        <ele>553.53125</ele>
+      </trkpt>
+      <trkpt lat="47.189921736717224" lon="8.792962431907654">
+        <ele>551.265625</ele>
+      </trkpt>
+      <trkpt lat="47.18997538089752" lon="8.792903423309326">
+        <ele>549.92578125</ele>
+      </trkpt>
+      <trkpt lat="47.1900075674057" lon="8.792855143547058">
+        <ele>549.140625</ele>
+      </trkpt>
+      <trkpt lat="47.19003438949585" lon="8.792780041694641">
+        <ele>548.48828125</ele>
+      </trkpt>
+      <trkpt lat="47.19004511833191" lon="8.792726397514343">
+        <ele>548.0078125</ele>
+      </trkpt>
+      <trkpt lat="47.19005584716797" lon="8.792635202407837">
+        <ele>547.39453125</ele>
+      </trkpt>
+      <trkpt lat="47.19005584716797" lon="8.79256546497345">
+        <ele>547.15234375</ele>
+      </trkpt>
+      <trkpt lat="47.19005048274994" lon="8.792501091957092">
+        <ele>547.08203125</ele>
+      </trkpt>
+      <trkpt lat="47.19001829624176" lon="8.792366981506348">
+        <ele>547.55078125</ele>
+      </trkpt>
+      <trkpt lat="47.18994319438934" lon="8.792104125022888">
+        <ele>548.69921875</ele>
+      </trkpt>
+      <trkpt lat="47.189932465553284" lon="8.792034387588501">
+        <ele>548.76953125</ele>
+      </trkpt>
+      <trkpt lat="47.189932465553284" lon="8.791970014572144">
+        <ele>548.51953125</ele>
+      </trkpt>
+      <trkpt lat="47.18994319438934" lon="8.791900277137756">
+        <ele>547.88671875</ele>
+      </trkpt>
+      <trkpt lat="47.18997001647949" lon="8.79183053970337">
+        <ele>546.7265625</ele>
+      </trkpt>
+      <trkpt lat="47.19000220298767" lon="8.791755437850952">
+        <ele>545.3984375</ele>
+      </trkpt>
+      <trkpt lat="47.19003975391388" lon="8.791680335998535">
+        <ele>543.87890625</ele>
+      </trkpt>
+      <trkpt lat="47.190120220184326" lon="8.791535496711731">
+        <ele>540.6484375</ele>
+      </trkpt>
+      <trkpt lat="47.19023287296295" lon="8.79129409790039">
+        <ele>536.4296875</ele>
+      </trkpt>
+      <trkpt lat="47.19025433063507" lon="8.791224360466003">
+        <ele>536.046875</ele>
+      </trkpt>
+      <trkpt lat="47.19027042388916" lon="8.791149258613586">
+        <ele>535.765625</ele>
+      </trkpt>
+      <trkpt lat="47.19027578830719" lon="8.791015148162842">
+        <ele>535.71875</ele>
+      </trkpt>
+      <trkpt lat="47.19027578830719" lon="8.790768384933472">
+        <ele>535.55859375</ele>
+      </trkpt>
+      <trkpt lat="47.19026505947113" lon="8.790435791015625">
+        <ele>535.359375</ele>
+      </trkpt>
+      <trkpt lat="47.1902596950531" lon="8.790162205696106">
+        <ele>534.5234375</ele>
+      </trkpt>
+      <trkpt lat="47.1902596950531" lon="8.789920806884766">
+        <ele>534.2578125</ele>
+      </trkpt>
+      <trkpt lat="47.19025433063507" lon="8.789674043655396">
+        <ele>535.1328125</ele>
+      </trkpt>
+      <trkpt lat="47.19025433063507" lon="8.78955602645874">
+        <ele>535.46875</ele>
+      </trkpt>
+      <trkpt lat="47.19025433063507" lon="8.789491653442383">
+        <ele>535.04296875</ele>
+      </trkpt>
+      <trkpt lat="47.19027042388916" lon="8.789438009262085">
+        <ele>534.04296875</ele>
+      </trkpt>
+      <trkpt lat="47.19030797481537" lon="8.789384365081787">
+        <ele>532.234375</ele>
+      </trkpt>
+      <trkpt lat="47.19035625457764" lon="8.789357542991638">
+        <ele>530.2109375</ele>
+      </trkpt>
+      <trkpt lat="47.190393805503845" lon="8.789357542991638">
+        <ele>528.7890625</ele>
+      </trkpt>
+      <trkpt lat="47.190425992012024" lon="8.789373636245728">
+        <ele>527.69140625</ele>
+      </trkpt>
+      <trkpt lat="47.1904581785202" lon="8.789411187171936">
+        <ele>526.76171875</ele>
+      </trkpt>
+      <trkpt lat="47.19048500061035" lon="8.789459466934204">
+        <ele>526.1171875</ele>
+      </trkpt>
+      <trkpt lat="47.19050645828247" lon="8.789529204368591">
+        <ele>525.83984375</ele>
+      </trkpt>
+      <trkpt lat="47.19052255153656" lon="8.789609670639038">
+        <ele>525.51171875</ele>
+      </trkpt>
+      <trkpt lat="47.19053328037262" lon="8.789727687835693">
+        <ele>525.34375</ele>
+      </trkpt>
+      <trkpt lat="47.19054400920868" lon="8.78982961177826">
+        <ele>525.18359375</ele>
+      </trkpt>
+      <trkpt lat="47.19058692455292" lon="8.790022730827332">
+        <ele>524.3515625</ele>
+      </trkpt>
+      <trkpt lat="47.190635204315186" lon="8.790242671966553">
+        <ele>524.41015625</ele>
+      </trkpt>
+      <trkpt lat="47.190672755241394" lon="8.790398240089417">
+        <ele>524.47265625</ele>
+      </trkpt>
+      <trkpt lat="47.19072639942169" lon="8.79054844379425">
+        <ele>524.02734375</ele>
+      </trkpt>
+      <trkpt lat="47.19078004360199" lon="8.790677189826965">
+        <ele>523.09375</ele>
+      </trkpt>
+      <trkpt lat="47.19083368778229" lon="8.79082202911377">
+        <ele>521.92578125</ele>
+      </trkpt>
+      <trkpt lat="47.190876603126526" lon="8.790961503982544">
+        <ele>520.87109375</ele>
+      </trkpt>
+      <trkpt lat="47.190908789634705" lon="8.791095614433289">
+        <ele>520.51953125</ele>
+      </trkpt>
+      <trkpt lat="47.19093561172485" lon="8.791192173957825">
+        <ele>520.2578125</ele>
+      </trkpt>
+      <trkpt lat="47.19097316265106" lon="8.791267275810242">
+        <ele>519.6640625</ele>
+      </trkpt>
+      <trkpt lat="47.19103217124939" lon="8.791337013244629">
+        <ele>518.5703125</ele>
+      </trkpt>
+      <trkpt lat="47.191112637519836" lon="8.791401386260986">
+        <ele>517.04296875</ele>
+      </trkpt>
+      <trkpt lat="47.19128429889679" lon="8.791524767875671">
+        <ele>513.03125</ele>
+      </trkpt>
+      <trkpt lat="47.191407680511475" lon="8.791610598564148">
+        <ele>510.19921875</ele>
+      </trkpt>
+      <trkpt lat="47.19148814678192" lon="8.791669607162476">
+        <ele>508.5</ele>
+      </trkpt>
+      <trkpt lat="47.1915203332901" lon="8.791696429252625">
+        <ele>507.8828125</ele>
+      </trkpt>
+      <trkpt lat="47.19157934188843" lon="8.791739344596863">
+        <ele>506.71875</ele>
+      </trkpt>
+      <trkpt lat="47.191627621650696" lon="8.79179835319519">
+        <ele>506.03125</ele>
+      </trkpt>
+      <trkpt lat="47.191659808158875" lon="8.791851997375488">
+        <ele>505.5390625</ele>
+      </trkpt>
+      <trkpt lat="47.19168663024902" lon="8.791916370391846">
+        <ele>504.96875</ele>
+      </trkpt>
+      <trkpt lat="47.1917188167572" lon="8.792018294334412">
+        <ele>504.28125</ele>
+      </trkpt>
+      <trkpt lat="47.19175100326538" lon="8.792141675949097">
+        <ele>503.6640625</ele>
+      </trkpt>
+      <trkpt lat="47.19179928302765" lon="8.79229724407196">
+        <ele>502.578125</ele>
+      </trkpt>
+      <trkpt lat="47.19184219837189" lon="8.792458176612854">
+        <ele>500.921875</ele>
+      </trkpt>
+      <trkpt lat="47.191869020462036" lon="8.79257082939148">
+        <ele>499.85546875</ele>
+      </trkpt>
+      <trkpt lat="47.191879749298096" lon="8.792662024497986">
+        <ele>499.40234375</ele>
+      </trkpt>
+      <trkpt lat="47.191890478134155" lon="8.792763948440552">
+        <ele>498.96875</ele>
+      </trkpt>
+      <trkpt lat="47.191895842552185" lon="8.792887330055237">
+        <ele>497.8828125</ele>
+      </trkpt>
+      <trkpt lat="47.191895842552185" lon="8.79306435585022">
+        <ele>496.2265625</ele>
+      </trkpt>
+      <trkpt lat="47.191901206970215" lon="8.793182373046875">
+        <ele>494.9609375</ele>
+      </trkpt>
+      <trkpt lat="47.191906571388245" lon="8.793257474899292">
+        <ele>494.13671875</ele>
+      </trkpt>
+      <trkpt lat="47.191928029060364" lon="8.793343305587769">
+        <ele>493.6015625</ele>
+      </trkpt>
+      <trkpt lat="47.19196021556854" lon="8.793472051620483">
+        <ele>492.828125</ele>
+      </trkpt>
+      <trkpt lat="47.19199282117188" lon="8.793616723269224">
+        <ele>492.1015625</ele>
+      </trkpt>
+      <trkpt lat="47.19200849533081" lon="8.793686628341675">
+        <ele>491.76953125</ele>
+      </trkpt>
+      <trkpt lat="47.19204068183899" lon="8.793852925300598">
+        <ele>490.83984375</ele>
+      </trkpt>
+      <trkpt lat="47.19206213951111" lon="8.793992400169373">
+        <ele>490.23828125</ele>
+      </trkpt>
+      <trkpt lat="47.19207286834717" lon="8.7940514087677">
+        <ele>489.96484375</ele>
+      </trkpt>
+      <trkpt lat="47.19208359718323" lon="8.794147968292236">
+        <ele>489.703125</ele>
+      </trkpt>
+      <trkpt lat="47.192121148109436" lon="8.795000910758972">
+        <ele>484.7109375</ele>
+      </trkpt>
+      <trkpt lat="47.192137241363525" lon="8.79530131816864">
+        <ele>482.328125</ele>
+      </trkpt>
+      <trkpt lat="47.192137241363525" lon="8.795451521873474">
+        <ele>481.04296875</ele>
+      </trkpt>
+      <trkpt lat="47.192137241363525" lon="8.79553735256195">
+        <ele>480.3046875</ele>
+      </trkpt>
+      <trkpt lat="47.192126512527466" lon="8.795607089996338">
+        <ele>479.70703125</ele>
+      </trkpt>
+      <trkpt lat="47.19211041927338" lon="8.795682191848755">
+        <ele>478.984375</ele>
+      </trkpt>
+      <trkpt lat="47.19208896160126" lon="8.795746564865112">
+        <ele>478.4609375</ele>
+      </trkpt>
+      <trkpt lat="47.19203531742096" lon="8.795832395553589">
+        <ele>479.1015625</ele>
+      </trkpt>
+      <trkpt lat="47.19198167324066" lon="8.795896768569946">
+        <ele>480.359375</ele>
+      </trkpt>
+      <trkpt lat="47.19194948673248" lon="8.795934319496155">
+        <ele>481.19140625</ele>
+      </trkpt>
+      <trkpt lat="47.191906571388245" lon="8.795993328094482">
+        <ele>482.2890625</ele>
+      </trkpt>
+      <trkpt lat="47.191869020462036" lon="8.79606306552887">
+        <ele>483.28125</ele>
+      </trkpt>
+      <trkpt lat="47.19184756278992" lon="8.796138167381287">
+        <ele>483.69921875</ele>
+      </trkpt>
+      <trkpt lat="47.19184219837189" lon="8.796213269233704">
+        <ele>483.4609375</ele>
+      </trkpt>
+      <trkpt lat="47.19184219837189" lon="8.79628300666809">
+        <ele>483.0390625</ele>
+      </trkpt>
+      <trkpt lat="47.19185829162598" lon="8.796374201774597">
+        <ele>481.9140625</ele>
+      </trkpt>
+      <trkpt lat="47.191885113716125" lon="8.796454668045044">
+        <ele>480.515625</ele>
+      </trkpt>
+      <trkpt lat="47.191917300224304" lon="8.796513676643372">
+        <ele>479.16796875</ele>
+      </trkpt>
+      <trkpt lat="47.19198703765869" lon="8.796631693840027">
+        <ele>476.74609375</ele>
+      </trkpt>
+      <trkpt lat="47.19206750392914" lon="8.796760439872742">
+        <ele>474.3515625</ele>
+      </trkpt>
+      <trkpt lat="47.192131876945496" lon="8.796835541725159">
+        <ele>473.28515625</ele>
+      </trkpt>
+      <trkpt lat="47.19219088554382" lon="8.796894550323486">
+        <ele>472.39453125</ele>
+      </trkpt>
+      <trkpt lat="47.19225525856018" lon="8.796948194503784">
+        <ele>471.3671875</ele>
+      </trkpt>
+      <trkpt lat="47.19234645366669" lon="8.797001838684082">
+        <ele>470.0390625</ele>
+      </trkpt>
+      <trkpt lat="47.192426919937134" lon="8.79704475402832">
+        <ele>468.76171875</ele>
+      </trkpt>
+      <trkpt lat="47.19250738620758" lon="8.797082304954529">
+        <ele>467.3671875</ele>
+      </trkpt>
+      <trkpt lat="47.19255566596985" lon="8.797114491462708">
+        <ele>466.60546875</ele>
+      </trkpt>
+      <trkpt lat="47.1927273273468" lon="8.797253966331482">
+        <ele>464.65625</ele>
+      </trkpt>
+      <trkpt lat="47.19280779361725" lon="8.79730761051178">
+        <ele>463.62109375</ele>
+      </trkpt>
+      <trkpt lat="47.19286604784429" lon="8.79733837209642">
+        <ele>462.84375</ele>
+      </trkpt>
+      <trkpt lat="47.19286596402526" lon="8.797338204458356">
+        <ele>462.84765625</ele>
+      </trkpt>
+    </trkseg>
+  </trk>
+  <trk>
+    <extensions>
+      <gpxd:color>#00FF00</gpxd:color>
+    </extensions>
+    <trkseg>
+      <trkpt lat="47.18561486341059" lon="8.796475538983941">
+        <ele>647.81640625</ele>
+      </trkpt>
+      <trkpt lat="47.185668759047985" lon="8.796514933928847">
+        <ele>646.87109375</ele>
+      </trkpt>
+      <trkpt lat="47.18571729026735" lon="8.796522812917829">
+        <ele>646.1953125</ele>
+      </trkpt>
+      <trkpt lat="47.185757691040635" lon="8.796562207862735">
+        <ele>645.5859375</ele>
+      </trkpt>
+      <trkpt lat="47.18580354005098" lon="8.796577882021666">
+        <ele>644.8203125</ele>
+      </trkpt>
+      <trkpt lat="47.185914013534784" lon="8.796581821516156">
+        <ele>642.9765625</ele>
+      </trkpt>
+      <trkpt lat="47.18596254475415" lon="8.796625155955553">
+        <ele>641.796875</ele>
+      </trkpt>
+      <trkpt lat="47.186081148684025" lon="8.796644853428006">
+        <ele>639.4296875</ele>
+      </trkpt>
+      <trkpt lat="47.186186257749796" lon="8.7967315223068">
+        <ele>636.4921875</ele>
+      </trkpt>
+      <trkpt lat="47.186264377087355" lon="8.796790530905128">
+        <ele>634.1328125</ele>
+      </trkpt>
+      <trkpt lat="47.18639915809035" lon="8.796892957761884">
+        <ele>629.55859375</ele>
+      </trkpt>
+      <trkpt lat="47.186458418145776" lon="8.7969284132123">
+        <ele>627.55078125</ele>
+      </trkpt>
+      <trkpt lat="47.18660661019385" lon="8.796955989673734">
+        <ele>624.0234375</ele>
+      </trkpt>
+    </trkseg>
+  </trk>
+  <trk>
+    <extensions>
+      <gpxd:color>#FFCC00</gpxd:color>
+    </extensions>
+    <trkseg>
+      <trkpt lat="47.18490038998425" lon="8.796944171190262">
+        <ele>663.90234375</ele>
+      </trkpt>
+      <trkpt lat="47.18495160341263" lon="8.796790530905128">
+        <ele>662.74609375</ele>
+      </trkpt>
+      <trkpt lat="47.18495696783066" lon="8.796640913933516">
+        <ele>662.1328125</ele>
+      </trkpt>
+      <trkpt lat="47.184981275349855" lon="8.796550389379263">
+        <ele>661.39453125</ele>
+      </trkpt>
+      <trkpt lat="47.18511060811579" lon="8.796479478478432">
+        <ele>658.98828125</ele>
+      </trkpt>
+      <trkpt lat="47.18521839939058" lon="8.7964085675776">
+        <ele>657.47265625</ele>
+      </trkpt>
+      <trkpt lat="47.18536122702062" lon="8.796420386061072">
+        <ele>654.22265625</ele>
+      </trkpt>
+      <trkpt lat="47.18553640879691" lon="8.796440083533525">
+        <ele>650.0703125</ele>
+      </trkpt>
+      <trkpt lat="47.185609163716435" lon="8.796475538983941">
+        <ele>647.890625</ele>
+      </trkpt>
+    </trkseg>
+  </trk>
+  <trk>
+    <trkseg>
+      <trkpt lat="47.20138901844621" lon="8.774476982653141">
+        <ele>421.52999999999997</ele>
+        <time>2016-01-03T12:08:53Z</time>
+      </trkpt>
+      <trkpt lat="47.201492534950376" lon="8.773281471803784">
+        <ele>423.57999999999998</ele>
+        <time>2016-01-03T12:09:10Z</time>
+      </trkpt>
+      <trkpt lat="47.2014878410846" lon="8.772208672016859">
+        <ele>423</ele>
+        <time>2016-01-03T12:09:26Z</time>
+      </trkpt>
+      <trkpt lat="47.2014997433871" lon="8.772082105278969">
+        <ele>423.07999999999998</ele>
+        <time>2016-01-03T12:09:28Z</time>
+      </trkpt>
+      <trkpt lat="47.2014896851033" lon="8.772034915164113">
+        <ele>423.02999999999997</ele>
+        <time>2016-01-03T12:09:29Z</time>
+      </trkpt>
+      <trkpt lat="47.20144324935973" lon="8.77200884744525">
+        <ele>422.26999999999998</ele>
+        <time>2016-01-03T12:09:31Z</time>
+      </trkpt>
+      <trkpt lat="47.201405949890614" lon="8.7720338255167">
+        <ele>421.35000000000002</ele>
+        <time>2016-01-03T12:09:42Z</time>
+      </trkpt>
+      <trkpt lat="47.20132657326758" lon="8.771982276812196">
+        <ele>421.75</ele>
+        <time>2016-01-03T12:10:04Z</time>
+      </trkpt>
+      <trkpt lat="47.20126815140247" lon="8.77192972227931">
+        <ele>421.48000000000002</ele>
+        <time>2016-01-03T12:10:23Z</time>
+      </trkpt>
+    </trkseg>
+  </trk>
+</gpx>
Index: /trunk/test/unit/org/openstreetmap/josm/data/gpx/GpxDataTest.java
===================================================================
--- /trunk/test/unit/org/openstreetmap/josm/data/gpx/GpxDataTest.java	(revision 15495)
+++ /trunk/test/unit/org/openstreetmap/josm/data/gpx/GpxDataTest.java	(revision 15496)
@@ -36,4 +36,5 @@
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 import nl.jqno.equalsverifier.EqualsVerifier;
+import nl.jqno.equalsverifier.Warning;
 
 /**
@@ -64,5 +65,5 @@
     @Test
     public void testMergeFrom() {
-        ImmutableGpxTrack track = singleWaypointGpxTrack();
+        GpxTrack track = singleWaypointGpxTrack();
         GpxRoute route = singleWaypointRoute();
         WayPoint newWP = new WayPoint(LatLon.NORTH_POLE);
@@ -103,5 +104,7 @@
         final GpxData expected = getGpx(exp);
         own.mergeFrom(other, cut, connect);
-        assertEquals(expected, own);
+        own.put(GpxConstants.META_BOUNDS, null);
+        expected.put(GpxConstants.META_BOUNDS, null); //they are only updated by GpxWriter
+        assertEquals(exp + " didn't match!", expected, own);
     }
 
@@ -117,6 +120,6 @@
         assertEquals(0, data.getTracks().size());
 
-        ImmutableGpxTrack track1 = emptyGpxTrack();
-        ImmutableGpxTrack track2 = singleWaypointGpxTrack();
+        GpxTrack track1 = emptyGpxTrack();
+        GpxTrack track2 = singleWaypointGpxTrack();
         data.addTrack(track1);
         assertEquals(1, data.getTracks().size());
@@ -137,5 +140,5 @@
     @Test(expected = IllegalArgumentException.class)
     public void testAddTrackFails() {
-        ImmutableGpxTrack track1 = emptyGpxTrack();
+        GpxTrack track1 = emptyGpxTrack();
         data.addTrack(track1);
         data.addTrack(track1);
@@ -147,5 +150,5 @@
     @Test(expected = IllegalArgumentException.class)
     public void testRemoveTrackFails() {
-        ImmutableGpxTrack track1 = emptyGpxTrack();
+        GpxTrack track1 = emptyGpxTrack();
         data.addTrack(track1);
         data.removeTrack(track1);
@@ -246,8 +249,8 @@
     public void testHasTrackPoints() {
         assertFalse(data.hasTrackPoints());
-        ImmutableGpxTrack track1 = emptyGpxTrack();
+        GpxTrack track1 = emptyGpxTrack();
         data.addTrack(track1);
         assertFalse(data.hasTrackPoints());
-        ImmutableGpxTrack track2 = singleWaypointGpxTrack();
+        GpxTrack track2 = singleWaypointGpxTrack();
         data.addTrack(track2);
         assertTrue(data.hasTrackPoints());
@@ -260,8 +263,8 @@
     public void testGetTrackPoints() {
         assertEquals(0, data.getTrackPoints().count());
-        ImmutableGpxTrack track1 = singleWaypointGpxTrack();
+        GpxTrack track1 = singleWaypointGpxTrack();
         data.addTrack(track1);
         assertEquals(1, data.getTrackPoints().count());
-        ImmutableGpxTrack track2 = singleWaypointGpxTrack();
+        GpxTrack track2 = singleWaypointGpxTrack();
         data.addTrack(track2);
         assertEquals(2, data.getTrackPoints().count());
@@ -281,5 +284,5 @@
     @Test
     public void testIsEmpty() {
-        ImmutableGpxTrack track1 = singleWaypointGpxTrack();
+        GpxTrack track1 = singleWaypointGpxTrack();
         WayPoint waypoint = new WayPoint(LatLon.ZERO);
         GpxRoute route = singleWaypointRoute();
@@ -308,9 +311,9 @@
     @Test
     public void testLength() {
-        ImmutableGpxTrack track1 = waypointGpxTrack(
+        GpxTrack track1 = waypointGpxTrack(
                 new WayPoint(new LatLon(0, 0)),
                 new WayPoint(new LatLon(1, 1)),
                 new WayPoint(new LatLon(0, 2)));
-        ImmutableGpxTrack track2 = waypointGpxTrack(
+        GpxTrack track2 = waypointGpxTrack(
                 new WayPoint(new LatLon(0, 0)),
                 new WayPoint(new LatLon(-1, 1)));
@@ -336,6 +339,6 @@
         p2.setTime(new Date(100020));
         p4.setTime(new Date(500020));
-        data.addTrack(new ImmutableGpxTrack(Arrays.asList(Arrays.asList(p1, p2)), Collections.emptyMap()));
-        data.addTrack(new ImmutableGpxTrack(Arrays.asList(Arrays.asList(p3, p4, p5)), Collections.emptyMap()));
+        data.addTrack(new GpxTrack(Arrays.asList(Arrays.asList(p1, p2)), Collections.emptyMap()));
+        data.addTrack(new GpxTrack(Arrays.asList(Arrays.asList(p3, p4, p5)), Collections.emptyMap()));
 
         Date[] times = data.getMinMaxTimeForAllTracks();
@@ -355,5 +358,5 @@
                 .map(WayPoint::new)
                 .collect(Collectors.toList());
-        data.addTrack(new ImmutableGpxTrack(Arrays.asList(points), Collections.emptyMap()));
+        data.addTrack(new GpxTrack(Arrays.asList(points), Collections.emptyMap()));
 
         WayPoint closeToMiddle = data.nearestPointOnTrack(new EastNorth(10, 0), 10);
@@ -449,14 +452,14 @@
     }
 
-    private static ImmutableGpxTrack emptyGpxTrack() {
-        return new ImmutableGpxTrack(Collections.<Collection<WayPoint>>emptyList(), Collections.emptyMap());
-    }
-
-    private static ImmutableGpxTrack singleWaypointGpxTrack() {
-        return new ImmutableGpxTrack(Collections.singleton(Collections.singleton(new WayPoint(LatLon.ZERO))), Collections.emptyMap());
-    }
-
-    private static ImmutableGpxTrack waypointGpxTrack(WayPoint... wps) {
-        return new ImmutableGpxTrack(Collections.singleton(Arrays.asList(wps)), Collections.emptyMap());
+    private static GpxTrack emptyGpxTrack() {
+        return new GpxTrack(Collections.<Collection<WayPoint>>emptyList(), Collections.emptyMap());
+    }
+
+    private static GpxTrack singleWaypointGpxTrack() {
+        return new GpxTrack(Collections.singleton(Collections.singleton(new WayPoint(LatLon.ZERO))), Collections.emptyMap());
+    }
+
+    private static GpxTrack waypointGpxTrack(WayPoint... wps) {
+        return new GpxTrack(Collections.singleton(Arrays.asList(wps)), Collections.emptyMap());
     }
 
@@ -473,8 +476,12 @@
     public void testEqualsContract() {
         TestUtils.assumeWorkingEqualsVerifier();
+        GpxExtensionCollection col = new GpxExtensionCollection();
+        col.add("josm", "from-server", "true");
         EqualsVerifier.forClass(GpxData.class).usingGetClass()
-            .withIgnoredFields("attr", "creator", "fromServer", "storageFile", "listeners", "tracks", "routes", "waypoints", "proxy", "segSpans")
+            .suppress(Warning.NONFINAL_FIELDS)
+            .withIgnoredFields("creator", "fromServer", "storageFile", "initializing", "updating", "suppressedInvalidate", "listeners", "tracks", "routes", "waypoints", "proxy", "segSpans", "modified")
             .withPrefabValues(WayPoint.class, new WayPoint(LatLon.NORTH_POLE), new WayPoint(LatLon.SOUTH_POLE))
             .withPrefabValues(ListenerList.class, ListenerList.create(), ListenerList.create())
+            .withPrefabValues(GpxExtensionCollection.class, new GpxExtensionCollection(), col)
             .verify();
     }
Index: /trunk/test/unit/org/openstreetmap/josm/data/gpx/GpxExtensionTest.java
===================================================================
--- /trunk/test/unit/org/openstreetmap/josm/data/gpx/GpxExtensionTest.java	(revision 15496)
+++ /trunk/test/unit/org/openstreetmap/josm/data/gpx/GpxExtensionTest.java	(revision 15496)
@@ -0,0 +1,46 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.data.gpx;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.openstreetmap.josm.TestUtils;
+import org.openstreetmap.josm.gui.layer.gpx.ConvertToDataLayerActionTest;
+import org.openstreetmap.josm.io.GpxReaderTest;
+import org.openstreetmap.josm.io.GpxWriterTest;
+import org.openstreetmap.josm.testutils.JOSMTestRules;
+
+import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+import nl.jqno.equalsverifier.EqualsVerifier;
+import nl.jqno.equalsverifier.Warning;
+
+/**
+ * Unit tests for class {@link GpxExtension}
+ */
+public class GpxExtensionTest {
+
+    /**
+     * Setup test.
+     */
+    @Rule
+    @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
+    public JOSMTestRules test = new JOSMTestRules();
+
+    /**
+     * Unit test of methods {@link GpxExtension#equals} and {@link GpxExtension#hashCode}.
+     * @see GpxWriterTest#testExtensions()
+     * @see GpxReaderTest#testLayerPrefs()
+     * @see ConvertToDataLayerActionTest#testFromTrack()
+     */
+    @Test
+    public void testEqualsContract() {
+        TestUtils.assumeWorkingEqualsVerifier();
+        GpxExtensionCollection col = new GpxExtensionCollection();
+        col.add("josm", "from-server", "true");
+        EqualsVerifier.forClass(GpxExtension.class).usingGetClass()
+        .suppress(Warning.NONFINAL_FIELDS)
+        .withIgnoredFields("qualifiedName")
+        .withPrefabValues(GpxExtensionCollection.class, new GpxExtensionCollection(), col)
+        .verify();
+    }
+
+}
Index: /trunk/test/unit/org/openstreetmap/josm/data/gpx/GpxRouteTest.java
===================================================================
--- /trunk/test/unit/org/openstreetmap/josm/data/gpx/GpxRouteTest.java	(revision 15495)
+++ /trunk/test/unit/org/openstreetmap/josm/data/gpx/GpxRouteTest.java	(revision 15496)
@@ -30,7 +30,10 @@
     public void testEqualsContract() {
         TestUtils.assumeWorkingEqualsVerifier();
+        GpxExtensionCollection col = new GpxExtensionCollection();
+        col.add("josm", "from-server", "true");
         EqualsVerifier.forClass(GpxRoute.class).usingGetClass()
             .suppress(Warning.NONFINAL_FIELDS)
             .withPrefabValues(WayPoint.class, new WayPoint(LatLon.NORTH_POLE), new WayPoint(LatLon.SOUTH_POLE))
+            .withPrefabValues(GpxExtensionCollection.class, new GpxExtensionCollection(), col)
             .verify();
     }
Index: /trunk/test/unit/org/openstreetmap/josm/data/gpx/GpxTrackSegmentTest.java
===================================================================
--- /trunk/test/unit/org/openstreetmap/josm/data/gpx/GpxTrackSegmentTest.java	(revision 15496)
+++ /trunk/test/unit/org/openstreetmap/josm/data/gpx/GpxTrackSegmentTest.java	(revision 15496)
@@ -0,0 +1,41 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.data.gpx;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.openstreetmap.josm.TestUtils;
+import org.openstreetmap.josm.data.coor.LatLon;
+import org.openstreetmap.josm.testutils.JOSMTestRules;
+
+import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+import nl.jqno.equalsverifier.EqualsVerifier;
+import nl.jqno.equalsverifier.Warning;
+
+/**
+ * Unit tests for class {@link GpxTrackSegment}.
+ */
+public class GpxTrackSegmentTest {
+
+    /**
+     * Setup test.
+     */
+    @Rule
+    @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
+    public JOSMTestRules test = new JOSMTestRules();
+
+    /**
+     * Unit test of methods {@link GpxTrackSegment#equals} and {@link GpxTrackSegment#hashCode}.
+     */
+    @Test
+    public void testEqualsContract() {
+        TestUtils.assumeWorkingEqualsVerifier();
+        GpxExtensionCollection col = new GpxExtensionCollection();
+        col.add("josm", "from-server", "true");
+        EqualsVerifier.forClass(GpxTrackSegment.class).usingGetClass()
+            .suppress(Warning.NONFINAL_FIELDS)
+            .withIgnoredFields("bounds", "length")
+            .withPrefabValues(WayPoint.class, new WayPoint(LatLon.NORTH_POLE), new WayPoint(LatLon.SOUTH_POLE))
+            .withPrefabValues(GpxExtensionCollection.class, new GpxExtensionCollection(), col)
+            .verify();
+    }
+}
Index: /trunk/test/unit/org/openstreetmap/josm/data/gpx/GpxTrackTest.java
===================================================================
--- /trunk/test/unit/org/openstreetmap/josm/data/gpx/GpxTrackTest.java	(revision 15496)
+++ /trunk/test/unit/org/openstreetmap/josm/data/gpx/GpxTrackTest.java	(revision 15496)
@@ -0,0 +1,74 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.data.gpx;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+import java.awt.Color;
+import java.util.ArrayList;
+import java.util.HashMap;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.openstreetmap.josm.TestUtils;
+import org.openstreetmap.josm.testutils.JOSMTestRules;
+import org.openstreetmap.josm.tools.ListenerList;
+
+import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+import nl.jqno.equalsverifier.EqualsVerifier;
+import nl.jqno.equalsverifier.Warning;
+
+/**
+ * Unit tests for class {@link GpxTrack}.
+ */
+public class GpxTrackTest {
+
+    /**
+     * Setup test.
+     */
+    @Rule
+    @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
+    public JOSMTestRules test = new JOSMTestRules();
+
+    /**
+     * Tests weather the track can read and write colors.
+     */
+    @Test
+    public void testColors() {
+        GpxTrack trk = new GpxTrack(new ArrayList<IGpxTrackSegment>(), new HashMap<>());
+        GpxExtensionCollection ext = trk.getExtensions();
+        ext.add("gpxd", "color", "#FF0000");
+        trk.invalidate();
+        assertEquals(trk.getColor(), Color.RED);
+        trk.setColor(Color.GREEN);
+        assertEquals(trk.getColor(), Color.GREEN);
+        trk.invalidate();
+        assertEquals(trk.getColor(), Color.GREEN);
+        ext.remove("gpxd", "color");
+        trk.invalidate();
+        assertNull(trk.getColor());
+        ext.add("gpxx", "TrackExtensions").getExtensions().add("gpxx", "DisplayColor", "Blue");
+        trk.invalidate();
+        assertEquals(trk.getColor(), Color.BLUE);
+        trk.setColor(null);
+        assertNull(trk.getColor());
+        trk.invalidate();
+        assertNull(trk.getColor());
+    }
+
+    /**
+     * Unit test of methods {@link GpxTrack#equals} and {@link GpxTrack#hashCode}.
+     */
+    @Test
+    public void testEqualsContract() {
+        TestUtils.assumeWorkingEqualsVerifier();
+        GpxExtensionCollection col = new GpxExtensionCollection();
+        col.add("josm", "from-server", "true");
+        EqualsVerifier.forClass(GpxTrack.class).usingGetClass()
+            .suppress(Warning.NONFINAL_FIELDS)
+            .withPrefabValues(ListenerList.class, ListenerList.create(), ListenerList.create())
+            .withPrefabValues(GpxExtensionCollection.class, new GpxExtensionCollection(), col)
+            .withIgnoredFields("bounds", "length", "colorCache", "colorFormat", "listeners")
+            .verify();
+    }
+}
Index: unk/test/unit/org/openstreetmap/josm/data/gpx/ImmutableGpxTrackSegmentTest.java
===================================================================
--- /trunk/test/unit/org/openstreetmap/josm/data/gpx/ImmutableGpxTrackSegmentTest.java	(revision 15495)
+++ 	(revision )
@@ -1,36 +1,0 @@
-// License: GPL. For details, see LICENSE file.
-package org.openstreetmap.josm.data.gpx;
-
-import org.junit.Rule;
-import org.junit.Test;
-import org.openstreetmap.josm.TestUtils;
-import org.openstreetmap.josm.data.coor.LatLon;
-import org.openstreetmap.josm.testutils.JOSMTestRules;
-
-import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
-import nl.jqno.equalsverifier.EqualsVerifier;
-
-/**
- * Unit tests for class {@link ImmutableGpxTrackSegment}.
- */
-public class ImmutableGpxTrackSegmentTest {
-
-    /**
-     * Setup test.
-     */
-    @Rule
-    @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
-    public JOSMTestRules test = new JOSMTestRules();
-
-    /**
-     * Unit test of methods {@link ImmutableGpxTrackSegment#equals} and {@link ImmutableGpxTrackSegment#hashCode}.
-     */
-    @Test
-    public void testEqualsContract() {
-        TestUtils.assumeWorkingEqualsVerifier();
-        EqualsVerifier.forClass(ImmutableGpxTrackSegment.class).usingGetClass()
-            .withIgnoredFields("bounds", "length")
-            .withPrefabValues(WayPoint.class, new WayPoint(LatLon.NORTH_POLE), new WayPoint(LatLon.SOUTH_POLE))
-            .verify();
-    }
-}
Index: unk/test/unit/org/openstreetmap/josm/data/gpx/ImmutableGpxTrackTest.java
===================================================================
--- /trunk/test/unit/org/openstreetmap/josm/data/gpx/ImmutableGpxTrackTest.java	(revision 15495)
+++ 	(revision )
@@ -1,36 +1,0 @@
-// License: GPL. For details, see LICENSE file.
-package org.openstreetmap.josm.data.gpx;
-
-import org.junit.Rule;
-import org.junit.Test;
-import org.openstreetmap.josm.TestUtils;
-import org.openstreetmap.josm.testutils.JOSMTestRules;
-
-import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
-import nl.jqno.equalsverifier.EqualsVerifier;
-import nl.jqno.equalsverifier.Warning;
-
-/**
- * Unit tests for class {@link ImmutableGpxTrack}.
- */
-public class ImmutableGpxTrackTest {
-
-    /**
-     * Setup test.
-     */
-    @Rule
-    @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
-    public JOSMTestRules test = new JOSMTestRules();
-
-    /**
-     * Unit test of methods {@link ImmutableGpxTrack#equals} and {@link ImmutableGpxTrack#hashCode}.
-     */
-    @Test
-    public void testEqualsContract() {
-        TestUtils.assumeWorkingEqualsVerifier();
-        EqualsVerifier.forClass(ImmutableGpxTrack.class).usingGetClass()
-            .suppress(Warning.NONFINAL_FIELDS)
-            .withIgnoredFields("bounds", "length")
-            .verify();
-    }
-}
Index: /trunk/test/unit/org/openstreetmap/josm/data/gpx/WayPointTest.java
===================================================================
--- /trunk/test/unit/org/openstreetmap/josm/data/gpx/WayPointTest.java	(revision 15495)
+++ /trunk/test/unit/org/openstreetmap/josm/data/gpx/WayPointTest.java	(revision 15496)
@@ -29,7 +29,10 @@
     public void testEqualsContract() {
         TestUtils.assumeWorkingEqualsVerifier();
+        GpxExtensionCollection col = new GpxExtensionCollection();
+        col.add("josm", "from-server", "true");
         EqualsVerifier.forClass(WayPoint.class).usingGetClass()
             .suppress(Warning.NONFINAL_FIELDS)
             .withIgnoredFields("customColoring", "dir", "drawLine", "east", "north", "eastNorthCacheKey")
+            .withPrefabValues(GpxExtensionCollection.class, new GpxExtensionCollection(), col)
             .verify();
     }
Index: /trunk/test/unit/org/openstreetmap/josm/data/gpx/WithAttributesTest.java
===================================================================
--- /trunk/test/unit/org/openstreetmap/josm/data/gpx/WithAttributesTest.java	(revision 15495)
+++ /trunk/test/unit/org/openstreetmap/josm/data/gpx/WithAttributesTest.java	(revision 15496)
@@ -29,6 +29,9 @@
     public void testEqualsContract() {
         TestUtils.assumeWorkingEqualsVerifier();
+        GpxExtensionCollection col = new GpxExtensionCollection();
+        col.add("josm", "from-server", "true");
         EqualsVerifier.forClass(WithAttributes.class).usingGetClass()
             .suppress(Warning.NONFINAL_FIELDS)
+            .withPrefabValues(GpxExtensionCollection.class, new GpxExtensionCollection(), col)
             .verify();
     }
Index: /trunk/test/unit/org/openstreetmap/josm/gui/layer/GpxLayerTest.java
===================================================================
--- /trunk/test/unit/org/openstreetmap/josm/gui/layer/GpxLayerTest.java	(revision 15495)
+++ /trunk/test/unit/org/openstreetmap/josm/gui/layer/GpxLayerTest.java	(revision 15496)
@@ -4,4 +4,5 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 
@@ -19,5 +20,6 @@
 import org.openstreetmap.josm.TestUtils;
 import org.openstreetmap.josm.data.gpx.GpxData;
-import org.openstreetmap.josm.data.gpx.ImmutableGpxTrack;
+import org.openstreetmap.josm.data.gpx.GpxTrack;
+import org.openstreetmap.josm.data.gpx.IGpxTrackSegment;
 import org.openstreetmap.josm.data.gpx.WayPoint;
 import org.openstreetmap.josm.data.osm.DataSet;
@@ -74,13 +76,17 @@
     public void testGpxLayer() throws Exception {
         GpxLayer layer = new GpxLayer(new GpxData(), "foo", false);
+        GpxTrack trk = new GpxTrack(new ArrayList<IGpxTrackSegment>(), new HashMap<>());
+        trk.getExtensions().add("gpxd", "color", "#FF0000");
+        layer.data.addTrack(trk);
+
         assertEquals("foo", layer.getName());
         assertFalse(layer.isLocalFile());
-        assertEquals(Color.MAGENTA, layer.getColorProperty().get());
-        assertEquals("<html>0 tracks (0 segments), 0 routes, 0 waypoints<br>Length: < 0.01 m<br></html>", layer.getToolTipText());
+        assertEquals(layer.getColor(), Color.RED);
+        assertEquals("<html>1 track (0 segments), 0 routes, 0 waypoints<br>Length: < 0.01 m<br></html>", layer.getToolTipText());
 
         GpxLayer layer2 = new GpxLayer(new GpxData(), "bar", true);
         assertEquals("bar", layer2.getName());
         assertTrue(layer2.isLocalFile());
-        assertEquals(Color.MAGENTA, layer2.getColorProperty().get());
+        assertNull(layer2.getColor());
         assertEquals("<html>0 tracks (0 segments), 0 routes, 0 waypoints<br>Length: < 0.01 m<br></html>", layer2.getToolTipText());
 
@@ -188,5 +194,5 @@
     public void testGetTimespanForTrack() throws Exception {
         assertEquals("", GpxLayer.getTimespanForTrack(
-                new ImmutableGpxTrack(new ArrayList<Collection<WayPoint>>(), new HashMap<String, Object>())));
+                new GpxTrack(new ArrayList<Collection<WayPoint>>(), new HashMap<String, Object>())));
 
         assertEquals("1/3/16 11:59 AM - 12:00 PM (0:00)", GpxLayer.getTimespanForTrack(getMinimalGpxData().tracks.iterator().next()));
Index: /trunk/test/unit/org/openstreetmap/josm/gui/layer/LayerTest.java
===================================================================
--- /trunk/test/unit/org/openstreetmap/josm/gui/layer/LayerTest.java	(revision 15495)
+++ /trunk/test/unit/org/openstreetmap/josm/gui/layer/LayerTest.java	(revision 15496)
@@ -8,5 +8,4 @@
 import static org.junit.Assert.assertTrue;
 
-import java.awt.Color;
 import java.io.File;
 
@@ -14,6 +13,4 @@
 import org.junit.Rule;
 import org.junit.Test;
-import org.openstreetmap.josm.data.preferences.AbstractProperty;
-import org.openstreetmap.josm.data.preferences.NamedColorProperty;
 import org.openstreetmap.josm.data.projection.ProjectionRegistry;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
@@ -41,23 +38,4 @@
     public void setUp() {
         testLayer = new LayerManagerTest.TestLayer();
-    }
-
-    /**
-     * Test {@link Layer#getColorProperty()}
-     */
-    @Test
-    public void testGetColorProperty() {
-        assertEquals(null, testLayer.getColorProperty());
-
-        AbstractProperty<Color> color = new LayerManagerTest.TestLayer() {
-            @Override
-            protected NamedColorProperty getBaseColorProperty() {
-                return new NamedColorProperty("x", Color.BLACK);
-            }
-        }.getColorProperty();
-
-        assertEquals(Color.BLACK, color.get());
-        assertEquals(Color.BLACK, color.getDefaultValue());
-        assertEquals("clr.layer.Test Layer.x", color.getKey());
     }
 
@@ -98,10 +76,5 @@
         assertEquals("Test Layer2", testLayer.getName());
 
-        testLayer = new LayerManagerTest.TestLayer() {
-            @Override
-            public AbstractProperty<Color> getColorProperty() {
-                return new NamedColorProperty("test", Color.RED);
-            }
-        };
+        testLayer = new LayerManagerTest.TestLayer();
 
         testLayer.setName("Test Layer2");
Index: unk/test/unit/org/openstreetmap/josm/gui/layer/MarkerLayerTest.java
===================================================================
--- /trunk/test/unit/org/openstreetmap/josm/gui/layer/MarkerLayerTest.java	(revision 15495)
+++ 	(revision )
@@ -1,49 +1,0 @@
-// License: GPL. For details, see LICENSE file.
-package org.openstreetmap.josm.gui.layer;
-
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-
-import org.junit.Rule;
-import org.junit.Test;
-import org.openstreetmap.josm.data.gpx.GpxData;
-import org.openstreetmap.josm.data.osm.DataSet;
-import org.openstreetmap.josm.gui.MainApplication;
-import org.openstreetmap.josm.gui.MapFrame;
-import org.openstreetmap.josm.gui.layer.markerlayer.MarkerLayer;
-import org.openstreetmap.josm.testutils.JOSMTestRules;
-
-import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
-
-/**
- * Unit tests of {@link MarkerLayer} class.
- */
-public class MarkerLayerTest {
-
-    /**
-     * For creating layers
-     */
-    @Rule
-    @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
-    public JOSMTestRules test = new JOSMTestRules().main().projection();
-
-    /**
-     * Unit test of {@code Main.map.mapView.playHeadMarker}.
-     */
-    @Test
-    public void testPlayHeadMarker() {
-        try {
-            MainApplication.getLayerManager().addLayer(new OsmDataLayer(new DataSet(), "", null));
-            MapFrame map = MainApplication.getMap();
-            MarkerLayer layer = new MarkerLayer(new GpxData(), null, null, null);
-            assertNull(map.mapView.playHeadMarker);
-            MainApplication.getLayerManager().addLayer(layer);
-            assertNotNull(map.mapView.playHeadMarker);
-            MainApplication.getLayerManager().removeLayer(layer);
-        } finally {
-            if (MainApplication.isDisplayingMapView()) {
-                MainApplication.getMap().mapView.playHeadMarker = null;
-            }
-        }
-    }
-}
Index: /trunk/test/unit/org/openstreetmap/josm/gui/layer/OsmDataLayerTest.java
===================================================================
--- /trunk/test/unit/org/openstreetmap/josm/gui/layer/OsmDataLayerTest.java	(revision 15495)
+++ /trunk/test/unit/org/openstreetmap/josm/gui/layer/OsmDataLayerTest.java	(revision 15496)
@@ -24,5 +24,5 @@
 import org.openstreetmap.josm.data.gpx.GpxData;
 import org.openstreetmap.josm.data.gpx.GpxTrack;
-import org.openstreetmap.josm.data.gpx.GpxTrackSegment;
+import org.openstreetmap.josm.data.gpx.IGpxTrackSegment;
 import org.openstreetmap.josm.data.gpx.WayPoint;
 import org.openstreetmap.josm.data.osm.DataSet;
@@ -241,5 +241,5 @@
         assertEquals(1, gpx.getTrackCount());
         GpxTrack track = gpx.getTracks().iterator().next();
-        Collection<GpxTrackSegment> segments = track.getSegments();
+        Collection<IGpxTrackSegment> segments = track.getSegments();
         assertEquals(1, segments.size());
         Collection<WayPoint> trackpoints = segments.iterator().next().getWayPoints();
Index: /trunk/test/unit/org/openstreetmap/josm/gui/layer/gpx/ChooseTrackVisibilityActionTest.java
===================================================================
--- /trunk/test/unit/org/openstreetmap/josm/gui/layer/gpx/ChooseTrackVisibilityActionTest.java	(revision 15495)
+++ /trunk/test/unit/org/openstreetmap/josm/gui/layer/gpx/ChooseTrackVisibilityActionTest.java	(revision 15496)
@@ -39,13 +39,13 @@
             @Override
             protected String getString(final ExtendedDialog instance) {
-                return ((JLabel) ((JPanel) this.getContent(instance)).getComponent(2)).getText();
+                return ((JLabel) ((JPanel) instance.getContentPane().getComponent(0)).getComponent(2)).getText();
             }
         };
         edMocker.getMockResultMap().put(
-            "<html>Select all tracks that you want to be displayed. You can drag select a range of " +
-            "tracks or use CTRL+Click to select specific ones. The map is updated live in the " +
-            "background. Open the URLs by double clicking them.</html>",
-            "Show all"
-        );
+                "<html>Select all tracks that you want to be displayed. " +
+                        "You can drag select a range of tracks or use CTRL+Click to select specific ones. " +
+                        "The map is updated live in the background. Open the URLs by double clicking them, edit name and description by double clicking the cell.</html>",
+                        "Show all"
+                );
 
         new ChooseTrackVisibilityAction(GpxLayerTest.getMinimalGpxLayer()).actionPerformed(null);
@@ -53,5 +53,5 @@
         assertEquals(1, edMocker.getInvocationLog().size());
         Object[] invocationLogEntry = edMocker.getInvocationLog().get(0);
-        assertEquals(1, (int) invocationLogEntry[0]);
+        assertEquals(2, (int) invocationLogEntry[0]);
         assertEquals("Set track visibility for Bananas", invocationLogEntry[2]);
     }
Index: /trunk/test/unit/org/openstreetmap/josm/gui/layer/gpx/ConvertToDataLayerActionTest.java
===================================================================
--- /trunk/test/unit/org/openstreetmap/josm/gui/layer/gpx/ConvertToDataLayerActionTest.java	(revision 15495)
+++ /trunk/test/unit/org/openstreetmap/josm/gui/layer/gpx/ConvertToDataLayerActionTest.java	(revision 15496)
@@ -67,18 +67,31 @@
     public void testFromTrack() throws Exception {
         Config.getPref().put("gpx.convert-tags", "no");
-        testFromTrack("tracks");
+        testFromTrack("tracks.gpx", "tracks.osm");
 
         Config.getPref().put("gpx.convert-tags", "yes");
-        testFromTrack("tracks-ele-time");
+        testFromTrack("tracks.gpx", "tracks-ele-time.osm");
 
         Config.getPref().put("gpx.convert-tags", "list");
         Config.getPref().putList("gpx.convert-tags.list.yes", Arrays.asList("ele"));
         Config.getPref().putList("gpx.convert-tags.list.no", Arrays.asList("time"));
-        testFromTrack("tracks-ele");
-
+        testFromTrack("tracks.gpx", "tracks-ele.osm");
 
         Config.getPref().putList("gpx.convert-tags.list.yes", Arrays.asList("time"));
         Config.getPref().putList("gpx.convert-tags.list.no", Arrays.asList("ele"));
-        testFromTrack("tracks-time");
+        testFromTrack("tracks.gpx", "tracks-time.osm");
+
+        //Extension tests:
+        Config.getPref().put("gpx.convert-tags", "yes");
+        testFromTrack("tracks-extensions.gpx", "tracks-extensions.osm");
+
+        Config.getPref().put("gpx.convert-tags", "list");
+        Config.getPref().putList("gpx.convert-tags.list.yes", Arrays.asList("time", "ele"));
+        Config.getPref().putList("gpx.convert-tags.list.no", Arrays.asList(
+                "gpxx:DisplayColor",
+                "gpxd:color",
+                "gpx:extension:test:tag",
+                "gpx:extension:test:segment:tag"));
+        testFromTrack("tracks-extensions.gpx", "tracks-ele-time.osm");
+
     }
 
@@ -107,11 +120,11 @@
     }
 
-    private void testFromTrack(String expected) throws IOException, SAXException, IllegalDataException {
-        final GpxData data = GpxReaderTest.parseGpxData(TestUtils.getTestDataRoot() + "tracks/tracks.gpx");
+    private void testFromTrack(String originalGpx, String expectedOsm) throws IOException, SAXException, IllegalDataException {
+        final GpxData data = GpxReaderTest.parseGpxData(TestUtils.getTestDataRoot() + "tracks/" + originalGpx);
         final DataSet osmExpected = OsmReader.parseDataSet(Files.newInputStream(
-                Paths.get(TestUtils.getTestDataRoot(), "tracks/" + expected + ".osm")), null);
+                Paths.get(TestUtils.getTestDataRoot(), "tracks/" + expectedOsm)), null);
         final GpxLayer layer = new GpxLayer(data);
         final DataSet osm = new ConvertFromGpxLayerAction(layer).convert();
-        //compare sorted coordinates/tags and total amount of primitives, because IDs and order will vary after reload
+        //compare sorted nodes/ways, tags and total amount of primitives, because IDs and order will vary after reload
 
         List<GenericNode> nodes = osm.getNodes().stream()
@@ -125,6 +138,19 @@
                 .collect(Collectors.toList());
 
-        assertEquals(nodesExpected, nodes);
-        assertEquals(osmExpected.allPrimitives().size(), osm.allPrimitives().size());
+        assertEquals("Conversion " + originalGpx + " -> " + expectedOsm + " didn't match!", nodesExpected, nodes);
+
+        List<String> ways = osm.getWays().stream()
+                .map(w -> Integer.toString(w.getNodes().size()) + ":" + w.getKeys().entrySet().stream().sorted((e1, e2) -> e1.getKey().compareTo(e2.getKey())).collect(Collectors.toList()).toString())
+                .sorted()
+                .collect(Collectors.toList());
+
+        List<String> waysExpected = osmExpected.getWays().stream()
+                .map(w -> Integer.toString(w.getNodes().size()) + ":" + w.getKeys().entrySet().stream().sorted((e1, e2) -> e1.getKey().compareTo(e2.getKey())).collect(Collectors.toList()).toString())
+                .sorted()
+                .collect(Collectors.toList());
+
+        assertEquals("Conversion " + originalGpx + " -> " + expectedOsm + " didn't match!", waysExpected, ways);
+
+        assertEquals("Conversion " + originalGpx + " -> " + expectedOsm + " didn't match!", osmExpected.allPrimitives().size(), osm.allPrimitives().size());
     }
 
Index: /trunk/test/unit/org/openstreetmap/josm/gui/layer/gpx/GpxDrawHelperTest.java
===================================================================
--- /trunk/test/unit/org/openstreetmap/josm/gui/layer/gpx/GpxDrawHelperTest.java	(revision 15495)
+++ /trunk/test/unit/org/openstreetmap/josm/gui/layer/gpx/GpxDrawHelperTest.java	(revision 15496)
@@ -7,4 +7,5 @@
 import java.io.IOException;
 import java.util.List;
+import java.util.Map;
 import java.util.stream.Collectors;
 
@@ -14,9 +15,11 @@
 import org.openstreetmap.josm.data.gpx.GpxData;
 import org.openstreetmap.josm.gui.layer.GpxLayer;
+import org.openstreetmap.josm.gui.layer.gpx.GpxDrawHelper.ColorMode;
 import org.openstreetmap.josm.io.GpxReaderTest;
-import org.openstreetmap.josm.spi.preferences.Config;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
 import org.openstreetmap.josm.tools.ColorHelper;
 import org.xml.sax.SAXException;
+
+import com.google.common.collect.ImmutableMap;
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
@@ -42,8 +45,9 @@
     @Test
     public void testTicket12312() throws FileNotFoundException, IOException, SAXException {
-        Config.getPref().putBoolean("draw.rawgps.colors.dynamic.layer 12312", true);
-        Config.getPref().putInt("draw.rawgps.colors.layer 12312", GpxDrawHelper.ColorMode.VELOCITY.toIndex());
-        final List<String> colors = calculateColors(TestUtils.getRegressionDataFile(12312, "single_trackpoint.gpx"), "12312", 1);
-        assertEquals("[#FF00FF]", colors.toString());
+        final List<String> colors = calculateColors(TestUtils.getRegressionDataFile(12312, "single_trackpoint.gpx"),
+                ImmutableMap.of("colormode.dynamic-range", "true",
+                        "colormode", Integer.toString(ColorMode.VELOCITY.toIndex())),
+                1);
+        assertEquals("[null]", colors.toString());
     }
 
@@ -56,6 +60,6 @@
     @Test
     public void testNone() throws IOException, SAXException {
-        final List<String> colors = calculateColors("data_nodist/2094047.gpx", "000", 10);
-        assertEquals("[#FF00FF, #FF00FF, #FF00FF, #FF00FF, #FF00FF, #FF00FF, #FF00FF, #FF00FF, #FF00FF, #FF00FF]", colors.toString());
+        final List<String> colors = calculateColors("data_nodist/2094047.gpx", ImmutableMap.of(), 10);
+        assertEquals("[#000000, #000000, #000000, #000000, #000000, #000000, #000000, #000000, #000000, #000000]", colors.toString());
     }
 
@@ -68,7 +72,6 @@
     @Test
     public void testVelocity() throws IOException, SAXException {
-        Config.getPref().putInt("draw.rawgps.colors.layer 001", GpxDrawHelper.ColorMode.VELOCITY.toIndex());
-        final List<String> colors = calculateColors("data_nodist/2094047.gpx", "001", 10);
-        assertEquals("[#FF00FF, #FFAD00, #FFA800, #FFA800, #FF9E00, #FF9400, #FF7000, #FF7000, #FF8000, #FF9400]", colors.toString());
+        final List<String> colors = calculateColors("data_nodist/2094047.gpx", ImmutableMap.of("colormode", Integer.toString(ColorMode.VELOCITY.toIndex())), 10);
+        assertEquals("[#000000, #FFAD00, #FFA800, #FFA800, #FF9E00, #FF9400, #FF7000, #FF7000, #FF8000, #FF9400]", colors.toString());
     }
 
@@ -81,8 +84,9 @@
     @Test
     public void testVelocityDynamic() throws IOException, SAXException {
-        Config.getPref().putInt("draw.rawgps.colors.layer 002", GpxDrawHelper.ColorMode.VELOCITY.toIndex());
-        Config.getPref().putBoolean("draw.rawgps.colors.dynamic.layer 002", true);
-        final List<String> colors = calculateColors("data_nodist/2094047.gpx", "002", 10);
-        assertEquals("[#FF00FF, #00FFE0, #00FFC2, #00FFC2, #00FF75, #00FF3D, #99FF00, #94FF00, #38FF00, #00FF38]", colors.toString());
+        final List<String> colors = calculateColors("data_nodist/2094047.gpx",
+                ImmutableMap.of("colormode.dynamic-range", "true",
+                        "colormode", Integer.toString(ColorMode.VELOCITY.toIndex())),
+                10);
+        assertEquals("[#000000, #00FFE0, #00FFC2, #00FFC2, #00FF75, #00FF3D, #99FF00, #94FF00, #38FF00, #00FF38]", colors.toString());
     }
 
@@ -95,7 +99,6 @@
     @Test
     public void testDirection() throws IOException, SAXException {
-        Config.getPref().putInt("draw.rawgps.colors.layer 003", GpxDrawHelper.ColorMode.DIRECTION.toIndex());
-        final List<String> colors = calculateColors("data_nodist/2094047.gpx", "003", 10);
-        assertEquals("[#FF00FF, #EAEC25, #EDEA26, #EDE525, #ECD322, #EBB81D, #E85A0D, #E73708, #E84D0B, #EA8A15]", colors.toString());
+        final List<String> colors = calculateColors("data_nodist/2094047.gpx", ImmutableMap.of("colormode", Integer.toString(ColorMode.DIRECTION.toIndex())), 10);
+        assertEquals("[#000000, #EAEC25, #EDEA26, #EDE525, #ECD322, #EBB81D, #E85A0D, #E73708, #E84D0B, #EA8A15]", colors.toString());
     }
 
@@ -108,7 +111,6 @@
     @Test
     public void testTime() throws IOException, SAXException {
-        Config.getPref().putInt("draw.rawgps.colors.layer 003", GpxDrawHelper.ColorMode.TIME.toIndex());
-        final List<String> colors = calculateColors("data_nodist/2094047.gpx", "003", 10);
-        assertEquals("[#FF00FF, #FF0000, #FF0000, #FF0500, #FF0500, #FF0A00, #FF0A00, #FF1F00, #FF2E00, #FF3300]", colors.toString());
+        final List<String> colors = calculateColors("data_nodist/2094047.gpx", ImmutableMap.of("colormode", Integer.toString(ColorMode.TIME.toIndex())), 10);
+        assertEquals("[#000000, #FF0000, #FF0000, #FF0500, #FF0500, #FF0A00, #FF0A00, #FF1F00, #FF2E00, #FF3300]", colors.toString());
     }
 
@@ -116,5 +118,5 @@
      *
      * @param fileName the GPX filename to parse
-     * @param layerName the layer name used to fetch the color settings, see {@link GpxDrawHelper#readPreferences(java.lang.String)}
+     * @param layerPrefs a HashMap representing the layer specific preferences
      * @param n the number of waypoints of the first track/segment to analyze
      * @return the HTML color codes for the first {@code n} points
@@ -123,9 +125,10 @@
      * @throws SAXException if any SAX error occurs
      */
-    static List<String> calculateColors(String fileName, String layerName, int n) throws IOException, SAXException {
+    static List<String> calculateColors(String fileName, Map<String, String> layerPrefs, int n) throws IOException, SAXException {
         final GpxData data = GpxReaderTest.parseGpxData(fileName);
+        data.getLayerPrefs().putAll(layerPrefs);
         final GpxLayer layer = new GpxLayer(data);
         final GpxDrawHelper gdh = new GpxDrawHelper(layer);
-        gdh.readPreferences(layerName);
+        gdh.readPreferences();
         gdh.calculateColors();
         return data.getTrackPoints().limit(n).map(p -> ColorHelper.color2html(p.customColoring)).collect(Collectors.toList());
Index: /trunk/test/unit/org/openstreetmap/josm/gui/layer/markerlayer/AudioMarkerTest.java
===================================================================
--- /trunk/test/unit/org/openstreetmap/josm/gui/layer/markerlayer/AudioMarkerTest.java	(revision 15495)
+++ /trunk/test/unit/org/openstreetmap/josm/gui/layer/markerlayer/AudioMarkerTest.java	(revision 15496)
@@ -11,6 +11,4 @@
 import org.openstreetmap.josm.JOSMFixture;
 import org.openstreetmap.josm.data.coor.LatLon;
-import org.openstreetmap.josm.data.gpx.Extensions;
-import org.openstreetmap.josm.data.gpx.GpxConstants;
 import org.openstreetmap.josm.data.gpx.GpxData;
 import org.openstreetmap.josm.data.gpx.WayPoint;
@@ -46,6 +44,5 @@
         WayPoint wpt = marker.convertToWayPoint();
         assertEquals(LatLon.ZERO, wpt.getCoor());
-        Extensions ext = (Extensions) wpt.get(GpxConstants.META_EXTENSIONS);
-        assertEquals("2.0", ext.get("offset"));
+        assertEquals("2.0", wpt.getExtensions().get("josm", "offset").getValue());
     }
 }
Index: /trunk/test/unit/org/openstreetmap/josm/gui/layer/markerlayer/MarkerLayerTest.java
===================================================================
--- /trunk/test/unit/org/openstreetmap/josm/gui/layer/markerlayer/MarkerLayerTest.java	(revision 15495)
+++ /trunk/test/unit/org/openstreetmap/josm/gui/layer/markerlayer/MarkerLayerTest.java	(revision 15496)
@@ -4,7 +4,7 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 
-import java.awt.Color;
 import java.util.Arrays;
 
@@ -17,5 +17,8 @@
 import org.openstreetmap.josm.data.gpx.GpxLink;
 import org.openstreetmap.josm.data.gpx.WayPoint;
+import org.openstreetmap.josm.data.osm.DataSet;
 import org.openstreetmap.josm.gui.MainApplication;
+import org.openstreetmap.josm.gui.MapFrame;
+import org.openstreetmap.josm.gui.layer.OsmDataLayer;
 import org.openstreetmap.josm.spi.preferences.Config;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
@@ -29,5 +32,5 @@
 
     /**
-     * Setup tests
+     * For creating layers
      */
     @Rule
@@ -48,10 +51,9 @@
     @Test
     public void testMarkerLayer() {
-        assertEquals(Color.magenta, MarkerLayer.getGenericColor());
         MarkerLayer layer = new MarkerLayer(new GpxData(), "foo", null, null);
         MainApplication.getLayerManager().addLayer(layer);
 
         assertEquals("foo", layer.getName());
-        assertEquals(Color.magenta, layer.getColorProperty().get());
+        assertNull(layer.getColor());
         assertNotNull(layer.getIcon());
         assertEquals("0 markers", layer.getToolTipText());
@@ -62,13 +64,13 @@
         WayPoint wpt = new WayPoint(LatLon.ZERO);
         wpt.attr.put(GpxConstants.META_LINKS, Arrays.asList(new GpxLink("https://josm.openstreetmap.de")));
-        wpt.addExtension("offset", "1.0");
+        wpt.getExtensions().add("josm", "offset", "1.0");
         gpx.waypoints.add(wpt);
         wpt = new WayPoint(LatLon.ZERO);
-        wpt.addExtension("offset", "NaN");
+        wpt.getExtensions().add("josm", "offset", "NaN");
         gpx.waypoints.add(wpt);
         layer = new MarkerLayer(gpx, "bar", null, null);
 
         assertEquals("bar", layer.getName());
-        assertEquals(Color.magenta, layer.getColorProperty().get());
+        assertNull(layer.getColor());
         assertNotNull(layer.getIcon());
         assertEquals("3 markers", layer.getToolTipText());
@@ -76,3 +78,23 @@
         assertTrue(layer.getMenuEntries().length > 10);
     }
+
+    /**
+     * Unit test of {@code Main.map.mapView.playHeadMarker}.
+     */
+    @Test
+    public void testPlayHeadMarker() {
+        try {
+            MainApplication.getLayerManager().addLayer(new OsmDataLayer(new DataSet(), "", null));
+            MapFrame map = MainApplication.getMap();
+            MarkerLayer layer = new MarkerLayer(new GpxData(), null, null, null);
+            assertNull(map.mapView.playHeadMarker);
+            MainApplication.getLayerManager().addLayer(layer);
+            assertNotNull(map.mapView.playHeadMarker);
+            MainApplication.getLayerManager().removeLayer(layer);
+        } finally {
+            if (MainApplication.isDisplayingMapView()) {
+                MainApplication.getMap().mapView.playHeadMarker = null;
+            }
+        }
+    }
 }
Index: /trunk/test/unit/org/openstreetmap/josm/io/GpxReaderTest.java
===================================================================
--- /trunk/test/unit/org/openstreetmap/josm/io/GpxReaderTest.java	(revision 15495)
+++ /trunk/test/unit/org/openstreetmap/josm/io/GpxReaderTest.java	(revision 15496)
@@ -11,4 +11,6 @@
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
 
 import org.junit.Rule;
@@ -70,4 +72,22 @@
 
     /**
+     * Tests if layer preferences can be read
+     * @throws Exception if track can't be parsed
+     */
+    @Test
+    public void testLayerPrefs() throws Exception {
+        final GpxData data = parseGpxData(TestUtils.getTestDataRoot() + "tracks/tracks-layerprefs.gpx");
+        Map<String, String> e = new HashMap<>();
+        e.put("colormode.velocity.tune", "10");
+        e.put("lines.arrows.min-distance", "20");
+        e.put("colormode", "1");
+        e.put("lines", "1");
+        e.put("lines.arrows", "true");
+        e.put("colormode.dynamic-range", "true");
+        e.put("colors", "0");
+        assertEquals(data.getLayerPrefs(), e);
+    }
+
+    /**
      * Tests invalid data.
      * @throws Exception always SAXException
Index: /trunk/test/unit/org/openstreetmap/josm/io/GpxWriterTest.java
===================================================================
--- /trunk/test/unit/org/openstreetmap/josm/io/GpxWriterTest.java	(revision 15495)
+++ /trunk/test/unit/org/openstreetmap/josm/io/GpxWriterTest.java	(revision 15496)
@@ -4,4 +4,5 @@
 import static org.junit.Assert.assertEquals;
 
+import java.awt.Color;
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
@@ -10,5 +11,7 @@
 import java.time.Month;
 import java.time.ZoneOffset;
+import java.util.Arrays;
 import java.util.Date;
+import java.util.HashMap;
 import java.util.function.Consumer;
 
@@ -18,4 +21,8 @@
 import org.openstreetmap.josm.data.gpx.GpxConstants;
 import org.openstreetmap.josm.data.gpx.GpxData;
+import org.openstreetmap.josm.data.gpx.GpxData.XMLNamespace;
+import org.openstreetmap.josm.data.gpx.GpxExtensionCollection;
+import org.openstreetmap.josm.data.gpx.GpxTrack;
+import org.openstreetmap.josm.data.gpx.GpxTrackSegment;
 import org.openstreetmap.josm.data.gpx.WayPoint;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
@@ -88,3 +95,185 @@
                 "    <pdop>1.2</pdop>%n");
     }
+
+    /**
+     * Tests if extensions are written correctly.
+     * @throws IOException
+     */
+    @Test
+    public void testExtensions() throws IOException {
+        GpxData data = new GpxData();
+        data.getNamespaces().add(new XMLNamespace("test", "http://example.com/testURI")); //only namespace, no location printed
+        data.getNamespaces().add(new XMLNamespace("knownprefix", "http://example.com/URI", "http://example.com/location.xsd")); //printed
+        data.getNamespaces().add(new XMLNamespace("notpresent", "http://example.com/notpresent", "http://example.com/notpresent.xsd")); //NOT printed
+
+        GpxExtensionCollection exts = data.getExtensions();
+        data.fromServer = true; //printed
+        data.getLayerPrefs().put("foo", "bar"); //printed depending on writer config
+        exts.add("knownprefix", "foo", "bar"); //printed
+        exts.add("unknownprefix", "foo", "bar"); //NOT printed
+
+        WayPoint wpt = new WayPoint(LatLon.ZERO);
+        wpt.getExtensions().add("test", "foo", "extension of a waypoint"); //printed
+
+        GpxTrackSegment seg = new GpxTrackSegment(Arrays.asList(wpt));
+        seg.getExtensions().add("test", "foo", "extension of a segment"); //printed
+
+        GpxTrack trk = new GpxTrack(Arrays.asList(seg), new HashMap<>());
+
+        trk.setColor(Color.RED); //printed depending on writer configuration
+
+        data.addTrack(trk);
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        GpxWriter writer = new GpxWriter(baos);
+
+        writer.write(data);
+        assertEquals("<?xml version='1.0' encoding='UTF-8'?>\n" +
+                "<gpx version=\"1.1\" creator=\"JOSM GPX export\" xmlns=\"http://www.topografix.com/GPX/1/1\"\n" +
+                "    xmlns:knownprefix=\"http://example.com/URI\"\n" +
+                "    xmlns:josm=\"http://josm.openstreetmap.de/gpx-extensions-1.1\"\n" +
+                "    xmlns:gpxd=\"http://josm.openstreetmap.de/gpx-drawing-extensions-1.0\"\n" +
+                "    xmlns:test=\"http://example.com/testURI\"\n" +
+                "    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n" +
+                "    xsi:schemaLocation=\"http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd http://example.com/URI http://example.com/location.xsd http://josm.openstreetmap.de/gpx-extensions-1.1 http://josm.openstreetmap.de/gpx-extensions-1.1.xsd http://josm.openstreetmap.de/gpx-drawing-extensions-1.0 http://josm.openstreetmap.de/gpx-drawing-extensions-1.0.xsd\">\n" +
+                "  <metadata>\n" +
+                "    <bounds minlat=\"0.0\" minlon=\"0.0\" maxlat=\"0.0\" maxlon=\"0.0\"/>\n" +
+                "    <extensions>\n" +
+                "      <knownprefix:foo>bar</knownprefix:foo>\n" +
+                "      <josm:from-server>true</josm:from-server>\n" +
+                "      <josm:layerPreferences>\n" +
+                "        <josm:entry key=\"foo\" value=\"bar\"/>\n" +
+                "      </josm:layerPreferences>\n" +
+                "    </extensions>\n" +
+                "  </metadata>\n" +
+                "  <trk>\n" +
+                "    <extensions>\n" +
+                "      <gpxd:color>#FF0000</gpxd:color>\n" +
+                "    </extensions>\n" +
+                "    <trkseg>\n" +
+                "      <extensions>\n" +
+                "        <test:foo>extension of a segment</test:foo>\n" +
+                "      </extensions>\n" +
+                "      <trkpt lat=\"0.0\" lon=\"0.0\">\n" +
+                "        <extensions>\n" +
+                "          <test:foo>extension of a waypoint</test:foo>\n" +
+                "        </extensions>\n" +
+                "      </trkpt>\n" +
+                "    </trkseg>\n" +
+                "  </trk>\n" +
+                "</gpx>", baos.toString());
+
+        baos.reset();
+        writer.write(data, GpxConstants.ColorFormat.GPXX, true);
+        assertEquals("<?xml version='1.0' encoding='UTF-8'?>\n" +
+                "<gpx version=\"1.1\" creator=\"JOSM GPX export\" xmlns=\"http://www.topografix.com/GPX/1/1\"\n" +
+                "    xmlns:knownprefix=\"http://example.com/URI\"\n" +
+                "    xmlns:josm=\"http://josm.openstreetmap.de/gpx-extensions-1.1\"\n" +
+                "    xmlns:gpxx=\"http://www.garmin.com/xmlschemas/GpxExtensions/v3\"\n" +
+                "    xmlns:test=\"http://example.com/testURI\"\n" +
+                "    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n" +
+                "    xsi:schemaLocation=\"http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd http://example.com/URI http://example.com/location.xsd http://josm.openstreetmap.de/gpx-extensions-1.1 http://josm.openstreetmap.de/gpx-extensions-1.1.xsd http://www.garmin.com/xmlschemas/GpxExtensions/v3 http://www.garmin.com/xmlschemas/GpxExtensionsv3.xsd\">\n" +
+                "  <metadata>\n" +
+                "    <bounds minlat=\"0.0\" minlon=\"0.0\" maxlat=\"0.0\" maxlon=\"0.0\"/>\n" +
+                "    <extensions>\n" +
+                "      <knownprefix:foo>bar</knownprefix:foo>\n" +
+                "      <josm:from-server>true</josm:from-server>\n" +
+                "      <josm:layerPreferences>\n" +
+                "        <josm:entry key=\"foo\" value=\"bar\"/>\n" +
+                "      </josm:layerPreferences>\n" +
+                "    </extensions>\n" +
+                "  </metadata>\n" +
+                "  <trk>\n" +
+                "    <extensions>\n" +
+                "      <gpxx:TrackExtensions>\n" +
+                "        <gpxx:DisplayColor>Red</gpxx:DisplayColor>\n" +
+                "      </gpxx:TrackExtensions>\n" +
+                "    </extensions>\n" +
+                "    <trkseg>\n" +
+                "      <extensions>\n" +
+                "        <test:foo>extension of a segment</test:foo>\n" +
+                "      </extensions>\n" +
+                "      <trkpt lat=\"0.0\" lon=\"0.0\">\n" +
+                "        <extensions>\n" +
+                "          <test:foo>extension of a waypoint</test:foo>\n" +
+                "        </extensions>\n" +
+                "      </trkpt>\n" +
+                "    </trkseg>\n" +
+                "  </trk>\n" +
+                "</gpx>", baos.toString());
+
+        baos.reset();
+        writer.write(data, null, false);
+        assertEquals("<?xml version='1.0' encoding='UTF-8'?>\n" +
+                "<gpx version=\"1.1\" creator=\"JOSM GPX export\" xmlns=\"http://www.topografix.com/GPX/1/1\"\n" +
+                "    xmlns:knownprefix=\"http://example.com/URI\"\n" +
+                "    xmlns:josm=\"http://josm.openstreetmap.de/gpx-extensions-1.1\"\n" +
+                "    xmlns:test=\"http://example.com/testURI\"\n" +
+                "    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n" +
+                "    xsi:schemaLocation=\"http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd http://example.com/URI http://example.com/location.xsd http://josm.openstreetmap.de/gpx-extensions-1.1 http://josm.openstreetmap.de/gpx-extensions-1.1.xsd\">\n" +
+                "  <metadata>\n" +
+                "    <bounds minlat=\"0.0\" minlon=\"0.0\" maxlat=\"0.0\" maxlon=\"0.0\"/>\n" +
+                "    <extensions>\n" +
+                "      <knownprefix:foo>bar</knownprefix:foo>\n" +
+                "      <josm:from-server>true</josm:from-server>\n" +
+                "    </extensions>\n" +
+                "  </metadata>\n" +
+                "  <trk>\n" +
+                "    <trkseg>\n" +
+                "      <extensions>\n" +
+                "        <test:foo>extension of a segment</test:foo>\n" +
+                "      </extensions>\n" +
+                "      <trkpt lat=\"0.0\" lon=\"0.0\">\n" +
+                "        <extensions>\n" +
+                "          <test:foo>extension of a waypoint</test:foo>\n" +
+                "        </extensions>\n" +
+                "      </trkpt>\n" +
+                "    </trkseg>\n" +
+                "  </trk>\n" +
+                "</gpx>", baos.toString());
+
+        baos.reset();
+        writer.write(data, GpxConstants.ColorFormat.GPXX, true);
+        // checked again to make sure that extensions are shown again after
+        // being hidden, even if they don't actually have to be converted
+        // (GPXD -> convertColor() -> GPXX -> hide() -> null -> show() -> GPXX)
+        assertEquals("<?xml version='1.0' encoding='UTF-8'?>\n" +
+                "<gpx version=\"1.1\" creator=\"JOSM GPX export\" xmlns=\"http://www.topografix.com/GPX/1/1\"\n" +
+                "    xmlns:knownprefix=\"http://example.com/URI\"\n" +
+                "    xmlns:josm=\"http://josm.openstreetmap.de/gpx-extensions-1.1\"\n" +
+                "    xmlns:gpxx=\"http://www.garmin.com/xmlschemas/GpxExtensions/v3\"\n" +
+                "    xmlns:test=\"http://example.com/testURI\"\n" +
+                "    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n" +
+                "    xsi:schemaLocation=\"http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd http://example.com/URI http://example.com/location.xsd http://josm.openstreetmap.de/gpx-extensions-1.1 http://josm.openstreetmap.de/gpx-extensions-1.1.xsd http://www.garmin.com/xmlschemas/GpxExtensions/v3 http://www.garmin.com/xmlschemas/GpxExtensionsv3.xsd\">\n" +
+                "  <metadata>\n" +
+                "    <bounds minlat=\"0.0\" minlon=\"0.0\" maxlat=\"0.0\" maxlon=\"0.0\"/>\n" +
+                "    <extensions>\n" +
+                "      <knownprefix:foo>bar</knownprefix:foo>\n" +
+                "      <josm:from-server>true</josm:from-server>\n" +
+                "      <josm:layerPreferences>\n" +
+                "        <josm:entry key=\"foo\" value=\"bar\"/>\n" +
+                "      </josm:layerPreferences>\n" +
+                "    </extensions>\n" +
+                "  </metadata>\n" +
+                "  <trk>\n" +
+                "    <extensions>\n" +
+                "      <gpxx:TrackExtensions>\n" +
+                "        <gpxx:DisplayColor>Red</gpxx:DisplayColor>\n" +
+                "      </gpxx:TrackExtensions>\n" +
+                "    </extensions>\n" +
+                "    <trkseg>\n" +
+                "      <extensions>\n" +
+                "        <test:foo>extension of a segment</test:foo>\n" +
+                "      </extensions>\n" +
+                "      <trkpt lat=\"0.0\" lon=\"0.0\">\n" +
+                "        <extensions>\n" +
+                "          <test:foo>extension of a waypoint</test:foo>\n" +
+                "        </extensions>\n" +
+                "      </trkpt>\n" +
+                "    </trkseg>\n" +
+                "  </trk>\n" +
+                "</gpx>", baos.toString());
+
+        writer.close();
+    }
 }
Index: /trunk/test/unit/org/openstreetmap/josm/io/nmea/NmeaReaderTest.java
===================================================================
--- /trunk/test/unit/org/openstreetmap/josm/io/nmea/NmeaReaderTest.java	(revision 15495)
+++ /trunk/test/unit/org/openstreetmap/josm/io/nmea/NmeaReaderTest.java	(revision 15496)
@@ -25,5 +25,5 @@
 import org.openstreetmap.josm.data.gpx.GpxData;
 import org.openstreetmap.josm.data.gpx.GpxTrack;
-import org.openstreetmap.josm.data.gpx.GpxTrackSegment;
+import org.openstreetmap.josm.data.gpx.IGpxTrackSegment;
 import org.openstreetmap.josm.data.gpx.WayPoint;
 import org.openstreetmap.josm.io.GpxReaderTest;
@@ -101,6 +101,6 @@
         assertEquals(nTracks, nmeaTrack.getSegments().size());
         if (nTracks > 0) {
-            GpxTrackSegment gpxSeg = gpxTrack.getSegments().iterator().next();
-            GpxTrackSegment nmeaSeg = nmeaTrack.getSegments().iterator().next();
+            IGpxTrackSegment gpxSeg = gpxTrack.getSegments().iterator().next();
+            IGpxTrackSegment nmeaSeg = nmeaTrack.getSegments().iterator().next();
             assertEquals(gpxSeg.getBounds(), nmeaSeg.getBounds());
             assertEquals(numCoor, gpxSeg.getWayPoints().size());
