Merge branch 'stable-2.6' into stable-2.7

* stable-2.6:
  Work around MySQL refusing to be case sensitive
  Reference included plugins by absolute Urls
  Fix PatchScript's mapping of lines below the last edit
  Fix refreshing PatchScreen when fileList has not yet been loaded
  Fix login servlets when canonicalWebUrl is not set
diff --git a/.gitmodules b/.gitmodules
index 32483d6..0f7fdab 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,11 +1,11 @@
 [submodule "plugins/replication"]
 	path = plugins/replication
-	url = ../plugins/replication
+	url = https://gerrit.googlesource.com/plugins/replication
 
 [submodule "plugins/reviewnotes"]
 	path = plugins/reviewnotes
-	url = ../plugins/reviewnotes
+	url = https://gerrit.googlesource.com/plugins/reviewnotes
 
 [submodule "plugins/commit-message-length-validator"]
 	path = plugins/commit-message-length-validator
-	url = ../plugins/commit-message-length-validator
+	url = https://gerrit.googlesource.com/plugins/commit-message-length-validator
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/PatchTable.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/PatchTable.java
index d47e2c1..6c14740 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/PatchTable.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/PatchTable.java
@@ -169,7 +169,9 @@
   }
 
   public void movePointerTo(final Patch.Key k) {
-    myTable.movePointerTo(k);
+    if (myTable != null) {
+      myTable.movePointerTo(k);
+    }
   }
 
   public void setActive(boolean active) {
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchScreen.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchScreen.java
index 4e24742..200562a 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchScreen.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/PatchScreen.java
@@ -366,7 +366,7 @@
     lastScript = null;
     settingsPanel.setEnabled(false);
     reviewedPanels.populate(patchKey, fileList, patchIndex, getPatchScreenType());
-    if (isFirst && fileList != null) {
+    if (isFirst && fileList != null && fileList.isLoaded()) {
       fileList.movePointerTo(patchKey);
     }
 
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/CanonicalWebUrl.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/CanonicalWebUrl.java
new file mode 100644
index 0000000..61c0cd1
--- /dev/null
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/CanonicalWebUrl.java
@@ -0,0 +1,47 @@
+// Copyright (C) 2013 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.httpd;
+
+import javax.annotation.Nullable;
+import javax.servlet.http.HttpServletRequest;
+
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+
+public class CanonicalWebUrl {
+  private final Provider<String> configured;
+
+  @Inject
+  CanonicalWebUrl(
+      @com.google.gerrit.server.config.CanonicalWebUrl
+      @Nullable
+      Provider<String> provider) {
+    configured = provider;
+  }
+
+  public String get(HttpServletRequest req) {
+    String url = configured.get();
+    return url != null ? url : computeFromRequest(req);
+  }
+
+  static String computeFromRequest(HttpServletRequest req) {
+    StringBuffer url = req.getRequestURL();
+    url.setLength(url.length() - req.getServletPath().length());
+    if (url.charAt(url.length() - 1) != '/') {
+      url.append('/');
+    }
+    return url.toString();
+  }
+}
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/HttpCanonicalWebUrlProvider.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/HttpCanonicalWebUrlProvider.java
index 5df678b..5196e9c 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/HttpCanonicalWebUrlProvider.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/HttpCanonicalWebUrlProvider.java
@@ -14,7 +14,6 @@
 
 package com.google.gerrit.httpd;
 
-import com.google.gerrit.server.config.CanonicalWebUrl;
 import com.google.gerrit.server.config.CanonicalWebUrlProvider;
 import com.google.gerrit.server.config.GerritServerConfig;
 import com.google.inject.Inject;
@@ -26,7 +25,7 @@
 
 import javax.servlet.http.HttpServletRequest;
 
-/** Sets {@link CanonicalWebUrl} to current HTTP request if not configured. */
+/** Sets {@code CanonicalWebUrl} to current HTTP request if not configured. */
 public class HttpCanonicalWebUrlProvider extends CanonicalWebUrlProvider {
   private Provider<HttpServletRequest> requestProvider;
 
@@ -65,13 +64,7 @@
           throw noWeb;
         }
       }
-
-      final StringBuffer url = req.getRequestURL();
-      url.setLength(url.length() - req.getServletPath().length());
-      if (url.charAt(url.length() - 1) != '/') {
-        url.append('/');
-      }
-      return url.toString();
+      return CanonicalWebUrl.computeFromRequest(req);
     }
 
     // We have no way of guessing our HTTP url.
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/auth/container/HttpLoginServlet.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/auth/container/HttpLoginServlet.java
index 696a585..fe7aa23 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/auth/container/HttpLoginServlet.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/auth/container/HttpLoginServlet.java
@@ -15,13 +15,13 @@
 package com.google.gerrit.httpd.auth.container;
 
 import com.google.gerrit.common.PageLinks;
+import com.google.gerrit.httpd.CanonicalWebUrl;
 import com.google.gerrit.httpd.HtmlDomUtil;
 import com.google.gerrit.httpd.WebSession;
 import com.google.gerrit.server.account.AccountException;
 import com.google.gerrit.server.account.AccountManager;
 import com.google.gerrit.server.account.AuthRequest;
 import com.google.gerrit.server.account.AuthResult;
-import com.google.gerrit.server.config.CanonicalWebUrl;
 import com.google.gwtexpui.server.CacheHeaders;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
@@ -57,13 +57,13 @@
       LoggerFactory.getLogger(HttpLoginServlet.class);
 
   private final Provider<WebSession> webSession;
-  private final Provider<String> urlProvider;
+  private final CanonicalWebUrl urlProvider;
   private final AccountManager accountManager;
   private final HttpAuthFilter authFilter;
 
   @Inject
   HttpLoginServlet(final Provider<WebSession> webSession,
-      @CanonicalWebUrl @Nullable final Provider<String> urlProvider,
+      final CanonicalWebUrl urlProvider,
       final AccountManager accountManager,
       final HttpAuthFilter authFilter) {
     this.webSession = webSession;
@@ -121,7 +121,7 @@
     }
 
     final StringBuilder rdr = new StringBuilder();
-    rdr.append(urlProvider.get());
+    rdr.append(urlProvider.get(req));
     rdr.append('#');
     if (arsp.isNew() && !token.startsWith(PageLinks.REGISTER + "/")) {
       rdr.append(PageLinks.REGISTER);
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/auth/ldap/LdapLoginServlet.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/auth/ldap/LdapLoginServlet.java
index cfae86c..9a2a7da 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/auth/ldap/LdapLoginServlet.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/auth/ldap/LdapLoginServlet.java
@@ -17,6 +17,7 @@
 import com.google.common.base.Objects;
 import com.google.common.base.Strings;
 import com.google.gerrit.common.PageLinks;
+import com.google.gerrit.httpd.CanonicalWebUrl;
 import com.google.gerrit.httpd.HtmlDomUtil;
 import com.google.gerrit.httpd.WebSession;
 import com.google.gerrit.httpd.template.SiteHeaderFooter;
@@ -26,7 +27,7 @@
 import com.google.gerrit.server.account.AuthRequest;
 import com.google.gerrit.server.account.AuthResult;
 import com.google.gerrit.server.auth.AuthenticationUnavailableException;
-import com.google.gerrit.server.config.CanonicalWebUrl;
+import com.google.gerrit.server.config.SitePaths;
 import com.google.gwtexpui.server.CacheHeaders;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
@@ -55,28 +56,24 @@
 
   private final AccountManager accountManager;
   private final Provider<WebSession> webSession;
-  private final Provider<String> urlProvider;
+  private final CanonicalWebUrl urlProvider;
   private final SiteHeaderFooter headers;
 
   @Inject
   LdapLoginServlet(AccountManager accountManager,
       Provider<WebSession> webSession,
-      @CanonicalWebUrl @Nullable Provider<String> urlProvider,
+      CanonicalWebUrl urlProvider,
       SiteHeaderFooter headers) {
     this.accountManager = accountManager;
     this.webSession = webSession;
     this.urlProvider = urlProvider;
     this.headers = headers;
-
-    if (Strings.isNullOrEmpty(urlProvider.get())) {
-      log.error("gerrit.canonicalWebUrl must be set in gerrit.config");
-    }
   }
 
   private void sendForm(HttpServletRequest req, HttpServletResponse res,
       @Nullable String errorMessage) throws IOException {
     String self = req.getRequestURI();
-    String cancel = Objects.firstNonNull(urlProvider.get(), "/");
+    String cancel = Objects.firstNonNull(urlProvider.get(req), "/");
     String token = getToken(req);
     if (!token.equals("/")) {
       cancel += "#" + token;
@@ -146,11 +143,10 @@
       return;
     }
 
-    String token = getToken(req);
     StringBuilder dest = new StringBuilder();
-    dest.append(urlProvider.get());
+    dest.append(urlProvider.get(req));
     dest.append('#');
-    dest.append(token);
+    dest.append(getToken(req));
 
     CacheHeaders.setNotCacheable(res);
     webSession.get().login(ares, "1".equals(remember));
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/patch/PatchScriptBuilder.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/patch/PatchScriptBuilder.java
index 5019403..9a4b89f 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/patch/PatchScriptBuilder.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/patch/PatchScriptBuilder.java
@@ -346,7 +346,7 @@
     }
 
     final Edit last = edits.get(edits.size() - 1);
-    return last.getBeginB() + (a - last.getEndA());
+    return last.getEndB() + (a - last.getEndA());
   }
 
   private int mapB2A(final int b) {
@@ -372,7 +372,7 @@
     }
 
     final Edit last = edits.get(edits.size() - 1);
-    return last.getBeginA() + (b - last.getEndB());
+    return last.getEndA() + (b - last.getEndB());
   }
 
   private void packContent(boolean ignoredWhitespace) {
diff --git a/gerrit-openid/src/main/java/com/google/gerrit/httpd/auth/openid/LoginForm.java b/gerrit-openid/src/main/java/com/google/gerrit/httpd/auth/openid/LoginForm.java
index b8d31ee..678ec00 100644
--- a/gerrit-openid/src/main/java/com/google/gerrit/httpd/auth/openid/LoginForm.java
+++ b/gerrit-openid/src/main/java/com/google/gerrit/httpd/auth/openid/LoginForm.java
@@ -161,7 +161,7 @@
       remember = false;
     }
 
-    DiscoveryResult r = impl.discover(id, mode, remember, token);
+    DiscoveryResult r = impl.discover(req, id, mode, remember, token);
     switch (r.status) {
       case VALID:
         redirect(r, res);
diff --git a/gerrit-openid/src/main/java/com/google/gerrit/httpd/auth/openid/OpenIdServiceImpl.java b/gerrit-openid/src/main/java/com/google/gerrit/httpd/auth/openid/OpenIdServiceImpl.java
index 52f3b03..5d74166 100644
--- a/gerrit-openid/src/main/java/com/google/gerrit/httpd/auth/openid/OpenIdServiceImpl.java
+++ b/gerrit-openid/src/main/java/com/google/gerrit/httpd/auth/openid/OpenIdServiceImpl.java
@@ -16,6 +16,7 @@
 
 import com.google.gerrit.common.PageLinks;
 import com.google.gerrit.common.auth.openid.OpenIdUrls;
+import com.google.gerrit.httpd.CanonicalWebUrl;
 import com.google.gerrit.httpd.WebSession;
 import com.google.gerrit.reviewdb.client.Account;
 import com.google.gerrit.server.IdentifiedUser;
@@ -24,7 +25,6 @@
 import com.google.gerrit.server.account.AccountManager;
 import com.google.gerrit.server.auth.openid.OpenIdProviderPattern;
 import com.google.gerrit.server.config.AuthConfig;
-import com.google.gerrit.server.config.CanonicalWebUrl;
 import com.google.gerrit.server.config.ConfigUtil;
 import com.google.gerrit.server.config.GerritServerConfig;
 import com.google.gwtorm.client.KeyUtil;
@@ -63,7 +63,6 @@
 import java.util.List;
 import java.util.concurrent.TimeUnit;
 
-import javax.annotation.Nullable;
 import javax.servlet.http.Cookie;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
@@ -93,7 +92,7 @@
 
   private final Provider<WebSession> webSession;
   private final Provider<IdentifiedUser> identifiedUser;
-  private final Provider<String> urlProvider;
+  private final CanonicalWebUrl urlProvider;
   private final AccountManager accountManager;
   private final ConsumerManager manager;
   private final List<OpenIdProviderPattern> allowedOpenIDs;
@@ -105,7 +104,7 @@
   @Inject
   OpenIdServiceImpl(final Provider<WebSession> cf,
       final Provider<IdentifiedUser> iu,
-      @CanonicalWebUrl @Nullable final Provider<String> up,
+      CanonicalWebUrl up,
       @GerritServerConfig final Config config, final AuthConfig ac,
       final AccountManager am) throws ConsumerException, MalformedURLException {
 
@@ -145,10 +144,10 @@
   }
 
   @SuppressWarnings("unchecked")
-  DiscoveryResult discover(final String openidIdentifier, final SignInMode mode,
-      final boolean remember, final String returnToken) {
+  DiscoveryResult discover(HttpServletRequest req, String openidIdentifier,
+      final SignInMode mode, final boolean remember, final String returnToken) {
     final State state;
-    state = init(openidIdentifier, mode, remember, returnToken);
+    state = init(req, openidIdentifier, mode, remember, returnToken);
     if (state == null) {
       return new DiscoveryResult(DiscoveryResult.Status.NO_PROVIDER);
     }
@@ -235,7 +234,7 @@
       return;
     }
 
-    state = init(rediscoverIdentifier, mode, remember, returnToken);
+    state = init(req, rediscoverIdentifier, mode, remember, returnToken);
     if (state == null) {
       // Re-discovery must have failed, we can't run a login.
       //
@@ -482,7 +481,7 @@
     }
 
     final StringBuilder rdr = new StringBuilder();
-    rdr.append(urlProvider.get());
+    rdr.append(urlProvider.get(req));
     rdr.append('#');
     if (isNew && !token.startsWith(PageLinks.REGISTER + "/")) {
       rdr.append(PageLinks.REGISTER);
@@ -507,7 +506,7 @@
       webSession.get().logout();
     }
     final StringBuilder rdr = new StringBuilder();
-    rdr.append(urlProvider.get());
+    rdr.append(urlProvider.get(req));
     rdr.append('#');
     rdr.append("SignInFailure");
     rdr.append(',');
@@ -517,8 +516,8 @@
     rsp.sendRedirect(rdr.toString());
   }
 
-  private State init(final String openidIdentifier, final SignInMode mode,
-      final boolean remember, final String returnToken) {
+  private State init(HttpServletRequest req, final String openidIdentifier,
+      final SignInMode mode, final boolean remember, final String returnToken) {
     final List<?> list;
     try {
       list = manager.discover(openidIdentifier);
@@ -530,7 +529,7 @@
       return null;
     }
 
-    final String contextUrl = urlProvider.get();
+    final String contextUrl = urlProvider.get(req);
     final DiscoveryInformation discovered = manager.associate(list);
     final UrlEncoded retTo = new UrlEncoded(contextUrl + RETURN_URL);
     retTo.put(P_MODE, mode.name());
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/ChangeUtil.java b/gerrit-server/src/main/java/com/google/gerrit/server/ChangeUtil.java
index 2d1707c..bfa4e8f 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/ChangeUtil.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/ChangeUtil.java
@@ -14,7 +14,6 @@
 
 package com.google.gerrit.server;
 
-import com.google.common.base.CharMatcher;
 import com.google.gerrit.common.ChangeHooks;
 import com.google.gerrit.common.data.LabelTypes;
 import com.google.gerrit.common.errors.EmailException;
@@ -63,9 +62,7 @@
 import org.eclipse.jgit.revwalk.RevCommit;
 import org.eclipse.jgit.revwalk.RevWalk;
 import org.eclipse.jgit.transport.ReceiveCommand;
-import org.eclipse.jgit.util.Base64;
 import org.eclipse.jgit.util.ChangeIdUtil;
-import org.eclipse.jgit.util.NB;
 
 import java.io.IOException;
 import java.sql.Timestamp;
@@ -80,6 +77,8 @@
 import java.util.regex.Matcher;
 
 public class ChangeUtil {
+  private static final Object uuidLock = new Object();
+  private static final int SEED = 0x2418e6f9;
   private static int uuidPrefix;
   private static int uuidSeq;
 
@@ -91,25 +90,19 @@
    * @return the new unique identifier.
    * @throws OrmException the database couldn't be incremented.
    */
-  public static String messageUUID(final ReviewDb db) throws OrmException {
-    final byte[] raw = new byte[8];
-    fill(raw, db);
-
-    // Make the resulting base64 string more URL friendly.
-    return CharMatcher.is('A').trimLeadingFrom(
-           CharMatcher.is('=').trimTrailingFrom(Base64.encodeBytes(raw)))
-        .replace('+', '.')
-        .replace('/', '-');
-  }
-
-  private static synchronized void fill(byte[] raw, ReviewDb db)
-      throws OrmException {
-    if (uuidSeq == 0) {
-      uuidPrefix = db.nextChangeMessageId();
-      uuidSeq = Integer.MAX_VALUE;
+  public static String messageUUID(ReviewDb db) throws OrmException {
+    int p, s;
+    synchronized (uuidLock) {
+      if (uuidSeq == 0) {
+        uuidPrefix = db.nextChangeMessageId();
+        uuidSeq = Integer.MAX_VALUE;
+      }
+      p = uuidPrefix;
+      s = uuidSeq--;
     }
-    NB.encodeInt32(raw, 0, uuidPrefix);
-    NB.encodeInt32(raw, 4, IdGenerator.mix(uuidPrefix, uuidSeq--));
+    String u = IdGenerator.format(IdGenerator.mix(SEED, p));
+    String l = IdGenerator.format(IdGenerator.mix(p, s));
+    return u + '_' + l;
   }
 
   public static void touch(final Change change, ReviewDb db)