http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/blob/8c7424a1/zeppelin-web/src/WEB-INF/web.xml
----------------------------------------------------------------------
diff --git a/zeppelin-web/src/WEB-INF/web.xml b/zeppelin-web/src/WEB-INF/web.xml
new file mode 100644
index 0000000..f34da18
--- /dev/null
+++ b/zeppelin-web/src/WEB-INF/web.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one or more
+  ~ contributor license agreements.  See the NOTICE file distributed with
+  ~ this work for additional information regarding copyright ownership.
+  ~ The ASF licenses this file to You 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.
+  -->
+
+<web-app xmlns="http://java.sun.com/xml/ns/javaee"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+       xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd";
+       version="2.5">
+
+ <display-name>zeppelin-web</display-name>
+       <servlet>
+               <servlet-name>default</servlet-name>
+               
<servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
+               <init-param>
+                       
<param-name>com.sun.jersey.config.property.packages</param-name>
+                       
<param-value>org.apache.zeppelin.rest;com.wordnik.swagger.jersey.listing</param-value>
+               </init-param>
+               <load-on-startup>1</load-on-startup>
+       </servlet>
+
+       <!-- This route is for swagger, must be different than root -->
+       <servlet-mapping>
+               <servlet-name>default</servlet-name>
+               <url-pattern>/rest/*</url-pattern>
+       </servlet-mapping>
+
+       <context-param>
+               <param-name>configuration</param-name>
+               <param-value>deployment</param-value>
+       </context-param>
+</web-app>

http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/blob/8c7424a1/zeppelin-web/src/app/app.controller.js
----------------------------------------------------------------------
diff --git a/zeppelin-web/src/app/app.controller.js 
b/zeppelin-web/src/app/app.controller.js
new file mode 100644
index 0000000..f2bf8ab
--- /dev/null
+++ b/zeppelin-web/src/app/app.controller.js
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ */
+'use strict';
+
+angular.module('zeppelinWebApp').controller('MainCtrl', function($scope, 
$rootScope, $window) {
+  $rootScope.compiledScope = $scope.$new(true, $rootScope);
+  $scope.looknfeel = 'default';
+
+  var init = function() {
+    $scope.asIframe = (($window.location.href.indexOf('asIframe') > -1) ? true 
: false);
+  };
+  
+  init();
+
+  $rootScope.$on('setIframe', function(event, data) {
+    if (!event.defaultPrevented) {
+      $scope.asIframe = data;
+      event.preventDefault();
+    }
+  });
+
+  $rootScope.$on('setLookAndFeel', function(event, data) {
+    if (!event.defaultPrevented && data && data !== '' && data != 
$scope.looknfeel) {
+      $scope.looknfeel = data;
+      event.preventDefault();
+    }
+  });
+  
+  // Set The lookAndFeel to default on every page
+  $rootScope.$on('$routeChangeStart', function(event, next, current) {
+    $rootScope.$broadcast('setLookAndFeel', 'default');
+  });
+
+});

http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/blob/8c7424a1/zeppelin-web/src/app/app.js
----------------------------------------------------------------------
diff --git a/zeppelin-web/src/app/app.js b/zeppelin-web/src/app/app.js
new file mode 100644
index 0000000..0d163d9
--- /dev/null
+++ b/zeppelin-web/src/app/app.js
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+'use strict';
+
+angular.module('zeppelinWebApp', [
+    'ngAnimate',
+    'ngCookies',
+    'ngRoute',
+    'ngSanitize',
+    'angular-websocket',
+    'ui.ace',
+    'ui.bootstrap',
+    'ui.sortable',
+    'ngTouch',
+    'ngDragDrop',
+    'monospaced.elastic',
+    'puElasticInput',
+    'xeditable'
+  ])
+  .filter('breakFilter', function() {
+    return function (text) {
+      if (!!text) {
+        return text.replace(/\n/g, '<br />');
+      }
+    };
+  })
+  .config(function ($routeProvider) {
+    $routeProvider
+      .when('/', {
+        templateUrl: 'app/home/home.html',
+        controller: 'HomeCtrl'
+      })
+      .when('/notebook/:noteId', {
+        templateUrl: 'app/notebook/notebook.html',
+        controller: 'NotebookCtrl'
+      })
+      .when('/notebook/:noteId/paragraph/:paragraphId?', {
+        templateUrl: 'app/notebook/notebook.html',
+        controller: 'NotebookCtrl'
+      })
+      .when('/interpreter', {
+        templateUrl: 'app/interpreter/interpreter.html',
+        controller: 'InterpreterCtrl'
+      })
+      .otherwise({
+        redirectTo: '/'
+      });
+  });

http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/blob/8c7424a1/zeppelin-web/src/app/home/home.controller.js
----------------------------------------------------------------------
diff --git a/zeppelin-web/src/app/home/home.controller.js 
b/zeppelin-web/src/app/home/home.controller.js
new file mode 100644
index 0000000..e66201c
--- /dev/null
+++ b/zeppelin-web/src/app/home/home.controller.js
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ */
+'use strict';
+
+angular.module('zeppelinWebApp').controller('HomeCtrl', function($scope, 
notebookListDataFactory, websocketMsgSrv) {
+  
+  var vm = this;
+  vm.notes = notebookListDataFactory;
+  vm.websocketMsgSrv = websocketMsgSrv;
+  
+});

http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/blob/8c7424a1/zeppelin-web/src/app/home/home.css
----------------------------------------------------------------------
diff --git a/zeppelin-web/src/app/home/home.css 
b/zeppelin-web/src/app/home/home.css
new file mode 100644
index 0000000..5058cb8
--- /dev/null
+++ b/zeppelin-web/src/app/home/home.css
@@ -0,0 +1,288 @@
+/*
+ * 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.
+ */
+@import url(//fonts.googleapis.com/css?family=Patua+One);
+@import url(//fonts.googleapis.com/css?family=Roboto);
+@import url(//fonts.googleapis.com/css?family=Source+Code+Pro);
+
+body {
+  padding-top: 60px;
+  color: #212121;
+}
+
+html,body { height: 100%;}
+
+.bodyAsIframe {
+  background: white;
+}
+
+.displayNavBar {
+  display: inline !important;
+}
+
+
+body.asIframe {
+  padding-top: 0px;
+}
+body .navbar {
+  margin-bottom: 10px;
+}
+
+.container {
+  padding-right: 15px;
+  padding-left: 15px;
+  margin-right: auto;
+  margin-left: auto;
+  width: auto;
+}
+
+.navbar-inverse {
+  background-color: #3071a9;
+  color: #fff;
+  border-color: #3071a9;
+  font-size: 18px;
+}
+
+.navbar-inverse .navbar-nav > .open > a, .navbar-inverse .navbar-nav > .open > 
a:hover, .navbar-inverse .navbar-nav > .open > a:focus {
+  color: #fff;
+  background-color: #3071a9;
+}
+
+.navbar-inverse .navbar-toggle:hover, .navbar-inverse .navbar-toggle:focus {
+  background-color: #3071a9;
+}
+
+.navbar-inverse .navbar-nav > li > a:hover, .navbar-inverse .navbar-nav > li > 
a:focus {
+  color: #fff;
+  background-color: rgba(0, 0, 0, 0.2);
+
+}
+
+.navbar-inverse .navbar-toggle {
+  border-color: #FFFFFF;
+}
+
+.navbar-inverse .navbar-nav > .active > a, .navbar-inverse .navbar-nav > 
.active > a:hover, .navbar-inverse .navbar-nav > .active > a:focus {
+  color: #fff;
+  background-color: #080808;
+}
+
+.navbar-inverse .navbar-nav > li > a {
+  color: #FFFFFF;
+}
+
+.navbar-inverse .navbar-brand {
+  color: #fff;
+  text-decoration: none;
+  font-family: 'Patua One', cursive;
+  font-size: 32px;
+}
+
+a.navbar-brand:hover {
+  color: #fff !important;
+}
+
+/* bootstrap customization for scrollable dropdown menu */
+.dropdown-menu > .scrollbar-container > li > a {
+  display: block;
+  padding: 3px 20px;
+  clear: both;
+  font-weight: normal;
+  line-height: 1.42857143;
+  color: #333;
+  white-space: nowrap;
+}
+.dropdown-menu > .scrollbar-container > li > a:hover,
+.dropdown-menu > .scrollbar-container > li > a:focus {
+  color: #262626;
+  text-decoration: none;
+  background-color: #f5f5f5;
+}
+
+.dropdown-menu > .scrollbar-container > .active > a,
+.dropdown-menu > .scrollbar-container > .active > a:hover,
+.dropdown-menu > .scrollbar-container > .active > a:focus {
+  color: #fff;
+  text-decoration: none;
+  background-color: #428bca;
+  outline: 0;
+}
+
+@media (max-width: 767px) {
+  .navbar-nav .open .dropdown-menu > .scrollbar-container > li > a {
+    padding: 5px 15px 5px 25px;
+    line-height: 20px;
+  }
+  .navbar-inverse .navbar-nav .open .dropdown-menu > .scrollbar-container > li 
> a {
+    color: #777;
+  }
+  .navbar-inverse .navbar-nav .open .dropdown-menu > .scrollbar-container > li 
> a:hover,
+  .navbar-inverse .navbar-nav .open .dropdown-menu > .scrollbar-container > li 
> a:focus {
+    color: #fff;
+    background-color: transparent;
+  }
+  .navbar-inverse .navbar-nav .open .dropdown-menu > .scrollbar-container > 
.active > a,
+  .navbar-inverse .navbar-nav .open .dropdown-menu > .scrollbar-container > 
.active > a:hover,
+  .navbar-inverse .navbar-nav .open .dropdown-menu > .scrollbar-container > 
.active > a:focus {
+    color: #fff;
+    background-color: #080808;
+  }
+}
+
+
+#main {
+  padding-left: 10px;
+  padding-right: 10px;
+  padding-bottom: 10px;
+  height: 100%;
+}
+
+#notebook-list {
+  position: relative;
+  overflow: hidden;
+}
+
+@media (min-width: 768px) {
+  #notebook-list {
+    max-height: 500px;
+  }
+}
+
+.server-status {
+  font-size:12px;
+  margin-top: 6px;
+}
+
+.server-connected {
+  color: #00CC00;
+}
+
+.server-disconnected {
+  color: rgba(240, 48, 0, 1);
+  font-size: 12px !important;
+  font-weight: bold !important;
+}
+
+
+/**
+ * Box and well
+ */
+.box{
+  border-style: solid;
+  min-height: 20px;
+  padding: 10px;
+  margin-bottom: 20px;
+}
+
+.box,
+.well {
+  background-color: #ffffff;
+  border-color: #e5e5e5;
+  border-width: 1px 1px 2px;
+  border-radius: 3px;
+  -webkit-box-shadow: none;
+  box-shadow: none;
+}
+
+.box-heading{
+  position:relative;
+  max-width: 100%;
+  /*font-size: 20px;*/
+  font-weight:300;
+  white-space: nowrap;
+  /*overflow:hidden;*/
+  text-overflow: ellipsis;
+  vertical-align: middle;
+  margin: 0 0 15px;
+  padding-bottom: 2px;
+}
+/**
+h1.box-heading,
+h2.box-heading,
+h3.box-heading,
+h4.box-heading,
+h5.box-heading,
+h6.box-heading{
+  font-size: 20px;
+}*/
+.box-heading > .btn-group,
+.box-heading > .btn{
+  margin-top: -3px;
+}
+
+
+.icheck-label{
+  position: relative;
+  top: 0;
+}
+
+
+.zeppelin {
+  background-image: url('/assets/images/zepLogo.png');
+  background-repeat: no-repeat;
+  background-position: right;
+  height: 380px;
+  opacity: 0.2;
+}
+
+.zeppelin2 {
+  background-image: url('/assets/images/zepLogo.png');
+  background-repeat: no-repeat;
+  background-position: right;
+  background-position-y: 12px;
+  height: 380px;
+  opacity: 0.2;
+}
+
+.keys {
+  padding-right: 10px;
+  color: #999;
+  text-align: right;
+  white-space: nowrap;
+}
+
+.kbd-dark {
+  color: #eee;
+  background-color: #222;
+  background-image: none;
+  border: 0;
+}
+
+kbd {
+  background-color: #e7e7e7;
+  background-image: -webkit-linear-gradient(#fefefe, #e7e7e7);
+  background-image: linear-gradient(#fefefe, #e7e7e7);
+  background-repeat: repeat-x;
+  display: inline-block;
+  padding: 4px 5px;
+  font: 11px Consolas, "Liberation Mono", Menlo, Courier, monospace;
+  line-height: 10px;
+  color: #000;
+  border: 1px solid #cfcfcf;
+  border-radius: 2px;
+}
+
+.home {
+  min-height: 400px;
+}
+
+
+/*
+temporary fix for bootstrap issue 
(https://github.com/twbs/bootstrap/issues/5865)
+This part should be removed when new version of bootstrap handles this issue.
+*/
+.btn-group > .tooltip + .btn,
+.btn-group > .popover + .btn {
+  margin-left:-1px;
+}
+

http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/blob/8c7424a1/zeppelin-web/src/app/home/home.html
----------------------------------------------------------------------
diff --git a/zeppelin-web/src/app/home/home.html 
b/zeppelin-web/src/app/home/home.html
new file mode 100644
index 0000000..9e7963c
--- /dev/null
+++ b/zeppelin-web/src/app/home/home.html
@@ -0,0 +1,53 @@
+<!--
+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.
+-->
+
+<div class="box width-full home" ng-controller="HomeCtrl as home">
+  <div class="zeppelin">
+    <div class="zeppelin2"></div>
+  </div>
+  <div style="margin-top: -380px;">
+    <h1 class="box-heading" id="welcome">
+      Welcome to Zeppelin!
+    </h1>
+    Zeppelin is web-based notebook that enables interactive data 
analytics.<br>You can make beautiful data-driven, interactive, collaborative 
document with SQL, code and even more!<br>
+
+    <div class="row">
+      <div class="col-md-4">
+        <h4>Notebook</h4>
+
+        <div>
+          <h5><a href="javascript:void(0);" 
ng-click="home.websocketMsgSrv.createNotebook()" style="text-decoration: none;">
+              <i style="font-size: 15px;" class="icon-notebook"></i> Create 
new note</a></h5>
+          <ul style="list-style-type: none;">
+            <li ng-repeat="note in home.notes.list track by $index"><i 
style="font-size: 10px;" class="icon-doc"></i>
+              <a style="text-decoration: none;" 
href="#/notebook/{{note.id}}">{{note.name || 'Note ' + note.id}}</a>
+            </li>
+          </ul>
+        </div>
+      </div>
+      <div class="col-md-6">
+        <h4>Help</h4>
+        Get started with <a style="text-decoration: none;" 
href="http://zeppelin.incubator.apache.org/docs/index.html"; 
target="_blank">Zeppelin documentation</a><br>
+
+        <h4>Community</h4>
+        Please feel free to help us to improve Zeppelin, <br>
+        Any contribution are welcome!<br><br>
+        <a style="text-decoration: none;" 
href="http://zeppelin.incubator.apache.org/community.html"; target="_blank"><i 
style="font-size: 15px;" class="fa fa-users"></i> Mailing list</a><br>
+        <a style="text-decoration: none;" 
href="https://issues.apache.org/jira/browse/ZEPPELIN"; target="_blank"><i 
style="font-size: 15px;" class="fa fa-bug"></i> Issues tracking</a><br>
+        <a style="text-decoration: none;" 
href="https://github.com/apache/incubator-zeppelin"; target="_blank"><i 
style="font-size: 20px;" class="fa fa-github"></i> Github</a>
+      </div>
+    </div>
+  </div>
+  <br/><br/><br/>
+</div>

http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/blob/8c7424a1/zeppelin-web/src/app/interpreter/interpreter-create/interpreter-create.html
----------------------------------------------------------------------
diff --git 
a/zeppelin-web/src/app/interpreter/interpreter-create/interpreter-create.html 
b/zeppelin-web/src/app/interpreter/interpreter-create/interpreter-create.html
new file mode 100644
index 0000000..e7096f6
--- /dev/null
+++ 
b/zeppelin-web/src/app/interpreter/interpreter-create/interpreter-create.html
@@ -0,0 +1,77 @@
+<!--
+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.
+-->
+<div>
+  <div class="row">
+    <div class="col-md-12">
+      <div class="interpreterSettingAdd" ng-show="showAddNewSetting">
+        <hr />
+        <h4>Create new interpreter</h4>
+
+        <div class="form-group" style="width:200px">
+          <b>Name</b>
+          <input id="newInterpreterSettingName" input pu-elastic-input
+                 pu-elastic-input-minwidth="180px" 
ng-model="newInterpreterSetting.name" />
+        </div>
+
+        <b>Interpreter</b>
+        <div class="form-group"
+             style="width:180px">
+          <select class="form-control input-sm" 
ng-model="newInterpreterSetting.group"
+                  ng-change="newInterpreterGroupChange()">
+            <option ng-repeat="(groupName, interpreterGroup) in 
availableInterpreters" value="{{groupName}}">{{groupName}}</option>
+          </select>
+        </div>
+
+        <b>Properties</b>
+        <table class="table table-striped properties">
+          <tr>
+            <th>name</th>
+            <th>value</th>
+            <th>description</th>
+            <th>action</th>
+          </tr>
+          <tr ng-repeat="(key, value) in newInterpreterSetting.properties">
+            <td>{{key}}</td>
+            <td><textarea msd-elastic ng-model="value.value" 
ng-init="value.value = value.defaultValue"></textarea></td>
+            <td>{{value.description}}</td>
+            <td>
+              <div class="btn btn-default btn-sm fa fa-remove" 
ng-click="removeInterpreterProperty(key)">
+              </div>
+            </td>
+          </tr>
+
+          <tr>
+            <td>
+              <input pu-elastic-input pu-elastic-input-minwidth="180px"
+                     ng-model="newInterpreterSetting.propertyKey" />
+            </td>
+            <td><textarea msd-elastic 
ng-model="newInterpreterSetting.propertyValue"></textarea></td>
+            <td></td>
+            <td>
+              <div class="btn btn-default btn-sm fa fa-plus" 
ng-click="addNewInterpreterProperty()">
+              </div>
+            </td>
+          </tr>
+        </table>
+
+        <span class="btn btn-primary" ng-click="addNewInterpreterSetting()">
+          Save
+        </span>
+        <span class="btn btn-default" ng-click="showAddNewSetting=false">
+          Cancel
+        </span>
+      </div>
+    </div>
+  </div>
+</div>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/blob/8c7424a1/zeppelin-web/src/app/interpreter/interpreter.controller.js
----------------------------------------------------------------------
diff --git a/zeppelin-web/src/app/interpreter/interpreter.controller.js 
b/zeppelin-web/src/app/interpreter/interpreter.controller.js
new file mode 100644
index 0000000..499c270
--- /dev/null
+++ b/zeppelin-web/src/app/interpreter/interpreter.controller.js
@@ -0,0 +1,202 @@
+/* global confirm:false, alert:false, _:false */
+/* jshint loopfunc: true */
+/*
+ * 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.
+ */
+'use strict';
+
+angular.module('zeppelinWebApp').controller('InterpreterCtrl', 
function($scope, $route, $routeParams, $location, $rootScope,
+                                                                         
$http, baseUrlSrv) {
+  var interpreterSettingsTmp = [];
+  $scope.interpreterSettings = [];
+  $scope.availableInterpreters = {};
+  $scope.showAddNewSetting = false;
+
+  var getInterpreterSettings = function() {
+    $http.get(baseUrlSrv.getRestApiBase()+'/interpreter/setting').
+    success(function(data, status, headers, config) {
+      $scope.interpreterSettings = data.body;
+    }).
+    error(function(data, status, headers, config) {
+      console.log('Error %o %o', status, data.message);
+    });
+  };
+
+  var getAvailableInterpreters = function() {
+    $http.get(baseUrlSrv.getRestApiBase()+'/interpreter').
+    success(function(data, status, headers, config) {
+      $scope.availableInterpreters = data.body;
+    }).
+    error(function(data, status, headers, config) {
+      console.log('Error %o %o', status, data.message);
+    });
+  };
+
+  var emptyNewProperty = function(object) {
+    angular.extend(object, {propertyValue: '', propertyKey: ''});
+  };
+
+  var removeTMPSettings = function(index) {
+    interpreterSettingsTmp.splice(index, 1);
+  };
+
+  $scope.copyOriginInterpreterSettingProperties = function(settingId) {
+    var index = _.findIndex($scope.interpreterSettings, { 'id': settingId });
+    interpreterSettingsTmp[index] = 
angular.copy($scope.interpreterSettings[index]);
+  };
+
+  $scope.updateInterpreterSetting = function(settingId) {
+    var result = confirm('Do you want to update this interpreter and restart 
with new settings?');
+    if (!result) {
+      return;
+    }
+
+    var index = _.findIndex($scope.interpreterSettings, { 'id': settingId });
+
+    var request = {
+      option : angular.copy($scope.interpreterSettings[index].option),
+      properties : angular.copy($scope.interpreterSettings[index].properties),
+    };
+
+
+    $http.put(baseUrlSrv.getRestApiBase() + '/interpreter/setting/' + 
settingId, request).
+    success(function(data, status, headers, config) {
+      $scope.interpreterSettings[index] = data.body;
+      removeTMPSettings(index);
+    }).
+    error(function(data, status, headers, config) {
+      console.log('Error %o %o', status, data.message);
+    });
+  };
+
+  $scope.resetInterpreterSetting = function(settingId){
+    var index = _.findIndex($scope.interpreterSettings, { 'id': settingId });
+
+    // Set the old settings back
+    $scope.interpreterSettings[index] = 
angular.copy(interpreterSettingsTmp[index]);
+    removeTMPSettings(index);
+  };
+
+  $scope.removeInterpreterSetting = function(settingId) {
+    var result = confirm('Do you want to delete this interpreter setting?');
+    if (!result) {
+      return;
+    }
+
+    $http.delete(baseUrlSrv.getRestApiBase() + '/interpreter/setting/' + 
settingId).
+    success(function(data, status, headers, config) {
+
+      var index = _.findIndex($scope.interpreterSettings, { 'id': settingId });
+      $scope.interpreterSettings.splice(index, 1);
+    }).
+    error(function(data, status, headers, config) {
+      console.log('Error %o %o', status, data.message);
+    });
+  };
+
+  $scope.newInterpreterGroupChange = function() {
+    $scope.newInterpreterSetting.properties = 
$scope.availableInterpreters[$scope.newInterpreterSetting.group].properties;
+  };
+
+  $scope.restartInterpreterSetting = function(settingId) {
+    var result = confirm('Do you want to restart this interpreter?');
+    if (!result) {
+      return;
+    }
+
+    $http.put(baseUrlSrv.getRestApiBase() + '/interpreter/setting/restart/' + 
settingId).
+    success(function(data, status, headers, config) {
+      var index = _.findIndex($scope.interpreterSettings, { 'id': settingId });
+      $scope.interpreterSettings[index] = data.body;
+    }).
+    error(function(data, status, headers, config) {
+      console.log('Error %o %o', status, data.message);
+    });
+  };
+
+  $scope.addNewInterpreterSetting = function() {
+    if (!$scope.newInterpreterSetting.name || 
!$scope.newInterpreterSetting.group) {
+      alert('Please determine name and interpreter');
+      return;
+    }
+
+    if (_.findIndex($scope.interpreterSettings, { 'name': 
$scope.newInterpreterSetting.name }) >= 0) {
+      alert('Name ' + $scope.newInterpreterSetting.name + ' already exists');
+      return;
+    }
+
+    var newSetting = angular.copy($scope.newInterpreterSetting);
+
+    for (var p in $scope.newInterpreterSetting.properties) {
+      newSetting.properties[p] = 
$scope.newInterpreterSetting.properties[p].value;
+    }
+
+    $http.post(baseUrlSrv.getRestApiBase()+'/interpreter/setting', newSetting).
+    success(function(data, status, headers, config) {
+      $scope.resetNewInterpreterSetting();
+      getInterpreterSettings();
+      $scope.showAddNewSetting = false;
+    }).
+    error(function(data, status, headers, config) {
+      console.log('Error %o %o', status, data.message);
+    });
+  };
+
+
+  $scope.resetNewInterpreterSetting = function() {
+    $scope.newInterpreterSetting = {
+      name : undefined,
+      group : undefined,
+      option : { remote : true },
+      properties : {}
+    };
+    emptyNewProperty($scope.newInterpreterSetting);
+  };
+
+  $scope.removeInterpreterProperty = function(key, settingId) {
+    if (settingId === undefined) {
+      delete $scope.newInterpreterSetting.properties[key];
+    }
+    else {
+      var index = _.findIndex($scope.interpreterSettings, { 'id': settingId });
+      delete $scope.interpreterSettings[index].properties[key];
+    }
+  };
+
+  $scope.addNewInterpreterProperty = function(settingId) {
+    if(settingId === undefined) {
+      // Add new property from create form
+      if (!$scope.newInterpreterSetting.propertyKey || 
$scope.newInterpreterSetting.propertyKey === '') {
+        return;
+      }
+      
$scope.newInterpreterSetting.properties[$scope.newInterpreterSetting.propertyKey]
 = $scope.newInterpreterSetting.propertyValue;
+      emptyNewProperty($scope.newInterpreterSetting);
+    }
+    else {
+      // Add new property from create form 
+      var index = _.findIndex($scope.interpreterSettings, { 'id': settingId });
+      var setting = $scope.interpreterSettings[index];
+
+      setting.properties[setting.propertyKey] = setting.propertyValue;
+      emptyNewProperty(setting);
+    }
+  };
+
+  var init = function() {
+    $scope.resetNewInterpreterSetting();
+    getInterpreterSettings();
+    getAvailableInterpreters();
+  };
+
+  init();
+});

http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/blob/8c7424a1/zeppelin-web/src/app/interpreter/interpreter.css
----------------------------------------------------------------------
diff --git a/zeppelin-web/src/app/interpreter/interpreter.css 
b/zeppelin-web/src/app/interpreter/interpreter.css
new file mode 100644
index 0000000..1dcc52b
--- /dev/null
+++ b/zeppelin-web/src/app/interpreter/interpreter.css
@@ -0,0 +1,79 @@
+/*
+ * 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.
+ */
+
+.interpreterHead {
+  margin-left: -10px;
+  margin-right: -10px;
+  margin-top: -10px;
+  margin-bottom: 20px;
+  padding: 10px 15px 15px 15px;
+  background-color: white;
+  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.15);
+  border-bottom: 1px solid #E5E5E5;
+}
+
+.interpreterHead .header {
+  font-family: 'Roboto', sans-serif;
+}
+
+.interpreterHead textarea, .interpreter textarea {
+  width: 100%;
+  display: block;
+  height: 20px;
+  resize: none;
+  border: 1px solid #CCCCCC;
+  font-size: 12px;
+}
+
+.interpreter .interpreter-title {
+  font-size:20px;
+  font-weight:bold;
+  color:#3071a9;
+  float:left;
+  margin-top:0px;
+}
+
+.interpreter ul {
+  margin: 0px 0px 0px 0px;
+  padding: 0px 0px 0px 0px;
+}
+
+.interpreter .interpreterInfo {
+  list-style-type: none;
+}
+
+
+.interpreter table tr .interpreterPropertyKey {
+  padding : 5px 5px 5px 5px;
+}
+
+.interpreter table tr .interpreterPropertyValue {
+  padding : 5px 5px 5px 5px;
+  display: block;
+  max-height: 100px;
+  overflow-y: auto;
+}
+
+.interpreter table tr {
+  height : 45px;
+}
+
+.interpreterSettingAdd {
+  margin : 5px 5px 5px 5px;
+  padding : 10px 10px 10px 10px;
+}
+
+.editable-wrap {
+  width : 100%;
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/blob/8c7424a1/zeppelin-web/src/app/interpreter/interpreter.html
----------------------------------------------------------------------
diff --git a/zeppelin-web/src/app/interpreter/interpreter.html 
b/zeppelin-web/src/app/interpreter/interpreter.html
new file mode 100644
index 0000000..69b4766
--- /dev/null
+++ b/zeppelin-web/src/app/interpreter/interpreter.html
@@ -0,0 +1,119 @@
+<!--
+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.
+-->
+<div class="interpreterHead">
+  <div class="header">
+    <div class="row">
+      <div class="col-md-12">
+        <h3 class="new_h3" style="float:left">
+          Interpreters
+        </h3>
+        <span class="btn btn-default fa fa-plus"
+              ng-click="showAddNewSetting = !showAddNewSetting"
+              style="float:right;margin-top:10px;">
+          Create
+        </span>
+      </div>
+    </div>
+    <div class="row">
+      <div class="col-md-12">
+        Manage interpreters settings. You can create create / remove settings. 
Note can bind/unbind these interpreter settings.
+      </div>
+    </div>
+  </div>
+  <div ng-include 
src="'app/interpreter/interpreter-create/interpreter-create.html'"></div>
+</div>
+
+<div class="box width-full home"
+     ng-repeat="setting in interpreterSettings">
+  <div>
+    <div class="row interpreter">
+      <div class="col-md-12">
+        <h3 class="interpreter-title">{{setting.name}} 
+          <small>
+            <span ng-repeat="interpreter in setting.interpreterGroup"
+                  title="{{interpreter.class}}">
+              <span ng-show="!$first">, </span>
+              %{{interpreter.name}}
+            </span>
+          </small>
+        </h3>
+        <span style="float:right">
+          <button class="btn btn-default btn-xs"
+                  ng-click="valueform.$show();
+                  copyOriginInterpreterSettingProperties(setting.id)">
+            <span class="fa fa-pencil"></span> edit</button>
+          <button class="btn btn-default btn-xs"
+                  ng-click="restartInterpreterSetting(setting.id)">
+            <span class="fa fa-refresh"></span> restart</button>
+          <button class="btn btn-default btn-xs"
+                  ng-click="removeInterpreterSetting(setting.id)">
+            <span class="fa fa-remove"></span> remove</button>
+        </span>
+      </div>
+    </div>
+    <br />
+    <div class="row interpreter">
+      <div class="col-md-12">
+        <b>Properties</b>
+        <table class="table table-striped">
+          <tr>
+            <th style="width:30%">name</th>
+            <th>value</th>
+            <th ng-if="valueform.$visible">action</th>
+          </tr>
+          <tr ng-repeat="(key, value) in setting.properties">
+            <td>{{key}}</td>
+            <td>
+              <span editable-textarea="setting.properties[key]" 
e-form="valueform" e-msd-elastic>
+                {{value | breakFilter}}
+              </span>
+            </td>
+            <td ng-if="valueform.$visible">
+              <div class="btn btn-default btn-sm fa fa-remove"
+                   ng-click="removeInterpreterProperty(key, setting.id)">
+              </div>
+            </td>
+          </tr>
+          <tr ng-if="valueform.$visible">
+            <td>
+              <input ng-model="setting.propertyKey"
+                     pu-elastic-input
+                     pu-elastic-input-minwidth="180px">
+              </input>
+            </td>
+            <td>
+              <textarea msd-elastic 
ng-model="setting.propertyValue"></textarea>
+            </td>
+            <td>
+              <div class="btn btn-default btn-sm fa fa-plus"
+                   ng-click="addNewInterpreterProperty(setting.id)">
+              </div>
+            </td>
+          </tr>
+        </table>
+        <form editable-form name="valueform" 
onaftersave="updateInterpreterSetting(setting.id)" ng-show="valueform.$visible">
+          <button type="submit" class="btn btn-primary"
+                  ng-disabled="valueform.$waiting">
+            Save
+          </button>
+          <button type="button" class="btn btn-default"
+                  ng-disabled="valueform.$waiting"
+                  ng-click="valueform.$cancel(); 
resetInterpreterSetting(setting.id)">
+            Cancel
+          </button>
+        </form>
+      </div>
+    </div>
+  </div>
+</div>

http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/blob/8c7424a1/zeppelin-web/src/app/notebook/notebook.controller.js
----------------------------------------------------------------------
diff --git a/zeppelin-web/src/app/notebook/notebook.controller.js 
b/zeppelin-web/src/app/notebook/notebook.controller.js
new file mode 100644
index 0000000..0d01c37
--- /dev/null
+++ b/zeppelin-web/src/app/notebook/notebook.controller.js
@@ -0,0 +1,473 @@
+/* global confirm:false, alert:false */
+/* jshint loopfunc: true */
+/*
+ * 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.
+ */
+'use strict';
+
+angular.module('zeppelinWebApp').controller('NotebookCtrl', function($scope, 
$route, $routeParams, $location, $rootScope, $http, websocketMsgSrv, 
baseUrlSrv) {
+  $scope.note = null;
+  $scope.showEditor = false;
+  $scope.editorToggled = false;
+  $scope.tableToggled = false;
+  $scope.viewOnly = false;
+  $scope.looknfeelOption = [ 'default', 'simple', 'report'];
+  $scope.cronOption = [
+    {name: 'None', value : undefined},
+    {name: '1m', value: '0 0/1 * * * ?'},
+    {name: '5m', value: '0 0/5 * * * ?'},
+    {name: '1h', value: '0 0 0/1 * * ?'},
+    {name: '3h', value: '0 0 0/3 * * ?'},
+    {name: '6h', value: '0 0 0/6 * * ?'},
+    {name: '12h', value: '0 0 0/12 * * ?'},
+    {name: '1d', value: '0 0 0 * * ?'}
+  ];
+
+  $scope.interpreterSettings = [];
+  $scope.interpreterBindings = [];
+
+  var angularObjectRegistry = {};
+
+  $scope.getCronOptionNameFromValue = function(value) {
+    if (!value) {
+      return '';
+    }
+
+    for (var o in $scope.cronOption) {
+      if ($scope.cronOption[o].value===value) {
+        return $scope.cronOption[o].name;
+      }
+    }
+    return value;
+  };
+
+  /** Init the new controller */
+  var initNotebook = function() {
+    websocketMsgSrv.getNotebook($routeParams.noteId);
+  };
+
+  initNotebook();
+
+  /** Remove the note and go back tot he main page */
+  /** TODO(anthony): In the nearly future, go back to the main page and telle 
to the dude that the note have been remove */
+  $scope.removeNote = function(noteId) {
+    var result = confirm('Do you want to delete this notebook?');
+    if (result) {
+      websocketMsgSrv.deleteNotebook(noteId);
+      $location.path('/#');
+    }
+  };
+
+  $scope.runNote = function() {
+    var result = confirm('Run all paragraphs?');
+    if (result) {
+      $scope.$broadcast('runParagraph');
+    }
+  };
+
+  $scope.toggleAllEditor = function() {
+    if ($scope.editorToggled) {
+      $scope.$broadcast('closeEditor');
+    } else {
+      $scope.$broadcast('openEditor');
+    }
+    $scope.editorToggled = !$scope.editorToggled;
+  };
+
+  $scope.showAllEditor = function() {
+    $scope.$broadcast('openEditor');
+  };
+
+  $scope.hideAllEditor = function() {
+    $scope.$broadcast('closeEditor');
+  };
+
+  $scope.toggleAllTable = function() {
+    if ($scope.tableToggled) {
+      $scope.$broadcast('closeTable');
+    } else {
+      $scope.$broadcast('openTable');
+    }
+    $scope.tableToggled = !$scope.tableToggled;
+  };
+
+  $scope.showAllTable = function() {
+    $scope.$broadcast('openTable');
+  };
+
+  $scope.hideAllTable = function() {
+    $scope.$broadcast('closeTable');
+  };
+
+  $scope.isNoteRunning = function() {
+    var running = false;
+    if(!$scope.note){ return false; }
+    for (var i=0; i<$scope.note.paragraphs.length; i++) {
+      if ( $scope.note.paragraphs[i].status === 'PENDING' || 
$scope.note.paragraphs[i].status === 'RUNNING') {
+        running = true;
+        break;
+      }
+    }
+    return running;
+  };
+
+  $scope.setLookAndFeel = function(looknfeel) {
+    $scope.note.config.looknfeel = looknfeel;
+    $scope.setConfig();
+  };
+
+  /** Set cron expression for this note **/
+  $scope.setCronScheduler = function(cronExpr) {
+    $scope.note.config.cron = cronExpr;
+    $scope.setConfig();
+  };
+
+  /** Update note config **/
+  $scope.setConfig = function(config) {
+    if(config) {
+      $scope.note.config = config;
+    }
+    websocketMsgSrv.updateNotebook($scope.note.id, $scope.note.name, 
$scope.note.config);
+  };
+
+  /** Update the note name */
+  $scope.sendNewName = function() {
+    $scope.showEditor = false;
+    if ($scope.note.name) {
+      websocketMsgSrv.updateNotebook($scope.note.id, $scope.note.name, 
$scope.note.config);
+    }
+  };
+
+  /** update the current note */
+  $scope.$on('setNoteContent', function(event, note) {
+    $scope.paragraphUrl = $routeParams.paragraphId;
+    $scope.asIframe = $routeParams.asIframe;
+    if ($scope.paragraphUrl) {
+      note = cleanParagraphExcept($scope.paragraphUrl, note);
+      $rootScope.$broadcast('setIframe', $scope.asIframe);
+    }
+
+    if ($scope.note === null) {
+      $scope.note = note;
+    } else {
+      updateNote(note);
+    }
+    initializeLookAndFeel();
+    //open interpreter binding setting when there're none selected
+    getInterpreterBindings(getInterpreterBindingsCallBack);
+  });
+
+
+  var initializeLookAndFeel = function() {
+    if (!$scope.note.config.looknfeel) {
+      $scope.note.config.looknfeel = 'default';
+    } else {
+      $scope.viewOnly = $scope.note.config.looknfeel === 'report' ? true : 
false;
+    }
+    $rootScope.$broadcast('setLookAndFeel', $scope.note.config.looknfeel);
+  };
+
+  var cleanParagraphExcept = function(paragraphId, note) {
+    var noteCopy = {};
+    noteCopy.id = note.id;
+    noteCopy.name = note.name;
+    noteCopy.config = note.config;
+    noteCopy.info = note.info;
+    noteCopy.paragraphs = [];
+    for (var i=0; i<note.paragraphs.length; i++) {
+      if (note.paragraphs[i].id === paragraphId) {
+        noteCopy.paragraphs[0] = note.paragraphs[i];
+        if (!noteCopy.paragraphs[0].config) {
+          noteCopy.paragraphs[0].config = {};
+        }
+        noteCopy.paragraphs[0].config.editorHide = true;
+        noteCopy.paragraphs[0].config.tableHide = false;
+        break;
+      }
+    }
+    return noteCopy;
+  };
+
+  $scope.$on('moveParagraphUp', function(event, paragraphId) {
+    var newIndex = -1;
+    for (var i=0; i<$scope.note.paragraphs.length; i++) {
+      if ($scope.note.paragraphs[i].id === paragraphId) {
+        newIndex = i-1;
+        break;
+      }
+    }
+
+    if (newIndex<0 || newIndex>=$scope.note.paragraphs.length) {
+      return;
+    }
+    websocketMsgSrv.moveParagraph(paragraphId, newIndex);
+  });
+
+  // create new paragraph on current position
+  $scope.$on('insertParagraph', function(event, paragraphId) {
+    var newIndex = -1;
+    for (var i=0; i<$scope.note.paragraphs.length; i++) {
+      if ($scope.note.paragraphs[i].id === paragraphId) {
+        newIndex = i+1;
+        break;
+      }
+    }
+
+    if (newIndex === $scope.note.paragraphs.length) {
+      alert('Cannot insert after the last paragraph.');
+      return;
+    }
+    if (newIndex < 0 || newIndex > $scope.note.paragraphs.length) {
+      return;
+    }
+    websocketMsgSrv.insertParagraph(newIndex);
+  });
+
+  $scope.$on('moveParagraphDown', function(event, paragraphId) {
+    var newIndex = -1;
+    for (var i=0; i<$scope.note.paragraphs.length; i++) {
+      if ($scope.note.paragraphs[i].id === paragraphId) {
+        newIndex = i+1;
+        break;
+      }
+    }
+
+    if (newIndex<0 || newIndex>=$scope.note.paragraphs.length) {
+      return;
+    }
+    websocketMsgSrv.moveParagraph(paragraphId, newIndex);
+  });
+
+  $scope.$on('moveFocusToPreviousParagraph', function(event, 
currentParagraphId){
+    var focus = false;
+    for (var i=$scope.note.paragraphs.length-1; i>=0; i--) {
+      if (focus === false ) {
+        if ($scope.note.paragraphs[i].id === currentParagraphId) {
+            focus = true;
+            continue;
+        }
+      } else {
+        var p = $scope.note.paragraphs[i];
+        if (!p.config.hide && !p.config.editorHide && !p.config.tableHide) {
+          $scope.$broadcast('focusParagraph', $scope.note.paragraphs[i].id);
+          break;
+        }
+      }
+    }
+  });
+
+  $scope.$on('moveFocusToNextParagraph', function(event, currentParagraphId){
+    var focus = false;
+    for (var i=0; i<$scope.note.paragraphs.length; i++) {
+      if (focus === false ) {
+        if ($scope.note.paragraphs[i].id === currentParagraphId) {
+            focus = true;
+            continue;
+        }
+      } else {
+        var p = $scope.note.paragraphs[i];
+        if (!p.config.hide && !p.config.editorHide && !p.config.tableHide) {
+          $scope.$broadcast('focusParagraph', $scope.note.paragraphs[i].id);
+          break;
+        }
+      }
+    }
+  });
+
+  var updateNote = function(note) {
+    /** update Note name */
+    if (note.name !== $scope.note.name) {
+      console.log('change note name: %o to %o', $scope.note.name, note.name);
+      $scope.note.name = note.name;
+    }
+
+    $scope.note.config = note.config;
+    $scope.note.info = note.info;
+
+    var newParagraphIds = note.paragraphs.map(function(x) {return x.id;});
+    var oldParagraphIds = $scope.note.paragraphs.map(function(x) {return 
x.id;});
+
+    var numNewParagraphs = newParagraphIds.length;
+    var numOldParagraphs = oldParagraphIds.length;
+
+    /** add a new paragraph */
+    if (numNewParagraphs > numOldParagraphs) {
+      for (var index in newParagraphIds) {
+        if (oldParagraphIds[index] !== newParagraphIds[index]) {
+          $scope.note.paragraphs.splice(index, 0, note.paragraphs[index]);
+          break;
+        }
+      }
+    }
+
+    /** update or move paragraph */
+    if (numNewParagraphs === numOldParagraphs) {
+      for (var idx in newParagraphIds) {
+        var newEntry = note.paragraphs[idx];
+        if (oldParagraphIds[idx] === newParagraphIds[idx]) {
+          $scope.$broadcast('updateParagraph', {paragraph: newEntry});
+        } else {
+          // move paragraph
+          var oldIdx = oldParagraphIds.indexOf(newParagraphIds[idx]);
+          $scope.note.paragraphs.splice(oldIdx, 1);
+          $scope.note.paragraphs.splice(idx, 0, newEntry);
+          // rebuild id list since paragraph has moved.
+          oldParagraphIds = $scope.note.paragraphs.map(function(x) {return 
x.id;});
+        }
+      }
+    }
+
+    /** remove paragraph */
+    if (numNewParagraphs < numOldParagraphs) {
+      for (var oldidx in oldParagraphIds) {
+        if(oldParagraphIds[oldidx] !== newParagraphIds[oldidx]) {
+          $scope.note.paragraphs.splice(oldidx, 1);
+          break;
+        }
+      }
+    }
+  };
+
+  var getInterpreterBindings = function(callback) {
+    $http.get(baseUrlSrv.getRestApiBase()+ '/notebook/interpreter/bind/' 
+$scope.note.id).
+      success(function(data, status, headers, config) {
+        $scope.interpreterBindings = data.body;
+        $scope.interpreterBindingsOrig = jQuery.extend(true, [], 
$scope.interpreterBindings); // to check dirty
+        if (callback) {
+          callback();
+        }
+      }).
+      error(function(data, status, headers, config) {
+        console.log('Error %o %o', status, data.message);
+      });
+  };
+
+  var getInterpreterBindingsCallBack = function() {
+    var selected = false;
+    for (var i in $scope.interpreterBindings) {
+      var setting = $scope.interpreterBindings[i];
+      if (setting.selected) {
+        selected = true;
+        break;
+      }
+    }
+
+    if (!selected) {
+      // make default selection
+      var selectedIntp = {};
+      for (var i in $scope.interpreterBindings) {
+        var setting = $scope.interpreterBindings[i];
+        if (!selectedIntp[setting.group]) {
+          setting.selected = true;
+          selectedIntp[setting.group] = true;
+        }
+      }
+      $scope.showSetting = true;
+    }
+  };
+
+  $scope.interpreterSelectionListeners = {
+    accept : function(sourceItemHandleScope, destSortableScope) {return true;},
+    itemMoved: function (event) {},
+    orderChanged: function(event) {}
+  };
+
+  $scope.openSetting = function() {
+    $scope.showSetting = true;
+    getInterpreterBindings();
+  };
+
+  $scope.closeSetting = function() {
+    if (isSettingDirty()) {
+      var result = confirm('Changes will be discarded');
+      if (!result) {
+        return;
+      }
+    }
+    $scope.showSetting = false;
+  };
+
+  $scope.saveSetting = function() {
+    var selectedSettingIds = [];
+    for (var no in $scope.interpreterBindings) {
+      var setting = $scope.interpreterBindings[no];
+      if (setting.selected) {
+        selectedSettingIds.push(setting.id);
+      }
+    }
+
+    $http.put(baseUrlSrv.getRestApiBase() + '/notebook/interpreter/bind/' + 
$scope.note.id,
+             selectedSettingIds).
+      success(function(data, status, headers, config) {
+        console.log('Interpreter binding %o saved', selectedSettingIds);
+        $scope.showSetting = false;
+      }).
+      error(function(data, status, headers, config) {
+        console.log('Error %o %o', status, data.message);
+      });
+  };
+
+  $scope.toggleSetting = function() {
+    if ($scope.showSetting) {
+      $scope.closeSetting();
+    } else {
+      $scope.openSetting();
+    }
+  };
+
+  var isSettingDirty = function() {
+    if (angular.equals($scope.interpreterBindings, 
$scope.interpreterBindingsOrig)) {
+      return false;
+    } else {
+      return true;
+    }
+  };
+
+  $scope.$on('angularObjectUpdate', function(event, data) {
+    if (data.noteId === $scope.note.id) {
+      var scope = $rootScope.compiledScope;
+      var varName = data.angularObject.name;
+
+      if (angular.equals(data.angularObject.object, scope[varName])) {
+        // return when update has no change
+        return;
+      }
+
+      if (!angularObjectRegistry[varName]) {
+        angularObjectRegistry[varName] = {
+          interpreterGroupId : data.interpreterGroupId,
+        };
+      }
+
+      angularObjectRegistry[varName].skipEmit = true;
+
+      if (!angularObjectRegistry[varName].clearWatcher) {
+        angularObjectRegistry[varName].clearWatcher = scope.$watch(varName, 
function(newValue, oldValue) {
+          if (angularObjectRegistry[varName].skipEmit) {
+            angularObjectRegistry[varName].skipEmit = false;
+            return;
+          }
+          websocketMsgSrv.updateAngularObject($routeParams.noteId, varName, 
newValue, angularObjectRegistry[varName].interpreterGroupId);
+        });
+      }
+      scope[varName] = data.angularObject.object;
+    }
+      
+  });
+
+  var isFunction = function(functionToCheck) {
+    var getType = {};
+    return functionToCheck && getType.toString.call(functionToCheck) === 
'[object Function]';
+  };
+
+});

http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/blob/8c7424a1/zeppelin-web/src/app/notebook/notebook.css
----------------------------------------------------------------------
diff --git a/zeppelin-web/src/app/notebook/notebook.css 
b/zeppelin-web/src/app/notebook/notebook.css
new file mode 100644
index 0000000..477e7a1
--- /dev/null
+++ b/zeppelin-web/src/app/notebook/notebook.css
@@ -0,0 +1,517 @@
+/*
+ * 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.
+ */
+
+.paragraph-col {
+  margin: 0 0 0 0px;
+  padding: 0 0 0 0px;
+}
+
+.paragraph {
+  padding: 2px 8px 4px 8px;
+  min-height: 32px;
+}
+
+.paragraphForm.form-horizontal .form-group {
+  margin-right: 0px;
+  margin-left:  0px;
+}
+
+.paragraphForm.form-horizontal .form-group label {
+  padding-left: 0;
+}
+
+.paragraph .tableDisplay .hljs {
+  background: none;
+}
+
+.paragraph .ace_print-margin {
+  background: none !important;
+}
+
+.paragraphAsIframe{
+  padding: 0px 0px 0px 0px;
+  margin-top: -79px;
+  margin-left: -10px;
+  margin-right: -10px;
+}
+
+.paragraphAsIframe .control {
+  background-color: rgba(255,255,255,0.9);
+  border-top: 1px solid #EFEFEF;
+  display: none;
+  float: right;
+  color: #999;
+  margin-top: -9px;
+  margin-right:0px;
+  position:absolute;
+  clear:both;
+  right:25px;
+  /*z-index:10;*/
+}
+
+.paragraphAsIframe table {
+  margin-bottom: 0px;
+}
+
+.paragraphAsIframe .editor {
+  width: 100%;
+  border-left: 4px solid #EEEEEE;
+  background: rgba(255, 255, 255, 0.9);
+}
+
+.paragraphAsIframe .text {
+  white-space: pre;
+  display: block;
+  unicode-bidi: embed;
+  display: block !important;
+  margin: 0 0 10px!important;
+  font-size: 12px!important;
+  line-height: 1.42857143!important;
+  word-break: break-all!important;
+  word-wrap: break-word!important;
+  font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', 'Consolas', 
'source-code-pro', monospace;
+}
+
+.ace_marker-layer .ace_selection {
+    z-index: 0 !important;
+}
+
+.ace_marker-layer .ace_selected-word {
+    z-index: 0 !important;
+}
+
+.labelBtn {
+  padding: .2em .6em .3em;
+  font-size: 75%;
+  font-weight: bold;
+  line-height: 1;
+  color: #fff;
+  text-align: center;
+  white-space: nowrap;
+  border-radius: .25em;
+}
+
+.note-jump {
+  margin-top: 20px;
+}
+
+.noteBtnfa {
+    margin-left: 3px;
+}
+
+.control span {
+    margin-left: 4px;
+}
+
+.control {
+    padding: 4px;
+}
+
+.paragraph-space {
+  margin-bottom: 5px;
+  padding: 10px !important;
+}
+
+.paragraph .control {
+  background-color: rgba(255,255,255,0.85);
+  /*display: none;*/
+  float: right;
+  color: #999;
+  margin-top: 1px;
+  margin-right: 5px;
+  position:absolute;
+  clear:both;
+  right:15px;
+  top: 16px;
+  text-align:right;
+  font-size:12px;
+}
+
+.paragraph .control li{
+  font-size:12px;
+  margin-bottom:4px;
+  color: #333333;
+}
+
+.paragraph table {
+  margin-bottom: 0px;
+}
+
+.paragraph .title {
+  margin: 3px 0px 0px 0px;
+  height: 20px;
+  font-size: 12px;
+}
+
+.paragraph .title div {
+  width: 80%;
+  font-weight: bold;
+  font-family: 'Roboto', sans-serif;
+  font-size: 17px !important;
+  text-transform: capitalize;
+}
+
+.paragraph .title input {
+  width: 80%;
+  line-height: 1.42857143;
+  color: #555;
+  background-color: #fff;
+  background-image: none;
+  border: 1px solid #ccc;
+  border-radius: 0px;
+  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
+  box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
+  -webkit-transition: border-color ease-in-out .15s, -webkit-box-shadow 
ease-in-out .15s;
+  -o-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
+  transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
+  text-transform: capitalize;
+  font-family: 'Roboto', sans-serif;
+  font-size: 14px!important;
+}
+
+.paragraph .editor {
+  width: 100%;
+  border-left: 4px solid #DDDDDD;
+  background: rgba(255, 255, 255, 0.0);
+  margin: 7px 0 2px 0px;
+}
+
+.paragraph .text {
+  white-space: pre;
+  display: block;
+  unicode-bidi: embed;
+  display: block !important;
+  margin: 0 0 0px !important;
+  line-height: 1.42857143 !important;
+  word-break: break-all !important;
+  word-wrap: break-word !important;
+  font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', 'Consolas', 
'source-code-pro', monospace;
+  font-size: 12px !important;
+  margin-bottom: 5px !important;
+}
+
+.paragraph p {
+  margin : 0 0 0 0px;
+}
+
+.paragraph div svg {
+  width : 100%;
+}
+
+.ace-tm {
+  background-color: #FFFFFF;
+  color: black;
+}
+.ace_editor {
+  position: relative;
+  overflow: hidden;
+  font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', 'Consolas', 
'source-code-pro', monospace;
+  font-size: 12px;
+  line-height: normal;
+  direction: ltr;
+}
+
+.ace_hidden-cursors {opacity:0}
+
+/** Remove z-index to ace */
+.ace_text-input, .ace_gutter, .ace_layer,
+.emacs-mode, .ace_text-layer, .ace_cursor-layer,
+.ace_cursor, .ace_scrollbar {
+  z-index:auto !important;
+}
+
+/** Force opacity:0 to textarea in writing texts **/
+.ace_text-input.ace_composition {
+ opacity: 0 !important;
+}
+
+#main .emacs-mode .ace_cursor {
+  background-color:#C0C0C0!important;
+  border: none !important;
+}
+
+.paragraph .status {
+  font-size: 10px;
+  color: #AAAAAA;
+  text-align: right;
+  visibility: hidden;
+}
+
+.paragraph .runControl {
+  font-size: 1px;
+  color: #AAAAAA;
+  height:4px;
+  margin: 1px 0px 0px 0px;
+}
+
+.paragraph .runControl .progress {
+  position: relative;
+  width:100%;
+  height:4px;
+  z-index:100;
+  border-radius: 0px;
+}
+
+.paragraph .runControl .progress .progress-bar {
+  z-index:100;
+}
+
+.paragraph .executionTime {
+  color: #999;
+  font-size: 10px;
+  font-family: 'Roboto', sans-serif;
+}
+
+
+.disable {
+  opacity:0.6!important;
+  pointer-events: none;
+}
+
+.noteAction {
+  margin-left: -10px;
+  margin-right: -10px;
+  margin-top: -10px;
+  font-family: 'Roboto', sans-serif;
+}
+
+.noteAction li{
+  font-size:12px;
+  margin-bottom:4px;
+  color: #333333;
+}
+
+.new_h3 {
+  margin-top: 1px;
+  padding-top: 7px;
+}
+
+.form-control2 {
+  width: 100%;
+  margin-left: 15px;
+  font-size: 29px;
+  line-height: 1.42857143;
+  color: #555;
+  background-color: #fff;
+  background-image: none;
+  border: 1px solid #ccc;
+  border-radius: 4px;
+  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
+  box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
+  -webkit-transition: border-color ease-in-out .15s, -webkit-box-shadow 
ease-in-out .15s;
+  -o-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
+  transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
+}
+
+.form-control-static2 {
+  padding-top: 7px;
+  font-size: 29px;
+  margin-left: 15px;
+  padding-bottom: 7px;
+  margin-bottom: 0;
+  display: inline-block;
+}
+
+/* panel default */
+.panel-default {
+  /* border: none; */
+  border-color: #DDDDDD;
+  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.15);
+}
+
+.panel-group .panel-default {
+  /*border: solid #e5e5e5;
+  border-width: 1px 1px 2px;*/
+}
+
+.panel-default > .panel-heading {
+  color: #34495e;
+  background-color: #ffffff;
+  border-color: #e5e5e5;
+}
+
+.panel-default > .panel-heading + .panel-collapse .panel-body {
+  border-top-color: #e5e5e5;
+}
+
+.panel-default > .panel-heading > .dropdown .caret {
+  border-color: #ecf0f1 transparent;
+}
+
+.panel-default > .panel-footer + .panel-collapse .panel-body {
+  border-bottom-color: #e5e5e5;
+}
+
+.panel-body-heading {
+  position: relative;
+  display: block;
+  padding-left: 10px;
+  padding-top: 15px;
+  padding-bottom: 15px;
+}
+
+.paragraph-margin {
+  margin-right: 2px;
+  margin-left: 2px;
+}
+
+.tableDisplay img {
+  display: block;
+  max-width: 100%;
+  height: auto;
+}
+
+.tableDisplay .btn-group span {
+  margin: 10px 0px 0px 10px;
+  font-size:12px;
+}
+.tableDisplay .btn-group span a {
+  cursor:pointer;
+}
+
+.tableDisplay .option {
+  padding: 5px 5px 5px 5px;
+  font-size:12px;
+  height:auto;
+  overflow : auto;
+  /*min-height: 200px;*/
+  border-top: 1px solid #ecf0f1;
+
+}
+
+.tableDisplay .option .columns {
+  height: 100%;
+}
+
+.tableDisplay .option .columns ul {
+
+  background-color: white;
+  /*min-width: 100px;*/
+  width:auto;
+  padding: 3px 3px 3px 3px;
+  height : 150px;
+  border: 1px solid #CCC;
+  box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
+  -webkit-transition: border-color ease-in-out .15s, -webkit-box-shadow 
ease-in-out .15s;
+  -o-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
+  transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
+
+}
+
+.tableDisplay .option .columns ul li {
+  margin: 3px 3px 3px 3px;
+}
+
+.tableDisplay .option .columns ul li span {
+  cursor: pointer;
+  margin-left: 3px;
+  margin-top: 3px;
+}
+
+.tableDisplay .option .columns ul li div ul { /* aggregation menu */
+  width:auto;
+  height:auto;
+}
+
+.tableDisplay .option .columns ul li div ul li a {
+  padding: 0px;
+  margin: 0px;
+  cursor: pointer;
+}
+
+.tableDisplay .option .columns a:focus,
+.tableDisplay .option .columns a:hover {
+  text-decoration: none;
+  outline: 0;
+  outline-offset: 0px;
+}
+
+.graphContainer {
+  position:relative;
+  margin-bottom: 5px;
+  overflow: visible;
+}
+
+.noOverflow {
+    overflow: hidden !important;
+}
+
+.graphContainer .table {
+  overflow: hidden;
+  margin-bottom: 5px !important;
+}
+
+.allFields {
+  margin-bottom: 10px;
+}
+.noDot {
+  list-style-type: none;
+  padding-left:5px;
+}
+
+.liVertical {
+  display:block;
+  float:left;
+  padding: 5px;
+}
+.row {
+  margin-right: 0px !important
+}
+
+.lightBold {
+  font-weight: 500;
+}
+
+.resizable-helper {
+  border: 3px solid #DDDDDD;
+}
+
+/* note setting panel */
+.setting {
+  background-color: white;
+  padding: 10px 15px 15px 15px;
+  margin-left: -10px;
+  margin-right: -10px;
+  font-family: 'Roboto', sans-serif;
+  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.15);
+  border-bottom: 1px solid #E5E5E5;
+}
+
+.setting .interpreterSettings {
+  list-style-type: none;
+  background-color: #EFEFEF;
+  padding: 10px 10px 10px 10px;
+  box-shadow: 0px 1px 1px rgba(0, 0, 0, 0.15);
+  border: 1px solid #E5E5E5;
+}
+
+.setting .interpreterSettings div div {
+  margin: 2px 0px 2px 0px;
+}
+
+.setting .interpreterSettings div div {
+  cursor: pointer;
+}
+
+.setting .modal-header {
+  border: 0px;
+}
+
+.setting .modal-body {
+  border: 0px;
+}
+
+.setting .modal-footer {
+  border: 0px;
+}

http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/blob/8c7424a1/zeppelin-web/src/app/notebook/notebook.html
----------------------------------------------------------------------
diff --git a/zeppelin-web/src/app/notebook/notebook.html 
b/zeppelin-web/src/app/notebook/notebook.html
new file mode 100644
index 0000000..3a3f751
--- /dev/null
+++ b/zeppelin-web/src/app/notebook/notebook.html
@@ -0,0 +1,170 @@
+<!--
+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.
+-->
+<!-- Here the controller <NotebookCtrl> is not needed because explicitly set 
in the app.js (route) -->
+<div>
+  <div class="noteAction" ng-show="note.id && !paragraphUrl">
+    <h3 class="new_h3">
+      <input type="text" class="form-control2" placeholder="{{note.name || 
'Note ' + note.id}}" style="width:200px;"
+             ng-show="showEditor" ng-model="note.name" 
ng-enter="sendNewName()" ng-delete="showEditor = false" autofocus/>
+        <p class="form-control-static2" ng-click="showEditor = true" 
ng-show="!showEditor">{{note.name || 'Note ' + note.id}}</p>
+          <span class="labelBtn btn-group">
+            <button type="button"
+                    class="btn btn-default btn-xs"
+                    ng-click="runNote()"
+                    ng-if="!isNoteRunning()"
+                    tooltip-placement="top" tooltip="Run all the note">
+              <i class="icon-control-play"></i>
+            </button>
+
+            <button type="button"
+                    class="btn btn-default btn-xs"
+                    ng-click="toggleAllEditor()"
+                    ng-hide="viewOnly"
+                    tooltip-placement="top" tooltip="Show/hide the code">
+              <i ng-class="editorToggled ? 'fa icon-size-actual' : 'fa 
icon-size-fullscreen'"></i></button>
+
+            <button type="button"
+                    class="btn btn-default btn-xs"
+                    ng-click="toggleAllTable()"
+                    ng-hide="viewOnly"
+                    tooltip-placement="top" tooltip="Show/hide the output">
+              <i ng-class="tableToggled ? 'fa icon-notebook' : 'fa 
icon-book-open'"></i></button>
+
+            <button type="button"
+                    class="btn btn-default btn-xs"
+                    ng-click="removeNote(note.id)"
+                    ng-hide="viewOnly"
+                    tooltip-placement="top" tooltip="Remove the notebook">
+              <i class="icon-trash"></i></button>
+          </span>
+
+          <span ng-hide="viewOnly">
+            <div class="labelBtn btn-group">
+              <div class="btn btn-default btn-xs dropdown-toggle"
+                   type="button"
+                   data-toggle="dropdown"
+                   ng-class="{ 'btn-info' : note.config.cron, 'btn-danger' : 
note.info.cron, 'btn-default' : !note.config.cron}">
+                <span class="fa fa-clock-o"></span> 
{{getCronOptionNameFromValue(note.config.cron)}}
+              </div>
+              <ul class="dropdown-menu" role="menu" style="width:300px">
+                <li>
+                  <div style="padding:10px 20px 0 
20px;font-weight:normal;word-wrap:break-word">
+                    Run note with cron scheduler.
+                    Either choose from<br/>preset or write your own <a 
href="http://www.quartz-scheduler.org/documentation/quartz-1.x/tutorials/crontrigger";
 target=_blank>cron expression</a>.
+                    <br/><br/>
+                    <span>- Preset</span>
+                    <a ng-repeat="cr in cronOption"
+                       type="button"
+                       ng-click="setCronScheduler(cr.value)"
+                       style="cursor:pointer"
+                       dropdown-input>{{cr.name}}</a>
+                    <br/><br/>
+                    <span>- Cron expression</span>
+                    <input type="text"
+                           ng-model="note.config.cron"
+                           ng-change="setCronScheduler(note.config.cron)"
+                           dropdown-input>
+                    </input>
+                    <p ng-show="note.info.cron"
+                       style="color:red">
+                      {{note.info.cron}}
+                    </p>
+                  </div>
+                </li>
+              </ul>
+            </div>
+      </span>
+
+      <div class="pull-right"
+           style="margin-top:15px; margin-right:15px; font-size:15px;">
+        <span style="position:relative; top:3px; margin-right:4px; 
cursor:pointer"
+              data-toggle="modal"
+              data-target="#shortcutModal"
+              tooltip-placement="top" tooltip="List of shortcut">
+          <i class="icon-question"></i>
+        </span>
+        <span style="position:relative; top:2px; margin-right:4px; 
cursor:pointer;"
+              ng-click="toggleSetting()"
+              tooltip-placement="top" tooltip="Interpreter binding">
+          <i class="fa fa-cog"
+             ng-style="{color: showSetting ? '#3071A9' : 'black' }"></i>
+        </span>
+
+        <span class="btn-group">
+          <button type="button"
+                  class="btn btn-default btn-xs dropdown-toggle"
+                  data-toggle="dropdown">
+            {{note.config.looknfeel}} <span class="caret"></span>
+          </button>
+          <ul class="dropdown-menu pull-right" role="menu">
+            <li ng-repeat="looknfeel in looknfeelOption">
+              <a style="cursor:pointer"
+                 ng-click="setLookAndFeel(looknfeel)">{{looknfeel}}</a>
+            </li>
+          </ul>
+        </span>
+      </div>
+    </h3>
+  </div>
+
+  <!-- settings -->
+  <div ng-show="showSetting"
+       class="setting">
+    <div>
+      <h4>Settings</h4>
+    </div>
+    <hr />
+    <div>
+      <h5>Interpreter binding</h5>
+      <p>
+        Bind interpreter for this note.
+        Click to Bind/Unbind interpreter.
+        Drag and drop to reorder interpreters. <br />
+        The first interpreter on the list becomes default. To create/remove 
interpreters, go to <a href="/#/interpreter">Interpreter</a> menu.
+      </p>
+
+      <div class="interpreterSettings"
+           as-sortable="interpreterSelectionListeners" 
data-ng-model="interpreterBindings">
+        <div data-ng-repeat="item in interpreterBindings" as-sortable-item>
+          <div as-sortable-item-handle
+               ng-click="item.selected = !item.selected"
+               class="btn"
+               ng-class="{'btn-info': item.selected, 'btn-default': 
!item.selected}"><font style="font-size:16px">{{item.name}}</font> <small><span 
ng-repeat="intp in item.interpreters"><span ng-show="!$first">, 
</span>%{{intp.name}}</span></small></div>
+        </div>
+      </div>
+    </div>
+    <br />
+    <div>
+      <button class="btn btn-primary" ng-click="saveSetting()">Save</button>
+      <button class="btn btn-default" ng-click="closeSetting()">Cancel</button>
+    </div>
+  </div>
+
+  <div class="note-jump"></div>
+
+  <!-- Include the paragraphs according to the note -->
+  <div id="{{currentParagraph.id}}_paragraphColumn_main"
+       ng-repeat="currentParagraph in note.paragraphs"
+       ng-controller="ParagraphCtrl"
+       ng-Init="init(currentParagraph)"
+       ng-class="columnWidthClass(currentParagraph.config.colWidth)"
+       class="paragraph-col">
+    <div id="{{currentParagraph.id}}_paragraphColumn"
+         ng-include src="'app/notebook/paragraph/paragraph.html'"
+         ng-class="{'paragraph-space box paragraph-margin': !asIframe, 
'focused': paragraphFocused}"
+         ng-hide="currentParagraph.config.tableHide && viewOnly">
+    </div>
+  </div>
+  <div style="clear:both;height:10px"></div>
+</div>

Reply via email to