Index: trunk/src/org/openstreetmap/josm/tools/OsmUrlToBounds.java
===================================================================
--- trunk/src/org/openstreetmap/josm/tools/OsmUrlToBounds.java	(revision 2539)
+++ trunk/src/org/openstreetmap/josm/tools/OsmUrlToBounds.java	(revision 2540)
@@ -3,4 +3,5 @@
 
 import java.util.HashMap;
+import java.util.Map;
 
 import org.openstreetmap.josm.data.Bounds;
@@ -8,6 +9,10 @@
 
 public class OsmUrlToBounds {
+    private static final String SHORTLINK_PREFIX = "http://osm.org/go/";
 
     public static Bounds parse(String url) {
+        Bounds b = parseShortLink(url);
+        if (b != null)
+            return b;
         int i = url.indexOf('?');
         if (i == -1)
@@ -22,5 +27,4 @@
         }
 
-        Bounds b = null;
         try {
             if (map.containsKey("bbox")) {
@@ -40,8 +44,7 @@
                 b = new Bounds(new LatLon(minlat, minlon), new LatLon(maxlat, maxlon));
             } else {
-                double size = 180.0 / Math.pow(2, Integer.parseInt(map.get("zoom")));
-                b = new Bounds(
-                    new LatLon(parseDouble(map, "lat") - size/2, parseDouble(map, "lon") - size),
-                    new LatLon(parseDouble(map, "lat") + size/2, parseDouble(map, "lon") + size));
+                b = positionToBounds(parseDouble(map, "lat"),
+                                     parseDouble(map, "lon"),
+                                     Integer.parseInt(map.get("zoom")));
             }
         } catch (NumberFormatException x) {
@@ -55,4 +58,81 @@
             return Double.parseDouble(map.get(key));
         return Double.parseDouble(map.get("m"+key));
+    }
+
+    private static final char[] SHORTLINK_CHARS = {
+        'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
+        'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
+        'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
+        'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
+        'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
+        'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
+        'w', 'x', 'y', 'z', '0', '1', '2', '3',
+        '4', '5', '6', '7', '8', '9', '_', '@'
+    };
+
+    /**
+     * p
+     *
+     * @param url string for parsing
+     *
+     * @return Bounds if shortlink, null otherwise
+     *
+     * @see http://trac.openstreetmap.org/browser/sites/rails_port/lib/short_link.rb
+     */
+    private static Bounds parseShortLink(final String url) {
+        if (!url.startsWith(SHORTLINK_PREFIX)) {
+            return null;
+        }
+        final String shortLink = url.substring(SHORTLINK_PREFIX.length());
+
+        final Map<Character, Integer> array = new HashMap<Character, Integer>();
+
+        for (int i=0; i<SHORTLINK_CHARS.length; ++i) {
+            array.put(SHORTLINK_CHARS[i], i);
+        }
+
+        // long is necessary (need 32 bit positive value is needed)
+        long x = 0;
+        long y = 0;
+        int zoom = 0;
+        int zoomOffset = 0;
+
+        for (final char ch : shortLink.toCharArray()) {
+            if (array.containsKey(ch)) {
+                int val = array.get(ch);
+                for (int i=0; i<3; ++i) {
+                    x <<= 1;
+                    if ((val & 32) != 0) {
+                        x |= 1;
+                    }
+                    val <<= 1;
+
+                    y <<= 1;
+                    if ((val & 32) != 0) {
+                        y |= 1;
+                    }
+                    val <<= 1;
+                }
+                zoom += 3;
+            } else {
+                zoomOffset--;
+            }
+        }
+
+        x <<= 32 - zoom;
+        y <<= 32 - zoom;
+
+        // 2**32 == 4294967296
+        return positionToBounds(y * 180.0 / 4294967296.0 - 90.0,
+                                x * 360.0 / 4294967296.0 - 180.0,
+                                // TODO: -2 was not in ruby code
+                                zoom - 8 - (zoomOffset % 3) - 2);
+    }
+
+    private static Bounds positionToBounds(final double lat, final double lon, final int zoom) {
+        final double size = 180.0 / Math.pow(2, zoom);
+        return new Bounds(
+                          new LatLon(lat - size/2, lon - size),
+                          new LatLon(lat + size/2, lon + size));
     }
 
