Return-Path: X-Original-To: apmail-flink-commits-archive@minotaur.apache.org Delivered-To: apmail-flink-commits-archive@minotaur.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 0060B18F7F for ; Tue, 20 Oct 2015 07:58:54 +0000 (UTC) Received: (qmail 78322 invoked by uid 500); 20 Oct 2015 07:58:53 -0000 Delivered-To: apmail-flink-commits-archive@flink.apache.org Received: (qmail 78198 invoked by uid 500); 20 Oct 2015 07:58:53 -0000 Mailing-List: contact commits-help@flink.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@flink.apache.org Delivered-To: mailing list commits@flink.apache.org Received: (qmail 77098 invoked by uid 99); 20 Oct 2015 07:58:53 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 20 Oct 2015 07:58:53 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id EB4BAE03D0; Tue, 20 Oct 2015 07:58:52 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: trohrmann@apache.org To: commits@flink.apache.org Date: Tue, 20 Oct 2015 07:59:11 -0000 Message-Id: <3a2c3c7ec8704a5fb65fdfdd9f75dc0b@git.apache.org> In-Reply-To: References: X-Mailer: ASF-Git Admin Mailer Subject: [20/47] flink git commit: [FLINK-2793] [runtime-web] Redirect to leader in non-standalone mode http://git-wip-us.apache.org/repos/asf/flink/blob/77fc0cc4/flink-runtime-web/src/main/resources/web/js/index.js ---------------------------------------------------------------------- diff --git a/flink-runtime-web/src/main/resources/web/js/index.js b/flink-runtime-web/src/main/resources/web/js/index.js new file mode 100644 index 0000000..d370765 --- /dev/null +++ b/flink-runtime-web/src/main/resources/web/js/index.js @@ -0,0 +1,1420 @@ +angular.module('flinkApp', ['ui.router', 'angularMoment']).run(["$rootScope", function($rootScope) { + $rootScope.sidebarVisible = false; + return $rootScope.showSidebar = function() { + $rootScope.sidebarVisible = !$rootScope.sidebarVisible; + return $rootScope.sidebarClass = 'force-show'; + }; +}]).value('flinkConfig', { + "refresh-interval": 10000 +}).run(["JobsService", "MainService", "flinkConfig", "$interval", function(JobsService, MainService, flinkConfig, $interval) { + MainService.loadConfig().then(function(config) { + angular.extend(flinkConfig, config); + JobsService.listJobs(); + return $interval(function() { + return JobsService.listJobs(); + }, flinkConfig["refresh-interval"]); + }); + Highcharts.setOptions({ + global: { + useUTC: false + } + }); + Highcharts.createElement('link', { + href: '//fonts.googleapis.com/css?family=Dosis:400,600', + rel: 'stylesheet', + type: 'text/css' + }, null, document.getElementsByTagName('head')[0]); + Highcharts.theme = { + colors: ["#7cb5ec", "#f7a35c", "#90ee7e", "#7798BF", "#aaeeee", "#ff0066", "#eeaaee", "#55BF3B", "#DF5353", "#7798BF", "#aaeeee"], + chart: { + backgroundColor: null, + style: { + fontFamily: "Dosis, sans-serif" + } + }, + title: { + style: { + fontSize: '16px', + fontWeight: 'bold', + textTransform: 'uppercase' + } + }, + tooltip: { + borderWidth: 0, + backgroundColor: 'rgba(219,219,216,0.8)', + shadow: false + }, + legend: { + itemStyle: { + fontWeight: 'bold', + fontSize: '13px' + } + }, + xAxis: { + gridLineWidth: 1, + labels: { + style: { + fontSize: '12px' + } + } + }, + yAxis: { + minorTickInterval: 'auto', + title: { + style: { + textTransform: 'uppercase' + } + }, + labels: { + style: { + fontSize: '12px' + } + } + }, + plotOptions: { + candlestick: { + lineColor: '#404048' + } + }, + background2: '#F0F0EA' + }; + return Highcharts.setOptions(Highcharts.theme); +}]).config(["$uiViewScrollProvider", function($uiViewScrollProvider) { + return $uiViewScrollProvider.useAnchorScroll(); +}]).config(["$stateProvider", "$urlRouterProvider", function($stateProvider, $urlRouterProvider) { + $stateProvider.state("overview", { + url: "/overview", + views: { + main: { + templateUrl: "partials/overview.html", + controller: 'OverviewController' + } + } + }).state("running-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: true, + views: { + main: { + templateUrl: "partials/jobs/job.html", + controller: 'SingleJobController' + } + } + }).state("single-job.plan", { + url: "", + abstract: true, + views: { + details: { + templateUrl: "partials/jobs/job.plan.html", + controller: 'JobPlanController' + } + } + }).state("single-job.plan.overview", { + url: "", + views: { + 'node-details': { + templateUrl: "partials/jobs/job.plan.node-list.overview.html", + controller: 'JobPlanOverviewController' + } + } + }).state("single-job.plan.accumulators", { + url: "/accumulators", + views: { + 'node-details': { + templateUrl: "partials/jobs/job.plan.node-list.accumulators.html", + controller: 'JobPlanAccumulatorsController' + } + } + }).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.statistics", { + url: "/statistics", + views: { + details: { + templateUrl: "partials/jobs/job.statistics.html" + } + } + }).state("single-job.exceptions", { + url: "/exceptions", + views: { + details: { + templateUrl: "partials/jobs/job.exceptions.html", + controller: 'JobExceptionsController' + } + } + }).state("single-job.properties", { + url: "/properties", + views: { + details: { + templateUrl: "partials/jobs/job.properties.html", + controller: 'JobPropertiesController' + } + } + }).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}", + 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.log", { + url: "/logfile", + views: { + details: { + templateUrl: "partials/taskmanager/taskmanager.logfile.html" + } + } + }).state("single-manager.stdout", { + url: "/stdout", + views: { + details: { + templateUrl: "partials/taskmanager/taskmanager.stdout.html" + } + } + }).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' + } + } + }); + return $urlRouterProvider.otherwise("/overview"); +}]); + +angular.module('flinkApp').directive('bsLabel', ["JobsService", function(JobsService) { + return { + transclude: true, + replace: true, + scope: { + getLabelClass: "&", + status: "@" + }, + template: "", + link: function(scope, element, attrs) { + return scope.getLabelClass = function() { + return 'label label-' + JobsService.translateLabelState(attrs.status); + }; + } + }; +}]).directive('indicatorPrimary', ["JobsService", function(JobsService) { + return { + replace: true, + scope: { + getLabelClass: "&", + status: '@' + }, + template: "", + link: function(scope, element, attrs) { + return scope.getLabelClass = function() { + return 'fa fa-circle indicator indicator-' + JobsService.translateLabelState(attrs.status); + }; + } + }; +}]).directive('tableProperty', function() { + return { + replace: true, + scope: { + value: '=' + }, + template: "{{value || 'None'}}" + }; +}); + +angular.module('flinkApp').filter("amDurationFormatExtended", ["angularMomentConfig", function(angularMomentConfig) { + var amDurationFormatExtendedFilter; + amDurationFormatExtendedFilter = function(value, format, durationFormat) { + if (typeof value === "undefined" || value === null) { + return ""; + } + return moment.duration(value, format).format(durationFormat, { + trim: false + }); + }; + amDurationFormatExtendedFilter.$stateful = angularMomentConfig.statefulFilters; + return amDurationFormatExtendedFilter; +}]).filter("humanizeText", function() { + return function(text) { + if (text) { + return text.replace(/>/g, ">").replace(//g, ""); + } else { + return ''; + } + }; +}).filter("bytes", function() { + return function(bytes, precision) { + var number, units; + if (isNaN(parseFloat(bytes)) || !isFinite(bytes)) { + return "-"; + } + if (typeof precision === "undefined") { + precision = 1; + } + units = ["bytes", "kB", "MB", "GB", "TB", "PB"]; + number = Math.floor(Math.log(bytes) / Math.log(1024)); + return (bytes / Math.pow(1024, Math.floor(number))).toFixed(precision) + " " + units[number]; + }; +}); + +angular.module('flinkApp').service('MainService', ["$http", "flinkConfig", "$q", function($http, flinkConfig, $q) { + this.loadConfig = function() { + var deferred; + deferred = $q.defer(); + $http.get("config").success(function(data, status, headers, config) { + return deferred.resolve(data); + }); + return deferred.promise; + }; + return this; +}]); + +angular.module('flinkApp').controller('JobManagerConfigController', ["$scope", "JobManagerConfigService", function($scope, JobManagerConfigService) { + return JobManagerConfigService.loadConfig().then(function(data) { + if ($scope.jobmanager == null) { + $scope.jobmanager = {}; + } + return $scope.jobmanager['config'] = data; + }); +}]).controller('JobManagerLogsController', ["$scope", "JobManagerLogsService", function($scope, JobManagerLogsService) { + JobManagerLogsService.loadLogs().then(function(data) { + if ($scope.jobmanager == null) { + $scope.jobmanager = {}; + } + return $scope.jobmanager['log'] = data; + }); + return $scope.reloadData = function() { + return JobManagerLogsService.loadLogs().then(function(data) { + return $scope.jobmanager['log'] = data; + }); + }; +}]).controller('JobManagerStdoutController', ["$scope", "JobManagerStdoutService", function($scope, JobManagerStdoutService) { + JobManagerStdoutService.loadStdout().then(function(data) { + if ($scope.jobmanager == null) { + $scope.jobmanager = {}; + } + return $scope.jobmanager['stdout'] = data; + }); + return $scope.reloadData = function() { + return JobManagerStdoutService.loadStdout().then(function(data) { + return $scope.jobmanager['stdout'] = data; + }); + }; +}]); + +angular.module('flinkApp').service('JobManagerConfigService', ["$http", "flinkConfig", "$q", function($http, flinkConfig, $q) { + var config; + config = {}; + this.loadConfig = function() { + var deferred; + deferred = $q.defer(); + $http.get("jobmanager/config").success(function(data, status, headers, config) { + config = data; + return deferred.resolve(data); + }); + return deferred.promise; + }; + return this; +}]).service('JobManagerLogsService', ["$http", "flinkConfig", "$q", function($http, flinkConfig, $q) { + var logs; + logs = {}; + this.loadLogs = function() { + var deferred; + deferred = $q.defer(); + $http.get("jobmanager/log").success(function(data, status, headers, config) { + logs = data; + return deferred.resolve(data); + }); + return deferred.promise; + }; + return this; +}]).service('JobManagerStdoutService', ["$http", "flinkConfig", "$q", function($http, flinkConfig, $q) { + var stdout; + stdout = {}; + this.loadStdout = function() { + var deferred; + deferred = $q.defer(); + $http.get("jobmanager/stdout").success(function(data, status, headers, config) { + stdout = data; + return deferred.resolve(data); + }); + return deferred.promise; + }; + return this; +}]); + +angular.module('flinkApp').controller('RunningJobsController', ["$scope", "$state", "$stateParams", "JobsService", function($scope, $state, $stateParams, JobsService) { + $scope.jobObserver = function() { + return $scope.jobs = JobsService.getJobs('running'); + }; + JobsService.registerObserver($scope.jobObserver); + $scope.$on('$destroy', function() { + return JobsService.unRegisterObserver($scope.jobObserver); + }); + return $scope.jobObserver(); +}]).controller('CompletedJobsController', ["$scope", "$state", "$stateParams", "JobsService", function($scope, $state, $stateParams, JobsService) { + $scope.jobObserver = function() { + return $scope.jobs = JobsService.getJobs('finished'); + }; + JobsService.registerObserver($scope.jobObserver); + $scope.$on('$destroy', function() { + return JobsService.unRegisterObserver($scope.jobObserver); + }); + return $scope.jobObserver(); +}]).controller('SingleJobController', ["$scope", "$state", "$stateParams", "JobsService", "$rootScope", "flinkConfig", "$interval", function($scope, $state, $stateParams, JobsService, $rootScope, flinkConfig, $interval) { + var refresher; + console.log('SingleJobController'); + $scope.jobid = $stateParams.jobid; + $scope.job = null; + $scope.plan = null; + $scope.vertices = null; + JobsService.loadJob($stateParams.jobid).then(function(data) { + $scope.job = data; + $scope.plan = data.plan; + return $scope.vertices = data.vertices; + }); + refresher = $interval(function() { + return JobsService.loadJob($stateParams.jobid).then(function(data) { + $scope.job = data; + return $scope.$broadcast('reload'); + }); + }, flinkConfig["refresh-interval"]); + return $scope.$on('$destroy', function() { + $scope.job = null; + $scope.plan = null; + $scope.vertices = null; + return $interval.cancel(refresher); + }); +}]).controller('JobPlanController', ["$scope", "$state", "$stateParams", "JobsService", function($scope, $state, $stateParams, JobsService) { + console.log('JobPlanController'); + $scope.nodeid = null; + $scope.nodeUnfolded = false; + $scope.stateList = JobsService.stateList(); + $scope.changeNode = function(nodeid) { + if (nodeid !== $scope.nodeid) { + $scope.nodeid = nodeid; + $scope.vertex = null; + $scope.subtasks = null; + $scope.accumulators = null; + return $scope.$broadcast('reload'); + } else { + $scope.nodeid = null; + $scope.nodeUnfolded = false; + $scope.vertex = null; + $scope.subtasks = null; + return $scope.accumulators = null; + } + }; + $scope.deactivateNode = function() { + $scope.nodeid = null; + $scope.nodeUnfolded = false; + $scope.vertex = null; + $scope.subtasks = null; + return $scope.accumulators = null; + }; + return $scope.toggleFold = function() { + return $scope.nodeUnfolded = !$scope.nodeUnfolded; + }; +}]).controller('JobPlanOverviewController', ["$scope", "JobsService", function($scope, JobsService) { + console.log('JobPlanOverviewController'); + if ($scope.nodeid && (!$scope.vertex || !$scope.vertex.st)) { + JobsService.getSubtasks($scope.nodeid).then(function(data) { + return $scope.subtasks = data; + }); + } + return $scope.$on('reload', function(event) { + console.log('JobPlanOverviewController'); + if ($scope.nodeid) { + return JobsService.getSubtasks($scope.nodeid).then(function(data) { + return $scope.subtasks = data; + }); + } + }); +}]).controller('JobPlanAccumulatorsController', ["$scope", "JobsService", function($scope, JobsService) { + console.log('JobPlanAccumulatorsController'); + if ($scope.nodeid && (!$scope.vertex || !$scope.vertex.accumulators)) { + JobsService.getAccumulators($scope.nodeid).then(function(data) { + $scope.accumulators = data.main; + return $scope.subtaskAccumulators = data.subtasks; + }); + } + return $scope.$on('reload', function(event) { + console.log('JobPlanAccumulatorsController'); + if ($scope.nodeid) { + return JobsService.getAccumulators($scope.nodeid).then(function(data) { + $scope.accumulators = data.main; + return $scope.subtaskAccumulators = data.subtasks; + }); + } + }); +}]).controller('JobTimelineVertexController', ["$scope", "$state", "$stateParams", "JobsService", function($scope, $state, $stateParams, JobsService) { + console.log('JobTimelineVertexController'); + JobsService.getVertex($stateParams.vertexId).then(function(data) { + return $scope.vertex = data; + }); + return $scope.$on('reload', function(event) { + console.log('JobTimelineVertexController'); + return JobsService.getVertex($stateParams.vertexId).then(function(data) { + return $scope.vertex = data; + }); + }); +}]).controller('JobExceptionsController', ["$scope", "$state", "$stateParams", "JobsService", function($scope, $state, $stateParams, JobsService) { + return JobsService.loadExceptions().then(function(data) { + return $scope.exceptions = data; + }); +}]).controller('JobPropertiesController', ["$scope", "JobsService", function($scope, JobsService) { + console.log('JobPropertiesController'); + return $scope.changeNode = function(nodeid) { + if (nodeid !== $scope.nodeid) { + $scope.nodeid = nodeid; + return JobsService.getNode(nodeid).then(function(data) { + return $scope.node = data; + }); + } else { + $scope.nodeid = null; + return $scope.node = null; + } + }; +}]); + +angular.module('flinkApp').directive('vertex', ["$state", function($state) { + return { + template: "", + scope: { + data: "=" + }, + link: function(scope, elem, attrs) { + var analyzeTime, containerW, svgEl; + svgEl = elem.children()[0]; + containerW = elem.width(); + angular.element(svgEl).attr('width', containerW); + analyzeTime = function(data) { + var chart, svg, testData; + d3.select(svgEl).selectAll("*").remove(); + testData = []; + angular.forEach(data.subtasks, function(subtask, i) { + var times; + times = [ + { + label: "Scheduled", + color: "#666", + borderColor: "#555", + starting_time: subtask.timestamps["SCHEDULED"], + ending_time: subtask.timestamps["DEPLOYING"], + type: 'regular' + }, { + label: "Deploying", + color: "#aaa", + borderColor: "#555", + starting_time: subtask.timestamps["DEPLOYING"], + ending_time: subtask.timestamps["RUNNING"], + type: 'regular' + } + ]; + if (subtask.timestamps["FINISHED"] > 0) { + times.push({ + label: "Running", + color: "#ddd", + borderColor: "#555", + starting_time: subtask.timestamps["RUNNING"], + ending_time: subtask.timestamps["FINISHED"], + type: 'regular' + }); + } + return testData.push({ + label: "(" + subtask.subtask + ") " + subtask.host, + times: times + }); + }); + chart = d3.timeline().stack().tickFormat({ + format: d3.time.format("%L"), + tickSize: 1 + }).prefix("single").labelFormat(function(label) { + return label; + }).margin({ + left: 100, + right: 0, + top: 0, + bottom: 0 + }).itemHeight(30).relativeTime(); + return svg = d3.select(svgEl).datum(testData).call(chart); + }; + analyzeTime(scope.data); + } + }; +}]).directive('timeline', ["$state", function($state) { + return { + template: "", + scope: { + vertices: "=", + jobid: "=" + }, + link: function(scope, elem, attrs) { + var analyzeTime, containerW, svgEl, translateLabel; + svgEl = elem.children()[0]; + containerW = elem.width(); + angular.element(svgEl).attr('width', containerW); + translateLabel = function(label) { + return label.replace(">", ">"); + }; + analyzeTime = function(data) { + var chart, svg, testData; + d3.select(svgEl).selectAll("*").remove(); + testData = []; + angular.forEach(data, function(vertex) { + if (vertex['start-time'] > -1) { + if (vertex.type === 'scheduled') { + return testData.push({ + times: [ + { + label: translateLabel(vertex.name), + color: "#cccccc", + borderColor: "#555555", + starting_time: vertex['start-time'], + ending_time: vertex['end-time'], + type: vertex.type + } + ] + }); + } else { + return testData.push({ + times: [ + { + label: translateLabel(vertex.name), + color: "#d9f1f7", + borderColor: "#62cdea", + starting_time: vertex['start-time'], + ending_time: vertex['end-time'], + link: vertex.id, + type: vertex.type + } + ] + }); + } + } + }); + chart = d3.timeline().stack().click(function(d, i, datum) { + if (d.link) { + return $state.go("single-job.timeline.vertex", { + jobid: scope.jobid, + vertexId: d.link + }); + } + }).tickFormat({ + format: d3.time.format("%L"), + tickSize: 1 + }).prefix("main").margin({ + left: 0, + right: 0, + top: 0, + bottom: 0 + }).itemHeight(30).showBorderLine().showHourTimeline(); + return svg = d3.select(svgEl).datum(testData).call(chart); + }; + scope.$watch(attrs.vertices, function(data) { + if (data) { + return analyzeTime(data); + } + }); + } + }; +}]).directive('jobPlan', ["$timeout", function($timeout) { + return { + template: "
", + scope: { + plan: '=', + setNode: '&' + }, + link: function(scope, elem, attrs) { + var containerW, createEdge, createLabelEdge, createLabelNode, createNode, d3mainSvg, d3mainSvgG, d3tmpSvg, drawGraph, extendLabelNodeForIteration, g, getNodeType, isSpecialIterationNode, jobid, loadJsonToDagre, mainG, mainSvgElement, mainTmpElement, mainZoom, searchForNode, shortenString, subgraphs; + g = null; + mainZoom = d3.behavior.zoom(); + subgraphs = []; + jobid = attrs.jobid; + mainSvgElement = elem.children()[0]; + mainG = elem.children().children()[0]; + mainTmpElement = elem.children()[1]; + d3mainSvg = d3.select(mainSvgElement); + d3mainSvgG = d3.select(mainG); + d3tmpSvg = d3.select(mainTmpElement); + containerW = elem.width(); + angular.element(elem.children()[0]).width(containerW); + scope.zoomIn = function() { + var translate, v1, v2; + if (mainZoom.scale() < 2.99) { + translate = mainZoom.translate(); + v1 = translate[0] * (mainZoom.scale() + 0.1 / (mainZoom.scale())); + v2 = translate[1] * (mainZoom.scale() + 0.1 / (mainZoom.scale())); + mainZoom.scale(mainZoom.scale() + 0.1); + mainZoom.translate([v1, v2]); + return d3mainSvgG.attr("transform", "translate(" + v1 + "," + v2 + ") scale(" + mainZoom.scale() + ")"); + } + }; + scope.zoomOut = function() { + var translate, v1, v2; + if (mainZoom.scale() > 0.31) { + mainZoom.scale(mainZoom.scale() - 0.1); + translate = mainZoom.translate(); + v1 = translate[0] * (mainZoom.scale() - 0.1 / (mainZoom.scale())); + v2 = translate[1] * (mainZoom.scale() - 0.1 / (mainZoom.scale())); + mainZoom.translate([v1, v2]); + return d3mainSvgG.attr("transform", "translate(" + v1 + "," + v2 + ") scale(" + mainZoom.scale() + ")"); + } + }; + createLabelEdge = function(el) { + var labelValue; + labelValue = ""; + if ((el.ship_strategy != null) || (el.local_strategy != null)) { + labelValue += "
"; + if (el.ship_strategy != null) { + labelValue += el.ship_strategy; + } + if (el.temp_mode !== undefined) { + labelValue += " (" + el.temp_mode + ")"; + } + if (el.local_strategy !== undefined) { + labelValue += ",
" + el.local_strategy; + } + labelValue += "
"; + } + return labelValue; + }; + isSpecialIterationNode = function(info) { + return info === "partialSolution" || info === "nextPartialSolution" || info === "workset" || info === "nextWorkset" || info === "solutionSet" || info === "solutionDelta"; + }; + getNodeType = function(el, info) { + if (info === "mirror") { + return 'node-mirror'; + } else if (isSpecialIterationNode(info)) { + return 'node-iteration'; + } else { + return 'node-normal'; + } + }; + createLabelNode = function(el, info, maxW, maxH) { + var labelValue, stepName; + labelValue = "
"; + if (info === "mirror") { + labelValue += "

Mirror of " + el.operator + "

"; + } else { + labelValue += "

" + el.operator + "

"; + } + if (el.description === "") { + labelValue += ""; + } else { + stepName = el.description; + stepName = shortenString(stepName); + labelValue += "

" + stepName + "

"; + } + if (el.step_function != null) { + labelValue += extendLabelNodeForIteration(el.id, maxW, maxH); + } else { + if (isSpecialIterationNode(info)) { + labelValue += "
" + info + " Node
"; + } + if (el.parallelism !== "") { + labelValue += "
Parallelism: " + el.parallelism + "
"; + } + if (el.operator !== undefined) { + labelValue += "
Operation: " + shortenString(el.operator_strategy) + "
"; + } + } + labelValue += "
"; + return labelValue; + }; + extendLabelNodeForIteration = function(id, maxW, maxH) { + var labelValue, svgID; + svgID = "svg-" + id; + labelValue = ""; + return labelValue; + }; + shortenString = function(s) { + var sbr; + if (s.charAt(0) === "<") { + s = s.replace("<", "<"); + s = s.replace(">", ">"); + } + sbr = ""; + while (s.length > 30) { + sbr = sbr + s.substring(0, 30) + "
"; + s = s.substring(30, s.length); + } + sbr = sbr + s; + return sbr; + }; + createNode = function(g, data, el, isParent, maxW, maxH) { + if (isParent == null) { + isParent = false; + } + if (el.id === data.partial_solution) { + return g.setNode(el.id, { + label: createLabelNode(el, "partialSolution", maxW, maxH), + labelType: 'html', + "class": getNodeType(el, "partialSolution") + }); + } else if (el.id === data.next_partial_solution) { + return g.setNode(el.id, { + label: createLabelNode(el, "nextPartialSolution", maxW, maxH), + labelType: 'html', + "class": getNodeType(el, "nextPartialSolution") + }); + } else if (el.id === data.workset) { + return g.setNode(el.id, { + label: createLabelNode(el, "workset", maxW, maxH), + labelType: 'html', + "class": getNodeType(el, "workset") + }); + } else if (el.id === data.next_workset) { + return g.setNode(el.id, { + label: createLabelNode(el, "nextWorkset", maxW, maxH), + labelType: 'html', + "class": getNodeType(el, "nextWorkset") + }); + } else if (el.id === data.solution_set) { + return g.setNode(el.id, { + label: createLabelNode(el, "solutionSet", maxW, maxH), + labelType: 'html', + "class": getNodeType(el, "solutionSet") + }); + } else if (el.id === data.solution_delta) { + return g.setNode(el.id, { + label: createLabelNode(el, "solutionDelta", maxW, maxH), + labelType: 'html', + "class": getNodeType(el, "solutionDelta") + }); + } else { + return g.setNode(el.id, { + label: createLabelNode(el, "", maxW, maxH), + labelType: 'html', + "class": getNodeType(el, "") + }); + } + }; + createEdge = function(g, data, el, existingNodes, pred, missingNodes) { + var missingNode; + if (existingNodes.indexOf(pred.id) !== -1) { + return g.setEdge(pred.id, el.id, { + label: createLabelEdge(pred), + labelType: 'html', + arrowhead: 'normal' + }); + } else { + missingNode = searchForNode(data, pred.id); + if (!(!missingNode || missingNodes.indexOf(missingNode.id) > -1)) { + missingNodes.push(missingNode.id); + g.setNode(missingNode.id, { + label: createLabelNode(missingNode, "mirror"), + labelType: 'html', + "class": getNodeType(missingNode, 'mirror') + }); + return g.setEdge(missingNode.id, el.id, { + label: createLabelEdge(missingNode), + labelType: 'html' + }); + } + } + }; + loadJsonToDagre = function(g, data) { + var el, existingNodes, isParent, k, l, len, len1, maxH, maxW, missingNodes, pred, r, ref, sg, toIterate; + existingNodes = []; + missingNodes = []; + if (data.nodes != null) { + toIterate = data.nodes; + } else { + toIterate = data.step_function; + isParent = true; + } + for (k = 0, len = toIterate.length; k < len; k++) { + el = toIterate[k]; + maxW = 0; + maxH = 0; + if (el.step_function) { + sg = new dagreD3.graphlib.Graph({ + multigraph: true, + compound: true + }).setGraph({ + nodesep: 20, + edgesep: 0, + ranksep: 20, + rankdir: "LR", + marginx: 10, + marginy: 10 + }); + subgraphs[el.id] = sg; + loadJsonToDagre(sg, el); + r = new dagreD3.render(); + d3tmpSvg.select('g').call(r, sg); + maxW = sg.graph().width; + maxH = sg.graph().height; + angular.element(mainTmpElement).empty(); + } + createNode(g, data, el, isParent, maxW, maxH); + existingNodes.push(el.id); + if (el.inputs != null) { + ref = el.inputs; + for (l = 0, len1 = ref.length; l < len1; l++) { + pred = ref[l]; + createEdge(g, data, el, existingNodes, pred, missingNodes); + } + } + } + return g; + }; + searchForNode = function(data, nodeID) { + var el, i, j; + for (i in data.nodes) { + el = data.nodes[i]; + if (el.id === nodeID) { + return el; + } + if (el.step_function != null) { + for (j in el.step_function) { + if (el.step_function[j].id === nodeID) { + return el.step_function[j]; + } + } + } + } + }; + drawGraph = function(data) { + var i, newScale, renderer, sg, xCenterOffset, yCenterOffset; + g = new dagreD3.graphlib.Graph({ + multigraph: true, + compound: true + }).setGraph({ + nodesep: 70, + edgesep: 0, + ranksep: 50, + rankdir: "LR", + marginx: 40, + marginy: 40 + }); + loadJsonToDagre(g, data); + renderer = new dagreD3.render(); + d3mainSvgG.call(renderer, g); + for (i in subgraphs) { + sg = subgraphs[i]; + d3mainSvg.select('svg.svg-' + i + ' g').call(renderer, sg); + } + 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); + mainZoom.scale(newScale).translate([xCenterOffset, yCenterOffset]); + d3mainSvgG.attr("transform", "translate(" + xCenterOffset + ", " + yCenterOffset + ") scale(" + mainZoom.scale() + ")"); + mainZoom.on("zoom", function() { + var ev; + ev = d3.event; + return d3mainSvgG.attr("transform", "translate(" + ev.translate + ") scale(" + ev.scale + ")"); + }); + mainZoom(d3mainSvg); + return d3mainSvgG.selectAll('.node').on('click', function(d) { + return scope.setNode({ + nodeid: d + }); + }); + }; + scope.$watch(attrs.plan, function(newPlan) { + if (newPlan) { + return drawGraph(newPlan); + } + }); + } + }; +}]); + +angular.module('flinkApp').service('JobsService', ["$http", "flinkConfig", "$log", "amMoment", "$q", "$timeout", function($http, flinkConfig, $log, amMoment, $q, $timeout) { + var currentJob, currentPlan, deferreds, jobObservers, jobs, notifyObservers; + currentJob = null; + currentPlan = null; + deferreds = {}; + jobs = { + running: [], + finished: [], + cancelled: [], + failed: [] + }; + jobObservers = []; + notifyObservers = function() { + return angular.forEach(jobObservers, function(callback) { + return callback(); + }); + }; + this.registerObserver = function(callback) { + return jobObservers.push(callback); + }; + this.unRegisterObserver = function(callback) { + var index; + index = jobObservers.indexOf(callback); + return jobObservers.splice(index, 1); + }; + this.stateList = function() { + return ['SCHEDULED', 'DEPLOYING', 'RUNNING', 'FINISHED', 'FAILED', 'CANCELING', 'CANCELED']; + }; + this.translateLabelState = function(state) { + switch (state.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(list) { + return angular.forEach(list, function(item, jobKey) { + if (!(item['end-time'] > -1)) { + return item['end-time'] = item['start-time'] + item['duration']; + } + }); + }; + this.processVertices = function(data) { + angular.forEach(data.vertices, function(vertex, i) { + return vertex.type = 'regular'; + }); + return data.vertices.unshift({ + name: 'Scheduled', + 'start-time': data.timestamps['CREATED'], + 'end-time': data.timestamps['CREATED'] + 1, + type: 'scheduled' + }); + }; + this.listJobs = function() { + var deferred; + deferred = $q.defer(); + $http.get("joboverview").success((function(_this) { + return function(data, status, headers, config) { + angular.forEach(data, function(list, listKey) { + switch (listKey) { + case 'running': + return jobs.running = _this.setEndTimes(list); + case 'finished': + return jobs.finished = _this.setEndTimes(list); + case 'cancelled': + return jobs.cancelled = _this.setEndTimes(list); + case 'failed': + return jobs.failed = _this.setEndTimes(list); + } + }); + deferred.resolve(jobs); + return notifyObservers(); + }; + })(this)); + return deferred.promise; + }; + this.getJobs = function(type) { + return jobs[type]; + }; + this.getAllJobs = function() { + return jobs; + }; + this.loadJob = function(jobid) { + currentJob = null; + deferreds.job = $q.defer(); + $http.get("jobs/" + jobid).success((function(_this) { + return function(data, status, headers, config) { + _this.setEndTimes(data.vertices); + _this.processVertices(data); + return $http.get("jobs/" + jobid + "/config").success(function(jobConfig) { + data = angular.extend(data, jobConfig); + currentJob = data; + return deferreds.job.resolve(currentJob); + }); + }; + })(this)); + return deferreds.job.promise; + }; + this.getNode = function(nodeid) { + var deferred, seekNode; + seekNode = function(nodeid, data) { + var j, len, node, sub; + for (j = 0, len = data.length; j < len; j++) { + node = data[j]; + if (node.id === nodeid) { + return node; + } + if (node.step_function) { + sub = seekNode(nodeid, node.step_function); + } + if (sub) { + return sub; + } + } + return null; + }; + deferred = $q.defer(); + deferreds.job.promise.then((function(_this) { + return function(data) { + var foundNode; + foundNode = seekNode(nodeid, currentJob.plan.nodes); + foundNode.vertex = _this.seekVertex(nodeid); + return deferred.resolve(foundNode); + }; + })(this)); + return deferred.promise; + }; + this.seekVertex = function(nodeid) { + var j, len, ref, vertex; + ref = currentJob.vertices; + for (j = 0, len = ref.length; j < len; j++) { + vertex = ref[j]; + if (vertex.id === nodeid) { + return vertex; + } + } + return null; + }; + this.getVertex = function(vertexid) { + var deferred; + deferred = $q.defer(); + deferreds.job.promise.then((function(_this) { + return function(data) { + var vertex; + vertex = _this.seekVertex(vertexid); + return $http.get("jobs/" + currentJob.jid + "/vertices/" + vertexid + "/subtasktimes").success(function(data) { + vertex.subtasks = data.subtasks; + return deferred.resolve(vertex); + }); + }; + })(this)); + return deferred.promise; + }; + this.getSubtasks = function(vertexid) { + var deferred; + deferred = $q.defer(); + deferreds.job.promise.then((function(_this) { + return function(data) { + return $http.get("jobs/" + currentJob.jid + "/vertices/" + vertexid).success(function(data) { + var subtasks; + subtasks = data.subtasks; + return deferred.resolve(subtasks); + }); + }; + })(this)); + return deferred.promise; + }; + this.getAccumulators = function(vertexid) { + var deferred; + deferred = $q.defer(); + deferreds.job.promise.then((function(_this) { + return function(data) { + return $http.get("jobs/" + currentJob.jid + "/vertices/" + vertexid + "/accumulators").success(function(data) { + var accumulators; + accumulators = data['user-accumulators']; + return $http.get("jobs/" + currentJob.jid + "/vertices/" + vertexid + "/subtasks/accumulators").success(function(data) { + var subtaskAccumulators; + subtaskAccumulators = data.subtasks; + return deferred.resolve({ + main: accumulators, + subtasks: subtaskAccumulators + }); + }); + }); + }; + })(this)); + return deferred.promise; + }; + this.loadExceptions = function() { + var deferred; + deferred = $q.defer(); + deferreds.job.promise.then((function(_this) { + return function(data) { + return $http.get("jobs/" + currentJob.jid + "/exceptions").success(function(exceptions) { + currentJob.exceptions = exceptions; + return deferred.resolve(exceptions); + }); + }; + })(this)); + return deferred.promise; + }; + return this; +}]); + +angular.module('flinkApp').controller('OverviewController', ["$scope", "OverviewService", "JobsService", "$interval", "flinkConfig", function($scope, OverviewService, JobsService, $interval, flinkConfig) { + var refresh; + $scope.jobObserver = function() { + $scope.runningJobs = JobsService.getJobs('running'); + return $scope.finishedJobs = JobsService.getJobs('finished'); + }; + JobsService.registerObserver($scope.jobObserver); + $scope.$on('$destroy', function() { + return JobsService.unRegisterObserver($scope.jobObserver); + }); + $scope.jobObserver(); + OverviewService.loadOverview().then(function(data) { + return $scope.overview = data; + }); + refresh = $interval(function() { + return OverviewService.loadOverview().then(function(data) { + return $scope.overview = data; + }); + }, flinkConfig["refresh-interval"]); + return $scope.$on('$destroy', function() { + return $interval.cancel(refresh); + }); +}]); + +angular.module('flinkApp').service('OverviewService', ["$http", "flinkConfig", "$q", function($http, flinkConfig, $q) { + var overview; + overview = {}; + this.loadOverview = function() { + var deferred; + deferred = $q.defer(); + $http.get("overview").success(function(data, status, headers, config) { + overview = data; + return deferred.resolve(data); + }); + return deferred.promise; + }; + return this; +}]); + +angular.module('flinkApp').controller('AllTaskManagersController', ["$scope", "TaskManagersService", "$interval", "flinkConfig", function($scope, TaskManagersService, $interval, flinkConfig) { + var refresh; + TaskManagersService.loadManagers().then(function(data) { + return $scope.managers = data; + }); + refresh = $interval(function() { + return TaskManagersService.loadManagers().then(function(data) { + return $scope.managers = data; + }); + }, flinkConfig["refresh-interval"]); + return $scope.$on('$destroy', function() { + return $interval.cancel(refresh); + }); +}]).controller('SingleTaskManagerController', ["$scope", "$stateParams", "SingleTaskManagerService", "$interval", "flinkConfig", function($scope, $stateParams, SingleTaskManagerService, $interval, flinkConfig) { + var refresh; + $scope.metrics = {}; + SingleTaskManagerService.loadMetrics($stateParams.taskmanagerid).then(function(data) { + return $scope.metrics = data[0]; + }); + refresh = $interval(function() { + return SingleTaskManagerService.loadMetrics($stateParams.taskmanagerid).then(function(data) { + return $scope.metrics = data[0]; + }); + }, flinkConfig["refresh-interval"]); + return $scope.$on('$destroy', function() { + return $interval.cancel(refresh); + }); +}]); + +angular.module('flinkApp').directive('livechart', function() { + return { + link: function(scope, element, attrs) { + var getChartOptions, getChartType, getKey1, getKey2, getKey3, getKey4, getYAxisTitle, updateCharts; + getChartType = function() { + if (attrs.key === "cpuLoad") { + return "spline"; + } else { + return "area"; + } + }; + getYAxisTitle = function() { + if (attrs.key === "cpuLoad") { + return "CPU Usage(%)"; + } else { + return "Memory(MB)"; + } + }; + getKey1 = function() { + return "memory.total." + attrs.key; + }; + getKey2 = function() { + return "memory.heap." + attrs.key; + }; + getKey3 = function() { + return "memory.non-heap." + attrs.key; + }; + getKey4 = function() { + return "cpuLoad"; + }; + getChartOptions = function() { + return { + title: { + text: ' ' + }, + chart: { + type: getChartType(), + zoomType: 'x' + }, + xAxis: { + type: 'datetime' + }, + yAxis: { + title: { + text: getYAxisTitle() + }, + min: attrs.key === "cpuLoad" ? 0 : void 0, + max: attrs.key === "cpuLoad" ? 100 : void 0 + }, + series: [ + { + name: "Memory: Total", + id: getKey1(), + data: [], + color: "#7cb5ec" + }, { + name: "Memory: Heap", + id: getKey2(), + data: [], + color: "#434348" + }, { + name: "Memory: Non-Heap", + id: getKey3(), + data: [], + color: "#90ed7d" + }, { + name: "CPU Usage", + id: getKey4(), + data: [], + color: "#f7a35c", + showInLegend: false + } + ], + legend: { + enabled: false + }, + tooltip: { + shared: true + }, + exporting: { + enabled: false + }, + credits: { + enabled: false + } + }; + }; + if (element.highcharts() == null) { + element.highcharts(getChartOptions()); + } + scope.$watch(attrs.data, function(value) { + return updateCharts(value); + }); + return updateCharts = function(value) { + return (function(value) { + var chart, divider, heartbeat; + heartbeat = value.timeSinceLastHeartbeat; + chart = element.highcharts(); + if (attrs.key === "cpuLoad") { + return chart.get(getKey4()).addPoint([heartbeat, +((value.metrics.gauges[getKey4()].value * 100).toFixed(2))], true, false); + } else { + divider = 1048576; + chart.get(getKey1()).addPoint([heartbeat, +((value.metrics.gauges[getKey1()].value / divider).toFixed(2))], true, false); + chart.get(getKey2()).addPoint([heartbeat, +((value.metrics.gauges[getKey2()].value / divider).toFixed(2))], true, false); + return chart.get(getKey3()).addPoint([heartbeat, +((value.metrics.gauges[getKey3()].value / divider).toFixed(2))], true, false); + } + })(value); + }; + } + }; +}); + +angular.module('flinkApp').service('TaskManagersService', ["$http", "flinkConfig", "$q", function($http, flinkConfig, $q) { + this.loadManagers = function() { + var deferred; + deferred = $q.defer(); + $http.get("taskmanagers").success(function(data, status, headers, config) { + return deferred.resolve(data['taskmanagers']); + }); + return deferred.promise; + }; + return this; +}]).service('SingleTaskManagerService', ["$http", "flinkConfig", "$q", function($http, flinkConfig, $q) { + this.loadMetrics = function(taskmanagerid) { + var deferred; + deferred = $q.defer(); + $http.get("taskmanagers/" + taskmanagerid).success(function(data, status, headers, config) { + return deferred.resolve(data['taskmanagers']); + }); + return deferred.promise; + }; + return this; +}]); + +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImluZGV4LmNvZmZlZSIsImluZGV4LmpzIiwiY29tbW9uL2RpcmVjdGl2ZXMuY29mZmVlIiwiY29tbW9uL2RpcmVjdGl2ZXMuanMiLCJjb21tb24vZmlsdGVycy5jb2ZmZWUiLCJjb21tb24vZmlsdGVycy5qcyIsImNvbW1vbi9zZXJ2aWNlcy5jb2ZmZWUiLCJjb21tb24vc2VydmljZXMuanMiLCJtb2R1bGVzL2pvYm1hbmFnZXIvam9ibWFuYWdlci5jdHJsLmNvZmZlZSIsIm1vZHVsZXMvam9ibWFuYWdlci9qb2JtYW5hZ2VyLmN0cmwuanMiLCJtb2R1bGVzL2pvYm1hbmFnZXIvam9ibWFuYWdlci5zdmMuY29mZmVlIiwibW9kdWxlcy9qb2JtYW5hZ2VyL2pvYm1hbmFnZXIuc3ZjLmpzIiwibW9kdWxlcy9qb2JzL2pvYnMuY3RybC5jb2ZmZWUiLCJtb2R1bGVzL2pvYnMvam9icy5jdHJsLmpzIiwibW9kdWxlcy9qb2JzL2pvYnMuZGlyLmNvZmZlZSIsIm1vZHVsZXMvam9icy9qb2JzLmRpci5qcyIsIm1vZHVsZXMvam9icy9qb2JzLnN2Yy5jb2ZmZWUiLCJtb2R1bGVzL2pvYnMvam9icy5zdmMuanMiLCJtb2R1bGVzL292ZXJ2aWV3L292ZXJ2aWV3LmN0cmwuY29mZmVlIiwibW9kdWxlcy9vdmVydmlldy9vdmVydmlldy5jdHJsLmpzIiwibW9kdWxlcy9vdmVydmlldy9vdmVydmlldy5zdmMuY29mZmVlIiwibW9kdWxlcy9vdmVydmlldy9vdmVydmlldy5zdmMuanMiLCJtb2R1bGVzL3Rhc2ttYW5hZ2VyL3Rhc2ttYW5 hZ2VyLmN0cmwuY29mZmVlIiwibW9kdWxlcy90YXNrbWFuYWdlci90YXNrbWFuYWdlci5jdHJsLmpzIiwibW9kdWxlcy90YXNrbWFuYWdlci90YXNrbWFuYWdlci5kaXIuY29mZmVlIiwibW9kdWxlcy90YXNrbWFuYWdlci90YXNrbWFuYWdlci5kaXIuanMiLCJtb2R1bGVzL3Rhc2ttYW5hZ2VyL3Rhc2ttYW5hZ2VyLnN2Yy5jb2ZmZWUiLCJtb2R1bGVzL3Rhc2ttYW5hZ2VyL3Rhc2ttYW5hZ2VyLnN2Yy5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFrQkEsUUFBUSxPQUFPLFlBQVksQ0FBQyxhQUFhLGtCQUl4QyxtQkFBSSxTQUFDLFlBQUQ7RUFDSCxXQUFXLGlCQUFpQjtFQ3JCNUIsT0RzQkEsV0FBVyxjQUFjLFdBQUE7SUFDdkIsV0FBVyxpQkFBaUIsQ0FBQyxXQUFXO0lDckJ4QyxPRHNCQSxXQUFXLGVBQWU7O0lBSTdCLE1BQU0sZUFBZTtFQUNwQixvQkFBb0I7R0FLckIsK0RBQUksU0FBQyxhQUFhLGFBQWEsYUFBYSxXQUF4QztFQUNILFlBQVksYUFBYSxLQUFLLFNBQUMsUUFBRDtJQUM1QixRQUFRLE9BQU8sYUFBYTtJQUU1QixZQUFZO0lDNUJaLE9EOEJBLFVBQVUsV0FBQTtNQzdCUixPRDhCQSxZQUFZO09BQ1osWUFBWTs7RUFFaEIsV0FBVyxXQUFXO0lBQ3BCLFFBQVE7TUFDTixRQUFROzs7RUFZWixXQUFXLGNBQWMsUUFBUTtJQUNoQyxNQUFNO0lBQ04sS0FBSztJQUNMLE1BQU07S0FDSixNQUFNLFNBQVMscUJBQXFCLFFBQVE7RUFFL0MsV0FBVyxRQUFRO0lBQ2xCLFFBQVEsQ0FBQyxXQUFXLFdBQVcsV0FB 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 TTtjQUFhLElBQUk7Y0FBVyxNQUFNO2NBQUksT0FBTztjQUFXLGNBQWM7OztVQUUvRSxRQUFRO1lBQUMsU0FBUzs7VUFDbEIsU0FBUztZQUFDLFFBQVE7O1VBQ2xCLFdBQVc7WUFBQyxTQUFTOztVQUNyQixTQUFTO1lBQUMsU0FBUzs7OztNQUdyQixJQUFJLFFBQUEsZ0JBQUEsTUFBSjtRQUNFLFFBQVEsV0FBVzs7TUFFckIsTUFBTSxPQUFPLE1BQU0sTUFBTSxTQUFDLE9BQUQ7UUN1QnZCLE9EdEJBLGFBQWE7O01Dd0JmLE9EckJBLGVBQWUsU0FBQyxPQUFEO1FDc0JiLE9EckJFLENBQUEsU0FBQyxPQUFEO1VBQ0EsSUFBQSxPQUFBLFNBQUE7VUFBQSxZQUFZLE1BQU07VUFDbEIsUUFBUSxRQUFRO1VBQ2hCLElBQUcsTUFBTSxRQUFPLFdBQWhCO1lDdUJFLE9EdEJBLE1BQU0sSUFBSSxXQUFXLFNBQVMsQ0FDNUIsV0FBVyxFQUFFLENBQUMsTUFBTSxRQUFRLE9BQU8sV0FBVyxRQUFRLEtBQUssUUFBUSxNQUNsRSxNQUFNO2lCQUhYO1lBS0UsVUFBVTtZQUNWLE1BQU0sSUFBSSxXQUFXLFNBQVMsQ0FDNUIsV0FBVyxFQUFFLENBQUMsTUFBTSxRQUFRLE9BQU8sV0FBVyxRQUFRLFNBQVMsUUFBUSxNQUN0RSxNQUFNO1lBQ1QsTUFBTSxJQUFJLFdBQVcsU0FBUyxDQUM1QixXQUFXLEVBQUUsQ0FBQyxNQUFNLFFBQVEsT0FBTyxXQUFXLFFBQVEsU0FBUyxRQUFRLE1BQ3RFLE1BQU07WUNpQlQsT0RoQkEsTUFBTSxJQUFJLFdBQVcsU0FBUyxDQUM1QixXQUFXLEVBQUUsQ0FBQyxNQUFNLFFBQVEsT0FBTyxXQUFXLFFBQVEsU0FBUyxRQ UFRLE1BQ3RFLE1BQU07O1dBakJWOzs7OztBQ3NDWDtBQzdGQSxRQUFRLE9BQU8sWUFFZCxRQUFRLHNEQUF1QixTQUFDLE9BQU8sYUFBYSxJQUFyQjtFQUM5QixLQUFDLGVBQWUsV0FBQTtJQUNkLElBQUE7SUFBQSxXQUFXLEdBQUc7SUFFZCxNQUFNLElBQUksZ0JBQ1QsUUFBUSxTQUFDLE1BQU0sUUFBUSxTQUFTLFFBQXhCO01DcEJQLE9EcUJBLFNBQVMsUUFBUSxLQUFLOztJQ25CeEIsT0RxQkEsU0FBUzs7RUNuQlgsT0RxQkE7SUFFRCxRQUFRLDJEQUE0QixTQUFDLE9BQU8sYUFBYSxJQUFyQjtFQUNuQyxLQUFDLGNBQWMsU0FBQyxlQUFEO0lBQ2IsSUFBQTtJQUFBLFdBQVcsR0FBRztJQUVkLE1BQU0sSUFBSSxrQkFBa0IsZUFDM0IsUUFBUSxTQUFDLE1BQU0sUUFBUSxTQUFTLFFBQXhCO01DdEJQLE9EdUJBLFNBQVMsUUFBUSxLQUFLOztJQ3JCeEIsT0R1QkEsU0FBUzs7RUNyQlgsT0R1QkE7O0FDckJGIiwiZmlsZSI6ImluZGV4LmpzIiwic291cmNlc0NvbnRlbnQiOlsiI1xyXG4jIExpY2Vuc2VkIHRvIHRoZSBBcGFjaGUgU29mdHdhcmUgRm91bmRhdGlvbiAoQVNGKSB1bmRlciBvbmVcclxuIyBvciBtb3JlIGNvbnRyaWJ1dG9yIGxpY2Vuc2UgYWdyZWVtZW50cy4gIFNlZSB0aGUgTk9USUNFIGZpbGVcclxuIyBkaXN0cmlidXRlZCB3aXRoIHRoaXMgd29yayBmb3IgYWRkaXRpb25hbCBpbmZvcm1hdGlvblxyXG4jIHJlZ2FyZGluZyBjb3B5cmlnaHQgb3duZXJzaGlwLiAgVGhlIEFTRiBsaWNlbnNlcyB0aGlzIGZpbG VcclxuIyB0byB5b3UgdW5kZXIgdGhlIEFwYWNoZSBMaWNlbnNlLCBWZXJzaW9uIDIuMCAodGhlXHJcbiMgXCJMaWNlbnNlXCIpOyB5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlXHJcbiMgd2l0aCB0aGUgTGljZW5zZS4gIFlvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGUgTGljZW5zZSBhdFxyXG4jXHJcbiMgICAgIGh0dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMFxyXG4jXHJcbiMgVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZVxyXG4jIGRpc3RyaWJ1dGVkIHVuZGVyIHRoZSBMaWNlbnNlIGlzIGRpc3RyaWJ1dGVkIG9uIGFuIFwiQVMgSVNcIiBCQVNJUyxcclxuIyBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC5cclxuIyBTZWUgdGhlIExpY2Vuc2UgZm9yIHRoZSBzcGVjaWZpYyBsYW5ndWFnZSBnb3Zlcm5pbmcgcGVybWlzc2lvbnMgYW5kXHJcbiMgbGltaXRhdGlvbnMgdW5kZXIgdGhlIExpY2Vuc2UuXHJcbiNcclxuXHJcbmFuZ3VsYXIubW9kdWxlKCdmbGlua0FwcCcsIFsndWkucm91dGVyJywgJ2FuZ3VsYXJNb21lbnQnXSlcclxuXHJcbiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuXHJcbi5ydW4gKCRyb290U2NvcGUpIC0+XHJcbiAgJHJvb3RTY29wZS5zaWR lYmFyVmlzaWJsZSA9IGZhbHNlXHJcbiAgJHJvb3RTY29wZS5zaG93U2lkZWJhciA9IC0+XHJcbiAgICAkcm9vdFNjb3BlLnNpZGViYXJWaXNpYmxlID0gISRyb290U2NvcGUuc2lkZWJhclZpc2libGVcclxuICAgICRyb290U2NvcGUuc2lkZWJhckNsYXNzID0gJ2ZvcmNlLXNob3cnXHJcblxyXG4jIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXHJcblxyXG4udmFsdWUgJ2ZsaW5rQ29uZmlnJywge1xyXG4gIFwicmVmcmVzaC1pbnRlcnZhbFwiOiAxMDAwMFxyXG59XHJcblxyXG4jIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXHJcblxyXG4ucnVuIChKb2JzU2VydmljZSwgTWFpblNlcnZpY2UsIGZsaW5rQ29uZmlnLCAkaW50ZXJ2YWwpIC0+XHJcbiAgTWFpblNlcnZpY2UubG9hZENvbmZpZygpLnRoZW4gKGNvbmZpZykgLT5cclxuICAgIGFuZ3VsYXIuZXh0ZW5kIGZsaW5rQ29uZmlnLCBjb25maWdcclxuXHJcbiAgICBKb2JzU2VydmljZS5saXN0Sm9icygpXHJcblxyXG4gICAgJGludGVydmFsIC0+XHJcbiAgICAgIEpvYnNTZXJ2aWNlLmxpc3RKb2JzKClcclxuICAgICwgZmxpbmtDb25maWdbXCJyZWZyZXNoLWludGVydmFsXCJdXHJcblxyXG4gIEhpZ2hjaGFydHMuc2V0T3B0aW9ucyh7XHJcbiAgICBnbG9iYWw6IHtcclxuICAgICAgdXNlVVRDOiBmYWxzZVxyXG4gICAgfVxyXG4gIH0pXHJcblxyXG4gICNcclxuICAjIEdyaWQtbGlnaHQgdGhlbWUgZm9yIEhpZ2hj aGFydHMgSlNcclxuICAjIEBhdXRob3IgVG9yc3RlaW4gSG9uc2lcclxuICAjXHJcbiAgIyBUYWtlbiBmcm9tIGh0dHBzOi8vZ2l0aHViLmNvbS9oaWdoc2xpZGUtc29mdHdhcmUvaGlnaGNoYXJ0cy5jb21cclxuICAjXHJcblxyXG5cclxuICBIaWdoY2hhcnRzLmNyZWF0ZUVsZW1lbnQoJ2xpbmsnLCB7XHJcbiAgXHRocmVmOiAnLy9mb250cy5nb29nbGVhcGlzLmNvbS9jc3M/ZmFtaWx5PURvc2lzOjQwMCw2MDAnLFxyXG4gIFx0cmVsOiAnc3R5bGVzaGVldCcsXHJcbiAgXHR0eXBlOiAndGV4dC9jc3MnXHJcbiAgfSwgbnVsbCwgZG9jdW1lbnQuZ2V0RWxlbWVudHNCeVRhZ05hbWUoJ2hlYWQnKVswXSk7XHJcblxyXG4gIEhpZ2hjaGFydHMudGhlbWUgPSB7XHJcbiAgXHRjb2xvcnM6IFtcIiM3Y2I1ZWNcIiwgXCIjZjdhMzVjXCIsIFwiIzkwZWU3ZVwiLCBcIiM3Nzk4QkZcIiwgXCIjYWFlZWVlXCIsIFwiI2ZmMDA2NlwiLCBcIiNlZWFhZWVcIixcclxuICBcdFx0XCIjNTVCRjNCXCIsIFwiI0RGNTM1M1wiLCBcIiM3Nzk4QkZcIiwgXCIjYWFlZWVlXCJdLFxyXG4gIFx0Y2hhcnQ6IHtcclxuICBcdFx0YmFja2dyb3VuZENvbG9yOiBudWxsLFxyXG4gIFx0XHRzdHlsZToge1xyXG4gIFx0XHRcdGZvbnRGYW1pbHk6IFwiRG9zaXMsIHNhbnMtc2VyaWZcIlxyXG4gIFx0XHR9XHJcbiAgXHR9LFxyXG4gIFx0dGl0bGU6IHtcclxuICBcdFx0c3R5bGU6IHtcclxuICBcdFx0XHRmb250U2l6ZTogJzE2cHgnLFxyXG4gIFx0XHRcd GZvbnRXZWlnaHQ6ICdib2xkJyxcclxuICBcdFx0XHR0ZXh0VHJhbnNmb3JtOiAndXBwZXJjYXNlJ1xyXG4gIFx0XHR9XHJcbiAgXHR9LFxyXG4gIFx0dG9vbHRpcDoge1xyXG4gIFx0XHRib3JkZXJXaWR0aDogMCxcclxuICBcdFx0YmFja2dyb3VuZENvbG9yOiAncmdiYSgyMTksMjE5LDIxNiwwLjgpJyxcclxuICBcdFx0c2hhZG93OiBmYWxzZVxyXG4gIFx0fSxcclxuICBcdGxlZ2VuZDoge1xyXG4gIFx0XHRpdGVtU3R5bGU6IHtcclxuICBcdFx0XHRmb250V2VpZ2h0OiAnYm9sZCcsXHJcbiAgXHRcdFx0Zm9udFNpemU6ICcxM3B4J1xyXG4gIFx0XHR9XHJcbiAgXHR9LFxyXG4gIFx0eEF4aXM6IHtcclxuICBcdFx0Z3JpZExpbmVXaWR0aDogMSxcclxuICBcdFx0bGFiZWxzOiB7XHJcbiAgXHRcdFx0c3R5bGU6IHtcclxuICBcdFx0XHRcdGZvbnRTaXplOiAnMTJweCdcclxuICBcdFx0XHR9XHJcbiAgXHRcdH1cclxuICBcdH0sXHJcbiAgXHR5QXhpczoge1xyXG4gIFx0XHRtaW5vclRpY2tJbnRlcnZhbDogJ2F1dG8nLFxyXG4gIFx0XHR0aXRsZToge1xyXG4gIFx0XHRcdHN0eWxlOiB7XHJcbiAgXHRcdFx0XHR0ZXh0VHJhbnNmb3JtOiAndXBwZXJjYXNlJ1xyXG4gIFx0XHRcdH1cclxuICBcdFx0fSxcclxuICBcdFx0bGFiZWxzOiB7XHJcbiAgXHRcdFx0c3R5bGU6IHtcclxuICBcdFx0XHRcdGZvbnRTaXplOiAnMTJweCdcclxuICBcdFx0XHR9XHJcbiAgXHRcdH1cclxuICBcdH0sXHJcbiAgXHRwbG90T3B0aW9ucz oge1xyXG4gIFx0XHRjYW5kbGVzdGljazoge1xyXG4gIFx0XHRcdGxpbmVDb2xvcjogJyM0MDQwNDgnXHJcbiAgXHRcdH1cclxuICBcdH0sXHJcblxyXG4gIFx0YmFja2dyb3VuZDI6ICcjRjBGMEVBJ1xyXG5cclxuICB9O1xyXG5cclxuICBIaWdoY2hhcnRzLnNldE9wdGlvbnMoSGlnaGNoYXJ0cy50aGVtZSk7XHJcblxyXG5cclxuIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxyXG5cclxuLmNvbmZpZyAoJHVpVmlld1Njcm9sbFByb3ZpZGVyKSAtPlxyXG4gICR1aVZpZXdTY3JvbGxQcm92aWRlci51c2VBbmNob3JTY3JvbGwoKVxyXG5cclxuIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxyXG5cclxuLmNvbmZpZyAoJHN0YXRlUHJvdmlkZXIsICR1cmxSb3V0ZXJQcm92aWRlcikgLT5cclxuICAkc3RhdGVQcm92aWRlci5zdGF0ZSBcIm92ZXJ2aWV3XCIsXHJcbiAgICB1cmw6IFwiL292ZXJ2aWV3XCJcclxuICAgIHZpZXdzOlxyXG4gICAgICBtYWluOlxyXG4gICAgICAgIHRlbXBsYXRlVXJsOiBcInBhcnRpYWxzL292ZXJ2aWV3Lmh0bWxcIlxyXG4gICAgICAgIGNvbnRyb2xsZXI6ICdPdmVydmlld0NvbnRyb2xsZXInXHJcblxyXG4gIC5zdGF0ZSBcInJ1bm5pbmctam9ic1wiLFxyXG4gICAgdXJsOiBcIi9ydW5uaW5nLWpvYnNcIlxyXG4gICAgdmlld3M6XHJcbiAgICAgIG1haW46XHJcbiAgICAgICAgdGVtcGxhdGVVcmw6IFwicGFydGlhbHMvam9icy9ydW5uaW5 nLWpvYnMuaHRtbFwiXHJcbiAgICAgICAgY29udHJvbGxlcjogJ1J1bm5pbmdKb2JzQ29udHJvbGxlcidcclxuICBcclxuICAuc3RhdGUgXCJjb21wbGV0ZWQtam9ic1wiLFxyXG4gICAgdXJsOiBcIi9jb21wbGV0ZWQtam9ic1wiXHJcbiAgICB2aWV3czpcclxuICAgICAgbWFpbjpcclxuICAgICAgICB0ZW1wbGF0ZVVybDogXCJwYXJ0aWFscy9qb2JzL2NvbXBsZXRlZC1qb2JzLmh0bWxcIlxyXG4gICAgICAgIGNvbnRyb2xsZXI6ICdDb21wbGV0ZWRKb2JzQ29udHJvbGxlcidcclxuXHJcbiAgLnN0YXRlIFwic2luZ2xlLWpvYlwiLFxyXG4gICAgdXJsOiBcIi9qb2JzL3tqb2JpZH1cIlxyXG4gICAgYWJzdHJhY3Q6IHRydWVcclxuICAgIHZpZXdzOlxyXG4gICAgICBtYWluOlxyXG4gICAgICAgIHRlbXBsYXRlVXJsOiBcInBhcnRpYWxzL2pvYnMvam9iLmh0bWxcIlxyXG4gICAgICAgIGNvbnRyb2xsZXI6ICdTaW5nbGVKb2JDb250cm9sbGVyJ1xyXG5cclxuICAuc3RhdGUgXCJzaW5nbGUtam9iLnBsYW5cIixcclxuICAgIHVybDogXCJcIlxyXG4gICAgYWJzdHJhY3Q6IHRydWVcclxuICAgIHZpZXdzOlxyXG4gICAgICBkZXRhaWxzOlxyXG4gICAgICAgIHRlbXBsYXRlVXJsOiBcInBhcnRpYWxzL2pvYnMvam9iLnBsYW4uaHRtbFwiXHJcbiAgICAgICAgY29udHJvbGxlcjogJ0pvYlBsYW5Db250cm9sbGVyJ1xyXG5cclxuICAuc3RhdGUgXCJzaW5nbGUtam9iLnBsYW4ub3ZlcnZpZXdcIixcclxuICAgIHVybDogXCJc IlxyXG4gICAgdmlld3M6XHJcbiAgICAgICdub2RlLWRldGFpbHMnOlxyXG4gICAgICAgIHRlbXBsYXRlVXJsOiBcInBhcnRpYWxzL2pvYnMvam9iLnBsYW4ubm9kZS1saXN0Lm92ZXJ2aWV3Lmh0bWxcIlxyXG4gICAgICAgIGNvbnRyb2xsZXI6ICdKb2JQbGFuT3ZlcnZpZXdDb250cm9sbGVyJyBcclxuXHJcbiAgLnN0YXRlIFwic2luZ2xlLWpvYi5wbGFuLmFjY3VtdWxhdG9yc1wiLFxyXG4gICAgdXJsOiBcIi9hY2N1bXVsYXRvcnNcIlxyXG4gICAgdmlld3M6XHJcbiAgICAgICdub2RlLWRldGFpbHMnOlxyXG4gICAgICAgIHRlbXBsYXRlVXJsOiBcInBhcnRpYWxzL2pvYnMvam9iLnBsYW4ubm9kZS1saXN0LmFjY3VtdWxhdG9ycy5odG1sXCJcclxuICAgICAgICBjb250cm9sbGVyOiAnSm9iUGxhbkFjY3VtdWxhdG9yc0NvbnRyb2xsZXInIFxyXG5cclxuICAuc3RhdGUgXCJzaW5nbGUtam9iLnRpbWVsaW5lXCIsXHJcbiAgICB1cmw6IFwiL3RpbWVsaW5lXCJcclxuICAgIHZpZXdzOlxyXG4gICAgICBkZXRhaWxzOlxyXG4gICAgICAgIHRlbXBsYXRlVXJsOiBcInBhcnRpYWxzL2pvYnMvam9iLnRpbWVsaW5lLmh0bWxcIlxyXG5cclxuICAuc3RhdGUgXCJzaW5nbGUtam9iLnRpbWVsaW5lLnZlcnRleFwiLFxyXG4gICAgdXJsOiBcIi97dmVydGV4SWR9XCJcclxuICAgIHZpZXdzOlxyXG4gICAgICB2ZXJ0ZXg6XHJcbiAgICAgICAgdGVtcGxhdGVVcmw6IFwicGFydGlhbHMvam9icy9qb2IudGltZWxpbmUudmVydGV4L mh0bWxcIlxyXG4gICAgICAgIGNvbnRyb2xsZXI6ICdKb2JUaW1lbGluZVZlcnRleENvbnRyb2xsZXInXHJcblxyXG4gIC5zdGF0ZSBcInNpbmdsZS1qb2Iuc3RhdGlzdGljc1wiLFxyXG4gICAgdXJsOiBcIi9zdGF0aXN0aWNzXCJcclxuICAgIHZpZXdzOlxyXG4gICAgICBkZXRhaWxzOlxyXG4gICAgICAgIHRlbXBsYXRlVXJsOiBcInBhcnRpYWxzL2pvYnMvam9iLnN0YXRpc3RpY3MuaHRtbFwiXHJcblxyXG4gIC5zdGF0ZSBcInNpbmdsZS1qb2IuZXhjZXB0aW9uc1wiLFxyXG4gICAgdXJsOiBcIi9leGNlcHRpb25zXCJcclxuICAgIHZpZXdzOlxyXG4gICAgICBkZXRhaWxzOlxyXG4gICAgICAgIHRlbXBsYXRlVXJsOiBcInBhcnRpYWxzL2pvYnMvam9iLmV4Y2VwdGlvbnMuaHRtbFwiXHJcbiAgICAgICAgY29udHJvbGxlcjogJ0pvYkV4Y2VwdGlvbnNDb250cm9sbGVyJ1xyXG5cclxuICAuc3RhdGUgXCJzaW5nbGUtam9iLnByb3BlcnRpZXNcIixcclxuICAgIHVybDogXCIvcHJvcGVydGllc1wiXHJcbiAgICB2aWV3czpcclxuICAgICAgZGV0YWlsczpcclxuICAgICAgICB0ZW1wbGF0ZVVybDogXCJwYXJ0aWFscy9qb2JzL2pvYi5wcm9wZXJ0aWVzLmh0bWxcIlxyXG4gICAgICAgIGNvbnRyb2xsZXI6ICdKb2JQcm9wZXJ0aWVzQ29udHJvbGxlcidcclxuXHJcbiAgLnN0YXRlIFwic2luZ2xlLWpvYi5jb25maWdcIixcclxuICAgIHVybDogXCIvY29uZmlnXCJcclxuICAgIHZpZXdzOlxyXG4gICAgICBkZXRhaWxzOl xyXG4gICAgICAgIHRlbXBsYXRlVXJsOiBcInBhcnRpYWxzL2pvYnMvam9iLmNvbmZpZy5odG1sXCJcclxuXHJcbiAgLnN0YXRlIFwiYWxsLW1hbmFnZXJcIixcclxuICAgIHVybDogXCIvdGFza21hbmFnZXJzXCJcclxuICAgIHZpZXdzOlxyXG4gICAgICBtYWluOlxyXG4gICAgICAgIHRlbXBsYXRlVXJsOiBcInBhcnRpYWxzL3Rhc2ttYW5hZ2VyL2luZGV4Lmh0bWxcIlxyXG4gICAgICAgIGNvbnRyb2xsZXI6ICdBbGxUYXNrTWFuYWdlcnNDb250cm9sbGVyJ1xyXG5cclxuICAuc3RhdGUgXCJzaW5nbGUtbWFuYWdlclwiLFxyXG4gICAgICB1cmw6IFwiL3Rhc2ttYW5hZ2VyL3t0YXNrbWFuYWdlcmlkfVwiXHJcbiAgICAgIHZpZXdzOlxyXG4gICAgICAgIG1haW46XHJcbiAgICAgICAgICB0ZW1wbGF0ZVVybDogXCJwYXJ0aWFscy90YXNrbWFuYWdlci90YX