Merge branch 'stable-2.8' into stable-2.9

* stable-2.8:
  Fix plugin name in REST API documentation synopsis lines

Change-Id: Id73933ee6d6f8cb01e70c686f129e99ca564f5ed
diff --git a/BUCK b/BUCK
index 3a1b166..0ef0347 100644
--- a/BUCK
+++ b/BUCK
@@ -1,11 +1,16 @@
+MODULE = 'com.googlesource.gerrit.plugins.cookbook.HelloForm'
+
 gerrit_plugin(
   name = 'cookbook-plugin',
   srcs = glob(['src/main/java/**/*.java']),
-  resources = glob(['src/main/resources/**/*']),
+  resources = glob(['src/main/**/*']),
+  gwt_module = MODULE,
   manifest_entries = [
     'Gerrit-PluginName: cookbook',
     'Gerrit-Module: com.googlesource.gerrit.plugins.cookbook.Module',
     'Gerrit-HttpModule: com.googlesource.gerrit.plugins.cookbook.HttpModule',
     'Gerrit-SshModule: com.googlesource.gerrit.plugins.cookbook.SshModule',
+    'Implementation-Title: Cookbook plugin',
+    'Implementation-URL: https://gerrit-review.googlesource.com/#/admin/projects/plugins/cookbook-plugin',
   ]
 )
diff --git a/pom.xml b/pom.xml
index f3b56aa..fcb6f49 100644
--- a/pom.xml
+++ b/pom.xml
@@ -25,7 +25,7 @@
   <version>0.1</version>
   <properties>
     <Gerrit-ApiType>plugin</Gerrit-ApiType>
-    <Gerrit-ApiVersion>2.8.3</Gerrit-ApiVersion>
+    <Gerrit-ApiVersion>2.9-SNAPSHOT</Gerrit-ApiVersion>
   </properties>
 
   <build>
@@ -37,20 +37,19 @@
         <configuration>
           <archive>
             <manifestEntries>
+              <Gerrit-PluginName>cookbook</Gerrit-PluginName>
               <Gerrit-Module>com.googlesource.gerrit.plugins.cookbook.Module</Gerrit-Module>
               <Gerrit-HttpModule>com.googlesource.gerrit.plugins.cookbook.HttpModule</Gerrit-HttpModule>
               <Gerrit-SshModule>com.googlesource.gerrit.plugins.cookbook.SshModule</Gerrit-SshModule>
 
               <Implementation-Vendor>Gerrit Code Review</Implementation-Vendor>
-              <Implementation-URL>http://code.google.com/p/gerrit/</Implementation-URL>
+              <Implementation-URL>https://gerrit-review.googlesource.com/#/admin/projects/plugins/cookbook-plugin</Implementation-URL>
 
-              <Implementation-Title>Plugin ${project.artifactId}</Implementation-Title>
+              <Implementation-Title>Cookbook plugin</Implementation-Title>
               <Implementation-Version>${project.version}</Implementation-Version>
 
               <Gerrit-ApiType>${Gerrit-ApiType}</Gerrit-ApiType>
               <Gerrit-ApiVersion>${Gerrit-ApiVersion}</Gerrit-ApiVersion>
-              <Gerrit-PluginName>cookbook</Gerrit-PluginName>
-
             </manifestEntries>
           </archive>
         </configuration>
@@ -61,12 +60,32 @@
         <artifactId>maven-compiler-plugin</artifactId>
         <version>2.3.2</version>
         <configuration>
-          <source>1.6</source>
-          <target>1.6</target>
+          <source>1.7</source>
+          <target>1.7</target>
           <encoding>UTF-8</encoding>
         </configuration>
       </plugin>
+
+      <plugin>
+        <groupId>org.codehaus.mojo</groupId>
+        <artifactId>gwt-maven-plugin</artifactId>
+        <version>2.5.1</version>
+        <configuration>
+          <module>com.googlesource.gerrit.plugins.cookbook.HelloForm</module>
+          <disableClassMetadata>true</disableClassMetadata>
+          <disableCastChecking>true</disableCastChecking>
+          <webappDirectory>${project.build.directory}/classes/static</webappDirectory>
+        </configuration>
+        <executions>
+          <execution>
+            <goals>
+              <goal>compile</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
     </plugins>
+
   </build>
 
   <dependencies>
@@ -76,6 +95,17 @@
       <version>${Gerrit-ApiVersion}</version>
       <scope>provided</scope>
     </dependency>
+    <dependency>
+      <groupId>com.google.gerrit</groupId>
+      <artifactId>gerrit-plugin-gwtui</artifactId>
+      <version>${Gerrit-ApiVersion}</version>
+    </dependency>
+    <dependency>
+      <groupId>com.google.gwt</groupId>
+      <artifactId>gwt-user</artifactId>
+      <version>2.5.1</version>
+      <scope>provided</scope>
+    </dependency>
   </dependencies>
 
   <repositories>
diff --git a/src/main/java/com/googlesource/gerrit/plugins/cookbook/Greetings.java b/src/main/java/com/googlesource/gerrit/plugins/cookbook/Greetings.java
new file mode 100644
index 0000000..6e02c05
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/cookbook/Greetings.java
@@ -0,0 +1,54 @@
+// 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.googlesource.gerrit.plugins.cookbook;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+import com.google.gerrit.extensions.restapi.Response;
+import com.google.gerrit.extensions.restapi.RestReadView;
+import com.google.gerrit.server.change.RevisionResource;
+import com.google.inject.Inject;
+
+class Greetings implements RestReadView<RevisionResource> {
+
+  @Inject
+  Greetings() {
+  }
+
+  @Override
+  public Response<Collection<GreetInfo>> apply(RevisionResource rev) {
+    Collection<GreetInfo> l = new ArrayList<>(3);
+    l.add(new GreetInfo("Bonjour", "France",
+        "http://en.wikipedia.org/wiki/France"));
+    l.add(new GreetInfo("Hallo", "Germany",
+        "http://en.wikipedia.org/wiki/Germany"));
+    l.add(new GreetInfo("Hello", "USA",
+        "http://en.wikipedia.org/wiki/USA"));
+    return Response.ok(l);
+  }
+
+  class GreetInfo {
+    String message;
+    String country;
+    String href;
+
+    GreetInfo(String m, String c, String h) {
+      message = m;
+      country = c;
+      href = h;
+    }
+  }
+}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/cookbook/HelloForm.gwt.xml b/src/main/java/com/googlesource/gerrit/plugins/cookbook/HelloForm.gwt.xml
new file mode 100644
index 0000000..6616bca
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/cookbook/HelloForm.gwt.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+-->
+<module rename-to="cookbook">
+  <!-- Inherit the core Web Toolkit stuff.                        -->
+  <inherits name="com.google.gwt.user.User"/>
+  <!-- Other module inherits                                      -->
+  <inherits name="com.google.gerrit.Plugin"/>
+  <inherits name="com.google.gwt.http.HTTP"/>
+  <inherits name="com.google.gwt.json.JSON"/>
+  <!-- Using GWT built-in themes adds a number of static          -->
+  <!-- resources to the plugin. No theme inherits lines were      -->
+  <!-- added in order to make this plugin as simple as possible   -->
+  <!-- Specify the app entry point class.                         -->
+  <entry-point class="com.googlesource.gerrit.plugins.cookbook.client.CookBookPlugin"/>
+  <stylesheet src="cookbook.css"/>
+</module>
diff --git a/src/main/java/com/googlesource/gerrit/plugins/cookbook/HelloTopMenu.java b/src/main/java/com/googlesource/gerrit/plugins/cookbook/HelloTopMenu.java
index d7a4bf0..4d98601 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/cookbook/HelloTopMenu.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/cookbook/HelloTopMenu.java
@@ -27,9 +27,10 @@
   @Inject
   public HelloTopMenu(@PluginName String pluginName) {
     String baseUrl = "/plugins/" + pluginName + "/";
-    List<MenuItem> menuItems = Lists.newArrayListWithCapacity(1);
+    List<MenuItem> menuItems = Lists.newArrayListWithCapacity(2);
+    menuItems.add(new MenuItem("Greeting", "#/x/" + pluginName + "/", ""));
     menuItems.add(new MenuItem("Documentation", baseUrl));
-    menuEntries = Lists.newArrayListWithCapacity(1);
+    menuEntries = Lists.newArrayListWithCapacity(2);
     menuEntries.add(new MenuEntry("Cookbook", menuItems));
     menuEntries.add(new MenuEntry("Projects", Lists.newArrayList(
         new MenuItem("Browse Repositories", "https://gerrit.googlesource.com/"))));
diff --git a/src/main/java/com/googlesource/gerrit/plugins/cookbook/HelloWorldServlet.java b/src/main/java/com/googlesource/gerrit/plugins/cookbook/HelloWorldServlet.java
index c8823bf..9bb80a3 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/cookbook/HelloWorldServlet.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/cookbook/HelloWorldServlet.java
@@ -22,11 +22,24 @@
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
+import com.google.gerrit.extensions.annotations.PluginCanonicalWebUrl;
+import com.google.gerrit.extensions.annotations.PluginName;
+import com.google.inject.Inject;
 import com.google.inject.Singleton;
 
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
 @Singleton
 class HelloWorldServlet extends HttpServlet {
   private static final long serialVersionUID = 1L;
+  private static final Logger log = LoggerFactory.getLogger(HelloWorldServlet.class);
+
+  @Inject
+  public HelloWorldServlet(@PluginName String pluginName,
+      @PluginCanonicalWebUrl String url) {
+    log.info(String.format("Cookbook Plugin '%s' at url %s", pluginName, url));
+  }
 
   @Override
   protected void doGet(final HttpServletRequest req,
diff --git a/src/main/java/com/googlesource/gerrit/plugins/cookbook/HttpModule.java b/src/main/java/com/googlesource/gerrit/plugins/cookbook/HttpModule.java
index 6504563..5df7a2b 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/cookbook/HttpModule.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/cookbook/HttpModule.java
@@ -15,6 +15,7 @@
 package com.googlesource.gerrit.plugins.cookbook;
 
 import com.google.gerrit.extensions.registration.DynamicSet;
+import com.google.gerrit.extensions.webui.GwtPlugin;
 import com.google.gerrit.extensions.webui.JavaScriptPlugin;
 import com.google.gerrit.extensions.webui.WebUiPlugin;
 import com.google.gerrit.httpd.plugins.HttpPluginModule;
@@ -24,8 +25,14 @@
   protected void configureServlets() {
     serve("/say-hello/*").with(HelloWorldServlet.class);
     DynamicSet.bind(binder(), WebUiPlugin.class)
+        .toInstance(new JavaScriptPlugin("greetings.js"));
+    DynamicSet.bind(binder(), WebUiPlugin.class)
+        .toInstance(new JavaScriptPlugin("hello-change.js"));
+    DynamicSet.bind(binder(), WebUiPlugin.class)
         .toInstance(new JavaScriptPlugin("hello-project.js"));
     DynamicSet.bind(binder(), WebUiPlugin.class)
         .toInstance(new JavaScriptPlugin("hello-revision.js"));
+    DynamicSet.bind(binder(), WebUiPlugin.class)
+        .toInstance(new GwtPlugin("cookbook"));
   }
 }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/cookbook/Module.java b/src/main/java/com/googlesource/gerrit/plugins/cookbook/Module.java
index 8591acf..ae04cdc 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/cookbook/Module.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/cookbook/Module.java
@@ -17,9 +17,13 @@
 import static com.google.gerrit.server.change.RevisionResource.REVISION_KIND;
 import static com.google.gerrit.server.project.ProjectResource.PROJECT_KIND;
 
+import com.google.common.collect.ImmutableList;
+import com.google.gerrit.extensions.annotations.Exports;
 import com.google.gerrit.extensions.registration.DynamicSet;
 import com.google.gerrit.extensions.restapi.RestApiModule;
 import com.google.gerrit.extensions.webui.TopMenu;
+import com.google.gerrit.reviewdb.client.Project.InheritableBoolean;
+import com.google.gerrit.server.config.ProjectConfigEntry;
 import com.google.inject.AbstractModule;
 
 public class Module extends AbstractModule {
@@ -33,7 +37,40 @@
       protected void configure() {
         post(REVISION_KIND, "hello-revision").to(HelloRevisionAction.class);
         post(PROJECT_KIND, "hello-project").to(HelloProjectAction.class);
+        get(REVISION_KIND, "greetings").to(Greetings.class);
       }
     });
+    configurePluginParameters();
+  }
+
+  private void configurePluginParameters() {
+    bind(ProjectConfigEntry.class)
+        .annotatedWith(Exports.named("enable-hello"))
+        .toInstance(new ProjectConfigEntry("Enable Greeting", true));
+    bind(ProjectConfigEntry.class)
+       .annotatedWith(Exports.named("enable-goodbye"))
+       .toInstance(new ProjectConfigEntry("Enable Say Goodbye",
+           InheritableBoolean.TRUE,
+           InheritableBoolean.class, true));
+    bind(ProjectConfigEntry.class)
+       .annotatedWith(Exports.named("default-greeting"))
+       .toInstance(new ProjectConfigEntry("Default Greeting",
+           "Hey dude, how are you?", true));
+    bind(ProjectConfigEntry.class)
+        .annotatedWith(Exports.named("language"))
+        .toInstance(new ProjectConfigEntry("Preferred Language", "en",
+            ImmutableList.of("en", "de", "fr"), true));
+    bind(ProjectConfigEntry.class)
+        .annotatedWith(Exports.named("greet-number-per-week"))
+        .toInstance(new ProjectConfigEntry("Greets Per Week", 42, true));
+    bind(ProjectConfigEntry.class)
+       .annotatedWith(Exports.named("greet-number-per-year"))
+       .toInstance(new ProjectConfigEntry("Greets Per Year", 4711L, true));
+    bind(ProjectConfigEntry.class)
+       .annotatedWith(Exports.named("reviewers"))
+        .toInstance(
+            new ProjectConfigEntry("Reviewers", null,
+                ProjectConfigEntry.Type.ARRAY, null, false,
+                "Users or groups can be provided as reviewers"));
   }
 }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/cookbook/client/CookBookPlugin.java b/src/main/java/com/googlesource/gerrit/plugins/cookbook/client/CookBookPlugin.java
new file mode 100644
index 0000000..e9ace38
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/cookbook/client/CookBookPlugin.java
@@ -0,0 +1,25 @@
+// 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.googlesource.gerrit.plugins.cookbook.client;
+
+import com.google.gerrit.plugin.client.Plugin;
+import com.google.gerrit.plugin.client.PluginEntryPoint;
+
+public class CookBookPlugin extends PluginEntryPoint {
+  @Override
+  public void onPluginLoad() {
+    Plugin.get().screen("", new IndexScreen.Factory());
+  }
+}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/cookbook/client/IndexScreen.java b/src/main/java/com/googlesource/gerrit/plugins/cookbook/client/IndexScreen.java
new file mode 100644
index 0000000..c50dc36
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/cookbook/client/IndexScreen.java
@@ -0,0 +1,124 @@
+// 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.googlesource.gerrit.plugins.cookbook.client;
+
+import com.google.gerrit.plugin.client.screen.Screen;
+import com.google.gwt.core.client.Scheduler;
+import com.google.gwt.core.client.Scheduler.ScheduledCommand;
+import com.google.gwt.event.dom.client.ClickEvent;
+import com.google.gwt.event.dom.client.ClickHandler;
+import com.google.gwt.event.dom.client.KeyPressEvent;
+import com.google.gwt.event.dom.client.KeyPressHandler;
+import com.google.gwt.user.client.Event;
+import com.google.gwt.user.client.Window;
+import com.google.gwt.user.client.ui.Button;
+import com.google.gwt.user.client.ui.Label;
+import com.google.gwt.user.client.ui.Panel;
+import com.google.gwt.user.client.ui.TextArea;
+import com.google.gwt.user.client.ui.TextBox;
+import com.google.gwt.user.client.ui.VerticalPanel;
+
+class IndexScreen extends VerticalPanel {
+  static class Factory implements Screen.EntryPoint {
+    @Override
+    public void onLoad(Screen screen) {
+      screen.setPageTitle("cookbook index");
+      screen.show(new IndexScreen());
+    }
+  }
+
+  private TextBox usernameTxt;
+  private TextArea greetingTxt;
+
+  IndexScreen() {
+    setStyleName("cookbook-panel");
+
+    Panel usernamePanel = new VerticalPanel();
+    usernamePanel.add(new Label("Username:"));
+    usernameTxt = new TextBox() {
+      @Override
+      public void onBrowserEvent(Event event) {
+        super.onBrowserEvent(event);
+        if (event.getTypeInt() == Event.ONPASTE) {
+          Scheduler.get().scheduleDeferred(new ScheduledCommand() {
+            @Override
+            public void execute() {
+              if (getValue().trim().length() != 0) {
+                setEnabled(true);
+              }
+            }
+          });
+        }
+      }
+    };
+    usernameTxt.addKeyPressHandler(new KeyPressHandler() {
+      @Override
+      public void onKeyPress(final KeyPressEvent event) {
+        event.stopPropagation();
+      }
+    });
+    usernameTxt.sinkEvents(Event.ONPASTE);
+    usernameTxt.setVisibleLength(40);
+    usernamePanel.add(usernameTxt);
+    add(usernamePanel);
+
+    Panel messagePanel = new VerticalPanel();
+    messagePanel.add(new Label("Message:"));
+    greetingTxt = new TextArea();
+    greetingTxt.addKeyPressHandler(new KeyPressHandler() {
+      @Override
+      public void onKeyPress(final KeyPressEvent event) {
+        event.stopPropagation();
+      }
+    });
+    greetingTxt.setVisibleLines(12);
+    greetingTxt.setCharacterWidth(80);
+    greetingTxt.getElement().setPropertyBoolean("spellcheck", false);
+    messagePanel.add(greetingTxt);
+    add(messagePanel);
+
+    Button helloButton = new Button("Say Hello");
+    helloButton.addStyleName("cookbook-helloButton");
+    helloButton.addClickHandler(new ClickHandler() {
+      @Override
+      public void onClick(final ClickEvent event) {
+        sayHello();
+      }
+    });
+    add(helloButton);
+    helloButton.setEnabled(true);
+  }
+
+  private void sayHello() {
+    String username = usernameTxt.getValue();
+    String greeting = greetingTxt.getText();
+    if (username == null) {
+      username = "";
+    } else {
+      username = username.trim();
+    }
+    if (greeting == null) {
+      greeting = "";
+    } else {
+      greeting = greeting.trim();
+    }
+    StringBuilder sb = new StringBuilder();
+    sb.append("Hey ");
+    sb.append(username.isEmpty() ? "Dude" : username);
+    sb.append(", ");
+    sb.append(greeting.isEmpty() ? "what's up?" : greeting);
+    Window.alert(sb.toString());
+  }
+}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/cookbook/public/cookbook.css b/src/main/java/com/googlesource/gerrit/plugins/cookbook/public/cookbook.css
new file mode 100644
index 0000000..dd4f2a4
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/cookbook/public/cookbook.css
@@ -0,0 +1,8 @@
+.cookbook-panel {
+  border-spacing: 0px 5px;
+}
+
+.cookbook-helloButton {
+  margin-left: 35px !important;
+  margin-right: 450px !important;
+}
diff --git a/src/main/resources/Documentation/build.md b/src/main/resources/Documentation/build.md
new file mode 100644
index 0000000..6044d40
--- /dev/null
+++ b/src/main/resources/Documentation/build.md
@@ -0,0 +1,38 @@
+Build
+=====
+
+This plugin is built with Buck.
+
+Clone or link this plugin to the plugins directory of Gerrit's source
+tree, and issue the command:
+
+```
+  buck build plugins/cookbook-plugin
+```
+
+The output is created in
+
+```
+  buck-out/gen/plugins/cookbook-plugin/cookbook-plugin.jar
+```
+
+This project can be imported into the Eclipse IDE:
+
+```
+  ./tools/eclipse/project.py
+```
+
+Note that for compatibility reasons a Maven build is provided, but is considered
+to be deprecated and will be removed in a future version of this plugin.
+
+To build with Maven, change directory to the plugin folder and issue the
+command:
+
+```
+  mvn clean package
+```
+
+When building with Maven, the Gerrit Plugin API must be available.
+
+How to build the Gerrit Plugin API is described in the [Gerrit
+documentation](../../../Documentation/dev-buck.html#_extension_and_plugin_api_jar_files).
diff --git a/src/main/resources/static/greetings.js b/src/main/resources/static/greetings.js
new file mode 100644
index 0000000..49d43df
--- /dev/null
+++ b/src/main/resources/static/greetings.js
@@ -0,0 +1,55 @@
+// 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.
+
+Gerrit.install(function(self) {
+    function onOpenChange(c, r) {
+      var url = "changes/"
+          + c._number
+          + "/revisions/"
+          + r._number
+          + "/"
+          + self.getPluginName()
+          + "~"
+          + "greetings";
+      var change_plugins = document
+          .getElementById('change_plugins');
+      Gerrit.get(url, function(r) {
+         var doc = document;
+         var frg = doc.createDocumentFragment();
+         var table = doc.createElement('table');
+         frg.appendChild(table);
+         for (var i = 0; i < r.length; i++) {
+           // row
+           var tr = doc.createElement('tr');
+           // greet
+           var g = r[i];
+           // first column: message
+           var td = doc.createElement('td');
+           td.appendChild(doc.createTextNode(g.message));
+           tr.appendChild(td);
+           // second column: country
+           td = doc.createElement('td');
+           var a = doc.createElement('a');
+           a.href = g.href;
+           a.appendChild(doc.createTextNode(g.country));
+           td.appendChild(a);
+           tr.appendChild(td);
+           table.appendChild(tr);
+         }
+         // add frg to #change_plugins container
+         change_plugins.appendChild(frg);
+      });
+    }
+    Gerrit.on('showchange', onOpenChange);
+  });
diff --git a/src/main/resources/static/hello-change.js b/src/main/resources/static/hello-change.js
new file mode 100644
index 0000000..4c668fd
--- /dev/null
+++ b/src/main/resources/static/hello-change.js
@@ -0,0 +1,33 @@
+// 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.
+
+Gerrit.install(function(self) {
+    function onShowChange(c, r) {
+      console.log("Show change: "
+          + c.id
+          + ", revision: " + r.name);
+    }
+    function onSubmitChange(c, r) {
+      return confirm("Really submit change:\n"
+          + c.id + "\n"
+          + "revision: " + r.name
+          + "?");
+    }
+    function onHistory(t) {
+      console.log("History: " + t);
+    }
+    Gerrit.on('showchange', onShowChange);
+    Gerrit.on('submitchange', onSubmitChange);
+    Gerrit.on('history', onHistory);
+  });