You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@zeppelin.apache.org by mo...@apache.org on 2016/01/23 18:28:52 UTC

[2/2] incubator-zeppelin git commit: [ZEPPELIN-551] Add paragraph scope for angular object

[ZEPPELIN-551] Add paragraph scope for angular object

### What is this PR for?

Add paragraph scope for angular object. While it changes some internal api and ZeppelinServer - Interpreter process protocol (thrift), it's better be merged after creating 0.5.6 release branch

### What type of PR is it?
Improvement

### Is there a relevant Jira issue?
https://issues.apache.org/jira/browse/ZEPPELIN-551

### How should this be tested?
Creating AngularObject now taking 'paragraphId' as a parameter in addition to 'noteId'.
When 'paragraphId' is null, the AngularObject becomes notebook scope, otherwise it becomes paragraph scope.

### Screenshots (if appropriate)

### Questions:
* Does the licenses files need update? no
* Is there breaking changes for older versions? Yes

Incompatible with interpreter binary that built with older version because of this PR updates thrift idl

* Does this needs documentation? internal api change

Author: Lee moon soo <mo...@apache.org>

Closes #588 from Leemoonsoo/ZEPPELIN-551 and squashes the following commits:

11d27a8 [Lee moon soo] Merge branch 'master' into ZEPPELIN-551
b9a55fe [Lee moon soo] Add javadoc
917c1ca [Lee moon soo] Reduce build log message
1bba810 [Lee moon soo] Remove unused var
25aea61 [Lee moon soo] Handle scope correctly
8d7c07d [Lee moon soo] Add more tests
7d7fe2c [Lee moon soo] Fix test
f2fa347 [Lee moon soo] Take care paragraphs scope angular object
9d24a3b [Lee moon soo] Update ZeppelinContext
f35fe8e [Lee moon soo] Update zeppelin-server and zeppelin-zengine
8b13c1e [Lee moon soo] Add paragraph scope of angular object


Project: http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/commit/882cdead
Tree: http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/tree/882cdead
Diff: http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/diff/882cdead

Branch: refs/heads/master
Commit: 882cdead7e9dfead3228ea662a4ea2438547c1e9
Parents: 2714d28
Author: Lee moon soo <mo...@apache.org>
Authored: Wed Jan 20 19:19:23 2016 -0800
Committer: Lee moon soo <mo...@apache.org>
Committed: Sat Jan 23 09:31:24 2016 -0800

----------------------------------------------------------------------
 .../apache/zeppelin/spark/ZeppelinContext.java  |  55 +--
 testing/startSparkCluster.sh                    |   4 +-
 .../apache/zeppelin/display/AngularObject.java  | 103 ++++-
 .../zeppelin/display/AngularObjectRegistry.java | 143 +++++--
 .../display/AngularObjectRegistryListener.java  |   2 +-
 .../interpreter/remote/RemoteAngularObject.java |  10 +-
 .../remote/RemoteAngularObjectRegistry.java     |  28 +-
 .../remote/RemoteInterpreterEventPoller.java    |   7 +-
 .../remote/RemoteInterpreterProcess.java        |   4 +-
 .../remote/RemoteInterpreterServer.java         |  20 +-
 .../thrift/RemoteInterpreterService.java        | 423 ++++++++++++++++---
 .../main/thrift/RemoteInterpreterService.thrift |   7 +-
 .../display/AngularObjectRegistryTest.java      |  62 ++-
 .../zeppelin/display/AngularObjectTest.java     |  55 ++-
 .../remote/RemoteAngularObjectTest.java         |  14 +-
 .../remote/mock/MockInterpreterAngular.java     |  12 +-
 .../apache/zeppelin/socket/NotebookServer.java  |  37 +-
 .../zeppelin/socket/NotebookServerTest.java     |   4 +-
 zeppelin-web/src/app/app.controller.js          |   1 -
 .../src/app/notebook/notebook.controller.js     |  49 ---
 .../notebook/paragraph/paragraph.controller.js  |  85 +++-
 .../websocketEvents/websocketMsg.service.js     |   3 +-
 zeppelin-web/test/spec/controllers/paragraph.js |   4 +-
 .../java/org/apache/zeppelin/notebook/Note.java |  17 +
 .../org/apache/zeppelin/notebook/Notebook.java  |   7 +-
 .../apache/zeppelin/notebook/NotebookTest.java  |  16 +-
 26 files changed, 911 insertions(+), 261 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/blob/882cdead/spark/src/main/java/org/apache/zeppelin/spark/ZeppelinContext.java
----------------------------------------------------------------------
diff --git a/spark/src/main/java/org/apache/zeppelin/spark/ZeppelinContext.java b/spark/src/main/java/org/apache/zeppelin/spark/ZeppelinContext.java
index 6869161..926f3e7 100644
--- a/spark/src/main/java/org/apache/zeppelin/spark/ZeppelinContext.java
+++ b/spark/src/main/java/org/apache/zeppelin/spark/ZeppelinContext.java
@@ -427,7 +427,7 @@ public class ZeppelinContext extends HashMap<String, Object> {
 
   /**
    * Run paragraphs
-   * @param paragraphIdOrIdxs list of paragraph id or idx
+   * @param paragraphIdOrIdx list of paragraph id or idx
    */
   public void run(List<Object> paragraphIdOrIdx, InterpreterContext context) {
     for (Object idOrIdx : paragraphIdOrIdx) {
@@ -475,17 +475,17 @@ public class ZeppelinContext extends HashMap<String, Object> {
     AngularObjectRegistry registry = interpreterContext.getAngularObjectRegistry();
     String noteId = interpreterContext.getNoteId();
     // try get local object
-    AngularObject ao = registry.get(name, interpreterContext.getNoteId());
+    AngularObject ao = registry.get(name, interpreterContext.getNoteId(), null);
     if (ao == null) {
       // then global object
-      ao = registry.get(name, null);
+      ao = registry.get(name, null, null);
     }
     return ao;
   }
 
 
   /**
-   * Get angular object. Look up local registry first and then global registry
+   * Get angular object. Look up notebook scope first and then global scope
    * @param name variable name
    * @return value
    */
@@ -499,13 +499,13 @@ public class ZeppelinContext extends HashMap<String, Object> {
   }
 
   /**
-   * Get angular object. Look up global registry
+   * Get angular object. Look up global scope
    * @param name variable name
    * @return value
    */
   public Object angularGlobal(String name) {
     AngularObjectRegistry registry = interpreterContext.getAngularObjectRegistry();
-    AngularObject ao = registry.get(name, null);
+    AngularObject ao = registry.get(name, null, null);
     if (ao == null) {
       return null;
     } else {
@@ -514,7 +514,7 @@ public class ZeppelinContext extends HashMap<String, Object> {
   }
 
   /**
-   * Create angular variable in local registry and bind with front end Angular display system.
+   * Create angular variable in notebook scope and bind with front end Angular display system.
    * If variable exists, it'll be overwritten.
    * @param name name of the variable
    * @param o value
@@ -524,7 +524,7 @@ public class ZeppelinContext extends HashMap<String, Object> {
   }
 
   /**
-   * Create angular variable in global registry and bind with front end Angular display system.
+   * Create angular variable in global scope and bind with front end Angular display system.
    * If variable exists, it'll be overwritten.
    * @param name name of the variable
    * @param o value
@@ -534,7 +534,7 @@ public class ZeppelinContext extends HashMap<String, Object> {
   }
 
   /**
-   * Create angular variable in local registry and bind with front end Angular display system.
+   * Create angular variable in local scope and bind with front end Angular display system.
    * If variable exists, value will be overwritten and watcher will be added.
    * @param name name of variable
    * @param o value
@@ -545,7 +545,7 @@ public class ZeppelinContext extends HashMap<String, Object> {
   }
 
   /**
-   * Create angular variable in global registry and bind with front end Angular display system.
+   * Create angular variable in global scope and bind with front end Angular display system.
    * If variable exists, value will be overwritten and watcher will be added.
    * @param name name of variable
    * @param o value
@@ -556,7 +556,7 @@ public class ZeppelinContext extends HashMap<String, Object> {
   }
 
   /**
-   * Add watcher into angular variable (local registry)
+   * Add watcher into angular variable (local scope)
    * @param name name of the variable
    * @param watcher watcher
    */
@@ -565,7 +565,7 @@ public class ZeppelinContext extends HashMap<String, Object> {
   }
 
   /**
-   * Add watcher into angular variable (global registry)
+   * Add watcher into angular variable (global scope)
    * @param name name of the variable
    * @param watcher watcher
    */
@@ -649,7 +649,7 @@ public class ZeppelinContext extends HashMap<String, Object> {
   }
 
   /**
-   * Create angular variable in local registry and bind with front end Angular display system.
+   * Create angular variable in notebook scope and bind with front end Angular display system.
    * If variable exists, it'll be overwritten.
    * @param name name of the variable
    * @param o value
@@ -657,15 +657,16 @@ public class ZeppelinContext extends HashMap<String, Object> {
   private void angularBind(String name, Object o, String noteId) {
     AngularObjectRegistry registry = interpreterContext.getAngularObjectRegistry();
 
-    if (registry.get(name, noteId) == null) {
-      registry.add(name, o, noteId);
+    if (registry.get(name, noteId, null) == null) {
+      registry.add(name, o, noteId, null);
     } else {
-      registry.get(name, noteId).set(o);
+      registry.get(name, noteId, null).set(o);
     }
   }
 
   /**
-   * Create angular variable in local registry and bind with front end Angular display system.
+   * Create angular variable in notebook scope and bind with front end Angular display
+   * system.
    * If variable exists, value will be overwritten and watcher will be added.
    * @param name name of variable
    * @param o value
@@ -674,10 +675,10 @@ public class ZeppelinContext extends HashMap<String, Object> {
   private void angularBind(String name, Object o, String noteId, AngularObjectWatcher watcher) {
     AngularObjectRegistry registry = interpreterContext.getAngularObjectRegistry();
 
-    if (registry.get(name, noteId) == null) {
-      registry.add(name, o, noteId);
+    if (registry.get(name, noteId, null) == null) {
+      registry.add(name, o, noteId, null);
     } else {
-      registry.get(name, noteId).set(o);
+      registry.get(name, noteId, null).set(o);
     }
     angularWatch(name, watcher);
   }
@@ -690,8 +691,8 @@ public class ZeppelinContext extends HashMap<String, Object> {
   private void angularWatch(String name, String noteId, AngularObjectWatcher watcher) {
     AngularObjectRegistry registry = interpreterContext.getAngularObjectRegistry();
 
-    if (registry.get(name, noteId) != null) {
-      registry.get(name, noteId).addWatcher(watcher);
+    if (registry.get(name, noteId, null) != null) {
+      registry.get(name, noteId, null).addWatcher(watcher);
     }
   }
 
@@ -729,8 +730,8 @@ public class ZeppelinContext extends HashMap<String, Object> {
    */
   private void angularUnwatch(String name, String noteId, AngularObjectWatcher watcher) {
     AngularObjectRegistry registry = interpreterContext.getAngularObjectRegistry();
-    if (registry.get(name, noteId) != null) {
-      registry.get(name, noteId).removeWatcher(watcher);
+    if (registry.get(name, noteId, null) != null) {
+      registry.get(name, noteId, null).removeWatcher(watcher);
     }
   }
 
@@ -740,8 +741,8 @@ public class ZeppelinContext extends HashMap<String, Object> {
    */
   private void angularUnwatch(String name, String noteId) {
     AngularObjectRegistry registry = interpreterContext.getAngularObjectRegistry();
-    if (registry.get(name, noteId) != null) {
-      registry.get(name, noteId).clearAllWatchers();
+    if (registry.get(name, noteId, null) != null) {
+      registry.get(name, noteId, null).clearAllWatchers();
     }
   }
 
@@ -751,6 +752,6 @@ public class ZeppelinContext extends HashMap<String, Object> {
    */
   private void angularUnbind(String name, String noteId) {
     AngularObjectRegistry registry = interpreterContext.getAngularObjectRegistry();
-    registry.remove(name, noteId);
+    registry.remove(name, noteId, null);
   }
 }

http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/blob/882cdead/testing/startSparkCluster.sh
----------------------------------------------------------------------
diff --git a/testing/startSparkCluster.sh b/testing/startSparkCluster.sh
index 7333ab0..8b7ad36 100755
--- a/testing/startSparkCluster.sh
+++ b/testing/startSparkCluster.sh
@@ -34,7 +34,7 @@ if [ ! -d "${SPARK_HOME}" ]; then
     echo "${SPARK_VERSION}" | grep "^1.[12].[0-9]" > /dev/null
     if [ $? -eq 0 ]; then
         # spark 1.1.x and spark 1.2.x can be downloaded from archive
-        wget http://archive.apache.org/dist/spark/spark-${SPARK_VERSION}/spark-${SPARK_VERSION}-bin-hadoop${HADOOP_VERSION}.tgz
+        wget -q http://archive.apache.org/dist/spark/spark-${SPARK_VERSION}/spark-${SPARK_VERSION}-bin-hadoop${HADOOP_VERSION}.tgz
     else
         # spark 1.3.x and later can be downloaded from mirror
         # get download address from mirror
@@ -42,7 +42,7 @@ if [ ! -d "${SPARK_HOME}" ]; then
 
         PREFFERED=$(echo "${MIRROR_INFO}" | grep preferred | sed 's/[^"]*.preferred.: .\([^"]*\).*/\1/g')
         PATHINFO=$(echo "${MIRROR_INFO}" | grep path_info | sed 's/[^"]*.path_info.: .\([^"]*\).*/\1/g')
-        wget "${PREFFERED}${PATHINFO}"
+        wget -q "${PREFFERED}${PATHINFO}"
     fi
     tar zxf spark-${SPARK_VERSION}-bin-hadoop${HADOOP_VERSION}.tgz
 fi

http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/blob/882cdead/zeppelin-interpreter/src/main/java/org/apache/zeppelin/display/AngularObject.java
----------------------------------------------------------------------
diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/display/AngularObject.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/display/AngularObject.java
index cebe4cc..4b0c3e9 100644
--- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/display/AngularObject.java
+++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/display/AngularObject.java
@@ -26,7 +26,9 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 /**
- *
+ * AngularObject provides binding between back-end (interpreter) and front-end
+ * User provided object will automatically synchronized with front-end side.
+ * i.e. update from back-end will be sent to front-end, update from front-end will sent-to backend
  *
  * @param <T>
  */
@@ -39,27 +41,70 @@ public class AngularObject<T> {
     = new LinkedList<AngularObjectWatcher>();
   
   private String noteId;   // noteId belonging to. null for global scope 
-
-  protected AngularObject(String name, T o, String noteId,
+  private String paragraphId; // paragraphId belongs to. null for notebook scope
+
+  /**
+   * To create new AngularObject, use AngularObjectRegistry.add()
+   *
+   * @param name name of object
+   * @param o reference to user provided object to sent to front-end
+   * @param noteId noteId belongs to. can be null
+   * @param paragraphId paragraphId belongs to. can be null
+   * @param listener event listener
+   */
+  protected AngularObject(String name, T o, String noteId, String paragraphId,
       AngularObjectListener listener) {
     this.name = name;
     this.noteId = noteId;
+    this.paragraphId = paragraphId;
     this.listener = listener;
     object = o;
   }
 
+  /**
+   * Get name of this object
+   * @return name
+   */
   public String getName() {
     return name;
   }
-  
+
+  /**
+   * Set noteId
+   * @param noteId noteId belongs to. can be null
+   */
   public void setNoteId(String noteId) {
     this.noteId = noteId;
   }
-  
+
+  /**
+   * Get noteId
+   * @return noteId
+   */
   public String getNoteId() {
     return noteId;
   }
-  
+
+  /**
+   * get ParagraphId
+   * @return paragraphId
+   */
+  public String getParagraphId() {
+    return paragraphId;
+  }
+
+  /**
+   * Set paragraphId
+   * @param paragraphId paragraphId. can be null
+   */
+  public void setParagraphId(String paragraphId) {
+    this.paragraphId = paragraphId;
+  }
+
+  /**
+   * Check if it is global scope object
+   * @return true it is global scope
+   */
   public boolean isGlobal() {
     return noteId == null;
   }
@@ -70,26 +115,47 @@ public class AngularObject<T> {
       AngularObject ao = (AngularObject) o;
       if (noteId == null && ao.noteId == null ||
           (noteId != null && ao.noteId != null && noteId.equals(ao.noteId))) {
-        return name.equals(ao.name);
+        if (paragraphId == null && ao.paragraphId == null ||
+          (paragraphId != null && ao.paragraphId != null && paragraphId.equals(ao.paragraphId))) {
+          return name.equals(ao.name);
+        }
       }
     }
     return false;
   }
 
+  /**
+   * Get value
+   * @return
+   */
   public Object get() {
     return object;
   }
 
+  /**
+   * fire updated() event for listener
+   * Note that it does not invoke watcher.watch()
+   */
   public void emit(){
     if (listener != null) {
       listener.updated(this);
     }
   }
-  
+
+  /**
+   * Set value
+   * @param o reference to new user provided object
+   */
   public void set(T o) {
     set(o, true);
   }
 
+  /**
+   * Set value
+   * @param o reference to new user provided object
+   * @param emit false on skip firing event for listener. note that it does not skip invoke
+   *             watcher.watch() in any case
+   */
   public void set(T o, boolean emit) {
     final T before = object;
     final T after = o;
@@ -119,26 +185,47 @@ public class AngularObject<T> {
     }
   }
 
+  /**
+   * Set event listener for this object
+   * @param listener
+   */
   public void setListener(AngularObjectListener listener) {
     this.listener = listener;
   }
 
+  /**
+   * Get event listener of this object
+   * @return event listener
+   */
   public AngularObjectListener getListener() {
     return listener;
   }
 
+  /**
+   * Add a watcher for this object.
+   * Multiple watcher can be registered.
+   *
+   * @param watcher watcher to add
+   */
   public void addWatcher(AngularObjectWatcher watcher) {
     synchronized (watchers) {
       watchers.add(watcher);
     }
   }
 
+  /**
+   * Remove a watcher from this object
+   * @param watcher watcher to remove
+   */
   public void removeWatcher(AngularObjectWatcher watcher) {
     synchronized (watchers) {
       watchers.remove(watcher);
     }
   }
 
+  /**
+   * Remove all watchers from this object
+   */
   public void clearAllWatchers() {
     synchronized (watchers) {
       watchers.clear();

http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/blob/882cdead/zeppelin-interpreter/src/main/java/org/apache/zeppelin/display/AngularObjectRegistry.java
----------------------------------------------------------------------
diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/display/AngularObjectRegistry.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/display/AngularObjectRegistry.java
index d6bab7b..cf360af 100644
--- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/display/AngularObjectRegistry.java
+++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/display/AngularObjectRegistry.java
@@ -26,9 +26,10 @@ import java.util.Map;
 /**
  * AngularObjectRegistry keeps all the object that binded to Angular Display System.
  * AngularObjectRegistry is created per interpreter group.
- * It keeps two different set of AngularObjects :
- *  - globalRegistry: Shared to all notebook that uses the same interpreter group
- *  - localRegistry: AngularObject is valid only inside of a single notebook
+ * It provides three different scope of AngularObjects :
+ *  - Paragraphscope : AngularObject is valid in specific paragraph
+ *  - Notebook scope: AngularObject is valid in a single notebook
+ *  - Global scope : Shared to all notebook that uses the same interpreter group
  */
 public class AngularObjectRegistry {
   Map<String, Map<String, AngularObject>> registry = 
@@ -60,26 +61,36 @@ public class AngularObjectRegistry {
 
   /**
    * Add object into registry
-   * @param name
-   * @param o
-   * @param noteId noteId belonging to. null for global object.
-   * @return
+   *
+   * Paragraph scope when noteId and paragraphId both not null
+   * Notebook scope when paragraphId is null
+   * Global scope when noteId and paragraphId both null
+   *
+   * @param name Name of object
+   * @param o Reference to the object
+   * @param noteId noteId belonging to. null for global scope
+   * @param paragraphId paragraphId belongs to. null for notebook scope
+   * @return AngularObject that added
    */
-  public AngularObject add(String name, Object o, String noteId) {
-    return add(name, o, noteId, true);
+  public AngularObject add(String name, Object o, String noteId, String paragraphId) {
+    return add(name, o, noteId, paragraphId, true);
   }
 
-  private String getRegistryKey(String noteId) {
+  private String getRegistryKey(String noteId, String paragraphId) {
     if (noteId == null) {
       return GLOBAL_KEY;
     } else {
-      return noteId;
+      if (paragraphId == null) {
+        return noteId;
+      } else {
+        return noteId + "_" + paragraphId;
+      }
     }
   }
   
-  private Map<String, AngularObject> getRegistryForKey(String noteId) {
+  private Map<String, AngularObject> getRegistryForKey(String noteId, String paragraphId) {
     synchronized (registry) {
-      String key = getRegistryKey(noteId);
+      String key = getRegistryKey(noteId, paragraphId);
       if (!registry.containsKey(key)) {
         registry.put(key, new HashMap<String, AngularObject>());
       }
@@ -87,12 +98,27 @@ public class AngularObjectRegistry {
       return registry.get(key);
     }
   }
- 
-  public AngularObject add(String name, Object o, String noteId, boolean emit) {
-    AngularObject ao = createNewAngularObject(name, o, noteId);
+
+  /**
+   * Add object into registry
+   *
+   * Paragraph scope when noteId and paragraphId both not null
+   * Notebook scope when paragraphId is null
+   * Global scope when noteId and paragraphId both null
+   *
+   * @param name Name of object
+   * @param o Reference to the object
+   * @param noteId noteId belonging to. null for global scope
+   * @param paragraphId paragraphId belongs to. null for notebook scope
+   * @param emit skip firing onAdd event on false
+   * @return AngularObject that added
+   */
+  public AngularObject add(String name, Object o, String noteId, String paragraphId,
+                           boolean emit) {
+    AngularObject ao = createNewAngularObject(name, o, noteId, paragraphId);
 
     synchronized (registry) {
-      Map<String, AngularObject> noteLocalRegistry = getRegistryForKey(noteId);
+      Map<String, AngularObject> noteLocalRegistry = getRegistryForKey(noteId, paragraphId);
       noteLocalRegistry.put(name, ao);
       if (listener != null && emit) {
         listener.onAdd(interpreterId, ao);
@@ -102,49 +128,90 @@ public class AngularObjectRegistry {
     return ao;
   }
 
-  protected AngularObject createNewAngularObject(String name, Object o, String noteId) {
-    return new AngularObject(name, o, noteId, angularObjectListener);
+  protected AngularObject createNewAngularObject(String name, Object o, String noteId,
+                                                 String paragraphId) {
+    return new AngularObject(name, o, noteId, paragraphId, angularObjectListener);
   }
 
   protected AngularObjectListener getAngularObjectListener() {
     return angularObjectListener;
   }
 
-  public AngularObject remove(String name, String noteId) {
-    return remove(name, noteId, true);
+  /**
+   * Remove a object from registry
+   *
+   * @param name Name of object to remove
+   * @param noteId noteId belongs to. null for global scope
+   * @param paragraphId paragraphId belongs to. null for notebook scope
+   * @return removed object. null if object is not found in registry
+   */
+  public AngularObject remove(String name, String noteId, String paragraphId) {
+    return remove(name, noteId, paragraphId, true);
   }
 
-  public AngularObject remove(String name, String noteId, boolean emit) {
+  /**
+   * Remove a object from registry
+   *
+   * @param name Name of object to remove
+   * @param noteId noteId belongs to. null for global scope
+   * @param paragraphId paragraphId belongs to. null for notebook scope
+   * @param emit skip fireing onRemove event on false
+   * @return removed object. null if object is not found in registry
+   */
+  public AngularObject remove(String name, String noteId, String paragraphId, boolean emit) {
     synchronized (registry) {
-      Map<String, AngularObject> r = getRegistryForKey(noteId);
+      Map<String, AngularObject> r = getRegistryForKey(noteId, paragraphId);
       AngularObject o = r.remove(name);
       if (listener != null && emit) {
-        listener.onRemove(interpreterId, name, noteId);;
+        listener.onRemove(interpreterId, name, noteId, paragraphId);;
       }
       return o;
     }
   }
 
-  public void removeAll(String noteId) {
+  /**
+   * Remove all angular object in the scope.
+   *
+   * Remove all paragraph scope angular object when noteId and paragraphId both not null
+   * Remove all notebook scope angular object when paragraphId is null
+   * Remove all global scope angular objects when noteId and paragraphId both null
+   *
+   * @param noteId noteId
+   * @param paragraphId paragraphId
+   */
+  public void removeAll(String noteId, String paragraphId) {
     synchronized (registry) {
-      List<AngularObject> all = getAll(noteId);
+      List<AngularObject> all = getAll(noteId, paragraphId);
       for (AngularObject ao : all) {
-        remove(ao.getName(), noteId);
+        remove(ao.getName(), noteId, paragraphId);
       }
     }
   }
 
-  public AngularObject get(String name, String noteId) {
+  /**
+   * Get a object from registry
+   * @param name name of object
+   * @param noteId noteId that belongs to
+   * @param paragraphId paragraphId that belongs to
+   * @return angularobject. null when not found
+   */
+  public AngularObject get(String name, String noteId, String paragraphId) {
     synchronized (registry) {
-      Map<String, AngularObject> r = getRegistryForKey(noteId);
+      Map<String, AngularObject> r = getRegistryForKey(noteId, paragraphId);
       return r.get(name);
     }
   }
 
-  public List<AngularObject> getAll(String noteId) {
+  /**
+   * Get all object in the scope
+   * @param noteId noteId that belongs to
+   * @param paragraphId paragraphId that belongs to
+   * @return all angularobject in the scope
+   */
+  public List<AngularObject> getAll(String noteId, String paragraphId) {
     List<AngularObject> all = new LinkedList<AngularObject>();
     synchronized (registry) {
-      Map<String, AngularObject> r = getRegistryForKey(noteId);
+      Map<String, AngularObject> r = getRegistryForKey(noteId, paragraphId);
       if (r != null) {
         all.addAll(r.values());
       }
@@ -153,20 +220,24 @@ public class AngularObjectRegistry {
   }
   
   /**
-   * Get all object with global merged
+   * Get all angular object related to specific note.
+   * That includes all global scope objects, notebook scope objects and paragraph scope objects
+   * belongs to the noteId.
+   *
    * @param noteId
    * @return
    */
   public List<AngularObject> getAllWithGlobal(String noteId) {
     List<AngularObject> all = new LinkedList<AngularObject>();
     synchronized (registry) {
-      Map<String, AngularObject> global = getRegistryForKey(null);
+      Map<String, AngularObject> global = getRegistryForKey(null, null);
       if (global != null) {
         all.addAll(global.values());
       }
-      Map<String, AngularObject> local = getRegistryForKey(noteId);
-      if (local != null) {
-        all.addAll(local.values());
+      for (String key : registry.keySet()) {
+        if (key.startsWith(noteId)) {
+          all.addAll(registry.get(key).values());
+        }
       }
     }
     return all;

http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/blob/882cdead/zeppelin-interpreter/src/main/java/org/apache/zeppelin/display/AngularObjectRegistryListener.java
----------------------------------------------------------------------
diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/display/AngularObjectRegistryListener.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/display/AngularObjectRegistryListener.java
index 3ba57d7..103336d 100644
--- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/display/AngularObjectRegistryListener.java
+++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/display/AngularObjectRegistryListener.java
@@ -24,5 +24,5 @@ package org.apache.zeppelin.display;
 public interface AngularObjectRegistryListener {
   public void onAdd(String interpreterGroupId, AngularObject object);
   public void onUpdate(String interpreterGroupId, AngularObject object);
-  public void onRemove(String interpreterGroupId, String name, String noteId);
+  public void onRemove(String interpreterGroupId, String name, String noteId, String paragraphId);
 }

http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/blob/882cdead/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteAngularObject.java
----------------------------------------------------------------------
diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteAngularObject.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteAngularObject.java
index 351a2bb..8948b4e 100644
--- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteAngularObject.java
+++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteAngularObject.java
@@ -21,16 +21,17 @@ import org.apache.zeppelin.display.AngularObject;
 import org.apache.zeppelin.display.AngularObjectListener;
 
 /**
- *
+ * Proxy for AngularObject that exists in remote interpreter process
  */
 public class RemoteAngularObject extends AngularObject {
 
   private transient RemoteInterpreterProcess remoteInterpreterProcess;
 
-  RemoteAngularObject(String name, Object o, String noteId, String interpreterGroupId,
+  RemoteAngularObject(String name, Object o, String noteId, String paragraphId, String
+          interpreterGroupId,
       AngularObjectListener listener,
       RemoteInterpreterProcess remoteInterpreterProcess) {
-    super(name, o, noteId, listener);
+    super(name, o, noteId, paragraphId, listener);
     this.remoteInterpreterProcess = remoteInterpreterProcess;
   }
 
@@ -44,7 +45,8 @@ public class RemoteAngularObject extends AngularObject {
 
     if (emitRemoteProcess) {
       // send updated value to remote interpreter
-      remoteInterpreterProcess.updateRemoteAngularObject(getName(), getNoteId(), o);
+      remoteInterpreterProcess.updateRemoteAngularObject(getName(), getNoteId(), getParagraphId()
+              , o);
     }
   }
 }

http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/blob/882cdead/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteAngularObjectRegistry.java
----------------------------------------------------------------------
diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteAngularObjectRegistry.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteAngularObjectRegistry.java
index 9b33cb8..790ed95 100644
--- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteAngularObjectRegistry.java
+++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteAngularObjectRegistry.java
@@ -33,7 +33,7 @@ import org.slf4j.LoggerFactory;
 import com.google.gson.Gson;
 
 /**
- *
+ * Proxy for AngularObjectRegistry that exists in remote interpreter process
  */
 public class RemoteAngularObjectRegistry extends AngularObjectRegistry {
   Logger logger = LoggerFactory.getLogger(RemoteAngularObjectRegistry.class);
@@ -70,7 +70,8 @@ public class RemoteAngularObjectRegistry extends AngularObjectRegistry {
    * @param noteId
    * @return
    */
-  public AngularObject addAndNotifyRemoteProcess(String name, Object o, String noteId) {
+  public AngularObject addAndNotifyRemoteProcess(String name, Object o, String noteId, String
+          paragraphId) {
     Gson gson = new Gson();
     RemoteInterpreterProcess remoteInterpreterProcess = getRemoteInterpreterProcess();
     if (!remoteInterpreterProcess.isRunning()) {
@@ -81,8 +82,8 @@ public class RemoteAngularObjectRegistry extends AngularObjectRegistry {
     boolean broken = false;
     try {
       client = remoteInterpreterProcess.getClient();
-      client.angularObjectAdd(name, noteId, gson.toJson(o));
-      return super.add(name, o, noteId, true);
+      client.angularObjectAdd(name, noteId, paragraphId, gson.toJson(o));
+      return super.add(name, o, noteId, paragraphId, true);
     } catch (TException e) {
       broken = true;
       logger.error("Error", e);
@@ -101,9 +102,11 @@ public class RemoteAngularObjectRegistry extends AngularObjectRegistry {
    * this method should be used instead of remove()
    * @param name
    * @param noteId
+   * @param paragraphId
    * @return
    */
-  public AngularObject removeAndNotifyRemoteProcess(String name, String noteId) {
+  public AngularObject removeAndNotifyRemoteProcess(String name, String noteId, String
+          paragraphId) {
     RemoteInterpreterProcess remoteInterpreterProcess = getRemoteInterpreterProcess();
     if (!remoteInterpreterProcess.isRunning()) {
       return null;
@@ -113,8 +116,8 @@ public class RemoteAngularObjectRegistry extends AngularObjectRegistry {
     boolean broken = false;
     try {
       client = remoteInterpreterProcess.getClient();
-      client.angularObjectRemove(name, noteId);
-      return super.remove(name, noteId);
+      client.angularObjectRemove(name, noteId, paragraphId);
+      return super.remove(name, noteId, paragraphId);
     } catch (TException e) {
       broken = true;
       logger.error("Error", e);
@@ -128,20 +131,21 @@ public class RemoteAngularObjectRegistry extends AngularObjectRegistry {
     return null;
   }
   
-  public void removeAllAndNotifyRemoteProcess(String noteId) {
-    List<AngularObject> all = getAll(noteId);
+  public void removeAllAndNotifyRemoteProcess(String noteId, String paragraphId) {
+    List<AngularObject> all = getAll(noteId, paragraphId);
     for (AngularObject ao : all) {
-      removeAndNotifyRemoteProcess(ao.getName(), noteId);
+      removeAndNotifyRemoteProcess(ao.getName(), noteId, paragraphId);
     }
   }
 
   @Override
-  protected AngularObject createNewAngularObject(String name, Object o, String noteId) {
+  protected AngularObject createNewAngularObject(String name, Object o, String noteId, String
+          paragraphId) {
     RemoteInterpreterProcess remoteInterpreterProcess = getRemoteInterpreterProcess();
     if (remoteInterpreterProcess == null) {
       throw new RuntimeException("Remote Interpreter process not found");
     }
-    return new RemoteAngularObject(name, o, noteId, getInterpreterGroupId(),
+    return new RemoteAngularObject(name, o, noteId, paragraphId, getInterpreterGroupId(),
         getAngularObjectListener(),
         getRemoteInterpreterProcess());
   }

http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/blob/882cdead/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreterEventPoller.java
----------------------------------------------------------------------
diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreterEventPoller.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreterEventPoller.java
index 6186205..b1055e2 100644
--- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreterEventPoller.java
+++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreterEventPoller.java
@@ -94,12 +94,12 @@ public class RemoteInterpreterEventPoller extends Thread {
         } else if (event.getType() == RemoteInterpreterEventType.ANGULAR_OBJECT_ADD) {
           AngularObject angularObject = gson.fromJson(event.getData(), AngularObject.class);
           angularObjectRegistry.add(angularObject.getName(),
-              angularObject.get(), angularObject.getNoteId());
+              angularObject.get(), angularObject.getNoteId(), angularObject.getParagraphId());
         } else if (event.getType() == RemoteInterpreterEventType.ANGULAR_OBJECT_UPDATE) {
           AngularObject angularObject = gson.fromJson(event.getData(),
               AngularObject.class);
           AngularObject localAngularObject = angularObjectRegistry.get(
-              angularObject.getName(), angularObject.getNoteId());
+              angularObject.getName(), angularObject.getNoteId(), angularObject.getParagraphId());
           if (localAngularObject instanceof RemoteAngularObject) {
             // to avoid ping-pong loop
             ((RemoteAngularObject) localAngularObject).set(
@@ -109,7 +109,8 @@ public class RemoteInterpreterEventPoller extends Thread {
           }
         } else if (event.getType() == RemoteInterpreterEventType.ANGULAR_OBJECT_REMOVE) {
           AngularObject angularObject = gson.fromJson(event.getData(), AngularObject.class);
-          angularObjectRegistry.remove(angularObject.getName(), angularObject.getNoteId());
+          angularObjectRegistry.remove(angularObject.getName(), angularObject.getNoteId(),
+                  angularObject.getParagraphId());
         } else if (event.getType() == RemoteInterpreterEventType.RUN_INTERPRETER_CONTEXT_RUNNER) {
           InterpreterContextRunner runnerFromRemote = gson.fromJson(
               event.getData(), RemoteInterpreterContextRunner.class);

http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/blob/882cdead/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreterProcess.java
----------------------------------------------------------------------
diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreterProcess.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreterProcess.java
index 56b5485..5612a2b 100644
--- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreterProcess.java
+++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreterProcess.java
@@ -267,7 +267,7 @@ public class RemoteInterpreterProcess implements ExecuteResultHandler {
    * @param name
    * @param o
    */
-  public void updateRemoteAngularObject(String name, String noteId, Object o) {
+  public void updateRemoteAngularObject(String name, String noteId, String paragraphId, Object o) {
     Client client = null;
     try {
       client = getClient();
@@ -283,7 +283,7 @@ public class RemoteInterpreterProcess implements ExecuteResultHandler {
     boolean broken = false;
     try {
       Gson gson = new Gson();
-      client.angularObjectUpdate(name, noteId, gson.toJson(o));
+      client.angularObjectUpdate(name, noteId, paragraphId, gson.toJson(o));
     } catch (TException e) {
       broken = true;
       logger.error("Can't update angular object", e);

http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/blob/882cdead/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreterServer.java
----------------------------------------------------------------------
diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreterServer.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreterServer.java
index 728d210..a59293b 100644
--- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreterServer.java
+++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreterServer.java
@@ -480,7 +480,7 @@ public class RemoteInterpreterServer
   }
 
   @Override
-  public void onRemove(String interpreterGroupId, String name, String noteId) {
+  public void onRemove(String interpreterGroupId, String name, String noteId, String paragraphId) {
     Map<String, String> removeObject = new HashMap<String, String>();
     removeObject.put("name", name);
     removeObject.put("noteId", noteId);
@@ -519,15 +519,16 @@ public class RemoteInterpreterServer
    * called when object is updated in client (web) side.
    * @param name
    * @param noteId noteId where the update issues
+   * @param paragraphId paragraphId where the update issues
    * @param object
    * @throws TException
    */
   @Override
-  public void angularObjectUpdate(String name, String noteId, String object)
+  public void angularObjectUpdate(String name, String noteId, String paragraphId, String object)
       throws TException {
     AngularObjectRegistry registry = interpreterGroup.getAngularObjectRegistry();
     // first try local objects
-    AngularObject ao = registry.get(name, noteId);
+    AngularObject ao = registry.get(name, noteId, paragraphId);
     if (ao == null) {
       logger.error("Angular object {} not exists", name);
       return;
@@ -576,13 +577,13 @@ public class RemoteInterpreterServer
    * Dont't need to emit event to zeppelin server
    */
   @Override
-  public void angularObjectAdd(String name, String noteId, String object)
+  public void angularObjectAdd(String name, String noteId, String paragraphId, String object)
       throws TException {
     AngularObjectRegistry registry = interpreterGroup.getAngularObjectRegistry();
     // first try local objects
-    AngularObject ao = registry.get(name, noteId);
+    AngularObject ao = registry.get(name, noteId, paragraphId);
     if (ao != null) {
-      angularObjectUpdate(name, noteId, object);
+      angularObjectUpdate(name, noteId, paragraphId, object);
       return;
     }
 
@@ -602,12 +603,13 @@ public class RemoteInterpreterServer
       value = gson.fromJson(object, String.class);
     }
 
-    registry.add(name, value, noteId, false);
+    registry.add(name, value, noteId, paragraphId, false);
   }
 
   @Override
-  public void angularObjectRemove(String name, String noteId) throws TException {
+  public void angularObjectRemove(String name, String noteId, String paragraphId) throws
+          TException {
     AngularObjectRegistry registry = interpreterGroup.getAngularObjectRegistry();
-    registry.remove(name, noteId, false);
+    registry.remove(name, noteId, paragraphId, false);
   }
 }

http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/blob/882cdead/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterService.java
----------------------------------------------------------------------
diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterService.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterService.java
index 738b453..fbcc514 100644
--- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterService.java
+++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterService.java
@@ -78,11 +78,11 @@ public class RemoteInterpreterService {
 
     public RemoteInterpreterEvent getEvent() throws org.apache.thrift.TException;
 
-    public void angularObjectUpdate(String name, String noteId, String object) throws org.apache.thrift.TException;
+    public void angularObjectUpdate(String name, String noteId, String paragraphId, String object) throws org.apache.thrift.TException;
 
-    public void angularObjectAdd(String name, String noteId, String object) throws org.apache.thrift.TException;
+    public void angularObjectAdd(String name, String noteId, String paragraphId, String object) throws org.apache.thrift.TException;
 
-    public void angularObjectRemove(String name, String noteId) throws org.apache.thrift.TException;
+    public void angularObjectRemove(String name, String noteId, String paragraphId) throws org.apache.thrift.TException;
 
   }
 
@@ -110,11 +110,11 @@ public class RemoteInterpreterService {
 
     public void getEvent(org.apache.thrift.async.AsyncMethodCallback resultHandler) throws org.apache.thrift.TException;
 
-    public void angularObjectUpdate(String name, String noteId, String object, org.apache.thrift.async.AsyncMethodCallback resultHandler) throws org.apache.thrift.TException;
+    public void angularObjectUpdate(String name, String noteId, String paragraphId, String object, org.apache.thrift.async.AsyncMethodCallback resultHandler) throws org.apache.thrift.TException;
 
-    public void angularObjectAdd(String name, String noteId, String object, org.apache.thrift.async.AsyncMethodCallback resultHandler) throws org.apache.thrift.TException;
+    public void angularObjectAdd(String name, String noteId, String paragraphId, String object, org.apache.thrift.async.AsyncMethodCallback resultHandler) throws org.apache.thrift.TException;
 
-    public void angularObjectRemove(String name, String noteId, org.apache.thrift.async.AsyncMethodCallback resultHandler) throws org.apache.thrift.TException;
+    public void angularObjectRemove(String name, String noteId, String paragraphId, org.apache.thrift.async.AsyncMethodCallback resultHandler) throws org.apache.thrift.TException;
 
   }
 
@@ -381,17 +381,18 @@ public class RemoteInterpreterService {
       throw new org.apache.thrift.TApplicationException(org.apache.thrift.TApplicationException.MISSING_RESULT, "getEvent failed: unknown result");
     }
 
-    public void angularObjectUpdate(String name, String noteId, String object) throws org.apache.thrift.TException
+    public void angularObjectUpdate(String name, String noteId, String paragraphId, String object) throws org.apache.thrift.TException
     {
-      send_angularObjectUpdate(name, noteId, object);
+      send_angularObjectUpdate(name, noteId, paragraphId, object);
       recv_angularObjectUpdate();
     }
 
-    public void send_angularObjectUpdate(String name, String noteId, String object) throws org.apache.thrift.TException
+    public void send_angularObjectUpdate(String name, String noteId, String paragraphId, String object) throws org.apache.thrift.TException
     {
       angularObjectUpdate_args args = new angularObjectUpdate_args();
       args.setName(name);
       args.setNoteId(noteId);
+      args.setParagraphId(paragraphId);
       args.setObject(object);
       sendBase("angularObjectUpdate", args);
     }
@@ -403,17 +404,18 @@ public class RemoteInterpreterService {
       return;
     }
 
-    public void angularObjectAdd(String name, String noteId, String object) throws org.apache.thrift.TException
+    public void angularObjectAdd(String name, String noteId, String paragraphId, String object) throws org.apache.thrift.TException
     {
-      send_angularObjectAdd(name, noteId, object);
+      send_angularObjectAdd(name, noteId, paragraphId, object);
       recv_angularObjectAdd();
     }
 
-    public void send_angularObjectAdd(String name, String noteId, String object) throws org.apache.thrift.TException
+    public void send_angularObjectAdd(String name, String noteId, String paragraphId, String object) throws org.apache.thrift.TException
     {
       angularObjectAdd_args args = new angularObjectAdd_args();
       args.setName(name);
       args.setNoteId(noteId);
+      args.setParagraphId(paragraphId);
       args.setObject(object);
       sendBase("angularObjectAdd", args);
     }
@@ -425,17 +427,18 @@ public class RemoteInterpreterService {
       return;
     }
 
-    public void angularObjectRemove(String name, String noteId) throws org.apache.thrift.TException
+    public void angularObjectRemove(String name, String noteId, String paragraphId) throws org.apache.thrift.TException
     {
-      send_angularObjectRemove(name, noteId);
+      send_angularObjectRemove(name, noteId, paragraphId);
       recv_angularObjectRemove();
     }
 
-    public void send_angularObjectRemove(String name, String noteId) throws org.apache.thrift.TException
+    public void send_angularObjectRemove(String name, String noteId, String paragraphId) throws org.apache.thrift.TException
     {
       angularObjectRemove_args args = new angularObjectRemove_args();
       args.setName(name);
       args.setNoteId(noteId);
+      args.setParagraphId(paragraphId);
       sendBase("angularObjectRemove", args);
     }
 
@@ -831,9 +834,9 @@ public class RemoteInterpreterService {
       }
     }
 
-    public void angularObjectUpdate(String name, String noteId, String object, org.apache.thrift.async.AsyncMethodCallback resultHandler) throws org.apache.thrift.TException {
+    public void angularObjectUpdate(String name, String noteId, String paragraphId, String object, org.apache.thrift.async.AsyncMethodCallback resultHandler) throws org.apache.thrift.TException {
       checkReady();
-      angularObjectUpdate_call method_call = new angularObjectUpdate_call(name, noteId, object, resultHandler, this, ___protocolFactory, ___transport);
+      angularObjectUpdate_call method_call = new angularObjectUpdate_call(name, noteId, paragraphId, object, resultHandler, this, ___protocolFactory, ___transport);
       this.___currentMethod = method_call;
       ___manager.call(method_call);
     }
@@ -841,11 +844,13 @@ public class RemoteInterpreterService {
     public static class angularObjectUpdate_call extends org.apache.thrift.async.TAsyncMethodCall {
       private String name;
       private String noteId;
+      private String paragraphId;
       private String object;
-      public angularObjectUpdate_call(String name, String noteId, String object, org.apache.thrift.async.AsyncMethodCallback resultHandler, org.apache.thrift.async.TAsyncClient client, org.apache.thrift.protocol.TProtocolFactory protocolFactory, org.apache.thrift.transport.TNonblockingTransport transport) throws org.apache.thrift.TException {
+      public angularObjectUpdate_call(String name, String noteId, String paragraphId, String object, org.apache.thrift.async.AsyncMethodCallback resultHandler, org.apache.thrift.async.TAsyncClient client, org.apache.thrift.protocol.TProtocolFactory protocolFactory, org.apache.thrift.transport.TNonblockingTransport transport) throws org.apache.thrift.TException {
         super(client, protocolFactory, transport, resultHandler, false);
         this.name = name;
         this.noteId = noteId;
+        this.paragraphId = paragraphId;
         this.object = object;
       }
 
@@ -854,6 +859,7 @@ public class RemoteInterpreterService {
         angularObjectUpdate_args args = new angularObjectUpdate_args();
         args.setName(name);
         args.setNoteId(noteId);
+        args.setParagraphId(paragraphId);
         args.setObject(object);
         args.write(prot);
         prot.writeMessageEnd();
@@ -869,9 +875,9 @@ public class RemoteInterpreterService {
       }
     }
 
-    public void angularObjectAdd(String name, String noteId, String object, org.apache.thrift.async.AsyncMethodCallback resultHandler) throws org.apache.thrift.TException {
+    public void angularObjectAdd(String name, String noteId, String paragraphId, String object, org.apache.thrift.async.AsyncMethodCallback resultHandler) throws org.apache.thrift.TException {
       checkReady();
-      angularObjectAdd_call method_call = new angularObjectAdd_call(name, noteId, object, resultHandler, this, ___protocolFactory, ___transport);
+      angularObjectAdd_call method_call = new angularObjectAdd_call(name, noteId, paragraphId, object, resultHandler, this, ___protocolFactory, ___transport);
       this.___currentMethod = method_call;
       ___manager.call(method_call);
     }
@@ -879,11 +885,13 @@ public class RemoteInterpreterService {
     public static class angularObjectAdd_call extends org.apache.thrift.async.TAsyncMethodCall {
       private String name;
       private String noteId;
+      private String paragraphId;
       private String object;
-      public angularObjectAdd_call(String name, String noteId, String object, org.apache.thrift.async.AsyncMethodCallback resultHandler, org.apache.thrift.async.TAsyncClient client, org.apache.thrift.protocol.TProtocolFactory protocolFactory, org.apache.thrift.transport.TNonblockingTransport transport) throws org.apache.thrift.TException {
+      public angularObjectAdd_call(String name, String noteId, String paragraphId, String object, org.apache.thrift.async.AsyncMethodCallback resultHandler, org.apache.thrift.async.TAsyncClient client, org.apache.thrift.protocol.TProtocolFactory protocolFactory, org.apache.thrift.transport.TNonblockingTransport transport) throws org.apache.thrift.TException {
         super(client, protocolFactory, transport, resultHandler, false);
         this.name = name;
         this.noteId = noteId;
+        this.paragraphId = paragraphId;
         this.object = object;
       }
 
@@ -892,6 +900,7 @@ public class RemoteInterpreterService {
         angularObjectAdd_args args = new angularObjectAdd_args();
         args.setName(name);
         args.setNoteId(noteId);
+        args.setParagraphId(paragraphId);
         args.setObject(object);
         args.write(prot);
         prot.writeMessageEnd();
@@ -907,9 +916,9 @@ public class RemoteInterpreterService {
       }
     }
 
-    public void angularObjectRemove(String name, String noteId, org.apache.thrift.async.AsyncMethodCallback resultHandler) throws org.apache.thrift.TException {
+    public void angularObjectRemove(String name, String noteId, String paragraphId, org.apache.thrift.async.AsyncMethodCallback resultHandler) throws org.apache.thrift.TException {
       checkReady();
-      angularObjectRemove_call method_call = new angularObjectRemove_call(name, noteId, resultHandler, this, ___protocolFactory, ___transport);
+      angularObjectRemove_call method_call = new angularObjectRemove_call(name, noteId, paragraphId, resultHandler, this, ___protocolFactory, ___transport);
       this.___currentMethod = method_call;
       ___manager.call(method_call);
     }
@@ -917,10 +926,12 @@ public class RemoteInterpreterService {
     public static class angularObjectRemove_call extends org.apache.thrift.async.TAsyncMethodCall {
       private String name;
       private String noteId;
-      public angularObjectRemove_call(String name, String noteId, org.apache.thrift.async.AsyncMethodCallback resultHandler, org.apache.thrift.async.TAsyncClient client, org.apache.thrift.protocol.TProtocolFactory protocolFactory, org.apache.thrift.transport.TNonblockingTransport transport) throws org.apache.thrift.TException {
+      private String paragraphId;
+      public angularObjectRemove_call(String name, String noteId, String paragraphId, org.apache.thrift.async.AsyncMethodCallback resultHandler, org.apache.thrift.async.TAsyncClient client, org.apache.thrift.protocol.TProtocolFactory protocolFactory, org.apache.thrift.transport.TNonblockingTransport transport) throws org.apache.thrift.TException {
         super(client, protocolFactory, transport, resultHandler, false);
         this.name = name;
         this.noteId = noteId;
+        this.paragraphId = paragraphId;
       }
 
       public void write_args(org.apache.thrift.protocol.TProtocol prot) throws org.apache.thrift.TException {
@@ -928,6 +939,7 @@ public class RemoteInterpreterService {
         angularObjectRemove_args args = new angularObjectRemove_args();
         args.setName(name);
         args.setNoteId(noteId);
+        args.setParagraphId(paragraphId);
         args.write(prot);
         prot.writeMessageEnd();
       }
@@ -1208,7 +1220,7 @@ public class RemoteInterpreterService {
 
       public angularObjectUpdate_result getResult(I iface, angularObjectUpdate_args args) throws org.apache.thrift.TException {
         angularObjectUpdate_result result = new angularObjectUpdate_result();
-        iface.angularObjectUpdate(args.name, args.noteId, args.object);
+        iface.angularObjectUpdate(args.name, args.noteId, args.paragraphId, args.object);
         return result;
       }
     }
@@ -1228,7 +1240,7 @@ public class RemoteInterpreterService {
 
       public angularObjectAdd_result getResult(I iface, angularObjectAdd_args args) throws org.apache.thrift.TException {
         angularObjectAdd_result result = new angularObjectAdd_result();
-        iface.angularObjectAdd(args.name, args.noteId, args.object);
+        iface.angularObjectAdd(args.name, args.noteId, args.paragraphId, args.object);
         return result;
       }
     }
@@ -1248,7 +1260,7 @@ public class RemoteInterpreterService {
 
       public angularObjectRemove_result getResult(I iface, angularObjectRemove_args args) throws org.apache.thrift.TException {
         angularObjectRemove_result result = new angularObjectRemove_result();
-        iface.angularObjectRemove(args.name, args.noteId);
+        iface.angularObjectRemove(args.name, args.noteId, args.paragraphId);
         return result;
       }
     }
@@ -1886,7 +1898,7 @@ public class RemoteInterpreterService {
       }
 
       public void start(I iface, angularObjectUpdate_args args, org.apache.thrift.async.AsyncMethodCallback<Void> resultHandler) throws TException {
-        iface.angularObjectUpdate(args.name, args.noteId, args.object,resultHandler);
+        iface.angularObjectUpdate(args.name, args.noteId, args.paragraphId, args.object,resultHandler);
       }
     }
 
@@ -1936,7 +1948,7 @@ public class RemoteInterpreterService {
       }
 
       public void start(I iface, angularObjectAdd_args args, org.apache.thrift.async.AsyncMethodCallback<Void> resultHandler) throws TException {
-        iface.angularObjectAdd(args.name, args.noteId, args.object,resultHandler);
+        iface.angularObjectAdd(args.name, args.noteId, args.paragraphId, args.object,resultHandler);
       }
     }
 
@@ -1986,7 +1998,7 @@ public class RemoteInterpreterService {
       }
 
       public void start(I iface, angularObjectRemove_args args, org.apache.thrift.async.AsyncMethodCallback<Void> resultHandler) throws TException {
-        iface.angularObjectRemove(args.name, args.noteId,resultHandler);
+        iface.angularObjectRemove(args.name, args.noteId, args.paragraphId,resultHandler);
       }
     }
 
@@ -10007,7 +10019,8 @@ public class RemoteInterpreterService {
 
     private static final org.apache.thrift.protocol.TField NAME_FIELD_DESC = new org.apache.thrift.protocol.TField("name", org.apache.thrift.protocol.TType.STRING, (short)1);
     private static final org.apache.thrift.protocol.TField NOTE_ID_FIELD_DESC = new org.apache.thrift.protocol.TField("noteId", org.apache.thrift.protocol.TType.STRING, (short)2);
-    private static final org.apache.thrift.protocol.TField OBJECT_FIELD_DESC = new org.apache.thrift.protocol.TField("object", org.apache.thrift.protocol.TType.STRING, (short)3);
+    private static final org.apache.thrift.protocol.TField PARAGRAPH_ID_FIELD_DESC = new org.apache.thrift.protocol.TField("paragraphId", org.apache.thrift.protocol.TType.STRING, (short)3);
+    private static final org.apache.thrift.protocol.TField OBJECT_FIELD_DESC = new org.apache.thrift.protocol.TField("object", org.apache.thrift.protocol.TType.STRING, (short)4);
 
     private static final Map<Class<? extends IScheme>, SchemeFactory> schemes = new HashMap<Class<? extends IScheme>, SchemeFactory>();
     static {
@@ -10017,13 +10030,15 @@ public class RemoteInterpreterService {
 
     public String name; // required
     public String noteId; // required
+    public String paragraphId; // required
     public String object; // required
 
     /** The set of fields this struct contains, along with convenience methods for finding and manipulating them. */
     public enum _Fields implements org.apache.thrift.TFieldIdEnum {
       NAME((short)1, "name"),
       NOTE_ID((short)2, "noteId"),
-      OBJECT((short)3, "object");
+      PARAGRAPH_ID((short)3, "paragraphId"),
+      OBJECT((short)4, "object");
 
       private static final Map<String, _Fields> byName = new HashMap<String, _Fields>();
 
@@ -10042,7 +10057,9 @@ public class RemoteInterpreterService {
             return NAME;
           case 2: // NOTE_ID
             return NOTE_ID;
-          case 3: // OBJECT
+          case 3: // PARAGRAPH_ID
+            return PARAGRAPH_ID;
+          case 4: // OBJECT
             return OBJECT;
           default:
             return null;
@@ -10091,6 +10108,8 @@ public class RemoteInterpreterService {
           new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING)));
       tmpMap.put(_Fields.NOTE_ID, new org.apache.thrift.meta_data.FieldMetaData("noteId", org.apache.thrift.TFieldRequirementType.DEFAULT, 
           new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING)));
+      tmpMap.put(_Fields.PARAGRAPH_ID, new org.apache.thrift.meta_data.FieldMetaData("paragraphId", org.apache.thrift.TFieldRequirementType.DEFAULT, 
+          new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING)));
       tmpMap.put(_Fields.OBJECT, new org.apache.thrift.meta_data.FieldMetaData("object", org.apache.thrift.TFieldRequirementType.DEFAULT, 
           new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING)));
       metaDataMap = Collections.unmodifiableMap(tmpMap);
@@ -10103,11 +10122,13 @@ public class RemoteInterpreterService {
     public angularObjectUpdate_args(
       String name,
       String noteId,
+      String paragraphId,
       String object)
     {
       this();
       this.name = name;
       this.noteId = noteId;
+      this.paragraphId = paragraphId;
       this.object = object;
     }
 
@@ -10121,6 +10142,9 @@ public class RemoteInterpreterService {
       if (other.isSetNoteId()) {
         this.noteId = other.noteId;
       }
+      if (other.isSetParagraphId()) {
+        this.paragraphId = other.paragraphId;
+      }
       if (other.isSetObject()) {
         this.object = other.object;
       }
@@ -10134,6 +10158,7 @@ public class RemoteInterpreterService {
     public void clear() {
       this.name = null;
       this.noteId = null;
+      this.paragraphId = null;
       this.object = null;
     }
 
@@ -10185,6 +10210,30 @@ public class RemoteInterpreterService {
       }
     }
 
+    public String getParagraphId() {
+      return this.paragraphId;
+    }
+
+    public angularObjectUpdate_args setParagraphId(String paragraphId) {
+      this.paragraphId = paragraphId;
+      return this;
+    }
+
+    public void unsetParagraphId() {
+      this.paragraphId = null;
+    }
+
+    /** Returns true if field paragraphId is set (has been assigned a value) and false otherwise */
+    public boolean isSetParagraphId() {
+      return this.paragraphId != null;
+    }
+
+    public void setParagraphIdIsSet(boolean value) {
+      if (!value) {
+        this.paragraphId = null;
+      }
+    }
+
     public String getObject() {
       return this.object;
     }
@@ -10227,6 +10276,14 @@ public class RemoteInterpreterService {
         }
         break;
 
+      case PARAGRAPH_ID:
+        if (value == null) {
+          unsetParagraphId();
+        } else {
+          setParagraphId((String)value);
+        }
+        break;
+
       case OBJECT:
         if (value == null) {
           unsetObject();
@@ -10246,6 +10303,9 @@ public class RemoteInterpreterService {
       case NOTE_ID:
         return getNoteId();
 
+      case PARAGRAPH_ID:
+        return getParagraphId();
+
       case OBJECT:
         return getObject();
 
@@ -10264,6 +10324,8 @@ public class RemoteInterpreterService {
         return isSetName();
       case NOTE_ID:
         return isSetNoteId();
+      case PARAGRAPH_ID:
+        return isSetParagraphId();
       case OBJECT:
         return isSetObject();
       }
@@ -10301,6 +10363,15 @@ public class RemoteInterpreterService {
           return false;
       }
 
+      boolean this_present_paragraphId = true && this.isSetParagraphId();
+      boolean that_present_paragraphId = true && that.isSetParagraphId();
+      if (this_present_paragraphId || that_present_paragraphId) {
+        if (!(this_present_paragraphId && that_present_paragraphId))
+          return false;
+        if (!this.paragraphId.equals(that.paragraphId))
+          return false;
+      }
+
       boolean this_present_object = true && this.isSetObject();
       boolean that_present_object = true && that.isSetObject();
       if (this_present_object || that_present_object) {
@@ -10327,6 +10398,11 @@ public class RemoteInterpreterService {
       if (present_noteId)
         list.add(noteId);
 
+      boolean present_paragraphId = true && (isSetParagraphId());
+      list.add(present_paragraphId);
+      if (present_paragraphId)
+        list.add(paragraphId);
+
       boolean present_object = true && (isSetObject());
       list.add(present_object);
       if (present_object)
@@ -10363,6 +10439,16 @@ public class RemoteInterpreterService {
           return lastComparison;
         }
       }
+      lastComparison = Boolean.valueOf(isSetParagraphId()).compareTo(other.isSetParagraphId());
+      if (lastComparison != 0) {
+        return lastComparison;
+      }
+      if (isSetParagraphId()) {
+        lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.paragraphId, other.paragraphId);
+        if (lastComparison != 0) {
+          return lastComparison;
+        }
+      }
       lastComparison = Boolean.valueOf(isSetObject()).compareTo(other.isSetObject());
       if (lastComparison != 0) {
         return lastComparison;
@@ -10409,6 +10495,14 @@ public class RemoteInterpreterService {
       }
       first = false;
       if (!first) sb.append(", ");
+      sb.append("paragraphId:");
+      if (this.paragraphId == null) {
+        sb.append("null");
+      } else {
+        sb.append(this.paragraphId);
+      }
+      first = false;
+      if (!first) sb.append(", ");
       sb.append("object:");
       if (this.object == null) {
         sb.append("null");
@@ -10475,7 +10569,15 @@ public class RemoteInterpreterService {
                 org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
               }
               break;
-            case 3: // OBJECT
+            case 3: // PARAGRAPH_ID
+              if (schemeField.type == org.apache.thrift.protocol.TType.STRING) {
+                struct.paragraphId = iprot.readString();
+                struct.setParagraphIdIsSet(true);
+              } else { 
+                org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
+              }
+              break;
+            case 4: // OBJECT
               if (schemeField.type == org.apache.thrift.protocol.TType.STRING) {
                 struct.object = iprot.readString();
                 struct.setObjectIsSet(true);
@@ -10508,6 +10610,11 @@ public class RemoteInterpreterService {
           oprot.writeString(struct.noteId);
           oprot.writeFieldEnd();
         }
+        if (struct.paragraphId != null) {
+          oprot.writeFieldBegin(PARAGRAPH_ID_FIELD_DESC);
+          oprot.writeString(struct.paragraphId);
+          oprot.writeFieldEnd();
+        }
         if (struct.object != null) {
           oprot.writeFieldBegin(OBJECT_FIELD_DESC);
           oprot.writeString(struct.object);
@@ -10537,16 +10644,22 @@ public class RemoteInterpreterService {
         if (struct.isSetNoteId()) {
           optionals.set(1);
         }
-        if (struct.isSetObject()) {
+        if (struct.isSetParagraphId()) {
           optionals.set(2);
         }
-        oprot.writeBitSet(optionals, 3);
+        if (struct.isSetObject()) {
+          optionals.set(3);
+        }
+        oprot.writeBitSet(optionals, 4);
         if (struct.isSetName()) {
           oprot.writeString(struct.name);
         }
         if (struct.isSetNoteId()) {
           oprot.writeString(struct.noteId);
         }
+        if (struct.isSetParagraphId()) {
+          oprot.writeString(struct.paragraphId);
+        }
         if (struct.isSetObject()) {
           oprot.writeString(struct.object);
         }
@@ -10555,7 +10668,7 @@ public class RemoteInterpreterService {
       @Override
       public void read(org.apache.thrift.protocol.TProtocol prot, angularObjectUpdate_args struct) throws org.apache.thrift.TException {
         TTupleProtocol iprot = (TTupleProtocol) prot;
-        BitSet incoming = iprot.readBitSet(3);
+        BitSet incoming = iprot.readBitSet(4);
         if (incoming.get(0)) {
           struct.name = iprot.readString();
           struct.setNameIsSet(true);
@@ -10565,6 +10678,10 @@ public class RemoteInterpreterService {
           struct.setNoteIdIsSet(true);
         }
         if (incoming.get(2)) {
+          struct.paragraphId = iprot.readString();
+          struct.setParagraphIdIsSet(true);
+        }
+        if (incoming.get(3)) {
           struct.object = iprot.readString();
           struct.setObjectIsSet(true);
         }
@@ -10826,7 +10943,8 @@ public class RemoteInterpreterService {
 
     private static final org.apache.thrift.protocol.TField NAME_FIELD_DESC = new org.apache.thrift.protocol.TField("name", org.apache.thrift.protocol.TType.STRING, (short)1);
     private static final org.apache.thrift.protocol.TField NOTE_ID_FIELD_DESC = new org.apache.thrift.protocol.TField("noteId", org.apache.thrift.protocol.TType.STRING, (short)2);
-    private static final org.apache.thrift.protocol.TField OBJECT_FIELD_DESC = new org.apache.thrift.protocol.TField("object", org.apache.thrift.protocol.TType.STRING, (short)3);
+    private static final org.apache.thrift.protocol.TField PARAGRAPH_ID_FIELD_DESC = new org.apache.thrift.protocol.TField("paragraphId", org.apache.thrift.protocol.TType.STRING, (short)3);
+    private static final org.apache.thrift.protocol.TField OBJECT_FIELD_DESC = new org.apache.thrift.protocol.TField("object", org.apache.thrift.protocol.TType.STRING, (short)4);
 
     private static final Map<Class<? extends IScheme>, SchemeFactory> schemes = new HashMap<Class<? extends IScheme>, SchemeFactory>();
     static {
@@ -10836,13 +10954,15 @@ public class RemoteInterpreterService {
 
     public String name; // required
     public String noteId; // required
+    public String paragraphId; // required
     public String object; // required
 
     /** The set of fields this struct contains, along with convenience methods for finding and manipulating them. */
     public enum _Fields implements org.apache.thrift.TFieldIdEnum {
       NAME((short)1, "name"),
       NOTE_ID((short)2, "noteId"),
-      OBJECT((short)3, "object");
+      PARAGRAPH_ID((short)3, "paragraphId"),
+      OBJECT((short)4, "object");
 
       private static final Map<String, _Fields> byName = new HashMap<String, _Fields>();
 
@@ -10861,7 +10981,9 @@ public class RemoteInterpreterService {
             return NAME;
           case 2: // NOTE_ID
             return NOTE_ID;
-          case 3: // OBJECT
+          case 3: // PARAGRAPH_ID
+            return PARAGRAPH_ID;
+          case 4: // OBJECT
             return OBJECT;
           default:
             return null;
@@ -10910,6 +11032,8 @@ public class RemoteInterpreterService {
           new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING)));
       tmpMap.put(_Fields.NOTE_ID, new org.apache.thrift.meta_data.FieldMetaData("noteId", org.apache.thrift.TFieldRequirementType.DEFAULT, 
           new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING)));
+      tmpMap.put(_Fields.PARAGRAPH_ID, new org.apache.thrift.meta_data.FieldMetaData("paragraphId", org.apache.thrift.TFieldRequirementType.DEFAULT, 
+          new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING)));
       tmpMap.put(_Fields.OBJECT, new org.apache.thrift.meta_data.FieldMetaData("object", org.apache.thrift.TFieldRequirementType.DEFAULT, 
           new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING)));
       metaDataMap = Collections.unmodifiableMap(tmpMap);
@@ -10922,11 +11046,13 @@ public class RemoteInterpreterService {
     public angularObjectAdd_args(
       String name,
       String noteId,
+      String paragraphId,
       String object)
     {
       this();
       this.name = name;
       this.noteId = noteId;
+      this.paragraphId = paragraphId;
       this.object = object;
     }
 
@@ -10940,6 +11066,9 @@ public class RemoteInterpreterService {
       if (other.isSetNoteId()) {
         this.noteId = other.noteId;
       }
+      if (other.isSetParagraphId()) {
+        this.paragraphId = other.paragraphId;
+      }
       if (other.isSetObject()) {
         this.object = other.object;
       }
@@ -10953,6 +11082,7 @@ public class RemoteInterpreterService {
     public void clear() {
       this.name = null;
       this.noteId = null;
+      this.paragraphId = null;
       this.object = null;
     }
 
@@ -11004,6 +11134,30 @@ public class RemoteInterpreterService {
       }
     }
 
+    public String getParagraphId() {
+      return this.paragraphId;
+    }
+
+    public angularObjectAdd_args setParagraphId(String paragraphId) {
+      this.paragraphId = paragraphId;
+      return this;
+    }
+
+    public void unsetParagraphId() {
+      this.paragraphId = null;
+    }
+
+    /** Returns true if field paragraphId is set (has been assigned a value) and false otherwise */
+    public boolean isSetParagraphId() {
+      return this.paragraphId != null;
+    }
+
+    public void setParagraphIdIsSet(boolean value) {
+      if (!value) {
+        this.paragraphId = null;
+      }
+    }
+
     public String getObject() {
       return this.object;
     }
@@ -11046,6 +11200,14 @@ public class RemoteInterpreterService {
         }
         break;
 
+      case PARAGRAPH_ID:
+        if (value == null) {
+          unsetParagraphId();
+        } else {
+          setParagraphId((String)value);
+        }
+        break;
+
       case OBJECT:
         if (value == null) {
           unsetObject();
@@ -11065,6 +11227,9 @@ public class RemoteInterpreterService {
       case NOTE_ID:
         return getNoteId();
 
+      case PARAGRAPH_ID:
+        return getParagraphId();
+
       case OBJECT:
         return getObject();
 
@@ -11083,6 +11248,8 @@ public class RemoteInterpreterService {
         return isSetName();
       case NOTE_ID:
         return isSetNoteId();
+      case PARAGRAPH_ID:
+        return isSetParagraphId();
       case OBJECT:
         return isSetObject();
       }
@@ -11120,6 +11287,15 @@ public class RemoteInterpreterService {
           return false;
       }
 
+      boolean this_present_paragraphId = true && this.isSetParagraphId();
+      boolean that_present_paragraphId = true && that.isSetParagraphId();
+      if (this_present_paragraphId || that_present_paragraphId) {
+        if (!(this_present_paragraphId && that_present_paragraphId))
+          return false;
+        if (!this.paragraphId.equals(that.paragraphId))
+          return false;
+      }
+
       boolean this_present_object = true && this.isSetObject();
       boolean that_present_object = true && that.isSetObject();
       if (this_present_object || that_present_object) {
@@ -11146,6 +11322,11 @@ public class RemoteInterpreterService {
       if (present_noteId)
         list.add(noteId);
 
+      boolean present_paragraphId = true && (isSetParagraphId());
+      list.add(present_paragraphId);
+      if (present_paragraphId)
+        list.add(paragraphId);
+
       boolean present_object = true && (isSetObject());
       list.add(present_object);
       if (present_object)
@@ -11182,6 +11363,16 @@ public class RemoteInterpreterService {
           return lastComparison;
         }
       }
+      lastComparison = Boolean.valueOf(isSetParagraphId()).compareTo(other.isSetParagraphId());
+      if (lastComparison != 0) {
+        return lastComparison;
+      }
+      if (isSetParagraphId()) {
+        lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.paragraphId, other.paragraphId);
+        if (lastComparison != 0) {
+          return lastComparison;
+        }
+      }
       lastComparison = Boolean.valueOf(isSetObject()).compareTo(other.isSetObject());
       if (lastComparison != 0) {
         return lastComparison;
@@ -11228,6 +11419,14 @@ public class RemoteInterpreterService {
       }
       first = false;
       if (!first) sb.append(", ");
+      sb.append("paragraphId:");
+      if (this.paragraphId == null) {
+        sb.append("null");
+      } else {
+        sb.append(this.paragraphId);
+      }
+      first = false;
+      if (!first) sb.append(", ");
       sb.append("object:");
       if (this.object == null) {
         sb.append("null");
@@ -11294,7 +11493,15 @@ public class RemoteInterpreterService {
                 org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
               }
               break;
-            case 3: // OBJECT
+            case 3: // PARAGRAPH_ID
+              if (schemeField.type == org.apache.thrift.protocol.TType.STRING) {
+                struct.paragraphId = iprot.readString();
+                struct.setParagraphIdIsSet(true);
+              } else { 
+                org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
+              }
+              break;
+            case 4: // OBJECT
               if (schemeField.type == org.apache.thrift.protocol.TType.STRING) {
                 struct.object = iprot.readString();
                 struct.setObjectIsSet(true);
@@ -11327,6 +11534,11 @@ public class RemoteInterpreterService {
           oprot.writeString(struct.noteId);
           oprot.writeFieldEnd();
         }
+        if (struct.paragraphId != null) {
+          oprot.writeFieldBegin(PARAGRAPH_ID_FIELD_DESC);
+          oprot.writeString(struct.paragraphId);
+          oprot.writeFieldEnd();
+        }
         if (struct.object != null) {
           oprot.writeFieldBegin(OBJECT_FIELD_DESC);
           oprot.writeString(struct.object);
@@ -11356,16 +11568,22 @@ public class RemoteInterpreterService {
         if (struct.isSetNoteId()) {
           optionals.set(1);
         }
-        if (struct.isSetObject()) {
+        if (struct.isSetParagraphId()) {
           optionals.set(2);
         }
-        oprot.writeBitSet(optionals, 3);
+        if (struct.isSetObject()) {
+          optionals.set(3);
+        }
+        oprot.writeBitSet(optionals, 4);
         if (struct.isSetName()) {
           oprot.writeString(struct.name);
         }
         if (struct.isSetNoteId()) {
           oprot.writeString(struct.noteId);
         }
+        if (struct.isSetParagraphId()) {
+          oprot.writeString(struct.paragraphId);
+        }
         if (struct.isSetObject()) {
           oprot.writeString(struct.object);
         }
@@ -11374,7 +11592,7 @@ public class RemoteInterpreterService {
       @Override
       public void read(org.apache.thrift.protocol.TProtocol prot, angularObjectAdd_args struct) throws org.apache.thrift.TException {
         TTupleProtocol iprot = (TTupleProtocol) prot;
-        BitSet incoming = iprot.readBitSet(3);
+        BitSet incoming = iprot.readBitSet(4);
         if (incoming.get(0)) {
           struct.name = iprot.readString();
           struct.setNameIsSet(true);
@@ -11384,6 +11602,10 @@ public class RemoteInterpreterService {
           struct.setNoteIdIsSet(true);
         }
         if (incoming.get(2)) {
+          struct.paragraphId = iprot.readString();
+          struct.setParagraphIdIsSet(true);
+        }
+        if (incoming.get(3)) {
           struct.object = iprot.readString();
           struct.setObjectIsSet(true);
         }
@@ -11645,6 +11867,7 @@ public class RemoteInterpreterService {
 
     private static final org.apache.thrift.protocol.TField NAME_FIELD_DESC = new org.apache.thrift.protocol.TField("name", org.apache.thrift.protocol.TType.STRING, (short)1);
     private static final org.apache.thrift.protocol.TField NOTE_ID_FIELD_DESC = new org.apache.thrift.protocol.TField("noteId", org.apache.thrift.protocol.TType.STRING, (short)2);
+    private static final org.apache.thrift.protocol.TField PARAGRAPH_ID_FIELD_DESC = new org.apache.thrift.protocol.TField("paragraphId", org.apache.thrift.protocol.TType.STRING, (short)3);
 
     private static final Map<Class<? extends IScheme>, SchemeFactory> schemes = new HashMap<Class<? extends IScheme>, SchemeFactory>();
     static {
@@ -11654,11 +11877,13 @@ public class RemoteInterpreterService {
 
     public String name; // required
     public String noteId; // required
+    public String paragraphId; // required
 
     /** The set of fields this struct contains, along with convenience methods for finding and manipulating them. */
     public enum _Fields implements org.apache.thrift.TFieldIdEnum {
       NAME((short)1, "name"),
-      NOTE_ID((short)2, "noteId");
+      NOTE_ID((short)2, "noteId"),
+      PARAGRAPH_ID((short)3, "paragraphId");
 
       private static final Map<String, _Fields> byName = new HashMap<String, _Fields>();
 
@@ -11677,6 +11902,8 @@ public class RemoteInterpreterService {
             return NAME;
           case 2: // NOTE_ID
             return NOTE_ID;
+          case 3: // PARAGRAPH_ID
+            return PARAGRAPH_ID;
           default:
             return null;
         }
@@ -11724,6 +11951,8 @@ public class RemoteInterpreterService {
           new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING)));
       tmpMap.put(_Fields.NOTE_ID, new org.apache.thrift.meta_data.FieldMetaData("noteId", org.apache.thrift.TFieldRequirementType.DEFAULT, 
           new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING)));
+      tmpMap.put(_Fields.PARAGRAPH_ID, new org.apache.thrift.meta_data.FieldMetaData("paragraphId", org.apache.thrift.TFieldRequirementType.DEFAULT, 
+          new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING)));
       metaDataMap = Collections.unmodifiableMap(tmpMap);
       org.apache.thrift.meta_data.FieldMetaData.addStructMetaDataMap(angularObjectRemove_args.class, metaDataMap);
     }
@@ -11733,11 +11962,13 @@ public class RemoteInterpreterService {
 
     public angularObjectRemove_args(
       String name,
-      String noteId)
+      String noteId,
+      String paragraphId)
     {
       this();
       this.name = name;
       this.noteId = noteId;
+      this.paragraphId = paragraphId;
     }
 
     /**
@@ -11750,6 +11981,9 @@ public class RemoteInterpreterService {
       if (other.isSetNoteId()) {
         this.noteId = other.noteId;
       }
+      if (other.isSetParagraphId()) {
+        this.paragraphId = other.paragraphId;
+      }
     }
 
     public angularObjectRemove_args deepCopy() {
@@ -11760,6 +11994,7 @@ public class RemoteInterpreterService {
     public void clear() {
       this.name = null;
       this.noteId = null;
+      this.paragraphId = null;
     }
 
     public String getName() {
@@ -11810,6 +12045,30 @@ public class RemoteInterpreterService {
       }
     }
 
+    public String getParagraphId() {
+      return this.paragraphId;
+    }
+
+    public angularObjectRemove_args setParagraphId(String paragraphId) {
+      this.paragraphId = paragraphId;
+      return this;
+    }
+
+    public void unsetParagraphId() {
+      this.paragraphId = null;
+    }
+
+    /** Returns true if field paragraphId is set (has been assigned a value) and false otherwise */
+    public boolean isSetParagraphId() {
+      return this.paragraphId != null;
+    }
+
+    public void setParagraphIdIsSet(boolean value) {
+      if (!value) {
+        this.paragraphId = null;
+      }
+    }
+
     public void setFieldValue(_Fields field, Object value) {
       switch (field) {
       case NAME:
@@ -11828,6 +12087,14 @@ public class RemoteInterpreterService {
         }
         break;
 
+      case PARAGRAPH_ID:
+        if (value == null) {
+          unsetParagraphId();
+        } else {
+          setParagraphId((String)value);
+        }
+        break;
+
       }
     }
 
@@ -11839,6 +12106,9 @@ public class RemoteInterpreterService {
       case NOTE_ID:
         return getNoteId();
 
+      case PARAGRAPH_ID:
+        return getParagraphId();
+
       }
       throw new IllegalStateException();
     }
@@ -11854,6 +12124,8 @@ public class RemoteInterpreterService {
         return isSetName();
       case NOTE_ID:
         return isSetNoteId();
+      case PARAGRAPH_ID:
+        return isSetParagraphId();
       }
       throw new IllegalStateException();
     }
@@ -11889,6 +12161,15 @@ public class RemoteInterpreterService {
           return false;
       }
 
+      boolean this_present_paragraphId = true && this.isSetParagraphId();
+      boolean that_present_paragraphId = true && that.isSetParagraphId();
+      if (this_present_paragraphId || that_present_paragraphId) {
+        if (!(this_present_paragraphId && that_present_paragraphId))
+          return false;
+        if (!this.paragraphId.equals(that.paragraphId))
+          return false;
+      }
+
       return true;
     }
 
@@ -11906,6 +12187,11 @@ public class RemoteInterpreterService {
       if (present_noteId)
         list.add(noteId);
 
+      boolean present_paragraphId = true && (isSetParagraphId());
+      list.add(present_paragraphId);
+      if (present_paragraphId)
+        list.add(paragraphId);
+
       return list.hashCode();
     }
 
@@ -11937,6 +12223,16 @@ public class RemoteInterpreterService {
           return lastComparison;
         }
       }
+      lastComparison = Boolean.valueOf(isSetParagraphId()).compareTo(other.isSetParagraphId());
+      if (lastComparison != 0) {
+        return lastComparison;
+      }
+      if (isSetParagraphId()) {
+        lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.paragraphId, other.paragraphId);
+        if (lastComparison != 0) {
+          return lastComparison;
+        }
+      }
       return 0;
     }
 
@@ -11972,6 +12268,14 @@ public class RemoteInterpreterService {
         sb.append(this.noteId);
       }
       first = false;
+      if (!first) sb.append(", ");
+      sb.append("paragraphId:");
+      if (this.paragraphId == null) {
+        sb.append("null");
+      } else {
+        sb.append(this.paragraphId);
+      }
+      first = false;
       sb.append(")");
       return sb.toString();
     }
@@ -12031,6 +12335,14 @@ public class RemoteInterpreterService {
                 org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
               }
               break;
+            case 3: // PARAGRAPH_ID
+              if (schemeField.type == org.apache.thrift.protocol.TType.STRING) {
+                struct.paragraphId = iprot.readString();
+                struct.setParagraphIdIsSet(true);
+              } else { 
+                org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
+              }
+              break;
             default:
               org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
           }
@@ -12056,6 +12368,11 @@ public class RemoteInterpreterService {
           oprot.writeString(struct.noteId);
           oprot.writeFieldEnd();
         }
+        if (struct.paragraphId != null) {
+          oprot.writeFieldBegin(PARAGRAPH_ID_FIELD_DESC);
+          oprot.writeString(struct.paragraphId);
+          oprot.writeFieldEnd();
+        }
         oprot.writeFieldStop();
         oprot.writeStructEnd();
       }
@@ -12080,19 +12397,25 @@ public class RemoteInterpreterService {
         if (struct.isSetNoteId()) {
           optionals.set(1);
         }
-        oprot.writeBitSet(optionals, 2);
+        if (struct.isSetParagraphId()) {
+          optionals.set(2);
+        }
+        oprot.writeBitSet(optionals, 3);
         if (struct.isSetName()) {
           oprot.writeString(struct.name);
         }
         if (struct.isSetNoteId()) {
           oprot.writeString(struct.noteId);
         }
+        if (struct.isSetParagraphId()) {
+          oprot.writeString(struct.paragraphId);
+        }
       }
 
       @Override
       public void read(org.apache.thrift.protocol.TProtocol prot, angularObjectRemove_args struct) throws org.apache.thrift.TException {
         TTupleProtocol iprot = (TTupleProtocol) prot;
-        BitSet incoming = iprot.readBitSet(2);
+        BitSet incoming = iprot.readBitSet(3);
         if (incoming.get(0)) {
           struct.name = iprot.readString();
           struct.setNameIsSet(true);
@@ -12101,6 +12424,10 @@ public class RemoteInterpreterService {
           struct.noteId = iprot.readString();
           struct.setNoteIdIsSet(true);
         }
+        if (incoming.get(2)) {
+          struct.paragraphId = iprot.readString();
+          struct.setParagraphIdIsSet(true);
+        }
       }
     }