Index: applications/editors/josm/plugins/MicrosoftStreetside/.classpath
===================================================================
--- applications/editors/josm/plugins/MicrosoftStreetside/.classpath	(revision 34427)
+++ applications/editors/josm/plugins/MicrosoftStreetside/.classpath	(revision 34428)
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <classpath>
-	<classpathentry including="data/**|images/**|LICENSE|LICENSE_*" kind="src" output="bin/main" path="">
+	<classpathentry excluding="config/" including="data/**|images/**|LICENSE|LICENSE_*" kind="src" output="bin/main" path="">
 		<attributes>
 			<attribute name="gradle_scope" value="main"/>
@@ -7,4 +7,5 @@
 		</attributes>
 	</classpathentry>
+	<classpathentry kind="src" path="config"/>
 	<classpathentry kind="src" output="bin/test" path="test/unit">
 		<attributes>
Index: applications/editors/josm/plugins/MicrosoftStreetside/.gitignore
===================================================================
--- applications/editors/josm/plugins/MicrosoftStreetside/.gitignore	(revision 34427)
+++ applications/editors/josm/plugins/MicrosoftStreetside/.gitignore	(revision 34428)
@@ -16,4 +16,5 @@
 .gradle/
 .travis.yml
+.settings
 
 # OS X metadata
Index: applications/editors/josm/plugins/MicrosoftStreetside/README.md
===================================================================
--- applications/editors/josm/plugins/MicrosoftStreetside/README.md	(revision 34427)
+++ applications/editors/josm/plugins/MicrosoftStreetside/README.md	(revision 34428)
@@ -13,14 +13,16 @@
 
 ## Building from source
-Checkout the JOSM source, compile it and checkout the plugin source:
+Checkout the JOSM source, compile it and checkout the plugin source (the last gradle command is optional, but contains code checking and unit test functionality - requires a Gradle installation):
 
     svn co http://svn.openstreetmap.org/applications/editors/josm josm
     cd josm/core
-    ant clean dist
+    ant
     cd ../plugins
     rm -rf MicrosoftStreetside
     git clone https://github.com/JOSM/MicrosoftStreetside.git MicrosoftStreetside
     cd MicrosoftStreetside
-    ant clean install
+    ant clean
+    ant dist
+    gradle build
     
 Now Restart JOSM and activate the MicrosoftStreeside plugin in your preferences. 
Index: applications/editors/josm/plugins/MicrosoftStreetside/build.xml
===================================================================
--- applications/editors/josm/plugins/MicrosoftStreetside/build.xml	(revision 34427)
+++ applications/editors/josm/plugins/MicrosoftStreetside/build.xml	(revision 34428)
@@ -39,4 +39,5 @@
 		<include name="apache-commons.jar"/>
 		<include name="apache-http.jar"/>
+		<include name="utilsplugin2.jar"/>
 	</fileset>
 
Index: applications/editors/josm/plugins/MicrosoftStreetside/gradle.properties
===================================================================
--- applications/editors/josm/plugins/MicrosoftStreetside/gradle.properties	(revision 34427)
+++ applications/editors/josm/plugins/MicrosoftStreetside/gradle.properties	(revision 34428)
@@ -14,5 +14,5 @@
 # If not, choose the next higher number that is available, or the gradle build will break.
 plugin.compile.version=13860
-plugin.requires=apache-commons;apache-http
+plugin.requires=apache-commons;apache-http;utilsplugin2
 
 # Character encoding of Gradle files
Index: applications/editors/josm/plugins/MicrosoftStreetside/src/org/openstreetmap/josm/plugins/streetside/StreetsideAbstractImage.java
===================================================================
--- applications/editors/josm/plugins/MicrosoftStreetside/src/org/openstreetmap/josm/plugins/streetside/StreetsideAbstractImage.java	(revision 34427)
+++ applications/editors/josm/plugins/MicrosoftStreetside/src/org/openstreetmap/josm/plugins/streetside/StreetsideAbstractImage.java	(revision 34428)
@@ -12,5 +12,5 @@
 /**
  * Abstract superclass for all image objects. At the moment there are 3,
- * {@link StreetsideImportedImage}, {@link StreetsideImage}, & {@link StreetsideCubemap}.
+ * {@link StreetsideImportedImage}, {@link StreetsideImage}, {@link StreetsideCubemap}.
  *
  * @author nokutu
Index: applications/editors/josm/plugins/MicrosoftStreetside/src/org/openstreetmap/josm/plugins/streetside/cubemap/CubemapBox.java
===================================================================
--- applications/editors/josm/plugins/MicrosoftStreetside/src/org/openstreetmap/josm/plugins/streetside/cubemap/CubemapBox.java	(revision 34427)
+++ applications/editors/josm/plugins/MicrosoftStreetside/src/org/openstreetmap/josm/plugins/streetside/cubemap/CubemapBox.java	(revision 34428)
@@ -8,4 +8,6 @@
 
 import java.awt.image.BufferedImage;
+
+import org.openstreetmap.josm.plugins.streetside.utils.GraphicsUtils;
 
 import javafx.animation.AnimationTimer;
Index: applications/editors/josm/plugins/MicrosoftStreetside/src/org/openstreetmap/josm/plugins/streetside/cubemap/CubemapBuilder.java
===================================================================
--- applications/editors/josm/plugins/MicrosoftStreetside/src/org/openstreetmap/josm/plugins/streetside/cubemap/CubemapBuilder.java	(revision 34427)
+++ applications/editors/josm/plugins/MicrosoftStreetside/src/org/openstreetmap/josm/plugins/streetside/cubemap/CubemapBuilder.java	(revision 34428)
@@ -5,4 +5,5 @@
 import java.text.MessageFormat;
 import java.util.ArrayList;
+import java.util.EnumSet;
 import java.util.HashMap;
 import java.util.List;
@@ -20,4 +21,5 @@
 import org.openstreetmap.josm.plugins.streetside.gui.StreetsideViewerDialog;
 import org.openstreetmap.josm.plugins.streetside.gui.imageinfo.StreetsideViewerPanel;
+import org.openstreetmap.josm.plugins.streetside.utils.GraphicsUtils;
 import org.openstreetmap.josm.plugins.streetside.utils.StreetsideProperties;
 
@@ -35,5 +37,8 @@
 	protected boolean cancelled;
 	private long startTime;
-  private Map<String, BufferedImage> tileImages = new ConcurrentHashMap();//new HashMap<>();
+
+	private Map<String, BufferedImage> tileImages = new ConcurrentHashMap<>();
+
+	private int currentTileCount = 0;
 
   /**
@@ -55,12 +60,26 @@
 	}
 
-	@Override
+	/**
+   * Fired when any image is added to the database.
+   */
+  @Override
 	public void imagesAdded() {
-		// Do nothing
-	}
-
-	@Override
-	public void selectedImageChanged(StreetsideAbstractImage oldImage, StreetsideAbstractImage newImage) {
-		startTime = System.currentTimeMillis();
+		// Not implemented by the CubemapBuilder
+	}
+
+	/**
+   * Fired when the selected image is changed by something different from
+   * manually clicking on the icon.
+   *
+   * @param oldImage
+   *          Old selected {@link StreetsideAbstractImage}
+   * @param newImage
+   *          New selected {@link StreetsideAbstractImage}
+   *
+   * @see StreetsideDataListener
+   */
+  @Override
+  public void selectedImageChanged(StreetsideAbstractImage oldImage, StreetsideAbstractImage newImage) {
+    startTime = System.currentTimeMillis();
 
 		if (newImage != null) {
@@ -90,125 +109,128 @@
 	public void downloadCubemapImages(String imageId) {
 
-		final int maxCols = StreetsideProperties.SHOW_HIGH_RES_STREETSIDE_IMAGERY.get() ? 4 : 2;
-		final int maxRows = StreetsideProperties.SHOW_HIGH_RES_STREETSIDE_IMAGERY.get() ? 4 : 2;
-		final int maxThreadCount = 6 * maxCols * maxRows;
+	  final int maxThreadCount = StreetsideProperties.DOWNLOAD_CUBEFACE_TILES_TOGETHER.get()?6:6 * CubemapUtils.getMaxCols() * CubemapUtils.getMaxRows();
 
 		int fails = 0;
 
-		int min = 0;   int max = (StreetsideProperties.SHOW_HIGH_RES_STREETSIDE_IMAGERY.get()?96:24)*2;
-
-		String[] message = new String[2];
+    // TODO: message for progress bar
+    String[] message = new String[2];
     message[0] = MessageFormat.format("Downloading Streetside imagery for {0}", imageId);
     message[1] = "Wait for completion…….";
 
-		long startTime = System.currentTimeMillis();
-
-		try {
-
-			ExecutorService pool = Executors.newFixedThreadPool(maxThreadCount);
-			List<Callable<String>> tasks = new ArrayList<>(maxThreadCount);
-
-			// launch 4-tiled (low-res) downloading tasks . . .
-			if (!StreetsideProperties.SHOW_HIGH_RES_STREETSIDE_IMAGERY.get()) {
-				for (int i = 0; i < CubemapUtils.NUM_SIDES; i++) {
-					int tileNr = 0;
-					for (int j = 0; j < maxCols; j++) {
-						for (int k = 0; k < maxRows; k++) {
-
-							String tileId = String.valueOf(imageId + CubemapUtils.getFaceNumberForCount(i)
-									+ Integer.valueOf(tileNr++).toString());
-							tasks.add(new TileDownloadingTask(tileId));
-						}
-					}
-				}
-
-				List<Future<String>> results = pool.invokeAll(tasks);
-				for (Future<String> ff : results) {
-
-					if(StreetsideProperties.DEBUGING_ENABLED.get()) {
-					  logger.debug(MessageFormat.format("Completed tile downloading task {0} in {1} seconds.", ff.get(), (startTime - System.currentTimeMillis())/ 1000));
-					}
-				}
-
-				// launch 16-tiled (high-res) downloading tasks
-			} else if (StreetsideProperties.SHOW_HIGH_RES_STREETSIDE_IMAGERY.get()) {
-				for (int i = 0; i < CubemapUtils.NUM_SIDES; i++) {
-					for (int j = 0; j < maxCols; j++) {
-						for (int k = 0; k < maxRows; k++) {
-
-							String tileId = String.valueOf(imageId + CubemapUtils.getFaceNumberForCount(i)
-									+ String.valueOf(Integer.valueOf(j).toString() + Integer.valueOf(k).toString()));
-							tasks.add(new TileDownloadingTask(tileId));
-						}
-					}
-				}
-
-				List<Future<String>> results = pool.invokeAll(tasks);
-				for (Future<String> ff : results) {
-					if(StreetsideProperties.DEBUGING_ENABLED.get()) {
-					  logger.debug(MessageFormat.format("Completed tile downloading task {0} in {1} seconds.",ff.get(),
-							(System.currentTimeMillis())/ 1000 - startTime));
-					}
-				}
-			}
-		} catch (Exception ee) {
-			fails++;
-			logger.error("Error loading tile for image " + imageId);
-			ee.printStackTrace();
-		}
-
-		long stopTime = System.currentTimeMillis();
-		long runTime = stopTime - startTime;
-
-		if (StreetsideProperties.DEBUGING_ENABLED.get()) {
-      logger.debug(MessageFormat.format("Tile imagery downloading tasks completed in {0} seconds.",  runTime/1000));
-		}
-
-		if (fails > 0) {
-			logger.error(Integer.valueOf(fails) + " downloading tasks failed!");
-		}
-
-	}
-
-	@Override
-	public void tileAdded(String tileId) {
-		// determine whether all tiles have been set for each of the
-		// six cubemap faces. If so, build the images for the faces
-		// and set the views in the cubemap box.
-
-		int tileCount = 0;
-
-		tileCount = CubemapBuilder.getInstance().getTileImages().keySet().size();
-
-		int maxCols = StreetsideProperties.SHOW_HIGH_RES_STREETSIDE_IMAGERY.get() ? 4 : 2;
-		int maxRows = StreetsideProperties.SHOW_HIGH_RES_STREETSIDE_IMAGERY.get() ? 4 : 2;
-
-		if (tileCount == (CubemapUtils.NUM_SIDES * maxCols * maxRows)) {
-		  if (StreetsideProperties.DEBUGING_ENABLED.get()) {
-        logger.debug(MessageFormat.format("{0} tile images ready for building cumbemap faces for cubemap {1}.", tileCount,
-					CubemapBuilder.getInstance().getCubemap().getId()));
-		  }
-
-			buildCubemapFaces();
-		}
-	}
-
-	@Override
-  public void tilesAdded(String[] tileIds) {
-    // determine whether all tiles have been set for each of the
+    long startTime = System.currentTimeMillis();
+
+    try {
+
+      ExecutorService pool = Executors.newFixedThreadPool(maxThreadCount);
+      List<Callable<List<String>>> tasks = new ArrayList<>(maxThreadCount);
+
+      if (StreetsideProperties.DOWNLOAD_CUBEFACE_TILES_TOGETHER.get()) {
+        EnumSet.allOf(CubemapUtils.CubemapFaces.class).forEach(face -> {
+          String tileId = String.valueOf(imageId + face.getValue());
+          tasks.add(new TileDownloadingTask(tileId));
+        });
+      } else {
+
+        // launch 4-tiled (low-res) downloading tasks . . .
+        if (!StreetsideProperties.SHOW_HIGH_RES_STREETSIDE_IMAGERY.get()) {
+          // download all imagery for each cubeface at once
+
+          for (int i = 0; i < CubemapUtils.NUM_SIDES; i++) {
+            int tileNr = 0;
+            for (int j = 0; j < CubemapUtils.getMaxCols(); j++) {
+              for (int k = 0; k < CubemapUtils.getMaxRows(); k++) {
+
+                String tileId = String
+                  .valueOf(imageId + CubemapUtils.getFaceNumberForCount(i) + Integer.valueOf(tileNr++).toString());
+                tasks.add(new TileDownloadingTask(tileId));
+              }
+            }
+          }
+
+          List<Future<List<String>>> results = pool.invokeAll(tasks);
+          /*for (Future<List<String>> ff : results) {
+
+            if (StreetsideProperties.DEBUGING_ENABLED.get()) {
+              logger.debug(
+                MessageFormat.format(
+                  "Completed tile downloading task {0} in {1} seconds.", ff.get().toString(),
+                  (System.currentTimeMillis()) / 1000 - startTime)
+                );
+            }
+          }*/
+
+          // launch 16-tiled (high-res) downloading tasks
+        } else if (StreetsideProperties.SHOW_HIGH_RES_STREETSIDE_IMAGERY.get()) {
+
+          for (int i = 0; i < CubemapUtils.NUM_SIDES; i++) {
+            for (int j = 0; j < CubemapUtils.getMaxCols(); j++) {
+              for (int k = 0; k < CubemapUtils.getMaxRows(); k++) {
+
+                String tileId = String
+                  .valueOf(imageId + CubemapUtils.getFaceNumberForCount(i) + String.valueOf(Integer.valueOf(j).toString() + Integer.valueOf(k).toString()));
+                tasks.add(new TileDownloadingTask(tileId));
+              }
+            }
+          }
+        }
+      } // finish preparing tasks for invocation
+
+      List<Future<List<String>>> results = pool.invokeAll(tasks);
+      for (Future<List<String>> ff : results) {
+        if (StreetsideProperties.DEBUGING_ENABLED.get()) {
+          logger.debug(
+            MessageFormat.format(
+              "Completed tile downloading task {0} in {1} seconds.", ff.get().toString(),
+              ((System.currentTimeMillis()) - startTime)/1000)
+            );
+        }
+      }
+    } catch (Exception ee) {
+      fails++;
+      logger.error("Error loading tile for image " + imageId);
+      ee.printStackTrace();
+    }
+
+    long stopTime = System.currentTimeMillis();
+    long runTime = stopTime - startTime;
+
+    if (StreetsideProperties.DEBUGING_ENABLED.get()) {
+      logger.debug(MessageFormat.format("Tile imagery downloading tasks completed in {0} seconds.", runTime / 1000));
+    }
+
+    if (fails > 0) {
+      logger.error(Integer.valueOf(fails) + " downloading tasks failed!");
+    }
+  }
+
+  /**
+   * Fired when a TileDownloadingTask has completed downloading an image tile. When all of the tiles for the Cubemap
+   * have been downloaded, the CubemapBuilder assembles the cubemap.
+   *
+   * @param tileId
+   *          the complete quadKey of the imagery tile, including cubeface and row/column in quaternary.
+   * @see TileDownloadingTask
+   */
+  @Override
+  public void tileAdded(String tileId) {
+    // determine whether four tiles have been set for each of the
     // six cubemap faces. If so, build the images for the faces
     // and set the views in the cubemap box.
 
-    int tileCount = 0;
-
-    tileCount = CubemapBuilder.getInstance().getTileImages().keySet().size();
-
-    int maxCols = StreetsideProperties.SHOW_HIGH_RES_STREETSIDE_IMAGERY.get() ? 4 : 2;
-    int maxRows = StreetsideProperties.SHOW_HIGH_RES_STREETSIDE_IMAGERY.get() ? 4 : 2;
-
-    if (tileCount == (CubemapUtils.NUM_SIDES * maxCols * maxRows)) {
+    if(currentTileCount>96) {
+      int x = 0;
+    }
+
+    currentTileCount++;
+
+    if (currentTileCount == (CubemapUtils.NUM_SIDES * CubemapUtils.getMaxCols() * CubemapUtils.getMaxRows())) {
       if (StreetsideProperties.DEBUGING_ENABLED.get()) {
-        logger.debug(MessageFormat.format("{0} tile images ready for building cumbemap faces for cubemap {1}.", tileCount,
-          CubemapBuilder.getInstance().getCubemap().getId()));
+        long endTime = System.currentTimeMillis();
+        long runTime = (endTime - startTime) / 1000;
+        logger.debug(
+          MessageFormat.format(
+            "{0} tile images ready for building cumbemap faces for cubemap {1} in {2} seconds.", currentTileCount,
+            CubemapBuilder.getInstance().getCubemap().getId(), Long.toString(runTime))
+          );
       }
 
@@ -217,15 +239,15 @@
   }
 
-	private void buildCubemapFaces() {
-
-	  if (StreetsideProperties.DEBUGING_ENABLED.get()) {
-      logger.debug("Assembling cubemap tile images");
-	  }
-
-	  CubemapBox cmb = StreetsideViewerDialog.getInstance().getStreetsideViewerPanel().getCubemapBox();
+  /**
+   * Assembles the cubemap once all of the tiles have been downloaded.
+   * <p>
+   * The tiles for each cubemap face are cropped and stitched together
+   * then the ImageViews of the cubemap are set with the new imagery.
+   *
+   * @see         StreetsideCubemap
+   */
+   private void buildCubemapFaces() {
+		CubemapBox cmb = StreetsideViewerDialog.getInstance().getStreetsideViewerPanel().getCubemapBox();
 		ImageView[] views = cmb.getViews();
-
-		final int maxCols = StreetsideProperties.SHOW_HIGH_RES_STREETSIDE_IMAGERY.get() ? 4 : 2;
-		final int maxRows = StreetsideProperties.SHOW_HIGH_RES_STREETSIDE_IMAGERY.get() ? 4 : 2;
 
 		Image finalImages[] = new Image[CubemapUtils.NUM_SIDES];
@@ -235,7 +257,7 @@
 			for (int i = 0; i < CubemapUtils.NUM_SIDES; i++) {
 
-				BufferedImage[] faceTileImages = new BufferedImage[maxCols * maxRows];
-
-				for (int j = 0; j < (maxCols * maxRows); j++) {
+				BufferedImage[] faceTileImages = new BufferedImage[CubemapUtils.getMaxCols() * CubemapUtils.getMaxRows()];
+
+				for (int j = 0; j < (CubemapUtils.getMaxCols() * CubemapUtils.getMaxRows()); j++) {
 					String tileId = String.valueOf(getCubemap().getId() + CubemapUtils.getFaceNumberForCount(i)
 							+ Integer.valueOf(j).toString());
@@ -262,6 +284,6 @@
 						.get() ? 16 : 4];
 
-				for (int j = 0; j < maxCols; j++) {
-					for (int k = 0; k < maxRows; k++) {
+				for (int j = 0; j < CubemapUtils.getMaxCols(); j++) {
+					for (int k = 0; k < CubemapUtils.getMaxRows(); k++) {
 						String tileId = String.valueOf(getCubemap().getId() + CubemapUtils.getFaceNumberForCount(i)
 								+ CubemapUtils.convertDoubleCountNrto16TileNr(
@@ -303,5 +325,7 @@
     }
 
-    CubemapBuilder.getInstance().resetTileImages();
+    // reset count and image map after assembly
+    resetTileImages();
+    currentTileCount = 0;
 	}
 
Index: applications/editors/josm/plugins/MicrosoftStreetside/src/org/openstreetmap/josm/plugins/streetside/cubemap/CubemapUtils.java
===================================================================
--- applications/editors/josm/plugins/MicrosoftStreetside/src/org/openstreetmap/josm/plugins/streetside/cubemap/CubemapUtils.java	(revision 34427)
+++ applications/editors/josm/plugins/MicrosoftStreetside/src/org/openstreetmap/josm/plugins/streetside/cubemap/CubemapUtils.java	(revision 34428)
@@ -14,4 +14,7 @@
   final static Logger logger = Logger.getLogger(CubemapUtils.class);
 
+  private CubemapUtils() {
+    // Private constructor to avoid instantiation
+  }
 
 	public enum CubefaceType {
@@ -71,5 +74,4 @@
 	public static final String IMPORTED_ID = "00000000";
 	public static final int NUM_SIDES = 6;
-
 	public static Map<String,String> rowCol2StreetsideCellAddressMap = null;
 
@@ -96,4 +98,12 @@
 	}
 
+	public static int getMaxCols() {
+	  return StreetsideProperties.SHOW_HIGH_RES_STREETSIDE_IMAGERY.get()?4:2;
+	}
+
+	public static int getMaxRows() {
+	  return getMaxCols();
+	}
+
 	public static String convertDecimal2Quaternary(long inputNum) {
 		String res = null;
Index: applications/editors/josm/plugins/MicrosoftStreetside/src/org/openstreetmap/josm/plugins/streetside/cubemap/ITileDownloadingTaskListener.java
===================================================================
--- applications/editors/josm/plugins/MicrosoftStreetside/src/org/openstreetmap/josm/plugins/streetside/cubemap/ITileDownloadingTaskListener.java	(revision 34427)
+++ applications/editors/josm/plugins/MicrosoftStreetside/src/org/openstreetmap/josm/plugins/streetside/cubemap/ITileDownloadingTaskListener.java	(revision 34428)
@@ -16,8 +16,3 @@
  void tileAdded(String imageId);
 
- /**
-  * Fired when multiple cubemap tile images are downloaded by a download worker.
-  * @param imageId image id
-  */
-  void tilesAdded(String[] imageId);
 }
Index: applications/editors/josm/plugins/MicrosoftStreetside/src/org/openstreetmap/josm/plugins/streetside/cubemap/TileDownloadingTask.java
===================================================================
--- applications/editors/josm/plugins/MicrosoftStreetside/src/org/openstreetmap/josm/plugins/streetside/cubemap/TileDownloadingTask.java	(revision 34427)
+++ applications/editors/josm/plugins/MicrosoftStreetside/src/org/openstreetmap/josm/plugins/streetside/cubemap/TileDownloadingTask.java	(revision 34428)
@@ -3,5 +3,7 @@
 
 import java.awt.image.BufferedImage;
+import java.io.IOException;
 import java.text.MessageFormat;
+import java.util.ArrayList;
 import java.util.List;
 import java.util.Objects;
@@ -18,10 +20,9 @@
 import us.monoid.web.Resty;
 
-public class TileDownloadingTask implements Callable<String> {
+public class TileDownloadingTask implements Callable<List<String>> {
 
   final static Logger logger = Logger.getLogger(TileDownloadingTask.class);
 
 	private String tileId;
-	private final long startTime = System.currentTimeMillis();
 	private StreetsideCache cache;
 	protected CubemapBuilder cb;
@@ -98,27 +99,65 @@
 	}
 
-	@Override
-	public String call() throws Exception {
+  @Override
+  public List<String> call() throws Exception {
 
-	  BufferedImage img = ImageIO.read(new Resty().bytes(
-				StreetsideURL.VirtualEarth.streetsideTile(tileId, false).toExternalForm())
-				.stream());
+    List<String> res = new ArrayList<>();
 
-		if (img == null) {
-			logger.error("Download of BufferedImage " + tileId + " is null!");
-		}
+    if (StreetsideProperties.DOWNLOAD_CUBEFACE_TILES_TOGETHER.get()) {
+      // download all imagery for each cubeface at once
+      if (!StreetsideProperties.SHOW_HIGH_RES_STREETSIDE_IMAGERY.get()) {
+        // download low-res imagery
+        int tileNr = 0;
+        for (int j = 0; j < CubemapUtils.getMaxCols(); j++) {
+          for (int k = 0; k < CubemapUtils.getMaxRows(); k++) {
+            String quadKey = String.valueOf(tileId + Integer.valueOf(tileNr++).toString());
+            res.add(downloadTile(quadKey));
+          }
+        }
+        // download high-res imagery
+      } else {
+        for (int j = 0; j < CubemapUtils.getMaxCols(); j++) {
+          for (int k = 0; k < CubemapUtils.getMaxRows(); k++) {
+            String quadKey = String
+              .valueOf(tileId + String.valueOf(Integer.valueOf(j).toString() + Integer.valueOf(k).toString()));
+            res.add(downloadTile(quadKey));
+          }
+        }
+      }
+    // task downloads just one tile
+    } else {
+      res.add(downloadTile(tileId));
+    }
+    return res;
+  }
 
-		CubemapBuilder.getInstance().getTileImages().put(tileId, img);
+  private String downloadTile(String tileId) {
+    BufferedImage img;
 
-		fireTileAdded(tileId);
+    long startTime = System.currentTimeMillis();
 
-		if (StreetsideProperties.DEBUGING_ENABLED.get()) {
-		  long endTime = System.currentTimeMillis();
-	    long runTime = (endTime-startTime)/1000;
-	    logger.debug(MessageFormat.format("Loaded image for {0} in {1} seconds.", tileId, runTime));
-		}
+    try {
+      img = ImageIO
+        .read(new Resty().bytes(StreetsideURL.VirtualEarth.streetsideTile(tileId, false).toExternalForm()).stream());
 
-		return tileId;
-	}
+      if (img == null) {
+        logger.error("Download of BufferedImage " + tileId + " is null!");
+      }
+
+      CubemapBuilder.getInstance().getTileImages().put(tileId, img);
+
+      fireTileAdded(tileId);
+
+      if (StreetsideProperties.DEBUGING_ENABLED.get()) {
+        long endTime = System.currentTimeMillis();
+        long runTime = (endTime - startTime) / 1000;
+        logger.debug(MessageFormat.format("Loaded image for {0} in {1} seconds.", tileId, runTime));
+      }
+    } catch (IOException e) {
+      logger.error(MessageFormat.format("Error downloading image for tileId {0}", tileId));
+      return null;
+    }
+    return tileId;
+  }
 
 	private void fireTileAdded(String id) {
Index: applications/editors/josm/plugins/MicrosoftStreetside/src/org/openstreetmap/josm/plugins/streetside/gui/StreetsideMainDialog.java
===================================================================
--- applications/editors/josm/plugins/MicrosoftStreetside/src/org/openstreetmap/josm/plugins/streetside/gui/StreetsideMainDialog.java	(revision 34427)
+++ applications/editors/josm/plugins/MicrosoftStreetside/src/org/openstreetmap/josm/plugins/streetside/gui/StreetsideMainDialog.java	(revision 34428)
@@ -57,19 +57,4 @@
 	private volatile StreetsideAbstractImage image;
 
-	/*public final SideButton nextButton = new SideButton(new NextPictureAction());
-	public final SideButton previousButton = new SideButton(new PreviousPictureAction());
-	*//**
-	 * Button used to jump to the image following the red line
-	 *//*
-	public final SideButton redButton = new SideButton(new RedAction());
-	*//**
-	 * Button used to jump to the image following the blue line
-	 *//*
-	public final SideButton blueButton = new SideButton(new BlueAction());
-
-	private final SideButton playButton = new SideButton(new PlayAction());
-	private final SideButton pauseButton = new SideButton(new PauseAction());
-	private final SideButton stopButton = new SideButton(new StopAction());*/
-
 	private ImageInfoHelpPopup imageInfoHelp;
 
@@ -107,7 +92,4 @@
 		streetsideImageDisplay = new StreetsideImageDisplay();
 
-		/*blueButton.setForeground(Color.BLUE);
-		redButton.setForeground(Color.RED);*/
-
 		setMode(MODE.NORMAL);
 	}
@@ -117,17 +99,5 @@
 	 */
 	private void addShortcuts() {
-		/*nextButton.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
-				KeyStroke.getKeyStroke("PAGE_DOWN"), "next");
-		nextButton.getActionMap().put("next", new NextPictureAction());
-		previousButton.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
-				KeyStroke.getKeyStroke("PAGE_UP"), "previous");
-		previousButton.getActionMap().put("previous",
-				new PreviousPictureAction());
-		blueButton.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
-				KeyStroke.getKeyStroke("control PAGE_UP"), "blue");
-		blueButton.getActionMap().put("blue", new BlueAction());
-		redButton.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
-				KeyStroke.getKeyStroke("control PAGE_DOWN"), "red");
-		redButton.getActionMap().put("red", new RedAction());*/
+		// next, previous, blueAction and redAction from Mapillary removed
 	}
 
@@ -176,5 +146,6 @@
 			createLayout(
 				streetsideImageDisplay,
-				null//Arrays.asList(playButton, pauseButton, stopButton)
+				null
+				// TODO: Walk Action for Streetside - re-add buttons here
 			);
 		case NORMAL:
@@ -182,8 +153,8 @@
 			createLayout(
 		        streetsideImageDisplay,
-		        null//Arrays.asList(blueButton, previousButton, nextButton, redButton)
+		        null
 		    );
 		}
-		//disableAllButtons();
+
 		if (MODE.NORMAL.equals(mode)) {
 			updateImage();
@@ -222,9 +193,7 @@
 				streetsideImageDisplay.setImage(null, null);
 				setTitle(I18n.tr(StreetsideMainDialog.BASE_TITLE));
-				//disableAllButtons();
 				return;
 			}
 
-			// TODO: help for cubemaps? @rrh
 			if (imageInfoHelp != null && StreetsideProperties.IMAGEINFO_HELP_COUNTDOWN.get() > 0 && imageInfoHelp.showPopup()) {
 				// Count down the number of times the popup will be displayed
@@ -232,7 +201,4 @@
 			}
 
-			// Enables/disables next/previous buttons
-			/*nextButton.setEnabled(false);
-			previousButton.setEnabled(false);*/
 			if (image.getSequence() != null) {
 				StreetsideAbstractImage tempImage = image;
@@ -250,5 +216,4 @@
 					tempImage = tempImage.previous();
 					if (tempImage.isVisible()) {
-						//previousButton.setEnabled(true);
 						break;
 					}
@@ -290,14 +255,4 @@
 
 	/**
-	 * Disables all the buttons in the dialog
-	 */
-	/*public private void disableAllButtons() {
-		nextButton.setEnabled(false);
-		previousButton.setEnabled(false);
-		blueButton.setEnabled(false);
-		redButton.setEnabled(false);
-	}*/
-
-	/**
 	 * Sets a new StreetsideImage to be shown.
 	 *
@@ -407,5 +362,4 @@
 		}
 
-		// TODO: RedAction for cubemaps? @rrh
 		@Override
 		public void actionPerformed(ActionEvent e) {
@@ -553,8 +507,6 @@
 						|| img.getHeight() > streetsideImageDisplay.getImage().getHeight()
 						) {
-					//final StreetsideAbstractImage mai = getImage();
 					streetsideImageDisplay.setImage(
 							img,
-							//mai instanceof StreetsideImage ? ((StreetsideImage) getImage()).getDetections() : null
 							null);
 				}
Index: applications/editors/josm/plugins/MicrosoftStreetside/src/org/openstreetmap/josm/plugins/streetside/gui/imageinfo/StreetsideViewerPanel.java
===================================================================
--- applications/editors/josm/plugins/MicrosoftStreetside/src/org/openstreetmap/josm/plugins/streetside/gui/imageinfo/StreetsideViewerPanel.java	(revision 34427)
+++ applications/editors/josm/plugins/MicrosoftStreetside/src/org/openstreetmap/josm/plugins/streetside/gui/imageinfo/StreetsideViewerPanel.java	(revision 34428)
@@ -18,6 +18,6 @@
 import org.openstreetmap.josm.plugins.streetside.cubemap.CubemapBuilder;
 import org.openstreetmap.josm.plugins.streetside.cubemap.CubemapUtils;
-import org.openstreetmap.josm.plugins.streetside.cubemap.GraphicsUtils;
 import org.openstreetmap.josm.plugins.streetside.gui.boilerplate.StreetsideButton;
+import org.openstreetmap.josm.plugins.streetside.utils.GraphicsUtils;
 import org.openstreetmap.josm.plugins.streetside.utils.StreetsideProperties;
 import org.openstreetmap.josm.plugins.streetside.utils.StreetsideURL;
Index: applications/editors/josm/plugins/MicrosoftStreetside/src/org/openstreetmap/josm/plugins/streetside/io/download/BoundsDownloadRunnable.java
===================================================================
--- applications/editors/josm/plugins/MicrosoftStreetside/src/org/openstreetmap/josm/plugins/streetside/io/download/BoundsDownloadRunnable.java	(revision 34427)
+++ applications/editors/josm/plugins/MicrosoftStreetside/src/org/openstreetmap/josm/plugins/streetside/io/download/BoundsDownloadRunnable.java	(revision 34428)
@@ -59,5 +59,5 @@
 
   /**
-   * Logs information about the given connection via {@link logger#info(String)}.
+   * Logs information about the given connection via {@link Logger}.
    * If it's a {@link HttpURLConnection}, the request method, the response code and the URL itself are logged.
    * Otherwise only the URL is logged.
Index: applications/editors/josm/plugins/MicrosoftStreetside/src/org/openstreetmap/josm/plugins/streetside/io/download/SequenceDownloadRunnable.java
===================================================================
--- applications/editors/josm/plugins/MicrosoftStreetside/src/org/openstreetmap/josm/plugins/streetside/io/download/SequenceDownloadRunnable.java	(revision 34427)
+++ applications/editors/josm/plugins/MicrosoftStreetside/src/org/openstreetmap/josm/plugins/streetside/io/download/SequenceDownloadRunnable.java	(revision 34428)
@@ -6,4 +6,5 @@
 import java.net.URL;
 import java.net.URLConnection;
+import java.text.MessageFormat;
 import java.util.ArrayList;
 import java.util.EnumSet;
@@ -128,9 +129,9 @@
 
     } catch (JsonParseException e) {
-      e.printStackTrace();
+      logger.error(MessageFormat.format("JSON parsing error occured during Streetside sequence download {0}",e.getMessage()));
     } catch (JsonMappingException e) {
-      e.printStackTrace();
+      logger.error(MessageFormat.format("JSON mapping error occured during Streetside sequence download {0}",e.getMessage()));
     } catch (IOException e) {
-      e.printStackTrace();
+      logger.error(MessageFormat.format("Input/output error occured during Streetside sequence download {0}",e.getMessage()));
     }
 
Index: applications/editors/josm/plugins/MicrosoftStreetside/src/org/openstreetmap/josm/plugins/streetside/mode/package-info.java
===================================================================
--- applications/editors/josm/plugins/MicrosoftStreetside/src/org/openstreetmap/josm/plugins/streetside/mode/package-info.java	(revision 34427)
+++ applications/editors/josm/plugins/MicrosoftStreetside/src/org/openstreetmap/josm/plugins/streetside/mode/package-info.java	(revision 34428)
@@ -5,5 +5,4 @@
  * Currently there are two of them:
  * <ul>
- *  <li><strong>{@link org.openstreetmap.josm.plugins.streetside.mode.JoinMode JoinMode}</strong> for joining pictures to make sequences</li>
  *  <li><strong>{@link org.openstreetmap.josm.plugins.streetside.mode.SelectMode SelectMode}</strong> for selecting pictures in the layer</li>
  * </ul>
Index: applications/editors/josm/plugins/MicrosoftStreetside/src/org/openstreetmap/josm/plugins/streetside/utils/StreetsideProperties.java
===================================================================
--- applications/editors/josm/plugins/MicrosoftStreetside/src/org/openstreetmap/josm/plugins/streetside/utils/StreetsideProperties.java	(revision 34427)
+++ applications/editors/josm/plugins/MicrosoftStreetside/src/org/openstreetmap/josm/plugins/streetside/utils/StreetsideProperties.java	(revision 34428)
@@ -24,5 +24,7 @@
   public static final IntegerProperty TILE_DOWNLOAD_THREAD_PAUSE_LEN_SEC = new IntegerProperty("streetside.tile-download-thread-pause-len-sec", 60);
   public static final BooleanProperty PREDOWNLOAD_CUBEMAPS = new BooleanProperty("streetside.predownload-cubemaps", false);
-  public static final BooleanProperty DEBUGING_ENABLED = new BooleanProperty("streetside.debugging-enabled", false);
+  public static final BooleanProperty DEBUGING_ENABLED = new BooleanProperty("streetside.debugging-enabled", true);
+  public static final BooleanProperty DOWNLOAD_CUBEFACE_TILES_TOGETHER = new BooleanProperty("streetside.download-cubeface-tiles-together", false);
+
   /**
    * If false, all sequences that cross the download bounds are put completely into the StreetsideData object.
Index: applications/editors/josm/plugins/MicrosoftStreetside/src/org/openstreetmap/josm/plugins/streetside/utils/StreetsideSequenceIdGenerator.java
===================================================================
--- applications/editors/josm/plugins/MicrosoftStreetside/src/org/openstreetmap/josm/plugins/streetside/utils/StreetsideSequenceIdGenerator.java	(revision 34427)
+++ applications/editors/josm/plugins/MicrosoftStreetside/src/org/openstreetmap/josm/plugins/streetside/utils/StreetsideSequenceIdGenerator.java	(revision 34428)
@@ -5,12 +5,20 @@
 
 /**
- * 
+ * Utility class to generated unique ids for Streetside "sequences".
+ * Due to the functionality inherited from Mapillary the plugin is structured to
+ * handle sequences of contiguous imagery, but Streetside only has implicit
+ * sequences defined by the "pre" and "ne" attributes.
+ * <p/>
+ * @See StreetsideSequence
  */
 public class StreetsideSequenceIdGenerator {
-  
+
+  private StreetsideSequenceIdGenerator() {
+    // private constructor to avoid instantiation
+  }
   public static String generateId() {
-    
+
     return UUID.randomUUID().toString();
-    
+
   }
 
Index: applications/editors/josm/plugins/MicrosoftStreetside/src/org/openstreetmap/josm/plugins/streetside/utils/StreetsideURL.java
===================================================================
--- applications/editors/josm/plugins/MicrosoftStreetside/src/org/openstreetmap/josm/plugins/streetside/utils/StreetsideURL.java	(revision 34427)
+++ applications/editors/josm/plugins/MicrosoftStreetside/src/org/openstreetmap/josm/plugins/streetside/utils/StreetsideURL.java	(revision 34428)
@@ -324,5 +324,5 @@
 	/**
 	 * Converts a {@link String} into a {@link URL} without throwing a {@link MalformedURLException}.
-	 * Instead such an exception will lead to an {@link logger#error(Throwable)}.
+	 * Instead such an exception will lead to an {@link Logger}.
 	 * So you should be very confident that your URL is well-formed when calling this method.
 	 * @param strings the Strings describing the URL
Index: applications/editors/josm/plugins/MicrosoftStreetside/src/org/openstreetmap/josm/plugins/streetside/utils/api/JsonDecoder.java
===================================================================
--- applications/editors/josm/plugins/MicrosoftStreetside/src/org/openstreetmap/josm/plugins/streetside/utils/api/JsonDecoder.java	(revision 34427)
+++ applications/editors/josm/plugins/MicrosoftStreetside/src/org/openstreetmap/josm/plugins/streetside/utils/api/JsonDecoder.java	(revision 34428)
@@ -96,5 +96,5 @@
    * @return the point in time as a {@link Long} value representing the UNIX epoch time, or <code>null</code> if the
    *   parameter does not match the required format (this also triggers a warning via
-   *   {@link logger#warn(Throwable)}), or the parameter is <code>null</code>.
+   *   {@link Logger}, or the parameter is <code>null</code>).
    */
   static Long decodeTimestamp(final String timestamp) {
Index: applications/editors/josm/plugins/MicrosoftStreetside/src/org/openstreetmap/josm/plugins/streetside/utils/api/JsonStreetsideDecoder.java
===================================================================
--- applications/editors/josm/plugins/MicrosoftStreetside/src/org/openstreetmap/josm/plugins/streetside/utils/api/JsonStreetsideDecoder.java	(revision 34427)
+++ applications/editors/josm/plugins/MicrosoftStreetside/src/org/openstreetmap/josm/plugins/streetside/utils/api/JsonStreetsideDecoder.java	(revision 34428)
@@ -96,5 +96,5 @@
    * @return the point in time as a {@link Long} value representing the UNIX epoch time, or <code>null</code> if the
    *   parameter does not match the required format (this also triggers a warning via
-   *   {@link logger#warn(Throwable)}), or the parameter is <code>null</code>.
+   *   {@link Logger}, or the parameter is <code>null</code>).
    */
   static Long decodeTimestamp(final String timestamp) {
Index: applications/editors/josm/plugins/MicrosoftStreetside/test/unit/org/openstreetmap/josm/plugins/streetside/StreetsideAbstractImageTest.java
===================================================================
--- applications/editors/josm/plugins/MicrosoftStreetside/test/unit/org/openstreetmap/josm/plugins/streetside/StreetsideAbstractImageTest.java	(revision 34427)
+++ applications/editors/josm/plugins/MicrosoftStreetside/test/unit/org/openstreetmap/josm/plugins/streetside/StreetsideAbstractImageTest.java	(revision 34428)
@@ -13,6 +13,6 @@
 public class StreetsideAbstractImageTest {
 
-  @Rule
-  public JOSMTestRules rules = new StreetsideTestRules().platform();
+  /*@Rule
+  public JOSMTestRules rules = new StreetsideTestRules().platform();*/
 
   @Test
Index: applications/editors/josm/plugins/MicrosoftStreetside/test/unit/org/openstreetmap/josm/plugins/streetside/StreetsideDataTest.java
===================================================================
--- applications/editors/josm/plugins/MicrosoftStreetside/test/unit/org/openstreetmap/josm/plugins/streetside/StreetsideDataTest.java	(revision 34427)
+++ applications/editors/josm/plugins/MicrosoftStreetside/test/unit/org/openstreetmap/josm/plugins/streetside/StreetsideDataTest.java	(revision 34428)
@@ -25,6 +25,6 @@
 public class StreetsideDataTest {
 
-  @Rule
-  public JOSMTestRules rules = new StreetsideTestRules().platform();
+  /*@Rule
+  public JOSMTestRules rules = new StreetsideTestRules().platform();*/
 
   private StreetsideData data;
@@ -96,5 +96,4 @@
    * Tests the selection of images.
    */
-  @Ignore
   @Test
   public void selectTest() {
@@ -113,5 +112,4 @@
    * {@link StreetsideData#selectPrevious()} methods.
    */
-  @Ignore
   @Test
   public void nextAndPreviousTest() {
@@ -128,5 +126,4 @@
   }
 
-  @Ignore
   @Test(expected=IllegalStateException.class)
   public void nextOfNullImgTest() {
@@ -135,5 +132,4 @@
   }
 
-  @Ignore
   @Test(expected=IllegalStateException.class)
   public void previousOfNullImgTest() {
@@ -146,5 +142,4 @@
    * multiselected List should reset.
    */
-  @Ignore
   @Test
   public void multiSelectTest() {
Index: applications/editors/josm/plugins/MicrosoftStreetside/test/unit/org/openstreetmap/josm/plugins/streetside/StreetsideLayerTest.java
===================================================================
--- applications/editors/josm/plugins/MicrosoftStreetside/test/unit/org/openstreetmap/josm/plugins/streetside/StreetsideLayerTest.java	(revision 34427)
+++ applications/editors/josm/plugins/MicrosoftStreetside/test/unit/org/openstreetmap/josm/plugins/streetside/StreetsideLayerTest.java	(revision 34428)
@@ -73,5 +73,4 @@
   }
 
-  @Ignore
   @Test
   public void testClearInstance() {
Index: applications/editors/josm/plugins/MicrosoftStreetside/test/unit/org/openstreetmap/josm/plugins/streetside/cubemap/GraphicsUtilsTest.java
===================================================================
--- applications/editors/josm/plugins/MicrosoftStreetside/test/unit/org/openstreetmap/josm/plugins/streetside/cubemap/GraphicsUtilsTest.java	(revision 34427)
+++ applications/editors/josm/plugins/MicrosoftStreetside/test/unit/org/openstreetmap/josm/plugins/streetside/cubemap/GraphicsUtilsTest.java	(revision 34428)
@@ -48,5 +48,5 @@
 
   /**
-   * Test method for {@link org.openstreetmap.josm.plugins.streetside.cubemap.GraphicsUtils#convertBufferedImage2JavaFXImage(java.awt.image.BufferedImage)}.
+   * Test method for {@link org.openstreetmap.josm.plugins.streetside.utils.GraphicsUtils#convertBufferedImage2JavaFXImage(java.awt.image.BufferedImage)}.
    */
   @Ignore
@@ -57,5 +57,5 @@
 
   /**
-   * Test method for {@link org.openstreetmap.josm.plugins.streetside.cubemap.GraphicsUtils#buildMultiTiledCubemapFaceImage(java.awt.image.BufferedImage[])}.
+   * Test method for {@link org.openstreetmap.josm.plugins.streetside.utils.GraphicsUtils#buildMultiTiledCubemapFaceImage(java.awt.image.BufferedImage[])}.
    */
   @Ignore
@@ -66,5 +66,5 @@
 
   /**
-   * Test method for {@link org.openstreetmap.josm.plugins.streetside.cubemap.GraphicsUtils#rotateImage(java.awt.image.BufferedImage)}.
+   * Test method for {@link org.openstreetmap.josm.plugins.streetside.utils.GraphicsUtils#rotateImage(java.awt.image.BufferedImage)}.
    */
   @Ignore
Index: applications/editors/josm/plugins/MicrosoftStreetside/test/unit/org/openstreetmap/josm/plugins/streetside/cubemap/TileDownloadingTaskTest.java
===================================================================
--- applications/editors/josm/plugins/MicrosoftStreetside/test/unit/org/openstreetmap/josm/plugins/streetside/cubemap/TileDownloadingTaskTest.java	(revision 34427)
+++ applications/editors/josm/plugins/MicrosoftStreetside/test/unit/org/openstreetmap/josm/plugins/streetside/cubemap/TileDownloadingTaskTest.java	(revision 34428)
@@ -21,8 +21,8 @@
   public final void testCall() {
     ExecutorService pool = Executors.newFixedThreadPool(1);
-    List<Callable<String>> tasks = new ArrayList<>(1);
+    List<Callable<List<String>>> tasks = new ArrayList<>(1);
       tasks.add(new TileDownloadingTask("2202112030033001233"));
       try {
-        List<Future<String>> results = pool.invokeAll(tasks);
+        List<Future<List<String>>> results = pool.invokeAll(tasks);
         assertEquals(results.get(0),"2202112030033001233");
       } catch (InterruptedException e) {
