Index: /applications/editors/josm/plugins/wikipedia/build.xml
===================================================================
--- /applications/editors/josm/plugins/wikipedia/build.xml	(revision 33807)
+++ /applications/editors/josm/plugins/wikipedia/build.xml	(revision 33808)
@@ -1,4 +1,4 @@
 <?xml version="1.0" encoding="utf-8"?>
-<project name="wikipedia" default="dist" basedir=".">
+<project name="wikipedia" default="dist2" basedir=".">
 
     <!-- enter the SVN commit message -->
@@ -17,3 +17,7 @@
     <import file="../build-common.xml"/>
 
+    <target name="dist2" depends="dist">
+      <copy file="${plugin.jar}" todir="${plugin.dist.dir}/../.josm/plugins"/>
+    </target>
+
 </project>
Index: /applications/editors/josm/plugins/wikipedia/src/org/wikipedia/WikipediaPlugin.java
===================================================================
--- /applications/editors/josm/plugins/wikipedia/src/org/wikipedia/WikipediaPlugin.java	(revision 33807)
+++ /applications/editors/josm/plugins/wikipedia/src/org/wikipedia/WikipediaPlugin.java	(revision 33808)
@@ -28,5 +28,5 @@
         MainMenu.add(dataMenu, new WikidataItemSearchDialog.Action());
 
-        DownloadDialog.addDownloadSource(new WikosmDownloadSource());
+        DownloadDialog.addDownloadSource(new SophoxDownloadReader());
     }
 
@@ -42,5 +42,5 @@
     public PreferenceSetting getPreferenceSetting() {
         if (preferences == null) {
-            preferences = (new WikosmServerPreference.Factory()).createPreferenceSetting();
+            preferences = (new SophoxServerPreference.Factory()).createPreferenceSetting();
         }
         return preferences;
Index: /applications/editors/josm/plugins/wikipedia/src/org/wikipedia/gui/SophoxDownloadReader.java
===================================================================
--- /applications/editors/josm/plugins/wikipedia/src/org/wikipedia/gui/SophoxDownloadReader.java	(revision 33808)
+++ /applications/editors/josm/plugins/wikipedia/src/org/wikipedia/gui/SophoxDownloadReader.java	(revision 33808)
@@ -0,0 +1,388 @@
+// License: GPL. For details, see LICENSE file.
+package org.wikipedia.gui;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.*;
+import java.awt.event.ActionEvent;
+import java.awt.event.FocusEvent;
+import java.awt.event.FocusListener;
+import java.util.Collection;
+import java.util.concurrent.Future;
+import java.util.function.Consumer;
+
+import javax.swing.*;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.event.ListSelectionListener;
+import javax.swing.plaf.basic.BasicArrowButton;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.actions.downloadtasks.DownloadOsmTask;
+import org.openstreetmap.josm.actions.downloadtasks.PostDownloadHandler;
+import org.openstreetmap.josm.data.Bounds;
+import org.openstreetmap.josm.data.preferences.AbstractProperty;
+import org.openstreetmap.josm.data.preferences.BooleanProperty;
+import org.openstreetmap.josm.data.preferences.IntegerProperty;
+import org.openstreetmap.josm.gui.MainApplication;
+import org.openstreetmap.josm.gui.download.AbstractDownloadSourcePanel;
+import org.openstreetmap.josm.gui.download.DownloadDialog;
+import org.openstreetmap.josm.gui.download.DownloadSettings;
+import org.openstreetmap.josm.gui.download.DownloadSource;
+import org.openstreetmap.josm.gui.download.DownloadSourceSizingPolicy;
+import org.openstreetmap.josm.gui.download.DownloadSourceSizingPolicy.AdjustableDownloadSizePolicy;
+import org.openstreetmap.josm.gui.download.UserQueryList;
+import org.openstreetmap.josm.gui.util.GuiHelper;
+import org.openstreetmap.josm.gui.widgets.JosmTextArea;
+import org.openstreetmap.josm.tools.GBC;
+import org.openstreetmap.josm.tools.ImageProvider;
+import org.openstreetmap.josm.tools.OpenBrowser;
+
+/**
+ * Class defines the way data is fetched from Sophox API.
+ */
+public class SophoxDownloadReader implements DownloadSource<SophoxDownloadReader.SophoxDownloadData> {
+
+    @Override
+    public AbstractDownloadSourcePanel<SophoxDownloadData> createPanel(DownloadDialog dialog) {
+        return new SophoxDownloadSourcePanel(this);
+    }
+
+    @Override
+    public void doDownload(SophoxDownloadData data, DownloadSettings settings) {
+        Bounds area = settings.getDownloadBounds().orElse(new Bounds(0, 0, 0, 0));
+        DownloadOsmTask task = new DownloadOsmTask();
+        task.setZoomAfterDownload(settings.zoomToData());
+        Future<?> future = task.download(
+                new org.wikipedia.io.SophoxDownloadReader(area, org.wikipedia.io.SophoxDownloadReader.SOPHOX_SERVER.get(), data.getQuery(),
+                        settings.asNewLayer(), data.getDownloadReferrers(), data.getDownloadFull()),
+
+                settings.asNewLayer(), area, null);
+        MainApplication.worker.submit(new PostDownloadHandler(task, future, data.getErrorReporter()));
+    }
+
+    @Override
+    public String getLabel() {
+        return tr("Download from Sophox API");
+    }
+
+    @Override
+    public boolean onlyExpert() {
+        return true;
+    }
+
+    /**
+     * The GUI representation of the Sophox download source.
+     */
+    public static class SophoxDownloadSourcePanel extends AbstractDownloadSourcePanel<SophoxDownloadData> {
+
+        private static final String HELP_PAGE = "https://wiki.openstreetmap.org/wiki/Wikidata%2BOSM_SPARQL_query_service";
+        private static final String SIMPLE_NAME = "sophoxdownloadpanel";
+        private static final AbstractProperty<Integer> PANEL_SIZE_PROPERTY =
+                new IntegerProperty(TAB_SPLIT_NAMESPACE + SIMPLE_NAME, 150).cached();
+        private static final BooleanProperty SOPHOX_QUERY_LIST_OPENED =
+                new BooleanProperty("download.sophox.query-list.opened", false);
+        private static final String ACTION_IMG_SUBDIR = "dialogs";
+
+        private final JosmTextArea sophoxQuery;
+        private final UserQueryList sophoxQueryList;
+        private final JCheckBox referrers;
+        private final JCheckBox fullRel;
+
+        /**
+         * Create a new {@code SophoxDownloadSourcePanel}
+         * @param ds The download source to create the panel for
+         */
+        public SophoxDownloadSourcePanel(SophoxDownloadReader ds) {
+            super(ds);
+            setLayout(new BorderLayout());
+
+            String queryText = "# " +
+                    tr("Find places of education at least 2km, and at most 3km from the center of the selection") +
+                    "\n" +
+                    "SELECT ?osmid WHERE {\n" +
+                    "  VALUES ?amenity { \"kindergarten\" \"school\" \"university\" \"college\" }\n" +
+                    "  ?osmid osmt:amenity ?amenity ;\n" +
+                    "         osmm:loc ?location .\n" +
+                    "  BIND(geof:distance({{center}}, ?location) as ?distance)\n" +
+                    "  FILTER(?distance > 2 && ?distance < 3)\n" +
+                    "}";
+
+            this.sophoxQuery = new JosmTextArea(queryText, 8, 80);
+
+            this.sophoxQuery.setFont(GuiHelper.getMonospacedFont(sophoxQuery));
+            this.sophoxQuery.addFocusListener(new FocusListener() {
+                @Override
+                public void focusGained(FocusEvent e) {
+                    sophoxQuery.selectAll();
+                }
+
+                @Override
+                public void focusLost(FocusEvent e) {
+                    // ignored
+                }
+            });
+
+
+            this.sophoxQueryList = new UserQueryList(this, this.sophoxQuery, "download.sophox.query");
+            this.sophoxQueryList.setPreferredSize(new Dimension(350, 300));
+
+            EditSnippetAction edit = new EditSnippetAction();
+            RemoveSnippetAction remove = new RemoveSnippetAction();
+            this.sophoxQueryList.addSelectionListener(edit);
+            this.sophoxQueryList.addSelectionListener(remove);
+
+            JPanel listPanel = new JPanel(new GridBagLayout());
+            listPanel.add(new JLabel(tr("Your saved queries:")), GBC.eol().insets(2).anchor(GBC.CENTER));
+            listPanel.add(this.sophoxQueryList, GBC.eol().fill(GBC.BOTH));
+            listPanel.add(new JButton(new AddSnippetAction()), GBC.std().fill(GBC.HORIZONTAL));
+            listPanel.add(new JButton(edit), GBC.std().fill(GBC.HORIZONTAL));
+            listPanel.add(new JButton(remove), GBC.std().fill(GBC.HORIZONTAL));
+            listPanel.setVisible(SOPHOX_QUERY_LIST_OPENED.get());
+
+            JScrollPane scrollPane = new JScrollPane(sophoxQuery);
+            BasicArrowButton arrowButton = new BasicArrowButton(listPanel.isVisible()
+                    ? BasicArrowButton.EAST
+                    : BasicArrowButton.WEST);
+            arrowButton.setToolTipText(tr("Show/hide Sophox snippet list"));
+            arrowButton.addActionListener(e -> {
+                if (listPanel.isVisible()) {
+                    listPanel.setVisible(false);
+                    arrowButton.setDirection(BasicArrowButton.WEST);
+                    SOPHOX_QUERY_LIST_OPENED.put(Boolean.FALSE);
+                } else {
+                    listPanel.setVisible(true);
+                    arrowButton.setDirection(BasicArrowButton.EAST);
+                    SOPHOX_QUERY_LIST_OPENED.put(Boolean.TRUE);
+                }
+            });
+
+            // TODO: Once new core is widely avialable, replace:
+            //   Main.pref.getBoolean --> Config.getPref().getBoolean
+            //   Main.pref.put --> Config.getPref().putBoolean
+
+            referrers = new JCheckBox(tr("Download referrers (parent relations)"));
+            referrers.setToolTipText(tr("Select if the referrers of the object should be downloaded as well, i.e.,"
+                    + "parent relations and for nodes, additionally, parent ways"));
+            referrers.setSelected(Main.pref.getBoolean("sophox.downloadprimitive.referrers", true));
+            referrers.addActionListener(e -> Main.pref.putBoolean("sophox.downloadprimitive.referrers", referrers.isSelected()));
+
+            fullRel = new JCheckBox(tr("Download relation members"));
+            fullRel.setToolTipText(tr("Select if the members of a relation should be downloaded as well"));
+            fullRel.setSelected(Main.pref.getBoolean("sophox.downloadprimitive.full", true));
+            fullRel.addActionListener(e -> Main.pref.putBoolean("sophox.downloadprimitive.full", fullRel.isSelected()));
+
+            // https://stackoverflow.com/questions/527719/how-to-add-hyperlink-in-jlabel
+            JButton helpLink = new JButton();
+            helpLink.setText("<HTML><FONT color=\"#000099\"><U>"+tr("help")+"</U></FONT></HTML>");
+            helpLink.setToolTipText(HELP_PAGE);
+            helpLink.setHorizontalAlignment(SwingConstants.LEFT);
+            helpLink.setBorderPainted(false);
+            helpLink.setOpaque(false);
+            helpLink.setBackground(Color.WHITE);
+            helpLink.addActionListener(e -> OpenBrowser.displayUrl(HELP_PAGE));
+
+            JPanel centerPanel = new JPanel(new GridBagLayout());
+            centerPanel.add(scrollPane, GBC.eol().fill(GBC.BOTH));
+            centerPanel.add(referrers, GBC.std().anchor(GBC.WEST).insets(5, 5, 5, 5));
+            centerPanel.add(fullRel, GBC.std().anchor(GBC.WEST).insets(15, 5, 5, 5));
+            centerPanel.add(helpLink, GBC.std().anchor(GBC.WEST).insets(10, 5, 5, 5));
+
+
+            JPanel innerPanel = new JPanel(new BorderLayout());
+            innerPanel.add(centerPanel, BorderLayout.CENTER);
+            innerPanel.add(arrowButton, BorderLayout.EAST);
+
+            add(innerPanel, BorderLayout.CENTER);
+            add(listPanel, BorderLayout.EAST);
+
+            setMinimumSize(new Dimension(450, 240));
+        }
+
+        @Override
+        public SophoxDownloadData getData() {
+            String query = sophoxQuery.getText();
+            /*
+             * A callback that is passed to PostDownloadReporter that is called once the download task
+             * has finished. According to the number of errors happened, their type we decide whether we
+             * want to save the last query in SophoxQueryList.
+             */
+            Consumer<Collection<Object>> errorReporter = errors -> {
+
+                boolean onlyNoDataError = errors.size() == 1 &&
+                        errors.contains("No data found in this area.");
+
+                if (errors.isEmpty() || onlyNoDataError) {
+                    sophoxQueryList.saveHistoricItem(query);
+                }
+            };
+
+            return new SophoxDownloadData(query, referrers.isSelected(), fullRel.isSelected(), errorReporter);
+        }
+
+        @Override
+        public void rememberSettings() {
+            // nothing
+        }
+
+        @Override
+        public void restoreSettings() {
+            // nothing
+        }
+
+        @Override
+        public boolean checkDownload(DownloadSettings settings) {
+            String query = getData().getQuery();
+
+            /*
+             * Absence of the selected area can be justified only if the Sophox query
+             * is not restricted to bbox.
+             */
+            if (!settings.getDownloadBounds().isPresent() && (
+                    query.contains("{{boxParams}}") ||
+                    query.contains("{{center}}")
+            )) {
+                JOptionPane.showMessageDialog(
+                        this.getParent(),
+                        tr("Please select a download area first."),
+                        tr("Error"),
+                        JOptionPane.ERROR_MESSAGE
+                );
+                return false;
+            }
+
+            return true;
+        }
+
+        @Override
+        public Icon getIcon() {
+            return ImageProvider.get(ACTION_IMG_SUBDIR, "sophox");
+        }
+
+        @Override
+        public String getSimpleName() {
+            return SIMPLE_NAME;
+        }
+
+        @Override
+        public DownloadSourceSizingPolicy getSizingPolicy() {
+            return new AdjustableDownloadSizePolicy(PANEL_SIZE_PROPERTY);
+        }
+
+        /**
+         * Action that delegates snippet creation to {@link UserQueryList#createNewItem()}.
+         */
+        private class AddSnippetAction extends AbstractAction {
+
+            /**
+             * Constructs a new {@code AddSnippetAction}.
+             */
+            AddSnippetAction() {
+                super();
+                putValue(SMALL_ICON, ImageProvider.get(ACTION_IMG_SUBDIR, "add"));
+                putValue(SHORT_DESCRIPTION, tr("Add new snippet"));
+            }
+
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                sophoxQueryList.createNewItem();
+            }
+        }
+
+        /**
+         * Action that delegates snippet removal to {@link UserQueryList#removeSelectedItem()}.
+         */
+        private class RemoveSnippetAction extends AbstractAction implements ListSelectionListener {
+
+            /**
+             * Constructs a new {@code RemoveSnippetAction}.
+             */
+            RemoveSnippetAction() {
+                super();
+                putValue(SMALL_ICON, ImageProvider.get(ACTION_IMG_SUBDIR, "delete"));
+                putValue(SHORT_DESCRIPTION, tr("Delete selected snippet"));
+                checkEnabled();
+            }
+
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                sophoxQueryList.removeSelectedItem();
+            }
+
+            /**
+             * Disables the action if no items are selected.
+             */
+            void checkEnabled() {
+                setEnabled(sophoxQueryList.getSelectedItem().isPresent());
+            }
+
+            @Override
+            public void valueChanged(ListSelectionEvent e) {
+                checkEnabled();
+            }
+        }
+
+        /**
+         * Action that delegates snippet edit to {@link UserQueryList#editSelectedItem()}.
+         */
+        private class EditSnippetAction extends AbstractAction implements ListSelectionListener {
+
+            /**
+             * Constructs a new {@code EditSnippetAction}.
+             */
+            EditSnippetAction() {
+                super();
+                putValue(SMALL_ICON, ImageProvider.get(ACTION_IMG_SUBDIR, "edit"));
+                putValue(SHORT_DESCRIPTION, tr("Edit selected snippet"));
+                checkEnabled();
+            }
+
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                sophoxQueryList.editSelectedItem();
+            }
+
+            /**
+             * Disables the action if no items are selected.
+             */
+            void checkEnabled() {
+                setEnabled(sophoxQueryList.getSelectedItem().isPresent());
+            }
+
+            @Override
+            public void valueChanged(ListSelectionEvent e) {
+                checkEnabled();
+            }
+        }
+    }
+
+    /**
+     * Encapsulates data that is required to preform download from Sophox API.
+     */
+    static class SophoxDownloadData {
+        private final String query;
+        private final boolean downloadReferrers;
+        private final boolean downloadFull;
+        private final Consumer<Collection<Object>> errorReporter;
+
+        SophoxDownloadData(String query, boolean downloadReferrers, boolean downloadFull, Consumer<Collection<Object>> errorReporter) {
+            this.query = query;
+            this.downloadReferrers = downloadReferrers;
+            this.downloadFull = downloadFull;
+            this.errorReporter = errorReporter;
+        }
+
+        String getQuery() {
+            return this.query;
+        }
+
+        boolean getDownloadReferrers() {
+            return this.downloadReferrers;
+        }
+
+        boolean getDownloadFull() { return this.downloadFull; }
+
+        Consumer<Collection<Object>> getErrorReporter() {
+            return this.errorReporter;
+        }
+    }
+}
Index: /applications/editors/josm/plugins/wikipedia/src/org/wikipedia/gui/SophoxServerPreference.java
===================================================================
--- /applications/editors/josm/plugins/wikipedia/src/org/wikipedia/gui/SophoxServerPreference.java	(revision 33808)
+++ /applications/editors/josm/plugins/wikipedia/src/org/wikipedia/gui/SophoxServerPreference.java	(revision 33808)
@@ -0,0 +1,70 @@
+// License: GPL. For details, see LICENSE file.
+package org.wikipedia.gui;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.GridBagLayout;
+
+import javax.swing.BorderFactory;
+import javax.swing.Box;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+
+import org.openstreetmap.josm.gui.preferences.PreferenceSetting;
+import org.openstreetmap.josm.gui.preferences.PreferenceSettingFactory;
+import org.openstreetmap.josm.gui.preferences.PreferenceTabbedPane;
+import org.openstreetmap.josm.gui.preferences.SubPreferenceSetting;
+import org.openstreetmap.josm.gui.preferences.TabPreferenceSetting;
+import org.openstreetmap.josm.gui.widgets.HistoryComboBox;
+import org.openstreetmap.josm.tools.GBC;
+import org.wikipedia.io.SophoxDownloadReader;
+
+/**
+ * Preferences related to Sophox API servers.
+ */
+public class SophoxServerPreference implements SubPreferenceSetting {
+
+    private final HistoryComboBox SophoxServer = new HistoryComboBox();
+
+    /**
+     * Factory used to create a new {@link SophoxServerPreference}.
+     */
+    public static class Factory implements PreferenceSettingFactory {
+        @Override
+        public PreferenceSetting createPreferenceSetting() {
+            return new SophoxServerPreference();
+        }
+    }
+
+    @Override
+    public TabPreferenceSetting getTabPreferenceSetting(PreferenceTabbedPane gui) {
+        return gui.getServerPreference();
+    }
+
+    @Override
+    public void addGui(PreferenceTabbedPane gui) {
+        final JPanel panel = new JPanel(new GridBagLayout());
+
+        panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
+        panel.add(new JLabel(tr("Server: ")), GBC.std().insets(5, 5, 5, 5));
+        panel.add(SophoxServer, GBC.eop().fill(GBC.HORIZONTAL));
+        SophoxServer.setPossibleItems(SophoxDownloadReader.SOPHOX_SERVER_HISTORY.get());
+        SophoxServer.setText(SophoxDownloadReader.SOPHOX_SERVER.get());
+
+        panel.add(Box.createVerticalGlue(), GBC.eol().fill());
+
+        getTabPreferenceSetting(gui).addSubTab(this, tr("Wikidata+OSM server"), panel);
+    }
+
+    @Override
+    public boolean ok() {
+        SophoxDownloadReader.SOPHOX_SERVER.put(SophoxServer.getText());
+        SophoxDownloadReader.SOPHOX_SERVER_HISTORY.put(SophoxServer.getHistory());
+        return false;
+    }
+
+    @Override
+    public boolean isExpert() {
+        return true;
+    }
+}
Index: plications/editors/josm/plugins/wikipedia/src/org/wikipedia/gui/WikosmDownloadSource.java
===================================================================
--- /applications/editors/josm/plugins/wikipedia/src/org/wikipedia/gui/WikosmDownloadSource.java	(revision 33807)
+++ 	(revision )
@@ -1,389 +1,0 @@
-// License: GPL. For details, see LICENSE file.
-package org.wikipedia.gui;
-
-import static org.openstreetmap.josm.tools.I18n.tr;
-
-import java.awt.*;
-import java.awt.event.ActionEvent;
-import java.awt.event.FocusEvent;
-import java.awt.event.FocusListener;
-import java.util.Collection;
-import java.util.concurrent.Future;
-import java.util.function.Consumer;
-
-import javax.swing.*;
-import javax.swing.event.ListSelectionEvent;
-import javax.swing.event.ListSelectionListener;
-import javax.swing.plaf.basic.BasicArrowButton;
-
-import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.actions.downloadtasks.DownloadOsmTask;
-import org.openstreetmap.josm.actions.downloadtasks.PostDownloadHandler;
-import org.openstreetmap.josm.data.Bounds;
-import org.openstreetmap.josm.data.preferences.AbstractProperty;
-import org.openstreetmap.josm.data.preferences.BooleanProperty;
-import org.openstreetmap.josm.data.preferences.IntegerProperty;
-import org.openstreetmap.josm.gui.MainApplication;
-import org.openstreetmap.josm.gui.download.AbstractDownloadSourcePanel;
-import org.openstreetmap.josm.gui.download.DownloadDialog;
-import org.openstreetmap.josm.gui.download.DownloadSettings;
-import org.openstreetmap.josm.gui.download.DownloadSource;
-import org.openstreetmap.josm.gui.download.DownloadSourceSizingPolicy;
-import org.openstreetmap.josm.gui.download.DownloadSourceSizingPolicy.AdjustableDownloadSizePolicy;
-import org.openstreetmap.josm.gui.download.UserQueryList;
-import org.openstreetmap.josm.gui.util.GuiHelper;
-import org.openstreetmap.josm.gui.widgets.JosmTextArea;
-import org.openstreetmap.josm.tools.GBC;
-import org.openstreetmap.josm.tools.ImageProvider;
-import org.openstreetmap.josm.tools.OpenBrowser;
-import org.wikipedia.io.WikosmDownloadReader;
-
-/**
- * Class defines the way data is fetched from Wikosm API.
- */
-public class WikosmDownloadSource implements DownloadSource<WikosmDownloadSource.WikosmDownloadData> {
-
-    @Override
-    public AbstractDownloadSourcePanel<WikosmDownloadData> createPanel(DownloadDialog dialog) {
-        return new WikosmDownloadSourcePanel(this);
-    }
-
-    @Override
-    public void doDownload(WikosmDownloadData data, DownloadSettings settings) {
-        Bounds area = settings.getDownloadBounds().orElse(new Bounds(0, 0, 0, 0));
-        DownloadOsmTask task = new DownloadOsmTask();
-        task.setZoomAfterDownload(settings.zoomToData());
-        Future<?> future = task.download(
-                new WikosmDownloadReader(area, WikosmDownloadReader.WIKOSM_SERVER.get(), data.getQuery(),
-                        settings.asNewLayer(), data.getDownloadReferrers(), data.getDownloadFull()),
-
-                settings.asNewLayer(), area, null);
-        MainApplication.worker.submit(new PostDownloadHandler(task, future, data.getErrorReporter()));
-    }
-
-    @Override
-    public String getLabel() {
-        return tr("Download from Wikosm API");
-    }
-
-    @Override
-    public boolean onlyExpert() {
-        return true;
-    }
-
-    /**
-     * The GUI representation of the Wikosm download source.
-     */
-    public static class WikosmDownloadSourcePanel extends AbstractDownloadSourcePanel<WikosmDownloadData> {
-
-        private static final String HELP_PAGE = "https://wiki.openstreetmap.org/wiki/Wikidata%2BOSM_SPARQL_query_service";
-        private static final String SIMPLE_NAME = "wikosmdownloadpanel";
-        private static final AbstractProperty<Integer> PANEL_SIZE_PROPERTY =
-                new IntegerProperty(TAB_SPLIT_NAMESPACE + SIMPLE_NAME, 150).cached();
-        private static final BooleanProperty WIKOSM_QUERY_LIST_OPENED =
-                new BooleanProperty("download.wikosm.query-list.opened", false);
-        private static final String ACTION_IMG_SUBDIR = "dialogs";
-
-        private final JosmTextArea wikosmQuery;
-        private final UserQueryList wikosmQueryList;
-        private final JCheckBox referrers;
-        private final JCheckBox fullRel;
-
-        /**
-         * Create a new {@code WikosmDownloadSourcePanel}
-         * @param ds The download source to create the panel for
-         */
-        public WikosmDownloadSourcePanel(WikosmDownloadSource ds) {
-            super(ds);
-            setLayout(new BorderLayout());
-
-            String queryText = "# " +
-                    tr("Find places of education at least 2km, and at most 3km from the center of the selection") +
-                    "\n" +
-                    "SELECT ?osmid WHERE {\n" +
-                    "  VALUES ?amenity { \"kindergarten\" \"school\" \"university\" \"college\" }\n" +
-                    "  ?osmid osmt:amenity ?amenity ;\n" +
-                    "         osmm:loc ?location .\n" +
-                    "  BIND(geof:distance({{center}}, ?location) as ?distance)\n" +
-                    "  FILTER(?distance > 2 && ?distance < 3)\n" +
-                    "}";
-
-            this.wikosmQuery = new JosmTextArea(queryText, 8, 80);
-
-            this.wikosmQuery.setFont(GuiHelper.getMonospacedFont(wikosmQuery));
-            this.wikosmQuery.addFocusListener(new FocusListener() {
-                @Override
-                public void focusGained(FocusEvent e) {
-                    wikosmQuery.selectAll();
-                }
-
-                @Override
-                public void focusLost(FocusEvent e) {
-                    // ignored
-                }
-            });
-
-
-            this.wikosmQueryList = new UserQueryList(this, this.wikosmQuery, "download.wikosm.query");
-            this.wikosmQueryList.setPreferredSize(new Dimension(350, 300));
-
-            EditSnippetAction edit = new EditSnippetAction();
-            RemoveSnippetAction remove = new RemoveSnippetAction();
-            this.wikosmQueryList.addSelectionListener(edit);
-            this.wikosmQueryList.addSelectionListener(remove);
-
-            JPanel listPanel = new JPanel(new GridBagLayout());
-            listPanel.add(new JLabel(tr("Your saved queries:")), GBC.eol().insets(2).anchor(GBC.CENTER));
-            listPanel.add(this.wikosmQueryList, GBC.eol().fill(GBC.BOTH));
-            listPanel.add(new JButton(new AddSnippetAction()), GBC.std().fill(GBC.HORIZONTAL));
-            listPanel.add(new JButton(edit), GBC.std().fill(GBC.HORIZONTAL));
-            listPanel.add(new JButton(remove), GBC.std().fill(GBC.HORIZONTAL));
-            listPanel.setVisible(WIKOSM_QUERY_LIST_OPENED.get());
-
-            JScrollPane scrollPane = new JScrollPane(wikosmQuery);
-            BasicArrowButton arrowButton = new BasicArrowButton(listPanel.isVisible()
-                    ? BasicArrowButton.EAST
-                    : BasicArrowButton.WEST);
-            arrowButton.setToolTipText(tr("Show/hide Wikosm snippet list"));
-            arrowButton.addActionListener(e -> {
-                if (listPanel.isVisible()) {
-                    listPanel.setVisible(false);
-                    arrowButton.setDirection(BasicArrowButton.WEST);
-                    WIKOSM_QUERY_LIST_OPENED.put(Boolean.FALSE);
-                } else {
-                    listPanel.setVisible(true);
-                    arrowButton.setDirection(BasicArrowButton.EAST);
-                    WIKOSM_QUERY_LIST_OPENED.put(Boolean.TRUE);
-                }
-            });
-
-            // TODO: Once new core is widely avialable, replace:
-            //   Main.pref.getBoolean --> Config.getPref().getBoolean
-            //   Main.pref.put --> Config.getPref().putBoolean
-
-            referrers = new JCheckBox(tr("Download referrers (parent relations)"));
-            referrers.setToolTipText(tr("Select if the referrers of the object should be downloaded as well, i.e.,"
-                    + "parent relations and for nodes, additionally, parent ways"));
-            referrers.setSelected(Main.pref.getBoolean("wikosm.downloadprimitive.referrers", true));
-            referrers.addActionListener(e -> Main.pref.putBoolean("wikosm.downloadprimitive.referrers", referrers.isSelected()));
-
-            fullRel = new JCheckBox(tr("Download relation members"));
-            fullRel.setToolTipText(tr("Select if the members of a relation should be downloaded as well"));
-            fullRel.setSelected(Main.pref.getBoolean("wikosm.downloadprimitive.full", true));
-            fullRel.addActionListener(e -> Main.pref.putBoolean("wikosm.downloadprimitive.full", fullRel.isSelected()));
-
-            // https://stackoverflow.com/questions/527719/how-to-add-hyperlink-in-jlabel
-            JButton helpLink = new JButton();
-            helpLink.setText("<HTML><FONT color=\"#000099\"><U>"+tr("help")+"</U></FONT></HTML>");
-            helpLink.setToolTipText(HELP_PAGE);
-            helpLink.setHorizontalAlignment(SwingConstants.LEFT);
-            helpLink.setBorderPainted(false);
-            helpLink.setOpaque(false);
-            helpLink.setBackground(Color.WHITE);
-            helpLink.addActionListener(e -> OpenBrowser.displayUrl(HELP_PAGE));
-
-            JPanel centerPanel = new JPanel(new GridBagLayout());
-            centerPanel.add(scrollPane, GBC.eol().fill(GBC.BOTH));
-            centerPanel.add(referrers, GBC.std().anchor(GBC.WEST).insets(5, 5, 5, 5));
-            centerPanel.add(fullRel, GBC.std().anchor(GBC.WEST).insets(15, 5, 5, 5));
-            centerPanel.add(helpLink, GBC.std().anchor(GBC.WEST).insets(10, 5, 5, 5));
-
-
-            JPanel innerPanel = new JPanel(new BorderLayout());
-            innerPanel.add(centerPanel, BorderLayout.CENTER);
-            innerPanel.add(arrowButton, BorderLayout.EAST);
-
-            add(innerPanel, BorderLayout.CENTER);
-            add(listPanel, BorderLayout.EAST);
-
-            setMinimumSize(new Dimension(450, 240));
-        }
-
-        @Override
-        public WikosmDownloadData getData() {
-            String query = wikosmQuery.getText();
-            /*
-             * A callback that is passed to PostDownloadReporter that is called once the download task
-             * has finished. According to the number of errors happened, their type we decide whether we
-             * want to save the last query in WikosmQueryList.
-             */
-            Consumer<Collection<Object>> errorReporter = errors -> {
-
-                boolean onlyNoDataError = errors.size() == 1 &&
-                        errors.contains("No data found in this area.");
-
-                if (errors.isEmpty() || onlyNoDataError) {
-                    wikosmQueryList.saveHistoricItem(query);
-                }
-            };
-
-            return new WikosmDownloadData(query, referrers.isSelected(), fullRel.isSelected(), errorReporter);
-        }
-
-        @Override
-        public void rememberSettings() {
-            // nothing
-        }
-
-        @Override
-        public void restoreSettings() {
-            // nothing
-        }
-
-        @Override
-        public boolean checkDownload(DownloadSettings settings) {
-            String query = getData().getQuery();
-
-            /*
-             * Absence of the selected area can be justified only if the Wikosm query
-             * is not restricted to bbox.
-             */
-            if (!settings.getDownloadBounds().isPresent() && (
-                    query.contains("{{boxParams}}") ||
-                    query.contains("{{center}}")
-            )) {
-                JOptionPane.showMessageDialog(
-                        this.getParent(),
-                        tr("Please select a download area first."),
-                        tr("Error"),
-                        JOptionPane.ERROR_MESSAGE
-                );
-                return false;
-            }
-
-            return true;
-        }
-
-        @Override
-        public Icon getIcon() {
-            return ImageProvider.get(ACTION_IMG_SUBDIR, "wikosm");
-        }
-
-        @Override
-        public String getSimpleName() {
-            return SIMPLE_NAME;
-        }
-
-        @Override
-        public DownloadSourceSizingPolicy getSizingPolicy() {
-            return new AdjustableDownloadSizePolicy(PANEL_SIZE_PROPERTY);
-        }
-
-        /**
-         * Action that delegates snippet creation to {@link UserQueryList#createNewItem()}.
-         */
-        private class AddSnippetAction extends AbstractAction {
-
-            /**
-             * Constructs a new {@code AddSnippetAction}.
-             */
-            AddSnippetAction() {
-                super();
-                putValue(SMALL_ICON, ImageProvider.get(ACTION_IMG_SUBDIR, "add"));
-                putValue(SHORT_DESCRIPTION, tr("Add new snippet"));
-            }
-
-            @Override
-            public void actionPerformed(ActionEvent e) {
-                wikosmQueryList.createNewItem();
-            }
-        }
-
-        /**
-         * Action that delegates snippet removal to {@link UserQueryList#removeSelectedItem()}.
-         */
-        private class RemoveSnippetAction extends AbstractAction implements ListSelectionListener {
-
-            /**
-             * Constructs a new {@code RemoveSnippetAction}.
-             */
-            RemoveSnippetAction() {
-                super();
-                putValue(SMALL_ICON, ImageProvider.get(ACTION_IMG_SUBDIR, "delete"));
-                putValue(SHORT_DESCRIPTION, tr("Delete selected snippet"));
-                checkEnabled();
-            }
-
-            @Override
-            public void actionPerformed(ActionEvent e) {
-                wikosmQueryList.removeSelectedItem();
-            }
-
-            /**
-             * Disables the action if no items are selected.
-             */
-            void checkEnabled() {
-                setEnabled(wikosmQueryList.getSelectedItem().isPresent());
-            }
-
-            @Override
-            public void valueChanged(ListSelectionEvent e) {
-                checkEnabled();
-            }
-        }
-
-        /**
-         * Action that delegates snippet edit to {@link UserQueryList#editSelectedItem()}.
-         */
-        private class EditSnippetAction extends AbstractAction implements ListSelectionListener {
-
-            /**
-             * Constructs a new {@code EditSnippetAction}.
-             */
-            EditSnippetAction() {
-                super();
-                putValue(SMALL_ICON, ImageProvider.get(ACTION_IMG_SUBDIR, "edit"));
-                putValue(SHORT_DESCRIPTION, tr("Edit selected snippet"));
-                checkEnabled();
-            }
-
-            @Override
-            public void actionPerformed(ActionEvent e) {
-                wikosmQueryList.editSelectedItem();
-            }
-
-            /**
-             * Disables the action if no items are selected.
-             */
-            void checkEnabled() {
-                setEnabled(wikosmQueryList.getSelectedItem().isPresent());
-            }
-
-            @Override
-            public void valueChanged(ListSelectionEvent e) {
-                checkEnabled();
-            }
-        }
-    }
-
-    /**
-     * Encapsulates data that is required to preform download from Wikosm API.
-     */
-    static class WikosmDownloadData {
-        private final String query;
-        private final boolean downloadReferrers;
-        private final boolean downloadFull;
-        private final Consumer<Collection<Object>> errorReporter;
-
-        WikosmDownloadData(String query, boolean downloadReferrers, boolean downloadFull, Consumer<Collection<Object>> errorReporter) {
-            this.query = query;
-            this.downloadReferrers = downloadReferrers;
-            this.downloadFull = downloadFull;
-            this.errorReporter = errorReporter;
-        }
-
-        String getQuery() {
-            return this.query;
-        }
-
-        boolean getDownloadReferrers() {
-            return this.downloadReferrers;
-        }
-
-        boolean getDownloadFull() { return this.downloadFull; }
-
-        Consumer<Collection<Object>> getErrorReporter() {
-            return this.errorReporter;
-        }
-    }
-}
Index: plications/editors/josm/plugins/wikipedia/src/org/wikipedia/gui/WikosmServerPreference.java
===================================================================
--- /applications/editors/josm/plugins/wikipedia/src/org/wikipedia/gui/WikosmServerPreference.java	(revision 33807)
+++ 	(revision )
@@ -1,70 +1,0 @@
-// License: GPL. For details, see LICENSE file.
-package org.wikipedia.gui;
-
-import static org.openstreetmap.josm.tools.I18n.tr;
-
-import java.awt.GridBagLayout;
-
-import javax.swing.BorderFactory;
-import javax.swing.Box;
-import javax.swing.JLabel;
-import javax.swing.JPanel;
-
-import org.openstreetmap.josm.gui.preferences.PreferenceSetting;
-import org.openstreetmap.josm.gui.preferences.PreferenceSettingFactory;
-import org.openstreetmap.josm.gui.preferences.PreferenceTabbedPane;
-import org.openstreetmap.josm.gui.preferences.SubPreferenceSetting;
-import org.openstreetmap.josm.gui.preferences.TabPreferenceSetting;
-import org.openstreetmap.josm.gui.widgets.HistoryComboBox;
-import org.openstreetmap.josm.tools.GBC;
-import org.wikipedia.io.WikosmDownloadReader;
-
-/**
- * Preferences related to Wikosm API servers.
- */
-public class WikosmServerPreference implements SubPreferenceSetting {
-
-    private final HistoryComboBox wikosmServer = new HistoryComboBox();
-
-    /**
-     * Factory used to create a new {@link WikosmServerPreference}.
-     */
-    public static class Factory implements PreferenceSettingFactory {
-        @Override
-        public PreferenceSetting createPreferenceSetting() {
-            return new WikosmServerPreference();
-        }
-    }
-
-    @Override
-    public TabPreferenceSetting getTabPreferenceSetting(PreferenceTabbedPane gui) {
-        return gui.getServerPreference();
-    }
-
-    @Override
-    public void addGui(PreferenceTabbedPane gui) {
-        final JPanel panel = new JPanel(new GridBagLayout());
-
-        panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
-        panel.add(new JLabel(tr("Server: ")), GBC.std().insets(5, 5, 5, 5));
-        panel.add(wikosmServer, GBC.eop().fill(GBC.HORIZONTAL));
-        wikosmServer.setPossibleItems(WikosmDownloadReader.WIKOSM_SERVER_HISTORY.get());
-        wikosmServer.setText(WikosmDownloadReader.WIKOSM_SERVER.get());
-
-        panel.add(Box.createVerticalGlue(), GBC.eol().fill());
-
-        getTabPreferenceSetting(gui).addSubTab(this, tr("Wikidata+OSM server"), panel);
-    }
-
-    @Override
-    public boolean ok() {
-        WikosmDownloadReader.WIKOSM_SERVER.put(wikosmServer.getText());
-        WikosmDownloadReader.WIKOSM_SERVER_HISTORY.put(wikosmServer.getHistory());
-        return false;
-    }
-
-    @Override
-    public boolean isExpert() {
-        return true;
-    }
-}
Index: /applications/editors/josm/plugins/wikipedia/src/org/wikipedia/io/SophoxDownloadReader.java
===================================================================
--- /applications/editors/josm/plugins/wikipedia/src/org/wikipedia/io/SophoxDownloadReader.java	(revision 33808)
+++ /applications/editors/josm/plugins/wikipedia/src/org/wikipedia/io/SophoxDownloadReader.java	(revision 33808)
@@ -0,0 +1,286 @@
+// License: GPL. For details, see LICENSE file.
+package org.wikipedia.io;
+
+import org.openstreetmap.josm.actions.DownloadPrimitiveAction;
+import org.openstreetmap.josm.data.Bounds;
+import org.openstreetmap.josm.data.DataSource;
+import org.openstreetmap.josm.data.coor.LatLon;
+import org.openstreetmap.josm.data.osm.*;
+import org.openstreetmap.josm.data.preferences.ListProperty;
+import org.openstreetmap.josm.data.preferences.StringProperty;
+import org.openstreetmap.josm.gui.progress.ProgressMonitor;
+import org.openstreetmap.josm.io.*;
+import org.openstreetmap.josm.io.NameFinder.SearchResult;
+import org.openstreetmap.josm.tools.HttpClient;
+import org.openstreetmap.josm.tools.Logging;
+import org.openstreetmap.josm.tools.Utils;
+
+import javax.json.Json;
+import javax.json.JsonArray;
+import javax.json.JsonObject;
+import javax.json.JsonValue;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.UnsupportedEncodingException;
+import java.time.Duration;
+import java.time.LocalDateTime;
+import java.time.Period;
+import java.time.ZoneOffset;
+import java.util.*;
+import java.util.concurrent.TimeUnit;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+/**
+ * Read content from an Sophox server.
+ */
+public class SophoxDownloadReader extends BoundingBoxDownloader {
+
+    /**
+     * Property for current Sophox server.
+     */
+    public static final StringProperty SOPHOX_SERVER = new StringProperty("download.sophox.server",
+            "https://sophox.org/bigdata/namespace/wdq/sparql");
+    /**
+     * Property for list of known Sophox servers.
+     */
+// TODO: Core dependency:
+//    public static final ListProperty SOPHOX_SERVER_HISTORY = new ListProperty("download.sophox.servers",
+//            Arrays.asList("https://sophox.org/bigdata/namespace/wdq/sparql"));
+    public static final ListProperty SOPHOX_SERVER_HISTORY = new ListProperty("download.sophox.servers",
+            Arrays.asList("https://sophox.org/bigdata/namespace/wdq/sparql"));
+
+    private static final String DATA_PREFIX = "?query=";
+
+    private final String sophoxServer;
+    private final String sophoxQuery;
+    private final boolean asNewLayer;
+    private final boolean downloadReferrers;
+    private final boolean downloadFull;
+
+    /**
+     * Constructs a new {@code SophoxDownloadReader}.
+     *
+     * @param downloadArea The area to download
+     * @param sophoxServer The Sophox server to use
+     * @param sophoxQuery  The Sophox query
+     */
+    public SophoxDownloadReader(Bounds downloadArea, String sophoxServer, String sophoxQuery,
+                                boolean asNewLayer, boolean downloadReferrers, boolean downloadFull) {
+        super(downloadArea);
+        setDoAuthenticate(false);
+        this.sophoxServer = sophoxServer;
+        this.sophoxQuery = sophoxQuery.trim();
+        this.asNewLayer = asNewLayer;
+        this.downloadReferrers = downloadReferrers;
+        this.downloadFull = downloadFull;
+    }
+
+    @Override
+    protected String getBaseUrl() {
+        return sophoxServer;
+    }
+
+    @Override
+    protected String getRequestForBbox(double lon1, double lat1, double lon2, double lat2) {
+        final String query = this.sophoxQuery
+                .replace("{{boxParams}}", boxParams(lon1, lat1, lon2, lat2))
+                .replace("{{center}}", center(lon1, lat1, lon2, lat2));
+        return DATA_PREFIX + Utils.encodeUrl(query);
+    }
+
+    public static String boxParams(double lon1, double lat1, double lon2, double lat2) {
+        return "\nbd:serviceParam wikibase:cornerWest " + point(lon1, lat1) + ".\n" +
+                "bd:serviceParam wikibase:cornerEast " + point(lon2, lat2) + ".\n";
+    }
+
+    public static String center(double lon1, double lat1, double lon2, double lat2) {
+        LatLon c = new BBox(lon1, lat1, lon2, lat2).getCenter();
+        return point(c.lon(), c.lat());
+    }
+
+    public static String point(double lon, double lat) {
+        return "\"Point(" + lon + " " + lat + ")\"^^geo:wktLiteral";
+    }
+
+    static String date(String humanDuration, LocalDateTime from) {
+        // Convert to ISO 8601. Replace months by X temporarily to avoid conflict with minutes
+        String duration = humanDuration.toLowerCase(Locale.ENGLISH).replace(" ", "")
+                .replaceAll("years?", "Y").replaceAll("months?", "X").replaceAll("weeks?", "W")
+                .replaceAll("days?", "D").replaceAll("hours?", "H").replaceAll("minutes?", "M").replaceAll("seconds?", "S");
+        Matcher matcher = Pattern.compile(
+                "((?:[0-9]+Y)?(?:[0-9]+X)?(?:[0-9]+W)?)"+
+                "((?:[0-9]+D)?)" +
+                "((?:[0-9]+H)?(?:[0-9]+M)?(?:[0-9]+(?:[.,][0-9]{0,9})?S)?)?").matcher(duration);
+        boolean javaPer = false;
+        boolean javaDur = false;
+        if (matcher.matches()) {
+            javaPer = matcher.group(1) != null && !matcher.group(1).isEmpty();
+            javaDur = matcher.group(3) != null && !matcher.group(3).isEmpty();
+            duration = 'P' + matcher.group(1).replace('X', 'M') + matcher.group(2);
+            if (javaDur) {
+                duration += 'T' + matcher.group(3);
+            }
+        }
+
+        // Duration is now a full ISO 8601 duration string. Unfortunately Java does not allow to parse it entirely.
+        // We must split the "period" (years, months, weeks, days) from the "duration" (days, hours, minutes, seconds).
+        Period p = null;
+        Duration d = null;
+        int idx = duration.indexOf('T');
+        if (javaPer) {
+            p = Period.parse(javaDur ? duration.substring(0, idx) : duration);
+        }
+        if (javaDur) {
+            d = Duration.parse(javaPer ? 'P' + duration.substring(idx, duration.length()) : duration);
+        } else if (!javaPer) {
+            d = Duration.parse(duration);
+        }
+
+        // Now that period and duration are known, compute the correct date/time
+        LocalDateTime dt = from;
+        if (p != null) {
+            dt = dt.minus(p);
+        }
+        if (d != null) {
+            dt = dt.minus(d);
+        }
+
+        // Returns the date/time formatted in ISO 8601
+        return dt.toInstant(ZoneOffset.UTC).toString();
+    }
+
+    private static SearchResult searchName(String area) throws IOException {
+        return NameFinder.queryNominatim(area).stream().filter(
+                x -> !OsmPrimitiveType.NODE.equals(x.getOsmId().getType())).iterator().next();
+    }
+
+    static String geocodeArea(String area) throws IOException {
+        // Offsets defined in https://wiki.openstreetmap.org/wiki/Overpass_API/Overpass_QL#By_element_id
+        final EnumMap<OsmPrimitiveType, Long> idOffset = new EnumMap<>(OsmPrimitiveType.class);
+        idOffset.put(OsmPrimitiveType.NODE, 0L);
+        idOffset.put(OsmPrimitiveType.WAY, 2_400_000_000L);
+        idOffset.put(OsmPrimitiveType.RELATION, 3_600_000_000L);
+        final PrimitiveId osmId = searchName(area).getOsmId();
+        return String.format("area(%d)", osmId.getUniqueId() + idOffset.get(osmId.getType()));
+    }
+
+    static String geocodeBbox(String area) throws IOException {
+        Bounds bounds = searchName(area).getBounds();
+        return bounds.getMinLat() + "," + bounds.getMinLon() + "," + bounds.getMaxLat() + "," + bounds.getMaxLon();
+    }
+
+    static String geocodeCoords(String area) throws IOException {
+        SearchResult result = searchName(area);
+        return result.getLat() + "," + result.getLon();
+    }
+
+    static String geocodeId(String area) throws IOException {
+        PrimitiveId osmId = searchName(area).getOsmId();
+        return String.format("%s(%d)", osmId.getType().getAPIName(), osmId.getUniqueId());
+    }
+
+    @Override
+    protected InputStream getInputStreamRaw(String urlStr, ProgressMonitor progressMonitor, String reason,
+                                            boolean uncompressAccordingToContentDisposition) throws OsmTransferException {
+        try {
+            return super.getInputStreamRaw(urlStr, progressMonitor, reason, uncompressAccordingToContentDisposition);
+        } catch (OsmApiException ex) {
+//            final String errorIndicator = "Error</strong>: ";
+//            if (ex.getMessage() != null && ex.getMessage().contains(errorIndicator)) {
+//                final String errorPlusRest = ex.getMessage().split(errorIndicator)[1];
+//                if (errorPlusRest != null) {
+//                    ex.setErrorHeader(errorPlusRest.split("</")[0].replaceAll(".*::request_read_and_idx::", ""));
+//                }
+//            }
+            throw ex;
+        }
+    }
+
+    @Override
+    protected void adaptRequest(HttpClient request) {
+        // see https://wiki.openstreetmap.org/wiki/Overpass_API/Overpass_QL#timeout
+        final Matcher timeoutMatcher = Pattern.compile("#timeout:(\\d+)").matcher(sophoxQuery);
+        final int timeout;
+        if (timeoutMatcher.find()) {
+            timeout = (int) TimeUnit.SECONDS.toMillis(Integer.parseInt(timeoutMatcher.group(1)));
+        } else {
+            timeout = (int) TimeUnit.MINUTES.toMillis(3);
+        }
+        request.setConnectTimeout(timeout);
+        request.setReadTimeout(timeout);
+        request.setAccept("application/sparql-results+json");
+    }
+
+    @Override
+    protected String getTaskName() {
+        return tr("Contacting Server...");
+    }
+
+    @Override
+    protected DataSet parseDataSet(InputStream source, ProgressMonitor progressMonitor) throws IllegalDataException {
+        try {
+            List<PrimitiveId> ids = getPrimitiveIds(source);
+
+            // REVIEW: this seems like a bad way to initiate download from parsing, and makes it hard to test
+            DownloadPrimitiveAction.processItems(asNewLayer, ids, downloadReferrers, downloadFull);
+        } catch (IOException e) {
+            Logging.error(e);
+        }
+
+        return null;
+    }
+
+    static List<PrimitiveId> getPrimitiveIds(InputStream source) throws UnsupportedEncodingException {
+        Pattern uriPattern = Pattern.compile("^https://www\\.openstreetmap\\.org/(node|way|relation)/(\\d+)");
+        List<PrimitiveId> ids = new ArrayList<>();
+
+        JsonArray results = Json.createReader(new InputStreamReader(source, "UTF-8"))
+                .readObject()
+                .getJsonObject("results")
+                .getJsonArray("bindings");
+
+        for (JsonObject row : results.getValuesAs(JsonObject.class)) {
+            for (JsonValue column : row.values()) {
+                JsonObject columnObj = (JsonObject) column;
+                if (columnObj.getString("type").equals("uri"))  {
+                    Matcher matcher = uriPattern.matcher(columnObj.getString("value"));
+                    if (matcher.matches()) {
+                        ids.add(new SimplePrimitiveId(Long.parseLong(matcher.group(2)),
+                                OsmPrimitiveType.from(matcher.group(1))));
+                    }
+                }
+            }
+        }
+
+        return ids;
+    }
+
+    @Override
+    public DataSet parseOsm(ProgressMonitor progressMonitor) throws OsmTransferException {
+
+        DataSet ds = super.parseOsm(progressMonitor);
+
+        // add bounds if necessary (note that Sophox API does not return bounds in the response XML)
+        if (ds != null && ds.getDataSources().isEmpty() && sophoxQuery.contains("{{boxParams}}")) {
+            if (crosses180th) {
+                Bounds bounds = new Bounds(lat1, lon1, lat2, 180.0);
+                DataSource src = new DataSource(bounds, getBaseUrl());
+                ds.addDataSource(src);
+
+                bounds = new Bounds(lat1, -180.0, lat2, lon2);
+                src = new DataSource(bounds, getBaseUrl());
+                ds.addDataSource(src);
+            } else {
+                Bounds bounds = new Bounds(lat1, lon1, lat2, lon2);
+                DataSource src = new DataSource(bounds, getBaseUrl());
+                ds.addDataSource(src);
+            }
+        }
+
+        return ds;
+    }
+}
Index: plications/editors/josm/plugins/wikipedia/src/org/wikipedia/io/WikosmDownloadReader.java
===================================================================
--- /applications/editors/josm/plugins/wikipedia/src/org/wikipedia/io/WikosmDownloadReader.java	(revision 33807)
+++ 	(revision )
@@ -1,286 +1,0 @@
-// License: GPL. For details, see LICENSE file.
-package org.wikipedia.io;
-
-import org.openstreetmap.josm.actions.DownloadPrimitiveAction;
-import org.openstreetmap.josm.data.Bounds;
-import org.openstreetmap.josm.data.DataSource;
-import org.openstreetmap.josm.data.coor.LatLon;
-import org.openstreetmap.josm.data.osm.*;
-import org.openstreetmap.josm.data.preferences.ListProperty;
-import org.openstreetmap.josm.data.preferences.StringProperty;
-import org.openstreetmap.josm.gui.progress.ProgressMonitor;
-import org.openstreetmap.josm.io.*;
-import org.openstreetmap.josm.io.NameFinder.SearchResult;
-import org.openstreetmap.josm.tools.HttpClient;
-import org.openstreetmap.josm.tools.Logging;
-import org.openstreetmap.josm.tools.Utils;
-
-import javax.json.Json;
-import javax.json.JsonArray;
-import javax.json.JsonObject;
-import javax.json.JsonValue;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.UnsupportedEncodingException;
-import java.time.Duration;
-import java.time.LocalDateTime;
-import java.time.Period;
-import java.time.ZoneOffset;
-import java.util.*;
-import java.util.concurrent.TimeUnit;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import static org.openstreetmap.josm.tools.I18n.tr;
-
-/**
- * Read content from an Wikosm server.
- */
-public class WikosmDownloadReader extends BoundingBoxDownloader {
-
-    /**
-     * Property for current Wikosm server.
-     */
-    public static final StringProperty WIKOSM_SERVER = new StringProperty("download.wikosm.server",
-            "http://88.99.164.208/bigdata/namespace/wdq/sparql");
-    /**
-     * Property for list of known Wikosm servers.
-     */
-// TODO: Core dependency:
-//    public static final ListProperty WIKOSM_SERVER_HISTORY = new ListProperty("download.wikosm.servers",
-//            Arrays.asList("http://88.99.164.208/bigdata/namespace/wdq/sparql"));
-    public static final ListProperty WIKOSM_SERVER_HISTORY = new ListProperty("download.wikosm.servers",
-            Arrays.asList("http://88.99.164.208/bigdata/namespace/wdq/sparql"));
-
-    private static final String DATA_PREFIX = "?query=";
-
-    private final String wikosmServer;
-    private final String wikosmQuery;
-    private final boolean asNewLayer;
-    private final boolean downloadReferrers;
-    private final boolean downloadFull;
-
-    /**
-     * Constructs a new {@code WikosmDownloadReader}.
-     *
-     * @param downloadArea The area to download
-     * @param wikosmServer The Wikosm server to use
-     * @param wikosmQuery  The Wikosm query
-     */
-    public WikosmDownloadReader(Bounds downloadArea, String wikosmServer, String wikosmQuery,
-                                boolean asNewLayer, boolean downloadReferrers, boolean downloadFull) {
-        super(downloadArea);
-        setDoAuthenticate(false);
-        this.wikosmServer = wikosmServer;
-        this.wikosmQuery = wikosmQuery.trim();
-        this.asNewLayer = asNewLayer;
-        this.downloadReferrers = downloadReferrers;
-        this.downloadFull = downloadFull;
-    }
-
-    @Override
-    protected String getBaseUrl() {
-        return wikosmServer;
-    }
-
-    @Override
-    protected String getRequestForBbox(double lon1, double lat1, double lon2, double lat2) {
-        final String query = this.wikosmQuery
-                .replace("{{boxParams}}", boxParams(lon1, lat1, lon2, lat2))
-                .replace("{{center}}", center(lon1, lat1, lon2, lat2));
-        return DATA_PREFIX + Utils.encodeUrl(query);
-    }
-
-    public static String boxParams(double lon1, double lat1, double lon2, double lat2) {
-        return "\nbd:serviceParam wikibase:cornerWest " + point(lon1, lat1) + ".\n" +
-                "bd:serviceParam wikibase:cornerEast " + point(lon2, lat2) + ".\n";
-    }
-
-    public static String center(double lon1, double lat1, double lon2, double lat2) {
-        LatLon c = new BBox(lon1, lat1, lon2, lat2).getCenter();
-        return point(c.lon(), c.lat());
-    }
-
-    public static String point(double lon, double lat) {
-        return "\"Point(" + lon + " " + lat + ")\"^^geo:wktLiteral";
-    }
-
-    static String date(String humanDuration, LocalDateTime from) {
-        // Convert to ISO 8601. Replace months by X temporarily to avoid conflict with minutes
-        String duration = humanDuration.toLowerCase(Locale.ENGLISH).replace(" ", "")
-                .replaceAll("years?", "Y").replaceAll("months?", "X").replaceAll("weeks?", "W")
-                .replaceAll("days?", "D").replaceAll("hours?", "H").replaceAll("minutes?", "M").replaceAll("seconds?", "S");
-        Matcher matcher = Pattern.compile(
-                "((?:[0-9]+Y)?(?:[0-9]+X)?(?:[0-9]+W)?)"+
-                "((?:[0-9]+D)?)" +
-                "((?:[0-9]+H)?(?:[0-9]+M)?(?:[0-9]+(?:[.,][0-9]{0,9})?S)?)?").matcher(duration);
-        boolean javaPer = false;
-        boolean javaDur = false;
-        if (matcher.matches()) {
-            javaPer = matcher.group(1) != null && !matcher.group(1).isEmpty();
-            javaDur = matcher.group(3) != null && !matcher.group(3).isEmpty();
-            duration = 'P' + matcher.group(1).replace('X', 'M') + matcher.group(2);
-            if (javaDur) {
-                duration += 'T' + matcher.group(3);
-            }
-        }
-
-        // Duration is now a full ISO 8601 duration string. Unfortunately Java does not allow to parse it entirely.
-        // We must split the "period" (years, months, weeks, days) from the "duration" (days, hours, minutes, seconds).
-        Period p = null;
-        Duration d = null;
-        int idx = duration.indexOf('T');
-        if (javaPer) {
-            p = Period.parse(javaDur ? duration.substring(0, idx) : duration);
-        }
-        if (javaDur) {
-            d = Duration.parse(javaPer ? 'P' + duration.substring(idx, duration.length()) : duration);
-        } else if (!javaPer) {
-            d = Duration.parse(duration);
-        }
-
-        // Now that period and duration are known, compute the correct date/time
-        LocalDateTime dt = from;
-        if (p != null) {
-            dt = dt.minus(p);
-        }
-        if (d != null) {
-            dt = dt.minus(d);
-        }
-
-        // Returns the date/time formatted in ISO 8601
-        return dt.toInstant(ZoneOffset.UTC).toString();
-    }
-
-    private static SearchResult searchName(String area) throws IOException {
-        return NameFinder.queryNominatim(area).stream().filter(
-                x -> !OsmPrimitiveType.NODE.equals(x.getOsmId().getType())).iterator().next();
-    }
-
-    static String geocodeArea(String area) throws IOException {
-        // Offsets defined in https://wiki.openstreetmap.org/wiki/Overpass_API/Overpass_QL#By_element_id
-        final EnumMap<OsmPrimitiveType, Long> idOffset = new EnumMap<>(OsmPrimitiveType.class);
-        idOffset.put(OsmPrimitiveType.NODE, 0L);
-        idOffset.put(OsmPrimitiveType.WAY, 2_400_000_000L);
-        idOffset.put(OsmPrimitiveType.RELATION, 3_600_000_000L);
-        final PrimitiveId osmId = searchName(area).getOsmId();
-        return String.format("area(%d)", osmId.getUniqueId() + idOffset.get(osmId.getType()));
-    }
-
-    static String geocodeBbox(String area) throws IOException {
-        Bounds bounds = searchName(area).getBounds();
-        return bounds.getMinLat() + "," + bounds.getMinLon() + "," + bounds.getMaxLat() + "," + bounds.getMaxLon();
-    }
-
-    static String geocodeCoords(String area) throws IOException {
-        SearchResult result = searchName(area);
-        return result.getLat() + "," + result.getLon();
-    }
-
-    static String geocodeId(String area) throws IOException {
-        PrimitiveId osmId = searchName(area).getOsmId();
-        return String.format("%s(%d)", osmId.getType().getAPIName(), osmId.getUniqueId());
-    }
-
-    @Override
-    protected InputStream getInputStreamRaw(String urlStr, ProgressMonitor progressMonitor, String reason,
-                                            boolean uncompressAccordingToContentDisposition) throws OsmTransferException {
-        try {
-            return super.getInputStreamRaw(urlStr, progressMonitor, reason, uncompressAccordingToContentDisposition);
-        } catch (OsmApiException ex) {
-//            final String errorIndicator = "Error</strong>: ";
-//            if (ex.getMessage() != null && ex.getMessage().contains(errorIndicator)) {
-//                final String errorPlusRest = ex.getMessage().split(errorIndicator)[1];
-//                if (errorPlusRest != null) {
-//                    ex.setErrorHeader(errorPlusRest.split("</")[0].replaceAll(".*::request_read_and_idx::", ""));
-//                }
-//            }
-            throw ex;
-        }
-    }
-
-    @Override
-    protected void adaptRequest(HttpClient request) {
-        // see https://wiki.openstreetmap.org/wiki/Overpass_API/Overpass_QL#timeout
-        final Matcher timeoutMatcher = Pattern.compile("#timeout:(\\d+)").matcher(wikosmQuery);
-        final int timeout;
-        if (timeoutMatcher.find()) {
-            timeout = (int) TimeUnit.SECONDS.toMillis(Integer.parseInt(timeoutMatcher.group(1)));
-        } else {
-            timeout = (int) TimeUnit.MINUTES.toMillis(3);
-        }
-        request.setConnectTimeout(timeout);
-        request.setReadTimeout(timeout);
-        request.setAccept("application/sparql-results+json");
-    }
-
-    @Override
-    protected String getTaskName() {
-        return tr("Contacting Server...");
-    }
-
-    @Override
-    protected DataSet parseDataSet(InputStream source, ProgressMonitor progressMonitor) throws IllegalDataException {
-        try {
-            List<PrimitiveId> ids = getPrimitiveIds(source);
-
-            // REVIEW: this seems like a bad way to initiate download from parsing, and makes it hard to test
-            DownloadPrimitiveAction.processItems(asNewLayer, ids, downloadReferrers, downloadFull);
-        } catch (IOException e) {
-            Logging.error(e);
-        }
-
-        return null;
-    }
-
-    static List<PrimitiveId> getPrimitiveIds(InputStream source) throws UnsupportedEncodingException {
-        Pattern uriPattern = Pattern.compile("^https://www\\.openstreetmap\\.org/(node|way|relation)/(\\d+)");
-        List<PrimitiveId> ids = new ArrayList<>();
-
-        JsonArray results = Json.createReader(new InputStreamReader(source, "UTF-8"))
-                .readObject()
-                .getJsonObject("results")
-                .getJsonArray("bindings");
-
-        for (JsonObject row : results.getValuesAs(JsonObject.class)) {
-            for (JsonValue column : row.values()) {
-                JsonObject columnObj = (JsonObject) column;
-                if (columnObj.getString("type").equals("uri"))  {
-                    Matcher matcher = uriPattern.matcher(columnObj.getString("value"));
-                    if (matcher.matches()) {
-                        ids.add(new SimplePrimitiveId(Long.parseLong(matcher.group(2)),
-                                OsmPrimitiveType.from(matcher.group(1))));
-                    }
-                }
-            }
-        }
-
-        return ids;
-    }
-
-    @Override
-    public DataSet parseOsm(ProgressMonitor progressMonitor) throws OsmTransferException {
-
-        DataSet ds = super.parseOsm(progressMonitor);
-
-        // add bounds if necessary (note that Wikosm API does not return bounds in the response XML)
-        if (ds != null && ds.getDataSources().isEmpty() && wikosmQuery.contains("{{boxParams}}")) {
-            if (crosses180th) {
-                Bounds bounds = new Bounds(lat1, lon1, lat2, 180.0);
-                DataSource src = new DataSource(bounds, getBaseUrl());
-                ds.addDataSource(src);
-
-                bounds = new Bounds(lat1, -180.0, lat2, lon2);
-                src = new DataSource(bounds, getBaseUrl());
-                ds.addDataSource(src);
-            } else {
-                Bounds bounds = new Bounds(lat1, lon1, lat2, lon2);
-                DataSource src = new DataSource(bounds, getBaseUrl());
-                ds.addDataSource(src);
-            }
-        }
-
-        return ds;
-    }
-}
Index: /applications/editors/josm/plugins/wikipedia/test/unit/org/wikipedia/gui/SophoxServerPreferenceTest.java
===================================================================
--- /applications/editors/josm/plugins/wikipedia/test/unit/org/wikipedia/gui/SophoxServerPreferenceTest.java	(revision 33808)
+++ /applications/editors/josm/plugins/wikipedia/test/unit/org/wikipedia/gui/SophoxServerPreferenceTest.java	(revision 33808)
@@ -0,0 +1,41 @@
+// License: GPL. For details, see LICENSE file.
+package org.wikipedia.gui;
+
+import static org.junit.Assert.assertNotNull;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.openstreetmap.josm.gui.preferences.PreferencesTestUtils;
+import org.openstreetmap.josm.gui.preferences.server.ServerAccessPreference;
+import org.openstreetmap.josm.testutils.JOSMTestRules;
+
+import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+
+/**
+ * Unit tests of {@link SophoxServerPreference} class.
+ */
+public class SophoxServerPreferenceTest {
+
+    /**
+     * Setup tests
+     */
+    @Rule
+    @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
+    public JOSMTestRules test = new JOSMTestRules().preferences().platform();
+
+    /**
+     * Unit test of {@link SophoxServerPreference}.
+     */
+    @Test
+    public void testSophoxServerPreference() {
+        assertNotNull(new SophoxServerPreference.Factory().createPreferenceSetting());
+    }
+
+    /**
+     * Unit test of {@link SophoxServerPreference#addGui}.
+     */
+    @Test
+    public void testAddGui() {
+        PreferencesTestUtils.doTestPreferenceSettingAddGui(new SophoxServerPreference.Factory(), ServerAccessPreference.class);
+    }
+}
Index: plications/editors/josm/plugins/wikipedia/test/unit/org/wikipedia/gui/WikosmServerPreferenceTest.java
===================================================================
--- /applications/editors/josm/plugins/wikipedia/test/unit/org/wikipedia/gui/WikosmServerPreferenceTest.java	(revision 33807)
+++ 	(revision )
@@ -1,41 +1,0 @@
-// License: GPL. For details, see LICENSE file.
-package org.wikipedia.gui;
-
-import static org.junit.Assert.assertNotNull;
-
-import org.junit.Rule;
-import org.junit.Test;
-import org.openstreetmap.josm.gui.preferences.PreferencesTestUtils;
-import org.openstreetmap.josm.gui.preferences.server.ServerAccessPreference;
-import org.openstreetmap.josm.testutils.JOSMTestRules;
-
-import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
-
-/**
- * Unit tests of {@link WikosmServerPreference} class.
- */
-public class WikosmServerPreferenceTest {
-
-    /**
-     * Setup tests
-     */
-    @Rule
-    @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
-    public JOSMTestRules test = new JOSMTestRules().preferences().platform();
-
-    /**
-     * Unit test of {@link WikosmServerPreference}.
-     */
-    @Test
-    public void testWikosmServerPreference() {
-        assertNotNull(new WikosmServerPreference.Factory().createPreferenceSetting());
-    }
-
-    /**
-     * Unit test of {@link WikosmServerPreference#addGui}.
-     */
-    @Test
-    public void testAddGui() {
-        PreferencesTestUtils.doTestPreferenceSettingAddGui(new WikosmServerPreference.Factory(), ServerAccessPreference.class);
-    }
-}
Index: /applications/editors/josm/plugins/wikipedia/test/unit/org/wikipedia/io/SophoxDownloadReaderTest.java
===================================================================
--- /applications/editors/josm/plugins/wikipedia/test/unit/org/wikipedia/io/SophoxDownloadReaderTest.java	(revision 33808)
+++ /applications/editors/josm/plugins/wikipedia/test/unit/org/wikipedia/io/SophoxDownloadReaderTest.java	(revision 33808)
@@ -0,0 +1,70 @@
+// License: GPL. For details, see LICENSE file.
+package org.wikipedia.io;
+
+import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+import org.junit.Rule;
+import org.junit.Test;
+import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
+import org.openstreetmap.josm.data.osm.PrimitiveId;
+import org.openstreetmap.josm.data.osm.SimplePrimitiveId;
+import org.openstreetmap.josm.testutils.JOSMTestRules;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+import java.util.List;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+
+/**
+ * Unit tests of {@link SophoxDownloadReader} class.
+ */
+public class SophoxDownloadReaderTest {
+
+    /**
+     * Base test environment is enough
+     */
+    @Rule
+    @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
+    public JOSMTestRules test = new JOSMTestRules().preferences();
+
+    /**
+     * Tests point generation
+     */
+    @Test
+    public void testPoint() throws UnsupportedEncodingException {
+        assertThat(SophoxDownloadReader.point(9.5, 47.16),
+                is("\"Point(9.5 47.16)\"^^geo:wktLiteral"));
+        assertThat(SophoxDownloadReader.boxParams(1.1, 2.2, 3.3, 4.4),
+                is("\nbd:serviceParam wikibase:cornerWest \"Point(1.1 2.2)\"^^geo:wktLiteral." +
+                        "\nbd:serviceParam wikibase:cornerEast \"Point(3.3 4.4)\"^^geo:wktLiteral.\n"));
+    }
+
+    /**
+     * Tests server response parsing
+     */
+    @Test
+    public void testIdParsing() throws UnsupportedEncodingException {
+        String json = String.join("\n",
+                "{\"results\":{\"bindings\":[",
+                "{\"a\":{\"type\": \"uri\", \"value\": \"https://www.openstreetmap.org/node/12345\"}},",
+                "{\"a\":{\"type\": \"uri\", \"value\": \"https://www.openstreetmap.org/way/1234512345\"}},",
+                "{\"a\":{\"type\": \"uri\", \"value\": \"https://www.openstreetmap.org/relation/98765\"}}",
+                "]}}"
+        );
+
+        InputStream stream = new ByteArrayInputStream(json.getBytes(StandardCharsets.UTF_8.name()));
+        List<PrimitiveId> actual = SophoxDownloadReader.getPrimitiveIds(stream);
+
+        List<PrimitiveId> expected = Arrays.asList(new PrimitiveId[]{
+                new SimplePrimitiveId(12345, OsmPrimitiveType.NODE),
+                new SimplePrimitiveId(1234512345, OsmPrimitiveType.WAY),
+                new SimplePrimitiveId(98765, OsmPrimitiveType.RELATION),
+        });
+
+        assertThat(actual, is(expected));
+    }
+}
Index: plications/editors/josm/plugins/wikipedia/test/unit/org/wikipedia/io/WikosmDownloadReaderTest.java
===================================================================
--- /applications/editors/josm/plugins/wikipedia/test/unit/org/wikipedia/io/WikosmDownloadReaderTest.java	(revision 33807)
+++ 	(revision )
@@ -1,70 +1,0 @@
-// License: GPL. For details, see LICENSE file.
-package org.wikipedia.io;
-
-import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
-import org.junit.Rule;
-import org.junit.Test;
-import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
-import org.openstreetmap.josm.data.osm.PrimitiveId;
-import org.openstreetmap.josm.data.osm.SimplePrimitiveId;
-import org.openstreetmap.josm.testutils.JOSMTestRules;
-
-import java.io.ByteArrayInputStream;
-import java.io.InputStream;
-import java.io.UnsupportedEncodingException;
-import java.nio.charset.StandardCharsets;
-import java.util.Arrays;
-import java.util.List;
-
-import static org.hamcrest.CoreMatchers.is;
-import static org.junit.Assert.assertThat;
-
-/**
- * Unit tests of {@link WikosmDownloadReader} class.
- */
-public class WikosmDownloadReaderTest {
-
-    /**
-     * Base test environment is enough
-     */
-    @Rule
-    @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
-    public JOSMTestRules test = new JOSMTestRules().preferences();
-
-    /**
-     * Tests point generation
-     */
-    @Test
-    public void testPoint() throws UnsupportedEncodingException {
-        assertThat(WikosmDownloadReader.point(9.5, 47.16),
-                is("\"Point(9.5 47.16)\"^^geo:wktLiteral"));
-        assertThat(WikosmDownloadReader.boxParams(1.1, 2.2, 3.3, 4.4),
-                is("\nbd:serviceParam wikibase:cornerWest \"Point(1.1 2.2)\"^^geo:wktLiteral." +
-                        "\nbd:serviceParam wikibase:cornerEast \"Point(3.3 4.4)\"^^geo:wktLiteral.\n"));
-    }
-
-    /**
-     * Tests server response parsing
-     */
-    @Test
-    public void testIdParsing() throws UnsupportedEncodingException {
-        String json = String.join("\n",
-                "{\"results\":{\"bindings\":[",
-                "{\"a\":{\"type\": \"uri\", \"value\": \"https://www.openstreetmap.org/node/12345\"}},",
-                "{\"a\":{\"type\": \"uri\", \"value\": \"https://www.openstreetmap.org/way/1234512345\"}},",
-                "{\"a\":{\"type\": \"uri\", \"value\": \"https://www.openstreetmap.org/relation/98765\"}}",
-                "]}}"
-        );
-
-        InputStream stream = new ByteArrayInputStream(json.getBytes(StandardCharsets.UTF_8.name()));
-        List<PrimitiveId> actual = WikosmDownloadReader.getPrimitiveIds(stream);
-
-        List<PrimitiveId> expected = Arrays.asList(new PrimitiveId[]{
-                new SimplePrimitiveId(12345, OsmPrimitiveType.NODE),
-                new SimplePrimitiveId(1234512345, OsmPrimitiveType.WAY),
-                new SimplePrimitiveId(98765, OsmPrimitiveType.RELATION),
-        });
-
-        assertThat(actual, is(expected));
-    }
-}
