You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@flink.apache.org by uc...@apache.org on 2017/03/08 14:28:48 UTC

[1/5] flink git commit: [FLINK-3427] [webui] Rebuild web UI

Repository: flink
Updated Branches:
  refs/heads/master 7a629fc59 -> 121b12b7c


http://git-wip-us.apache.org/repos/asf/flink/blob/121b12b7/flink-runtime-web/web-dashboard/web/partials/jobs/job.plan.html
----------------------------------------------------------------------
diff --git a/flink-runtime-web/web-dashboard/web/partials/jobs/job.plan.html b/flink-runtime-web/web-dashboard/web/partials/jobs/job.plan.html
index 6d88b23..c52d67f 100644
--- a/flink-runtime-web/web-dashboard/web/partials/jobs/job.plan.html
+++ b/flink-runtime-web/web-dashboard/web/partials/jobs/job.plan.html
@@ -20,7 +20,7 @@ limitations under the License.
 <split>
   <div id="canvas" class="split">
     <div class="canvas-wrapper">
-      <div job-plan="job-plan" plan="plan" jobid="{{jobid}}" set-node="changeNode(nodeid)" class="main-canvas"></div>
+      <div job-plan="job-plan" plan="plan" watermarks="watermarks" jobid="{{jobid}}" set-node="changeNode(nodeid)" class="main-canvas"></div>
     </div>
   </div>
   <div id="job-panel" class="split">
@@ -30,6 +30,7 @@ limitations under the License.
           <li ui-sref-active="active"><a ui-sref=".subtasks({nodeid: nodeid})">Subtasks</a></li>
           <li ui-sref-active="active"><a ui-sref=".taskmanagers({nodeid: nodeid})">TaskManagers</a></li>
           <li ui-sref-active="active"><a ui-sref=".metrics({nodeid: nodeid})">Metrics</a></li>
+          <li ui-sref-active="active"><a ui-sref=".watermarks({nodeid: nodeid})">Watermarks</a></li>
           <li ui-sref-active="active"><a ui-sref=".accumulators({nodeid: nodeid})">Accumulators</a></li>
           <li ui-sref-active="active"><a ui-sref=".checkpoints({nodeid: nodeid})">Checkpoints</a></li>
           <li ng-if="job.state == 'RUNNING'" ui-sref-active="active"><a ui-sref=".backpressure({nodeid: nodeid})">Back Pressure</a></li>

http://git-wip-us.apache.org/repos/asf/flink/blob/121b12b7/flink-runtime-web/web-dashboard/web/partials/jobs/job.plan.node-list.watermarks.html
----------------------------------------------------------------------
diff --git a/flink-runtime-web/web-dashboard/web/partials/jobs/job.plan.node-list.watermarks.html b/flink-runtime-web/web-dashboard/web/partials/jobs/job.plan.node-list.watermarks.html
new file mode 100644
index 0000000..9a8095a
--- /dev/null
+++ b/flink-runtime-web/web-dashboard/web/partials/jobs/job.plan.node-list.watermarks.html
@@ -0,0 +1,45 @@
+
+<!--
+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.
+
+-->
+<table class="table table-body-hover table-clickable table-activable">
+  <thead>
+    <tr>
+      <th>Name</th>
+      <th>Low Watermark</th>
+      <th>Parallelism</th>
+      <th>Status</th>
+    </tr>
+  </thead>
+  <tbody ng-repeat="v in job.vertices" ng-class="{ active: v.id == nodeid }" ng-click="changeNode(v.id)">
+    <tr ng-if="v.type == 'regular'">
+      <td class="td-long">{{ v.name | humanizeText }}</td>
+      <td>{{ watermarks[v.id]["lowWatermark"] | humanizeWatermark }}</td>
+      <td>{{ v.parallelism }}</td>
+      <td>
+        <bs-label status="{{v.status}}">{{v.status}}</bs-label>
+      </td>
+    </tr>
+    <tr ng-if="nodeid &amp;&amp; v.id == nodeid">
+      <td colspan="4">
+        <div ng-show="hasWatermark(v.id)" ng-include=" 'partials/jobs/job.plan.node.watermarks.html' "></div>
+        <div ng-show="!hasWatermark(v.id)">No Watermarks</div>
+      </td>
+    </tr>
+  </tbody>
+</table>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/flink/blob/121b12b7/flink-runtime-web/web-dashboard/web/partials/jobs/job.plan.node.watermarks.html
----------------------------------------------------------------------
diff --git a/flink-runtime-web/web-dashboard/web/partials/jobs/job.plan.node.watermarks.html b/flink-runtime-web/web-dashboard/web/partials/jobs/job.plan.node.watermarks.html
new file mode 100644
index 0000000..f1530a5
--- /dev/null
+++ b/flink-runtime-web/web-dashboard/web/partials/jobs/job.plan.node.watermarks.html
@@ -0,0 +1,33 @@
+
+<!--
+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.
+
+-->
+<table class="table table-hover table-clickable table-activable table-inner">
+  <thead>
+    <tr>
+      <th>Subtask</th>
+      <th>Watermark</th>
+    </tr>
+  </thead>
+  <tbody>
+    <tr ng-repeat="(subtaskIndex, watermark) in watermarks[nodeid]['watermarks']">
+      <td>{{ subtaskIndex | increment }}</td>
+      <td>{{ watermark | humanizeWatermark }}</td>
+    </tr>
+  </tbody>
+</table>
\ No newline at end of file


[3/5] flink git commit: [FLINK-3427] [webui] Rebuild web UI

Posted by uc...@apache.org.
[FLINK-3427] [webui] Rebuild web UI

This closes #3366.


Project: http://git-wip-us.apache.org/repos/asf/flink/repo
Commit: http://git-wip-us.apache.org/repos/asf/flink/commit/121b12b7
Tree: http://git-wip-us.apache.org/repos/asf/flink/tree/121b12b7
Diff: http://git-wip-us.apache.org/repos/asf/flink/diff/121b12b7

Branch: refs/heads/master
Commit: 121b12b7c7156a5b45f2cb9e069b4ec685d33364
Parents: 4ef18f6
Author: Ufuk Celebi <uc...@apache.org>
Authored: Wed Mar 8 11:36:35 2017 +0100
Committer: Ufuk Celebi <uc...@apache.org>
Committed: Wed Mar 8 15:28:41 2017 +0100

----------------------------------------------------------------------
 flink-runtime-web/web-dashboard/web/js/index.js |  4 +-
 .../web-dashboard/web/js/vendor.js              | 10 ++---
 .../web/partials/jobs/job.plan.html             |  3 +-
 .../jobs/job.plan.node-list.watermarks.html     | 45 ++++++++++++++++++++
 .../partials/jobs/job.plan.node.watermarks.html | 33 ++++++++++++++
 5 files changed, 87 insertions(+), 8 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/flink/blob/121b12b7/flink-runtime-web/web-dashboard/web/js/index.js
----------------------------------------------------------------------
diff --git a/flink-runtime-web/web-dashboard/web/js/index.js b/flink-runtime-web/web-dashboard/web/js/index.js
index e4b76aa..cb9fd6c 100644
--- a/flink-runtime-web/web-dashboard/web/js/index.js
+++ b/flink-runtime-web/web-dashboard/web/js/index.js
@@ -1,2 +1,2 @@
-angular.module("flinkApp",["ui.router","angularMoment","dndLists"]).run(["$rootScope",function(e){return e.sidebarVisible=!1,e.showSidebar=function(){return e.sidebarVisible=!e.sidebarVisible,e.sidebarClass="force-show"}}]).value("flinkConfig",{jobServer:"","refresh-interval":1e4}).run(["JobsService","MainService","flinkConfig","$interval",function(e,t,r,n){return t.loadConfig().then(function(t){return angular.extend(r,t),e.listJobs(),n(function(){return e.listJobs()},r["refresh-interval"])})}]).config(["$uiViewScrollProvider",function(e){return e.useAnchorScroll()}]).run(["$rootScope","$state",function(e,t){return e.$on("$stateChangeStart",function(e,r,n,o){if(r.redirectTo)return e.preventDefault(),t.go(r.redirectTo,n)})}]).config(["$stateProvider","$urlRouterProvider",function(e,t){return e.state("overview",{url:"/overview",views:{main:{templateUrl:"partials/overview.html",controller:"OverviewController"}}}).state("running-jobs",{url:"/running-jobs",views:{main:{templateUrl:"parti
 als/jobs/running-jobs.html",controller:"RunningJobsController"}}}).state("completed-jobs",{url:"/completed-jobs",views:{main:{templateUrl:"partials/jobs/completed-jobs.html",controller:"CompletedJobsController"}}}).state("single-job",{url:"/jobs/{jobid}","abstract":!0,views:{main:{templateUrl:"partials/jobs/job.html",controller:"SingleJobController"}}}).state("single-job.plan",{url:"",redirectTo:"single-job.plan.subtasks",views:{details:{templateUrl:"partials/jobs/job.plan.html",controller:"JobPlanController"}}}).state("single-job.plan.subtasks",{url:"",views:{"node-details":{templateUrl:"partials/jobs/job.plan.node-list.subtasks.html",controller:"JobPlanSubtasksController"}}}).state("single-job.plan.metrics",{url:"/metrics",views:{"node-details":{templateUrl:"partials/jobs/job.plan.node-list.metrics.html",controller:"JobPlanMetricsController"}}}).state("single-job.plan.taskmanagers",{url:"/taskmanagers",views:{"node-details":{templateUrl:"partials/jobs/job.plan.node-list.taskmanage
 rs.html",controller:"JobPlanTaskManagersController"}}}).state("single-job.plan.accumulators",{url:"/accumulators",views:{"node-details":{templateUrl:"partials/jobs/job.plan.node-list.accumulators.html",controller:"JobPlanAccumulatorsController"}}}).state("single-job.plan.checkpoints",{url:"/checkpoints",redirectTo:"single-job.plan.checkpoints.overview",views:{"node-details":{templateUrl:"partials/jobs/job.plan.node-list.checkpoints.html",controller:"JobPlanCheckpointsController"}}}).state("single-job.plan.checkpoints.overview",{url:"/overview",views:{"checkpoints-view":{templateUrl:"partials/jobs/job.plan.node.checkpoints.overview.html",controller:"JobPlanCheckpointsController"}}}).state("single-job.plan.checkpoints.summary",{url:"/summary",views:{"checkpoints-view":{templateUrl:"partials/jobs/job.plan.node.checkpoints.summary.html",controller:"JobPlanCheckpointsController"}}}).state("single-job.plan.checkpoints.history",{url:"/history",views:{"checkpoints-view":{templateUrl:"partia
 ls/jobs/job.plan.node.checkpoints.history.html",controller:"JobPlanCheckpointsController"}}}).state("single-job.plan.checkpoints.config",{url:"/config",views:{"checkpoints-view":{templateUrl:"partials/jobs/job.plan.node.checkpoints.config.html",controller:"JobPlanCheckpointsController"}}}).state("single-job.plan.checkpoints.details",{url:"/details/{checkpointId}",views:{"checkpoints-view":{templateUrl:"partials/jobs/job.plan.node.checkpoints.details.html",controller:"JobPlanCheckpointDetailsController"}}}).state("single-job.plan.backpressure",{url:"/backpressure",views:{"node-details":{templateUrl:"partials/jobs/job.plan.node-list.backpressure.html",controller:"JobPlanBackPressureController"}}}).state("single-job.timeline",{url:"/timeline",views:{details:{templateUrl:"partials/jobs/job.timeline.html"}}}).state("single-job.timeline.vertex",{url:"/{vertexId}",views:{vertex:{templateUrl:"partials/jobs/job.timeline.vertex.html",controller:"JobTimelineVertexController"}}}).state("single-
 job.exceptions",{url:"/exceptions",views:{details:{templateUrl:"partials/jobs/job.exceptions.html",controller:"JobExceptionsController"}}}).state("single-job.config",{url:"/config",views:{details:{templateUrl:"partials/jobs/job.config.html"}}}).state("all-manager",{url:"/taskmanagers",views:{main:{templateUrl:"partials/taskmanager/index.html",controller:"AllTaskManagersController"}}}).state("single-manager",{url:"/taskmanager/{taskmanagerid}","abstract":!0,views:{main:{templateUrl:"partials/taskmanager/taskmanager.html",controller:"SingleTaskManagerController"}}}).state("single-manager.metrics",{url:"/metrics",views:{details:{templateUrl:"partials/taskmanager/taskmanager.metrics.html"}}}).state("single-manager.stdout",{url:"/stdout",views:{details:{templateUrl:"partials/taskmanager/taskmanager.stdout.html",controller:"SingleTaskManagerStdoutController"}}}).state("single-manager.log",{url:"/log",views:{details:{templateUrl:"partials/taskmanager/taskmanager.log.html",controller:"Singl
 eTaskManagerLogsController"}}}).state("jobmanager",{url:"/jobmanager",views:{main:{templateUrl:"partials/jobmanager/index.html"}}}).state("jobmanager.config",{url:"/config",views:{details:{templateUrl:"partials/jobmanager/config.html",controller:"JobManagerConfigController"}}}).state("jobmanager.stdout",{url:"/stdout",views:{details:{templateUrl:"partials/jobmanager/stdout.html",controller:"JobManagerStdoutController"}}}).state("jobmanager.log",{url:"/log",views:{details:{templateUrl:"partials/jobmanager/log.html",controller:"JobManagerLogsController"}}}).state("submit",{url:"/submit",views:{main:{templateUrl:"partials/submit.html",controller:"JobSubmitController"}}}),t.otherwise("/overview")}]),angular.module("flinkApp").directive("bsLabel",["JobsService",function(e){return{transclude:!0,replace:!0,scope:{getLabelClass:"&",status:"@"},template:"<span title='{{status}}' ng-class='getLabelClass()'><ng-transclude></ng-transclude></span>",link:function(t,r,n){return t.getLabelClass=fun
 ction(){return"label label-"+e.translateLabelState(n.status)}}}}]).directive("bpLabel",["JobsService",function(e){return{transclude:!0,replace:!0,scope:{getBackPressureLabelClass:"&",status:"@"},template:"<span title='{{status}}' ng-class='getBackPressureLabelClass()'><ng-transclude></ng-transclude></span>",link:function(t,r,n){return t.getBackPressureLabelClass=function(){return"label label-"+e.translateBackPressureLabelState(n.status)}}}}]).directive("indicatorPrimary",["JobsService",function(e){return{replace:!0,scope:{getLabelClass:"&",status:"@"},template:"<i title='{{status}}' ng-class='getLabelClass()' />",link:function(t,r,n){return t.getLabelClass=function(){return"fa fa-circle indicator indicator-"+e.translateLabelState(n.status)}}}}]).directive("tableProperty",function(){return{replace:!0,scope:{value:"="},template:"<td title=\"{{value || 'None'}}\">{{value || 'None'}}</td>"}}),angular.module("flinkApp").filter("amDurationFormatExtended",["angularMomentConfig",function(e)
 {var t;return t=function(e,t,r){return"undefined"==typeof e||null===e?"":moment.duration(e,t).format(r,{trim:!1})},t.$stateful=e.statefulFilters,t}]).filter("humanizeDuration",function(){return function(e,t){var r,n,o,i,s,a;return"undefined"==typeof e||null===e?"":(i=e%1e3,a=Math.floor(e/1e3),s=a%60,a=Math.floor(a/60),o=a%60,a=Math.floor(a/60),n=a%24,a=Math.floor(a/24),r=a,0===r?0===n?0===o?0===s?i+"ms":s+"s ":o+"m "+s+"s":t?n+"h "+o+"m":n+"h "+o+"m "+s+"s":t?r+"d "+n+"h":r+"d "+n+"h "+o+"m "+s+"s")}}).filter("limit",function(){return function(e){return e.length>73&&(e=e.substring(0,35)+"..."+e.substring(e.length-35,e.length)),e}}).filter("humanizeText",function(){return function(e){return e?e.replace(/&gt;/g,">").replace(/<br\/>/g,""):""}}).filter("humanizeBytes",function(){return function(e){var t,r;return r=["B","KB","MB","GB","TB","PB","EB"],t=function(e,n){var o;return o=Math.pow(1024,n),e<o?(e/o).toFixed(2)+" "+r[n]:e<1e3*o?(e/o).toPrecision(3)+" "+r[n]:t(e,n+1)},"undefined"==
 typeof e||null===e?"":e<1e3?e+" B":t(e,1)}}).filter("toLocaleString",function(){return function(e){return e.toLocaleString()}}).filter("toUpperCase",function(){return function(e){return e.toUpperCase()}}).filter("percentage",function(){return function(e){return(100*e).toFixed(0)+"%"}}),angular.module("flinkApp").service("MainService",["$http","flinkConfig","$q",function(e,t,r){return this.loadConfig=function(){var n;return n=r.defer(),e.get(t.jobServer+"config").success(function(e,t,r,o){return n.resolve(e)}),n.promise},this}]),angular.module("flinkApp").controller("JobManagerConfigController",["$scope","JobManagerConfigService",function(e,t){return t.loadConfig().then(function(t){return null==e.jobmanager&&(e.jobmanager={}),e.jobmanager.config=t})}]).controller("JobManagerLogsController",["$scope","JobManagerLogsService",function(e,t){return t.loadLogs().then(function(t){return null==e.jobmanager&&(e.jobmanager={}),e.jobmanager.log=t}),e.reloadData=function(){return t.loadLogs().th
 en(function(t){return e.jobmanager.log=t})}}]).controller("JobManagerStdoutController",["$scope","JobManagerStdoutService",function(e,t){return t.loadStdout().then(function(t){return null==e.jobmanager&&(e.jobmanager={}),e.jobmanager.stdout=t}),e.reloadData=function(){return t.loadStdout().then(function(t){return e.jobmanager.stdout=t})}}]),angular.module("flinkApp").service("JobManagerConfigService",["$http","flinkConfig","$q",function(e,t,r){var n;return n={},this.loadConfig=function(){var n;return n=r.defer(),e.get(t.jobServer+"jobmanager/config").success(function(e,t,r,o){return o=e,n.resolve(e)}),n.promise},this}]).service("JobManagerLogsService",["$http","flinkConfig","$q",function(e,t,r){var n;return n={},this.loadLogs=function(){var o;return o=r.defer(),e.get(t.jobServer+"jobmanager/log").success(function(e,t,r,i){return n=e,o.resolve(e)}),o.promise},this}]).service("JobManagerStdoutService",["$http","flinkConfig","$q",function(e,t,r){var n;return n={},this.loadStdout=functi
 on(){var o;return o=r.defer(),e.get(t.jobServer+"jobmanager/stdout").success(function(e,t,r,i){return n=e,o.resolve(e)}),o.promise},this}]),angular.module("flinkApp").controller("RunningJobsController",["$scope","$state","$stateParams","JobsService",function(e,t,r,n){return e.jobObserver=function(){return e.jobs=n.getJobs("running")},n.registerObserver(e.jobObserver),e.$on("$destroy",function(){return n.unRegisterObserver(e.jobObserver)}),e.jobObserver()}]).controller("CompletedJobsController",["$scope","$state","$stateParams","JobsService",function(e,t,r,n){return e.jobObserver=function(){return e.jobs=n.getJobs("finished")},n.registerObserver(e.jobObserver),e.$on("$destroy",function(){return n.unRegisterObserver(e.jobObserver)}),e.jobObserver()}]).controller("SingleJobController",["$scope","$state","$stateParams","JobsService","MetricsService","$rootScope","flinkConfig","$interval",function(e,t,r,n,o,i,s,a){var l;return e.jobid=r.jobid,e.job=null,e.plan=null,e.vertices=null,e.back
 PressureOperatorStats={},n.loadJob(r.jobid).then(function(t){return e.job=t,e.plan=t.plan,e.vertices=t.vertices,o.setupMetrics(r.jobid,t.vertices)}),l=a(function(){return n.loadJob(r.jobid).then(function(t){return e.job=t,e.$broadcast("reload")})},s["refresh-interval"]),e.$on("$destroy",function(){return e.job=null,e.plan=null,e.vertices=null,e.backPressureOperatorStats=null,a.cancel(l)}),e.cancelJob=function(e){return angular.element(e.currentTarget).removeClass("btn").removeClass("btn-default").html("Cancelling..."),n.cancelJob(r.jobid).then(function(e){return{}})},e.stopJob=function(e){return angular.element(e.currentTarget).removeClass("btn").removeClass("btn-default").html("Stopping..."),n.stopJob(r.jobid).then(function(e){return{}})}}]).controller("JobPlanController",["$scope","$state","$stateParams","$window","JobsService",function(e,t,r,n,o){return e.nodeid=null,e.nodeUnfolded=!1,e.stateList=o.stateList(),e.changeNode=function(t){return t!==e.nodeid?(e.nodeid=t,e.vertex=null
 ,e.subtasks=null,e.accumulators=null,e.operatorCheckpointStats=null,e.$broadcast("reload"),e.$broadcast("node:change",e.nodeid)):(e.nodeid=null,e.nodeUnfolded=!1,e.vertex=null,e.subtasks=null,e.accumulators=null,e.operatorCheckpointStats=null)},e.deactivateNode=function(){return e.nodeid=null,e.nodeUnfolded=!1,e.vertex=null,e.subtasks=null,e.accumulators=null,e.operatorCheckpointStats=null},e.toggleFold=function(){return e.nodeUnfolded=!e.nodeUnfolded}}]).controller("JobPlanSubtasksController",["$scope","JobsService",function(e,t){var r;return r=function(){return t.getSubtasks(e.nodeid).then(function(t){return e.subtasks=t})},!e.nodeid||e.vertex&&e.vertex.st||r(),e.$on("reload",function(t){if(e.nodeid)return r()})}]).controller("JobPlanTaskManagersController",["$scope","JobsService",function(e,t){var r;return r=function(){return t.getTaskManagers(e.nodeid).then(function(t){return e.taskmanagers=t})},!e.nodeid||e.vertex&&e.vertex.st||r(),e.$on("reload",function(t){if(e.nodeid)return 
 r()})}]).controller("JobPlanAccumulatorsController",["$scope","JobsService",function(e,t){var r;return r=function(){return t.getAccumulators(e.nodeid).then(function(t){return e.accumulators=t.main,e.subtaskAccumulators=t.subtasks})},!e.nodeid||e.vertex&&e.vertex.accumulators||r(),e.$on("reload",function(t){if(e.nodeid)return r()})}]).controller("JobPlanCheckpointsController",["$scope","$state","$stateParams","JobsService",function(e,t,r,n){var o;return e.checkpointDetails={},e.checkpointDetails.id=-1,n.getCheckpointConfig().then(function(t){return e.checkpointConfig=t}),o=function(){return n.getCheckpointStats().then(function(t){if(null!==t)return e.checkpointStats=t})},o(),e.$on("reload",function(e){return o()})}]).controller("JobPlanCheckpointDetailsController",["$scope","$state","$stateParams","JobsService",function(e,t,r,n){var o,i;return e.subtaskDetails={},e.checkpointDetails.id=r.checkpointId,o=function(t){return n.getCheckpointDetails(t).then(function(t){return null!==t?e.ch
 eckpoint=t:e.unknown_checkpoint=!0})},i=function(t,r){return n.getCheckpointSubtaskDetails(t,r).then(function(t){if(null!==t)return e.subtaskDetails[r]=t})},o(r.checkpointId),e.nodeid&&i(r.checkpointId,e.nodeid),e.$on("reload",function(t){if(o(r.checkpointId),e.nodeid)return i(r.checkpointId,e.nodeid)}),e.$on("$destroy",function(){return e.checkpointDetails.id=-1})}]).controller("JobPlanBackPressureController",["$scope","JobsService",function(e,t){var r;return r=function(){if(e.now=Date.now(),e.nodeid)return t.getOperatorBackPressure(e.nodeid).then(function(t){return e.backPressureOperatorStats[e.nodeid]=t})},r(),e.$on("reload",function(e){return r()})}]).controller("JobTimelineVertexController",["$scope","$state","$stateParams","JobsService",function(e,t,r,n){var o;return o=function(){return n.getVertex(r.vertexId).then(function(t){return e.vertex=t})},o(),e.$on("reload",function(e){return o()})}]).controller("JobExceptionsController",["$scope","$state","$stateParams","JobsService"
 ,function(e,t,r,n){return n.loadExceptions().then(function(t){return e.exceptions=t})}]).controller("JobPropertiesController",["$scope","JobsService",function(e,t){return e.changeNode=function(r){return r!==e.nodeid?(e.nodeid=r,t.getNode(r).then(function(t){return e.node=t})):(e.nodeid=null,e.node=null)}}]).controller("JobPlanMetricsController",["$scope","JobsService","MetricsService",function(e,t,r){var n;if(e.dragging=!1,e.window=r.getWindow(),e.availableMetrics=null,e.$on("$destroy",function(){return r.unRegisterObserver()}),n=function(){return t.getVertex(e.nodeid).then(function(t){return e.vertex=t}),r.getAvailableMetrics(e.jobid,e.nodeid).then(function(t){return e.availableMetrics=t,e.metrics=r.getMetricsSetup(e.jobid,e.nodeid).names,r.registerObserver(e.jobid,e.nodeid,function(t){return e.$broadcast("metrics:data:update",t.timestamp,t.values)})})},e.dropped=function(t,o,i,s,a){return r.orderMetrics(e.jobid,e.nodeid,i,o),e.$broadcast("metrics:refresh",i),n(),!1},e.dragStart=fu
 nction(){return e.dragging=!0},e.dragEnd=function(){return e.dragging=!1},e.addMetric=function(t){return r.addMetric(e.jobid,e.nodeid,t.id),n()},e.removeMetric=function(t){return r.removeMetric(e.jobid,e.nodeid,t),n()},e.setMetricSize=function(t,o){return r.setMetricSize(e.jobid,e.nodeid,t,o),n()},e.getValues=function(t){return r.getValues(e.jobid,e.nodeid,t)},e.$on("node:change",function(t,r){if(!e.dragging)return n()}),e.nodeid)return n()}]),angular.module("flinkApp").directive("vertex",["$state",function(e){return{template:"<svg class='timeline secondary' width='0' height='0'></svg>",scope:{data:"="},link:function(e,t,r){var n,o,i;i=t.children()[0],o=t.width(),angular.element(i).attr("width",o),(n=function(e){var t,r,n;return d3.select(i).selectAll("*").remove(),n=[],angular.forEach(e.subtasks,function(e,t){var r;return r=[{label:"Scheduled",color:"#666",borderColor:"#555",starting_time:e.timestamps.SCHEDULED,ending_time:e.timestamps.DEPLOYING,type:"regular"},{label:"Deploying",c
 olor:"#aaa",borderColor:"#555",starting_time:e.timestamps.DEPLOYING,ending_time:e.timestamps.RUNNING,type:"regular"}],e.timestamps.FINISHED>0&&r.push({label:"Running",color:"#ddd",borderColor:"#555",starting_time:e.timestamps.RUNNING,ending_time:e.timestamps.FINISHED,type:"regular"}),n.push({label:"("+e.subtask+") "+e.host,times:r})}),t=d3.timeline().stack().tickFormat({format:d3.time.format("%L"),tickSize:1}).prefix("single").labelFormat(function(e){return e}).margin({left:100,right:0,top:0,bottom:0}).itemHeight(30).relativeTime(),r=d3.select(i).datum(n).call(t)})(e.data)}}}]).directive("timeline",["$state",function(e){return{template:"<svg class='timeline' width='0' height='0'></svg>",scope:{vertices:"=",jobid:"="},link:function(t,r,n){var o,i,s,a;s=r.children()[0],i=r.width(),angular.element(s).attr("width",i),a=function(e){return e.replace("&gt;",">")},o=function(r){var n,o,i;return d3.select(s).selectAll("*").remove(),i=[],angular.forEach(r,function(e){if(e["start-time"]>-1)ret
 urn"scheduled"===e.type?i.push({times:[{label:a(e.name),color:"#cccccc",borderColor:"#555555",starting_time:e["start-time"],ending_time:e["end-time"],type:e.type}]}):i.push({times:[{label:a(e.name),color:"#d9f1f7",borderColor:"#62cdea",starting_time:e["start-time"],ending_time:e["end-time"],link:e.id,type:e.type}]})}),n=d3.timeline().stack().click(function(r,n,o){if(r.link)return e.go("single-job.timeline.vertex",{jobid:t.jobid,vertexId:r.link})}).tickFormat({format:d3.time.format("%L"),tickSize:1}).prefix("main").margin({left:0,right:0,top:0,bottom:0}).itemHeight(30).showBorderLine().showHourTimeline(),o=d3.select(s).datum(i).call(n)},t.$watch(n.vertices,function(e){if(e)return o(e)})}}}]).directive("split",function(){return{compile:function(e,t){return Split(e.children(),{sizes:[50,50],direction:"vertical"})}}}).directive("jobPlan",["$timeout",function(e){return{template:"<svg class='graph'><g /></svg> <svg class='tmp' width='1' height='1'><g /></svg> <div class='btn-group zoom-bu
 ttons'> <a class='btn btn-default zoom-in' ng-click='zoomIn()'><i class='fa fa-plus' /></a> <a class='btn btn-default zoom-out' ng-click='zoomOut()'><i class='fa fa-minus' /></a> </div>",scope:{plan:"=",setNode:"&"},link:function(e,t,r){var n,o,i,s,a,l,u,c,d,f,p,g,m,b,h,v,k,j,S,C,w,$;p=null,S=d3.behavior.zoom(),$=[],b=r.jobid,k=t.children()[0],v=t.children().children()[0],j=t.children()[1],l=d3.select(k),u=d3.select(v),c=d3.select(j),n=t.width(),angular.element(t.children()[0]).width(n),e.zoomIn=function(){var e,t,r;if(S.scale()<2.99)return e=S.translate(),t=e[0]*(S.scale()+.1/S.scale()),r=e[1]*(S.scale()+.1/S.scale()),S.scale(S.scale()+.1),S.translate([t,r]),u.attr("transform","translate("+t+","+r+") scale("+S.scale()+")")},e.zoomOut=function(){var e,t,r;if(S.scale()>.31)return S.scale(S.scale()-.1),e=S.translate(),t=e[0]*(S.scale()-.1/S.scale()),r=e[1]*(S.scale()-.1/S.scale()),S.translate([t,r]),u.attr("transform","translate("+t+","+r+") scale("+S.scale()+")")},i=function(e){var t
 ;return t="",null==e.ship_strategy&&null==e.local_strategy||(t+="<div class='edge-label'>",null!=e.ship_strategy&&(t+=e.ship_strategy),void 0!==e.temp_mode&&(t+=" ("+e.temp_mode+")"),void 0!==e.local_strategy&&(t+=",<br>"+e.local_strategy),t+="</div>"),t},m=function(e){return"partialSolution"===e||"nextPartialSolution"===e||"workset"===e||"nextWorkset"===e||"solutionSet"===e||"solutionDelta"===e},g=function(e,t){return"mirror"===t?"node-mirror":m(t)?"node-iteration":"node-normal"},s=function(e,t,r,n){var o,i;return o="<div href='#/jobs/"+b+"/vertex/"+e.id+"' class='node-label "+g(e,t)+"'>",o+="mirror"===t?"<h3 class='node-name'>Mirror of "+e.operator+"</h3>":"<h3 class='node-name'>"+e.operator+"</h3>",""===e.description?o+="":(i=e.description,i=w(i),o+="<h4 class='step-name'>"+i+"</h4>"),null!=e.step_function?o+=f(e.id,r,n):(m(t)&&(o+="<h5>"+t+" Node</h5>"),""!==e.parallelism&&(o+="<h5>Parallelism: "+e.parallelism+"</h5>"),void 0!==e.operator&&e.operator_strategy&&(o+="<h5>Operation
 : "+w(e.operator_strategy)+"</h5>")),o+="</div>"},f=function(e,t,r){var n,o;return o="svg-"+e,n="<svg class='"+o+"' width="+t+" height="+r+"><g /></svg>"},w=function(e){var t;for("<"===e.charAt(0)&&(e=e.replace("<","&lt;"),e=e.replace(">","&gt;")),t="";e.length>30;)t=t+e.substring(0,30)+"<br>",e=e.substring(30,e.length);return t+=e},a=function(e,t,r,n,o,i){return null==n&&(n=!1),r.id===t.partial_solution?e.setNode(r.id,{label:s(r,"partialSolution",o,i),labelType:"html","class":g(r,"partialSolution")}):r.id===t.next_partial_solution?e.setNode(r.id,{label:s(r,"nextPartialSolution",o,i),labelType:"html","class":g(r,"nextPartialSolution")}):r.id===t.workset?e.setNode(r.id,{label:s(r,"workset",o,i),labelType:"html","class":g(r,"workset")}):r.id===t.next_workset?e.setNode(r.id,{label:s(r,"nextWorkset",o,i),labelType:"html","class":g(r,"nextWorkset")}):r.id===t.solution_set?e.setNode(r.id,{label:s(r,"solutionSet",o,i),labelType:"html","class":g(r,"solutionSet")}):r.id===t.solution_delta?e.
 setNode(r.id,{label:s(r,"solutionDelta",o,i),labelType:"html","class":g(r,"solutionDelta")}):e.setNode(r.id,{label:s(r,"",o,i),labelType:"html","class":g(r,"")})},o=function(e,t,r,n,o){return e.setEdge(o.id,r.id,{label:i(o),labelType:"html",arrowhead:"normal"})},h=function(e,t){var r,n,i,s,l,u,d,f,p,g,m,b,v,k;for(n=[],null!=t.nodes?k=t.nodes:(k=t.step_function,i=!0),s=0,u=k.length;s<u;s++)if(r=k[s],p=0,f=0,r.step_function&&(v=new dagreD3.graphlib.Graph({multigraph:!0,compound:!0}).setGraph({nodesep:20,edgesep:0,ranksep:20,rankdir:"LR",marginx:10,marginy:10}),$[r.id]=v,h(v,r),m=new dagreD3.render,c.select("g").call(m,v),p=v.graph().width,f=v.graph().height,angular.element(j).empty()),a(e,t,r,i,p,f),n.push(r.id),null!=r.inputs)for(b=r.inputs,l=0,d=b.length;l<d;l++)g=b[l],o(e,t,r,n,g);return e},C=function(e,t){var r,n,o;for(n in e.nodes){if(r=e.nodes[n],r.id===t)return r;if(null!=r.step_function)for(o in r.step_function)if(r.step_function[o].id===t)return r.step_function[o]}},d=functio
 n(t){var r,n,o,i,s,a;p=new dagreD3.graphlib.Graph({multigraph:!0,compound:!0}).setGraph({nodesep:70,edgesep:0,ranksep:50,rankdir:"LR",marginx:40,marginy:40}),h(p,t),o=new dagreD3.render,u.call(o,p);for(r in $)i=$[r],l.select("svg.svg-"+r+" g").call(o,i);return n=.5,s=Math.floor((angular.element(k).width()-p.graph().width*n)/2),a=Math.floor((angular.element(k).height()-p.graph().height*n)/2),S.scale(n).translate([s,a]),u.attr("transform","translate("+s+", "+a+") scale("+S.scale()+")"),S.on("zoom",function(){var e;return e=d3.event,u.attr("transform","translate("+e.translate+") scale("+e.scale+")")}),S(l),u.selectAll(".node").on("click",function(t){return e.setNode({nodeid:t})})},e.$watch(r.plan,function(e){if(e)return d(e)})}}}]),angular.module("flinkApp").service("JobsService",["$http","flinkConfig","$log","amMoment","$q","$timeout",function(e,t,r,n,o,i){var s,a,l,u,c,d;return s=null,a=null,l={},c={running:[],finished:[],cancelled:[],failed:[]},u=[],d=function(){return angular.forEa
 ch(u,function(e){return e()})},this.registerObserver=function(e){return u.push(e)},this.unRegisterObserver=function(e){var t;return t=u.indexOf(e),u.splice(t,1)},this.stateList=function(){return["SCHEDULED","DEPLOYING","RUNNING","FINISHED","FAILED","CANCELING","CANCELED"]},this.translateLabelState=function(e){switch(e.toLowerCase()){case"finished":return"success";case"failed":return"danger";case"scheduled":return"default";case"deploying":return"info";case"running":return"primary";case"canceling":return"warning";case"pending":return"info";case"total":return"black";default:return"default"}},this.setEndTimes=function(e){return angular.forEach(e,function(e,t){if(!(e["end-time"]>-1))return e["end-time"]=e["start-time"]+e.duration})},this.processVertices=function(e){return angular.forEach(e.vertices,function(e,t){return e.type="regular"}),e.vertices.unshift({name:"Scheduled","start-time":e.timestamps.CREATED,"end-time":e.timestamps.CREATED+1,type:"scheduled"})},this.listJobs=function(){va
 r r;return r=o.defer(),e.get(t.jobServer+"joboverview").success(function(e){return function(t,n,o,i){return angular.forEach(t,function(t,r){switch(r){case"running":return c.running=e.setEndTimes(t);case"finished":return c.finished=e.setEndTimes(t);case"cancelled":return c.cancelled=e.setEndTimes(t);case"failed":return c.failed=e.setEndTimes(t)}}),r.resolve(c),d()}}(this)),r.promise},this.getJobs=function(e){return c[e]},this.getAllJobs=function(){return c},this.loadJob=function(r){return s=null,l.job=o.defer(),e.get(t.jobServer+"jobs/"+r).success(function(n){return function(o,i,a,u){return n.setEndTimes(o.vertices),n.processVertices(o),e.get(t.jobServer+"jobs/"+r+"/config").success(function(e){return o=angular.extend(o,e),s=o,l.job.resolve(s)})}}(this)),l.job.promise},this.getNode=function(e){var t,r;return r=function(e,t){var n,o,i,s;for(n=0,o=t.length;n<o;n++){if(i=t[n],i.id===e)return i;if(i.step_function&&(s=r(e,i.step_function)),s)return s}return null},t=o.defer(),l.job.promise
 .then(function(n){return function(o){var i;return i=r(e,s.plan.nodes),i.vertex=n.seekVertex(e),t.resolve(i)}}(this)),t.promise},this.seekVertex=function(e){var t,r,n,o;for(n=s.vertices,t=0,r=n.length;t<r;t++)if(o=n[t],o.id===e)return o;return null},this.getVertex=function(r){var n;return n=o.defer(),l.job.promise.then(function(o){return function(i){var a;return a=o.seekVertex(r),e.get(t.jobServer+"jobs/"+s.jid+"/vertices/"+r+"/subtasktimes").success(function(e){return a.subtasks=e.subtasks,n.resolve(a)})}}(this)),n.promise},this.getSubtasks=function(r){var n;return n=o.defer(),l.job.promise.then(function(o){return function(o){return e.get(t.jobServer+"jobs/"+s.jid+"/vertices/"+r).success(function(e){var t;return t=e.subtasks,n.resolve(t)})}}(this)),n.promise},this.getTaskManagers=function(r){var n;return n=o.defer(),l.job.promise.then(function(o){return function(o){return e.get(t.jobServer+"jobs/"+s.jid+"/vertices/"+r+"/taskmanagers").success(function(e){var t;return t=e.taskmanager
 s,n.resolve(t)})}}(this)),n.promise},this.getAccumulators=function(r){var n;return n=o.defer(),l.job.promise.then(function(o){return function(o){return console.log(s.jid),e.get(t.jobServer+"jobs/"+s.jid+"/vertices/"+r+"/accumulators").success(function(o){var i;return i=o["user-accumulators"],e.get(t.jobServer+"jobs/"+s.jid+"/vertices/"+r+"/subtasks/accumulators").success(function(e){var t;return t=e.subtasks,n.resolve({main:i,subtasks:t})})})}}(this)),n.promise},this.getCheckpointConfig=function(){var r;return r=o.defer(),l.job.promise.then(function(n){return function(n){return e.get(t.jobServer+"jobs/"+s.jid+"/checkpoints/config").success(function(e){return angular.equals({},e)?r.resolve(null):r.resolve(e)})}}(this)),r.promise},this.getCheckpointStats=function(){var r;return r=o.defer(),l.job.promise.then(function(n){return function(n){return e.get(t.jobServer+"jobs/"+s.jid+"/checkpoints").success(function(e,t,n,o){return angular.equals({},e)?r.resolve(null):r.resolve(e)})}}(this))
 ,r.promise},this.getCheckpointDetails=function(r){var n;return n=o.defer(),l.job.promise.then(function(o){return function(o){return e.get(t.jobServer+"jobs/"+s.jid+"/checkpoints/details/"+r).success(function(e){return angular.equals({},e)?n.resolve(null):n.resolve(e)})}}(this)),n.promise},this.getCheckpointSubtaskDetails=function(r,n){var i;return i=o.defer(),l.job.promise.then(function(o){return function(o){return e.get(t.jobServer+"jobs/"+s.jid+"/checkpoints/details/"+r+"/subtasks/"+n).success(function(e){return angular.equals({},e)?i.resolve(null):i.resolve(e)})}}(this)),i.promise},this.getOperatorBackPressure=function(r){var n;return n=o.defer(),e.get(t.jobServer+"jobs/"+s.jid+"/vertices/"+r+"/backpressure").success(function(e){return function(e){return n.resolve(e)}}(this)),n.promise},this.translateBackPressureLabelState=function(e){switch(e.toLowerCase()){case"in-progress":return"danger";case"ok":return"success";case"low":return"warning";case"high":return"danger";default:retur
 n"default"}},this.loadExceptions=function(){var r;return r=o.defer(),l.job.promise.then(function(n){return function(n){return e.get(t.jobServer+"jobs/"+s.jid+"/exceptions").success(function(e){return s.exceptions=e,r.resolve(e)})}}(this)),r.promise},this.cancelJob=function(r){return e.get(t.jobServer+"jobs/"+r+"/yarn-cancel")},this.stopJob=function(t){return e.get("jobs/"+t+"/yarn-stop")},this}]),angular.module("flinkApp").directive("metricsGraph",function(){return{template:'<div class="panel panel-default panel-metric"> <div class="panel-heading"> <span class="metric-title">{{metric.id}}</span> <div class="buttons"> <div class="btn-group"> <button type="button" ng-class="[btnClasses, {active: metric.size != \'big\'}]" ng-click="setSize(\'small\')">Small</button> <button type="button" ng-class="[btnClasses, {active: metric.size == \'big\'}]" ng-click="setSize(\'big\')">Big</button> </div> <a title="Remove" class="btn btn-default btn-xs remove" ng-click="removeMetric()"><i class="fa 
 fa-close" /></a> </div> </div> <div class="panel-body"> <svg /> </div> </div>',replace:!0,scope:{metric:"=",window:"=",removeMetric:"&",setMetricSize:"=",getValues:"&"},link:function(e,t,r){return e.btnClasses=["btn","btn-default","btn-xs"],e.value=null,e.data=[{values:e.getValues()}],e.options={x:function(e,t){return e.x},y:function(e,t){return e.y},xTickFormat:function(e){return d3.time.format("%H:%M:%S")(new Date(e))},yTickFormat:function(e){var t,r,n,o;for(r=!1,n=0,o=1,t=Math.abs(e);!r&&n<50;)Math.pow(10,n)<=t&&t<Math.pow(10,n+o)?r=!0:n+=o;return r&&n>6?e/Math.pow(10,n)+"E"+n:""+e}},e.showChart=function(){return d3.select(t.find("svg")[0]).datum(e.data).transition().duration(250).call(e.chart)},e.chart=nv.models.lineChart().options(e.options).showLegend(!1).margin({top:15,left:60,bottom:30,right:30}),e.chart.yAxis.showMaxMin(!1),e.chart.tooltip.hideDelay(0),e.chart.tooltip.contentGenerator(function(e){return"<p>"+d3.time.format("%H:%M:%S")(new Date(e.point.x))+" | "+e.point.y+"<
 /p>"}),nv.utils.windowResize(e.chart.update),e.setSize=function(t){return e.setMetricSize(e.metric,t)},e.showChart(),e.$on("metrics:data:update",function(t,r,n){return e.value=parseFloat(n[e.metric.id]),e.data[0].values.push({x:r,y:e.value}),e.data[0].values.length>e.window&&e.data[0].values.shift(),e.showChart(),e.chart.clearHighlights(),e.chart.tooltip.hidden(!0)}),t.find(".metric-title").qtip({content:{text:e.metric.id},position:{my:"bottom left",at:"top left"},style:{classes:"qtip-light qtip-timeline-bar"}})}}}),angular.module("flinkApp").service("MetricsService",["$http","$q","flinkConfig","$interval",function(e,t,r,n){return this.metrics={},this.values={},this.watched={},this.observer={jobid:null,nodeid:null,callback:null},this.refresh=n(function(e){return function(){return angular.forEach(e.metrics,function(t,r){return angular.forEach(t,function(t,n){var o;if(o=[],angular.forEach(t,function(e,t){return o.push(e.id)}),o.length>0)return e.getMetrics(r,n,o).then(function(t){if(r
 ===e.observer.jobid&&n===e.observer.nodeid&&e.observer.callback)return e.observer.callback(t)})});
-})}}(this),r["refresh-interval"]),this.registerObserver=function(e,t,r){return this.observer.jobid=e,this.observer.nodeid=t,this.observer.callback=r},this.unRegisterObserver=function(){return this.observer={jobid:null,nodeid:null,callback:null}},this.setupMetrics=function(e,t){return this.setupLS(),this.watched[e]=[],angular.forEach(t,function(t){return function(r,n){if(r.id)return t.watched[e].push(r.id)}}(this))},this.getWindow=function(){return 100},this.setupLS=function(){return null==sessionStorage.flinkMetrics&&this.saveSetup(),this.metrics=JSON.parse(sessionStorage.flinkMetrics)},this.saveSetup=function(){return sessionStorage.flinkMetrics=JSON.stringify(this.metrics)},this.saveValue=function(e,t,r){if(null==this.values[e]&&(this.values[e]={}),null==this.values[e][t]&&(this.values[e][t]=[]),this.values[e][t].push(r),this.values[e][t].length>this.getWindow())return this.values[e][t].shift()},this.getValues=function(e,t,r){var n;return null==this.values[e]?[]:null==this.values[
 e][t]?[]:(n=[],angular.forEach(this.values[e][t],function(e){return function(e,t){if(null!=e.values[r])return n.push({x:e.timestamp,y:e.values[r]})}}(this)),n)},this.setupLSFor=function(e,t){if(null==this.metrics[e]&&(this.metrics[e]={}),null==this.metrics[e][t])return this.metrics[e][t]=[]},this.addMetric=function(e,t,r){return this.setupLSFor(e,t),this.metrics[e][t].push({id:r,size:"small"}),this.saveSetup()},this.removeMetric=function(e){return function(t,r,n){var o;if(null!=e.metrics[t][r])return o=e.metrics[t][r].indexOf(n),o===-1&&(o=_.findIndex(e.metrics[t][r],{id:n})),o!==-1&&e.metrics[t][r].splice(o,1),e.saveSetup()}}(this),this.setMetricSize=function(e){return function(t,r,n,o){var i;if(null!=e.metrics[t][r])return i=e.metrics[t][r].indexOf(n.id),i===-1&&(i=_.findIndex(e.metrics[t][r],{id:n.id})),i!==-1&&(e.metrics[t][r][i]={id:n.id,size:o}),e.saveSetup()}}(this),this.orderMetrics=function(e,t,r,n){return this.setupLSFor(e,t),angular.forEach(this.metrics[e][t],function(o){
 return function(i,s){if(i.id===r.id&&(o.metrics[e][t].splice(s,1),s<n))return n-=1}}(this)),this.metrics[e][t].splice(n,0,r),this.saveSetup()},this.getMetricsSetup=function(e){return function(t,r){return{names:_.map(e.metrics[t][r],function(e){return _.isString(e)?{id:e,size:"small"}:e})}}}(this),this.getAvailableMetrics=function(n){return function(o,i){var s;return n.setupLSFor(o,i),s=t.defer(),e.get(r.jobServer+"jobs/"+o+"/vertices/"+i+"/metrics").success(function(e){var t;return t=[],angular.forEach(e,function(e,r){var s;if(s=n.metrics[o][i].indexOf(e.id),s===-1&&(s=_.findIndex(n.metrics[o][i],{id:e.id})),s===-1)return t.push(e)}),s.resolve(t)}),s.promise}}(this),this.getAllAvailableMetrics=function(n){return function(n,o){var i;return i=t.defer(),e.get(r.jobServer+"jobs/"+n+"/vertices/"+o+"/metrics").success(function(e){return i.resolve(e)}),i.promise}}(this),this.getMetrics=function(n,o,i){var s,a;return s=t.defer(),a=i.join(","),e.get(r.jobServer+"jobs/"+n+"/vertices/"+o+"/met
 rics?get="+a).success(function(e){return function(t){var r,i;return i={},angular.forEach(t,function(e,t){return i[e.id]=parseInt(e.value)}),r={timestamp:Date.now(),values:i},e.saveValue(n,o,r),s.resolve(r)}}(this)),s.promise},this.setupLS(),this}]),angular.module("flinkApp").controller("OverviewController",["$scope","OverviewService","JobsService","$interval","flinkConfig",function(e,t,r,n,o){var i;return e.jobObserver=function(){return e.runningJobs=r.getJobs("running"),e.finishedJobs=r.getJobs("finished")},r.registerObserver(e.jobObserver),e.$on("$destroy",function(){return r.unRegisterObserver(e.jobObserver)}),e.jobObserver(),t.loadOverview().then(function(t){return e.overview=t}),i=n(function(){return t.loadOverview().then(function(t){return e.overview=t})},o["refresh-interval"]),e.$on("$destroy",function(){return n.cancel(i)})}]),angular.module("flinkApp").service("OverviewService",["$http","flinkConfig","$q",function(e,t,r){var n;return n={},this.loadOverview=function(){var o;
 return o=r.defer(),e.get(t.jobServer+"overview").success(function(e,t,r,i){return n=e,o.resolve(e)}),o.promise},this}]),angular.module("flinkApp").controller("JobSubmitController",["$scope","JobSubmitService","$interval","flinkConfig","$state","$location",function(e,t,r,n,o,i){var s;return e.yarn=i.absUrl().indexOf("/proxy/application_")!==-1,e.loadList=function(){return t.loadJarList().then(function(t){return e.address=t.address,e.noaccess=t.error,e.jars=t.files})},e.defaultState=function(){return e.plan=null,e.error=null,e.state={selected:null,parallelism:"",savepointPath:"",allowNonRestoredState:!1,"entry-class":"","program-args":"","plan-button":"Show Plan","submit-button":"Submit","action-time":0}},e.defaultState(),e.uploader={},e.loadList(),s=r(function(){return e.loadList()},n["refresh-interval"]),e.$on("$destroy",function(){return r.cancel(s)}),e.selectJar=function(t){return e.state.selected===t?e.defaultState():(e.defaultState(),e.state.selected=t)},e.deleteJar=function(r,n
 ){return e.state.selected===n&&e.defaultState(),angular.element(r.currentTarget).removeClass("fa-remove").addClass("fa-spin fa-spinner"),t.deleteJar(n).then(function(e){if(angular.element(r.currentTarget).removeClass("fa-spin fa-spinner").addClass("fa-remove"),null!=e.error)return alert(e.error)})},e.loadEntryClass=function(t){return e.state["entry-class"]=t},e.getPlan=function(){var r;if("Show Plan"===e.state["plan-button"])return r=(new Date).getTime(),e.state["action-time"]=r,e.state["submit-button"]="Submit",e.state["plan-button"]="Getting Plan",e.error=null,e.plan=null,t.getPlan(e.state.selected,{"entry-class":e.state["entry-class"],parallelism:e.state.parallelism,"program-args":e.state["program-args"]}).then(function(t){if(r===e.state["action-time"])return e.state["plan-button"]="Show Plan",e.error=t.error,e.plan=t.plan})},e.runJob=function(){var r;if("Submit"===e.state["submit-button"])return r=(new Date).getTime(),e.state["action-time"]=r,e.state["submit-button"]="Submitting
 ",e.state["plan-button"]="Show Plan",e.error=null,t.runJob(e.state.selected,{"entry-class":e.state["entry-class"],parallelism:e.state.parallelism,"program-args":e.state["program-args"],savepointPath:e.state.savepointPath,allowNonRestoredState:e.state.allowNonRestoredState}).then(function(t){if(r===e.state["action-time"]&&(e.state["submit-button"]="Submit",e.error=t.error,null!=t.jobid))return o.go("single-job.plan.subtasks",{jobid:t.jobid})})},e.nodeid=null,e.changeNode=function(t){return t!==e.nodeid?(e.nodeid=t,e.vertex=null,e.subtasks=null,e.accumulators=null,e.$broadcast("reload")):(e.nodeid=null,e.nodeUnfolded=!1,e.vertex=null,e.subtasks=null,e.accumulators=null)},e.clearFiles=function(){return e.uploader={}},e.uploadFiles=function(t){return e.uploader={},1===t.length?(e.uploader.file=t[0],e.uploader.upload=!0):e.uploader.error="Did ya forget to select a file?"},e.startUpload=function(){var t,r;return null!=e.uploader.file?(t=new FormData,t.append("jarfile",e.uploader.file),e.u
 ploader.upload=!1,e.uploader.success="Initializing upload...",r=new XMLHttpRequest,r.upload.onprogress=function(t){return e.uploader.success=null,e.uploader.progress=parseInt(100*t.loaded/t.total)},r.upload.onerror=function(t){return e.uploader.progress=null,e.uploader.error="An error occurred while uploading your file"},r.upload.onload=function(t){return e.uploader.progress=null,e.uploader.success="Saving..."},r.onreadystatechange=function(){var t;if(4===r.readyState)return t=JSON.parse(r.responseText),null!=t.error?(e.uploader.error=t.error,e.uploader.success=null):e.uploader.success="Uploaded!"},r.open("POST",n.jobServer+"jars/upload"),r.send(t)):console.log("Unexpected Error. This should not happen")}}]).filter("getJarSelectClass",function(){return function(e,t){return e===t?"fa-check-square":"fa-square-o"}}),angular.module("flinkApp").service("JobSubmitService",["$http","flinkConfig","$q",function(e,t,r){return this.loadJarList=function(){var n;return n=r.defer(),e.get(t.jobSer
 ver+"jars/").success(function(e,t,r,o){return n.resolve(e)}),n.promise},this.deleteJar=function(n){var o;return o=r.defer(),e["delete"](t.jobServer+"jars/"+encodeURIComponent(n)).success(function(e,t,r,n){return o.resolve(e)}),o.promise},this.getPlan=function(n,o){var i;return i=r.defer(),e.get(t.jobServer+"jars/"+encodeURIComponent(n)+"/plan",{params:o}).success(function(e,t,r,n){return i.resolve(e)}),i.promise},this.runJob=function(n,o){var i;return i=r.defer(),e.post(t.jobServer+"jars/"+encodeURIComponent(n)+"/run",{},{params:o}).success(function(e,t,r,n){return i.resolve(e)}),i.promise},this}]),angular.module("flinkApp").controller("AllTaskManagersController",["$scope","TaskManagersService","$interval","flinkConfig",function(e,t,r,n){var o;return t.loadManagers().then(function(t){return e.managers=t}),o=r(function(){return t.loadManagers().then(function(t){return e.managers=t})},n["refresh-interval"]),e.$on("$destroy",function(){return r.cancel(o)})}]).controller("SingleTaskMana
 gerController",["$scope","$stateParams","SingleTaskManagerService","$interval","flinkConfig",function(e,t,r,n,o){var i;return e.metrics={},r.loadMetrics(t.taskmanagerid).then(function(t){return e.metrics=t[0]}),i=n(function(){return r.loadMetrics(t.taskmanagerid).then(function(t){return e.metrics=t[0]})},o["refresh-interval"]),e.$on("$destroy",function(){return n.cancel(i)})}]).controller("SingleTaskManagerLogsController",["$scope","$stateParams","SingleTaskManagerService","$interval","flinkConfig",function(e,t,r,n,o){return e.log={},e.taskmanagerid=t.taskmanagerid,r.loadLogs(t.taskmanagerid).then(function(t){return e.log=t}),e.reloadData=function(){return r.loadLogs(t.taskmanagerid).then(function(t){return e.log=t})}}]).controller("SingleTaskManagerStdoutController",["$scope","$stateParams","SingleTaskManagerService","$interval","flinkConfig",function(e,t,r,n,o){return e.stdout={},e.taskmanagerid=t.taskmanagerid,r.loadStdout(t.taskmanagerid).then(function(t){return e.stdout=t}),e.r
 eloadData=function(){return r.loadStdout(t.taskmanagerid).then(function(t){return e.stdout=t})}}]),angular.module("flinkApp").service("TaskManagersService",["$http","flinkConfig","$q",function(e,t,r){return this.loadManagers=function(){var n;return n=r.defer(),e.get(t.jobServer+"taskmanagers").success(function(e,t,r,o){return n.resolve(e.taskmanagers)}),n.promise},this}]).service("SingleTaskManagerService",["$http","flinkConfig","$q",function(e,t,r){return this.loadMetrics=function(n){var o;return o=r.defer(),e.get(t.jobServer+"taskmanagers/"+n).success(function(e,t,r,n){return o.resolve(e.taskmanagers)}),o.promise},this.loadLogs=function(n){var o;return o=r.defer(),e.get(t.jobServer+"taskmanagers/"+n+"/log").success(function(e,t,r,n){return o.resolve(e)}),o.promise},this.loadStdout=function(n){var o;return o=r.defer(),e.get(t.jobServer+"taskmanagers/"+n+"/stdout").success(function(e,t,r,n){return o.resolve(e)}),o.promise},this}]);
\ No newline at end of file
+angular.module("flinkApp",["ui.router","angularMoment","dndLists"]).run(["$rootScope",function(e){return e.sidebarVisible=!1,e.showSidebar=function(){return e.sidebarVisible=!e.sidebarVisible,e.sidebarClass="force-show"}}]).value("flinkConfig",{jobServer:"","refresh-interval":1e4}).value("watermarksConfig",{noWatermark:-0x8000000000000000}).run(["JobsService","MainService","flinkConfig","$interval",function(e,t,r,n){return t.loadConfig().then(function(t){return angular.extend(r,t),e.listJobs(),n(function(){return e.listJobs()},r["refresh-interval"])})}]).config(["$uiViewScrollProvider",function(e){return e.useAnchorScroll()}]).run(["$rootScope","$state",function(e,t){return e.$on("$stateChangeStart",function(e,r,n,o){if(r.redirectTo)return e.preventDefault(),t.go(r.redirectTo,n)})}]).config(["$stateProvider","$urlRouterProvider",function(e,t){return e.state("overview",{url:"/overview",views:{main:{templateUrl:"partials/overview.html",controller:"OverviewController"}}}).state("runnin
 g-jobs",{url:"/running-jobs",views:{main:{templateUrl:"partials/jobs/running-jobs.html",controller:"RunningJobsController"}}}).state("completed-jobs",{url:"/completed-jobs",views:{main:{templateUrl:"partials/jobs/completed-jobs.html",controller:"CompletedJobsController"}}}).state("single-job",{url:"/jobs/{jobid}","abstract":!0,views:{main:{templateUrl:"partials/jobs/job.html",controller:"SingleJobController"}}}).state("single-job.plan",{url:"",redirectTo:"single-job.plan.subtasks",views:{details:{templateUrl:"partials/jobs/job.plan.html",controller:"JobPlanController"}}}).state("single-job.plan.subtasks",{url:"",views:{"node-details":{templateUrl:"partials/jobs/job.plan.node-list.subtasks.html",controller:"JobPlanSubtasksController"}}}).state("single-job.plan.metrics",{url:"/metrics",views:{"node-details":{templateUrl:"partials/jobs/job.plan.node-list.metrics.html",controller:"JobPlanMetricsController"}}}).state("single-job.plan.watermarks",{url:"/watermarks",views:{"node-details":{
 templateUrl:"partials/jobs/job.plan.node-list.watermarks.html"}}}).state("single-job.plan.taskmanagers",{url:"/taskmanagers",views:{"node-details":{templateUrl:"partials/jobs/job.plan.node-list.taskmanagers.html",controller:"JobPlanTaskManagersController"}}}).state("single-job.plan.accumulators",{url:"/accumulators",views:{"node-details":{templateUrl:"partials/jobs/job.plan.node-list.accumulators.html",controller:"JobPlanAccumulatorsController"}}}).state("single-job.plan.checkpoints",{url:"/checkpoints",redirectTo:"single-job.plan.checkpoints.overview",views:{"node-details":{templateUrl:"partials/jobs/job.plan.node-list.checkpoints.html",controller:"JobPlanCheckpointsController"}}}).state("single-job.plan.checkpoints.overview",{url:"/overview",views:{"checkpoints-view":{templateUrl:"partials/jobs/job.plan.node.checkpoints.overview.html",controller:"JobPlanCheckpointsController"}}}).state("single-job.plan.checkpoints.summary",{url:"/summary",views:{"checkpoints-view":{templateUrl:"pa
 rtials/jobs/job.plan.node.checkpoints.summary.html",controller:"JobPlanCheckpointsController"}}}).state("single-job.plan.checkpoints.history",{url:"/history",views:{"checkpoints-view":{templateUrl:"partials/jobs/job.plan.node.checkpoints.history.html",controller:"JobPlanCheckpointsController"}}}).state("single-job.plan.checkpoints.config",{url:"/config",views:{"checkpoints-view":{templateUrl:"partials/jobs/job.plan.node.checkpoints.config.html",controller:"JobPlanCheckpointsController"}}}).state("single-job.plan.checkpoints.details",{url:"/details/{checkpointId}",views:{"checkpoints-view":{templateUrl:"partials/jobs/job.plan.node.checkpoints.details.html",controller:"JobPlanCheckpointDetailsController"}}}).state("single-job.plan.backpressure",{url:"/backpressure",views:{"node-details":{templateUrl:"partials/jobs/job.plan.node-list.backpressure.html",controller:"JobPlanBackPressureController"}}}).state("single-job.timeline",{url:"/timeline",views:{details:{templateUrl:"partials/jobs/
 job.timeline.html"}}}).state("single-job.timeline.vertex",{url:"/{vertexId}",views:{vertex:{templateUrl:"partials/jobs/job.timeline.vertex.html",controller:"JobTimelineVertexController"}}}).state("single-job.exceptions",{url:"/exceptions",views:{details:{templateUrl:"partials/jobs/job.exceptions.html",controller:"JobExceptionsController"}}}).state("single-job.config",{url:"/config",views:{details:{templateUrl:"partials/jobs/job.config.html"}}}).state("all-manager",{url:"/taskmanagers",views:{main:{templateUrl:"partials/taskmanager/index.html",controller:"AllTaskManagersController"}}}).state("single-manager",{url:"/taskmanager/{taskmanagerid}","abstract":!0,views:{main:{templateUrl:"partials/taskmanager/taskmanager.html",controller:"SingleTaskManagerController"}}}).state("single-manager.metrics",{url:"/metrics",views:{details:{templateUrl:"partials/taskmanager/taskmanager.metrics.html"}}}).state("single-manager.stdout",{url:"/stdout",views:{details:{templateUrl:"partials/taskmanager/
 taskmanager.stdout.html",controller:"SingleTaskManagerStdoutController"}}}).state("single-manager.log",{url:"/log",views:{details:{templateUrl:"partials/taskmanager/taskmanager.log.html",controller:"SingleTaskManagerLogsController"}}}).state("jobmanager",{url:"/jobmanager",views:{main:{templateUrl:"partials/jobmanager/index.html"}}}).state("jobmanager.config",{url:"/config",views:{details:{templateUrl:"partials/jobmanager/config.html",controller:"JobManagerConfigController"}}}).state("jobmanager.stdout",{url:"/stdout",views:{details:{templateUrl:"partials/jobmanager/stdout.html",controller:"JobManagerStdoutController"}}}).state("jobmanager.log",{url:"/log",views:{details:{templateUrl:"partials/jobmanager/log.html",controller:"JobManagerLogsController"}}}).state("submit",{url:"/submit",views:{main:{templateUrl:"partials/submit.html",controller:"JobSubmitController"}}}),t.otherwise("/overview")}]),angular.module("flinkApp").directive("bsLabel",["JobsService",function(e){return{transcl
 ude:!0,replace:!0,scope:{getLabelClass:"&",status:"@"},template:"<span title='{{status}}' ng-class='getLabelClass()'><ng-transclude></ng-transclude></span>",link:function(t,r,n){return t.getLabelClass=function(){return"label label-"+e.translateLabelState(n.status)}}}}]).directive("bpLabel",["JobsService",function(e){return{transclude:!0,replace:!0,scope:{getBackPressureLabelClass:"&",status:"@"},template:"<span title='{{status}}' ng-class='getBackPressureLabelClass()'><ng-transclude></ng-transclude></span>",link:function(t,r,n){return t.getBackPressureLabelClass=function(){return"label label-"+e.translateBackPressureLabelState(n.status)}}}}]).directive("indicatorPrimary",["JobsService",function(e){return{replace:!0,scope:{getLabelClass:"&",status:"@"},template:"<i title='{{status}}' ng-class='getLabelClass()' />",link:function(t,r,n){return t.getLabelClass=function(){return"fa fa-circle indicator indicator-"+e.translateLabelState(n.status)}}}}]).directive("tableProperty",function(){
 return{replace:!0,scope:{value:"="},template:"<td title=\"{{value || 'None'}}\">{{value || 'None'}}</td>"}}),angular.module("flinkApp").filter("amDurationFormatExtended",["angularMomentConfig",function(e){var t;return t=function(e,t,r){return"undefined"==typeof e||null===e?"":moment.duration(e,t).format(r,{trim:!1})},t.$stateful=e.statefulFilters,t}]).filter("humanizeDuration",function(){return function(e,t){var r,n,o,a,i,s;return"undefined"==typeof e||null===e?"":(a=e%1e3,s=Math.floor(e/1e3),i=s%60,s=Math.floor(s/60),o=s%60,s=Math.floor(s/60),n=s%24,s=Math.floor(s/24),r=s,0===r?0===n?0===o?0===i?a+"ms":i+"s ":o+"m "+i+"s":t?n+"h "+o+"m":n+"h "+o+"m "+i+"s":t?r+"d "+n+"h":r+"d "+n+"h "+o+"m "+i+"s")}}).filter("limit",function(){return function(e){return e.length>73&&(e=e.substring(0,35)+"..."+e.substring(e.length-35,e.length)),e}}).filter("humanizeText",function(){return function(e){return e?e.replace(/&gt;/g,">").replace(/<br\/>/g,""):""}}).filter("humanizeBytes",function(){return 
 function(e){var t,r;return r=["B","KB","MB","GB","TB","PB","EB"],t=function(e,n){var o;return o=Math.pow(1024,n),e<o?(e/o).toFixed(2)+" "+r[n]:e<1e3*o?(e/o).toPrecision(3)+" "+r[n]:t(e,n+1)},"undefined"==typeof e||null===e?"":e<1e3?e+" B":t(e,1)}}).filter("toLocaleString",function(){return function(e){return e.toLocaleString()}}).filter("toUpperCase",function(){return function(e){return e.toUpperCase()}}).filter("percentage",function(){return function(e){return(100*e).toFixed(0)+"%"}}).filter("humanizeWatermark",["watermarksConfig",function(e){return function(t){return isNaN(t)||t<=e.noWatermark?"No Watermark":t}}]).filter("increment",function(){return function(e){return parseInt(e)+1}}),angular.module("flinkApp").service("MainService",["$http","flinkConfig","$q",function(e,t,r){return this.loadConfig=function(){var n;return n=r.defer(),e.get(t.jobServer+"config").success(function(e,t,r,o){return n.resolve(e)}),n.promise},this}]),angular.module("flinkApp").controller("JobManagerConf
 igController",["$scope","JobManagerConfigService",function(e,t){return t.loadConfig().then(function(t){return null==e.jobmanager&&(e.jobmanager={}),e.jobmanager.config=t})}]).controller("JobManagerLogsController",["$scope","JobManagerLogsService",function(e,t){return t.loadLogs().then(function(t){return null==e.jobmanager&&(e.jobmanager={}),e.jobmanager.log=t}),e.reloadData=function(){return t.loadLogs().then(function(t){return e.jobmanager.log=t})}}]).controller("JobManagerStdoutController",["$scope","JobManagerStdoutService",function(e,t){return t.loadStdout().then(function(t){return null==e.jobmanager&&(e.jobmanager={}),e.jobmanager.stdout=t}),e.reloadData=function(){return t.loadStdout().then(function(t){return e.jobmanager.stdout=t})}}]),angular.module("flinkApp").service("JobManagerConfigService",["$http","flinkConfig","$q",function(e,t,r){var n;return n={},this.loadConfig=function(){var n;return n=r.defer(),e.get(t.jobServer+"jobmanager/config").success(function(e,t,r,o){retu
 rn o=e,n.resolve(e)}),n.promise},this}]).service("JobManagerLogsService",["$http","flinkConfig","$q",function(e,t,r){var n;return n={},this.loadLogs=function(){var o;return o=r.defer(),e.get(t.jobServer+"jobmanager/log").success(function(e,t,r,a){return n=e,o.resolve(e)}),o.promise},this}]).service("JobManagerStdoutService",["$http","flinkConfig","$q",function(e,t,r){var n;return n={},this.loadStdout=function(){var o;return o=r.defer(),e.get(t.jobServer+"jobmanager/stdout").success(function(e,t,r,a){return n=e,o.resolve(e)}),o.promise},this}]),angular.module("flinkApp").controller("RunningJobsController",["$scope","$state","$stateParams","JobsService",function(e,t,r,n){return e.jobObserver=function(){return e.jobs=n.getJobs("running")},n.registerObserver(e.jobObserver),e.$on("$destroy",function(){return n.unRegisterObserver(e.jobObserver)}),e.jobObserver()}]).controller("CompletedJobsController",["$scope","$state","$stateParams","JobsService",function(e,t,r,n){return e.jobObserver=f
 unction(){return e.jobs=n.getJobs("finished")},n.registerObserver(e.jobObserver),e.$on("$destroy",function(){return n.unRegisterObserver(e.jobObserver)}),e.jobObserver()}]).controller("SingleJobController",["$scope","$state","$stateParams","JobsService","MetricsService","$rootScope","flinkConfig","$interval","$q","watermarksConfig",function(e,t,r,n,o,a,i,s,l,u){var c,d;return e.jobid=r.jobid,e.job=null,e.plan=null,e.watermarks={},e.vertices=null,e.backPressureOperatorStats={},d=s(function(){return n.loadJob(r.jobid).then(function(t){return e.job=t,e.$broadcast("reload")})},i["refresh-interval"]),e.$on("$destroy",function(){return e.job=null,e.plan=null,e.watermarks={},e.vertices=null,e.backPressureOperatorStats=null,s.cancel(d)}),e.cancelJob=function(e){return angular.element(e.currentTarget).removeClass("btn").removeClass("btn-default").html("Cancelling..."),n.cancelJob(r.jobid).then(function(e){return{}})},e.stopJob=function(e){return angular.element(e.currentTarget).removeClass("
 btn").removeClass("btn-default").html("Stopping..."),n.stopJob(r.jobid).then(function(e){return{}})},n.loadJob(r.jobid).then(function(t){return e.job=t,e.vertices=t.vertices,e.plan=t.plan,o.setupMetrics(r.jobid,t.vertices)}),c=function(t){var r,n,a,i;return a=function(t){return function(t){var r,n,a,i;return r=l.defer(),a=e.job.jid,i=function(){var e,r,o;for(o=[],n=e=0,r=t.parallelism-1;0<=r?e<=r:e>=r;n=0<=r?++e:--e)o.push(n+".currentLowWatermark");return o}(),o.getMetrics(a,t.id,i).then(function(e){var t,n,o,a,i,s,l;o=NaN,l={},a=e.values;for(t in a)s=a[t],i=t.replace(".currentLowWatermark",""),l[i]=s,(isNaN(o)||s<o)&&(o=s);return n=!isNaN(o)&&o>u.noWatermark?o:NaN,r.resolve({lowWatermark:n,watermarks:l})}),r.promise}}(this),r=l.defer(),i={},n=t.length,angular.forEach(t,function(e){return function(e,t){var o;return o=e.id,a(e).then(function(e){if(i[o]=e,t>=n-1)return r.resolve(i)})}}(this)),r.promise},e.hasWatermark=function(t){return e.watermarks[t]&&!isNaN(e.watermarks[t].lowWater
 mark)},e.$watch("plan",function(t){if(t)return c(t.nodes).then(function(t){return e.watermarks=t})}),e.$on("reload",function(){if(e.plan)return c(e.plan.nodes).then(function(t){return e.watermarks=t})})}]).controller("JobPlanController",["$scope","$state","$stateParams","$window","JobsService",function(e,t,r,n,o){return e.nodeid=null,e.nodeUnfolded=!1,e.stateList=o.stateList(),e.changeNode=function(t){return t!==e.nodeid?(e.nodeid=t,e.vertex=null,e.subtasks=null,e.accumulators=null,e.operatorCheckpointStats=null,e.$broadcast("reload"),e.$broadcast("node:change",e.nodeid)):(e.nodeid=null,e.nodeUnfolded=!1,e.vertex=null,e.subtasks=null,e.accumulators=null,e.operatorCheckpointStats=null)},e.deactivateNode=function(){return e.nodeid=null,e.nodeUnfolded=!1,e.vertex=null,e.subtasks=null,e.accumulators=null,e.operatorCheckpointStats=null},e.toggleFold=function(){return e.nodeUnfolded=!e.nodeUnfolded}}]).controller("JobPlanSubtasksController",["$scope","JobsService",function(e,t){var r;retu
 rn r=function(){return t.getSubtasks(e.nodeid).then(function(t){return e.subtasks=t})},!e.nodeid||e.vertex&&e.vertex.st||r(),e.$on("reload",function(t){if(e.nodeid)return r()})}]).controller("JobPlanTaskManagersController",["$scope","JobsService",function(e,t){var r;return r=function(){return t.getTaskManagers(e.nodeid).then(function(t){return e.taskmanagers=t})},!e.nodeid||e.vertex&&e.vertex.st||r(),e.$on("reload",function(t){if(e.nodeid)return r()})}]).controller("JobPlanAccumulatorsController",["$scope","JobsService",function(e,t){var r;return r=function(){return t.getAccumulators(e.nodeid).then(function(t){return e.accumulators=t.main,e.subtaskAccumulators=t.subtasks})},!e.nodeid||e.vertex&&e.vertex.accumulators||r(),e.$on("reload",function(t){if(e.nodeid)return r()})}]).controller("JobPlanCheckpointsController",["$scope","$state","$stateParams","JobsService",function(e,t,r,n){var o;return e.checkpointDetails={},e.checkpointDetails.id=-1,n.getCheckpointConfig().then(function(t){
 return e.checkpointConfig=t}),o=function(){return n.getCheckpointStats().then(function(t){if(null!==t)return e.checkpointStats=t})},o(),e.$on("reload",function(e){return o()})}]).controller("JobPlanCheckpointDetailsController",["$scope","$state","$stateParams","JobsService",function(e,t,r,n){var o,a;return e.subtaskDetails={},e.checkpointDetails.id=r.checkpointId,o=function(t){return n.getCheckpointDetails(t).then(function(t){return null!==t?e.checkpoint=t:e.unknown_checkpoint=!0})},a=function(t,r){return n.getCheckpointSubtaskDetails(t,r).then(function(t){if(null!==t)return e.subtaskDetails[r]=t})},o(r.checkpointId),e.nodeid&&a(r.checkpointId,e.nodeid),e.$on("reload",function(t){if(o(r.checkpointId),e.nodeid)return a(r.checkpointId,e.nodeid)}),e.$on("$destroy",function(){return e.checkpointDetails.id=-1})}]).controller("JobPlanBackPressureController",["$scope","JobsService",function(e,t){var r;return r=function(){if(e.now=Date.now(),e.nodeid)return t.getOperatorBackPressure(e.nodei
 d).then(function(t){return e.backPressureOperatorStats[e.nodeid]=t})},r(),e.$on("reload",function(e){return r()})}]).controller("JobTimelineVertexController",["$scope","$state","$stateParams","JobsService",function(e,t,r,n){var o;return o=function(){return n.getVertex(r.vertexId).then(function(t){return e.vertex=t})},o(),e.$on("reload",function(e){return o()})}]).controller("JobExceptionsController",["$scope","$state","$stateParams","JobsService",function(e,t,r,n){return n.loadExceptions().then(function(t){return e.exceptions=t})}]).controller("JobPropertiesController",["$scope","JobsService",function(e,t){return e.changeNode=function(r){return r!==e.nodeid?(e.nodeid=r,t.getNode(r).then(function(t){return e.node=t})):(e.nodeid=null,e.node=null)}}]).controller("JobPlanMetricsController",["$scope","JobsService","MetricsService",function(e,t,r){var n;if(e.dragging=!1,e.window=r.getWindow(),e.availableMetrics=null,e.$on("$destroy",function(){return r.unRegisterObserver()}),n=function(){
 return t.getVertex(e.nodeid).then(function(t){return e.vertex=t}),r.getAvailableMetrics(e.jobid,e.nodeid).then(function(t){return e.availableMetrics=t,e.metrics=r.getMetricsSetup(e.jobid,e.nodeid).names,r.registerObserver(e.jobid,e.nodeid,function(t){return e.$broadcast("metrics:data:update",t.timestamp,t.values)})})},e.dropped=function(t,o,a,i,s){return r.orderMetrics(e.jobid,e.nodeid,a,o),e.$broadcast("metrics:refresh",a),n(),!1},e.dragStart=function(){return e.dragging=!0},e.dragEnd=function(){return e.dragging=!1},e.addMetric=function(t){return r.addMetric(e.jobid,e.nodeid,t.id),n()},e.removeMetric=function(t){return r.removeMetric(e.jobid,e.nodeid,t),n()},e.setMetricSize=function(t,o){return r.setMetricSize(e.jobid,e.nodeid,t,o),n()},e.getValues=function(t){return r.getValues(e.jobid,e.nodeid,t)},e.$on("node:change",function(t,r){if(!e.dragging)return n()}),e.nodeid)return n()}]),angular.module("flinkApp").directive("vertex",["$state",function(e){return{template:"<svg class='ti
 meline secondary' width='0' height='0'></svg>",scope:{data:"="},link:function(e,t,r){var n,o,a;a=t.children()[0],o=t.width(),angular.element(a).attr("width",o),(n=function(e){var t,r,n;return d3.select(a).selectAll("*").remove(),n=[],angular.forEach(e.subtasks,function(e,t){var r;return r=[{label:"Scheduled",color:"#666",borderColor:"#555",starting_time:e.timestamps.SCHEDULED,ending_time:e.timestamps.DEPLOYING,type:"regular"},{label:"Deploying",color:"#aaa",borderColor:"#555",starting_time:e.timestamps.DEPLOYING,ending_time:e.timestamps.RUNNING,type:"regular"}],e.timestamps.FINISHED>0&&r.push({label:"Running",color:"#ddd",borderColor:"#555",starting_time:e.timestamps.RUNNING,ending_time:e.timestamps.FINISHED,type:"regular"}),n.push({label:"("+e.subtask+") "+e.host,times:r})}),t=d3.timeline().stack().tickFormat({format:d3.time.format("%L"),tickSize:1}).prefix("single").labelFormat(function(e){return e}).margin({left:100,right:0,top:0,bottom:0}).itemHeight(30).relativeTime(),r=d3.sele
 ct(a).datum(n).call(t)})(e.data)}}}]).directive("timeline",["$state",function(e){return{template:"<svg class='timeline' width='0' height='0'></svg>",scope:{vertices:"=",jobid:"="},link:function(t,r,n){var o,a,i,s;i=r.children()[0],a=r.width(),angular.element(i).attr("width",a),s=function(e){return e.replace("&gt;",">")},o=function(r){var n,o,a;return d3.select(i).selectAll("*").remove(),a=[],angular.forEach(r,function(e){if(e["start-time"]>-1)return"scheduled"===e.type?a.push({times:[{label:s(e.name),color:"#cccccc",borderColor:"#555555",starting_time:e["start-time"],ending_time:e["end-time"],type:e.type}]}):a.push({times:[{label:s(e.name),color:"#d9f1f7",borderColor:"#62cdea",starting_time:e["start-time"],ending_time:e["end-time"],link:e.id,type:e.type}]})}),n=d3.timeline().stack().click(function(r,n,o){if(r.link)return e.go("single-job.timeline.vertex",{jobid:t.jobid,vertexId:r.link})}).tickFormat({format:d3.time.format("%L"),tickSize:1}).prefix("main").margin({left:0,right:0,top:
 0,bottom:0}).itemHeight(30).showBorderLine().showHourTimeline(),o=d3.select(i).datum(a).call(n)},t.$watch(n.vertices,function(e){if(e)return o(e)})}}}]).directive("split",function(){return{compile:function(e,t){return Split(e.children(),{sizes:[50,50],direction:"vertical"})}}}).directive("jobPlan",["$timeout",function(e){return{template:"<svg class='graph'><g /></svg> <svg class='tmp' width='1' height='1'><g /></svg> <div class='btn-group zoom-buttons'> <a class='btn btn-default zoom-in' ng-click='zoomIn()'><i class='fa fa-plus' /></a> <a class='btn btn-default zoom-out' ng-click='zoomOut()'><i class='fa fa-minus' /></a> </div>",scope:{plan:"=",watermarks:"=",setNode:"&"},link:function(e,t,r){var n,o,a,i,s,l,u,c,d,f,p,m,g,b,h,v,k,j,S,w,C,$,J,M,y;p=null,C=d3.behavior.zoom(),y=[],b=r.jobid,S=t.children()[0],j=t.children().children()[0],w=t.children()[1],l=d3.select(S),u=d3.select(j),c=d3.select(w),n=t.width(),angular.element(t.children()[0]).width(n),v=0,h=0,e.zoomIn=function(){var e,
 t,r;if(C.scale()<2.99)return e=C.translate(),t=e[0]*(C.scale()+.1/C.scale()),r=e[1]*(C.scale()+.1/C.scale()),C.scale(C.scale()+.1),C.translate([t,r]),u.attr("transform","translate("+t+","+r+") scale("+C.scale()+")"),v=C.scale(),h=C.translate()},e.zoomOut=function(){var e,t,r;if(C.scale()>.31)return C.scale(C.scale()-.1),e=C.translate(),t=e[0]*(C.scale()-.1/C.scale()),r=e[1]*(C.scale()-.1/C.scale()),C.translate([t,r]),u.attr("transform","translate("+t+","+r+") scale("+C.scale()+")"),v=C.scale(),h=C.translate()},a=function(e){var t;return t="",null==e.ship_strategy&&null==e.local_strategy||(t+="<div class='edge-label'>",null!=e.ship_strategy&&(t+=e.ship_strategy),void 0!==e.temp_mode&&(t+=" ("+e.temp_mode+")"),void 0!==e.local_strategy&&(t+=",<br>"+e.local_strategy),t+="</div>"),t},g=function(e){return"partialSolution"===e||"nextPartialSolution"===e||"workset"===e||"nextWorkset"===e||"solutionSet"===e||"solutionDelta"===e},m=function(e,t){return"mirror"===t?"node-mirror":g(t)?"node-it
 eration":"node-normal"},i=function(e,t,r,n){var o,a;return o="<div href='#/jobs/"+b+"/vertex/"+e.id+"' class='node-label "+m(e,t)+"'>",o+="mirror"===t?"<h3 class='node-name'>Mirror of "+e.operator+"</h3>":"<h3 class='node-name'>"+e.operator+"</h3>",""===e.description?o+="":(a=e.description,a=M(a),o+="<h4 class='step-name'>"+a+"</h4>"),null!=e.step_function?o+=f(e.id,r,n):(g(t)&&(o+="<h5>"+t+" Node</h5>"),""!==e.parallelism&&(o+="<h5>Parallelism: "+e.parallelism+"</h5>"),void 0!==e.lowWatermark&&(o+="<h5>Low Watermark: "+e.lowWatermark+"</h5>"),void 0!==e.operator&&e.operator_strategy&&(o+="<h5>Operation: "+M(e.operator_strategy)+"</h5>")),o+="</div>"},f=function(e,t,r){var n,o;return o="svg-"+e,n="<svg class='"+o+"' width="+t+" height="+r+"><g /></svg>"},M=function(e){var t;for("<"===e.charAt(0)&&(e=e.replace("<","&lt;"),e=e.replace(">","&gt;")),t="";e.length>30;)t=t+e.substring(0,30)+"<br>",e=e.substring(30,e.length);return t+=e},s=function(e,t,r,n,o,a){return null==n&&(n=!1),r.id=
 ==t.partial_solution?e.setNode(r.id,{label:i(r,"partialSolution",o,a),labelType:"html","class":m(r,"partialSolution")}):r.id===t.next_partial_solution?e.setNode(r.id,{label:i(r,"nextPartialSolution",o,a),labelType:"html","class":m(r,"nextPartialSolution")}):r.id===t.workset?e.setNode(r.id,{label:i(r,"workset",o,a),labelType:"html","class":m(r,"workset")}):r.id===t.next_workset?e.setNode(r.id,{label:i(r,"nextWorkset",o,a),labelType:"html","class":m(r,"nextWorkset")}):r.id===t.solution_set?e.setNode(r.id,{label:i(r,"solutionSet",o,a),labelType:"html","class":m(r,"solutionSet")}):r.id===t.solution_delta?e.setNode(r.id,{label:i(r,"solutionDelta",o,a),labelType:"html","class":m(r,"solutionDelta")}):e.setNode(r.id,{label:i(r,"",o,a),labelType:"html","class":m(r,"")})},o=function(e,t,r,n,o){return e.setEdge(o.id,r.id,{label:a(o),labelType:"html",arrowhead:"normal"})},k=function(e,t){var r,n,a,i,l,u,d,f,p,m,g,b,h,v;for(n=[],null!=t.nodes?v=t.nodes:(v=t.step_function,a=!0),i=0,u=v.length;i<u
 ;i++)if(r=v[i],p=0,f=0,r.step_function&&(h=new dagreD3.graphlib.Graph({multigraph:!0,compound:!0}).setGraph({nodesep:20,edgesep:0,ranksep:20,rankdir:"LR",marginx:10,marginy:10}),y[r.id]=h,k(h,r),g=new dagreD3.render,c.select("g").call(g,h),p=h.graph().width,f=h.graph().height,angular.element(w).empty()),s(e,t,r,a,p,f),n.push(r.id),null!=r.inputs)for(b=r.inputs,l=0,d=b.length;l<d;l++)m=b[l],o(e,t,r,n,m);return e},J=function(e,t){var r,n,o;for(n in e.nodes){if(r=e.nodes[n],r.id===t)return r;if(null!=r.step_function)for(o in r.step_function)if(r.step_function[o].id===t)return r.step_function[o]}},$=function(e,t){var r,n,o,a;if(!_.isEmpty(t))for(a=e.nodes,r=0,n=a.length;r<n;r++)o=a[r],t[o.id]&&!isNaN(t[o.id].lowWatermark)&&(o.lowWatermark=t[o.id].lowWatermark);return e},h=0,v=0,d=function(){var t,r,n,o,a,i;if(e.plan){p=new dagreD3.graphlib.Graph({multigraph:!0,compound:!0}).setGraph({nodesep:70,edgesep:0,ranksep:50,rankdir:"LR",marginx:40,marginy:40}),k(p,$(e.plan,e.watermarks)),u.selec
 tAll("*").remove(),u.attr("transform","scale(1)"),n=new dagreD3.render,u.call(n,p);for(t in y)o=y[t],l.select("svg.svg-"+t+" g").call(n,o);return r=.5,a=Math.floor((angular.element(S).width()-p.graph().width*r)/2),i=Math.floor((angular.element(S).height()-p.graph().height*r)/2),0!==v&&0!==h?(C.scale(v).translate(h),u.attr("transform","translate("+h+") scale("+v+")")):(C.scale(r).translate([a,i]),u.attr("transform","translate("+a+", "+i+") scale("+C.scale()+")")),C.on("zoom",function(){var e;return e=d3.event,v=e.scale,h=e.translate,u.attr("transform","translate("+h+") scale("+v+")")}),C(l),u.selectAll(".node").on("click",function(t){return e.setNode({nodeid:t})})}},e.$watch(r.plan,function(e){if(e)return d()}),e.$watch(r.watermarks,function(t){if(t&&e.plan)return d()})}}}]),angular.module("flinkApp").service("JobsService",["$http","flinkConfig","$log","amMoment","$q","$timeout",function(e,t,r,n,o,a){var i,s,l,u,c,d;return i=null,s=null,l={},c={running:[],finished:[],cancelled:[],fai
 led:[]},u=[],d=function(){return angular.forEach(u,function(e){return e()})},this.registerObserver=function(e){return u.push(e)},this.unRegisterObserver=function(e){var t;return t=u.indexOf(e),u.splice(t,1)},this.stateList=function(){return["SCHEDULED","DEPLOYING","RUNNING","FINISHED","FAILED","CANCELING","CANCELED"]},this.translateLabelState=function(e){switch(e.toLowerCase()){case"finished":return"success";case"failed":return"danger";case"scheduled":return"default";case"deploying":return"info";case"running":return"primary";case"canceling":return"warning";case"pending":return"info";case"total":return"black";default:return"default"}},this.setEndTimes=function(e){return angular.forEach(e,function(e,t){if(!(e["end-time"]>-1))return e["end-time"]=e["start-time"]+e.duration})},this.processVertices=function(e){return angular.forEach(e.vertices,function(e,t){return e.type="regular"}),e.vertices.unshift({name:"Scheduled","start-time":e.timestamps.CREATED,"end-time":e.timestamps.CREATED+1,t
 ype:"scheduled"})},this.listJobs=function(){var r;return r=o.defer(),e.get(t.jobServer+"joboverview").success(function(e){return function(t,n,o,a){return angular.forEach(t,function(t,r){switch(r){case"running":return c.running=e.setEndTimes(t);case"finished":return c.finished=e.setEndTimes(t);case"cancelled":return c.cancelled=e.setEndTimes(t);case"failed":return c.failed=e.setEndTimes(t)}}),r.resolve(c),d()}}(this)),r.promise},this.getJobs=function(e){return c[e]},this.getAllJobs=function(){return c},this.loadJob=function(r){return i=null,l.job=o.defer(),e.get(t.jobServer+"jobs/"+r).success(function(n){return function(o,a,s,u){return n.setEndTimes(o.vertices),n.processVertices(o),e.get(t.jobServer+"jobs/"+r+"/config").success(function(e){return o=angular.extend(o,e),i=o,l.job.resolve(i)})}}(this)),l.job.promise},this.getNode=function(e){var t,r;return r=function(e,t){var n,o,a,i;for(n=0,o=t.length;n<o;n++){if(a=t[n],a.id===e)return a;if(a.step_function&&(i=r(e,a.step_function)),i)r
 eturn i}return null},t=o.defer(),l.job.promise.then(function(n){return function(o){var a;return a=r(e,i.plan.nodes),a.vertex=n.seekVertex(e),t.resolve(a)}}(this)),t.promise},this.seekVertex=function(e){var t,r,n,o;for(n=i.vertices,t=0,r=n.length;t<r;t++)if(o=n[t],o.id===e)return o;return null},this.getVertex=function(r){var n;return n=o.defer(),l.job.promise.then(function(o){return function(a){var s;return s=o.seekVertex(r),e.get(t.jobServer+"jobs/"+i.jid+"/vertices/"+r+"/subtasktimes").success(function(e){return s.subtasks=e.subtasks,n.resolve(s)})}}(this)),n.promise},this.getSubtasks=function(r){var n;return n=o.defer(),l.job.promise.then(function(o){return function(o){return e.get(t.jobServer+"jobs/"+i.jid+"/vertices/"+r).success(function(e){var t;return t=e.subtasks,n.resolve(t)})}}(this)),n.promise},this.getTaskManagers=function(r){var n;return n=o.defer(),l.job.promise.then(function(o){return function(o){return e.get(t.jobServer+"jobs/"+i.jid+"/vertices/"+r+"/taskmanagers").su
 ccess(function(e){var t;return t=e.taskmanagers,n.resolve(t)})}}(this)),n.promise},this.getAccumulators=function(r){var n;return n=o.defer(),l.job.promise.then(function(o){return function(o){return console.log(i.jid),e.get(t.jobServer+"jobs/"+i.jid+"/vertices/"+r+"/accumulators").success(function(o){var a;return a=o["user-accumulators"],e.get(t.jobServer+"jobs/"+i.jid+"/vertices/"+r+"/subtasks/accumulators").success(function(e){var t;return t=e.subtasks,n.resolve({main:a,subtasks:t})})})}}(this)),n.promise},this.getCheckpointConfig=function(){var r;return r=o.defer(),l.job.promise.then(function(n){return function(n){return e.get(t.jobServer+"jobs/"+i.jid+"/checkpoints/config").success(function(e){return angular.equals({},e)?r.resolve(null):r.resolve(e)})}}(this)),r.promise},this.getCheckpointStats=function(){var r;return r=o.defer(),l.job.promise.then(function(n){return function(n){return e.get(t.jobServer+"jobs/"+i.jid+"/checkpoints").success(function(e,t,n,o){return angular.equals
 ({},e)?r.resolve(null):r.resolve(e)})}}(this)),r.promise},this.getCheckpointDetails=function(r){var n;return n=o.defer(),l.job.promise.then(function(o){return function(o){return e.get(t.jobServer+"jobs/"+i.jid+"/checkpoints/details/"+r).success(function(e){return angular.equals({},e)?n.resolve(null):n.resolve(e)})}}(this)),n.promise},this.getCheckpointSubtaskDetails=function(r,n){var a;return a=o.defer(),l.job.promise.then(function(o){return function(o){return e.get(t.jobServer+"jobs/"+i.jid+"/checkpoints/details/"+r+"/subtasks/"+n).success(function(e){return angular.equals({},e)?a.resolve(null):a.resolve(e)})}}(this)),a.promise},this.getOperatorBackPressure=function(r){var n;return n=o.defer(),e.get(t.jobServer+"jobs/"+i.jid+"/vertices/"+r+"/backpressure").success(function(e){return function(e){return n.resolve(e)}}(this)),n.promise},this.translateBackPressureLabelState=function(e){switch(e.toLowerCase()){case"in-progress":return"danger";case"ok":return"success";case"low":return"wa
 rning";case"high":return"danger";default:return"default"}},this.loadExceptions=function(){var r;return r=o.defer(),l.job.promise.then(function(n){return function(n){return e.get(t.jobServer+"jobs/"+i.jid+"/exceptions").success(function(e){return i.exceptions=e,r.resolve(e)})}}(this)),r.promise},this.cancelJob=function(r){return e.get(t.jobServer+"jobs/"+r+"/yarn-cancel")},this.stopJob=function(t){return e.get("jobs/"+t+"/yarn-stop")},this}]),angular.module("flinkApp").directive("metricsGraph",function(){return{template:'<div class="panel panel-default panel-metric"> <div class="panel-heading"> <span class="metric-title">{{metric.id}}</span> <div class="buttons"> <div class="btn-group"> <button type="button" ng-class="[btnClasses, {active: metric.size != \'big\'}]" ng-click="setSize(\'small\')">Small</button> <button type="button" ng-class="[btnClasses, {active: metric.size == \'big\'}]" ng-click="setSize(\'big\')">Big</button> </div> <a title="Remove" class="btn btn-default btn-xs r
 emove" ng-click="removeMetric()"><i class="fa fa-close" /></a> </div> </div> <div class="panel-body"> <svg /> </div> </div>',
+replace:!0,scope:{metric:"=",window:"=",removeMetric:"&",setMetricSize:"=",getValues:"&"},link:function(e,t,r){return e.btnClasses=["btn","btn-default","btn-xs"],e.value=null,e.data=[{values:e.getValues()}],e.options={x:function(e,t){return e.x},y:function(e,t){return e.y},xTickFormat:function(e){return d3.time.format("%H:%M:%S")(new Date(e))},yTickFormat:function(e){var t,r,n,o;for(r=!1,n=0,o=1,t=Math.abs(e);!r&&n<50;)Math.pow(10,n)<=t&&t<Math.pow(10,n+o)?r=!0:n+=o;return r&&n>6?e/Math.pow(10,n)+"E"+n:""+e}},e.showChart=function(){return d3.select(t.find("svg")[0]).datum(e.data).transition().duration(250).call(e.chart)},e.chart=nv.models.lineChart().options(e.options).showLegend(!1).margin({top:15,left:60,bottom:30,right:30}),e.chart.yAxis.showMaxMin(!1),e.chart.tooltip.hideDelay(0),e.chart.tooltip.contentGenerator(function(e){return"<p>"+d3.time.format("%H:%M:%S")(new Date(e.point.x))+" | "+e.point.y+"</p>"}),nv.utils.windowResize(e.chart.update),e.setSize=function(t){return e.set
 MetricSize(e.metric,t)},e.showChart(),e.$on("metrics:data:update",function(t,r,n){return e.value=parseFloat(n[e.metric.id]),e.data[0].values.push({x:r,y:e.value}),e.data[0].values.length>e.window&&e.data[0].values.shift(),e.showChart(),e.chart.clearHighlights(),e.chart.tooltip.hidden(!0)}),t.find(".metric-title").qtip({content:{text:e.metric.id},position:{my:"bottom left",at:"top left"},style:{classes:"qtip-light qtip-timeline-bar"}})}}}),angular.module("flinkApp").service("MetricsService",["$http","$q","flinkConfig","$interval",function(e,t,r,n){return this.metrics={},this.values={},this.watched={},this.observer={jobid:null,nodeid:null,callback:null},this.refresh=n(function(e){return function(){return angular.forEach(e.metrics,function(t,r){return angular.forEach(t,function(t,n){var o;if(o=[],angular.forEach(t,function(e,t){return o.push(e.id)}),o.length>0)return e.getMetrics(r,n,o).then(function(t){if(r===e.observer.jobid&&n===e.observer.nodeid&&e.observer.callback)return e.observ
 er.callback(t)})})})}}(this),r["refresh-interval"]),this.registerObserver=function(e,t,r){return this.observer.jobid=e,this.observer.nodeid=t,this.observer.callback=r},this.unRegisterObserver=function(){return this.observer={jobid:null,nodeid:null,callback:null}},this.setupMetrics=function(e,t){return this.setupLS(),this.watched[e]=[],angular.forEach(t,function(t){return function(r,n){if(r.id)return t.watched[e].push(r.id)}}(this))},this.getWindow=function(){return 100},this.setupLS=function(){return null==sessionStorage.flinkMetrics&&this.saveSetup(),this.metrics=JSON.parse(sessionStorage.flinkMetrics)},this.saveSetup=function(){return sessionStorage.flinkMetrics=JSON.stringify(this.metrics)},this.saveValue=function(e,t,r){if(null==this.values[e]&&(this.values[e]={}),null==this.values[e][t]&&(this.values[e][t]=[]),this.values[e][t].push(r),this.values[e][t].length>this.getWindow())return this.values[e][t].shift()},this.getValues=function(e,t,r){var n;return null==this.values[e]?[]:
 null==this.values[e][t]?[]:(n=[],angular.forEach(this.values[e][t],function(e){return function(e,t){if(null!=e.values[r])return n.push({x:e.timestamp,y:e.values[r]})}}(this)),n)},this.setupLSFor=function(e,t){if(null==this.metrics[e]&&(this.metrics[e]={}),null==this.metrics[e][t])return this.metrics[e][t]=[]},this.addMetric=function(e,t,r){return this.setupLSFor(e,t),this.metrics[e][t].push({id:r,size:"small"}),this.saveSetup()},this.removeMetric=function(e){return function(t,r,n){var o;if(null!=e.metrics[t][r])return o=e.metrics[t][r].indexOf(n),o===-1&&(o=_.findIndex(e.metrics[t][r],{id:n})),o!==-1&&e.metrics[t][r].splice(o,1),e.saveSetup()}}(this),this.setMetricSize=function(e){return function(t,r,n,o){var a;if(null!=e.metrics[t][r])return a=e.metrics[t][r].indexOf(n.id),a===-1&&(a=_.findIndex(e.metrics[t][r],{id:n.id})),a!==-1&&(e.metrics[t][r][a]={id:n.id,size:o}),e.saveSetup()}}(this),this.orderMetrics=function(e,t,r,n){return this.setupLSFor(e,t),angular.forEach(this.metrics[
 e][t],function(o){return function(a,i){if(a.id===r.id&&(o.metrics[e][t].splice(i,1),i<n))return n-=1}}(this)),this.metrics[e][t].splice(n,0,r),this.saveSetup()},this.getMetricsSetup=function(e){return function(t,r){return{names:_.map(e.metrics[t][r],function(e){return _.isString(e)?{id:e,size:"small"}:e})}}}(this),this.getAvailableMetrics=function(n){return function(o,a){var i;return n.setupLSFor(o,a),i=t.defer(),e.get(r.jobServer+"jobs/"+o+"/vertices/"+a+"/metrics").success(function(e){var t;return t=[],angular.forEach(e,function(e,r){var i;if(i=n.metrics[o][a].indexOf(e.id),i===-1&&(i=_.findIndex(n.metrics[o][a],{id:e.id})),i===-1)return t.push(e)}),i.resolve(t)}),i.promise}}(this),this.getAllAvailableMetrics=function(n){return function(n,o){var a;return a=t.defer(),e.get(r.jobServer+"jobs/"+n+"/vertices/"+o+"/metrics").success(function(e){return a.resolve(e)}),a.promise}}(this),this.getMetrics=function(n,o,a){var i,s;return i=t.defer(),s=a.join(","),e.get(r.jobServer+"jobs/"+n+"/
 vertices/"+o+"/metrics?get="+s).success(function(e){return function(t){var r,a;return a={},angular.forEach(t,function(e,t){return a[e.id]=parseInt(e.value)}),r={timestamp:Date.now(),values:a},e.saveValue(n,o,r),i.resolve(r)}}(this)),i.promise},this.setupLS(),this}]),angular.module("flinkApp").controller("OverviewController",["$scope","OverviewService","JobsService","$interval","flinkConfig",function(e,t,r,n,o){var a;return e.jobObserver=function(){return e.runningJobs=r.getJobs("running"),e.finishedJobs=r.getJobs("finished")},r.registerObserver(e.jobObserver),e.$on("$destroy",function(){return r.unRegisterObserver(e.jobObserver)}),e.jobObserver(),t.loadOverview().then(function(t){return e.overview=t}),a=n(function(){return t.loadOverview().then(function(t){return e.overview=t})},o["refresh-interval"]),e.$on("$destroy",function(){return n.cancel(a)})}]),angular.module("flinkApp").service("OverviewService",["$http","flinkConfig","$q",function(e,t,r){var n;return n={},this.loadOverview
 =function(){var o;return o=r.defer(),e.get(t.jobServer+"overview").success(function(e,t,r,a){return n=e,o.resolve(e)}),o.promise},this}]),angular.module("flinkApp").controller("JobSubmitController",["$scope","JobSubmitService","$interval","flinkConfig","$state","$location",function(e,t,r,n,o,a){var i;return e.yarn=a.absUrl().indexOf("/proxy/application_")!==-1,e.loadList=function(){return t.loadJarList().then(function(t){return e.address=t.address,e.noaccess=t.error,e.jars=t.files})},e.defaultState=function(){return e.plan=null,e.error=null,e.state={selected:null,parallelism:"",savepointPath:"",allowNonRestoredState:!1,"entry-class":"","program-args":"","plan-button":"Show Plan","submit-button":"Submit","action-time":0}},e.defaultState(),e.uploader={},e.loadList(),i=r(function(){return e.loadList()},n["refresh-interval"]),e.$on("$destroy",function(){return r.cancel(i)}),e.selectJar=function(t){return e.state.selected===t?e.defaultState():(e.defaultState(),e.state.selected=t)},e.dele
 teJar=function(r,n){return e.state.selected===n&&e.defaultState(),angular.element(r.currentTarget).removeClass("fa-remove").addClass("fa-spin fa-spinner"),t.deleteJar(n).then(function(e){if(angular.element(r.currentTarget).removeClass("fa-spin fa-spinner").addClass("fa-remove"),null!=e.error)return alert(e.error)})},e.loadEntryClass=function(t){return e.state["entry-class"]=t},e.getPlan=function(){var r;if("Show Plan"===e.state["plan-button"])return r=(new Date).getTime(),e.state["action-time"]=r,e.state["submit-button"]="Submit",e.state["plan-button"]="Getting Plan",e.error=null,e.plan=null,t.getPlan(e.state.selected,{"entry-class":e.state["entry-class"],parallelism:e.state.parallelism,"program-args":e.state["program-args"]}).then(function(t){if(r===e.state["action-time"])return e.state["plan-button"]="Show Plan",e.error=t.error,e.plan=t.plan})},e.runJob=function(){var r;if("Submit"===e.state["submit-button"])return r=(new Date).getTime(),e.state["action-time"]=r,e.state["submit-bu
 tton"]="Submitting",e.state["plan-button"]="Show Plan",e.error=null,t.runJob(e.state.selected,{"entry-class":e.state["entry-class"],parallelism:e.state.parallelism,"program-args":e.state["program-args"],savepointPath:e.state.savepointPath,allowNonRestoredState:e.state.allowNonRestoredState}).then(function(t){if(r===e.state["action-time"]&&(e.state["submit-button"]="Submit",e.error=t.error,null!=t.jobid))return o.go("single-job.plan.subtasks",{jobid:t.jobid})})},e.nodeid=null,e.changeNode=function(t){return t!==e.nodeid?(e.nodeid=t,e.vertex=null,e.subtasks=null,e.accumulators=null,e.$broadcast("reload")):(e.nodeid=null,e.nodeUnfolded=!1,e.vertex=null,e.subtasks=null,e.accumulators=null)},e.clearFiles=function(){return e.uploader={}},e.uploadFiles=function(t){return e.uploader={},1===t.length?(e.uploader.file=t[0],e.uploader.upload=!0):e.uploader.error="Did ya forget to select a file?"},e.startUpload=function(){var t,r;return null!=e.uploader.file?(t=new FormData,t.append("jarfile",e.
 uploader.file),e.uploader.upload=!1,e.uploader.success="Initializing upload...",r=new XMLHttpRequest,r.upload.onprogress=function(t){return e.uploader.success=null,e.uploader.progress=parseInt(100*t.loaded/t.total)},r.upload.onerror=function(t){return e.uploader.progress=null,e.uploader.error="An error occurred while uploading your file"},r.upload.onload=function(t){return e.uploader.progress=null,e.uploader.success="Saving..."},r.onreadystatechange=function(){var t;if(4===r.readyState)return t=JSON.parse(r.responseText),null!=t.error?(e.uploader.error=t.error,e.uploader.success=null):e.uploader.success="Uploaded!"},r.open("POST",n.jobServer+"jars/upload"),r.send(t)):console.log("Unexpected Error. This should not happen")}}]).filter("getJarSelectClass",function(){return function(e,t){return e===t?"fa-check-square":"fa-square-o"}}),angular.module("flinkApp").service("JobSubmitService",["$http","flinkConfig","$q",function(e,t,r){return this.loadJarList=function(){var n;return n=r.defe
 r(),e.get(t.jobServer+"jars/").success(function(e,t,r,o){return n.resolve(e)}),n.promise},this.deleteJar=function(n){var o;return o=r.defer(),e["delete"](t.jobServer+"jars/"+encodeURIComponent(n)).success(function(e,t,r,n){return o.resolve(e)}),o.promise},this.getPlan=function(n,o){var a;return a=r.defer(),e.get(t.jobServer+"jars/"+encodeURIComponent(n)+"/plan",{params:o}).success(function(e,t,r,n){return a.resolve(e)}),a.promise},this.runJob=function(n,o){var a;return a=r.defer(),e.post(t.jobServer+"jars/"+encodeURIComponent(n)+"/run",{},{params:o}).success(function(e,t,r,n){return a.resolve(e)}),a.promise},this}]),angular.module("flinkApp").controller("AllTaskManagersController",["$scope","TaskManagersService","$interval","flinkConfig",function(e,t,r,n){var o;return t.loadManagers().then(function(t){return e.managers=t}),o=r(function(){return t.loadManagers().then(function(t){return e.managers=t})},n["refresh-interval"]),e.$on("$destroy",function(){return r.cancel(o)})}]).controll
 er("SingleTaskManagerController",["$scope","$stateParams","SingleTaskManagerService","$interval","flinkConfig",function(e,t,r,n,o){var a;return e.metrics={},r.loadMetrics(t.taskmanagerid).then(function(t){return e.metrics=t[0]}),a=n(function(){return r.loadMetrics(t.taskmanagerid).then(function(t){return e.metrics=t[0]})},o["refresh-interval"]),e.$on("$destroy",function(){return n.cancel(a)})}]).controller("SingleTaskManagerLogsController",["$scope","$stateParams","SingleTaskManagerService","$interval","flinkConfig",function(e,t,r,n,o){return e.log={},e.taskmanagerid=t.taskmanagerid,r.loadLogs(t.taskmanagerid).then(function(t){return e.log=t}),e.reloadData=function(){return r.loadLogs(t.taskmanagerid).then(function(t){return e.log=t})}}]).controller("SingleTaskManagerStdoutController",["$scope","$stateParams","SingleTaskManagerService","$interval","flinkConfig",function(e,t,r,n,o){return e.stdout={},e.taskmanagerid=t.taskmanagerid,r.loadStdout(t.taskmanagerid).then(function(t){retur
 n e.stdout=t}),e.reloadData=function(){return r.loadStdout(t.taskmanagerid).then(function(t){return e.stdout=t})}}]),angular.module("flinkApp").service("TaskManagersService",["$http","flinkConfig","$q",function(e,t,r){return this.loadManagers=function(){var n;return n=r.defer(),e.get(t.jobServer+"taskmanagers").success(function(e,t,r,o){return n.resolve(e.taskmanagers)}),n.promise},this}]).service("SingleTaskManagerService",["$http","flinkConfig","$q",function(e,t,r){return this.loadMetrics=function(n){var o;return o=r.defer(),e.get(t.jobServer+"taskmanagers/"+n).success(function(e,t,r,n){return o.resolve(e.taskmanagers)}),o.promise},this.loadLogs=function(n){var o;return o=r.defer(),e.get(t.jobServer+"taskmanagers/"+n+"/log").success(function(e,t,r,n){return o.resolve(e)}),o.promise},this.loadStdout=function(n){var o;return o=r.defer(),e.get(t.jobServer+"taskmanagers/"+n+"/stdout").success(function(e,t,r,n){return o.resolve(e)}),o.promise},this}]);
\ No newline at end of file


[4/5] flink git commit: [FLINK-3427] [webui] Refactorings to watermark tracking

Posted by uc...@apache.org.
[FLINK-3427] [webui] Refactorings to watermark tracking


Project: http://git-wip-us.apache.org/repos/asf/flink/repo
Commit: http://git-wip-us.apache.org/repos/asf/flink/commit/4ef18f65
Tree: http://git-wip-us.apache.org/repos/asf/flink/tree/4ef18f65
Diff: http://git-wip-us.apache.org/repos/asf/flink/diff/4ef18f65

Branch: refs/heads/master
Commit: 4ef18f6597bfde99733f8d4f4a54b90fc943c663
Parents: d84b65f
Author: Ufuk Celebi <uc...@apache.org>
Authored: Tue Mar 7 11:36:50 2017 +0100
Committer: Ufuk Celebi <uc...@apache.org>
Committed: Wed Mar 8 15:28:41 2017 +0100

----------------------------------------------------------------------
 .../app/partials/jobs/job.plan.jade             |  2 +-
 .../jobs/job.plan.node-list.watermarks.jade     | 14 +--
 .../partials/jobs/job.plan.node.watermarks.jade | 10 +-
 .../app/scripts/common/filters.coffee           | 16 +---
 .../web-dashboard/app/scripts/index.coffee      |  9 +-
 .../app/scripts/modules/jobs/jobs.ctrl.coffee   | 98 ++++++++++++--------
 .../app/scripts/modules/jobs/jobs.dir.coffee    | 17 ++--
 7 files changed, 93 insertions(+), 73 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/flink/blob/4ef18f65/flink-runtime-web/web-dashboard/app/partials/jobs/job.plan.jade
----------------------------------------------------------------------
diff --git a/flink-runtime-web/web-dashboard/app/partials/jobs/job.plan.jade b/flink-runtime-web/web-dashboard/app/partials/jobs/job.plan.jade
index c33b9a3..6c4cf0b 100644
--- a/flink-runtime-web/web-dashboard/app/partials/jobs/job.plan.jade
+++ b/flink-runtime-web/web-dashboard/app/partials/jobs/job.plan.jade
@@ -18,7 +18,7 @@
 split
   .split#canvas
     .canvas-wrapper
-      div.main-canvas(job-plan, plan="plan", low-watermarks="lowWatermarks" jobid="{{jobid}}", set-node="changeNode(nodeid)")
+      div.main-canvas(job-plan, plan="plan", watermarks="watermarks" jobid="{{jobid}}", set-node="changeNode(nodeid)")
 
   .split#job-panel
     .panel.panel-default.panel-multi(ng-if="plan")

http://git-wip-us.apache.org/repos/asf/flink/blob/4ef18f65/flink-runtime-web/web-dashboard/app/partials/jobs/job.plan.node-list.watermarks.jade
----------------------------------------------------------------------
diff --git a/flink-runtime-web/web-dashboard/app/partials/jobs/job.plan.node-list.watermarks.jade b/flink-runtime-web/web-dashboard/app/partials/jobs/job.plan.node-list.watermarks.jade
index 6b4c6a2..4605b61 100644
--- a/flink-runtime-web/web-dashboard/app/partials/jobs/job.plan.node-list.watermarks.jade
+++ b/flink-runtime-web/web-dashboard/app/partials/jobs/job.plan.node-list.watermarks.jade
@@ -23,14 +23,14 @@ table.table.table-body-hover.table-clickable.table-activable
       th Parallelism
       th Status
 
-  tbody(ng-repeat="v in job.vertices" ng-class="{ active: v.id == nodeid && hasWatermarks(nodeid) }" ng-click="changeNode(v.id)")
+  tbody(ng-repeat="v in job.vertices" ng-class="{ active: v.id == nodeid }" ng-click="changeNode(v.id)")
     tr(ng-if="v.type == 'regular'")
-
       td.td-long {{ v.name | humanizeText }}
-      td {{ watermarks | lowWatermark:v.id }}
+      td {{ watermarks[v.id]["lowWatermark"] | humanizeWatermark }}
       td {{ v.parallelism }}
-      td 
+      td
         bs-label(status="{{v.status}}") {{v.status}}
-    tr(ng-if="nodeid && v.id == nodeid && hasWatermarks(nodeid)")
-      td(colspan="11")
-        div(ng-include=" 'partials/jobs/job.plan.node.watermarks.html' ")
+    tr(ng-if="nodeid && v.id == nodeid")
+      td(colspan="4")
+        div(ng-show="hasWatermark(v.id)" ng-include=" 'partials/jobs/job.plan.node.watermarks.html' ")
+        div(ng-show="!hasWatermark(v.id)") No Watermarks

http://git-wip-us.apache.org/repos/asf/flink/blob/4ef18f65/flink-runtime-web/web-dashboard/app/partials/jobs/job.plan.node.watermarks.jade
----------------------------------------------------------------------
diff --git a/flink-runtime-web/web-dashboard/app/partials/jobs/job.plan.node.watermarks.jade b/flink-runtime-web/web-dashboard/app/partials/jobs/job.plan.node.watermarks.jade
index b406a1c..451ccaa 100644
--- a/flink-runtime-web/web-dashboard/app/partials/jobs/job.plan.node.watermarks.jade
+++ b/flink-runtime-web/web-dashboard/app/partials/jobs/job.plan.node.watermarks.jade
@@ -15,13 +15,13 @@
   See the License for the specific language governing permissions and
   limitations under the License.
 
-table.table.table-hover.table-clickable.table-activable.table-inner(ng-if="hasWatermarks(nodeid)")
+table.table.table-hover.table-clickable.table-activable.table-inner
   thead
     tr
-      th id
+      th Subtask
       th Watermark
 
   tbody
-    tr(ng-repeat="watermark in watermarksByNode(nodeid)")
-      td {{ watermark.id }}
-      td {{ watermark.value | parseWatermark }}
+    tr(ng-repeat="(subtaskIndex, watermark) in watermarks[nodeid]['watermarks']")
+      td {{ subtaskIndex | increment }}
+      td {{ watermark | humanizeWatermark }}

http://git-wip-us.apache.org/repos/asf/flink/blob/4ef18f65/flink-runtime-web/web-dashboard/app/scripts/common/filters.coffee
----------------------------------------------------------------------
diff --git a/flink-runtime-web/web-dashboard/app/scripts/common/filters.coffee b/flink-runtime-web/web-dashboard/app/scripts/common/filters.coffee
index 99e12a8..a3ce508 100644
--- a/flink-runtime-web/web-dashboard/app/scripts/common/filters.coffee
+++ b/flink-runtime-web/web-dashboard/app/scripts/common/filters.coffee
@@ -88,19 +88,13 @@ angular.module('flinkApp')
 .filter "percentage", ->
   (number) -> (number * 100).toFixed(0) + '%'
 
-.filter "parseWatermark", (watermarksConfig)->
+.filter "humanizeWatermark", (watermarksConfig) ->
   (value) ->
-    if value <= watermarksConfig.minValue
+    if isNaN(value) || value <= watermarksConfig.noWatermark
       return 'No Watermark'
     else
       return value
 
-.filter "lowWatermark", (watermarksConfig)->
-  (watermarks, nodeid) ->
-    lowWatermark = "No Watermark"
-    if watermarks != null && watermarks[nodeid] && watermarks[nodeid].length
-      values = (watermark.value for watermark in watermarks[nodeid])
-      lowWatermark = Math.min.apply(null, values)
-      if lowWatermark <= watermarksConfig.minValue
-        lowWatermark = "No Watermark"
-    return lowWatermark
+.filter "increment", ->
+  (number) ->
+    parseInt(number) + 1

http://git-wip-us.apache.org/repos/asf/flink/blob/4ef18f65/flink-runtime-web/web-dashboard/app/scripts/index.coffee
----------------------------------------------------------------------
diff --git a/flink-runtime-web/web-dashboard/app/scripts/index.coffee b/flink-runtime-web/web-dashboard/app/scripts/index.coffee
index cbbefab..52bb075 100644
--- a/flink-runtime-web/web-dashboard/app/scripts/index.coffee
+++ b/flink-runtime-web/web-dashboard/app/scripts/index.coffee
@@ -30,14 +30,17 @@ angular.module('flinkApp', ['ui.router', 'angularMoment', 'dndLists'])
 
 .value 'flinkConfig', {
   jobServer: ''
-  # jobServer: 'http://localhost:8081/'
+#  jobServer: 'http://localhost:8081/'
   "refresh-interval": 10000
 }
 
 # --------------------------------------
 
 .value 'watermarksConfig', {
-  minValue: -9223372036854776000
+  # A value of (Java) Long.MIN_VALUE indicates that there is no watermark
+  # available. This is parsed by Javascript as this number. We have it as
+  # a constant here to compare available watermarks against.
+  noWatermark: -9223372036854776000
 }
 
 # --------------------------------------
@@ -52,7 +55,6 @@ angular.module('flinkApp', ['ui.router', 'angularMoment', 'dndLists'])
       JobsService.listJobs()
     , flinkConfig["refresh-interval"]
 
-
 # --------------------------------------
 
 .config ($uiViewScrollProvider) ->
@@ -125,7 +127,6 @@ angular.module('flinkApp', ['ui.router', 'angularMoment', 'dndLists'])
     views:
       'node-details':
         templateUrl: "partials/jobs/job.plan.node-list.watermarks.html"
-        controller: 'JobPlanWatermarksController'
 
   .state "single-job.plan.taskmanagers",
     url: "/taskmanagers"

http://git-wip-us.apache.org/repos/asf/flink/blob/4ef18f65/flink-runtime-web/web-dashboard/app/scripts/modules/jobs/jobs.ctrl.coffee
----------------------------------------------------------------------
diff --git a/flink-runtime-web/web-dashboard/app/scripts/modules/jobs/jobs.ctrl.coffee b/flink-runtime-web/web-dashboard/app/scripts/modules/jobs/jobs.ctrl.coffee
index d18d7e3..f25c94d 100644
--- a/flink-runtime-web/web-dashboard/app/scripts/modules/jobs/jobs.ctrl.coffee
+++ b/flink-runtime-web/web-dashboard/app/scripts/modules/jobs/jobs.ctrl.coffee
@@ -46,8 +46,7 @@ angular.module('flinkApp')
   $scope.jobid = $stateParams.jobid
   $scope.job = null
   $scope.plan = null
-  $scope.watermarks = null
-  $scope.lowWatermarks = null
+  $scope.watermarks = {}
   $scope.vertices = null
   $scope.backPressureOperatorStats = {}
 
@@ -61,8 +60,7 @@ angular.module('flinkApp')
   $scope.$on '$destroy', ->
     $scope.job = null
     $scope.plan = null
-    $scope.watermarks = null
-    $scope.lowWatermarks = null
+    $scope.watermarks = {}
     $scope.vertices = null
     $scope.backPressureOperatorStats = null
 
@@ -84,43 +82,80 @@ angular.module('flinkApp')
     $scope.plan = data.plan
     MetricsService.setupMetrics($stateParams.jobid, data.vertices)
 
-  getWatermarks = (nodes)->
-    # This function uses a promise to resolve watermarks once fetched via the metrics service, since watermarks have to be fetched individually for each node, we have to wait until all API calls have been made before we can resolve the promise. In the end we will have an array of low watermarks for each node: e.g. {somenodeid: [{id: 0, value: -9223372036854776000}], anothernodeid: [{id: 0, value: -9223372036854776000}, {id: 1, value: -9223372036854776000}]}.
+  # Asynchronously requests the watermark metrics for the given nodes. The
+  # returned object has the following structure:
+  #
+  # {
+  #    "<nodeId>": {
+  #          "lowWatermark": <lowWatermark>
+  #          "watermarks": {
+  #               0: <watermark for subtask 0>
+  #               ...
+  #               n: <watermark for subtask n>
+  #            }
+  #       }
+  # }
+  #
+  # If no watermark is available, lowWatermark will be NaN and
+  # the watermarks will be empty.
+  getWatermarks = (nodes) ->
+    # Requests the watermarks for a single vertex. Triggers a request
+    # to the Metrics service.
+    requestWatermarkForNode = (node) =>
+      deferred = $q.defer()
+
+      jid = $scope.job.jid
+
+      # Request metrics for each subtask
+      metricIds = (i + ".currentLowWatermark" for i in [0..node.parallelism - 1])
+      MetricsService.getMetrics(jid, node.id, metricIds).then (metrics) ->
+        minValue = NaN
+        watermarks = {}
+
+        for key, value of metrics.values
+          subtaskIndex = key.replace('.currentLowWatermark', '')
+          watermarks[subtaskIndex] = value
+
+          if (isNaN(minValue) || value < minValue)
+            minValue = value
+
+        if (!isNaN(minValue) && minValue > watermarksConfig.noWatermark)
+          lowWatermark = minValue
+        else
+          # NaN indicates no watermark available
+          lowWatermark = NaN
+
+        deferred.resolve({"lowWatermark": lowWatermark, "watermarks": watermarks})
+
+      deferred.promise
+
     deferred = $q.defer()
     watermarks = {}
-    jid = $scope.job.jid
+
+    # Request watermarks for each node and update watermarks
+    len = nodes.length
     angular.forEach nodes, (node, index) =>
-      metricIds = []
-      # for each node, we need to specify which metrics we want to collect, for each subtask, we need to fetch the currentLowWatermark, and each param is formed by concatenating subtask index to '.currentLowWatermark'.
-      for num in [0..node.parallelism - 1]
-        metricIds.push(num + ".currentLowWatermark")
-      MetricsService.getMetrics(jid, node.id, metricIds).then (data) ->
-        values = []
-        for key, value of data.values
-          values.push(id: key.replace('.currentLowWatermark', ''), value: value)
-        watermarks[node.id] = values
-        if index >= $scope.plan.nodes.length - 1
+      nodeId = node.id
+      requestWatermarkForNode(node).then (data) ->
+        watermarks[nodeId] = data
+        if (index >= len - 1)
           deferred.resolve(watermarks)
+
     deferred.promise
 
-  getLowWatermarks = (watermarks)->
-    lowWatermarks = []
-    for k,v of watermarks
-      minValue = Math.min.apply(null,(watermark.value for watermark in v))
-      lowWatermarks[k] = if minValue <= watermarksConfig.minValue || v.length == 0 then 'No Watermark' else minValue
-    return lowWatermarks
+  # Returns true if the lowWatermark is != NaN
+  $scope.hasWatermark = (nodeid) ->
+    $scope.watermarks[nodeid] && !isNaN($scope.watermarks[nodeid]["lowWatermark"])
 
   $scope.$watch 'plan', (newPlan) ->
     if newPlan
       getWatermarks(newPlan.nodes).then (data) ->
         $scope.watermarks = data
-        $scope.lowWatermarks = getLowWatermarks(data)
 
-  $scope.$on 'reload', (event) ->
+  $scope.$on 'reload', () ->
     if $scope.plan
       getWatermarks($scope.plan.nodes).then (data) ->
         $scope.watermarks = data
-        $scope.lowWatermarks = getLowWatermarks(data)
 
 # --------------------------------------
 
@@ -359,14 +394,3 @@ angular.module('flinkApp')
   loadMetrics() if $scope.nodeid
 
 # --------------------------------------
-
-.controller 'JobPlanWatermarksController', ($scope, $filter) ->
-  $scope.hasWatermarks = (nodeid) ->
-    return true if $scope.watermarksByNode(nodeid).length
-
-  $scope.watermarksByNode = (nodeid) ->
-    if $scope.watermarks != null && $scope.watermarks[nodeid] && $scope.watermarks[nodeid].length
-      return $scope.watermarks[nodeid]
-    return []
-
-# --------------------------------------

http://git-wip-us.apache.org/repos/asf/flink/blob/4ef18f65/flink-runtime-web/web-dashboard/app/scripts/modules/jobs/jobs.dir.coffee
----------------------------------------------------------------------
diff --git a/flink-runtime-web/web-dashboard/app/scripts/modules/jobs/jobs.dir.coffee b/flink-runtime-web/web-dashboard/app/scripts/modules/jobs/jobs.dir.coffee
index 950cf06..36b0c43 100644
--- a/flink-runtime-web/web-dashboard/app/scripts/modules/jobs/jobs.dir.coffee
+++ b/flink-runtime-web/web-dashboard/app/scripts/modules/jobs/jobs.dir.coffee
@@ -169,7 +169,7 @@ angular.module('flinkApp')
 
 # ----------------------------------------------
 
-.directive 'split', () -> 
+.directive 'split', () ->
   return compile: (tElem, tAttrs) ->
       Split(tElem.children(), (
         sizes: [50, 50]
@@ -189,7 +189,7 @@ angular.module('flinkApp')
 
   scope:
     plan: '='
-    lowWatermarks: '='
+    watermarks: '='
     setNode: '&'
 
   link: (scope, elem, attrs) ->
@@ -436,10 +436,11 @@ angular.module('flinkApp')
             return el.step_function[j]  if el.step_function[j].id is nodeID
 
     mergeWatermarks = (data, watermarks) ->
-      for k,v of watermarks
+      if (!_.isEmpty(watermarks))
         for node in data.nodes
-          if node.id == k
-            node.lowWatermark = v
+          if (watermarks[node.id] && !isNaN(watermarks[node.id]["lowWatermark"]))
+            node.lowWatermark = watermarks[node.id]["lowWatermark"]
+
       return data
 
     lastPosition = 0
@@ -456,7 +457,7 @@ angular.module('flinkApp')
           marginy: 40
           })
 
-        loadJsonToDagre(g, mergeWatermarks(scope.plan, scope.lowWatermarks))
+        loadJsonToDagre(g, mergeWatermarks(scope.plan, scope.watermarks))
 
         d3mainSvgG.selectAll("*").remove()
 
@@ -494,7 +495,7 @@ angular.module('flinkApp')
     scope.$watch attrs.plan, (newPlan) ->
       drawGraph() if newPlan
 
-    scope.$watch attrs.lowWatermarks, (newLowWatermarks) ->
-      drawGraph() if newLowWatermarks && scope.plan
+    scope.$watch attrs.watermarks, (newWatermarks) ->
+      drawGraph() if newWatermarks && scope.plan
 
     return


[2/5] flink git commit: [FLINK-3427] [webui] Rebuild web UI

Posted by uc...@apache.org.
http://git-wip-us.apache.org/repos/asf/flink/blob/121b12b7/flink-runtime-web/web-dashboard/web/js/vendor.js
----------------------------------------------------------------------
diff --git a/flink-runtime-web/web-dashboard/web/js/vendor.js b/flink-runtime-web/web-dashboard/web/js/vendor.js
index 135358e..ee2e3e3 100644
--- a/flink-runtime-web/web-dashboard/web/js/vendor.js
+++ b/flink-runtime-web/web-dashboard/web/js/vendor.js
@@ -22,9 +22,9 @@ n.left=void 0!==t.left?t.left:n.left}},color:{get:function(){return s},set:funct
 g.scale(o)._ticks(t.utils.calcTicksY(Z/36,w)).tickSize(-X,0),v.scale(a)._ticks(t.utils.calcTicksY(Z/36,w)),R?v.tickSize(tt.length?0:-X,0):v.tickSize(J.length?0:-X,0);var u=J.length?1:0,c=tt.length&&!Y(tt)?1:0,d=R?c:u,p=R?u:c;ot.select(".nv-focus .nv-y1.nv-axis").style("opacity",d),ot.select(".nv-focus .nv-y2.nv-axis").style("opacity",p).attr("transform","translate("+r.range()[1]+",0)"),ot.select(".nv-focus .nv-y1.nv-axis").transition().duration(P).call(g),ot.select(".nv-focus .nv-y2.nv-axis").transition().duration(P).call(v)}var G=d3.select(this);t.utils.initSVG(G);var X=t.utils.availableWidth(_,G,$),Z=t.utils.availableHeight(M,G,$)-(T?O:0),Q=O-k.top-k.bottom;if(e.update=function(){G.transition().duration(P).call(e)},e.container=this,F.setter(U(w),e.update).getter(H(w)).update(),F.disabled=w.map(function(t){return!!t.disabled}),!q){var K;q={};for(K in F)F[K]instanceof Array?q[K]=F[K].slice(0):q[K]=F[K]}if(!(w&&w.length&&w.filter(function(t){return t.values.length}).length))return t.
 utils.noData(e,G),e;G.selectAll(".nv-noData").remove();var J=w.filter(function(t){return!t.disabled&&t.bar}),tt=w.filter(function(t){return!t.bar});r=J.length&&!R?f.xScale():l.xScale(),i=p.scale(),o=R?l.yScale():f.yScale(),a=R?f.yScale():l.yScale(),s=R?c.yScale():d.yScale(),u=R?d.yScale():c.yScale();var et=w.filter(function(t){return!t.disabled&&(R?!t.bar:t.bar)}).map(function(t){return t.values.map(function(t,e){return{x:C(t,e),y:S(t,e)}})}),nt=w.filter(function(t){return!t.disabled&&(R?t.bar:!t.bar)}).map(function(t){return t.values.map(function(t,e){return{x:C(t,e),y:S(t,e)}})});r.range([0,X]),i.domain(d3.extent(d3.merge(et.concat(nt)),function(t){return t.x})).range([0,X]);var rt=G.selectAll("g.nv-wrap.nv-linePlusBar").data([w]),it=rt.enter().append("g").attr("class","nvd3 nv-wrap nv-linePlusBar").append("g"),ot=rt.select("g");it.append("g").attr("class","nv-legendWrap");var at=it.append("g").attr("class","nv-focus");at.append("g").attr("class","nv-x nv-axis"),at.append("g").att
 r("class","nv-y1 nv-axis"),at.append("g").attr("class","nv-y2 nv-axis"),at.append("g").attr("class","nv-barsWrap"),at.append("g").attr("class","nv-linesWrap");var st=it.append("g").attr("class","nv-context");if(st.append("g").attr("class","nv-x nv-axis"),st.append("g").attr("class","nv-y1 nv-axis"),st.append("g").attr("class","nv-y2 nv-axis"),st.append("g").attr("class","nv-barsWrap"),st.append("g").attr("class","nv-linesWrap"),st.append("g").attr("class","nv-brushBackground"),st.append("g").attr("class","nv-x nv-brush"),A){var ut=b.align()?X/2:X,lt=b.align()?ut:0;b.width(ut),ot.select(".nv-legendWrap").datum(w.map(function(t){return t.originalKey=void 0===t.originalKey?t.key:t.originalKey,R?t.key=t.originalKey+(t.bar?W:z):t.key=t.originalKey+(t.bar?z:W),t})).call(b),b.height()>$.top&&($.top=b.height(),Z=t.utils.availableHeight(M,G,$)-O),ot.select(".nv-legendWrap").attr("transform","translate("+lt+","+-$.top+")")}else ot.select(".nv-legendWrap").selectAll("*").remove();rt.attr("tran
 sform","translate("+$.left+","+$.top+")"),ot.select(".nv-context").style("display",T?"initial":"none"),d.width(X).height(Q).color(w.map(function(t,e){return t.color||E(t,e)}).filter(function(t,e){return!w[e].disabled&&w[e].bar})),c.width(X).height(Q).color(w.map(function(t,e){return t.color||E(t,e)}).filter(function(t,e){return!w[e].disabled&&!w[e].bar}));var ct=ot.select(".nv-context .nv-barsWrap").datum(J.length?J:[{values:[]}]),ft=ot.select(".nv-context .nv-linesWrap").datum(Y(tt)?[{values:[]}]:tt.filter(function(t){return!t.disabled}));ot.select(".nv-context").attr("transform","translate(0,"+(Z+$.bottom+k.top)+")"),ct.transition().call(d),ft.transition().call(c),D&&(p._ticks(t.utils.calcTicksX(X/100,w)).tickSize(-Q,0),ot.select(".nv-context .nv-x.nv-axis").attr("transform","translate(0,"+s.range()[0]+")"),ot.select(".nv-context .nv-x.nv-axis").transition().call(p)),N&&(m.scale(s)._ticks(Q/36).tickSize(-X,0),y.scale(u)._ticks(Q/36).tickSize(J.length?0:-X,0),ot.select(".nv-context
  .nv-y3.nv-axis").style("opacity",J.length?1:0).attr("transform","translate(0,"+i.range()[0]+")"),ot.select(".nv-context .nv-y2.nv-axis").style("opacity",tt.length?1:0).attr("transform","translate("+i.range()[1]+",0)"),ot.select(".nv-context .nv-y1.nv-axis").transition().call(m),ot.select(".nv-context .nv-y2.nv-axis").transition().call(y)),x.x(i).on("brush",V),j&&x.extent(j);var dt=ot.select(".nv-brushBackground").selectAll("g").data([j||x.extent()]),ht=dt.enter().append("g");ht.append("rect").attr("class","left").attr("x",0).attr("y",0).attr("height",Q),ht.append("rect").attr("class","right").attr("x",0).attr("y",0).attr("height",Q);var pt=ot.select(".nv-x.nv-brush").call(x);pt.selectAll("rect").attr("height",Q),pt.selectAll(".resize").append("path").attr("d",I),b.dispatch.on("stateChange",function(t){for(var n in t)F[n]=t[n];L.stateChange(F),e.update()}),L.on("changeState",function(t){"undefined"!=typeof t.disabled&&(w.forEach(function(e,n){e.disabled=t.disabled[n]}),F.disabled=t.
 disabled),e.update()}),V()}),e}var n,r,i,o,a,s,u,l=t.models.line(),c=t.models.line(),f=t.models.historicalBar(),d=t.models.historicalBar(),h=t.models.axis(),p=t.models.axis(),g=t.models.axis(),v=t.models.axis(),m=t.models.axis(),y=t.models.axis(),b=t.models.legend(),x=d3.svg.brush(),w=t.models.tooltip(),$={top:30,right:30,bottom:30,left:60},k={top:0,right:30,bottom:20,left:60},_=null,M=null,C=function(t){return t.x},S=function(t){return t.y},E=t.utils.defaultColor(),A=!0,T=!0,N=!1,D=!0,O=50,j=null,I=null,L=d3.dispatch("brush","stateChange","changeState"),P=0,F=t.utils.state(),q=null,z=" (left axis)",W=" (right axis)",R=!1;l.clipEdge(!0),c.interactive(!1),c.pointActive(function(t){return!1}),h.orient("bottom").tickPadding(5),g.orient("left"),v.orient("right"),p.orient("bottom").tickPadding(5),m.orient("left"),y.orient("right"),w.headerEnabled(!0).headerFormatter(function(t,e){return h.tickFormat()(t,e)});var B=function(){return R?{main:v,focus:y}:{main:g,focus:m}},V=function(){return
  R?{main:g,focus:m}:{main:v,focus:y}},H=function(t){return function(){return{active:t.map(function(t){return!t.disabled})}}},U=function(t){return function(e){void 0!==e.active&&t.forEach(function(t,n){t.disabled=!e.active[n]})}},Y=function(t){return t.every(function(t){return t.disabled})};return l.dispatch.on("elementMouseover.tooltip",function(t){w.duration(100).valueFormatter(function(t,e){return V().main.tickFormat()(t,e)}).data(t).hidden(!1)}),l.dispatch.on("elementMouseout.tooltip",function(t){w.hidden(!0)}),f.dispatch.on("elementMouseover.tooltip",function(t){t.value=e.x()(t.data),t.series={value:e.y()(t.data),color:t.color},w.duration(0).valueFormatter(function(t,e){return B().main.tickFormat()(t,e)}).data(t).hidden(!1)}),f.dispatch.on("elementMouseout.tooltip",function(t){w.hidden(!0)}),f.dispatch.on("elementMousemove.tooltip",function(t){w()}),e.dispatch=L,e.legend=b,e.lines=l,e.lines2=c,e.bars=f,e.bars2=d,e.xAxis=h,e.x2Axis=p,e.y1Axis=g,e.y2Axis=v,e.y3Axis=m,e.y4Axis=y,e.
 tooltip=w,e.options=t.utils.optionsFunc.bind(e),e._options=Object.create({},{width:{get:function(){return _},set:function(t){_=t}},height:{get:function(){return M},set:function(t){M=t}},showLegend:{get:function(){return A},set:function(t){A=t}},brushExtent:{get:function(){return j},set:function(t){j=t}},noData:{get:function(){return I},set:function(t){I=t}},focusEnable:{get:function(){return T},set:function(t){T=t}},focusHeight:{get:function(){return O},set:function(t){O=t}},focusShowAxisX:{get:function(){return D},set:function(t){D=t}},focusShowAxisY:{get:function(){return N},set:function(t){N=t}},legendLeftAxisHint:{get:function(){return z},set:function(t){z=t}},legendRightAxisHint:{get:function(){return W},set:function(t){W=t}},margin:{get:function(){return $},set:function(t){$.top=void 0!==t.top?t.top:$.top,$.right=void 0!==t.right?t.right:$.right,$.bottom=void 0!==t.bottom?t.bottom:$.bottom,$.left=void 0!==t.left?t.left:$.left}},focusMargin:{get:function(){return k},set:functio
 n(t){k.top=void 0!==t.top?t.top:k.top,k.right=void 0!==t.right?t.right:k.right,k.bottom=void 0!==t.bottom?t.bottom:k.bottom,k.left=void 0!==t.left?t.left:k.left}},duration:{get:function(){return P},set:function(t){P=t}},color:{get:function(){return E},set:function(e){E=t.utils.getColor(e),b.color(E)}},x:{get:function(){return C},set:function(t){C=t,l.x(t),c.x(t),f.x(t),d.x(t)}},y:{get:function(){return S},set:function(t){S=t,l.y(t),c.y(t),f.y(t),d.y(t)}},switchYAxisOrder:{get:function(){return R},set:function(t){if(R!==t){var e=g;g=v,v=e;var n=m;m=y,y=n}R=t,g.orient("left"),v.orient("right"),m.orient("left"),y.orient("right")}}}),t.utils.inheritOptions(e,l),t.utils.initOptions(e),e},t.models.multiBar=function(){"use strict";function e(N){return A.reset(),N.each(function(e){var N=c-l.left-l.right,D=f-l.top-l.bottom;g=d3.select(this),t.utils.initSVG(g);var O=0;if(k&&e.length&&(k=[{values:e[0].values.map(function(t){return{x:t.x,y:0,series:t.series,size:.01}})}]),x){var j=d3.layout.sta
 ck().offset(w).values(function(t){return t.values}).y(m)(!e.length&&k?k:e);j.forEach(function(t,n){t.nonStackable?(e[n].nonStackableSeries=O++,j[n]=e[n]):n>0&&j[n-1].nonStackable&&j[n].values.map(function(t,e){t.y0-=j[n-1].values[e].y,t.y1=t.y0+t.y})}),e=j}e.forEach(function(t,e){t.values.forEach(function(n){n.series=e,n.key=t.key})}),x&&e.length>0&&e[0].values.map(function(t,n){var r=0,i=0;e.map(function(t,o){if(!e[o].nonStackable){var a=t.values[n];a.size=Math.abs(a.y),a.y<0?(a.y1=i,i-=a.size):(a.y1=a.size+r,r+=a.size)}})});var I=r&&i?[]:e.map(function(t,e){return t.values.map(function(t,n){return{x:v(t,n),y:m(t,n),y0:t.y0,y1:t.y1,idx:e}})});d.domain(r||d3.merge(I).map(function(t){return t.x})).rangeBands(o||[0,N],C),h.domain(i||d3.extent(d3.merge(I).map(function(t){var n=t.y;return x&&!e[t.idx].nonStackable&&(n=t.y>0?t.y1:t.y1+t.y),n}).concat(y))).range(a||[D,0]),d.domain()[0]===d.domain()[1]&&(d.domain()[0]?d.domain([d.domain()[0]-.01*d.domain()[0],d.domain()[1]+.01*d.domain()[1
 ]]):d.domain([-1,1])),h.domain()[0]===h.domain()[1]&&(h.domain()[0]?h.domain([h.domain()[0]+.01*h.domain()[0],h.domain()[1]-.01*h.domain()[1]]):h.domain([-1,1])),s=s||d,u=u||h;var L=g.selectAll("g.nv-wrap.nv-multibar").data([e]),P=L.enter().append("g").attr("class","nvd3 nv-wrap nv-multibar"),F=P.append("defs"),q=P.append("g"),z=L.select("g");q.append("g").attr("class","nv-groups"),L.attr("transform","translate("+l.left+","+l.top+")"),F.append("clipPath").attr("id","nv-edge-clip-"+p).append("rect"),L.select("#nv-edge-clip-"+p+" rect").attr("width",N).attr("height",D),z.attr("clip-path",b?"url(#nv-edge-clip-"+p+")":"");var W=L.select(".nv-groups").selectAll(".nv-group").data(function(t){return t},function(t,e){return e});W.enter().append("g").style("stroke-opacity",1e-6).style("fill-opacity",1e-6);var R=A.transition(W.exit().selectAll("rect.nv-bar"),"multibarExit",Math.min(100,M)).attr("y",function(t,n,r){var i=u(0)||0;return x&&e[t.series]&&!e[t.series].nonStackable&&(i=u(t.y0)),i})
 .attr("height",0).remove();R.delay&&R.delay(function(t,e){var n=e*(M/(T+1))-e;return n}),W.attr("class",function(t,e){return"nv-group nv-series-"+e}).classed("hover",function(t){return t.hover}).style("fill",function(t,e){return $(t,e)}).style("stroke",function(t,e){return $(t,e)}),W.style("stroke-opacity",1).style("fill-opacity",S);var B=W.selectAll("rect.nv-bar").data(function(t){return k&&!e.length?k.values:t.values});B.exit().remove();B.enter().append("rect").attr("class",function(t,e){return m(t,e)<0?"nv-bar negative":"nv-bar positive"}).attr("x",function(t,n,r){return x&&!e[r].nonStackable?0:r*d.rangeBand()/e.length}).attr("y",function(t,n,r){return u(x&&!e[r].nonStackable?t.y0:0)||0}).attr("height",0).attr("width",function(t,n,r){return d.rangeBand()/(x&&!e[r].nonStackable?1:e.length)}).attr("transform",function(t,e){return"translate("+d(v(t,e))+",0)"});B.style("fill",function(t,e,n){return $(t,n,e)}).style("stroke",function(t,e,n){return $(t,n,e)}).on("mouseover",function(t,
 e){d3.select(this).classed("hover",!0),E.elementMouseover({data:t,index:e,color:d3.select(this).style("fill")})}).on("mouseout",function(t,e){d3.select(this).classed("hover",!1),E.elementMouseout({data:t,index:e,color:d3.select(this).style("fill")})}).on("mousemove",function(t,e){E.elementMousemove({data:t,index:e,color:d3.select(this).style("fill")})}).on("click",function(t,e){var n=this;E.elementClick({data:t,index:e,color:d3.select(this).style("fill"),event:d3.event,element:n}),d3.event.stopPropagation()}).on("dblclick",function(t,e){E.elementDblClick({data:t,index:e,color:d3.select(this).style("fill")}),d3.event.stopPropagation()}),B.attr("class",function(t,e){return m(t,e)<0?"nv-bar negative":"nv-bar positive"}).attr("transform",function(t,e){return"translate("+d(v(t,e))+",0)"}),_&&(n||(n=e.map(function(){return!0})),B.style("fill",function(t,e,r){return d3.rgb(_(t,e)).darker(n.map(function(t,e){return e}).filter(function(t,e){return!n[e]})[r]).toString()}).style("stroke",funct
 ion(t,e,r){return d3.rgb(_(t,e)).darker(n.map(function(t,e){return e}).filter(function(t,e){return!n[e]})[r]).toString()}));var V=B.watchTransition(A,"multibar",Math.min(250,M)).delay(function(t,n){return n*M/e[0].values.length});x?V.attr("y",function(t,n,r){var i=0;return i=e[r].nonStackable?m(t,n)<0?h(0):h(0)-h(m(t,n))<-1?h(0)-1:h(m(t,n))||0:h(t.y1)}).attr("height",function(t,n,r){return e[r].nonStackable?Math.max(Math.abs(h(m(t,n))-h(0)),0)||0:Math.max(Math.abs(h(t.y+t.y0)-h(t.y0)),0)}).attr("x",function(t,n,r){var i=0;return e[r].nonStackable&&(i=t.series*d.rangeBand()/e.length,e.length!==O&&(i=e[r].nonStackableSeries*d.rangeBand()/(2*O))),i}).attr("width",function(t,n,r){if(e[r].nonStackable){var i=d.rangeBand()/O;return e.length!==O&&(i=d.rangeBand()/(2*O)),i}return d.rangeBand()}):V.attr("x",function(t,n){return t.series*d.rangeBand()/e.length}).attr("width",d.rangeBand()/e.length).attr("y",function(t,e){return m(t,e)<0?h(0):h(0)-h(m(t,e))<1?h(0)-1:h(m(t,e))||0}).attr("height
 ",function(t,e){return Math.max(Math.abs(h(m(t,e))-h(0)),1)||0}),s=d.copy(),u=h.copy(),e[0]&&e[0].values&&(T=e[0].values.length)}),A.renderEnd("multibar immediate"),e}var n,r,i,o,a,s,u,l={top:0,right:0,bottom:0,left:0},c=960,f=500,d=d3.scale.ordinal(),h=d3.scale.linear(),p=Math.floor(1e4*Math.random()),g=null,v=function(t){return t.x},m=function(t){return t.y},y=[0],b=!0,x=!1,w="zero",$=t.utils.defaultColor(),k=!1,_=null,M=500,C=.1,S=.75,E=d3.dispatch("chartClick","elementClick","elementDblClick","elementMouseover","elementMouseout","elementMousemove","renderEnd"),A=t.utils.renderWatch(E,M),T=0;return e.dispatch=E,e.options=t.utils.optionsFunc.bind(e),e._options=Object.create({},{width:{get:function(){return c},set:function(t){c=t}},height:{get:function(){return f},set:function(t){f=t}},x:{get:function(){return v},set:function(t){v=t}},y:{get:function(){return m},set:function(t){m=t}},xScale:{get:function(){return d},set:function(t){d=t}},yScale:{get:function(){return h},set:functio
 n(t){h=t}},xDomain:{get:function(){return r},set:function(t){r=t}},yDomain:{get:function(){return i},set:function(t){i=t}},xRange:{get:function(){return o},set:function(t){o=t}},yRange:{get:function(){return a},set:function(t){a=t}},forceY:{get:function(){return y},set:function(t){y=t}},stacked:{get:function(){return x},set:function(t){x=t}},stackOffset:{get:function(){return w},set:function(t){w=t}},clipEdge:{get:function(){return b},set:function(t){b=t}},disabled:{get:function(){return n},set:function(t){n=t}},id:{get:function(){return p},set:function(t){p=t}},hideable:{get:function(){return k},set:function(t){k=t}},groupSpacing:{get:function(){return C},set:function(t){C=t}},fillOpacity:{get:function(){return S},set:function(t){S=t}},margin:{get:function(){return l},set:function(t){l.top=void 0!==t.top?t.top:l.top,l.right=void 0!==t.right?t.right:l.right,l.bottom=void 0!==t.bottom?t.bottom:l.bottom,l.left=void 0!==t.left?t.left:l.left}},duration:{get:function(){return M},set:func
 tion(t){M=t,A.reset(M)}},color:{get:function(){return $},set:function(e){$=t.utils.getColor(e)}},barColor:{get:function(){return _},set:function(e){_=e?t.utils.getColor(e):null}}}),t.utils.initOptions(e),e},t.models.multiBarChart=function(){"use strict";function e(S){return D.reset(),D.models(i),y&&D.models(o),b&&D.models(a),S.each(function(S){var D=d3.select(this);t.utils.initSVG(D);var L=t.utils.availableWidth(d,D,f),P=t.utils.availableHeight(h,D,f);if(e.update=function(){0===T?D.call(e):D.transition().duration(T).call(e)},e.container=this,M.setter(I(S),e.update).getter(j(S)).update(),M.disabled=S.map(function(t){return!!t.disabled}),!C){var F;C={};for(F in M)M[F]instanceof Array?C[F]=M[F].slice(0):C[F]=M[F]}if(!(S&&S.length&&S.filter(function(t){return t.values.length}).length))return t.utils.noData(e,D),e;D.selectAll(".nv-noData").remove(),n=i.xScale(),r=i.yScale();var q=D.selectAll("g.nv-wrap.nv-multiBarWithLegend").data([S]),z=q.enter().append("g").attr("class","nvd3 nv-wrap n
 v-multiBarWithLegend").append("g"),W=q.select("g");if(z.append("g").attr("class","nv-x nv-axis"),z.append("g").attr("class","nv-y nv-axis"),z.append("g").attr("class","nv-barsWrap"),z.append("g").attr("class","nv-legendWrap"),z.append("g").attr("class","nv-controlsWrap"),z.append("g").attr("class","nv-interactive"),m?(u.width(L-A()),W.select(".nv-legendWrap").datum(S).call(u),u.height()>f.top&&(f.top=u.height(),P=t.utils.availableHeight(h,D,f)),W.select(".nv-legendWrap").attr("transform","translate("+A()+","+-f.top+")")):W.select(".nv-legendWrap").selectAll("*").remove(),g){var R=[{key:v.grouped||"Grouped",disabled:i.stacked()},{key:v.stacked||"Stacked",disabled:!i.stacked()}];l.width(A()).color(["#444","#444","#444"]),W.select(".nv-controlsWrap").datum(R).attr("transform","translate(0,"+-f.top+")").call(l)}else W.select(".nv-controlsWrap").selectAll("*").remove();q.attr("transform","translate("+f.left+","+f.top+")"),x&&W.select(".nv-y.nv-axis").attr("transform","translate("+L+",0)"
 ),i.disabled(S.map(function(t){return t.disabled})).width(L).height(P).color(S.map(function(t,e){return t.color||p(t,e)}).filter(function(t,e){return!S[e].disabled}));var B=W.select(".nv-barsWrap").datum(S.filter(function(t){return!t.disabled}));if(B.call(i),y){o.scale(n)._ticks(t.utils.calcTicksX(L/100,S)).tickSize(-P,0),W.select(".nv-x.nv-axis").attr("transform","translate(0,"+r.range()[0]+")"),W.select(".nv-x.nv-axis").call(o);var V=W.select(".nv-x.nv-axis > g").selectAll("g");if(V.selectAll("line, text").style("opacity",1),$){var H=function(t,e){return"translate("+t+","+e+")"},U=5,Y=17;V.selectAll("text").attr("transform",function(t,e,n){return H(0,n%2==0?U:Y)});var G=d3.selectAll(".nv-x.nv-axis .nv-wrap g g text")[0].length;W.selectAll(".nv-x.nv-axis .nv-axisMaxMin text").attr("transform",function(t,e){return H(0,0===e||G%2!==0?Y:U)})}k&&W.selectAll(".tick text").call(t.utils.wrapTicks,e.xAxis.rangeBand()),w&&V.filter(function(t,e){return e%Math.ceil(S[0].values.length/(L/100))
 !==0}).selectAll("text, line").style("opacity",0),_&&V.selectAll(".tick text").attr("transform","rotate("+_+" 0,0)").style("text-anchor",_>0?"start":"end"),W.select(".nv-x.nv-axis").selectAll("g.nv-axisMaxMin text").style("opacity",1)}b&&(a.scale(r)._ticks(t.utils.calcTicksY(P/36,S)).tickSize(-L,0),W.select(".nv-y.nv-axis").call(a)),N&&(s.width(L).height(P).margin({left:f.left,top:f.top}).svgContainer(D).xScale(n),q.select(".nv-interactive").call(s)),u.dispatch.on("stateChange",function(t){for(var n in t)M[n]=t[n];E.stateChange(M),e.update()}),l.dispatch.on("legendClick",function(t,n){if(t.disabled){switch(R=R.map(function(t){return t.disabled=!0,t}),t.disabled=!1,t.key){case"Grouped":case v.grouped:i.stacked(!1);break;case"Stacked":case v.stacked:i.stacked(!0)}M.stacked=i.stacked(),E.stateChange(M),e.update()}}),E.on("changeState",function(t){"undefined"!=typeof t.disabled&&(S.forEach(function(e,n){e.disabled=t.disabled[n]}),M.disabled=t.disabled),"undefined"!=typeof t.stacked&&(i.
 stacked(t.stacked),M.stacked=t.stacked,O=t.stacked),e.update()}),N?(s.dispatch.on("elementMousemove",function(t){if(void 0!=t.pointXValue){var r,i,o,a,u=[];S.filter(function(t,e){return t.seriesIndex=e,!t.disabled}).forEach(function(s,l){i=n.domain().indexOf(t.pointXValue);var c=s.values[i];void 0!==c&&(a=c.x,void 0===r&&(r=c),void 0===o&&(o=t.mouseX),u.push({key:s.key,value:e.y()(c,i),color:p(s,s.seriesIndex),data:s.values[i]}))}),s.tooltip.data({value:a,index:i,series:u})(),s.renderGuideLine(o)}}),s.dispatch.on("elementMouseout",function(t){s.tooltip.hidden(!0)})):(i.dispatch.on("elementMouseover.tooltip",function(t){t.value=e.x()(t.data),t.series={key:t.data.key,value:e.y()(t.data),color:t.color},c.data(t).hidden(!1)}),i.dispatch.on("elementMouseout.tooltip",function(t){c.hidden(!0)}),i.dispatch.on("elementMousemove.tooltip",function(t){c()}))}),D.renderEnd("multibarchart immediate"),e}var n,r,i=t.models.multiBar(),o=t.models.axis(),a=t.models.axis(),s=t.interactiveGuideline(),u=
 t.models.legend(),l=t.models.legend(),c=t.models.tooltip(),f={top:30,right:20,bottom:50,left:60},d=null,h=null,p=t.utils.defaultColor(),g=!0,v={},m=!0,y=!0,b=!0,x=!1,w=!0,$=!1,k=!1,_=0,M=t.utils.state(),C=null,S=null,E=d3.dispatch("stateChange","changeState","renderEnd"),A=function(){return g?180:0},T=250,N=!1;M.stacked=!1,i.stacked(!1),o.orient("bottom").tickPadding(7).showMaxMin(!1).tickFormat(function(t){return t}),a.orient(x?"right":"left").tickFormat(d3.format(",.1f")),c.duration(0).valueFormatter(function(t,e){return a.tickFormat()(t,e)}).headerFormatter(function(t,e){return o.tickFormat()(t,e)}),l.updateState(!1);var D=t.utils.renderWatch(E),O=!1,j=function(t){return function(){return{active:t.map(function(t){return!t.disabled}),stacked:O}}},I=function(t){return function(e){void 0!==e.stacked&&(O=e.stacked),void 0!==e.active&&t.forEach(function(t,n){t.disabled=!e.active[n]})}};return e.dispatch=E,e.multibar=i,e.legend=u,e.controls=l,e.xAxis=o,e.yAxis=a,e.state=M,e.tooltip=c,e
 .interactiveLayer=s,e.options=t.utils.optionsFunc.bind(e),e._options=Object.create({},{width:{get:function(){return d},set:function(t){d=t}},height:{get:function(){return h},set:function(t){h=t}},showLegend:{get:function(){return m},set:function(t){m=t}},showControls:{get:function(){return g},set:function(t){g=t}},controlLabels:{get:function(){return v},set:function(t){v=t}},showXAxis:{get:function(){return y},set:function(t){y=t}},showYAxis:{get:function(){return b},set:function(t){b=t}},defaultState:{get:function(){return C},set:function(t){C=t}},noData:{get:function(){return S},set:function(t){S=t}},reduceXTicks:{get:function(){return w},set:function(t){w=t}},rotateLabels:{get:function(){return _},set:function(t){_=t}},staggerLabels:{get:function(){return $},set:function(t){$=t}},wrapLabels:{get:function(){return k},set:function(t){k=!!t}},margin:{get:function(){return f},set:function(t){f.top=void 0!==t.top?t.top:f.top,f.right=void 0!==t.right?t.right:f.right,f.bottom=void 0!==t
 .bottom?t.bottom:f.bottom,f.left=void 0!==t.left?t.left:f.left}},duration:{get:function(){return T},set:function(t){T=t,i.duration(T),o.duration(T),a.duration(T),D.reset(T)}},color:{get:function(){return p},set:function(e){p=t.utils.getColor(e),u.color(p)}},rightAlignYAxis:{get:function(){return x},set:function(t){x=t,a.orient(x?"right":"left")}},useInteractiveGuideline:{get:function(){return N},set:function(t){N=t}},barColor:{get:function(){return i.barColor},set:function(t){i.barColor(t),u.color(function(t,e){return d3.rgb("#ccc").darker(1.5*e).toString()})}}}),t.utils.inheritOptions(e,i),t.utils.initOptions(e),e},t.models.multiBarHorizontal=function(){"use strict";function e(d){return N.reset(),d.each(function(e){var d=c-l.left-l.right,A=f-l.top-l.bottom;h=d3.select(this),t.utils.initSVG(h),$&&(e=d3.layout.stack().offset("zero").values(function(t){return t.values}).y(m)(e)),e.forEach(function(t,e){t.values.forEach(function(n){n.series=e,n.key=t.key})}),$&&e[0].values.map(function
 (t,n){var r=0,i=0;e.map(function(t){var e=t.values[n];e.size=Math.abs(e.y),e.y<0?(e.y1=i-e.size,i-=e.size):(e.y1=r,r+=e.size)})});var D=r&&i?[]:e.map(function(t){return t.values.map(function(t,e){return{x:v(t,e),y:m(t,e),y0:t.y0,y1:t.y1}})});p.domain(r||d3.merge(D).map(function(t){return t.x})).rangeBands(o||[0,A],C),g.domain(i||d3.extent(d3.merge(D).map(function(t){return $?t.y>0?t.y1+t.y:t.y1:t.y}).concat(b))),k&&!$?g.range(a||[g.domain()[0]<0?M:0,d-(g.domain()[1]>0?M:0)]):g.range(a||[0,d]),s=s||p,u=u||d3.scale.linear().domain(g.domain()).range([g(0),g(0)]);var O=d3.select(this).selectAll("g.nv-wrap.nv-multibarHorizontal").data([e]),j=O.enter().append("g").attr("class","nvd3 nv-wrap nv-multibarHorizontal"),I=(j.append("defs"),j.append("g"));O.select("g");I.append("g").attr("class","nv-groups"),O.attr("transform","translate("+l.left+","+l.top+")");var L=O.select(".nv-groups").selectAll(".nv-group").data(function(t){return t},function(t,e){return e});L.enter().append("g").style("str
 oke-opacity",1e-6).style("fill-opacity",1e-6),L.exit().watchTransition(N,"multibarhorizontal: exit groups").style("stroke-opacity",1e-6).style("fill-opacity",1e-6).remove(),L.attr("class",function(t,e){return"nv-group nv-series-"+e}).classed("hover",function(t){return t.hover}).style("fill",function(t,e){return x(t,e)}).style("stroke",function(t,e){return x(t,e)}),L.watchTransition(N,"multibarhorizontal: groups").style("stroke-opacity",1).style("fill-opacity",S);var P=L.selectAll("g.nv-bar").data(function(t){return t.values});P.exit().remove();var F=P.enter().append("g").attr("transform",function(t,n,r){return"translate("+u($?t.y0:0)+","+($?0:r*p.rangeBand()/e.length+p(v(t,n)))+")"});F.append("rect").attr("width",0).attr("height",p.rangeBand()/($?1:e.length)),P.on("mouseover",function(t,e){d3.select(this).classed("hover",!0),T.elementMouseover({data:t,index:e,color:d3.select(this).style("fill")})}).on("mouseout",function(t,e){d3.select(this).classed("hover",!1),T.elementMouseout({da
 ta:t,index:e,color:d3.select(this).style("fill")})}).on("mouseout",function(t,e){T.elementMouseout({data:t,index:e,color:d3.select(this).style("fill")})}).on("mousemove",function(t,e){T.elementMousemove({data:t,index:e,color:d3.select(this).style("fill")})}).on("click",function(t,e){var n=this;T.elementClick({data:t,index:e,color:d3.select(this).style("fill"),event:d3.event,element:n}),d3.event.stopPropagation()}).on("dblclick",function(t,e){T.elementDblClick({data:t,index:e,color:d3.select(this).style("fill")}),d3.event.stopPropagation()}),y(e[0],0)&&(F.append("polyline"),P.select("polyline").attr("fill","none").attr("points",function(t,n){var r=y(t,n),i=.8*p.rangeBand()/(2*($?1:e.length));r=r.length?r:[-Math.abs(r),Math.abs(r)],r=r.map(function(t){return g(t)-g(0)});var o=[[r[0],-i],[r[0],i],[r[0],0],[r[1],0],[r[1],-i],[r[1],i]];return o.map(function(t){return t.join(",")}).join(" ")}).attr("transform",function(t,n){var r=p.rangeBand()/(2*($?1:e.length));return"translate("+(m(t,n)
 <0?0:g(m(t,n))-g(0))+", "+r+")"})),F.append("text"),k&&!$?(P.select("text").attr("text-anchor",function(t,e){return m(t,e)<0?"end":"start"}).attr("y",p.rangeBand()/(2*e.length)).attr("dy",".32em").text(function(t,e){var n=E(m(t,e)),r=y(t,e);return void 0===r?n:r.length?n+"+"+E(Math.abs(r[1]))+"-"+E(Math.abs(r[0])):n+"�"+E(Math.abs(r))}),P.watchTransition(N,"multibarhorizontal: bars").select("text").attr("x",function(t,e){return m(t,e)<0?-4:g(m(t,e))-g(0)+4})):P.selectAll("text").text(""),_&&!$?(F.append("text").classed("nv-bar-label",!0),P.select("text.nv-bar-label").attr("text-anchor",function(t,e){return m(t,e)<0?"start":"end"}).attr("y",p.rangeBand()/(2*e.length)).attr("dy",".32em").text(function(t,e){return v(t,e)}),P.watchTransition(N,"multibarhorizontal: bars").select("text.nv-bar-label").attr("x",function(t,e){return m(t,e)<0?g(0)-g(m(t,e))+4:-4})):P.selectAll("text.nv-bar-label").text(""),P.attr("class",function(t,e){return m(t,e)<0?"nv-bar negative":"nv-bar positive"}),w&&
 (n||(n=e.map(function(){return!0})),P.style("fill",function(t,e,r){return d3.rgb(w(t,e)).darker(n.map(function(t,e){return e}).filter(function(t,e){return!n[e]})[r]).toString()}).style("stroke",function(t,e,r){return d3.rgb(w(t,e)).darker(n.map(function(t,e){return e}).filter(function(t,e){return!n[e]})[r]).toString()})),$?P.watchTransition(N,"multibarhorizontal: bars").attr("transform",function(t,e){return"translate("+g(t.y1)+","+p(v(t,e))+")"}).select("rect").attr("width",function(t,e){return Math.abs(g(m(t,e)+t.y0)-g(t.y0))||0}).attr("height",p.rangeBand()):P.watchTransition(N,"multibarhorizontal: bars").attr("transform",function(t,n){return"translate("+g(m(t,n)<0?m(t,n):0)+","+(t.series*p.rangeBand()/e.length+p(v(t,n)))+")"}).select("rect").attr("height",p.rangeBand()/e.length).attr("width",function(t,e){return Math.max(Math.abs(g(m(t,e))-g(0)),1)||0}),s=p.copy(),u=g.copy()}),N.renderEnd("multibarHorizontal immediate"),e}var n,r,i,o,a,s,u,l={top:0,right:0,bottom:0,left:0},c=960,
 f=500,d=Math.floor(1e4*Math.random()),h=null,p=d3.scale.ordinal(),g=d3.scale.linear(),v=function(t){return t.x},m=function(t){return t.y},y=function(t){return t.yErr},b=[0],x=t.utils.defaultColor(),w=null,$=!1,k=!1,_=!1,M=60,C=.1,S=.75,E=d3.format(",.2f"),A=250,T=d3.dispatch("chartClick","elementClick","elementDblClick","elementMouseover","elementMouseout","elementMousemove","renderEnd"),N=t.utils.renderWatch(T,A);return e.dispatch=T,e.options=t.utils.optionsFunc.bind(e),e._options=Object.create({},{width:{get:function(){return c},set:function(t){c=t}},height:{get:function(){return f},set:function(t){f=t}},x:{get:function(){return v},set:function(t){v=t}},y:{get:function(){return m},set:function(t){m=t}},yErr:{get:function(){return y},set:function(t){y=t}},xScale:{get:function(){return p},set:function(t){p=t}},yScale:{get:function(){return g},set:function(t){g=t}},xDomain:{get:function(){return r},set:function(t){r=t}},yDomain:{get:function(){return i},set:function(t){i=t}},xRange:{
 get:function(){return o},set:function(t){o=t}},yRange:{get:function(){return a},set:function(t){a=t}},forceY:{get:function(){return b},set:function(t){b=t}},stacked:{get:function(){return $},set:function(t){$=t}},showValues:{get:function(){return k},set:function(t){k=t}},disabled:{get:function(){return n},set:function(t){n=t}},id:{get:function(){return d},set:function(t){d=t}},valueFormat:{get:function(){return E},set:function(t){E=t}},valuePadding:{get:function(){return M},set:function(t){M=t}},groupSpacing:{get:function(){return C},set:function(t){C=t}},fillOpacity:{get:function(){return S},set:function(t){S=t}},margin:{get:function(){return l},set:function(t){l.top=void 0!==t.top?t.top:l.top,l.right=void 0!==t.right?t.right:l.right,l.bottom=void 0!==t.bottom?t.bottom:l.bottom,l.left=void 0!==t.left?t.left:l.left}},duration:{get:function(){return A},set:function(t){A=t,N.reset(A)}},color:{get:function(){return x},set:function(e){x=t.utils.getColor(e)}},barColor:{get:function(){ret
 urn w},set:function(e){w=e?t.utils.getColor(e):null}}}),t.utils.initOptions(e),e},t.models.multiBarHorizontalChart=function(){"use strict";function e(l){return E.reset(),E.models(i),m&&E.models(o),y&&E.models(a),l.each(function(l){var $=d3.select(this);t.utils.initSVG($);var E=t.utils.availableWidth(f,$,c),A=t.utils.availableHeight(d,$,c);if(e.update=function(){$.transition().duration(M).call(e)},e.container=this,b=i.stacked(),x.setter(S(l),e.update).getter(C(l)).update(),x.disabled=l.map(function(t){return!!t.disabled}),!w){var T;w={};for(T in x)x[T]instanceof Array?w[T]=x[T].slice(0):w[T]=x[T]}if(!(l&&l.length&&l.filter(function(t){return t.values.length}).length))return t.utils.noData(e,$),e;$.selectAll(".nv-noData").remove(),n=i.xScale(),r=i.yScale().clamp(!0);var N=$.selectAll("g.nv-wrap.nv-multiBarHorizontalChart").data([l]),D=N.enter().append("g").attr("class","nvd3 nv-wrap nv-multiBarHorizontalChart").append("g"),O=N.select("g");if(D.append("g").attr("class","nv-x nv-axis"),
 D.append("g").attr("class","nv-y nv-axis").append("g").attr("class","nv-zeroLine").append("line"),
 D.append("g").attr("class","nv-barsWrap"),D.append("g").attr("class","nv-legendWrap"),D.append("g").attr("class","nv-controlsWrap"),v?(s.width(E-_()),O.select(".nv-legendWrap").datum(l).call(s),s.height()>c.top&&(c.top=s.height(),A=t.utils.availableHeight(d,$,c)),O.select(".nv-legendWrap").attr("transform","translate("+_()+","+-c.top+")")):O.select(".nv-legendWrap").selectAll("*").remove(),p){var j=[{key:g.grouped||"Grouped",disabled:i.stacked()},{key:g.stacked||"Stacked",disabled:!i.stacked()}];u.width(_()).color(["#444","#444","#444"]),O.select(".nv-controlsWrap").datum(j).attr("transform","translate(0,"+-c.top+")").call(u)}else O.select(".nv-controlsWrap").selectAll("*").remove();N.attr("transform","translate("+c.left+","+c.top+")"),i.disabled(l.map(function(t){return t.disabled})).width(E).height(A).color(l.map(function(t,e){return t.color||h(t,e)}).filter(function(t,e){return!l[e].disabled}));var I=O.select(".nv-barsWrap").datum(l.filter(function(t){return!t.disabled}));if(I.tr
 ansition().call(i),m){o.scale(n)._ticks(t.utils.calcTicksY(A/24,l)).tickSize(-E,0),O.select(".nv-x.nv-axis").call(o);var L=O.select(".nv-x.nv-axis").selectAll("g");L.selectAll("line, text")}y&&(a.scale(r)._ticks(t.utils.calcTicksX(E/100,l)).tickSize(-A,0),O.select(".nv-y.nv-axis").attr("transform","translate(0,"+A+")"),O.select(".nv-y.nv-axis").call(a)),O.select(".nv-zeroLine line").attr("x1",r(0)).attr("x2",r(0)).attr("y1",0).attr("y2",-A),s.dispatch.on("stateChange",function(t){for(var n in t)x[n]=t[n];k.stateChange(x),e.update()}),u.dispatch.on("legendClick",function(t,n){if(t.disabled){switch(j=j.map(function(t){return t.disabled=!0,t}),t.disabled=!1,t.key){case"Grouped":case g.grouped:i.stacked(!1);break;case"Stacked":case g.stacked:i.stacked(!0)}x.stacked=i.stacked(),k.stateChange(x),b=i.stacked(),e.update()}}),k.on("changeState",function(t){"undefined"!=typeof t.disabled&&(l.forEach(function(e,n){e.disabled=t.disabled[n]}),x.disabled=t.disabled),"undefined"!=typeof t.stacked&
 &(i.stacked(t.stacked),x.stacked=t.stacked,b=t.stacked),e.update()})}),E.renderEnd("multibar horizontal chart immediate"),e}var n,r,i=t.models.multiBarHorizontal(),o=t.models.axis(),a=t.models.axis(),s=t.models.legend().height(30),u=t.models.legend().height(30),l=t.models.tooltip(),c={top:30,right:20,bottom:50,left:60},f=null,d=null,h=t.utils.defaultColor(),p=!0,g={},v=!0,m=!0,y=!0,b=!1,x=t.utils.state(),w=null,$=null,k=d3.dispatch("stateChange","changeState","renderEnd"),_=function(){return p?180:0},M=250;x.stacked=!1,i.stacked(b),o.orient("left").tickPadding(5).showMaxMin(!1).tickFormat(function(t){return t}),a.orient("bottom").tickFormat(d3.format(",.1f")),l.duration(0).valueFormatter(function(t,e){return a.tickFormat()(t,e)}).headerFormatter(function(t,e){return o.tickFormat()(t,e)}),u.updateState(!1);var C=function(t){return function(){return{active:t.map(function(t){return!t.disabled}),stacked:b}}},S=function(t){return function(e){void 0!==e.stacked&&(b=e.stacked),void 0!==e.a
 ctive&&t.forEach(function(t,n){t.disabled=!e.active[n]})}},E=t.utils.renderWatch(k,M);return i.dispatch.on("elementMouseover.tooltip",function(t){t.value=e.x()(t.data),t.series={key:t.data.key,value:e.y()(t.data),color:t.color},l.data(t).hidden(!1)}),i.dispatch.on("elementMouseout.tooltip",function(t){l.hidden(!0)}),i.dispatch.on("elementMousemove.tooltip",function(t){l()}),e.dispatch=k,e.multibar=i,e.legend=s,e.controls=u,e.xAxis=o,e.yAxis=a,e.state=x,e.tooltip=l,e.options=t.utils.optionsFunc.bind(e),e._options=Object.create({},{width:{get:function(){return f},set:function(t){f=t}},height:{get:function(){return d},set:function(t){d=t}},showLegend:{get:function(){return v},set:function(t){v=t}},showControls:{get:function(){return p},set:function(t){p=t}},controlLabels:{get:function(){return g},set:function(t){g=t}},showXAxis:{get:function(){return m},set:function(t){m=t}},showYAxis:{get:function(){return y},set:function(t){y=t}},defaultState:{get:function(){return w},set:function(t)
 {w=t}},noData:{get:function(){return $},set:function(t){$=t}},margin:{get:function(){return c},set:function(t){c.top=void 0!==t.top?t.top:c.top,c.right=void 0!==t.right?t.right:c.right,c.bottom=void 0!==t.bottom?t.bottom:c.bottom,c.left=void 0!==t.left?t.left:c.left}},duration:{get:function(){return M},set:function(t){M=t,E.reset(M),i.duration(M),o.duration(M),a.duration(M)}},color:{get:function(){return h},set:function(e){h=t.utils.getColor(e),s.color(h)}},barColor:{get:function(){return i.barColor},set:function(t){i.barColor(t),s.color(function(t,e){return d3.rgb("#ccc").darker(1.5*e).toString()})}}}),t.utils.inheritOptions(e,i),t.utils.initOptions(e),e},t.models.multiChart=function(){"use strict";function e(l){return l.each(function(l){function h(t){var e=2===l[t.seriesIndex].yAxis?T:A;t.value=t.point.x,t.series={value:t.point.y,color:t.point.color,key:t.series.key},D.duration(0).headerFormatter(function(t,e){return E.tickFormat()(t,e)}).valueFormatter(function(t,n){return e.tick
 Format()(t,n)}).data(t).hidden(!1)}function O(t){var e=2===l[t.seriesIndex].yAxis?T:A;t.value=t.point.x,t.series={value:t.point.y,color:t.point.color,key:t.series.key},D.duration(100).headerFormatter(function(t,e){return E.tickFormat()(t,e)}).valueFormatter(function(t,n){return e.tickFormat()(t,n)}).data(t).hidden(!1)}function I(t){var e=2===l[t.seriesIndex].yAxis?T:A;t.point.x=C.x()(t.point),t.point.y=C.y()(t.point),D.duration(0).headerFormatter(function(t,e){return E.tickFormat()(t,e)}).valueFormatter(function(t,n){return e.tickFormat()(t,n)}).data(t).hidden(!1)}function L(t){var e=2===l[t.data.series].yAxis?T:A;t.value=_.x()(t.data),t.series={value:_.y()(t.data),color:t.color,key:t.data.key},D.duration(0).headerFormatter(function(t,e){return E.tickFormat()(t,e)}).valueFormatter(function(t,n){return e.tickFormat()(t,n)}).data(t).hidden(!1)}function P(){for(var t=0,e=j.length;t<e;t++){var n=j[t];try{n.clearHighlights()}catch(r){}}}function F(t,e,n){for(var r=0,i=j.length;r<i;r++){v
 ar o=j[r];try{o.highlightPoint(t,e,n)}catch(a){}}}var q=d3.select(this);t.utils.initSVG(q),e.update=function(){q.transition().call(e)},e.container=this;var z=t.utils.availableWidth(a,q,i),W=t.utils.availableHeight(s,q,i),R=l.filter(function(t){return"line"==t.type&&1==t.yAxis}),B=l.filter(function(t){return"line"==t.type&&2==t.yAxis}),V=l.filter(function(t){return"scatter"==t.type&&1==t.yAxis}),H=l.filter(function(t){return"scatter"==t.type&&2==t.yAxis}),U=l.filter(function(t){return"bar"==t.type&&1==t.yAxis}),Y=l.filter(function(t){return"bar"==t.type&&2==t.yAxis}),G=l.filter(function(t){return"area"==t.type&&1==t.yAxis}),X=l.filter(function(t){return"area"==t.type&&2==t.yAxis});if(!(l&&l.length&&l.filter(function(t){return t.values.length}).length))return t.utils.noData(e,q),e;q.selectAll(".nv-noData").remove();var Z=l.filter(function(t){return!t.disabled&&1==t.yAxis}).map(function(t){return t.values.map(function(t,e){return{x:c(t),y:f(t)}})}),Q=l.filter(function(t){return!t.disab
 led&&2==t.yAxis}).map(function(t){return t.values.map(function(t,e){return{x:c(t),y:f(t)}})});m.domain(d3.extent(d3.merge(Z.concat(Q)),function(t){return t.x})).range([0,z]);var K=q.selectAll("g.wrap.multiChart").data([l]),J=K.enter().append("g").attr("class","wrap nvd3 multiChart").append("g");J.append("g").attr("class","nv-x nv-axis"),J.append("g").attr("class","nv-y1 nv-axis"),J.append("g").attr("class","nv-y2 nv-axis"),J.append("g").attr("class","stack1Wrap"),J.append("g").attr("class","stack2Wrap"),J.append("g").attr("class","bars1Wrap"),J.append("g").attr("class","bars2Wrap"),J.append("g").attr("class","scatters1Wrap"),J.append("g").attr("class","scatters2Wrap"),J.append("g").attr("class","lines1Wrap"),J.append("g").attr("class","lines2Wrap"),J.append("g").attr("class","legendWrap"),J.append("g").attr("class","nv-interactive");var tt=K.select("g"),et=l.map(function(t,e){return l[e].color||o(t,e)});if(u){var nt=N.align()?z/2:z,rt=N.align()?nt:0;N.width(nt),N.color(et),tt.select
 (".legendWrap").datum(l.map(function(t){return t.originalKey=void 0===t.originalKey?t.key:t.originalKey,t.key=t.originalKey+(1==t.yAxis?"":v),t})).call(N),N.height()>i.top&&(i.top=N.height(),W=t.utils.availableHeight(s,q,i)),tt.select(".legendWrap").attr("transform","translate("+rt+","+-i.top+")")}else tt.select(".legendWrap").selectAll("*").remove();x.width(z).height(W).interpolate(d).color(et.filter(function(t,e){return!l[e].disabled&&1==l[e].yAxis&&"line"==l[e].type})),w.width(z).height(W).interpolate(d).color(et.filter(function(t,e){return!l[e].disabled&&2==l[e].yAxis&&"line"==l[e].type})),$.width(z).height(W).color(et.filter(function(t,e){return!l[e].disabled&&1==l[e].yAxis&&"scatter"==l[e].type})),k.width(z).height(W).color(et.filter(function(t,e){return!l[e].disabled&&2==l[e].yAxis&&"scatter"==l[e].type})),_.width(z).height(W).color(et.filter(function(t,e){return!l[e].disabled&&1==l[e].yAxis&&"bar"==l[e].type})),M.width(z).height(W).color(et.filter(function(t,e){return!l[e].d
 isabled&&2==l[e].yAxis&&"bar"==l[e].type})),C.width(z).height(W).interpolate(d).color(et.filter(function(t,e){return!l[e].disabled&&1==l[e].yAxis&&"area"==l[e].type})),S.width(z).height(W).interpolate(d).color(et.filter(function(t,e){return!l[e].disabled&&2==l[e].yAxis&&"area"==l[e].type})),tt.attr("transform","translate("+i.left+","+i.top+")");var it=tt.select(".lines1Wrap").datum(R.filter(function(t){return!t.disabled})),ot=tt.select(".scatters1Wrap").datum(V.filter(function(t){return!t.disabled})),at=tt.select(".bars1Wrap").datum(U.filter(function(t){return!t.disabled})),st=tt.select(".stack1Wrap").datum(G.filter(function(t){return!t.disabled})),ut=tt.select(".lines2Wrap").datum(B.filter(function(t){return!t.disabled})),lt=tt.select(".scatters2Wrap").datum(H.filter(function(t){return!t.disabled})),ct=tt.select(".bars2Wrap").datum(Y.filter(function(t){return!t.disabled})),ft=tt.select(".stack2Wrap").datum(X.filter(function(t){return!t.disabled})),dt=G.length?G.map(function(t){retu
 rn t.values}).reduce(function(t,e){return t.map(function(t,n){return{x:t.x,y:t.y+e[n].y}})}).concat([{x:0,y:0}]):[],ht=X.length?X.map(function(t){return t.values}).reduce(function(t,e){return t.map(function(t,n){return{x:t.x,y:t.y+e[n].y}})}).concat([{x:0,y:0}]):[];y.domain(n||d3.extent(d3.merge(Z).concat(dt),function(t){return t.y})).range([0,W]),b.domain(r||d3.extent(d3.merge(Q).concat(ht),function(t){return t.y})).range([0,W]),x.yDomain(y.domain()),$.yDomain(y.domain()),_.yDomain(y.domain()),C.yDomain(y.domain()),w.yDomain(b.domain()),k.yDomain(b.domain()),M.yDomain(b.domain()),S.yDomain(b.domain()),G.length&&d3.transition(st).call(C),X.length&&d3.transition(ft).call(S),U.length&&d3.transition(at).call(_),Y.length&&d3.transition(ct).call(M),R.length&&d3.transition(it).call(x),B.length&&d3.transition(ut).call(w),V.length&&d3.transition(ot).call($),H.length&&d3.transition(lt).call(k),E._ticks(t.utils.calcTicksX(z/100,l)).tickSize(-W,0),tt.select(".nv-x.nv-axis").attr("transform","t
 ranslate(0,"+W+")"),d3.transition(tt.select(".nv-x.nv-axis")).call(E),A._ticks(t.utils.calcTicksY(W/36,l)).tickSize(-z,0),d3.transition(tt.select(".nv-y1.nv-axis")).call(A),T._ticks(t.utils.calcTicksY(W/36,l)).tickSize(-z,0),d3.transition(tt.select(".nv-y2.nv-axis")).call(T),tt.select(".nv-y1.nv-axis").classed("nv-disabled",!Z.length).attr("transform","translate("+m.range()[0]+",0)"),tt.select(".nv-y2.nv-axis").classed("nv-disabled",!Q.length).attr("transform","translate("+m.range()[1]+",0)"),N.dispatch.on("stateChange",function(t){e.update()}),g&&(p.width(z).height(W).margin({left:i.left,top:i.top}).svgContainer(q).xScale(m),K.select(".nv-interactive").call(p)),g?(p.dispatch.on("elementMousemove",function(n){P();var r,i,a,s=[];l.filter(function(t,e){return t.seriesIndex=e,!t.disabled}).forEach(function(u,l){var c=m.domain(),f=u.values.filter(function(t,n){return e.x()(t,n)>=c[0]&&e.x()(t,n)<=c[1]});i=t.interactiveBisect(f,n.pointXValue,e.x());var d=f[i],h=e.y()(d,i);null!==h&&F(l,i
 ,!0),void 0!==d&&(void 0===r&&(r=d),void 0===a&&(a=m(e.x()(d,i))),s.push({key:u.key,value:h,color:o(u,u.seriesIndex),data:d,yAxis:2==u.yAxis?T:A}))});var u=function(t,e){var n=s[e].yAxis;return null==t?"N/A":n.tickFormat()(t)};p.tooltip.headerFormatter(function(t,e){return E.tickFormat()(t,e)}).valueFormatter(p.tooltip.valueFormatter()||u).data({value:e.x()(r,i),index:i,series:s})(),p.renderGuideLine(a)}),p.dispatch.on("elementMouseout",function(t){P()})):(x.dispatch.on("elementMouseover.tooltip",h),w.dispatch.on("elementMouseover.tooltip",h),x.dispatch.on("elementMouseout.tooltip",function(t){D.hidden(!0)}),w.dispatch.on("elementMouseout.tooltip",function(t){D.hidden(!0)}),$.dispatch.on("elementMouseover.tooltip",O),k.dispatch.on("elementMouseover.tooltip",O),$.dispatch.on("elementMouseout.tooltip",function(t){D.hidden(!0)}),k.dispatch.on("elementMouseout.tooltip",function(t){D.hidden(!0)}),C.dispatch.on("elementMouseover.tooltip",I),S.dispatch.on("elementMouseover.tooltip",I),C.di
 spatch.on("elementMouseout.tooltip",function(t){D.hidden(!0)}),S.dispatch.on("elementMouseout.tooltip",function(t){D.hidden(!0)}),_.dispatch.on("elementMouseover.tooltip",L),M.dispatch.on("elementMouseover.tooltip",L),_.dispatch.on("elementMouseout.tooltip",function(t){D.hidden(!0)}),M.dispatch.on("elementMouseout.tooltip",function(t){D.hidden(!0)}),_.dispatch.on("elementMousemove.tooltip",function(t){D()}),M.dispatch.on("elementMousemove.tooltip",function(t){D()}))}),e}var n,r,i={top:30,right:20,bottom:50,left:60},o=t.utils.defaultColor(),a=null,s=null,u=!0,l=null,c=function(t){return t.x},f=function(t){return t.y},d="linear",h=!0,p=t.interactiveGuideline(),g=!1,v=" (right axis)",m=d3.scale.linear(),y=d3.scale.linear(),b=d3.scale.linear(),x=t.models.line().yScale(y),w=t.models.line().yScale(b),$=t.models.scatter().yScale(y),k=t.models.scatter().yScale(b),_=t.models.multiBar().stacked(!1).yScale(y),M=t.models.multiBar().stacked(!1).yScale(b),C=t.models.stackedArea().yScale(y),S=t.mo
 dels.stackedArea().yScale(b),E=t.models.axis().scale(m).orient("bottom").tickPadding(5),A=t.models.axis().scale(y).orient("left"),T=t.models.axis().scale(b).orient("right"),N=t.models.legend().height(30),D=t.models.tooltip(),O=d3.dispatch(),j=[x,w,$,k,_,M,C,S];return e.dispatch=O,e.legend=N,e.lines1=x,e.lines2=w,e.scatters1=$,e.scatters2=k,e.bars1=_,e.bars2=M,e.stack1=C,e.stack2=S,e.xAxis=E,e.yAxis1=A,e.yAxis2=T,e.tooltip=D,e.interactiveLayer=p,e.options=t.utils.optionsFunc.bind(e),e._options=Object.create({},{width:{get:function(){return a},set:function(t){a=t}},height:{get:function(){return s},set:function(t){s=t}},showLegend:{get:function(){return u},set:function(t){u=t}},yDomain1:{get:function(){return n},set:function(t){n=t}},yDomain2:{get:function(){return r},set:function(t){r=t}},noData:{get:function(){return l},set:function(t){l=t}},interpolate:{get:function(){return d},set:function(t){d=t}},legendRightAxisHint:{get:function(){return v},set:function(t){v=t}},margin:{get:func
 tion(){return i},set:function(t){i.top=void 0!==t.top?t.top:i.top,i.right=void 0!==t.right?t.right:i.right,i.bottom=void 0!==t.bottom?t.bottom:i.bottom,i.left=void 0!==t.left?t.left:i.left}},color:{get:function(){return o},set:function(e){o=t.utils.getColor(e)}},x:{get:function(){return c},set:function(t){c=t,x.x(t),w.x(t),$.x(t),k.x(t),_.x(t),M.x(t),C.x(t),S.x(t)}},y:{get:function(){return f},set:function(t){f=t,x.y(t),w.y(t),$.y(t),k.y(t),C.y(t),S.y(t),_.y(t),M.y(t)}},useVoronoi:{get:function(){return h},set:function(t){h=t,x.useVoronoi(t),w.useVoronoi(t),C.useVoronoi(t),S.useVoronoi(t)}},useInteractiveGuideline:{get:function(){return g},set:function(t){g=t,g&&(x.interactive(!1),x.useVoronoi(!1),w.interactive(!1),w.useVoronoi(!1),C.interactive(!1),C.useVoronoi(!1),S.interactive(!1),S.useVoronoi(!1),$.interactive(!1),k.interactive(!1))}}}),t.utils.initOptions(e),e},t.models.ohlcBar=function(){"use strict";function e(_){return _.each(function(e){c=d3.select(this);var _=t.utils.avail
 ableWidth(s,c,a),C=t.utils.availableHeight(u,c,a);t.utils.initSVG(c);var S=_/e[0].values.length*.9;f.domain(n||d3.extent(e[0].values.map(h).concat(b))),w?f.range(i||[.5*_/e[0].values.length,_*(e[0].values.length-.5)/e[0].values.length]):f.range(i||[5+S/2,_-S/2-5]),d.domain(r||[d3.min(e[0].values.map(y).concat(x)),d3.max(e[0].values.map(m).concat(x))]).range(o||[C,0]),f.domain()[0]===f.domain()[1]&&(f.domain()[0]?f.domain([f.domain()[0]-.01*f.domain()[0],f.domain()[1]+.01*f.domain()[1]]):f.domain([-1,1])),d.domain()[0]===d.domain()[1]&&(d.domain()[0]?d.domain([d.domain()[0]+.01*d.domain()[0],d.domain()[1]-.01*d.domain()[1]]):d.domain([-1,1]));var E=d3.select(this).selectAll("g.nv-wrap.nv-ohlcBar").data([e[0].values]),A=E.enter().append("g").attr("class","nvd3 nv-wrap nv-ohlcBar"),T=A.append("defs"),N=A.append("g"),D=E.select("g");N.append("g").attr("class","nv-ticks"),E.attr("transform","translate("+a.left+","+a.top+")"),c.on("click",function(t,e){M.chartClick({data:t,index:e,pos:d3.
 event,id:l})}),T.append("clipPath").attr("id","nv-chart-clip-path-"+l).append("rect"),E.select("#nv-chart-clip-path-"+l+" rect").attr("width",_).attr("height",C),D.attr("clip-path",$?"url(#nv-chart-clip-path-"+l+")":"");var O=E.select(".nv-ticks").selectAll(".nv-tick").data(function(t){return t});O.exit().remove(),O.enter().append("path").attr("class",function(t,e,n){return(g(t,e)>v(t,e)?"nv-tick negative":"nv-tick positive")+" nv-tick-"+n+"-"+e}).attr("d",function(t,e){return"m0,0l0,"+(d(g(t,e))-d(m(t,e)))+"l"+-S/2+",0l"+S/2+",0l0,"+(d(y(t,e))-d(g(t,e)))+"l0,"+(d(v(t,e))-d(y(t,e)))+"l"+S/2+",0l"+-S/2+",0z"}).attr("transform",function(t,e){return"translate("+f(h(t,e))+","+d(m(t,e))+")"}).attr("fill",function(t,e){return k[0]}).attr("stroke",function(t,e){return k[0]}).attr("x",0).attr("y",function(t,e){return d(Math.max(0,p(t,e)))}).attr("height",function(t,e){return Math.abs(d(p(t,e))-d(0))}),O.attr("class",function(t,e,n){return(g(t,e)>v(t,e)?"nv-tick negative":"nv-tick positive")
 +" nv-tick-"+n+"-"+e}),d3.transition(O).attr("transform",function(t,e){return"translate("+f(h(t,e))+","+d(m(t,e))+")"}).attr("d",function(t,n){var r=_/e[0].values.length*.9;return"m0,0l0,"+(d(g(t,n))-d(m(t,n)))+"l"+-r/2+",0l"+r/2+",0l0,"+(d(y(t,n))-d(g(t,n)))+"l0,"+(d(v(t,n))-d(y(t,n)))+"l"+r/2+",0l"+-r/2+",0z"})}),e}var n,r,i,o,a={top:0,right:0,bottom:0,left:0},s=null,u=null,l=Math.floor(1e4*Math.random()),c=null,f=d3.scale.linear(),d=d3.scale.linear(),h=function(t){return t.x},p=function(t){return t.y},g=function(t){return t.open},v=function(t){return t.close},m=function(t){return t.high},y=function(t){return t.low},b=[],x=[],w=!1,$=!0,k=t.utils.defaultColor(),_=!1,M=d3.dispatch("stateChange","changeState","renderEnd","chartClick","elementClick","elementDblClick","elementMouseover","elementMouseout","elementMousemove");return e.highlightPoint=function(t,n){e.clearHighlights(),c.select(".nv-ohlcBar .nv-tick-0-"+t).classed("hover",n)},e.clearHighlights=function(){c.select(".nv-ohlcB
 ar .nv-tick.hover").classed("hover",!1)},e.dispatch=M,e.options=t.utils.optionsFunc.bind(e),e._options=Object.create({},{width:{get:function(){return s},set:function(t){s=t}},height:{get:function(){return u},set:function(t){u=t}},xScale:{get:function(){return f},set:function(t){f=t}},yScale:{get:function(){return d},set:function(t){d=t}},xDomain:{get:function(){return n},set:function(t){n=t}},yDomain:{get:function(){return r},set:function(t){r=t}},xRange:{get:function(){return i},set:function(t){i=t}},yRange:{get:function(){return o},set:function(t){o=t}},forceX:{get:function(){return b},set:function(t){b=t}},forceY:{get:function(){return x},set:function(t){x=t}},padData:{get:function(){return w},set:function(t){w=t}},clipEdge:{get:function(){return $},set:function(t){$=t}},id:{get:function(){return l},set:function(t){l=t}},interactive:{get:function(){return _},set:function(t){_=t}},x:{get:function(){return h},set:function(t){h=t}},y:{get:function(){return p},set:function(t){p=t}},o
 pen:{get:function(){return g()},set:function(t){g=t}},close:{get:function(){return v()},set:function(t){v=t}},high:{get:function(){return m},set:function(t){m=t}},low:{get:function(){return y},set:function(t){y=t}},margin:{get:function(){return a},set:function(t){a.top=void 0!=t.top?t.top:a.top,a.right=void 0!=t.right?t.right:a.right,a.bottom=void 0!=t.bottom?t.bottom:a.bottom,a.left=void 0!=t.left?t.left:a.left}},color:{get:function(){return k},set:function(e){k=t.utils.getColor(e)}}}),t.utils.initOptions(e),e},t.models.parallelCoordinates=function(){"use strict";function e(S){return C.reset(),S.each(function(e){function C(t){return k(p.map(function(e){if(isNaN(t.values[e.key])||isNaN(parseFloat(t.values[e.key]))||z){var n=f[e.key].domain(),r=f[e.key].range(),i=n[0]-(n[1]-n[0])/9;if(w.indexOf(e.key)<0){var o=d3.scale.linear().domain([i,n[1]]).range([l-12,r[1]]);f[e.key].brush.y(o),w.push(e.key)}if(isNaN(t.values[e.key])||isNaN(parseFloat(t.values[e.key])))return[c(e.key),f[e.key](i
 )]}return void 0!==U&&(w.length>0||z?(U.style("display","inline"),Y.style("display","inline")):(U.style("display","none"),Y.style("display","none"))),[c(e.key),f[e.key](t.values[e.key])]}))}function S(t){y.forEach(function(e){var n=f[e.dimension].brush.y().domain();e.hasOnlyNaN&&(e.extent[1]=(f[e.dimension].domain()[1]-n[0])*(e.extent[1]-e.extent[0])/(q[e.dimension]-e.extent[0])+n[0]),e.hasNaN&&(e.extent[0]=n[0]),t&&f[e.dimension].brush.extent(e.extent)}),i.select(".nv-brushBackground").each(function(t){d3.select(this).call(f[t.key].brush)}).selectAll("rect").attr("x",-8).attr("width",16),N()}function E(){v===!1&&(v=!0,S(!0))}function A(){K=g.filter(function(t){return!f[t].brush.empty()}),J=K.map(function(t){return f[t].brush.extent()}),y=[],K.forEach(function(t,e){y[e]={dimension:t,extent:J[e],hasNaN:!1,hasOnlyNaN:!1}}),b=[],n.style("display",function(t){var e=K.every(function(e,n){return!(!isNaN(t.values[e])&&!isNaN(parseFloat(t.values[e]))||J[n][0]!=f[e].brush.y().domain()[0])||J
 [n][0]<=t.values[e]&&t.values[e]<=J[n][1]&&!isNaN(parseFloat(t.values[e]))});return e&&b.push(t),e?null:"none"}),N(),M.brush({filters:y,active:b})}function T(){var t=K.length>0;y.forEach(function(t){t.extent[0]===f[t.dimension].brush.y().domain()[0]&&w.indexOf(t.dimension)>=0&&(t.hasNaN=!0),t.extent[1]<f[t.dimension].domain()[0]&&(t.hasOnlyNaN=!0)}),M.brushEnd(b,t)}function N(){i.select(".nv-axis").each(function(t,e){var n=y.filter(function(e){return e.dimension==t.key});W[t.key]=f[t.key].domain(),0!=n.length&&v&&(W[t.key]=[],n[0].extent[1]>f[t.key].domain()[0]&&(W[t.key]=[n[0].extent[1]]),n[0].extent[0]>=f[t.key].domain()[0]&&W[t.key].push(n[0].extent[0])),d3.select(this).call(_.scale(f[t.key]).tickFormat(t.format).tickValues(W[t.key]))})}function D(t){x[t.key]=this.parentNode.__origin__=c(t.key),r.attr("visibility","hidden")}function O(t){x[t.key]=Math.min(u,Math.max(0,this.parentNode.__origin__+=d3.event.x)),n.attr("d",C),p.sort(function(t,e){return I(t.key)-I(e.key)}),p.forEach(
 function(t,e){return t.currentPosition=e}),c.domain(p.map(function(t){return t.key})),i.attr("transform",function(t){return"translate("+I(t.key)+")"})}function j(t,e){delete this.parentNode.__origin__,delete x[t.key],d3.select(this.parentNode).attr("transform","translate("+c(t.key)+")"),n.attr("d",C),r.attr("d",C).attr("visibility",null),M.dimensionsOrder(p)}function I(t){var e=x[t];return null==e?c(t):e}var L=d3.select(this);if(u=t.utils.availableWidth(a,L,o),l=t.utils.availableHeight(s,L,o),t.utils.initSVG(L),void 0===e[0].values){var P=[];e.forEach(function(t){var e={},n=Object.keys(t);n.forEach(function(n){"name"!==n&&(e[n]=t[n])}),P.push({key:t.name,values:e})}),e=P}var F=e.map(function(t){return t.values});0===b.length&&(b=e),g=h.sort(function(t,e){return t.currentPosition-e.currentPosition}).map(function(t){return t.key}),p=h.filter(function(t){return!t.disabled}),c.rangePoints([0,u],1).domain(p.map(function(t){return t.key}));var q={},z=!1,W=[];g.forEach(function(t){var e=d3
 .extent(F,function(e){return+e[t]}),n=e[0],r=e[1],i=!1;(isNaN(n)||isNaN(r))&&(i=!0,n=0,r=0),n===r&&(n-=1,r+=1);var o=y.filter(function(e){return e.dimension==t});0!==o.length&&(i?(n=f[t].domain()[0],r=f[t].domain()[1]):!o[0].hasOnlyNaN&&v?(n=n>o[0].extent[0]?o[0].extent[0]:n,r=r<o[0].extent[1]?o[0].extent[1]:r):o[0].hasNaN&&(r=r<o[0].extent[1]?o[0].extent[1]:r,q[t]=f[t].domain()[1],z=!0)),f[t]=d3.scale.linear().domain([n,r]).range([.9*(l-12),0]),w=[],f[t].brush=d3.svg.brush().y(f[t]).on("brushstart",E).on("brush",A).on("brushend",T)});var R=L.selectAll("g.nv-wrap.nv-parallelCoordinates").data([e]),B=R.enter().append("g").attr("class","nvd3 nv-wrap nv-parallelCoordinates"),V=B.append("g"),H=R.select("g");V.append("g").attr("class","nv-parallelCoordinates background"),V.append("g").attr("class","nv-parallelCoordinates foreground"),V.append("g").attr("class","nv-parallelCoordinates missingValuesline"),R.attr("transform","translate("+o.left+","+o.top+")"),k.interpolate("cardinal").tensi
 on($),_.orient("left");var U,Y,G=d3.behavior.drag().on("dragstart",D).on("drag",O).on("dragend",j),X=c.range()[1]-c.range()[0];if(!isNaN(X)){var Z=[0+X/2,l-12,u-X/2,l-12];U=R.select(".missingValuesline").selectAll("line").data([Z]),U.enter().append("line"),U.exit().remove(),U.attr("x1",function(t){return t[0]}).attr("y1",function(t){return t[1]}).attr("x2",function(t){return t[2]}).attr("y2",function(t){return t[3]}),Y=R.select(".missingValuesline").selectAll("text").data([d]),Y.append("text").data([d]),Y.enter().append("text"),Y.exit().remove(),Y.attr("y",l).attr("x",u-92-X/2).text(function(t){return t})}r=R.select(".background").selectAll("path").data(e),r.enter().append("path"),r.exit().remove(),r.attr("d",C),n=R.select(".foreground").selectAll("path").data(e),n.enter().append("path"),n.exit().remove(),n.attr("d",C).style("stroke-width",function(t,e){return isNaN(t.strokeWidth)&&(t.strokeWidth=1),t.strokeWidth}).attr("stroke",function(t,e){return t.color||m(t,e)}),n.on("mouseover
 ",function(t,e){d3.select(this).classed("hover",!0).style("stroke-width",t.strokeWidth+2+"px").style("stroke-opacity",1),M.elementMouseover({label:t.name,color:t.color||m(t,e),values:t.values,dimensions:p})}),n.on("mouseout",function(t,e){d3.select(this).classed("hover",!1).style("stroke-width",t.strokeWidth+"px").style("stroke-opacity",.7),M.elementMouseout({label:t.name,index:e})}),n.on("mousemove",function(t,e){M.elementMousemove()}),n.on("click",function(t){M.elementClick({id:t.id})}),i=H.selectAll(".dimension").data(p);var Q=i.enter().append("g").attr("class","nv-parallelCoordinates dimension");i.attr("transform",function(t){return"translate("+c(t.key)+",0)"}),Q.append("g").attr("class","nv-axis"),Q.append("text").attr("class","nv-label").style("cursor","move").attr("dy","-1em").attr("text-anchor","middle").on("mouseover",function(t,e){M.elementMouseover({label:t.tooltip||t.key,color:t.color})}).on("mouseout",function(t,e){M.elementMouseout({label:t.tooltip})}).on("mousemove",f
 unction(t,e){M.elementMousemove()}).call(G),Q.append("g").attr("class","nv-brushBackground"),i.exit().remove(),i.select(".nv-label").text(function(t){return t.key}),S(v);var K=g.filter(function(t){return!f[t].brush.empty()}),J=K.map(function(t){return f[t].brush.extent()}),tt=b.slice(0);b=[],n.style("display",function(t){var e=K.every(function(e,n){return!(!isNaN(t.values[e])&&!isNaN(parseFloat(t.values[e]))||J[n][0]!=f[e].brush.y().domain()[0])||J[n][0]<=t.values[e]&&t.values[e]<=J[n][1]&&!isNaN(parseFloat(t.values[e]))});return e&&b.push(t),e?null:"none"}),(y.length>0||!t.utils.arrayEquals(b,tt))&&M.activeChanged(b)}),e}var n,r,i,o={top:30,right:0,bottom:10,left:0},a=null,s=null,u=null,l=null,c=d3.scale.ordinal(),f={},d="undefined values",h=[],p=[],g=[],v=!0,m=t.utils.defaultColor(),y=[],b=[],x=[],w=[],$=1,k=d3.svg.line(),_=d3.svg.axis(),M=d3.dispatch("brushstart","brush","brushEnd","dimensionsOrder","stateChange","elementClick","elementMouseover","elementMouseout","elementMousemo
 ve","renderEnd","activeChanged"),C=t.utils.renderWatch(M);return e.dispatch=M,e.options=t.utils.optionsFunc.bind(e),e._options=Object.create({},{width:{get:function(){return a},set:function(t){a=t}},height:{get:function(){return s},set:function(t){s=t}},dimensionData:{get:function(){return h},set:function(t){h=t}},displayBrush:{get:function(){return v},set:function(t){v=t}},filters:{get:function(){return y},set:function(t){y=t}},active:{get:function(){return b},set:function(t){b=t}},lineTension:{get:function(){return $},set:function(t){$=t}},undefinedValuesLabel:{get:function(){return d},set:function(t){d=t}},dimensions:{get:function(){return h.map(function(t){return t.key})},set:function(e){t.deprecated("dimensions","use dimensionData instead"),0===h.length?e.forEach(function(t){h.push({key:t})}):e.forEach(function(t,e){h[e].key=t})}},dimensionNames:{get:function(){return h.map(function(t){return t.key})},set:function(e){t.deprecated("dimensionNames","use dimensionData instead"),g=
 [],0===h.length?e.forEach(function(t){h.push({key:t})}):e.forEach(function(t,e){h[e].key=t})}},dimensionFormats:{get:function(){return h.map(function(t){return t.format})},set:function(e){t.deprecated("dimensionFormats","use dimensionData instead"),0===h.length?e.forEach(function(t){h.push({format:t})}):e.forEach(function(t,e){h[e].format=t})}},margin:{get:function(){return o},set:function(t){o.top=void 0!==t.top?t.top:o.top,o.right=void 0!==t.right?t.right:o.right,o.bottom=void 0!==t.bottom?t.bottom:o.bottom,o.left=void 0!==t.left?t.left:o.left}},color:{get:function(){return m},set:function(e){m=t.utils.getColor(e)}}}),t.utils.initOptions(e),e},t.models.parallelCoordinatesChart=function(){"use strict";function e(i){return m.reset(),m.models(n),i.each(function(i){var l=d3.select(this);t.utils.initSVG(l);var p=t.utils.availableWidth(a,l,o),g=t.utils.availableHeight(s,l,o);if(e.update=function(){l.call(e)},e.container=this,c.setter(b(f),e.update).getter(y(f)).update(),c.disabled=f.map
 (function(t){return!!t.disabled}),f=f.map(function(t){return t.disabled=!!t.disabled,t}),f.forEach(function(t,e){t.originalPosition=isNaN(t.originalPosition)?e:t.originalPosition,t.currentPosition=isNaN(t.currentPosition)?e:t.currentPosition}),!h){var m;h={};for(m in c)c[m]instanceof Array?h[m]=c[m].slice(0):h[m]=c[m]}if(!i||!i.length)return t.utils.noData(e,l),e;l.selectAll(".nv-noData").remove();var x=l.selectAll("g.nv-wrap.nv-parallelCoordinatesChart").data([i]),w=x.enter().append("g").attr("class","nvd3 nv-wrap nv-parallelCoordinatesChart").append("g"),$=x.select("g");w.append("g").attr("class","nv-parallelCoordinatesWrap"),w.append("g").attr("class","nv-legendWrap"),$.select("rect").attr("width",p).attr("height",g>0?g:0),u?(r.width(p).color(function(t){return"rgb(188,190,192)"}),$.select(".nv-legendWrap").datum(f.sort(function(t,e){return t.originalPosition-e.originalPosition})).call(r),r.height()>o.top&&(o.top=r.height(),g=t.utils.availableHeight(s,l,o)),x.select(".nv-legendWr
 ap").attr("transform","translate( 0 ,"+-o.top+")")):$.select(".nv-legendWrap").selectAll("*").remove(),x.attr("transform","translate("+o.left+","+o.top+")"),n.width(p).height(g).dimensionData(f).displayBrush(d);var k=$.select(".nv-parallelCoordinatesWrap ").datum(i);k.transition().call(n),n.dispatch.on("brushEnd",function(t,e){e?(d=!0,v.brushEnd(t)):d=!1}),r.dispatch.on("stateChange",function(t){for(var n in t)c[n]=t[n];v.stateChange(c),e.update()}),n.dispatch.on("dimensionsOrder",function(t){f.sort(function(t,e){return t.currentPosition-e.currentPosition});var e=!1;f.forEach(function(t,n){t.currentPosition=n,t.currentPosition!==t.originalPosition&&(e=!0)}),v.dimensionsOrder(f,e)}),v.on("changeState",function(t){"undefined"!=typeof t.disabled&&(f.forEach(function(e,n){e.disabled=t.disabled[n]}),c.disabled=t.disabled),e.update()})}),m.renderEnd("parraleleCoordinateChart immediate"),e}var n=t.models.parallelCoordinates(),r=t.models.legend(),i=t.models.tooltip(),o=(t.models.tooltip(),{
 top:0,right:0,bottom:0,left:0}),a=null,s=null,u=!0,l=t.utils.defaultColor(),c=t.utils.state(),f=[],d=!0,h=null,p=null,g="undefined",v=d3.dispatch("dimensionsOrder","brushEnd","stateChange","changeState","renderEnd"),m=t.utils.renderWatch(v),y=function(t){
 return function(){return{active:t.map(function(t){return!t.disabled})}}},b=function(t){return function(e){void 0!==e.active&&t.forEach(function(t,n){t.disabled=!e.active[n]})}};return i.contentGenerator(function(t){var e='<table><thead><tr><td class="legend-color-guide"><div style="background-color:'+t.color+'"></div></td><td><strong>'+t.key+"</strong></td></tr></thead>";return 0!==t.series.length&&(e+='<tbody><tr><td height ="10px"></td></tr>',t.series.forEach(function(t){e=e+'<tr><td class="legend-color-guide"><div style="background-color:'+t.color+'"></div></td><td class="key">'+t.key+'</td><td class="value">'+t.value+"</td></tr>"}),e+="</tbody>"),e+="</table>"}),n.dispatch.on("elementMouseover.tooltip",function(t){var e={key:t.label,color:t.color,series:[]};t.values&&(Object.keys(t.values).forEach(function(n){var r=t.dimensions.filter(function(t){return t.key===n})[0];if(r){var i;i=isNaN(t.values[n])||isNaN(parseFloat(t.values[n]))?g:r.format(t.values[n]),e.series.push({idx:r.cu
 rrentPosition,key:n,value:i,color:r.color})}}),e.series.sort(function(t,e){return t.idx-e.idx})),i.data(e).hidden(!1)}),n.dispatch.on("elementMouseout.tooltip",function(t){i.hidden(!0)}),n.dispatch.on("elementMousemove.tooltip",function(){i()}),e.dispatch=v,e.parallelCoordinates=n,e.legend=r,e.tooltip=i,e.options=t.utils.optionsFunc.bind(e),e._options=Object.create({},{width:{get:function(){return a},set:function(t){a=t}},height:{get:function(){return s},set:function(t){s=t}},showLegend:{get:function(){return u},set:function(t){u=t}},defaultState:{get:function(){return h},set:function(t){h=t}},dimensionData:{get:function(){return f},set:function(t){f=t}},displayBrush:{get:function(){return d},set:function(t){d=t}},noData:{get:function(){return p},set:function(t){p=t}},nanValue:{get:function(){return g},set:function(t){g=t}},margin:{get:function(){return o},set:function(t){o.top=void 0!==t.top?t.top:o.top,o.right=void 0!==t.right?t.right:o.right,o.bottom=void 0!==t.bottom?t.bottom:o.
 bottom,o.left=void 0!==t.left?t.left:o.left}},color:{get:function(){return l},set:function(e){l=t.utils.getColor(e),r.color(l),n.color(l)}}}),t.utils.inheritOptions(e,n),t.utils.initOptions(e),e},t.models.pie=function(){"use strict";function e(N){return T.reset(),N.each(function(e){function N(t,e){t.endAngle=isNaN(t.endAngle)?0:t.endAngle,t.startAngle=isNaN(t.startAngle)?0:t.startAngle,g||(t.innerRadius=0);var n=d3.interpolate(this._current,t);return this._current=n(0),function(t){return E[e](n(t))}}var D=r-n.left-n.right,O=i-n.top-n.bottom,j=Math.min(D,O)/2,I=[],L=[];if(u=d3.select(this),0===C.length)for(var P=j-j/5,F=_*j,q=0;q<e[0].length;q++)I.push(P),L.push(F);else m?(I=C.map(function(t){return(t.outer-t.outer/5)*j}),L=C.map(function(t){return(t.inner-t.inner/5)*j}),_=d3.min(C.map(function(t){return t.inner-t.inner/5}))):(I=C.map(function(t){return t.outer*j}),L=C.map(function(t){return t.inner*j}),_=d3.min(C.map(function(t){return t.inner})));t.utils.initSVG(u);var z=u.selectAl
 l(".nv-wrap.nv-pie").data(e),W=z.enter().append("g").attr("class","nvd3 nv-wrap nv-pie nv-chart-"+s),R=W.append("g"),B=z.select("g"),V=R.append("g").attr("class","nv-pie");R.append("g").attr("class","nv-pieLabels"),z.attr("transform","translate("+n.left+","+n.top+")"),B.select(".nv-pie").attr("transform","translate("+D/2+","+O/2+")"),B.select(".nv-pieLabels").attr("transform","translate("+D/2+","+O/2+")"),u.on("click",function(t,e){S.chartClick({data:t,index:e,pos:d3.event,id:s})}),E=[],A=[];for(var q=0;q<e[0].length;q++){var H=d3.svg.arc().outerRadius(I[q]),U=d3.svg.arc().outerRadius(I[q]+5);x!==!1&&(H.startAngle(x),U.startAngle(x)),$!==!1&&(H.endAngle($),U.endAngle($)),g&&(H.innerRadius(L[q]),U.innerRadius(L[q])),H.cornerRadius&&k&&(H.cornerRadius(k),U.cornerRadius(k)),E.push(H),A.push(U)}var Y=d3.layout.pie().sort(null).value(function(t){return t.disabled?0:a(t)});Y.padAngle&&w&&Y.padAngle(w),g&&v&&(V.append("text").attr("class","nv-pie-title"),z.select(".nv-pie-title").style("te
 xt-anchor","middle").text(function(t){return v}).style("font-size",Math.min(D,O)*_*2/(v.length+2)+"px").attr("dy","0.35em").attr("transform",function(t,e){return"translate(0, "+y+")"}));var G=z.select(".nv-pie").selectAll(".nv-slice").data(Y),X=z.select(".nv-pieLabels").selectAll(".nv-label").data(Y);G.exit().remove(),X.exit().remove();var Z=G.enter().append("g");Z.attr("class","nv-slice"),Z.on("mouseover",function(t,e){d3.select(this).classed("hover",!0),m&&d3.select(this).select("path").transition().duration(70).attr("d",A[e]),S.elementMouseover({data:t.data,index:e,color:d3.select(this).style("fill"),percent:(t.endAngle-t.startAngle)/(2*Math.PI)})}),Z.on("mouseout",function(t,e){d3.select(this).classed("hover",!1),m&&d3.select(this).select("path").transition().duration(50).attr("d",E[e]),S.elementMouseout({data:t.data,index:e})}),Z.on("mousemove",function(t,e){S.elementMousemove({data:t.data,index:e})}),Z.on("click",function(t,e){var n=this;S.elementClick({data:t.data,index:e,col
 or:d3.select(this).style("fill"),event:d3.event,element:n})}),Z.on("dblclick",function(t,e){S.elementDblClick({data:t.data,index:e,color:d3.select(this).style("fill")})}),G.attr("fill",function(t,e){return l(t.data,e)}),G.attr("stroke",function(t,e){return l(t.data,e)});Z.append("path").each(function(t){this._current=t});if(G.select("path").transition().duration(M).attr("d",function(t,e){return E[e](t)}).attrTween("d",N),f){for(var Q=[],q=0;q<e[0].length;q++)Q.push(E[q]),d?g&&(Q[q]=d3.svg.arc().outerRadius(E[q].outerRadius()),x!==!1&&Q[q].startAngle(x),$!==!1&&Q[q].endAngle($)):g||Q[q].innerRadius(0);X.enter().append("g").classed("nv-label",!0).each(function(t,e){var n=d3.select(this);n.attr("transform",function(t,e){if(b){t.outerRadius=I[e]+10,t.innerRadius=I[e]+15;var n=(t.startAngle+t.endAngle)/2*(180/Math.PI);return(t.startAngle+t.endAngle)/2<Math.PI?n-=90:n+=90,"translate("+Q[e].centroid(t)+") rotate("+n+")"}return t.outerRadius=j+10,t.innerRadius=j+15,"translate("+Q[e].centroi
 d(t)+")"}),n.append("rect").style("stroke","#fff").style("fill","#fff").attr("rx",3).attr("ry",3),n.append("text").style("text-anchor",b?(t.startAngle+t.endAngle)/2<Math.PI?"start":"end":"middle").style("fill","#000")});var K={},J=14,tt=140,et=function(t){return Math.floor(t[0]/tt)*tt+","+Math.floor(t[1]/J)*J},nt=function(t){return(t.endAngle-t.startAngle)/(2*Math.PI)};X.watchTransition(T,"pie labels").attr("transform",function(t,e){if(b){t.outerRadius=I[e]+10,t.innerRadius=I[e]+15;var n=(t.startAngle+t.endAngle)/2*(180/Math.PI);return(t.startAngle+t.endAngle)/2<Math.PI?n-=90:n+=90,"translate("+Q[e].centroid(t)+") rotate("+n+")"}t.outerRadius=j+10,t.innerRadius=j+15;var r=Q[e].centroid(t),i=nt(t);if(t.value&&i>=p){var o=et(r);K[o]&&(r[1]-=J),K[et(r)]=!0}return"translate("+r+")"}),X.select(".nv-label text").style("text-anchor",function(t,e){return b?(t.startAngle+t.endAngle)/2<Math.PI?"start":"end":"middle"}).text(function(t,e){var n=nt(t),r="";if(!t.value||n<p)return"";if("function"
 ==typeof h)r=h(t,e,{key:o(t.data),value:a(t.data),percent:c(n)});else switch(h){case"key":r=o(t.data);break;case"value":r=c(a(t.data));break;case"percent":r=d3.format("%")(n)}return r})}}),T.renderEnd("pie immediate"),e}var n={top:0,right:0,bottom:0,left:0},r=500,i=500,o=function(t){return t.x},a=function(t){return t.y},s=Math.floor(1e4*Math.random()),u=null,l=t.utils.defaultColor(),c=d3.format(",.2f"),f=!0,d=!1,h="key",p=.02,g=!1,v=!1,m=!0,y=0,b=!1,x=!1,w=!1,$=!1,k=0,_=.5,M=250,C=[],S=d3.dispatch("chartClick","elementClick","elementDblClick","elementMouseover","elementMouseout","elementMousemove","renderEnd"),E=[],A=[],T=t.utils.renderWatch(S);return e.dispatch=S,e.options=t.utils.optionsFunc.bind(e),e._options=Object.create({},{arcsRadius:{get:function(){return C},set:function(t){C=t}},width:{get:function(){return r},set:function(t){r=t}},height:{get:function(){return i},set:function(t){i=t}},showLabels:{get:function(){return f},set:function(t){f=t}},title:{get:function(){return v
 },set:function(t){v=t}},titleOffset:{get:function(){return y},set:function(t){y=t}},labelThreshold:{get:function(){return p},set:function(t){p=t}},valueFormat:{get:function(){return c},set:function(t){c=t}},x:{get:function(){return o},set:function(t){o=t}},id:{get:function(){return s},set:function(t){s=t}},endAngle:{get:function(){return $},set:function(t){$=t}},startAngle:{get:function(){return x},set:function(t){x=t}},padAngle:{get:function(){return w},set:function(t){w=t}},cornerRadius:{get:function(){return k},set:function(t){k=t}},donutRatio:{get:function(){return _},set:function(t){_=t}},labelsOutside:{get:function(){return d},set:function(t){d=t}},labelSunbeamLayout:{get:function(){return b},set:function(t){b=t}},donut:{get:function(){return g},set:function(t){g=t}},growOnHover:{get:function(){return m},set:function(t){m=t}},pieLabelsOutside:{get:function(){return d},set:function(e){d=e,t.deprecated("pieLabelsOutside","use labelsOutside instead")}},donutLabelsOutside:{get:fun
 ction(){return d},set:function(e){d=e,t.deprecated("donutLabelsOutside","use labelsOutside instead")}},labelFormat:{get:function(){return c},set:function(e){c=e,t.deprecated("labelFormat","use valueFormat instead")}},margin:{get:function(){return n},set:function(t){n.top="undefined"!=typeof t.top?t.top:n.top,n.right="undefined"!=typeof t.right?t.right:n.right,n.bottom="undefined"!=typeof t.bottom?t.bottom:n.bottom,n.left="undefined"!=typeof t.left?t.left:n.left}},duration:{get:function(){return M},set:function(t){M=t,T.reset(M)}},y:{get:function(){return a},set:function(t){a=d3.functor(t)}},color:{get:function(){return l},set:function(e){l=t.utils.getColor(e)}},labelType:{get:function(){return h},set:function(t){h=t||"key"}}}),t.utils.initOptions(e),e},t.models.pieChart=function(){"use strict";function e(i){return m.reset(),m.models(n),i.each(function(i){var u=d3.select(this);t.utils.initSVG(u);var f=t.utils.availableWidth(a,u,o),p=t.utils.availableHeight(s,u,o);if(e.update=function
 (){u.transition().call(e)},e.container=this,d.setter(b(i),e.update).getter(y(i)).update(),d.disabled=i.map(function(t){return!!t.disabled}),!h){var g;h={};for(g in d)d[g]instanceof Array?h[g]=d[g].slice(0):h[g]=d[g]}if(!i||!i.length)return t.utils.noData(e,u),e;u.selectAll(".nv-noData").remove();var m=u.selectAll("g.nv-wrap.nv-pieChart").data([i]),x=m.enter().append("g").attr("class","nvd3 nv-wrap nv-pieChart").append("g"),w=m.select("g");if(x.append("g").attr("class","nv-pieWrap"),x.append("g").attr("class","nv-legendWrap"),l){if("top"===c)r.width(f).key(n.x()),m.select(".nv-legendWrap").datum(i).call(r),r.height()>o.top&&(o.top=r.height(),p=t.utils.availableHeight(s,u,o)),m.select(".nv-legendWrap").attr("transform","translate(0,"+-o.top+")");else if("right"===c){var $=t.models.legend().width();f/2<$&&($=f/2),r.height(p).key(n.x()),r.width($),f-=r.width(),m.select(".nv-legendWrap").datum(i).call(r).attr("transform","translate("+f+",0)")}}else w.select(".nv-legendWrap").selectAll("*
 ").remove();m.attr("transform","translate("+o.left+","+o.top+")"),n.width(f).height(p);var k=w.select(".nv-pieWrap").datum([i]);d3.transition(k).call(n),r.dispatch.on("stateChange",function(t){for(var n in t)d[n]=t[n];v.stateChange(d),e.update()}),v.on("changeState",function(t){"undefined"!=typeof t.disabled&&(i.forEach(function(e,n){e.disabled=t.disabled[n]}),d.disabled=t.disabled),e.update()})}),m.renderEnd("pieChart immediate"),e}var n=t.models.pie(),r=t.models.legend(),i=t.models.tooltip(),o={top:30,right:20,bottom:20,left:20},a=null,s=null,u=!1,l=!0,c="top",f=t.utils.defaultColor(),d=t.utils.state(),h=null,p=null,g=250,v=d3.dispatch("stateChange","changeState","renderEnd");i.duration(0).headerEnabled(!1).valueFormatter(function(t,e){return n.valueFormat()(t,e)});var m=t.utils.renderWatch(v),y=function(t){return function(){return{active:t.map(function(t){return!t.disabled})}}},b=function(t){return function(e){void 0!==e.active&&t.forEach(function(t,n){t.disabled=!e.active[n]})}}
 ;return n.dispatch.on("elementMouseover.tooltip",function(t){t.series={key:e.x()(t.data),value:e.y()(t.data),color:t.color,percent:t.percent},u||(delete t.percent,delete t.series.percent),i.data(t).hidden(!1)}),n.dispatch.on("elementMouseout.tooltip",function(t){i.hidden(!0)}),n.dispatch.on("elementMousemove.tooltip",function(t){i()}),e.legend=r,e.dispatch=v,e.pie=n,e.tooltip=i,e.options=t.utils.optionsFunc.bind(e),e._options=Object.create({},{width:{get:function(){return a},set:function(t){a=t}},height:{get:function(){return s},set:function(t){s=t}},noData:{get:function(){return p},set:function(t){p=t}},showTooltipPercent:{get:function(){return u},set:function(t){u=t}},showLegend:{get:function(){return l},set:function(t){l=t}},legendPosition:{get:function(){return c},set:function(t){c=t}},defaultState:{get:function(){return h},set:function(t){h=t}},color:{get:function(){return f},set:function(t){f=t,r.color(f),n.color(f)}},duration:{get:function(){return g},set:function(t){g=t,m.re
 set(g),n.duration(g)}},margin:{get:function(){return o},set:function(t){o.top=void 0!==t.top?t.top:o.top,o.right=void 0!==t.right?t.right:o.right,o.bottom=void 0!==t.bottom?t.bottom:o.bottom,o.left=void 0!==t.left?t.left:o.left}}}),t.utils.inheritOptions(e,n),t.utils.initOptions(e),e},t.models.scatter=function(){"use strict";function e(t){var e,n;return e=u=u||{},n=t[0].series,e=e[n]=e[n]||{},n=t[1],e=e[n]=e[n]||{}}function n(t){var n,r,i=t[0],o=e(t),a=!1;for(n=1;n<arguments.length;n++)r=arguments[n],o[r]===i[r]&&o.hasOwnProperty(r)||(o[r]=i[r],a=!0);return a}function r(e){return U.reset(),e.each(function(e){function u(){if(H=!1,!M)return!1;if(W===!0){var n=d3.merge(e.map(function(e,n){return e.values.map(function(e,r){var i=y(e,r),o=b(e,r);return[t.utils.NaNtoZero(g(i))+1e-4*Math.random(),t.utils.NaNtoZero(v(o))+1e-4*Math.random(),n,r,e]}).filter(function(t,e){return C(t[4],e)})}));if(0==n.length)return!1;n.length<3&&(n.push([g.range()[0]-20,v.range()[0]-20,null,null]),n.push([g.ra
 nge()[1]+20,v.range()[1]+20,null,null]),n.push([g.range()[0]-20,v.range()[0]+20,null,null]),n.push([g.range()[1]+20,v.range()[1]-20,null,null]));var r=d3.geom.polygon([[-10,-10],[-10,f+10],[c+10,f+10],[c+10,-10]]),i=d3.geom.voronoi(n).map(function(t,e){return{data:r.clip(t),series:n[e][2],point:n[e][3]}});J.select(".nv-point-paths").selectAll("path").remove();var o=J.select(".nv-point-paths").selectAll("path").data(i),a=o.enter().append("svg:path").attr("d",function(t){return t&&t.data&&0!==t.data.length?"M"+t.data.join(",")+"Z":"M 0 0"}).attr("id",function(t,e){return"nv-path-"+e}).attr("clip-path",function(t,e){return"url(#nv-clip-"+h+"-"+e+")"});if(N&&a.style("fill",d3.rgb(230,230,230)).style("fill-opacity",.4).style("stroke-opacity",1).style("stroke",d3.rgb(200,200,200)),T){J.select(".nv-point-clips").selectAll("*").remove();var s=J.select(".nv-point-clips").selectAll("clipPath").data(n);s.enter().append("svg:clipPath").attr("id",function(t,e){return"nv-clip-"+h+"-"+e}).append("
 svg:circle").attr("cx",function(t){return t[0]}).attr("cy",function(t){return t[1]}).attr("r",D)}var u=function(t,n){if(H)return 0;var r=e[t.series];if(void 0!==r){var i=r.values[t.point];i.color=d(r,t.series),i.x=y(i),i.y=b(i);var o=p.node().getBoundingClientRect(),a=window.pageYOffset||document.documentElement.scrollTop,s=window.pageXOffset||document.documentElement.scrollLeft,u={left:g(y(i,t.point))+o.left+s+l.left+10,top:v(b(i,t.point))+o.top+a+l.top+10};n({point:i,series:r,pos:u,relativePos:[g(y(i,t.point))+l.left,v(b(i,t.point))+l.top],seriesIndex:t.series,pointIndex:t.point})}};o.on("click",function(t){u(t,z.elementClick)}).on("dblclick",function(t){u(t,z.elementDblClick)}).on("mouseover",function(t){u(t,z.elementMouseover)}).on("mouseout",function(t,e){u(t,z.elementMouseout)})}else J.select(".nv-groups").selectAll(".nv-group").selectAll(".nv-point").on("click",function(t,n){if(H||!e[t.series])return 0;var r=e[t.series],i=r.values[n],o=this;z.elementClick({point:i,series:r,po
 s:[g(y(i,n))+l.left,v(b(i,n))+l.top],relativePos:[g(y(i,n))+l.left,v(b(i,n))+l.top],seriesIndex:t.series,pointIndex:n,event:d3.event,element:o})}).on("dblclick",function(t,n){if(H||!e[t.series])return 0;var r=e[t.series],i=r.values[n];z.elementDblClick({point:i,series:r,pos:[g(y(i,n))+l.left,v(b(i,n))+l.top],relativePos:[g(y(i,n))+l.left,v(b(i,n))+l.top],seriesIndex:t.series,pointIndex:n})}).on("mouseover",function(t,n){if(H||!e[t.series])return 0;var r=e[t.series],i=r.values[n];z.elementMouseover({point:i,series:r,pos:[g(y(i,n))+l.left,v(b(i,n))+l.top],relativePos:[g(y(i,n))+l.left,v(b(i,n))+l.top],seriesIndex:t.series,pointIndex:n,color:d(t,n)})}).on("mouseout",function(t,n){if(H||!e[t.series])return 0;var r=e[t.series],i=r.values[n];z.elementMouseout({point:i,series:r,pos:[g(y(i,n))+l.left,v(b(i,n))+l.top],relativePos:[g(y(i,n))+l.left,v(b(i,n))+l.top],seriesIndex:t.series,pointIndex:n,color:d(t,n)})})}p=d3.select(this);var R=t.utils.availableWidth(c,p,l),G=t.utils.availableHeigh
 t(f,p,l);t.utils.initSVG(p),e.forEach(function(t,e){t.values.forEach(function(t){t.series=e})});var X=r.yScale().name===d3.scale.log().name,Z=O&&j&&P?[]:d3.merge(e.map(function(t){return t.values.map(function(t,e){return{x:y(t,e),y:b(t,e),size:x(t,e)}})}));if(g.domain(O||d3.extent(Z.map(function(t){return t.x}).concat($))),S&&e[0]?g.range(I||[(R*E+R)/(2*e[0].values.length),R-R*(1+E)/(2*e[0].values.length)]):g.range(I||[0,R]),X){var Q=d3.min(Z.map(function(t){if(0!==t.y)return t.y}));v.clamp(!0).domain(j||d3.extent(Z.map(function(t){return 0!==t.y?t.y:.1*Q}).concat(k))).range(L||[G,0])}else v.domain(j||d3.extent(Z.map(function(t){return t.y}).concat(k))).range(L||[G,0]);m.domain(P||d3.extent(Z.map(function(t){return t.size}).concat(_))).range(F||Y),q=g.domain()[0]===g.domain()[1]||v.domain()[0]===v.domain()[1],g.domain()[0]===g.domain()[1]&&(g.domain()[0]?g.domain([g.domain()[0]-.01*g.domain()[0],g.domain()[1]+.01*g.domain()[1]]):g.domain([-1,1])),v.domain()[0]===v.domain()[1]&&(v.do
 main()[0]?v.domain([v.domain()[0]-.01*v.domain()[0],v.domain()[1]+.01*v.domain()[1]]):v.domain([-1,1])),isNaN(g.domain()[0])&&g.domain([-1,1]),isNaN(v.domain()[0])&&v.domain([-1,1]),i=i||g,o=o||v,a=a||m;var K=g(1)!==i(1)||v(1)!==o(1)||m(1)!==a(1),J=p.selectAll("g.nv-wrap.nv-scatter").data([e]),tt=J.enter().append("g").attr("class","nvd3 nv-wrap nv-scatter nv-chart-"+h),et=tt.append("defs"),nt=tt.append("g"),rt=J.select("g");J.classed("nv-single-point",q),nt.append("g").attr("class","nv-groups"),nt.append("g").attr("class","nv-point-paths"),tt.append("g").attr("class","nv-point-clips"),J.attr("transform","translate("+l.left+","+l.top+")"),et.append("clipPath").attr("id","nv-edge-clip-"+h).append("rect"),J.select("#nv-edge-clip-"+h+" rect").attr("width",R).attr("height",G>0?G:0),rt.attr("clip-path",A?"url(#nv-edge-clip-"+h+")":""),H=!0;var it=J.select(".nv-groups").selectAll(".nv-group").data(function(t){return t},function(t){return t.key});it.enter().append("g").style("stroke-opacity
 ",1e-6).style("fill-opacity",1e-6),it.exit().remove(),it.attr("class",function(t,e){return(t.classed||"")+" nv-group nv-series-"+e}).classed("nv-noninteractive",!M).classed("hover",function(t){return t.hover}),it.watchTransition(U,"scatter: groups").style("fill",function(t,e){return d(t,e)}).style("stroke",function(t,e){return d(t,e)}).style("stroke-opacity",1).style("fill-opacity",.5);var ot=it.selectAll("path.nv-point").data(function(t){return t.values.map(function(t,e){return[t,e]}).filter(function(t,e){return C(t[0],e)})});if(ot.enter().append("path").attr("class",function(t){return"nv-point nv-point-"+t[1]}).style("fill",function(t){return t.color}).style("stroke",function(t){return t.color}).attr("transform",function(e){return"translate("+t.utils.NaNtoZero(i(y(e[0],e[1])))+","+t.utils.NaNtoZero(o(b(e[0],e[1])))+")"}).attr("d",t.utils.symbol().type(function(t){return w(t[0])}).size(function(t){return m(x(t[0],t[1]))})),ot.exit().remove(),it.exit().selectAll("path.nv-point").wat
 chTransition(U,"scatter exit").attr("transform",function(e){return"translate("+t.utils.NaNtoZero(g(y(e[0],e[1])))+","+t.utils.NaNtoZero(v(b(e[0],e[1])))+")"}).remove(),ot.filter(function(t){return K||n(t,"x","y")}).watchTransition(U,"scatter points").attr("transform",function(e){return"translate("+t.utils.NaNtoZero(g(y(e[0],e[1])))+","+t.utils.NaNtoZero(v(b(e[0],e[1])))+")"}),ot.filter(function(t){return K||n(t,"shape","size")}).watchTransition(U,"scatter points").attr("d",t.utils.symbol().type(function(t){return w(t[0])}).size(function(t){return m(x(t[0],t[1]))})),V){var at=it.selectAll(".nv-label").data(function(t){return t.values.map(function(t,e){return[t,e]}).filter(function(t,e){return C(t[0],e)})});at.enter().append("text").style("fill",function(t,e){return t.color}).style("stroke-opacity",0).style("fill-opacity",1).attr("transform",function(e){var n=t.utils.NaNtoZero(i(y(e[0],e[1])))+Math.sqrt(m(x(e[0],e[1]))/Math.PI)+2;return"translate("+n+","+t.utils.NaNtoZero(o(b(e[0],e[1
 ])))+")"}).text(function(t,e){return t[0].label}),at.exit().remove(),it.exit().selectAll("path.nv-label").watchTransition(U,"scatter exit").attr("transform",function(e){var n=t.utils.NaNtoZero(g(y(e[0],e[1])))+Math.sqrt(m(x(e[0],e[1]))/Math.PI)+2;return"translate("+n+","+t.utils.NaNtoZero(v(b(e[0],e[1])))+")"}).remove(),at.each(function(t){d3.select(this).classed("nv-label",!0).classed("nv-label-"+t[1],!1).classed("hover",!1)}),at.watchTransition(U,"scatter labels").attr("transform",function(e){var n=t.utils.NaNtoZero(g(y(e[0],e[1])))+Math.sqrt(m(x(e[0],e[1]))/Math.PI)+2;return"translate("+n+","+t.utils.NaNtoZero(v(b(e[0],e[1])))+")"})}B?(clearTimeout(s),s=setTimeout(u,B)):u(),i=g.copy(),o=v.copy(),a=m.copy()}),U.renderEnd("scatter immediate"),r}var i,o,a,s,u,l={top:0,right:0,bottom:0,left:0},c=null,f=null,d=t.utils.defaultColor(),h=Math.floor(1e5*Math.random()),p=null,g=d3.scale.linear(),v=d3.scale.linear(),m=d3.scale.linear(),y=function(t){return t.x},b=function(t){return t.y},x=f
 unction(t){return t.size||1},w=function(t){return t.shape||"circle"},$=[],k=[],_=[],M=!0,C=function(t){return!t.notActive},S=!1,E=.1,A=!1,T=!0,N=!1,D=function(){return 25},O=null,j=null,I=null,L=null,P=null,F=null,q=!1,z=d3.dispatch("elementClick","elementDblClick","elementMouseover","elementMouseout","renderEnd"),W=!0,R=250,B=300,V=!1,H=!1,U=t.utils.renderWatch(z,R),Y=[16,256];return r.dispatch=z,r.options=t.utils.optionsFunc.bind(r),r._calls=new function(){this.clearHighlights=function(){return t.dom.write(function(){p.selectAll(".nv-point.hover").classed("hover",!1)}),null},this.highlightPoint=function(e,n,r){t.dom.write(function(){p.select(".nv-groups").selectAll(".nv-series-"+e).selectAll(".nv-point-"+n).classed("hover",r)})}},z.on("elementMouseover.point",function(t){M&&r._calls.highlightPoint(t.seriesIndex,t.pointIndex,!0)}),z.on("elementMouseout.point",function(t){M&&r._calls.highlightPoint(t.seriesIndex,t.pointIndex,!1)}),r._options=Object.create({},{width:{get:function(){r
 eturn c},set:function(t){c=t}},height:{get:function(){return f},set:function(t){f=t}},xScale:{get:function(){return g},set:function(t){g=t}},yScale:{get:function(){return v},set:function(t){v=t}},pointScale:{get:function(){return m},set:function(t){m=t}},xDomain:{get:function(){return O},set:function(t){O=t}},yDomain:{get:function(){return j},set:function(t){j=t}},pointDomain:{get:function(){return P},set:function(t){P=t}},xRange:{get:function(){return I},set:function(t){I=t}},yRange:{get:function(){return L},set:function(t){L=t}},pointRange:{get:function(){return F},set:function(t){F=t}},forceX:{get:function(){return $},set:function(t){$=t}},forceY:{get:function(){return k},set:function(t){k=t}},forcePoint:{get:function(){return _},set:function(t){_=t}},interactive:{get:function(){return M},set:function(t){M=t}},pointActive:{get:function(){return C},set:function(t){C=t}},padDataOuter:{get:function(){return E},set:function(t){E=t}},padData:{get:function(){return S},set:function(t){S
 =t}},clipEdge:{get:function(){return A},set:function(t){A=t}},clipVoronoi:{get:function(){return T},set:function(t){T=t}},clipRadius:{get:function(){return D},set:function(t){D=t}},showVoronoi:{get:function(){return N},set:function(t){N=t}},id:{get:function(){return h},set:function(t){h=t}},interactiveUpdateDelay:{get:function(){return B},set:function(t){B=t}},showLabels:{get:function(){return V},set:function(t){V=t}},x:{get:function(){return y},set:function(t){y=d3.functor(t)}},y:{get:function(){return b},set:function(t){b=d3.functor(t)}},pointSize:{get:function(){return x},set:function(t){x=d3.functor(t)}},pointShape:{get:function(){return w},set:function(t){w=d3.functor(t)}},margin:{get:function(){return l},set:function(t){l.top=void 0!==t.top?t.top:l.top,l.right=void 0!==t.right?t.right:l.right,l.bottom=void 0!==t.bottom?t.bottom:l.bottom,l.left=vo

<TRUNCATED>

[5/5] flink git commit: [FLINK-3427] [webui] Add watermark tracking

Posted by uc...@apache.org.
[FLINK-3427] [webui] Add watermark tracking


Project: http://git-wip-us.apache.org/repos/asf/flink/repo
Commit: http://git-wip-us.apache.org/repos/asf/flink/commit/d84b65ff
Tree: http://git-wip-us.apache.org/repos/asf/flink/tree/d84b65ff
Diff: http://git-wip-us.apache.org/repos/asf/flink/diff/d84b65ff

Branch: refs/heads/master
Commit: d84b65ff15876feb3e26dd20beb2e743968502bc
Parents: 7a629fc
Author: Ufuk Celebi <uc...@apache.org>
Authored: Wed Mar 8 11:34:29 2017 +0100
Committer: Ufuk Celebi <uc...@apache.org>
Committed: Wed Mar 8 15:28:41 2017 +0100

----------------------------------------------------------------------
 .../app/partials/jobs/job.plan.jade             |  5 +-
 .../jobs/job.plan.node-list.watermarks.jade     | 36 ++++++++
 .../partials/jobs/job.plan.node.watermarks.jade | 27 ++++++
 .../app/scripts/common/filters.coffee           | 17 ++++
 .../web-dashboard/app/scripts/index.coffee      | 15 +++-
 .../app/scripts/modules/jobs/jobs.ctrl.coffee   | 68 +++++++++++++--
 .../app/scripts/modules/jobs/jobs.dir.coffee    | 90 ++++++++++++++------
 7 files changed, 221 insertions(+), 37 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/flink/blob/d84b65ff/flink-runtime-web/web-dashboard/app/partials/jobs/job.plan.jade
----------------------------------------------------------------------
diff --git a/flink-runtime-web/web-dashboard/app/partials/jobs/job.plan.jade b/flink-runtime-web/web-dashboard/app/partials/jobs/job.plan.jade
index e84dd04..c33b9a3 100644
--- a/flink-runtime-web/web-dashboard/app/partials/jobs/job.plan.jade
+++ b/flink-runtime-web/web-dashboard/app/partials/jobs/job.plan.jade
@@ -18,7 +18,7 @@
 split
   .split#canvas
     .canvas-wrapper
-      div.main-canvas(job-plan, plan="plan", jobid="{{jobid}}", set-node="changeNode(nodeid)")
+      div.main-canvas(job-plan, plan="plan", low-watermarks="lowWatermarks" jobid="{{jobid}}", set-node="changeNode(nodeid)")
 
   .split#job-panel
     .panel.panel-default.panel-multi(ng-if="plan")
@@ -34,6 +34,9 @@ split
             a(ui-sref=".metrics({nodeid: nodeid})") Metrics
 
           li(ui-sref-active='active')
+            a(ui-sref=".watermarks({nodeid: nodeid})") Watermarks
+
+          li(ui-sref-active='active')
             a(ui-sref=".accumulators({nodeid: nodeid})") Accumulators
 
           li(ui-sref-active='active')

http://git-wip-us.apache.org/repos/asf/flink/blob/d84b65ff/flink-runtime-web/web-dashboard/app/partials/jobs/job.plan.node-list.watermarks.jade
----------------------------------------------------------------------
diff --git a/flink-runtime-web/web-dashboard/app/partials/jobs/job.plan.node-list.watermarks.jade b/flink-runtime-web/web-dashboard/app/partials/jobs/job.plan.node-list.watermarks.jade
new file mode 100644
index 0000000..6b4c6a2
--- /dev/null
+++ b/flink-runtime-web/web-dashboard/app/partials/jobs/job.plan.node-list.watermarks.jade
@@ -0,0 +1,36 @@
+//
+  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.
+
+table.table.table-body-hover.table-clickable.table-activable
+  thead
+    tr
+      th Name
+      th Low Watermark
+      th Parallelism
+      th Status
+
+  tbody(ng-repeat="v in job.vertices" ng-class="{ active: v.id == nodeid && hasWatermarks(nodeid) }" ng-click="changeNode(v.id)")
+    tr(ng-if="v.type == 'regular'")
+
+      td.td-long {{ v.name | humanizeText }}
+      td {{ watermarks | lowWatermark:v.id }}
+      td {{ v.parallelism }}
+      td 
+        bs-label(status="{{v.status}}") {{v.status}}
+    tr(ng-if="nodeid && v.id == nodeid && hasWatermarks(nodeid)")
+      td(colspan="11")
+        div(ng-include=" 'partials/jobs/job.plan.node.watermarks.html' ")

http://git-wip-us.apache.org/repos/asf/flink/blob/d84b65ff/flink-runtime-web/web-dashboard/app/partials/jobs/job.plan.node.watermarks.jade
----------------------------------------------------------------------
diff --git a/flink-runtime-web/web-dashboard/app/partials/jobs/job.plan.node.watermarks.jade b/flink-runtime-web/web-dashboard/app/partials/jobs/job.plan.node.watermarks.jade
new file mode 100644
index 0000000..b406a1c
--- /dev/null
+++ b/flink-runtime-web/web-dashboard/app/partials/jobs/job.plan.node.watermarks.jade
@@ -0,0 +1,27 @@
+//
+  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.
+
+table.table.table-hover.table-clickable.table-activable.table-inner(ng-if="hasWatermarks(nodeid)")
+  thead
+    tr
+      th id
+      th Watermark
+
+  tbody
+    tr(ng-repeat="watermark in watermarksByNode(nodeid)")
+      td {{ watermark.id }}
+      td {{ watermark.value | parseWatermark }}

http://git-wip-us.apache.org/repos/asf/flink/blob/d84b65ff/flink-runtime-web/web-dashboard/app/scripts/common/filters.coffee
----------------------------------------------------------------------
diff --git a/flink-runtime-web/web-dashboard/app/scripts/common/filters.coffee b/flink-runtime-web/web-dashboard/app/scripts/common/filters.coffee
index 67b02e3..99e12a8 100644
--- a/flink-runtime-web/web-dashboard/app/scripts/common/filters.coffee
+++ b/flink-runtime-web/web-dashboard/app/scripts/common/filters.coffee
@@ -87,3 +87,20 @@ angular.module('flinkApp')
 
 .filter "percentage", ->
   (number) -> (number * 100).toFixed(0) + '%'
+
+.filter "parseWatermark", (watermarksConfig)->
+  (value) ->
+    if value <= watermarksConfig.minValue
+      return 'No Watermark'
+    else
+      return value
+
+.filter "lowWatermark", (watermarksConfig)->
+  (watermarks, nodeid) ->
+    lowWatermark = "No Watermark"
+    if watermarks != null && watermarks[nodeid] && watermarks[nodeid].length
+      values = (watermark.value for watermark in watermarks[nodeid])
+      lowWatermark = Math.min.apply(null, values)
+      if lowWatermark <= watermarksConfig.minValue
+        lowWatermark = "No Watermark"
+    return lowWatermark

http://git-wip-us.apache.org/repos/asf/flink/blob/d84b65ff/flink-runtime-web/web-dashboard/app/scripts/index.coffee
----------------------------------------------------------------------
diff --git a/flink-runtime-web/web-dashboard/app/scripts/index.coffee b/flink-runtime-web/web-dashboard/app/scripts/index.coffee
index 95bb356..cbbefab 100644
--- a/flink-runtime-web/web-dashboard/app/scripts/index.coffee
+++ b/flink-runtime-web/web-dashboard/app/scripts/index.coffee
@@ -30,12 +30,18 @@ angular.module('flinkApp', ['ui.router', 'angularMoment', 'dndLists'])
 
 .value 'flinkConfig', {
   jobServer: ''
-#  jobServer: 'http://localhost:8081/'
+  # jobServer: 'http://localhost:8081/'
   "refresh-interval": 10000
 }
 
 # --------------------------------------
 
+.value 'watermarksConfig', {
+  minValue: -9223372036854776000
+}
+
+# --------------------------------------
+
 .run (JobsService, MainService, flinkConfig, $interval) ->
   MainService.loadConfig().then (config) ->
     angular.extend flinkConfig, config
@@ -114,6 +120,13 @@ angular.module('flinkApp', ['ui.router', 'angularMoment', 'dndLists'])
         templateUrl: "partials/jobs/job.plan.node-list.metrics.html"
         controller: 'JobPlanMetricsController'
 
+  .state "single-job.plan.watermarks",
+    url: "/watermarks"
+    views:
+      'node-details':
+        templateUrl: "partials/jobs/job.plan.node-list.watermarks.html"
+        controller: 'JobPlanWatermarksController'
+
   .state "single-job.plan.taskmanagers",
     url: "/taskmanagers"
     views:

http://git-wip-us.apache.org/repos/asf/flink/blob/d84b65ff/flink-runtime-web/web-dashboard/app/scripts/modules/jobs/jobs.ctrl.coffee
----------------------------------------------------------------------
diff --git a/flink-runtime-web/web-dashboard/app/scripts/modules/jobs/jobs.ctrl.coffee b/flink-runtime-web/web-dashboard/app/scripts/modules/jobs/jobs.ctrl.coffee
index bbb57c5..d18d7e3 100644
--- a/flink-runtime-web/web-dashboard/app/scripts/modules/jobs/jobs.ctrl.coffee
+++ b/flink-runtime-web/web-dashboard/app/scripts/modules/jobs/jobs.ctrl.coffee
@@ -42,23 +42,18 @@ angular.module('flinkApp')
 
 # --------------------------------------
 
-.controller 'SingleJobController', ($scope, $state, $stateParams, JobsService, MetricsService, $rootScope, flinkConfig, $interval) ->
+.controller 'SingleJobController', ($scope, $state, $stateParams, JobsService, MetricsService, $rootScope, flinkConfig, $interval, $q, watermarksConfig) ->
   $scope.jobid = $stateParams.jobid
   $scope.job = null
   $scope.plan = null
+  $scope.watermarks = null
+  $scope.lowWatermarks = null
   $scope.vertices = null
   $scope.backPressureOperatorStats = {}
 
-  JobsService.loadJob($stateParams.jobid).then (data) ->
-    $scope.job = data
-    $scope.plan = data.plan
-    $scope.vertices = data.vertices
-    MetricsService.setupMetrics($stateParams.jobid, data.vertices)
-
   refresher = $interval ->
     JobsService.loadJob($stateParams.jobid).then (data) ->
       $scope.job = data
-
       $scope.$broadcast 'reload'
 
   , flinkConfig["refresh-interval"]
@@ -66,6 +61,8 @@ angular.module('flinkApp')
   $scope.$on '$destroy', ->
     $scope.job = null
     $scope.plan = null
+    $scope.watermarks = null
+    $scope.lowWatermarks = null
     $scope.vertices = null
     $scope.backPressureOperatorStats = null
 
@@ -81,6 +78,50 @@ angular.module('flinkApp')
     JobsService.stopJob($stateParams.jobid).then (data) ->
       {}
 
+  JobsService.loadJob($stateParams.jobid).then (data) ->
+    $scope.job = data
+    $scope.vertices = data.vertices
+    $scope.plan = data.plan
+    MetricsService.setupMetrics($stateParams.jobid, data.vertices)
+
+  getWatermarks = (nodes)->
+    # This function uses a promise to resolve watermarks once fetched via the metrics service, since watermarks have to be fetched individually for each node, we have to wait until all API calls have been made before we can resolve the promise. In the end we will have an array of low watermarks for each node: e.g. {somenodeid: [{id: 0, value: -9223372036854776000}], anothernodeid: [{id: 0, value: -9223372036854776000}, {id: 1, value: -9223372036854776000}]}.
+    deferred = $q.defer()
+    watermarks = {}
+    jid = $scope.job.jid
+    angular.forEach nodes, (node, index) =>
+      metricIds = []
+      # for each node, we need to specify which metrics we want to collect, for each subtask, we need to fetch the currentLowWatermark, and each param is formed by concatenating subtask index to '.currentLowWatermark'.
+      for num in [0..node.parallelism - 1]
+        metricIds.push(num + ".currentLowWatermark")
+      MetricsService.getMetrics(jid, node.id, metricIds).then (data) ->
+        values = []
+        for key, value of data.values
+          values.push(id: key.replace('.currentLowWatermark', ''), value: value)
+        watermarks[node.id] = values
+        if index >= $scope.plan.nodes.length - 1
+          deferred.resolve(watermarks)
+    deferred.promise
+
+  getLowWatermarks = (watermarks)->
+    lowWatermarks = []
+    for k,v of watermarks
+      minValue = Math.min.apply(null,(watermark.value for watermark in v))
+      lowWatermarks[k] = if minValue <= watermarksConfig.minValue || v.length == 0 then 'No Watermark' else minValue
+    return lowWatermarks
+
+  $scope.$watch 'plan', (newPlan) ->
+    if newPlan
+      getWatermarks(newPlan.nodes).then (data) ->
+        $scope.watermarks = data
+        $scope.lowWatermarks = getLowWatermarks(data)
+
+  $scope.$on 'reload', (event) ->
+    if $scope.plan
+      getWatermarks($scope.plan.nodes).then (data) ->
+        $scope.watermarks = data
+        $scope.lowWatermarks = getLowWatermarks(data)
+
 # --------------------------------------
 
 .controller 'JobPlanController', ($scope, $state, $stateParams, $window, JobsService) ->
@@ -318,3 +359,14 @@ angular.module('flinkApp')
   loadMetrics() if $scope.nodeid
 
 # --------------------------------------
+
+.controller 'JobPlanWatermarksController', ($scope, $filter) ->
+  $scope.hasWatermarks = (nodeid) ->
+    return true if $scope.watermarksByNode(nodeid).length
+
+  $scope.watermarksByNode = (nodeid) ->
+    if $scope.watermarks != null && $scope.watermarks[nodeid] && $scope.watermarks[nodeid].length
+      return $scope.watermarks[nodeid]
+    return []
+
+# --------------------------------------

http://git-wip-us.apache.org/repos/asf/flink/blob/d84b65ff/flink-runtime-web/web-dashboard/app/scripts/modules/jobs/jobs.dir.coffee
----------------------------------------------------------------------
diff --git a/flink-runtime-web/web-dashboard/app/scripts/modules/jobs/jobs.dir.coffee b/flink-runtime-web/web-dashboard/app/scripts/modules/jobs/jobs.dir.coffee
index b67d0bf..950cf06 100644
--- a/flink-runtime-web/web-dashboard/app/scripts/modules/jobs/jobs.dir.coffee
+++ b/flink-runtime-web/web-dashboard/app/scripts/modules/jobs/jobs.dir.coffee
@@ -168,12 +168,14 @@ angular.module('flinkApp')
     return
 
 # ----------------------------------------------
+
 .directive 'split', () -> 
   return compile: (tElem, tAttrs) ->
       Split(tElem.children(), (
         sizes: [50, 50]
         direction: 'vertical'
       ))
+
 # ----------------------------------------------
 
 .directive 'jobPlan', ($timeout) ->
@@ -187,6 +189,7 @@ angular.module('flinkApp')
 
   scope:
     plan: '='
+    lowWatermarks: '='
     setNode: '&'
 
   link: (scope, elem, attrs) ->
@@ -209,6 +212,9 @@ angular.module('flinkApp')
     containerW = elem.width()
     angular.element(elem.children()[0]).width(containerW)
 
+    lastZoomScale = 0
+    lastPosition = 0
+
     scope.zoomIn = ->
       if mainZoom.scale() < 2.99
 
@@ -222,6 +228,9 @@ angular.module('flinkApp')
         # Transform svg
         d3mainSvgG.attr "transform", "translate(" + v1 + "," + v2 + ") scale(" + mainZoom.scale() + ")"
 
+        lastZoomScale = mainZoom.scale()
+        lastPosition = mainZoom.translate()
+
     scope.zoomOut = ->
       if mainZoom.scale() > 0.31
 
@@ -235,6 +244,9 @@ angular.module('flinkApp')
         # Transform svg
         d3mainSvgG.attr "transform", "translate(" + v1 + "," + v2 + ") scale(" + mainZoom.scale() + ")"
 
+        lastZoomScale = mainZoom.scale()
+        lastPosition = mainZoom.translate()
+
     #create a label of an edge
     createLabelEdge = (el) ->
       labelValue = ""
@@ -288,6 +300,7 @@ angular.module('flinkApp')
         # Otherwise add infos
         labelValue += "<h5>" + info + " Node</h5>"  if isSpecialIterationNode(info)
         labelValue += "<h5>Parallelism: " + el.parallelism + "</h5>"  unless el.parallelism is ""
+        labelValue += "<h5>Low Watermark: " + el.lowWatermark + "</h5>"  unless el.lowWatermark is `undefined`
         labelValue += "<h5>Operation: " + shortenString(el.operator_strategy) + "</h5>" unless el.operator is `undefined` or not el.operator_strategy
       # labelValue += "</a>"
       labelValue += "</div>"
@@ -422,43 +435,66 @@ angular.module('flinkApp')
           for j of el.step_function
             return el.step_function[j]  if el.step_function[j].id is nodeID
 
-    drawGraph = (data) ->
-      g = new dagreD3.graphlib.Graph({ multigraph: true, compound: true }).setGraph({
-        nodesep: 70
-        edgesep: 0
-        ranksep: 50
-        rankdir: "LR"
-        marginx: 40
-        marginy: 40
-        })
+    mergeWatermarks = (data, watermarks) ->
+      for k,v of watermarks
+        for node in data.nodes
+          if node.id == k
+            node.lowWatermark = v
+      return data
 
-      loadJsonToDagre(g, data)
+    lastPosition = 0
+    lastZoomScale = 0
 
-      renderer = new dagreD3.render()
-      d3mainSvgG.call(renderer, g)
+    drawGraph = () ->
+      if scope.plan
+        g = new dagreD3.graphlib.Graph({ multigraph: true, compound: true }).setGraph({
+          nodesep: 70
+          edgesep: 0
+          ranksep: 50
+          rankdir: "LR"
+          marginx: 40
+          marginy: 40
+          })
 
-      for i, sg of subgraphs
-        d3mainSvg.select('svg.svg-' + i + ' g').call(renderer, sg)
+        loadJsonToDagre(g, mergeWatermarks(scope.plan, scope.lowWatermarks))
 
-      newScale = 0.5
+        d3mainSvgG.selectAll("*").remove()
 
-      xCenterOffset = Math.floor((angular.element(mainSvgElement).width() - g.graph().width * newScale) / 2)
-      yCenterOffset = Math.floor((angular.element(mainSvgElement).height() - g.graph().height * newScale) / 2)
+        d3mainSvgG.attr("transform", "scale(" + 1 + ")")
 
-      mainZoom.scale(newScale).translate([xCenterOffset, yCenterOffset])
+        renderer = new dagreD3.render()
+        d3mainSvgG.call(renderer, g)
 
-      d3mainSvgG.attr("transform", "translate(" + xCenterOffset + ", " + yCenterOffset + ") scale(" + mainZoom.scale() + ")")
+        for i, sg of subgraphs
+          d3mainSvg.select('svg.svg-' + i + ' g').call(renderer, sg)
 
-      mainZoom.on("zoom", ->
-        ev = d3.event
-        d3mainSvgG.attr "transform", "translate(" + ev.translate + ") scale(" + ev.scale + ")"
-      )
-      mainZoom(d3mainSvg)
+        newScale = 0.5
+
+        xCenterOffset = Math.floor((angular.element(mainSvgElement).width() - g.graph().width * newScale) / 2)
+        yCenterOffset = Math.floor((angular.element(mainSvgElement).height() - g.graph().height * newScale) / 2)
+
+        if lastZoomScale != 0 && lastPosition != 0
+          mainZoom.scale(lastZoomScale).translate(lastPosition)
+          d3mainSvgG.attr("transform", "translate(" + lastPosition + ") scale(" + lastZoomScale + ")")
+        else
+          mainZoom.scale(newScale).translate([xCenterOffset, yCenterOffset])
+          d3mainSvgG.attr("transform", "translate(" + xCenterOffset + ", " + yCenterOffset + ") scale(" + mainZoom.scale() + ")")
 
-      d3mainSvgG.selectAll('.node').on 'click', (d) ->
-        scope.setNode({ nodeid: d })
+        mainZoom.on("zoom", ->
+          ev = d3.event
+          lastZoomScale = ev.scale
+          lastPosition = ev.translate
+          d3mainSvgG.attr "transform", "translate(" + lastPosition + ") scale(" + lastZoomScale + ")"
+        )
+        mainZoom(d3mainSvg)
+
+        d3mainSvgG.selectAll('.node').on 'click', (d) ->
+          scope.setNode({ nodeid: d })
 
     scope.$watch attrs.plan, (newPlan) ->
-      drawGraph(newPlan) if newPlan
+      drawGraph() if newPlan
+
+    scope.$watch attrs.lowWatermarks, (newLowWatermarks) ->
+      drawGraph() if newLowWatermarks && scope.plan
 
     return