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 31511)
+++ /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/MapillaryData.java	(revision 31512)
@@ -29,5 +29,4 @@
   /** Listeners of the class. */
   private CopyOnWriteArrayList<MapillaryDataListener> listeners = new CopyOnWriteArrayList<>();
-
   /** The bounds of the areas for which the pictures have been downloaded. */
   public CopyOnWriteArrayList<Bounds> bounds;
@@ -94,5 +93,5 @@
    *
    * @param images
-   *          The set of {@link MapillaryAbstractImage} objects that are going
+   *          A {@link List} of {@link MapillaryAbstractImage} objects that are going
    *          to be removed.
    */
@@ -348,9 +347,9 @@
 
   /**
-   * Adds a MapillaryImage object to the list of selected images, (when ctrl +
+   * Adds a {@link MapillaryImage} object to the list of selected images, (when ctrl +
    * click)
    *
    * @param image
-   *          The MapillaryImage object to be added.
+   *          The {@link MapillaryImage} object to be added.
    */
   public void addMultiSelectedImage(MapillaryAbstractImage image) {
Index: /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/MapillaryDataListener.java
===================================================================
--- /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/MapillaryDataListener.java	(revision 31511)
+++ /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/MapillaryDataListener.java	(revision 31512)
@@ -25,4 +25,3 @@
   public void selectedImageChanged(MapillaryAbstractImage oldImage,
       MapillaryAbstractImage newImage);
-
 }
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 31511)
+++ /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/MapillaryImage.java	(revision 31512)
@@ -12,10 +12,11 @@
  */
 public class MapillaryImage extends MapillaryAbstractImage {
-  /** Unique identifier of the object */
+  /** Unique identifier of the object. */
   private final String key;
-  /** The user that made the image */
+  /** The user that made the image. */
   private String user;
-  /** Set of traffic signs in the image */
+  /** Set of traffic signs in the image. */
   private List<String> signs;
+  /** Where the picture was taken. */
   private String location;
 
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 31511)
+++ /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/MapillaryLayer.java	(revision 31512)
@@ -124,6 +124,6 @@
         this.mode.zoomChanged();
     }
-    if (MapillaryPlugin.EXPORT_MENU != null) { // Does not execute when in
-                                               // headless mode
+    // Does not execute when in headless mode
+    if (MapillaryPlugin.EXPORT_MENU != null) {
       MapillaryPlugin.setMenuEnabled(MapillaryPlugin.EXPORT_MENU, true);
       if (!MapillaryMainDialog.getInstance().isShowing())
@@ -362,5 +362,7 @@
    * @param g
    * @param p
+   *          The {@link Point} where the image must be set.
    * @param size
+   *          The width in pixels of the highlight.
    */
   private void drawPointHighlight(Graphics2D g, Point p, int size) {
@@ -385,6 +387,9 @@
    * @param g
    * @param image
+   *          The {@link MapillaryAbstractImage} which is being drown.
    * @param icon
+   *          The {@link ImageIcon} that represents the image.
    * @param p
+   *          The P¡{@link Point} when the image lies.
    */
   private void draw(Graphics2D g, MapillaryAbstractImage image, ImageIcon icon,
@@ -437,5 +442,6 @@
 
   /**
-   * Returns the 2 closest images belonging to a different sequence.
+   * Returns the 2 closest images belonging to a different sequence and
+   * different from the currently selected one.
    *
    * @return An array of length 2 containing the two closest images belonging to
@@ -500,5 +506,4 @@
     if (oldLayer == null && newLayer != null) {
       newLayer.data.addDataSetListener(this);
-
     } else if (oldLayer != null && newLayer == null) {
       oldLayer.data.removeDataSetListener(this);
@@ -513,4 +518,10 @@
   }
 
+  /**
+   * Threads that runs a delayed Mapillary download.
+   *
+   * @author nokutu
+   *
+   */
   private class delayedDownload extends Thread {
 
@@ -569,10 +580,8 @@
   @Override
   public void layerAdded(Layer newLayer) {
-    // Nothing
   }
 
   @Override
   public void layerRemoved(Layer oldLayer) {
-    // Nothing
   }
 
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 31511)
+++ /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/MapillarySequence.java	(revision 31512)
@@ -12,6 +12,9 @@
  */
 public class MapillarySequence {
+  /** The images in the sequence. */
   private final List<MapillaryAbstractImage> images;
+  /** Unique identifier. Used only for {@link MapillaryImage} sequences. */
   private String key;
+  /** Epoch time when the sequence was created */
   private long created_at;
 
@@ -42,6 +45,7 @@
    * object.
    *
-   * @return A List object containing all the {@link MapillaryAbstractImage}
-   *         objects that are part of the sequence.
+   * @return A {@link List} object containing all the
+   *         {@link MapillaryAbstractImage} objects that are part of the
+   *         sequence.
    */
   public List<MapillaryAbstractImage> getImages() {
@@ -72,6 +76,6 @@
    * Returns the unique identifier of the sequence.
    *
-   * @return A String containing the unique identifier of the sequence. null
-   *         means that the sequence has been created locally for imported
+   * @return A {@code String} containing the unique identifier of the sequence.
+   *         null means that the sequence has been created locally for imported
    *         images.
    */
@@ -123,6 +127,6 @@
 
   /**
-   * Returns the previous {@link MapillaryAbstractImage} in the sequence of a given
-   * {@link MapillaryAbstractImage} object.
+   * Returns the previous {@link MapillaryAbstractImage} in the sequence of a
+   * given {@link MapillaryAbstractImage} object.
    *
    * @param image
Index: /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/actions/MapillaryImportAction.java
===================================================================
--- /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/actions/MapillaryImportAction.java	(revision 31511)
+++ /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/actions/MapillaryImportAction.java	(revision 31512)
@@ -14,16 +14,7 @@
 
 import org.apache.commons.imaging.ImageReadException;
-import org.apache.commons.imaging.Imaging;
-import org.apache.commons.imaging.common.ImageMetadata;
-import org.apache.commons.imaging.common.RationalNumber;
-import org.apache.commons.imaging.formats.jpeg.JpegImageMetadata;
-import org.apache.commons.imaging.formats.tiff.TiffField;
-import org.apache.commons.imaging.formats.tiff.constants.ExifTagConstants;
-import org.apache.commons.imaging.formats.tiff.constants.GpsTagConstants;
 import org.openstreetmap.josm.Main;
 import org.openstreetmap.josm.actions.JosmAction;
-import org.openstreetmap.josm.data.coor.LatLon;
 import org.openstreetmap.josm.plugins.mapillary.MapillaryAbstractImage;
-import org.openstreetmap.josm.plugins.mapillary.MapillaryImportedImage;
 import org.openstreetmap.josm.plugins.mapillary.MapillaryLayer;
 import org.openstreetmap.josm.plugins.mapillary.MapillaryPlugin;
@@ -44,9 +35,4 @@
 
   private JFileChooser chooser;
-
-  /**
-   * Amount of pictures without the proper EXIF tags.
-   */
-  private int noTagsPics = 0;
 
   /**
@@ -84,15 +70,10 @@
             continue;
           for (int j = 0; j < file.listFiles().length; j++) {
-            int k = file.listFiles()[j].getName().lastIndexOf('.');
-            String extension = null;
-            if (k > 0) {
-              extension = file.listFiles()[j].getName().substring(k + 1);
-            }
+            String extension = MapillaryUtils.getExtension(file.listFiles()[j]);
             try {
               if (extension.equals("jpg") || extension.equals("jpeg"))
-                images.add(readJPG(file.listFiles()[j]));
-
+                images.add(MapillaryUtils.readJPG(file.listFiles()[j]));
               else if (extension.equals("png"))
-                images.add(readPNG(file.listFiles()[j]));
+                images.add(MapillaryUtils.readPNG(file.listFiles()[j]));
             } catch (ImageReadException | IOException | NullPointerException e1) {
               Main.error(e1);
@@ -100,10 +81,8 @@
           }
         } else {
-          if (file.getPath().substring(file.getPath().length() - 4)
-              .equals(".jpg")
-              || file.getPath().substring(file.getPath().length() - 5)
-                  .equals(".jpeg")) {
+          String extension = MapillaryUtils.getExtension(file);
+          if (extension.equals("jpg") || extension.equals("jpeg")) {
             try {
-              images.add(readJPG(file));
+              images.add(MapillaryUtils.readJPG(file));
             } catch (ImageReadException ex) {
               Main.error(ex);
@@ -113,5 +92,5 @@
           } else if (file.getPath().substring(file.getPath().length() - 4)
               .equals(".png")) {
-            images.add(readPNG(file));
+            images.add(MapillaryUtils.readPNG(file));
           }
         }
@@ -121,103 +100,3 @@
     }
   }
-
-  /**
-   * Reads a JPG pictures that contains the needed GPS information (position and
-   * direction) and creates a new icon in that position.
-   *
-   * @param file
-   *          The file where the picture is located.
-   * @return The imported image.
-   * @throws ImageReadException
-   *           If the file isn't an image.
-   * @throws IOException
-   *           If the file doesn't have the valid metadata.
-   */
-  public MapillaryImportedImage readJPG(File file) throws IOException,
-      ImageReadException {
-    final ImageMetadata metadata = Imaging.getMetadata(file);
-    if (metadata instanceof JpegImageMetadata) {
-      final JpegImageMetadata jpegMetadata = (JpegImageMetadata) metadata;
-      final TiffField lat_ref = jpegMetadata
-          .findEXIFValueWithExactMatch(GpsTagConstants.GPS_TAG_GPS_LATITUDE_REF);
-      final TiffField lat = jpegMetadata
-          .findEXIFValueWithExactMatch(GpsTagConstants.GPS_TAG_GPS_LATITUDE);
-      final TiffField lon_ref = jpegMetadata
-          .findEXIFValueWithExactMatch(GpsTagConstants.GPS_TAG_GPS_LONGITUDE_REF);
-      final TiffField lon = jpegMetadata
-          .findEXIFValueWithExactMatch(GpsTagConstants.GPS_TAG_GPS_LONGITUDE);
-      final TiffField ca = jpegMetadata
-          .findEXIFValueWithExactMatch(GpsTagConstants.GPS_TAG_GPS_IMG_DIRECTION);
-      final TiffField datetimeOriginal = jpegMetadata
-          .findEXIFValueWithExactMatch(ExifTagConstants.EXIF_TAG_DATE_TIME_ORIGINAL);
-      if (lat_ref == null || lat == null || lon == null || lon_ref == null) {
-        return readNoTags(file);
-      }
-      double latValue = 0;
-      double lonValue = 0;
-      double caValue = 0;
-      if (lat.getValue() instanceof RationalNumber[])
-        latValue = MapillaryUtils.degMinSecToDouble(
-            (RationalNumber[]) lat.getValue(), lat_ref.getValue().toString());
-      if (lon.getValue() instanceof RationalNumber[])
-        lonValue = MapillaryUtils.degMinSecToDouble(
-            (RationalNumber[]) lon.getValue(), lon_ref.getValue().toString());
-      if (ca != null && ca.getValue() instanceof RationalNumber)
-        caValue = ((RationalNumber) ca.getValue()).doubleValue();
-      if (datetimeOriginal != null)
-        return new MapillaryImportedImage(latValue, lonValue, caValue, file,
-            datetimeOriginal.getStringValue());
-      else
-        return new MapillaryImportedImage(latValue, lonValue, caValue, file);
-    }
-    throw new IllegalStateException("Invalid format.");
-  }
-
-  /**
-   * Reads a image file that doesn't contain the needed GPS information. And
-   * creates a new icon in the middle of the map.
-   *
-   * @param file
-   *          The file where the image is located.
-   * @return The imported image.
-   */
-  public MapillaryImportedImage readNoTags(File file) {
-    return readNoTags(
-        file,
-        Main.map.mapView.getProjection().eastNorth2latlon(
-            Main.map.mapView.getCenter()));
-  }
-
-  /**
-   * Reads a image file that doesn't contain the needed GPS information. And
-   * creates a new icon in the middle of the map.
-   *
-   * @param file
-   *          The file where the image is located.
-   * @param pos
-   *          A {@link LatLon} object indicating the position in the map where
-   *          the image must be set.
-   * @return The imported image.
-   */
-  public MapillaryImportedImage readNoTags(File file, LatLon pos) {
-    double HORIZONTAL_DISTANCE = 0.0001;
-    double horDev;
-    if (this.noTagsPics % 2 == 0)
-      horDev = HORIZONTAL_DISTANCE * this.noTagsPics / 2;
-    else
-      horDev = -HORIZONTAL_DISTANCE * ((this.noTagsPics + 1) / 2);
-    this.noTagsPics++;
-    return new MapillaryImportedImage(pos.lat(), pos.lon() + horDev, 0, file);
-  }
-
-  /**
-   * Reads an image in PNG format.
-   *
-   * @param file
-   *          The file where the image is located.
-   * @return The imported image.
-   */
-  public MapillaryImportedImage readPNG(File file) {
-    return readNoTags(file);
-  }
 }
Index: /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/actions/MapillaryImportIntoSequenceAction.java
===================================================================
--- /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/actions/MapillaryImportIntoSequenceAction.java	(revision 31511)
+++ /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/actions/MapillaryImportIntoSequenceAction.java	(revision 31512)
@@ -16,15 +16,7 @@
 
 import org.apache.commons.imaging.ImageReadException;
-import org.apache.commons.imaging.Imaging;
-import org.apache.commons.imaging.common.ImageMetadata;
-import org.apache.commons.imaging.common.RationalNumber;
-import org.apache.commons.imaging.formats.jpeg.JpegImageMetadata;
-import org.apache.commons.imaging.formats.tiff.TiffField;
-import org.apache.commons.imaging.formats.tiff.constants.ExifTagConstants;
-import org.apache.commons.imaging.formats.tiff.constants.GpsTagConstants;
 import org.openstreetmap.josm.Main;
 import org.openstreetmap.josm.actions.JosmAction;
 import org.openstreetmap.josm.plugins.mapillary.MapillaryAbstractImage;
-import org.openstreetmap.josm.plugins.mapillary.MapillaryImportedImage;
 import org.openstreetmap.josm.plugins.mapillary.MapillaryLayer;
 import org.openstreetmap.josm.plugins.mapillary.MapillaryPlugin;
@@ -86,12 +78,8 @@
         if (file.isDirectory()) {
           for (int j = 0; j < file.listFiles().length; j++) {
-            int k = file.listFiles()[j].getName().lastIndexOf('.');
-            String extension = null;
-            if (k > 0) {
-              extension = file.listFiles()[j].getName().substring(k + 1);
-            }
+            String extension = MapillaryUtils.getExtension(file.listFiles()[j]);
             try {
               if (extension.equals("jpg") || extension.equals("jpeg"))
-                readJPG(file.listFiles()[j]);
+                MapillaryUtils.readJPG(file.listFiles()[j], true);
             } catch (ImageReadException | NullPointerException | IOException e) {
               Main.error(e);
@@ -99,14 +87,14 @@
           }
         } else {
-          if (file.getPath().substring(file.getPath().length() - 4)
-              .equals(".jpg")
-              || file.getPath().substring(file.getPath().length() - 5)
-                  .equals(".jpeg")) {
+          String extension = MapillaryUtils.getExtension(file);
+          if (extension.equals("jpg") || extension.equals("jpeg")) {
             try {
-              readJPG(file);
+              this.images.add(MapillaryUtils.readJPG(file, true));
             } catch (ImageReadException ex) {
               Main.error(ex);
             } catch (IOException ex) {
               Main.error(ex);
+            } catch (IllegalArgumentException ex) {
+              // Ignored image.
             }
           }
@@ -117,53 +105,4 @@
     }
     MapillaryUtils.showAllPictures();
-  }
-
-  /**
-   * Reads a JPG pictures that contains the needed GPS information (position and
-   * direction) and creates a new icon in that position.
-   *
-   * @param file
-   *          The file where the image is located.
-   * @throws ImageReadException
-   *           If the file doesn't contain an image.
-   * @throws IOException
-   *           If the file doesn't contain valid metadata.
-   */
-  public void readJPG(File file) throws ImageReadException, IOException {
-    final ImageMetadata metadata = Imaging.getMetadata(file);
-    if (metadata instanceof JpegImageMetadata) {
-      final JpegImageMetadata jpegMetadata = (JpegImageMetadata) metadata;
-      final TiffField lat_ref = jpegMetadata
-          .findEXIFValueWithExactMatch(GpsTagConstants.GPS_TAG_GPS_LATITUDE_REF);
-      final TiffField lat = jpegMetadata
-          .findEXIFValueWithExactMatch(GpsTagConstants.GPS_TAG_GPS_LATITUDE);
-      final TiffField lon_ref = jpegMetadata
-          .findEXIFValueWithExactMatch(GpsTagConstants.GPS_TAG_GPS_LONGITUDE_REF);
-      final TiffField lon = jpegMetadata
-          .findEXIFValueWithExactMatch(GpsTagConstants.GPS_TAG_GPS_LONGITUDE);
-      final TiffField ca = jpegMetadata
-          .findEXIFValueWithExactMatch(GpsTagConstants.GPS_TAG_GPS_IMG_DIRECTION);
-      final TiffField datetimeOriginal = jpegMetadata
-          .findEXIFValueWithExactMatch(ExifTagConstants.EXIF_TAG_DATE_TIME_ORIGINAL);
-      if (lat_ref == null || lat == null || lon == null || lon_ref == null
-          || datetimeOriginal == null)
-        return;
-
-      double latValue = 0;
-      double lonValue = 0;
-      double caValue = 0;
-      if (lat.getValue() instanceof RationalNumber[])
-        latValue = MapillaryUtils.degMinSecToDouble(
-            (RationalNumber[]) lat.getValue(), lat_ref.getValue().toString());
-      if (lon.getValue() instanceof RationalNumber[])
-        lonValue = MapillaryUtils.degMinSecToDouble(
-            (RationalNumber[]) lon.getValue(), lon_ref.getValue().toString());
-      if (ca != null && ca.getValue() instanceof RationalNumber)
-        caValue = ((RationalNumber) ca.getValue()).doubleValue();
-
-      MapillaryImportedImage image = new MapillaryImportedImage(latValue,
-          lonValue, caValue, file, datetimeOriginal.getStringValue());
-      this.images.add(image);
-    }
   }
 
Index: /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/actions/MapillaryJoinAction.java
===================================================================
--- /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/actions/MapillaryJoinAction.java	(revision 31511)
+++ /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/actions/MapillaryJoinAction.java	(revision 31512)
@@ -14,5 +14,5 @@
 
 /**
- * Changes the mode of the Layer, from Select mode to Join mode and viceversa.
+ * Changes the mode of the Layer, from Select mode to Join mode and vice versa.
  *
  * @author nokutu
@@ -36,9 +36,8 @@
   @Override
   public void actionPerformed(ActionEvent arg0) {
-    if (MapillaryLayer.getInstance().mode instanceof SelectMode) {
+    if (MapillaryLayer.getInstance().mode instanceof SelectMode)
       MapillaryLayer.getInstance().setMode(new JoinMode());
-    } else {
+    else
       MapillaryLayer.getInstance().setMode(new SelectMode());
-    }
   }
 }
Index: /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/actions/MapillaryUploadAction.java
===================================================================
--- /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/actions/MapillaryUploadAction.java	(revision 31511)
+++ /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/actions/MapillaryUploadAction.java	(revision 31512)
@@ -21,4 +21,7 @@
 
 /**
+ * Action called when an upload to the Mapillary servers is going to be
+ * performed. It lets you select a couple of options.
+ *
  * @author nokutu
  *
@@ -60,5 +63,4 @@
   @Override
   public void imagesAdded() {
-    // Nothing
   }
 
@@ -71,4 +73,3 @@
       MapillaryPlugin.setMenuEnabled(MapillaryPlugin.UPLOAD_MENU, false);
   }
-
 }
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 31511)
+++ /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/downloads/MapillarySquareDownloadManagerThread.java	(revision 31512)
@@ -95,4 +95,10 @@
   }
 
+  /**
+   * Downloads the sequence positions, directions and keys.
+   *
+   * @throws InterruptedException
+   *           if the thread is interrupted while running this method.
+   */
   private void downloadSequences() throws InterruptedException {
     int page = 0;
@@ -109,4 +115,10 @@
   }
 
+  /**
+   * Downloads the image's author's username and the image's location.
+   *
+   * @throws InterruptedException
+   *           if the thread is interrupted while running this method.
+   */
   private void completeImages() throws InterruptedException {
     int page = 0;
@@ -122,4 +134,10 @@
   }
 
+  /**
+   * Downloads the traffic signs in the images.
+   *
+   * @throws InterruptedException
+   *           if the thread is interrupted while running this method.
+   */
   private void downloadSigns() throws InterruptedException {
     int page = 0;
Index: /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/gui/HyperlinkLabel.java
===================================================================
--- /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/gui/HyperlinkLabel.java	(revision 31511)
+++ /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/gui/HyperlinkLabel.java	(revision 31512)
@@ -34,4 +34,5 @@
   private String text;
   private URL url;
+  private String key;
 
   /**
@@ -63,4 +64,5 @@
    */
   public void setURL(String key) {
+    this.key = key;
     if (key == null) {
       this.url = null;
@@ -110,10 +112,20 @@
     private static final long serialVersionUID = 1384054752970921552L;
 
-    JMenuItem copy;
+    private JMenuItem copy;
+    private JMenuItem copyTag;
+    private JMenuItem edit;
 
     public LinkPopUp() {
-      this.copy = new JMenuItem("Copy key");
+      this.copy = new JMenuItem(tr("Copy key"));
       this.copy.addActionListener(new copyAction());
       add(this.copy);
+
+      this.copyTag = new JMenuItem(tr("Copy key tag"));
+      this.copyTag.addActionListener(new copyTagAction());
+      add(this.copyTag);
+
+      this.edit = new JMenuItem(tr("Edit on webpage"));
+      this.edit.addActionListener(new editAction());
+      add(this.edit);
     }
 
@@ -128,5 +140,30 @@
         clpbrd.setContents(stringSelection, null);
       }
-
+    }
+
+    private class copyTagAction implements ActionListener {
+
+      @Override
+      public void actionPerformed(ActionEvent arg0) {
+        StringSelection stringSelection = new StringSelection(
+            "mapillary="
+                + ((MapillaryImage) MapillaryMainDialog.getInstance()
+                    .getImage()).getKey());
+        Clipboard clpbrd = Toolkit.getDefaultToolkit().getSystemClipboard();
+        clpbrd.setContents(stringSelection, null);
+      }
+    }
+
+    private class editAction implements ActionListener {
+
+      @Override
+      public void actionPerformed(ActionEvent arg0) {
+        try {
+          MapillaryUtils.browse(new URL("http://www.mapillary.com/map/e/"
+              + HyperlinkLabel.this.key));
+        } catch (MalformedURLException e) {
+          Main.error(e);
+        }
+      }
     }
   }
Index: /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/mode/SelectMode.java
===================================================================
--- /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/mode/SelectMode.java	(revision 31511)
+++ /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/mode/SelectMode.java	(revision 31512)
@@ -53,5 +53,5 @@
       return;
     MapillaryAbstractImage closest = getClosest(e.getPoint());
-    if (Main.map.mapView.getActiveLayer() instanceof OsmDataLayer
+    if (!(Main.map.mapView.getActiveLayer() instanceof MapillaryLayer)
         && closest != null && Main.map.mapMode == Main.map.mapModeSelect) {
       this.lastClicked = this.closest;
Index: /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/oauth/MapillaryUser.java
===================================================================
--- /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/oauth/MapillaryUser.java	(revision 31511)
+++ /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/oauth/MapillaryUser.java	(revision 31512)
@@ -8,4 +8,6 @@
 
 /**
+ * Represents the current logged in user and stores its data.
+ *
  * @author nokutu
  *
@@ -38,5 +40,4 @@
         isTokenValid = false;
       }
-
     return username;
   }
Index: /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/oauth/OAuthPortListener.java
===================================================================
--- /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/oauth/OAuthPortListener.java	(revision 31511)
+++ /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/oauth/OAuthPortListener.java	(revision 31512)
@@ -15,5 +15,6 @@
 
 /**
- * Listens to the OAuth port in order to get the access token.
+ * Listens to the OAuth port (8763) in order to get the access token and sends
+ * back a simple reply.
  *
  * @author nokutu
@@ -66,5 +67,4 @@
         Main.info("The username is: " + MapillaryUser.getUsername());
       }
-
     } catch (BindException e) {
       return;
Index: /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/oauth/UploadUtils.java
===================================================================
--- /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/oauth/UploadUtils.java	(revision 31511)
+++ /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/oauth/UploadUtils.java	(revision 31512)
@@ -265,4 +265,5 @@
         ((MapillaryImportedImage) image).getDate("yyyy/MM/dd hh:mm:ss"));
 
+    // Removes the ImageDescription tag, that causes problems in the upload.
     rootDirectory.removeField(TiffTagConstants.TIFF_TAG_IMAGE_DESCRIPTION);
 
Index: /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/utils/MapillaryUtils.java
===================================================================
--- /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/utils/MapillaryUtils.java	(revision 31511)
+++ /applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/utils/MapillaryUtils.java	(revision 31512)
@@ -4,4 +4,5 @@
 
 import java.awt.Desktop;
+import java.io.File;
 import java.io.IOException;
 import java.net.URISyntaxException;
@@ -14,5 +15,11 @@
 import javax.swing.SwingUtilities;
 
+import org.apache.commons.imaging.ImageReadException;
+import org.apache.commons.imaging.Imaging;
+import org.apache.commons.imaging.common.ImageMetadata;
 import org.apache.commons.imaging.common.RationalNumber;
+import org.apache.commons.imaging.formats.jpeg.JpegImageMetadata;
+import org.apache.commons.imaging.formats.tiff.TiffField;
+import org.apache.commons.imaging.formats.tiff.constants.ExifTagConstants;
 import org.apache.commons.imaging.formats.tiff.constants.GpsTagConstants;
 import org.openstreetmap.josm.Main;
@@ -21,4 +28,5 @@
 import org.openstreetmap.josm.plugins.mapillary.MapillaryAbstractImage;
 import org.openstreetmap.josm.plugins.mapillary.MapillaryData;
+import org.openstreetmap.josm.plugins.mapillary.MapillaryImportedImage;
 import org.openstreetmap.josm.plugins.mapillary.MapillaryLayer;
 import org.openstreetmap.josm.plugins.mapillary.MapillarySequence;
@@ -33,4 +41,6 @@
 
   private static double MIN_ZOOM_SQUARE_SIDE = 0.002;
+
+  private static int noTagsPics = 0;
 
   /**
@@ -281,3 +291,148 @@
     return formatter.format(cal.getTime());
   }
+
+  /**
+   * Reads a JPG pictures that contains the needed GPS information (position and
+   * direction) and creates a new icon in that position.
+   *
+   * @param file
+   *          The file where the picture is located.
+   * @return The imported image.
+   * @throws ImageReadException
+   *           If the file isn't an image.
+   * @throws IOException
+   *           If the file doesn't have the valid metadata.
+   */
+  public static MapillaryImportedImage readJPG(File file) throws IOException,
+      ImageReadException {
+    return readJPG(file, false);
+  }
+
+  /**
+   * Reads a JPG pictures that contains the needed GPS information (position and
+   * direction) and creates a new icon in that position.
+   *
+   * @param file
+   *          The {@link File} where the picture is located.
+   * @param exceptionNoTags
+   *          {@code true} if an exception must be thrown if the image doesn't
+   *          have all the needed EXIF tags; {@code false} returns an image in
+   *          the center of the screen.
+   * @return The imported image.
+   * @throws ImageReadException
+   *           If the {@link File} isn't an image.
+   * @throws IOException
+   *           If the {@link File} doesn't have the valid metadata.
+   * @throws IllegalArgumentException
+   *           if exceptionNoTags is set to {@code true} and the image doesn't
+   *           have the needed EXIF tags.
+   */
+  public static MapillaryImportedImage readJPG(File file,
+      boolean exceptionNoTags) throws IOException, ImageReadException {
+    final ImageMetadata metadata = Imaging.getMetadata(file);
+    if (metadata instanceof JpegImageMetadata) {
+      final JpegImageMetadata jpegMetadata = (JpegImageMetadata) metadata;
+      final TiffField lat_ref = jpegMetadata
+          .findEXIFValueWithExactMatch(GpsTagConstants.GPS_TAG_GPS_LATITUDE_REF);
+      final TiffField lat = jpegMetadata
+          .findEXIFValueWithExactMatch(GpsTagConstants.GPS_TAG_GPS_LATITUDE);
+      final TiffField lon_ref = jpegMetadata
+          .findEXIFValueWithExactMatch(GpsTagConstants.GPS_TAG_GPS_LONGITUDE_REF);
+      final TiffField lon = jpegMetadata
+          .findEXIFValueWithExactMatch(GpsTagConstants.GPS_TAG_GPS_LONGITUDE);
+      final TiffField ca = jpegMetadata
+          .findEXIFValueWithExactMatch(GpsTagConstants.GPS_TAG_GPS_IMG_DIRECTION);
+      final TiffField datetimeOriginal = jpegMetadata
+          .findEXIFValueWithExactMatch(ExifTagConstants.EXIF_TAG_DATE_TIME_ORIGINAL);
+      if (lat_ref == null || lat == null || lon == null || lon_ref == null) {
+        if (exceptionNoTags)
+          throw new IllegalArgumentException(
+              "The image doesn't have the needed EXIF tags.");
+        else
+          return readNoTags(file);
+      }
+      double latValue = 0;
+      double lonValue = 0;
+      double caValue = 0;
+      if (lat.getValue() instanceof RationalNumber[])
+        latValue = MapillaryUtils.degMinSecToDouble(
+            (RationalNumber[]) lat.getValue(), lat_ref.getValue().toString());
+      if (lon.getValue() instanceof RationalNumber[])
+        lonValue = MapillaryUtils.degMinSecToDouble(
+            (RationalNumber[]) lon.getValue(), lon_ref.getValue().toString());
+      if (ca != null && ca.getValue() instanceof RationalNumber)
+        caValue = ((RationalNumber) ca.getValue()).doubleValue();
+      if (datetimeOriginal != null)
+        return new MapillaryImportedImage(latValue, lonValue, caValue, file,
+            datetimeOriginal.getStringValue());
+      else
+        return new MapillaryImportedImage(latValue, lonValue, caValue, file);
+    }
+    throw new IllegalStateException("Invalid format.");
+  }
+
+  /**
+   * Reads a image file that doesn't contain the needed GPS information. And
+   * creates a new icon in the middle of the map.
+   *
+   * @param file
+   *          The file where the image is located.
+   * @param pos
+   *          A {@link LatLon} object indicating the position in the map where
+   *          the image must be set.
+   * @return The imported image.
+   */
+  public static MapillaryImportedImage readNoTags(File file, LatLon pos) {
+    double HORIZONTAL_DISTANCE = 0.0001;
+    double horDev;
+    if (noTagsPics % 2 == 0)
+      horDev = HORIZONTAL_DISTANCE * noTagsPics / 2;
+    else
+      horDev = -HORIZONTAL_DISTANCE * ((noTagsPics + 1) / 2);
+    noTagsPics++;
+    return new MapillaryImportedImage(pos.lat(), pos.lon() + horDev, 0, file);
+  }
+
+  /**
+   * Reads an image in PNG format.
+   *
+   * @param file
+   *          The file where the image is located.
+   * @return The imported image.
+   */
+  public static MapillaryImportedImage readPNG(File file) {
+    return readNoTags(file);
+  }
+
+  /**
+   * Reads a image file that doesn't contain the needed GPS information. And
+   * creates a new icon in the middle of the map.
+   *
+   * @param file
+   *          The file where the image is located.
+   * @return The imported image.
+   */
+  public static MapillaryImportedImage readNoTags(File file) {
+    return readNoTags(
+        file,
+        Main.map.mapView.getProjection().eastNorth2latlon(
+            Main.map.mapView.getCenter()));
+  }
+
+  /**
+   * Returns the extension of a {@link File} object.
+   *
+   * @param file
+   *          The {@link File} object whose extension is going to be returned.
+   * @return A {@code String} object containing the extension.
+   */
+  public static String getExtension(File file) {
+    if (file.isDirectory())
+      throw new IllegalArgumentException("The file is a directory");
+    int k = file.getName().lastIndexOf('.');
+    if (k > 0) {
+      return file.getName().substring(k + 1).toLowerCase();
+    }
+    throw new IllegalArgumentException("Error parsing the extension");
+  }
 }
Index: /applications/editors/josm/plugins/mapillary/test/unit/org/openstreetmap/josm/plugins/mapillary/ImportTest.java
===================================================================
--- /applications/editors/josm/plugins/mapillary/test/unit/org/openstreetmap/josm/plugins/mapillary/ImportTest.java	(revision 31511)
+++ /applications/editors/josm/plugins/mapillary/test/unit/org/openstreetmap/josm/plugins/mapillary/ImportTest.java	(revision 31512)
@@ -11,5 +11,5 @@
 
 import org.openstreetmap.josm.data.coor.LatLon;
-import org.openstreetmap.josm.plugins.mapillary.actions.MapillaryImportAction;
+import org.openstreetmap.josm.plugins.mapillary.utils.MapillaryUtils;
 
 /**
@@ -27,5 +27,5 @@
   public void importNoTagsTest() {
     File image = new File("images/icon16.png");
-    MapillaryImportedImage img = new MapillaryImportAction().readNoTags(image,
+    MapillaryImportedImage img = MapillaryUtils.readNoTags(image,
         new LatLon(0, 0));
     assertEquals(0, img.getCa(), 0.01);
Index: /applications/editors/josm/plugins/mapillary/test/unit/org/openstreetmap/josm/plugins/mapillary/oauth/UploadTest.java
===================================================================
--- /applications/editors/josm/plugins/mapillary/test/unit/org/openstreetmap/josm/plugins/mapillary/oauth/UploadTest.java	(revision 31511)
+++ /applications/editors/josm/plugins/mapillary/test/unit/org/openstreetmap/josm/plugins/mapillary/oauth/UploadTest.java	(revision 31512)
@@ -20,5 +20,4 @@
 import org.openstreetmap.josm.plugins.mapillary.AbstractTest;
 import org.openstreetmap.josm.plugins.mapillary.MapillaryImportedImage;
-import org.openstreetmap.josm.plugins.mapillary.actions.MapillaryImportAction;
 import org.openstreetmap.josm.plugins.mapillary.oauth.UploadUtils;
 import org.openstreetmap.josm.plugins.mapillary.utils.MapillaryUtils;
@@ -38,5 +37,5 @@
   public void updateFileTest() {
     File image = new File("images/icon16.png");
-    MapillaryImportedImage img = new MapillaryImportAction().readNoTags(image,
+    MapillaryImportedImage img = MapillaryUtils.readNoTags(image,
         new LatLon(0, 0));
     File updatedFile = null;
