Merge "Change border-color everywhere to #e8e8e8"
diff --git a/java/com/google/gerrit/acceptance/BUILD b/java/com/google/gerrit/acceptance/BUILD
index b23aca1..89d1f3d 100644
--- a/java/com/google/gerrit/acceptance/BUILD
+++ b/java/com/google/gerrit/acceptance/BUILD
@@ -10,13 +10,9 @@
     "//java/com/google/gerrit/exceptions",
     "//java/com/google/gerrit/gpg",
     "//java/com/google/gerrit/git",
-    "//java/com/google/gerrit/httpd/auth/openid",
     "//java/com/google/gerrit/index:query_exception",
     "//java/com/google/gerrit/launcher",
     "//java/com/google/gerrit/lifecycle",
-    "//java/com/google/gerrit/pgm",
-    "//java/com/google/gerrit/pgm/http/jetty",
-    "//java/com/google/gerrit/pgm/util",
     "//java/com/google/gerrit/common:annotations",
     "//java/com/google/gerrit/common:server",
     "//java/com/google/gerrit/entities",
@@ -50,7 +46,6 @@
     "//lib/guice",
     "//lib/guice:guice-assistedinject",
     "//lib/guice:guice-servlet",
-    "//lib/jetty:servlet",
     "//lib/mail",
     "//lib/mina:sshd",
     "//lib/log:impl-log4j",
@@ -62,6 +57,10 @@
 ]
 
 TEST_DEPS = [
+    "//java/com/google/gerrit/httpd/auth/openid",
+    "//java/com/google/gerrit/pgm",
+    "//java/com/google/gerrit/pgm/http/jetty",
+    "//java/com/google/gerrit/pgm/util",
     "//java/com/google/gerrit/truth",
     "//java/com/google/gerrit/acceptance/config",
     "//java/com/google/gerrit/acceptance/testsuite/project",
@@ -75,6 +74,13 @@
     "//java/com/google/gerrit/git/testing",
 ]
 
+PGM_DEPLOY_ENV = [
+    "//lib:caffeine",
+    "//lib:caffeine-guava",
+    "//lib/jackson:jackson-core",
+    "//lib/prolog:cafeteria",
+]
+
 java_library(
     name = "lib",
     testonly = True,
@@ -99,7 +105,7 @@
     name = "framework-deploy-env",
     testonly = True,
     main_class = "Dummy",
-    runtime_deps = DEPLOY_ENV,
+    runtime_deps = DEPLOY_ENV + PGM_DEPLOY_ENV,
 )
 
 exported_deps = [
diff --git a/java/com/google/gerrit/httpd/restapi/RestApiServlet.java b/java/com/google/gerrit/httpd/restapi/RestApiServlet.java
index a81a14e..1fd0f82 100644
--- a/java/com/google/gerrit/httpd/restapi/RestApiServlet.java
+++ b/java/com/google/gerrit/httpd/restapi/RestApiServlet.java
@@ -697,8 +697,9 @@
 
           if (status.isPresent()) {
             responseBytes = reply(req, res, e, status.get(), getUserMessages(traceContext, e));
+          } else {
+            responseBytes = replyInternalServerError(req, res, e, getUserMessages(traceContext, e));
           }
-          responseBytes = replyInternalServerError(req, res, e, getUserMessages(traceContext, e));
         }
       } finally {
         String metric = getViewName(viewData);
diff --git a/java/com/google/gerrit/server/fixes/FixCalculator.java b/java/com/google/gerrit/server/fixes/FixCalculator.java
index 5d9d2c2..9ea628e 100644
--- a/java/com/google/gerrit/server/fixes/FixCalculator.java
+++ b/java/com/google/gerrit/server/fixes/FixCalculator.java
@@ -88,7 +88,68 @@
     return String.format(
         "(%s:%s - %s:%s)", range.startLine, range.startChar, range.endLine, range.endChar);
   }
+  /*
+  Algorithm:
+  Input:
+    Original text (aka srcText)
+    Sorted list of replacements in ascending order, where each replacement has:
+        srcRange - part of the original text to be
+                   replaced, inserted or deleted (see {@link Comment.Range} for details)
+        replacement - text to be set instead of srcRange
+    Replacement ranges must not intersect.
 
+  Output:
+    Final text (aka finalText)
+    List of Edit, where each Edit is an instance of {@link ReplaceEdit}
+      Each ReplaceEdit cover one or more lines in the original text
+      Each ReplaceEdit contains one or more Edit for intraline edits
+    See {@link ReplaceEdit} and {@link Edit} for details.
+  *
+  Note: The algorithm is implemented in this way to avoid string.replace operations.
+  It has complexity O(len(replacements) + max(len(originalText), len(finalText)) )
+
+  Main steps:
+  - set srcPos to start of the original text. It is like a cursor position in the original text.
+  - set dstPos to start of the final text.  It is like a cursor position in the final text.
+  - the finalText initially empty
+
+  - for each replacement:
+       - append text between a previous and a current replacement to the finalText
+           (because replacements were sorted, this part of text can't be changed by
+             following replacements). I.e. append substring of srcText between srcPos
+             and replacement.srcRange.start to the finalText
+           Update srcPos and dstPos - set them at the end of appended text
+           (i.e. srcPos points to the position before replacement.srcRange.start,
+            dstPos points to the position where replacement.text should be inserted)
+       - set dstReplacementStart = dstPos
+       - append replacement.text to the finalText.
+           Update srcPos and dstPos accordingly (i.e. srcPos points to the position after
+           replacement.srcRange, dstPos points to the position in the finalText after
+           the appended replacement.text).
+       - set dstReplacementEnd = dstPos
+       - dstRange = (dstReplacementStart, dstReplacementEnd) - is the range in the finalText.
+       - srcRange = (replacement.Start, replacement.End) -  is the range in the original text *
+
+       - If previously created ReplaceEdit ends on the same or previous line as srcRange.startLine,
+           then intraline edit is added to it (and ReplaceEdit endLine must be updated if needed);
+           srcRange and dstRange together is used to calculate intraline Edit
+         otherwise
+          create new ReplaceEdit and add intraline Edit to it
+          srcRange and dstRange together is used to calculate intraline Edit
+
+  - append text after the last replacements,
+      i.e. add part of srcText after srcPos to the finalText
+
+  - Return the finalText and all created ReplaceEdits
+
+  Implementation notes:
+  1) The intraline Edits inside ReplaceEdit stores positions relative to ReplaceEdit start.
+  2) srcPos and dstPos tracks current position as 3 numbers:
+  - line number
+  - column number
+  - textPos - absolute position from the start of the text. The textPos is used to calculate
+  relative positions of Edit inside ReplaceEdit
+     */
   private static class ContentBuilder {
     private static class FixRegion {
       int startSrcLine;
diff --git a/lib/BUILD b/lib/BUILD
index 199f4fb..f0c0aad 100644
--- a/lib/BUILD
+++ b/lib/BUILD
@@ -114,6 +114,7 @@
     name = "caffeine",
     data = ["//lib:LICENSE-Apache2.0"],
     visibility = [
+        "//java/com/google/gerrit/acceptance:__pkg__",
         "//java/com/google/gerrit/server/cache/mem:__pkg__",
     ],
     exports = ["@caffeine//jar"],
@@ -128,6 +129,7 @@
     name = "caffeine-guava",
     data = ["//lib:LICENSE-Apache2.0"],
     visibility = [
+        "//java/com/google/gerrit/acceptance:__pkg__",
         "//java/com/google/gerrit/server/cache/mem:__pkg__",
     ],
     exports = [":caffeine-guava-renamed"],
diff --git a/lib/jackson/BUILD b/lib/jackson/BUILD
index 3eed77a..d5253a0 100644
--- a/lib/jackson/BUILD
+++ b/lib/jackson/BUILD
@@ -4,6 +4,7 @@
     name = "jackson-core",
     data = ["//lib:LICENSE-Apache2.0"],
     visibility = [
+        "//java/com/google/gerrit/acceptance:__pkg__",
         "//java/com/google/gerrit/elasticsearch:__pkg__",
         "//plugins:__pkg__",
     ],
diff --git a/polygerrit-ui/app/elements/core/gr-error-manager/gr-error-manager_test.html b/polygerrit-ui/app/elements/core/gr-error-manager/gr-error-manager_test.html
index 76d12e9..4f9b103 100644
--- a/polygerrit-ui/app/elements/core/gr-error-manager/gr-error-manager_test.html
+++ b/polygerrit-ui/app/elements/core/gr-error-manager/gr-error-manager_test.html
@@ -196,7 +196,7 @@
             let toast = toastSpy.lastCall.returnValue;
             assert.isOk(toast);
             assert.include(
-                Polymer.dom(toast.root).textContent, 'Credentails expired.');
+                Polymer.dom(toast.root).textContent, 'Credentials expired.');
             assert.include(
                 Polymer.dom(toast.root).textContent, 'Refresh credentials');
 
@@ -267,7 +267,7 @@
             // toast
             const toast = toastSpy.lastCall.returnValue;
             assert.include(
-                Polymer.dom(toast.root).textContent, 'Credentails expired.');
+                Polymer.dom(toast.root).textContent, 'Credentials expired.');
             assert.include(
                 Polymer.dom(toast.root).textContent, 'Refresh credentials');
             done();
@@ -313,7 +313,7 @@
           flush(() => {
             let toast = toastSpy.lastCall.returnValue;
             assert.include(
-                Polymer.dom(toast.root).textContent, 'Credentails expired.');
+                Polymer.dom(toast.root).textContent, 'Credentials expired.');
             assert.include(
                 Polymer.dom(toast.root).textContent, 'Refresh credentials');
 
@@ -325,7 +325,7 @@
               toast = toastSpy.lastCall.returnValue;
               assert.isOk(toast);
               assert.include(
-                  Polymer.dom(toast.root).textContent, 'Credentails expired.');
+                  Polymer.dom(toast.root).textContent, 'Credentials expired.');
               done();
             });
           });
@@ -463,4 +463,4 @@
       });
     });
   });
-</script>
\ No newline at end of file
+</script>
diff --git a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-auth.js b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-auth.js
index 2978193..7648b7d 100644
--- a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-auth.js
+++ b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-auth.js
@@ -264,7 +264,7 @@
     ERROR: 3,
   };
 
-  Auth.CREDS_EXPIRED_MSG = 'Credentails expired.';
+  Auth.CREDS_EXPIRED_MSG = 'Credentials expired.';
 
   // TODO(taoalpha): this whole thing should be moved to a service
   window.Auth = Auth;