Index: /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/MapillaryData.java
===================================================================
--- /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/MapillaryData.java	(revision 31158)
+++ /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/MapillaryData.java	(revision 31158)
@@ -0,0 +1,180 @@
+package org.openstreetmap.josm.plugins.mapillary;
+
+import org.openstreetmap.josm.Main;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+/**
+ * Database class for all the MapillaryImage objects.
+ * 
+ * @author nokutu
+ *
+ */
+public class MapillaryData {
+	public volatile static MapillaryData INSTANCE;
+	
+	private final List<MapillaryImage> images;
+	private MapillaryImage selectedImage = null;
+	private List<MapillaryImage> multiSelectedImages;
+
+
+	public MapillaryData() {
+		images = new CopyOnWriteArrayList<>();
+		multiSelectedImages = new ArrayList<>();
+	}
+
+	public static MapillaryData getInstance() {
+		if (INSTANCE == null) {
+			INSTANCE = new MapillaryData();
+		}
+		return INSTANCE;
+	}
+
+	public static void deleteInstance() {
+		INSTANCE = null;
+	}
+
+	public MapillaryData(List<MapillaryImage> images) {
+		this.images = images;
+	}
+
+	/**
+	 * Adds a set of MapillaryImages to the object, and then repaints mapView.
+	 * 
+	 * @param images
+	 *            The set of images to be added.
+	 */
+	public synchronized void add(List<MapillaryImage> images) {
+		for (MapillaryImage image : images) {
+			add(image);
+		}
+	}
+
+	/**
+	 * Adds an MapillaryImage to the object, and then repaints mapView.
+	 * 
+	 * @param image
+	 *            The image to be added.
+	 */
+	public synchronized void add(MapillaryImage image) {
+		if (!images.contains(image)) {
+			this.images.add(image);
+		}
+		dataUpdated();
+	}
+
+	/**
+	 * Adds a set of MapillaryImages to the object, but doesn't repaint mapView.
+	 * This is needed for concurrency.
+	 * 
+	 * @param images
+	 *            The set of images to be added.
+	 */
+	public synchronized void addWithoutUpdate(List<MapillaryImage> images) {
+		for (MapillaryImage image : images) {
+			addWithoutUpdate(image);
+		}
+	}
+
+	/**
+	 * Adds a MapillaryImage to the object, but doesn't repaint mapView. This is
+	 * needed for concurrency.
+	 * 
+	 * @param image
+	 *            The image to be added.
+	 */
+	public synchronized void addWithoutUpdate(MapillaryImage image) {
+		if (!images.contains(image)) {
+			this.images.add(image);
+		}
+	}
+
+	/**
+	 * Repaints mapView object.
+	 */
+	public synchronized void dataUpdated() {
+		Main.map.mapView.repaint();
+	}
+
+	/**
+	 * Returns a List containing all images.
+	 * 
+	 * @return A List object containing all images.
+	 */
+	public List<MapillaryImage> getImages() {
+		return images;
+	}
+
+	/**
+	 * Returns the MapillaryImage object that is currently selected.
+	 * 
+	 * @return The selected MapillaryImage object.
+	 */
+	public MapillaryImage getSelectedImage() {
+		return selectedImage;
+	}
+
+	/**
+	 * If the selected MapillaryImage is part of a MapillarySequence then the
+	 * following MapillaryImage is selected. In case there is none, does
+	 * nothing.
+	 */
+	public void selectNext() {
+		if (getSelectedImage() == null)
+			return;
+		if (getSelectedImage().getSequence() == null)
+			throw new IllegalStateException();
+		if (getSelectedImage().next() != null)
+			setSelectedImage(getSelectedImage().next());
+	}
+
+	/**
+	 * If the selected MapillaryImage is part of a MapillarySequence then the
+	 * previous MapillaryImage is selected. In case there is none, does nothing.
+	 */
+	public void selectPrevious() {
+		if (getSelectedImage() == null)
+			return;
+		if (getSelectedImage().getSequence() == null)
+			throw new IllegalStateException();
+		if (getSelectedImage().previous() != null)
+			setSelectedImage(getSelectedImage().previous());
+	}
+
+	/**
+	 * Selects a new image and then starts a new MapillaryImageDownloadThread
+	 * thread in order to download its surrounding thumbnails and images.
+	 * 
+	 * @param image
+	 *            The MapillaryImage which is going to be selected
+	 * @param clearThumbnail
+	 *            Whether if the old selected MapillaryImage's thumbnail should
+	 *            be deleted or not.
+	 * @param clearImageWhether
+	 *            if the old selected MapillaryImage's full resolution image
+	 *            should be deleted or not.
+	 */
+	public void setSelectedImage(MapillaryImage image) {
+		selectedImage = image;
+		multiSelectedImages.clear();
+		multiSelectedImages.add(image);
+		if (image != null) {
+			MapillaryToggleDialog.getInstance().setImage(selectedImage);
+			MapillaryToggleDialog.getInstance().updateImage();
+		}
+		if (Main.map != null) {
+			Main.map.mapView.repaint();
+		}
+	}
+	
+	public void addMultiSelectedImage(MapillaryImage image) {
+		this.multiSelectedImages.add(image);
+		Main.map.mapView.repaint();
+	}
+	
+	public List<MapillaryImage> getMultiSelectedImages(){
+		return multiSelectedImages;
+	}
+}
Index: /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/MapillaryDownloadAction.java
===================================================================
--- /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/MapillaryDownloadAction.java	(revision 31158)
+++ /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/MapillaryDownloadAction.java	(revision 31158)
@@ -0,0 +1,67 @@
+/**
+ *
+ */
+package org.openstreetmap.josm.plugins.mapillary;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.KeyEvent;
+
+import org.openstreetmap.josm.gui.layer.Layer;
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.actions.JosmAction;
+import org.openstreetmap.josm.tools.Shortcut;
+
+/**
+ * Action that triggers the plugin.
+ * 
+ * @author nokutu
+ *
+ */
+public class MapillaryDownloadAction extends JosmAction {
+	MapillaryLayer layer;
+
+	public MapillaryDownloadAction() {
+		super(tr("Mapillary"), "icon16.png",
+				tr("Create Mapillary layer."), Shortcut.registerShortcut(
+						"menu:Mapillary", tr("Menu: {0}", tr("Mapillary")),
+						KeyEvent.VK_M, Shortcut.ALT_SHIFT), false);
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see
+	 * java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
+	 */
+	@Override
+	public void actionPerformed(ActionEvent arg0) {
+		this.layer = null;
+		if (Main.map == null) {
+			return;
+		}
+		for (Layer layer : Main.map.mapView.getAllLayers()) {
+			if (layer instanceof MapillaryLayer) {
+				System.out.println("Tuturu");
+				this.layer = (MapillaryLayer) layer;
+			}
+		}
+
+		if (this.layer == null)
+			layer = new MapillaryLayer();
+		else
+			this.layer.download();
+		/*
+		 * MapillaryDialog dialog = new MapillaryDialog(); JOptionPane pane =
+		 * new JOptionPane(dialog, JOptionPane.PLAIN_MESSAGE,
+		 * JOptionPane.OK_CANCEL_OPTION); JDialog dlg =
+		 * pane.createDialog(Main.parent, tr("Export"));
+		 * dialog.setOptionPane(pane); dlg.setVisible(true);
+		 * if(((Integer)pane.getValue()) == JOptionPane.OK_OPTION){ //
+		 * MapillaryTask task = new MapillaryTask(); //
+		 * Main.worker.execute(task); } dlg.dispose();
+		 */
+	}
+
+}
Index: /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/MapillaryExportAction.java
===================================================================
--- /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/MapillaryExportAction.java	(revision 31158)
+++ /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/MapillaryExportAction.java	(revision 31158)
@@ -0,0 +1,63 @@
+package org.openstreetmap.josm.plugins.mapillary;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.Dimension;
+import java.awt.event.ActionEvent;
+import java.util.List;
+
+import javax.swing.JDialog;
+import javax.swing.JOptionPane;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.actions.JosmAction;
+import org.openstreetmap.josm.plugins.mapillary.downloads.MapillaryExportManager;
+
+/**
+ * Action that launches a MapillaryExportDialog.
+ * 
+ * @author nokutu
+ *
+ */
+public class MapillaryExportAction extends JosmAction {
+
+	MapillaryExportDialog dialog;
+
+	public MapillaryExportAction() {
+		super(tr("Export images"), "icon24.png", tr("Export images."),
+				null, false);
+	}
+
+	@Override
+	public void actionPerformed(ActionEvent e) {
+		dialog = new MapillaryExportDialog();
+		JOptionPane pane = new JOptionPane(dialog, JOptionPane.PLAIN_MESSAGE,
+				JOptionPane.OK_CANCEL_OPTION);
+		JDialog dlg = pane.createDialog(Main.parent, tr("Export images"));
+		dlg.setMinimumSize(new Dimension(400, 150));
+		dlg.setVisible(true);
+
+		if (pane.getValue() != null
+				&& (int) pane.getValue() == JOptionPane.OK_OPTION) {
+			if (dialog.group.isSelected(dialog.all.getModel())) {
+				export(MapillaryData.getInstance().getImages());
+			} else if (dialog.group.isSelected(dialog.sequence.getModel())) {
+				export(MapillaryData.getInstance().getSelectedImage()
+						.getSequence().getImages());
+			} else if (dialog.group.isSelected(dialog.selected.getModel())) {
+				export(MapillaryData.getInstance().getMultiSelectedImages());
+			}
+		}
+
+		dlg.dispose();
+	}
+
+	/**
+	 * Exports the given images from the database
+	 */
+	public void export(List<MapillaryImage> images) {
+		Main.worker.submit(new MapillaryExportManager(tr("Downloading..."),
+				images, dialog.chooser.getSelectedFile().toString()));
+	}
+
+}
Index: /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/MapillaryExportDialog.java
===================================================================
--- /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/MapillaryExportDialog.java	(revision 31158)
+++ /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/MapillaryExportDialog.java	(revision 31158)
@@ -0,0 +1,101 @@
+package org.openstreetmap.josm.plugins.mapillary;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.Component;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+import javax.swing.BoxLayout;
+import javax.swing.ButtonGroup;
+import javax.swing.JButton;
+import javax.swing.JFileChooser;
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JRadioButton;
+
+/**
+ * GUI for exporting images.
+ * 
+ * @author nokutu
+ *
+ */
+public class MapillaryExportDialog extends JPanel implements ActionListener {
+
+	protected JOptionPane optionPane;
+	protected JRadioButton all;
+	protected JRadioButton sequence;
+	protected JRadioButton selected;
+	protected ButtonGroup group;
+	protected JButton choose;
+	protected JLabel path;
+	protected JFileChooser chooser;
+	protected String exportDirectory;
+
+	public MapillaryExportDialog() {
+	setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
+
+
+		group = new ButtonGroup();
+		all = new JRadioButton(tr("Export all images"));
+		sequence = new JRadioButton(tr("Export selected sequence"));
+		selected = new JRadioButton(tr("Export selected images"));
+		group.add(all);
+		group.add(sequence);
+		group.add(selected);
+		if (MapillaryData.getInstance().getSelectedImage() == null
+				|| MapillaryData.getInstance().getSelectedImage().getSequence() == null) {
+			sequence.setEnabled(false);
+		}
+		if (MapillaryData.getInstance().getMultiSelectedImages().isEmpty()){
+			selected.setEnabled(false);
+		}
+		path = new JLabel("Select a folder");
+		choose = new JButton(tr("Explore"));
+		choose.addActionListener(this);
+		
+		JPanel jpanel = new JPanel();
+		jpanel.setLayout(new BoxLayout(jpanel, BoxLayout.PAGE_AXIS));
+		jpanel.add(all);
+		jpanel.add(sequence);
+		jpanel.add(selected);
+		//all.setAlignmentX(Component.CENTER_ALIGNMENT);
+		//sequence.setAlignmentX(Component.CENTER_ALIGNMENT);
+		jpanel.setAlignmentX(Component.CENTER_ALIGNMENT);
+		path.setAlignmentX(Component.CENTER_ALIGNMENT);
+		choose.setAlignmentX(Component.CENTER_ALIGNMENT);
+		//container.setAlignmentX(Component.CENTER_ALIGNMENT);
+
+		
+		add(jpanel);
+		add(path);
+		add(choose);
+
+
+	}
+
+	/**
+	 * Has to be called after this dialog has been added to a JOptionPane.
+	 * 
+	 * @param optionPane
+	 */
+	public void setOptionPane(JOptionPane optionPane) {
+		this.optionPane = optionPane;
+	}
+
+	@Override
+	public void actionPerformed(ActionEvent e) {
+		chooser = new JFileChooser();
+		chooser.setCurrentDirectory(new java.io.File(System.getProperty("user.home")));
+		chooser.setDialogTitle("Select a directory");
+		chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
+		chooser.setAcceptAllFileFilterUsed(false);
+
+		if (chooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) {
+			path.setText(chooser.getSelectedFile().toString());
+			this.updateUI();
+		}
+	}
+
+}
Index: /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/MapillaryImage.java
===================================================================
--- /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/MapillaryImage.java	(revision 31158)
+++ /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/MapillaryImage.java	(revision 31158)
@@ -0,0 +1,107 @@
+package org.openstreetmap.josm.plugins.mapillary;
+
+
+import org.openstreetmap.josm.data.coor.LatLon;
+
+/**
+ * A MapillaryImage object represents each of the images stored in Mapillary.
+ * 
+ * @author nokutu
+ *
+ */
+public class MapillaryImage {
+	private String key;
+	private LatLon latLon;
+
+	/**
+	 * 0 means north.
+	 */
+	private Double ca;
+	private boolean isModified = false;
+
+	/**
+	 * Used to prevent old running threads from setting images in an object
+	 * which are no longer needed.
+	 */
+
+	public MapillarySequence sequence;
+
+	/**
+	 * Main contructor of the class MapillaryImage
+	 * 
+	 * @param key
+	 *            The unique identifier of the image.
+	 * @param lat
+	 *            The latitude where it is positioned.
+	 * @param lon
+	 *            The longitude where it is positioned.
+	 * @param ca
+	 *            The direction of the images in degrees, meaning 0 north.
+	 */
+	public MapillaryImage(String key, double lat, double lon, double ca) {
+		this.key = key;
+		this.latLon = new LatLon(lat, lon);
+		this.ca = ca;
+	}
+
+	public boolean isModified() {
+		return this.isModified;
+	}
+
+	public LatLon getLatLon() {
+		return latLon;
+	}
+
+	public Double getCa() {
+		return ca;
+	}
+
+	public String getKey() {
+		return this.key;
+	}
+
+
+	/**
+	 * Sets the MapillarySequence object which contains the MapillaryImage.
+	 * 
+	 * @param sequence
+	 *            The MapillarySequence that contains the MapillaryImage.
+	 */
+	public void setSequence(MapillarySequence sequence) {
+		this.sequence = sequence;
+	}
+
+
+	public MapillarySequence getSequence() {
+		return this.sequence;
+	}
+
+	public String toString() {
+		return "Image[key=" + this.key + ";lat=" + this.latLon.lat() + ";lon="
+				+ this.latLon.lon() + ";ca=" + this.ca + "]";
+	}
+
+	public Boolean equals(MapillaryImage image) {
+		return this.key.equals(image.getKey());
+	}
+
+	/**
+	 * If the MapillaryImage belongs to a MapillarySequence, returns the next
+	 * MapillarySequence in it.
+	 * 
+	 * @return The following MapillaryImage, or null if there is none.
+	 */
+	public MapillaryImage next() {
+		return this.getSequence().next(this);
+	}
+
+	/**
+	 * If the MapillaryImage belongs to a MapillarySequence, returns the
+	 * previous MapillarySequence in it.
+	 * 
+	 * @return The previous MapillaryImage, or null if there is none.
+	 */
+	public MapillaryImage previous() {
+		return this.getSequence().previous(this);
+	}
+}
Index: /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/MapillaryLayer.java
===================================================================
--- /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/MapillaryLayer.java	(revision 31158)
+++ /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/MapillaryLayer.java	(revision 31158)
@@ -0,0 +1,277 @@
+package org.openstreetmap.josm.plugins.mapillary;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import org.apache.commons.jcs.access.CacheAccess;
+import org.openstreetmap.josm.plugins.mapillary.downloads.MapillaryDownloader;
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.gui.layer.Layer;
+import org.openstreetmap.josm.data.Bounds;
+import org.openstreetmap.josm.gui.MapView;
+import org.openstreetmap.josm.gui.MapView.EditLayerChangeListener;
+import org.openstreetmap.josm.gui.layer.AbstractModifiableLayer;
+import org.openstreetmap.josm.gui.layer.OsmDataLayer;
+import org.openstreetmap.josm.data.cache.BufferedImageCacheEntry;
+import org.openstreetmap.josm.data.cache.JCSCacheManager;
+import org.openstreetmap.josm.data.osm.visitor.BoundingXYVisitor;
+import org.openstreetmap.josm.gui.dialogs.LayerListDialog;
+import org.openstreetmap.josm.gui.dialogs.LayerListPopup;
+import org.openstreetmap.josm.data.osm.event.PrimitivesAddedEvent;
+import org.openstreetmap.josm.data.osm.event.PrimitivesRemovedEvent;
+import org.openstreetmap.josm.data.osm.event.TagsChangedEvent;
+import org.openstreetmap.josm.data.osm.event.NodeMovedEvent;
+import org.openstreetmap.josm.data.osm.event.WayNodesChangedEvent;
+import org.openstreetmap.josm.data.osm.event.RelationMembersChangedEvent;
+import org.openstreetmap.josm.data.osm.event.AbstractDatasetChangedEvent;
+import org.openstreetmap.josm.data.osm.event.DataChangedEvent;
+import org.openstreetmap.josm.data.osm.event.DataSetListener;
+
+import java.awt.Graphics2D;
+import java.awt.Point;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+import java.io.IOException;
+
+import javax.swing.ImageIcon;
+import javax.swing.Action;
+import javax.swing.Icon;
+
+import java.util.List;
+import java.util.ArrayList;
+
+public class MapillaryLayer extends AbstractModifiableLayer implements
+		MouseListener, DataSetListener, EditLayerChangeListener {
+
+	private final MapillaryData mapillaryData;
+	private List<Bounds> bounds;
+	private MapillaryToggleDialog tgd;
+	public static Boolean INSTANCED = false;
+	public static CacheAccess<String, BufferedImageCacheEntry> CACHE;
+
+	public MapillaryLayer() {
+		super(tr("Mapillary Images"));
+		mapillaryData = MapillaryData.getInstance();
+		bounds = new ArrayList<>();
+		init();
+	}
+
+	private void init() {
+		INSTANCED = true;
+		try {
+			CACHE = JCSCacheManager.getCache("Mapillary");
+		} catch (IOException e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}
+		if (Main.map != null && Main.map.mapView != null) {
+			Main.map.mapView.addMouseListener(this);
+			Main.map.mapView.addLayer(this);
+			MapView.addEditLayerChangeListener(this, false);
+			Main.map.mapView.getEditLayer().data.addDataSetListener(this);
+			if (tgd == null) {
+				if (MapillaryToggleDialog.INSTANCE == null) {
+					tgd = MapillaryToggleDialog.getInstance();
+					Main.map.addToggleDialog(tgd, false);
+				} else
+					tgd = MapillaryToggleDialog.getInstance();
+			}
+		}
+		MapillaryPlugin.setMenuEnabled(MapillaryPlugin.EXPORT_MENU, true);
+		download();
+	}
+
+	protected void download() {
+		for (Bounds bounds : Main.map.mapView.getEditLayer().data
+				.getDataSourceBounds()) {
+			if (!this.bounds.contains(bounds)) {
+				this.bounds.add(bounds);
+				new MapillaryDownloader(mapillaryData).getImages(
+						bounds.getMin(), bounds.getMax());
+			}
+		}
+	}
+
+	public MapillaryData getMapillaryData() {
+		return mapillaryData;
+	}
+
+	@Override
+	public void destroy() {
+		tgd.showDefault();
+		INSTANCED = false;
+		MapillaryPlugin.setMenuEnabled(MapillaryPlugin.EXPORT_MENU, false);
+		MapillaryData.deleteInstance();
+		super.destroy();
+	}
+
+	@Override
+	public boolean isModified() {
+		for (MapillaryImage image : mapillaryData.getImages()) {
+			if (image.isModified()) {
+				return true;
+			}
+		}
+		return false;
+	}
+
+	@Override
+	public void paint(Graphics2D g, MapView mv, Bounds box) {
+		synchronized (this) {
+			for (MapillaryImage image : mapillaryData.getImages()) {
+				Point p = mv.getPoint(image.getLatLon());
+				Point nextp;
+				if (image.getSequence() != null
+						&& image.getSequence().next(image) != null) {
+					nextp = mv.getPoint(image.getSequence().next(image)
+							.getLatLon());
+					g.drawLine(p.x, p.y, nextp.x, nextp.y);
+				}
+				ImageIcon icon;
+				if (!mapillaryData.getMultiSelectedImages().contains(image))
+					icon = MapillaryPlugin.ICON16;
+				else
+					icon = MapillaryPlugin.ICON16SELECTED;
+				int width = icon.getIconWidth();
+				int height = icon.getIconHeight();
+				g.drawImage(icon.getImage(), p.x - (width / 2), p.y
+						- (height / 2), Main.map.mapView);
+			}
+		}
+	}
+
+	@Override
+	public Icon getIcon() {
+		return MapillaryPlugin.ICON16;
+	}
+
+	@Override
+	public boolean isMergable(Layer other) {
+		return other instanceof MapillaryLayer;
+	}
+
+	@Override
+	public void mergeFrom(Layer from) {
+		throw new UnsupportedOperationException(
+				"Notes layer does not support merging yet");
+	}
+
+	@Override
+	public Action[] getMenuEntries() {
+		List<Action> actions = new ArrayList<>();
+		actions.add(LayerListDialog.getInstance().createShowHideLayerAction());
+		actions.add(LayerListDialog.getInstance().createDeleteLayerAction());
+		actions.add(new LayerListPopup.InfoAction(this));
+		return actions.toArray(new Action[actions.size()]);
+	}
+
+	@Override
+	public void mouseClicked(MouseEvent e) {
+		if (e.getButton() != MouseEvent.BUTTON1) {
+			return;
+		}
+		if (Main.map.mapView.getActiveLayer() != this) {
+			return;
+		}
+		Point clickPoint = e.getPoint();
+		double snapDistance = 10;
+		double minDistance = Double.MAX_VALUE;
+		MapillaryImage closest = null;
+		for (MapillaryImage image : mapillaryData.getImages()) {
+			Point imagePoint = Main.map.mapView.getPoint(image.getLatLon());
+			// move the note point to the center of the icon where users are
+			// most likely to click when selecting
+			imagePoint.setLocation(imagePoint.getX(), imagePoint.getY());
+			double dist = clickPoint.distanceSq(imagePoint);
+			if (minDistance > dist
+					&& clickPoint.distance(imagePoint) < snapDistance) {
+				minDistance = dist;
+				closest = image;
+			}
+		}
+		if (e.getModifiers() == (MouseEvent.BUTTON1_MASK | MouseEvent.CTRL_MASK))
+			mapillaryData.addMultiSelectedImage(closest);
+		else
+			mapillaryData.setSelectedImage(closest);
+	}
+
+	@Override
+	public Object getInfoComponent() {
+		StringBuilder sb = new StringBuilder();
+		sb.append(tr("Mapillary layer"));
+		sb.append("\n");
+		sb.append(tr("Total images:"));
+		sb.append(" ");
+		sb.append(this.size());
+		sb.append("\n");
+		return sb.toString();
+	}
+
+	@Override
+	public String getToolTipText() {
+		return this.size() + " " + tr("images");
+	}
+
+	private int size() {
+		return mapillaryData.getImages().size();
+	}
+
+	// MouseListener
+	@Override
+	public void visitBoundingBox(BoundingXYVisitor v) {
+	}
+
+	@Override
+	public void mousePressed(MouseEvent e) {
+	}
+
+	@Override
+	public void mouseReleased(MouseEvent e) {
+	}
+
+	@Override
+	public void mouseEntered(MouseEvent e) {
+	}
+
+	@Override
+	public void mouseExited(MouseEvent e) {
+	}
+
+	// EditDataLayerChanged
+	@Override
+	public void editLayerChanged(OsmDataLayer oldLayer, OsmDataLayer newLayer) {
+	}
+
+	// DataSetListener
+
+	@Override
+	public void dataChanged(DataChangedEvent event) {
+	}
+
+	@Override
+	public void primitivesAdded(PrimitivesAddedEvent event) {
+	}
+
+	@Override
+	public void primitivesRemoved(PrimitivesRemovedEvent event) {
+	}
+
+	@Override
+	public void tagsChanged(TagsChangedEvent event) {
+	}
+
+	@Override
+	public void nodeMoved(NodeMovedEvent event) {
+	}
+
+	@Override
+	public void wayNodesChanged(WayNodesChangedEvent event) {
+	}
+
+	@Override
+	public void relationMembersChanged(RelationMembersChangedEvent event) {
+	}
+
+	@Override
+	public void otherDatasetChange(AbstractDatasetChangedEvent event) {
+	}
+}
Index: /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/MapillarySequence.java
===================================================================
--- /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/MapillarySequence.java	(revision 31158)
+++ /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/MapillarySequence.java	(revision 31158)
@@ -0,0 +1,79 @@
+package org.openstreetmap.josm.plugins.mapillary;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Class that stores a sequence of MapillaryImage objects.
+ * 
+ * @author nokutu
+ *
+ */
+public class MapillarySequence {
+	private final List<MapillaryImage> images;
+
+	public MapillarySequence() {
+		this.images = new ArrayList<>();
+	}
+
+	public MapillarySequence(List<MapillaryImage> images) {
+		this.images = images;
+	}
+
+	public List<MapillaryImage> getImages() {
+		return this.images;
+	}
+
+	public synchronized void add(MapillaryImage image) {
+		this.images.add(image);
+	}
+
+	public synchronized void add(List<MapillaryImage> images) {
+		for (MapillaryImage image : images) {
+			add(image);
+		}
+	}
+
+	public void remove(MapillaryImage image) {
+		this.images.remove(image);
+	}
+
+	/**
+	 * Returns the next MapillaryImage in the sequence.
+	 * 
+	 * @param image
+	 * @return
+	 */
+	public MapillaryImage next(MapillaryImage image) {
+		if (!images.contains(image))
+			throw new IllegalArgumentException();
+		int i = images.indexOf(image);
+		if (i == images.size() - 1) {
+			return null;
+		} else
+			return images.get(i + 1);
+	}
+
+	/**
+	 * Returns the previous MapillaryImage in the sequence.
+	 * 
+	 * @param image
+	 * @return
+	 */
+	public MapillaryImage previous(MapillaryImage image) {
+		if (!images.contains(image))
+			throw new IllegalArgumentException();
+		int i = images.indexOf(image);
+		if (i == 0) {
+			return null;
+		} else
+			return images.get(i - 1);
+	}
+
+	public int getDistance(MapillaryImage image1, MapillaryImage image2) {
+		if (!this.images.contains(image1) || !this.images.contains(image2))
+			throw new IllegalArgumentException();
+		return Math.abs(this.images.indexOf(image1)
+				- this.images.indexOf(image2));
+	}
+}
Index: /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/MapillaryToggleDialog.java
===================================================================
--- /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/MapillaryToggleDialog.java	(revision 31158)
+++ /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/MapillaryToggleDialog.java	(revision 31158)
@@ -0,0 +1,174 @@
+package org.openstreetmap.josm.plugins.mapillary;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.event.ActionEvent;
+import java.awt.image.BufferedImage;
+import java.awt.BorderLayout;
+import java.awt.FlowLayout;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.util.HashMap;
+
+import org.apache.commons.jcs.access.CacheAccess;
+import org.openstreetmap.josm.data.cache.BufferedImageCacheEntry;
+import org.openstreetmap.josm.data.cache.CacheEntry;
+import org.openstreetmap.josm.data.cache.CacheEntryAttributes;
+import org.openstreetmap.josm.data.cache.ICachedLoaderListener;
+import org.openstreetmap.josm.data.cache.JCSCacheManager;
+import org.openstreetmap.josm.gui.dialogs.ToggleDialog;
+import org.openstreetmap.josm.gui.SideButton;
+import org.openstreetmap.josm.plugins.mapillary.cache.MapillaryCache;
+import org.openstreetmap.josm.tools.ImageProvider;
+
+import javax.imageio.ImageIO;
+import javax.swing.ImageIcon;
+import javax.swing.JLabel;
+import javax.swing.SwingUtilities;
+import javax.swing.AbstractAction;
+import javax.swing.JPanel;
+
+/**
+ * Toggle dialog that shows an image and some buttons.
+ * 
+ * @author nokutu
+ *
+ */
+public class MapillaryToggleDialog extends ToggleDialog implements ICachedLoaderListener{
+
+	public static MapillaryToggleDialog INSTANCE;
+
+	public volatile JLabel active;
+	public volatile MapillaryImage image;
+
+	final SideButton nextButton = new SideButton(new nextPictureAction());
+	final SideButton previousButton = new SideButton(
+			new previousPictureAction());
+
+	final JPanel buttons;
+
+	public MapillaryToggleDialog() {
+		super(tr("Mapillary image"), "mapillary", tr("Open Mapillary window"),
+				null, 200);
+		showDefault();
+		buttons = new JPanel();
+		buttons.setLayout(new FlowLayout(FlowLayout.CENTER));
+		buttons.add(previousButton);
+		buttons.add(nextButton);
+		this.add(buttons, BorderLayout.SOUTH);
+	}
+
+	public static MapillaryToggleDialog getInstance() {
+		if (INSTANCE == null) {
+			INSTANCE = new MapillaryToggleDialog();
+		}
+		return INSTANCE;
+	}
+	
+	public static void deleteInstance() {
+		INSTANCE = null;
+	}
+
+	public void showDefault() {
+		if (active != null)
+			this.remove(active);
+		JLabel label = new JLabel("", new ImageProvider(
+				"mapillary_icon_960.png").setWidth(100).setHeight(100).get(),
+				JLabel.CENTER);
+		active = label;
+		this.add(active);
+		this.updateUI();
+	}
+
+	public synchronized void updateImage() {
+		if (!SwingUtilities.isEventDispatchThread()) {
+			SwingUtilities.invokeLater(new Runnable() {
+				@Override
+				public void run() {
+					updateImage();
+				}
+			});
+		} else {
+			if (MapillaryLayer.INSTANCED == false) {
+				showDefault();
+				return;
+			}
+			if (this.image != null) {
+				CacheAccess<String, BufferedImageCacheEntry> prev;
+				try {
+					prev = JCSCacheManager.getCache("mapillary");
+					HashMap<String, String> headers = new HashMap<>();
+					MapillaryCache cache = new MapillaryCache(image.getKey(), MapillaryCache.Type.FULL_IMAGE, prev, 200000, 200000, headers);
+					cache.submit(MapillaryToggleDialog.getInstance(), false);
+				} catch (IOException e) {
+					// TODO Auto-generated catch block
+					e.printStackTrace();
+				} catch (Exception e) {
+					System.out.println("Hello");
+				}
+				/*if (image.getImage() != null) {
+					showImage();
+				} else if (image.getThumbnail() != null) {
+					showThumbnail();
+				}*/
+			} else
+				showDefault();
+		}
+	}
+
+	public synchronized void setImage(MapillaryImage image) {
+		this.image = image;
+	}
+
+	public synchronized MapillaryImage getImage() {
+		return this.image;
+	}
+
+	class nextPictureAction extends AbstractAction {
+		public nextPictureAction() {
+			putValue(NAME, tr("Next picture"));
+			putValue(SHORT_DESCRIPTION,
+					tr("Shows the next picture in the sequence"));
+		}
+
+		@Override
+		public void actionPerformed(ActionEvent e) {
+			if (MapillaryToggleDialog.getInstance().getImage() != null)
+				MapillaryData.getInstance().selectNext();
+		}
+	}
+
+	class previousPictureAction extends AbstractAction {
+		public previousPictureAction() {
+			putValue(NAME, tr("Previous picture"));
+			putValue(SHORT_DESCRIPTION,
+					tr("Shows the previous picture in the sequence"));
+		}
+
+		@Override
+		public void actionPerformed(ActionEvent e) {
+			if (MapillaryToggleDialog.getInstance().getImage() != null)
+				MapillaryData.getInstance().selectPrevious();
+		}
+	}
+
+	@Override
+	public void loadingFinished(CacheEntry data,
+			CacheEntryAttributes attributes, LoadResult result) {
+		System.out.println("Listener");
+		try {
+			BufferedImage img = ImageIO.read(new ByteArrayInputStream(data.getContent()));
+			this.remove(active);
+			JLabel label = new JLabel("", new ImageIcon(img), JLabel.CENTER);
+			active = label;
+			this.add(active);
+			this.updateUI();
+		} catch (IOException e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}
+			
+		
+		
+	}
+}
Index: /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/cache/MapillaryCache.java
===================================================================
--- /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/cache/MapillaryCache.java	(revision 31158)
+++ /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/cache/MapillaryCache.java	(revision 31158)
@@ -0,0 +1,71 @@
+package org.openstreetmap.josm.plugins.mapillary.cache;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Map;
+
+import org.apache.commons.jcs.access.behavior.ICacheAccess;
+import org.openstreetmap.josm.data.cache.BufferedImageCacheEntry;
+import org.openstreetmap.josm.data.cache.JCSCachedTileLoaderJob;
+
+public class MapillaryCache extends
+		JCSCachedTileLoaderJob<String, BufferedImageCacheEntry> {
+
+	private volatile URL url;
+	private volatile String key;
+
+	public static enum Type {
+		FULL_IMAGE, THUMBNAIL
+	}
+
+	public MapillaryCache(String key, Type type,
+			ICacheAccess<String, BufferedImageCacheEntry> cache,
+			int connectTimeout, int readTimeout, Map<String, String> headers) {
+		super(cache, connectTimeout, readTimeout, headers);
+		this.key = key;
+		try {
+			if (type == Type.FULL_IMAGE) {
+				url = new URL("https://d1cuyjsrcm0gby.cloudfront.net/" + key
+						+ "/thumb-2048.jpg");
+				this.key += ".FULL_IMAGE";
+
+			} else if (type == Type.THUMBNAIL) {
+				url = new URL("https://d1cuyjsrcm0gby.cloudfront.net/" + key
+						+ "/thumb-320.jpg");
+				this.key += ".THUMBNAIL";
+			}
+		} catch (MalformedURLException e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}
+	}
+
+	@Override
+	public String getCacheKey() {
+		return key;
+	}
+
+	@Override
+	public URL getUrl() {
+		return url;
+	}
+
+	@Override
+	protected BufferedImageCacheEntry createCacheEntry(byte[] content) {
+		return new BufferedImageCacheEntry(content);
+	}
+	
+	@Override
+    protected boolean isObjectLoadable() {
+		if (cacheData == null)
+			return false;
+        byte[] content = cacheData.getContent();
+        return content != null && content.length > 0;
+    }
+
+	//@Override
+	protected boolean handleNotFound() {
+		// TODO Auto-generated method stub
+		return false;
+	}
+}
Index: /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/downloads/MapillaryDownloader.java
===================================================================
--- /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/downloads/MapillaryDownloader.java	(revision 31158)
+++ /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/downloads/MapillaryDownloader.java	(revision 31158)
@@ -0,0 +1,74 @@
+package org.openstreetmap.josm.plugins.mapillary.downloads;
+
+import org.openstreetmap.josm.plugins.mapillary.MapillaryData;
+import org.openstreetmap.josm.data.Bounds;
+import org.openstreetmap.josm.data.coor.LatLon;
+
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * Class that concentrates all the ways of downloading of the plugin.
+ * 
+ * @author nokutu
+ *
+ */
+public class MapillaryDownloader {
+
+	public final static String BASE_URL = "https://a.mapillary.com/v2/";
+	public final static String CLIENT_ID = "NzNRM2otQkR2SHJzaXJmNmdQWVQ0dzo1YTA2NmNlODhlNWMwOTBm";
+
+	private String[] parameters = { "lat", "lon", "distance", "limit",
+			"min_lat", "min_lon", "max_lat", "max_lon" };
+	private MapillaryData data;
+
+	public MapillaryDownloader(MapillaryData data) {
+		this.data = data;
+	}
+
+	/*
+	 * public List<MapillaryImage> getImagesAround(LatLon latLon, double
+	 * distance) { String u rl = BASE_URL; url += "search/im/close/";
+	 * Hashtable<String, Double> hash = new Hashtable<String, Double>();
+	 * hash.put("lat", latLon.lat()); hash.put("lon", latLon.lon());
+	 * hash.put("distance", distance); url += buildParameters(hash); try {
+	 * return parseImages(parseUrl(url)); } catch (Exception e) { return null; }
+	 * }
+	 */
+
+	/**
+	 * Gets all the images in a square. It downloads all the images of all the
+	 * sequences that pass through the given rectangle.
+	 * 
+	 * @param minLatLon
+	 *            The minimum latitude and longitude of the rectangle.
+	 * @param maxLatLon
+	 *            The maximum latitude and longitude of the rectangle
+	 */
+	public void getImages(LatLon minLatLon, LatLon maxLatLon) {
+		String url1 = BASE_URL;
+		String url2 = BASE_URL;
+		url1 += "search/im/";
+		url2 += "search/s/";
+		ConcurrentHashMap<String, Double> hash = new ConcurrentHashMap<>();
+		hash.put("min_lat", minLatLon.lat());
+		hash.put("min_lon", minLatLon.lon());
+		hash.put("max_lat", maxLatLon.lat());
+		hash.put("max_lon", maxLatLon.lon());
+		url1 += buildParameters(hash);
+		url2 += buildParameters(hash);
+		try {
+			new Thread(new MapillarySquareDownloadManagerThread(this.data,
+					url1, url2, new Bounds(minLatLon, maxLatLon))).start();
+		} catch (Exception e) {
+		}
+	}
+
+	private String buildParameters(ConcurrentHashMap<String, Double> hash) {
+		String ret = "?client_id=" + CLIENT_ID;
+		for (int i = 0; i < parameters.length; i++) {
+			if (hash.get(parameters[i]) != null)
+				ret += "&" + parameters[i] + "=" + hash.get(parameters[i]);
+		}
+		return ret;
+	}
+}
Index: /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/downloads/MapillaryExportDownloadThread.java
===================================================================
--- /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/downloads/MapillaryExportDownloadThread.java	(revision 31158)
+++ /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/downloads/MapillaryExportDownloadThread.java	(revision 31158)
@@ -0,0 +1,42 @@
+package org.openstreetmap.josm.plugins.mapillary.downloads;
+
+import java.awt.image.BufferedImage;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.concurrent.ArrayBlockingQueue;
+
+import javax.imageio.ImageIO;
+
+import org.openstreetmap.josm.gui.progress.ProgressMonitor;
+import org.openstreetmap.josm.plugins.mapillary.MapillaryImage;
+
+public class MapillaryExportDownloadThread implements Runnable {
+
+	String url;
+	ArrayBlockingQueue<BufferedImage> queue;
+	ProgressMonitor monitor;
+
+	public MapillaryExportDownloadThread(MapillaryImage image, ArrayBlockingQueue<BufferedImage> queue) {
+		url = "https://d1cuyjsrcm0gby.cloudfront.net/" + image.getKey()
+				+ "/thumb-2048.jpg";
+		this.queue = queue;
+	}
+
+	@Override
+	public void run() {
+		try {
+			queue.put(ImageIO.read(new URL(url)));
+		} catch (MalformedURLException e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		} catch (InterruptedException e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		} catch (IOException e) {
+			// TODO -generated catch block
+			e.printStackTrace();
+		}
+	}
+
+}
Index: /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/downloads/MapillaryExportManager.java
===================================================================
--- /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/downloads/MapillaryExportManager.java	(revision 31158)
+++ /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/downloads/MapillaryExportManager.java	(revision 31158)
@@ -0,0 +1,65 @@
+package org.openstreetmap.josm.plugins.mapillary.downloads;
+
+import java.awt.image.BufferedImage;
+import java.io.IOException;
+import java.util.List;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+
+import org.openstreetmap.josm.gui.PleaseWaitRunnable;
+import org.openstreetmap.josm.gui.progress.PleaseWaitProgressMonitor;
+import org.openstreetmap.josm.io.OsmTransferException;
+import org.openstreetmap.josm.plugins.mapillary.MapillaryImage;
+import org.xml.sax.SAXException;
+
+public class MapillaryExportManager extends PleaseWaitRunnable {
+
+	ArrayBlockingQueue<BufferedImage> queue;
+	List<MapillaryImage> images;
+	String path;
+
+	public MapillaryExportManager(String title, List<MapillaryImage> images, String path) {
+		super(title, new PleaseWaitProgressMonitor("Exporting Mapillary Images"), true);
+		queue = new ArrayBlockingQueue<>(10);
+		this.images = images;
+		this.path = path;
+	}
+
+	@Override
+	protected void cancel() {
+		// TODO Auto-generated method stub
+
+	}
+
+	@Override
+	protected void realRun() throws SAXException, IOException,
+			OsmTransferException {
+		Thread writer = new Thread(new MapillaryExportWriterThread(path, queue, images.size(), this.getProgressMonitor()));
+		writer.start();
+		ThreadPoolExecutor ex = new ThreadPoolExecutor(20, 35, 25,
+				TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(10));
+		for (MapillaryImage image : images) {
+			ex.execute(new MapillaryExportDownloadThread(image, queue));
+			try {
+				while (ex.getQueue().remainingCapacity() == 0)
+					Thread.sleep(100);
+			} catch (Exception e) {
+				System.out.println(e);
+			}
+		}
+		try {
+			writer.join();
+		}
+		catch(Exception e){
+		}
+
+	}
+
+	@Override
+	protected void finish() {
+		// TODO Auto-generated method stub
+
+	}
+
+}
Index: /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/downloads/MapillaryExportWriterThread.java
===================================================================
--- /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/downloads/MapillaryExportWriterThread.java	(revision 31158)
+++ /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/downloads/MapillaryExportWriterThread.java	(revision 31158)
@@ -0,0 +1,51 @@
+package org.openstreetmap.josm.plugins.mapillary.downloads;
+
+import java.awt.image.BufferedImage;
+import java.io.File;
+import java.io.IOException;
+import java.util.concurrent.ArrayBlockingQueue;
+
+import javax.imageio.ImageIO;
+
+import org.openstreetmap.josm.gui.progress.PleaseWaitProgressMonitor;
+import org.openstreetmap.josm.gui.progress.ProgressMonitor;
+
+
+public class MapillaryExportWriterThread implements Runnable {
+
+	private String path;
+	private ArrayBlockingQueue<BufferedImage> queue;
+	private int amount;
+	private ProgressMonitor monitor;
+	
+	public MapillaryExportWriterThread(String path,
+			ArrayBlockingQueue<BufferedImage> queue, int amount, ProgressMonitor monitor) {
+		this.path = path;
+		this.queue = queue;
+		this.amount = amount;
+		this.monitor = monitor;
+	}
+
+	@Override
+	public void run() {
+		monitor.setCustomText("Downloaded 0/" + amount);
+		File outputfile;
+		BufferedImage img;
+		for (int i = 0; i < amount; i++) {
+			try {
+				img = queue.take();
+				outputfile = new File(path + "/" + i + ".png");
+				ImageIO.write(img, "png", outputfile);
+			} catch (InterruptedException e1) {
+				// TODO Auto-generated catch block
+				e1.printStackTrace();
+			} catch (IOException e) {
+				// TODO Auto-generated catch block
+				e.printStackTrace();
+			}
+			monitor.worked(PleaseWaitProgressMonitor.PROGRESS_BAR_MAX / amount);
+			monitor.setCustomText("Downloaded " + (i + 1) + "/" + amount);
+		}
+	}
+
+}
Index: /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/downloads/MapillarySequenceDownloadThread.java
===================================================================
--- /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/downloads/MapillarySequenceDownloadThread.java	(revision 31158)
+++ /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/downloads/MapillarySequenceDownloadThread.java	(revision 31158)
@@ -0,0 +1,111 @@
+package org.openstreetmap.josm.plugins.mapillary.downloads;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.net.URL;
+import java.io.InputStreamReader;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.json.JSONArray;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.ExecutorService;
+
+import org.openstreetmap.josm.data.Bounds;
+import org.openstreetmap.josm.plugins.mapillary.MapillaryData;
+import org.openstreetmap.josm.plugins.mapillary.MapillaryImage;
+import org.openstreetmap.josm.plugins.mapillary.MapillarySequence;
+
+/**
+ * This Class downloads all the pictures in a given sequence and creates the
+ * needed MapillaryImage and MapillarySequence objects
+ * 
+ * @author nokutu
+ *
+ */
+public class MapillarySequenceDownloadThread implements Runnable {
+
+	private MapillaryData data;
+	private String url;
+	private ExecutorService ex;
+	private Bounds bounds;
+
+	public MapillarySequenceDownloadThread(ExecutorService ex,
+			MapillaryData data, String url, Bounds bounds) {
+		this.data = data;
+		this.url = url;
+		this.ex = ex;
+		this.bounds = bounds;
+	}
+
+	public void run() {
+		try {
+			BufferedReader br;
+			br = new BufferedReader(new InputStreamReader(
+					new URL(url).openStream()));
+			String jsonLine = "";
+			while (br.ready()) {
+				jsonLine += br.readLine();
+			}
+			JSONObject jsonall = new JSONObject(jsonLine);
+
+			if (!jsonall.getBoolean("more") && !ex.isShutdown()) {
+				ex.shutdownNow();
+			}
+			JSONArray jsonseq = jsonall.getJSONArray("ss");
+			for (int i = 0; i < jsonseq.length(); i++) {
+				JSONObject jsonobj = jsonseq.getJSONObject(i);
+				JSONArray cas = jsonobj.getJSONArray("cas");
+				JSONArray coords = jsonobj.getJSONArray("coords");
+				JSONArray keys = jsonobj.getJSONArray("keys");
+				ArrayList<MapillaryImage> images = new ArrayList<>();
+				for (int j = 0; j < cas.length(); j++) {
+					try {
+						images.add(new MapillaryImage(keys.getString(j), coords
+								.getJSONArray(j).getDouble(1), coords
+								.getJSONArray(j).getDouble(0), cas.getDouble(j)));
+					} catch (Exception e) {
+						// Mapillary service bug here
+						//System.out.println(cas.length());
+						//System.out.println(coords.length());
+						//System.out.println(keys.length());
+						System.out.println(e);
+					}
+				}
+				MapillarySequence sequence = new MapillarySequence();
+				int first = -1;
+				int last = -1;
+				int pos = 0;
+				
+				// Here it gets only those images which are in the downloaded
+				// area.
+				for (MapillaryImage img : images) {
+					if (first == -1 && bounds.contains(img.getLatLon()))
+						first = pos;
+					else if (first != -1 && last == -1
+							&& !bounds.contains(img.getLatLon()))
+						last = pos;
+					else if (last != -1 && bounds.contains(img.getLatLon()))
+						last = -1;
+					pos++;
+				}
+				if (last == -1) {
+					last = pos;
+				}
+				if (first == -1)
+					continue;
+				List<MapillaryImage> finalImages = images.subList(first, last);
+				for (MapillaryImage img : finalImages) {
+					img.setSequence(sequence);
+				}
+				data.addWithoutUpdate(finalImages);
+				sequence.add(finalImages);
+			}
+		} catch (IOException | JSONException e) {
+			return;
+		}
+		return;
+	}
+}
Index: /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/downloads/MapillarySquareDownloadManagerThread.java
===================================================================
--- /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/downloads/MapillarySquareDownloadManagerThread.java	(revision 31158)
+++ /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/downloads/MapillarySquareDownloadManagerThread.java	(revision 31158)
@@ -0,0 +1,75 @@
+package org.openstreetmap.josm.plugins.mapillary.downloads;
+
+import java.util.concurrent.ThreadPoolExecutor;
+import static org.openstreetmap.josm.tools.I18n.tr;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.ArrayBlockingQueue;
+
+import org.openstreetmap.josm.data.Bounds;
+import org.openstreetmap.josm.plugins.mapillary.MapillaryData;
+
+/**
+ * This Class is needed to create an indeterminate amount of downloads, because
+ * the Mapillary API has a param page which is needed when the amount of
+ * requested images is quite big.
+ * 
+ * @author nokutu
+ *
+ */
+public class MapillarySquareDownloadManagerThread implements Runnable {
+
+	@SuppressWarnings("unused")
+	private String urlImages;
+	private String urlSequences;
+	private MapillaryData data;
+	private Bounds bounds;
+
+	public MapillarySquareDownloadManagerThread(MapillaryData data,
+			String urlImages, String urlSequences, Bounds bounds) {
+		this.data = data;
+		this.urlImages = urlImages;
+		this.urlSequences = urlSequences;
+		this.bounds = bounds;
+	}
+
+	public void run() {
+		/*
+		 * ThreadPoolExecutor ex = new ThreadPoolExecutor(30, 35, 25,
+		 * TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(20));
+		 * ArrayList<JSONArray> ret = new ArrayList<JSONArray>(); int page = 0;
+		 * while (!ex.isShutdown()) { ex.execute(new
+		 * MapillarySquareDownloadThread(ex, this.data, urlImages + "&page=" +
+		 * page + "&limit=25")); try { if (ex.getQueue().peek() != null)
+		 * Thread.sleep(1000); } catch(Exception e){ System.out.println(e); }
+		 * page++; }
+		 */
+		System.out.println(tr("INFORMATION: GET") + urlSequences);
+		fullfillSequences();
+		return;
+	}
+
+	public void fullfillSequences() {
+		ThreadPoolExecutor ex = new ThreadPoolExecutor(20, 35, 25,
+				TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(5));
+		;
+		int page = 0;
+		while (!ex.isShutdown()) {
+			ex.execute(new MapillarySequenceDownloadThread(ex, data,
+					urlSequences + "&page=" + page + "&limit=1", bounds));
+			try {
+				while (ex.getQueue().remainingCapacity() == 0)
+					Thread.sleep(100);
+			} catch (Exception e) {
+				System.out.println(e);
+			}
+			page++;
+		}
+		try {
+			while (!ex.awaitTermination(15, TimeUnit.SECONDS)) {
+			}
+		} catch (Exception e) {
+			System.out.println(e);
+		}
+		data.dataUpdated();
+	}
+}
Index: /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/downloads/MapillarySquareDownloadThread.java
===================================================================
--- /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/downloads/MapillarySquareDownloadThread.java	(revision 31158)
+++ /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/downloads/MapillarySquareDownloadThread.java	(revision 31158)
@@ -0,0 +1,60 @@
+package org.openstreetmap.josm.plugins.mapillary.downloads;
+
+import java.io.BufferedReader;
+import java.net.URL;
+import java.io.InputStreamReader;
+
+import org.json.JSONObject;
+import org.json.JSONArray;
+
+import java.util.ArrayList;
+import java.util.concurrent.ExecutorService;
+
+import org.openstreetmap.josm.plugins.mapillary.MapillaryData;
+import org.openstreetmap.josm.plugins.mapillary.MapillaryImage;
+
+public class MapillarySquareDownloadThread implements Runnable {
+	String url;
+	MapillaryData data;
+	ExecutorService ex;
+
+	public MapillarySquareDownloadThread(ExecutorService ex,
+			MapillaryData data, String url) {
+		this.ex = ex;
+		this.data = data;
+		this.url = url;
+	}
+
+	public void run() {
+		try {
+			BufferedReader br;
+			br = new BufferedReader(new InputStreamReader(
+					new URL(url).openStream()));
+			String jsonLine = "";
+			while (br.ready()) {
+				jsonLine += br.readLine();
+			}
+			JSONObject jsonobj = new JSONObject(jsonLine);
+			if (!jsonobj.getBoolean("more")) {
+				ex.shutdownNow();
+			}
+			JSONArray jsonarr = jsonobj.getJSONArray("ims");
+			ArrayList<MapillaryImage> images = new ArrayList<>();
+			JSONObject image;
+			for (int i = 0; i < jsonarr.length(); i++) {
+				try {
+					image = jsonarr.getJSONObject(i);
+					images.add(new MapillaryImage(image.getString("key"), image
+							.getDouble("lat"), image.getDouble("lon"), image
+							.getDouble("ca")));
+				} catch (Exception e) {
+					System.out.println(e);
+				}
+			}
+			data.add(images);
+			return;
+		} catch (Exception e) {
+			return;
+		}
+	}
+}
