Merge branch 'stable-2.11'

* stable-2.11:
  Add built-in documentation.
  Force ticket service off
  Restore anonymous repositories browse capability
  Minor refactoring of gitewb config URLs
  Top menu improvements
  Get rid of hacked Wicket version

Change-Id: I03b48683138d5faf04f5405b65405df8b24e3ae7
diff --git a/BUCK b/BUCK
index a66e8d2..7f845a1 100644
--- a/BUCK
+++ b/BUCK
@@ -9,31 +9,44 @@
     'Gerrit-ReloadMode: restart',
   ],
   deps = [
-    '//lib/commons:httpcore',
-    '//lib/commons:net',
-    '//lib/commons:codec',
+    ':gitblit-properties-jar',
+    '//lib/httpcomponents:httpcore',
+    '//plugins/gitblit/lib:confluence-core',
+    '//plugins/gitblit/lib:force-partner-api',
+    '//plugins/gitblit/lib:freemarker',
     '//plugins/gitblit/lib:gitblit-jar',
-    '//plugins/gitblit/lib:wicket',
-    '//plugins/gitblit/lib:wicket-extensions',
-    '//plugins/gitblit/lib:wicketstuff',
-    '//plugins/gitblit/lib:javax-mail',
     '//plugins/gitblit/lib:groovy',
-    '//plugins/gitblit/lib:beust-jcommander',
+    '//plugins/gitblit/lib:ivy',
+    '//plugins/gitblit/lib:javax-mail',
     '//plugins/gitblit/lib:jdom',
-    '//plugins/gitblit/lib:lucene-core',
+    '//plugins/gitblit/lib:jsoup',
+    '//plugins/gitblit/lib:libpam4j',
     '//plugins/gitblit/lib:lucene-highlighter',
     '//plugins/gitblit/lib:lucene-memory',
     '//plugins/gitblit/lib:markdownpapers',
+    '//plugins/gitblit/lib:mediawiki-core',
+    '//plugins/gitblit/lib:pf4j',
     '//plugins/gitblit/lib:rome',
+    '//plugins/gitblit/lib:textile-core',
+    '//plugins/gitblit/lib:tika',
+    '//plugins/gitblit/lib:tracwiki-core',
+    '//plugins/gitblit/lib:twiki-core',
     '//plugins/gitblit/lib:unboundid',
-    ':gitblit-properties-jar',
+    '//plugins/gitblit/lib:waffle-jna',
+    '//plugins/gitblit/lib:wicket',
+    '//plugins/gitblit/lib:wicket-extensions',
+    '//plugins/gitblit/lib:wikitext-core',
+  ],
+  provided_deps = [
+    '//lib/commons:codec',
+    '//lib/commons:net',
+    '//plugins/gitblit/lib:lucene-core',
   ]
 )
 
 prebuilt_jar(
   name = 'gitblit-properties-jar',
-  binary_jar = genfile('gitblit-properties.zip'),
-  deps = [':gitblit-properties'],
+  binary_jar = ':gitblit-properties',
 )
 
 genrule(
diff --git a/README.md b/README.md
index 08d468b..b5111b6 100644
--- a/README.md
+++ b/README.md
@@ -14,16 +14,8 @@
 build parameters and constraints (i.e. shaded-jar) that are
 needed for a Gerrit plugin to work properly.
 
-### Wicket
-You need to clone and build a modified version of Wicket that
-is currently published on GitHub under the GerritCodeReview
-organisation: https://github.com/GerritCodeReview/wicket.git
-
-    $ git clone https://github.com/GerritCodeReview/wicket.git
-    $ git checkout wicket-1.4.23-gerrit
-    $ mvn clean install -DskipTests
-
 ### Gitblit
+
 You need to clone Gitblit from GitHub and build it locally
 using the installMaven ANT target.
 
@@ -32,6 +24,7 @@
     $ ant -DresourceFolderPrefix=static installMaven
 
 ### Gitblit plugin
+
 You are ready now to clone and build the Gitblit plugin: the
 Wicket and Giblit dependencies will be taken from your local
 Maven repository.
@@ -46,10 +39,11 @@
     [gitweb]
         type = custom
         linkname = Gitblit
-        url = plugins/
-        revision = gitblit/commit/?r=${project}&h=${commit}
-        project = gitblit/summary/?r=${project}
-        branch = gitblit/log/?r=${project}&h=${branch}
-        filehistory = gitblit/history/?f=${file}&r=${project}&h=${branch}
-        file = gitblit/blob/?r=${project}&h=${commit}&f=${file}
-        roottree = gitblit/tree/?r=${project}&h=${commit}
+        url = plugins/gitblit/
+        revision = commit/?r=${project}&h=${commit}
+        project = summary/?r=${project}
+        branch = log/?r=${project}&h=${branch}
+        filehistory = history/?f=${file}&r=${project}&h=${branch}
+        file = blob/?r=${project}&h=${commit}&f=${file}
+        roottree = tree/?r=${project}&h=${commit}
+
diff --git a/lib/BUCK b/lib/BUCK
index f3892f0..28e3144 100644
--- a/lib/BUCK
+++ b/lib/BUCK
@@ -2,60 +2,52 @@
 GERRITFORGE = 'http://gerritforge.com/snapshot'
 
 maven_jar(
+  name = 'pf4j',
+  id = 'ro.fortsoft.pf4j:pf4j:0.9.0',
+  sha1 = 'ff412cadfee820c50bf02723187eda6165d70379',
+  license = 'Apache2.0',
+)
+
+maven_jar(
   name = 'gitblit-jar',
-  id = 'com.gitblit:gitblit:1.4.0-SNAPSHOT',
-  sha1 = '5d1a6df0ed4ee0517e1f61cdf92b7fb47b4b1119',
+  id = 'com.gitblit:gitblit:1.7.0-SNAPSHOT',
+  sha1 = 'bf24e3a78f5421908326ec4e5a522a0bc7af3903',
   license = 'Apache2.0',
   repository = GERRITFORGE,
 )
 
 maven_jar(
   name = 'wicket',
-  id = 'org.apache.wicket:wicket:1.4.21-selfload',
-  sha1 = 'b822e4ce05232f39cc60adc59d3866452f919d6d',
+  id = 'org.apache.wicket:wicket:1.4.23',
+  sha1 = '304d9e23e52e9488308644093663b568952abd0b',
   license = 'Apache2.0',
-  repository = GERRITFORGE,
 )
 
 maven_jar(
   name = 'wicket-auth-roles',
-  id = 'org.apache.wicket:wicket-auth-roles:1.4.21',
+  id = 'org.apache.wicket:wicket-auth-roles:1.4.23',
   sha1 = '1b130dbf5578ace37507430a4a523f6594bf34fa',
   license = 'Apache2.0',
 )
 
 maven_jar(
   name = 'wicket-extensions',
-  id = 'org.apache.wicket:wicket-extensions:1.4.21',
-  sha1 = 'fac510c7ee4399a29b927405ec3de40b67d105d8',
-  license = 'Apache2.0',
-)
-
-maven_jar(
-  name = 'wicketstuff',
-  id = 'org.wicketstuff:googlecharts:1.4.21',
-  sha1 = '73d7540267afc3a0e91ca6148d3073e050dba180',
+  id = 'org.apache.wicket:wicket-extensions:1.4.23',
+  sha1 = '9ca61ca2273289d648dbb430e9033693c9b5eed3',
   license = 'Apache2.0',
 )
 
 maven_jar(
   name = 'javax-mail',
-  id = 'javax.mail:mail:1.4',
-  sha1 = '1aa1579ae5ecd41920c4f355b0a9ef40b68315dd',
+  id = 'com.sun.mail:javax.mail:1.5.1',
+  sha1 = '9724dd44f1abbba99c9858aa05fc91d53f59e7a5',
   license = 'Apache2.0',
 )
 
 maven_jar(
   name = 'groovy',
-  id = 'org.codehaus.groovy:groovy-all:1.8.8',
-  sha1 = '98a489343d3c30da817d36cbea5de11ed07bef31',
-  license = 'Apache2.0',
-)
-
-maven_jar(
-  name = 'beust-jcommander',
-  id = 'com.beust:jcommander:1.17',
-  sha1 = '219a3540f3b27d7cc3b1d91d6ea046cd8723290e',
+  id = 'org.codehaus.groovy:groovy-all:2.4.1',
+  sha1 = 'a9ca9c9de09361ec2a18d2c058d2524fbd8eae0c',
   license = 'Apache2.0',
 )
 
@@ -66,25 +58,24 @@
   license = 'Apache2.0',
 )
 
-# Unfortunately an older version than used by Gerrit itself
 maven_jar(
   name = 'lucene-core',
-  id = 'org.apache.lucene:lucene-core:3.6.0',
-  sha1 = '8a0429de6b7c9918841fa2c441a6ef4cc07f2a18',
+  id = 'org.apache.lucene:lucene-core:4.10.2',
+  sha1 = 'c01e3d675d277e0a93e7890d03cc3246b2cdecaa',
   license = 'Apache2.0',
 )
 
 maven_jar(
   name = 'lucene-highlighter',
-  id = 'org.apache.lucene:lucene-highlighter:3.6.0',
-  sha1 = '9ee691f1dcc60f093df433c165d6a686c6d24553',
+  id = 'org.apache.lucene:lucene-highlighter:4.10.2',
+  sha1 = '7ced704190e1e5b9a9b32edec6dba9116d69ae72',
   license = 'Apache2.0',
 )
 
 maven_jar(
   name = 'lucene-memory',
-  id = 'org.apache.lucene:lucene-memory:3.6.1',
-  sha1 = '8c7ca5572edea50973dc0d26cf75c27047eebe7e',
+  id = 'org.apache.lucene:lucene-memory:4.10.2',
+  sha1 = 'c381123b510dd790e27445430ab8203e5a27f5bc',
   license = 'Apache2.0',
 )
 
@@ -97,15 +88,105 @@
 
 maven_jar(
   name = 'rome',
-  id = 'rome:rome:1.0-selfload',
-  sha1 = 'e8d80293c9c13b557f4e570d3e12afcaf64ac6d4',
+  id = 'rome:rome:1.0',
+  sha1 = '022b33347f315833e9348cec2751af1a5d5656e4',
   license = 'Apache2.0',
-  repository = GERRITFORGE
 )
 
 maven_jar(
   name = 'unboundid',
-  id = 'com.unboundid:unboundid-ldapsdk:2.3.0',
-  sha1 = '6fde8d9fb4ee3e7e3d7e764e3ea57195971e2eb2',
+  id = 'com.unboundid:unboundid-ldapsdk:2.3.8',
+  sha1 = '1788564d03f0b786a695f4de67b4cb55eda45e14',
+  license = 'Apache2.0',
+)
+
+maven_jar(
+  name = 'jsoup',
+  id = 'org.jsoup:jsoup:1.7.3',
+  sha1 = '92568d7167ce1bf9eb1fd815b022d5a2c113547a',
+  license = 'Apache2.0',
+)
+
+maven_jar(
+  name = 'tika',
+  id = 'org.apache.tika:tika-core:1.5',
+  sha1 = '194ca0fb3d73b07737524806fbc3bec89063c03a',
+  license = 'Apache2.0',
+)
+
+maven_jar(
+  name = 'wikitext-core',
+  id = 'org.fusesource.wikitext:wikitext-core:1.4',
+  sha1 = 'b877ee61d064c01cbf9834ab1b7146cd44acad65',
+  license = 'Apache2.0',
+)
+
+maven_jar(
+  name = 'twiki-core',
+  id = 'org.fusesource.wikitext:twiki-core:1.4',
+  sha1 = '00c392027ae056d555040af2d1e0ed217fa94712',
+  license = 'Apache2.0',
+)
+
+maven_jar(
+  name = 'textile-core',
+  id = 'org.fusesource.wikitext:textile-core:1.4',
+  sha1 = '9169c4a2865232c7b22137d759fb7ee2cbf019de',
+  license = 'Apache2.0',
+)
+
+maven_jar(
+  name = 'tracwiki-core',
+  id = 'org.fusesource.wikitext:tracwiki-core:1.4',
+  sha1 = 'e2c8a5597695dc82256f2a97a505783e5ab5b0cb',
+  license = 'Apache2.0',
+)
+
+maven_jar(
+  name = 'mediawiki-core',
+  id = 'org.fusesource.wikitext:mediawiki-core:1.4',
+  sha1 = '30d1b5551bbf97a17abc22d51fe8dd3b4d27f1ab',
+  license = 'Apache2.0',
+)
+
+maven_jar(
+  name = 'confluence-core',
+  id = 'org.fusesource.wikitext:confluence-core:1.4',
+  sha1 = '08210b4af6f055ada934753facd27d7abf9d01a8',
+  license = 'Apache2.0',
+)
+
+maven_jar(
+  name = 'ivy',
+  id = 'org.apache.ivy:ivy:2.2.0',
+  sha1 = 'f9d1e83e82fc085093510f7d2e77d81d52bc2081',
+  license = 'Apache2.0',
+)
+
+maven_jar(
+  name = 'force-partner-api',
+  id = 'com.force.api:force-partner-api:24.0.0',
+  sha1 = 'ce3cd3e2ccd51735f27a83e90018123e8bd10314',
+  license = 'Apache2.0',
+)
+
+maven_jar(
+  name = 'freemarker',
+  id = 'org.freemarker:freemarker:2.3.22',
+  sha1 = '473d784b3cd2dcb6d49a287ded0542b7862c7d68',
+  license = 'Apache2.0',
+)
+
+maven_jar(
+  name = 'waffle-jna',
+  id = 'com.github.dblock.waffle:waffle-jna:1.7.3',
+  sha1 = '94ba74d3fa15bb61d4901b062b8fd5046c9e99b9',
+  license = 'Apache2.0',
+)
+
+maven_jar(
+  name = 'libpam4j',
+  id = 'org.kohsuke:libpam4j:1.8',
+  sha1 = '548d4a1177adad8242fe03a6930c335669d669ad',
   license = 'Apache2.0',
 )
diff --git a/pom.xml b/pom.xml
index 7726835..f94f05b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -21,6 +21,12 @@
   <description>GitBlit for Gerrit integrated as a plugin</description>
   <name>Gerrit - GitBlit Plugin</name>
   <version>2.11-SNAPSHOT</version>
+  <licenses>
+    <license>
+      <name>Apache License 2.0</name>
+      <url>http://www.apache.org/licenses/LICENSE-2.0.html</url>
+    </license>
+  </licenses>
   <properties>
     <Gerrit-ApiType>plugin</Gerrit-ApiType>
     <Gerrit-ApiVersion>${project.version}</Gerrit-ApiVersion>
@@ -28,8 +34,8 @@
     <Gerrit-InitStep>com.googlesource.gerrit.plugins.gitblit.GitBlitInitStep</Gerrit-InitStep>
     <Gerrit-Module>com.googlesource.gerrit.plugins.gitblit.GitBlitModule</Gerrit-Module>
     <Gerrit-HttpModule>com.googlesource.gerrit.plugins.gitblit.GitBlitServletModule</Gerrit-HttpModule>
-    <dagger.version>1.1.0</dagger.version>
-    <wicket.version>1.4.23-gerrit</wicket.version>
+    <wicket.version>1.4.23</wicket.version>
+    <GitBlit-Version>1.7.0-SNAPSHOT</GitBlit-Version>
   </properties>
   <dependencies>
     <dependency>
@@ -41,24 +47,52 @@
     <dependency>
       <groupId>com.gitblit</groupId>
       <artifactId>gitblit</artifactId>
-      <version>1.7.0-SNAPSHOT</version>
-      <exclusions>
-        <exclusion>
-          <groupId>org.apache.wicket</groupId>
-          <artifactId>wicket</artifactId>
-        </exclusion>
-      </exclusions>
+      <version>${GitBlit-Version}</version>
     </dependency>
     <dependency>
       <groupId>org.apache.wicket</groupId>
       <artifactId>wicket</artifactId>
-      <version>1.4.23-gerrit</version>
+      <version>${wicket.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.wicket</groupId>
+      <artifactId>wicket-auth-roles</artifactId>
+      <version>${wicket.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.wicket</groupId>
+      <artifactId>wicket-extensions</artifactId>
+      <version>${wicket.version}</version>
     </dependency>
   </dependencies>
   <build>
+    <resources>
+      <resource>
+        <directory>src/main/resources</directory>
+        <filtering>true</filtering>
+        <includes>
+          <include>**/*.md</include>
+        </includes>
+      </resource>
+      <resource>
+        <directory>src/main/resources</directory>
+        <filtering>false</filtering>
+        <excludes>
+          <exclude>**/*.md</exclude>
+        </excludes>
+      </resource>
+    </resources>
     <plugins>
       <plugin>
         <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-resources-plugin</artifactId>
+        <version>2.7</version>
+        <configuration>
+          <escapeString>\</escapeString>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-compiler-plugin</artifactId>
         <version>2.5.1</version>
         <configuration>
@@ -107,7 +141,7 @@
               <exclude>org.apache.commons:commons-compress</exclude>
               <exclude>org.tukaani:xz</exclude>
               <exclude>org.ow2.asm:*</exclude>
-              <exclude>org.eclipse.jetty:*</exclude>
+              <exclude>org.eclipse.jetty.aggregate:*</exclude>
             </excludes>
           </artifactSet>
           <transformers>
diff --git a/src/main/java/com/googlesource/gerrit/plugins/gitblit/GerritWicketFilter.java b/src/main/java/com/googlesource/gerrit/plugins/gitblit/GerritWicketFilter.java
index d6f5aeb..d41a068 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/gitblit/GerritWicketFilter.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/gitblit/GerritWicketFilter.java
@@ -112,6 +112,11 @@
   }
 
   @Override
+  protected ClassLoader getClassLoader() {
+    return getClass().getClassLoader();
+  }
+
+  @Override
   public void doFilter(ServletRequest request, ServletResponse response,
       FilterChain chain) throws IOException, ServletException {
     HttpServletRequest httpServletRequest = (HttpServletRequest) request;
diff --git a/src/main/java/com/googlesource/gerrit/plugins/gitblit/GitBlitInitStep.java b/src/main/java/com/googlesource/gerrit/plugins/gitblit/GitBlitInitStep.java
index 329ef60..2580731 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/gitblit/GitBlitInitStep.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/gitblit/GitBlitInitStep.java
@@ -13,24 +13,31 @@
 // limitations under the License.
 package com.googlesource.gerrit.plugins.gitblit;
 
+import org.eclipse.jgit.lib.Config;
+
 import com.google.gerrit.extensions.annotations.PluginName;
+import com.google.gerrit.pgm.init.api.ConsoleUI;
+import com.google.gerrit.pgm.init.api.InitFlags;
 import com.google.gerrit.pgm.init.api.InitStep;
 import com.google.gerrit.pgm.init.api.Section;
 import com.google.gerrit.pgm.init.api.Section.Factory;
-import com.google.gerrit.pgm.init.api.ConsoleUI;
 import com.google.inject.Inject;
 
 public class GitBlitInitStep implements InitStep {
   private final ConsoleUI ui;
   private final String pluginName;
   private final Factory sections;
+  private final Config cfg;
 
   @Inject
-  public GitBlitInitStep(final ConsoleUI ui, final Section.Factory sections,
-      @PluginName final String pluginName) {
+  public GitBlitInitStep(ConsoleUI ui,
+      Section.Factory sections,
+      @PluginName String pluginName,
+      InitFlags flags) {
     this.ui = ui;
     this.pluginName = pluginName;
     this.sections = sections;
+    this.cfg = flags.cfg;
   }
 
   @Override
@@ -38,24 +45,71 @@
     ui.message("\n");
     ui.header("GitBlit Integration");
 
-    if(ui.yesno(true, "Do you want to use GitBlit as your GitWeb viewer ?")) {
+    if (ui.yesno(true, "Do you want to use GitBlit as your GitWeb viewer?")) {
       configureGitBlit();
     }
+    // If we don't use GitBlit here, we leave a potential [plugin "gitblit"]
+    // section in the config. It won't hurt,
+    // and maybe the user will later re-enable GitBlit, and then he'd be
+    // surprised if his customized settings were
+    // gone.
   }
 
   private void configureGitBlit() {
+    initGitWebConfig();
+    initGitBlitPluginConfig();
+  }
+
+  private void initGitWebConfig() {
     Section gitWeb = sections.get("gitweb", null);
     gitWeb.set("type", "custom");
-    gitWeb.set("url", "plugins/");
-    gitWeb.set("project", pluginName + "/summary/?r=${project}");
-    gitWeb.set("revision", pluginName + "/commit/?r=${project}&h=${commit}");
-    gitWeb.set("branch", pluginName + "/log/?r=${project}&h=${branch}");
-    gitWeb.set("filehistory", pluginName + "/history/?f=${file}&r=${project}&h=${branch}");
-    gitWeb.set("file", pluginName + "/blob/?r=${project}&h=${commit}&f=${file}");
-    gitWeb.set("roottree", pluginName + "/tree/?r=${project}&h=${commit}");
+    gitWeb.set("url", "plugins/" + pluginName + '/');
+    gitWeb.set("project", "summary/?r=${project}");
+    gitWeb.set("revision", "commit/?r=${project}&h=${commit}");
+    gitWeb.set("branch", "log/?r=${project}&h=${branch}");
+    gitWeb.set("filehistory", "history/?f=${file}&r=${project}&h=${branch}");
+    gitWeb.set("file", "blob/?r=${project}&h=${commit}&f=${file}");
+    gitWeb.set("roottree", "tree/?r=${project}&h=${commit}");
     gitWeb.string("Link name", "linkname", "GitBlit");
   }
 
+  private void initGitBlitPluginConfig() {
+    Section pluginCfg = sections.get("plugin", pluginName);
+    // These values are displayed in the UI.
+    pluginCfg.string("\"Repositories\" submenu title", "repositories",
+        "Repositories", true);
+    pluginCfg
+        .string("\"Activity\" submenu title", "activity", "Activity", true);
+    pluginCfg.string("\"Documentation\" submenu title", "documentation",
+        "Documentation", true);
+    String originalValue = pluginCfg.get("search");
+    if (originalValue == null) {
+      pluginCfg
+          .string(
+              "\"Search\" submenu title (makes only sense to set if some projects are indexed in GitBlit)",
+              "search", "", true);
+    } else {
+      String newValue =
+          ui.readString(
+              originalValue,
+              "%s",
+              "\"Search\" submenu title (makes only sense to set if some projects are indexed in GitBlit; single dash unsets)");
+      if (newValue == null || "-".equals(newValue)) {
+        pluginCfg.unset("search");
+      } else if (!originalValue.equals(newValue)) {
+        pluginCfg.set("search", newValue);
+      }
+    }
+    pluginCfg.string(
+        "\"Browse\" submenu title for the \"Projects\" top-level menu",
+        "browse", "Browse", true);
+    // If everything is at the default, then make sure we don't have the section
+    // at all.
+    if (cfg.getNames("plugin", pluginName).isEmpty()) {
+      cfg.unsetSection("plugin", pluginName);
+    }
+  }
+
   @Override
   public void postRun() throws Exception {
   }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/gitblit/GitBlitServletModule.java b/src/main/java/com/googlesource/gerrit/plugins/gitblit/GitBlitServletModule.java
index 3ec851d..9012053 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/gitblit/GitBlitServletModule.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/gitblit/GitBlitServletModule.java
@@ -55,6 +55,7 @@
 import com.google.inject.Inject;
 import com.google.inject.servlet.ServletModule;
 import com.googlesource.gerrit.plugins.gitblit.app.GitBlitSettings;
+import com.googlesource.gerrit.plugins.gitblit.app.ReallyNullTicketService;
 import com.googlesource.gerrit.plugins.gitblit.auth.GerritToGitBlitUserService;
 
 public class GitBlitServletModule extends ServletModule {
@@ -75,7 +76,7 @@
 
     // bind complex providers
     bind(IPublicKeyManager.class).toProvider(IPublicKeyManagerProvider.class);
-    bind(ITicketService.class).toProvider(ITicketServiceProvider.class);
+    bind(ITicketService.class).to(ReallyNullTicketService.class);
     bind(WorkQueue.class).toProvider(WorkQueueProvider.class);
 
     // core managers
diff --git a/src/main/java/com/googlesource/gerrit/plugins/gitblit/GitBlitTopMenu.java b/src/main/java/com/googlesource/gerrit/plugins/gitblit/GitBlitTopMenu.java
index b4e5778..44d62f8 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/gitblit/GitBlitTopMenu.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/gitblit/GitBlitTopMenu.java
@@ -17,45 +17,70 @@
 import java.util.Arrays;
 import java.util.List;
 
-import com.google.gerrit.extensions.annotations.Listen;
+import com.google.common.collect.Lists;
+import com.google.gerrit.extensions.annotations.PluginCanonicalWebUrl;
 import com.google.gerrit.extensions.annotations.PluginName;
+import com.google.gerrit.extensions.client.GerritTopMenu;
 import com.google.gerrit.extensions.webui.TopMenu;
-import com.google.gerrit.server.AnonymousUser;
 import com.google.gerrit.server.CurrentUser;
+import com.google.gerrit.server.config.PluginConfig;
+import com.google.gerrit.server.config.PluginConfigFactory;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 
-@Listen
 public class GitBlitTopMenu implements TopMenu {
+
+  // Not configurable to avoid mis-configurations clashing with predefined top
+  // menus.
+  private static final String GITBLIT_TOPMENU_NAME = "GitBlit";
+
   private final MenuEntry fullMenuEntries;
   private final MenuEntry restrictedMenuEntries;
+  private final MenuEntry extraProjectEntries;
   private final Provider<CurrentUser> userProvider;
 
   @Inject
-  public GitBlitTopMenu(final @PluginName String pluginName,
-      final Provider<CurrentUser> userProvider) {
+  public GitBlitTopMenu(@PluginName String pluginName,
+      @PluginCanonicalWebUrl String pluginUrl,
+      Provider<CurrentUser> userProvider,
+      PluginConfigFactory cfgProvider) {
     this.userProvider = userProvider;
 
-    String gitBlitBaseUrl = "/plugins/" + pluginName + "/";
-    this.restrictedMenuEntries =
-        menu("Gitblit", item("Repositories", gitBlitBaseUrl + "repositories/"));
-    this.fullMenuEntries =
-        menu("GitBlit", item("Repositories", gitBlitBaseUrl + "repositories/"),
-            item("Activity", gitBlitBaseUrl + "activity/"),
-            item("Search", gitBlitBaseUrl + "lucene/"));
-  }
-
-  private MenuEntry menu(String name, MenuItem... items) {
-    return new MenuEntry(name, Arrays.asList(items));
-  }
-
-  private MenuItem item(String name, String url) {
-    return new MenuItem(name, url, "");
+    String gitBlitBaseUrl = pluginUrl;
+    PluginConfig cfg = cfgProvider.getFromGerritConfig(pluginName, true);
+    // We don't have to worry about XSS here; the way these menu item get
+    // created through GWT ensures that these values read from the config
+    // end up as text nodes in the DOM, even if they contain potentially
+    // malicious code. So if somebody sets these values to some HTML snippet,
+    // he'll simply end up with a funny looking menu item, but he can't inject
+    // things here.
+    MenuItem repositories =
+        new MenuItem(cfg.getString("repositories", "Repositories"),
+            gitBlitBaseUrl + "repositories/", "");
+    // GitBlit handles its own "/" url, so Gerrit won't produce any link, not even on the "plugins" page, that would display the documentation.
+    // I've considered simply redirecting "/" to "/Documentation/" since GitBlit's "/" screen is very similar to its "/activity/" screen, but
+    // decided finally to provide an explicit documentation submenu instead.
+    MenuItem documentation = new MenuItem(cfg.getString("documentation", "Documentation"), gitBlitBaseUrl + "Documentation/", "");
+    restrictedMenuEntries = new MenuEntry(GITBLIT_TOPMENU_NAME, Arrays.asList(repositories, documentation));
+    List<MenuItem> fullMenuItems = Lists.newArrayList();
+    fullMenuItems.add(repositories);
+    fullMenuItems.add(new MenuItem(cfg.getString("activity", "Activity"),
+        gitBlitBaseUrl + "activity/", ""));
+    String search = cfg.getString("search");
+    if (search != null && !search.isEmpty()) {
+      fullMenuItems.add(new MenuItem(search, gitBlitBaseUrl + "lucene/", ""));
+    }
+    fullMenuItems.add(documentation);
+    fullMenuEntries = new MenuEntry(GITBLIT_TOPMENU_NAME, fullMenuItems);
+    extraProjectEntries =
+        new MenuEntry(GerritTopMenu.PROJECTS, Arrays.asList(new MenuItem(cfg
+            .getString("browse", "Browse"), gitBlitBaseUrl
+            + "summary?r=${projectName}", "")));
   }
 
   @Override
   public List<MenuEntry> getEntries() {
-    return Arrays.asList(userProvider.get() instanceof AnonymousUser
-        ? restrictedMenuEntries : fullMenuEntries);
+    return Arrays.asList(userProvider.get().isIdentifiedUser()
+        ? fullMenuEntries : restrictedMenuEntries, extraProjectEntries);
   }
 }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/gitblit/app/ReallyNullTicketService.java b/src/main/java/com/googlesource/gerrit/plugins/gitblit/app/ReallyNullTicketService.java
new file mode 100644
index 0000000..14f3fe3
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/gitblit/app/ReallyNullTicketService.java
@@ -0,0 +1,79 @@
+// Copyright (C) 2014 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.googlesource.gerrit.plugins.gitblit.app;
+
+import java.util.Collections;
+import java.util.List;
+
+import com.gitblit.manager.INotificationManager;
+import com.gitblit.manager.IPluginManager;
+import com.gitblit.manager.IRepositoryManager;
+import com.gitblit.manager.IRuntimeManager;
+import com.gitblit.manager.IUserManager;
+import com.gitblit.models.RepositoryModel;
+import com.gitblit.tickets.NullTicketService;
+import com.gitblit.tickets.TicketLabel;
+import com.gitblit.tickets.TicketMilestone;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+
+/**
+ * The {@link NullTicketService} of GitBlit is not really a null service. It
+ * creates a TicketIndexer, and because it neglects to override some methods
+ * from its base class, that even gets called sometimes, which then produces
+ * exceptions.
+ */
+@Singleton
+public class ReallyNullTicketService extends NullTicketService {
+
+  @Inject
+  public ReallyNullTicketService(IRuntimeManager runtimeManager,
+      IPluginManager pluginManager,
+      INotificationManager notificationManager,
+      IUserManager userManager,
+      IRepositoryManager repositoryManager) {
+    super(runtimeManager, pluginManager, notificationManager, userManager,
+        repositoryManager);
+  }
+
+  @Override
+  public boolean hasTickets(RepositoryModel repository) {
+    return false;
+  }
+
+  @Override
+  public boolean isAcceptingNewPatchsets(RepositoryModel repository) {
+    return false;
+  }
+
+  @Override
+  public boolean isAcceptingNewTickets(RepositoryModel repository) {
+    return false;
+  }
+
+  @Override
+  public boolean isAcceptingTicketUpdates(RepositoryModel repository) {
+    return false;
+  }
+
+  @Override
+  public List<TicketLabel> getLabels(RepositoryModel repository) {
+    return Collections.emptyList();
+  }
+
+  @Override
+  public List<TicketMilestone> getMilestones(RepositoryModel repository) {
+    return Collections.emptyList();
+  }
+}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/gitblit/auth/GerritToGitBlitUserService.java b/src/main/java/com/googlesource/gerrit/plugins/gitblit/auth/GerritToGitBlitUserService.java
index 1d0ce9d..a4bbb2c 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/gitblit/auth/GerritToGitBlitUserService.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/gitblit/auth/GerritToGitBlitUserService.java
@@ -142,14 +142,15 @@
     String gerritUsername =
         (String) httpRequest.getAttribute("gerrit-username");
     String gerritToken = (String) httpRequest.getAttribute("gerrit-token");
-    if (Strings.isNullOrEmpty(gerritUsername)
-        || Strings.isNullOrEmpty(gerritToken)) {
-      return null;
-    }
-
     httpRequest.getSession().setAttribute(Constants.AUTHENTICATION_TYPE,
         AuthenticationType.CONTAINER);
-    return authenticateSSO(gerritUsername, gerritToken);
+    
+    if (Strings.isNullOrEmpty(gerritUsername)
+        || Strings.isNullOrEmpty(gerritToken)) {
+      return GerritToGitBlitUserModel.getAnonymous(projectControl);
+    } else {      
+      return authenticateSSO(gerritUsername, gerritToken);
+    }
   }
 
   @Override
diff --git a/src/main/resources/Documentation/index.md b/src/main/resources/Documentation/index.md
new file mode 100644
index 0000000..a3a24eb
--- /dev/null
+++ b/src/main/resources/Documentation/index.md
@@ -0,0 +1,76 @@
+# GitBlit plugin
+
+This plugin integrates [GitBlit](https://github.com/gitblit/gitblit) _${GitBlit-Version}_ as a repository browser into [Gerrit](https://code.google.com/p/gerrit/),
+with full SSO through Gerrit.
+
+* License: [Apache Public License 2.0](http://www.apache.org/licenses/LICENSE-2.0)
+* [Home page](https://gerrit.googlesource.com/plugins/gitblit/+/refs/heads/master/README.md)
+* Installed plugin version: _${pom.version}_
+
+# Configuration
+
+There are two different configurations: one for Gerrit so it knows how to generate links that will be processed by the plugin, and
+an optional GitBlit configuration for the plugin itself.
+
+## Gerrit configuration
+
+In Gerrit's `gerrit.config`, define the `[gitweb]` section as follows:
+
+	[gitweb]
+	        type = custom
+	        url = plugins/@PLUGIN@/
+	        linkname = browse
+	        project = summary/?r=${project}
+	        revision = commit/?r=${project}&h=${commit}
+	        branch = log/?r=${project}&h=${branch}
+	        filehistory = history/?f=\${file}&r=${project}&h=${branch}
+	        file = blob/?r=${project}&h=${commit}&f=\${file}
+	        roottree = tree/?r=${project}&h=${commit}
+
+This is normally done automatically if you add the plugin and run through `java -jar gerrit.war init -d site_path`, but you can also
+add this manually to Gerrit's config file. The `linkname` can be adapted to your taste.
+
+### Configuring the top menu
+
+This plugin adds a "GitBlit" top menu to Gerrit, and also a new sub-menu item to the "Projects" top menu. Since v2.11 of this plugin, the link
+texts for all sub-menu items can be configured to your taste in a `[plugin "@PLUGIN@"]` section in your `gerrit.config`. If the section is not present,
+or some values in that section are not defined, the plugin uses built-in default texts. The default configuration would correspond to
+
+	[plugin "@PLUGIN@"]
+	        repositories = Repositories
+	        activity = Activity
+	        documentation = Documentation
+	        search =
+	        browse = Browse
+
+The first four are sub-menu items of the "GitBlit" top menu, the last one is a new "browse" sub-menu item in Gerrit's "Projects" menu that is shown
+for Gerrit's "current" project (since v2.11).
+
+The "search" sub-menu item is by default not set and will thus not be shown. Setting it makes only sense if you enable GitBlit indexing on some of
+your projects.
+
+## GitBlit configuration
+
+The plugin includes in the JAR a minimal default configuration to make GitBlit act only as a repository viewer. You can provide your own
+customized [`gitblit.properties`](http://gitblit.com/properties.html) file located in Gerrit's `$GERRIT_SITE/etc` directory.
+The `$GERRIT_SITE/etc/gitblit.properties` takes precedence over the pre-defined configuration settings.
+
+P.S. The following two GitBlit properties are not configurable as changing them would break the plugin functionality:
+
+- git.repositoriesFolder is hardcoded to point to Gerrit repositories directory
+- realm.userService is hardcoded to resolve GitBlit users using Gerrit authentication realm
+
+Additionally the GitBlit ticket service is not available as would not make sense when used in a read only
+repository viewer.
+
+The built-in configuration is archived in the GitBlit source repository. The latest version on master is
+[`gitblit.properties`](https://gerrit.googlesource.com/plugins/gitblit/+/master/src/main/resources/gitblit.properties).
+
+# Issue tracking
+
+Report bugs or make feature requests at the [Gerrit issue tracker](https://code.google.com/p/gerrit/issues/list).
+
+<hr style="color: #C0C0C0; background-color: #C0C0C0; border-color: #C0C0C0; height: 2px;" />
+<div style="float:right;">
+<a href="https://gerrit-review.googlesource.com/#/admin/projects/plugins/gitblit,dashboards" target="_blank">GitBlit plugin ${pom.version}</a>
+</div>
\ No newline at end of file