<!doctype html>
<html ng-app="App">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta name="generator" content="Rally version 0.12.1">
  <title>Rally | Rally Task Report</title>
  
  
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/nvd3/1.1.15-beta/nv.d3.min.css">
  <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.3/angular.min.js"></script>
  <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.13/d3.min.js"></script>
  <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/nvd3/1.1.15-beta/nv.d3.min.js"></script>
  

  <script type="text/javascript">
    "use strict";
    function changeFrameHeight(){
  var ifm= document.getElementById("embedchart");
  ifm.height=document.documentElement.clientHeight;
  ifm.width=document.documentElement.clientWidth;
}
window.onresize=function(){
  changeFrameHeight();
}
var widgetDirective = function($compile) {
  var Chart = {
    _render: function(node, data, chart, do_after){
      nv.addGraph(function() {
        d3.select(node)
          .datum(data).transition().duration(0)
          .call(chart);
        if (typeof do_after === "function") {
          do_after(node, chart)
        }
        nv.utils.windowResize(chart.update);
      })
    },
    _widgets: {
      Pie: "pie",
      StackedArea: "stack",
      Lines: "lines",
      Histogram: "histogram"
    },
    get_chart: function(widget) {
      if (widget in this._widgets) {
        var name = this._widgets[widget];
        return Chart[name]
      }
      return function() { console.log("Error: unexpected widget:", widget) }
    },
    pie: function(node, data, opts, do_after) {
      var chart = nv.models.pieChart()
        .x(function(d) { return d.key })
        .y(function(d) { return d.values })
        .showLabels(true)
        .labelType("percent")
        .donut(true)
        .donutRatio(0.25)
        .donutLabelsOutside(true)
        .color(function(d){
          if (d.data && d.data.color) { return d.data.color }
        });
      var colorizer = new Chart.colorizer("errors"), data_ = [];
      for (var i in data) {
        data_.push({key:data[i][0], values:data[i][1], color:colorizer.get_color(data[i][0])})
      }
      Chart._render(node, data_, chart)
    },
    colorizer: function(failure_key, failure_color) {
      this.failure_key = failure_key || "failed_duration";
      this.failure_color = failure_color || "#d62728";  // red
      this.color_idx = -1;
      /* NOTE(amaretskiy): this is actually a result of
         d3.scale.category20().range(), excluding red color (#d62728)
         which is reserved for errors */
      this.colors = ["#1f77b4", "#aec7e8", "#ff7f0e", "#ffbb78", "#2ca02c",
                     "#98df8a", "#ff9896", "#9467bd", "#c5b0d5", "#8c564b",
                     "#c49c94", "#e377c2", "#f7b6d2", "#7f7f7f", "#c7c7c7",
                     "#bcbd22", "#dbdb8d", "#17becf", "#9edae5"];
      this.get_color = function(key) {
        if (key === this.failure_key) {
          return this.failure_color
        }
        if (this.color_idx > (this.colors.length - 2)) {
          this.color_idx = 0
        } else {
          this.color_idx++
        }
        return this.colors[this.color_idx]
      }
    },
    stack: function(node, data, opts, do_after) {
      var chart = nv.models.stackedAreaChart()
        .x(function(d) { return d[0] })
        .y(function(d) { return d[1] })
        .useInteractiveGuideline(opts.guide)
        .showControls(opts.controls)
        .clipEdge(true);
      chart.xAxis
        .axisLabel(opts.xname)
        .tickFormat(opts.xformat)
        .showMaxMin(opts.showmaxmin);
      chart.yAxis
        .orient("left")
        .tickFormat(d3.format(opts.yformat || ",.3f"));
      var colorizer = new Chart.colorizer(), data_ = [];
      for (var i in data) {
        data_.push({key:data[i][0], values:data[i][1], color:colorizer.get_color(data[i][0])})
      }
      Chart._render(node, data_, chart, do_after);
    },
    lines: function(node, data, opts, do_after) {
      var chart = nv.models.lineChart()
        .x(function(d) { return d[0] })
        .y(function(d) { return d[1] })
        .useInteractiveGuideline(opts.guide)
        .clipEdge(true);
      chart.xAxis
        .axisLabel(opts.xname)
        .tickFormat(opts.xformat)
        .rotateLabels(opts.xrotate)
        .showMaxMin(opts.showmaxmin);
      chart.yAxis
        .orient("left")
        .tickFormat(d3.format(opts.yformat || ",.3f"));
      var colorizer = new Chart.colorizer(), data_ = [];
      for (var i in data) {
        data_.push({key:data[i][0], values:data[i][1], color:colorizer.get_color(data[i][0])})
      }
      Chart._render(node, data_, chart, do_after)
    },
    histogram: function(node, data, opts) {
      var chart = nv.models.multiBarChart()
        .reduceXTicks(true)
        .showControls(false)
        .transitionDuration(0)
        .groupSpacing(0.05);
      chart
        .legend.radioButtonMode(true);
      chart.xAxis
        .axisLabel("Duration (seconds)")
        .tickFormat(d3.format(",.2f"));
      chart.yAxis
        .axisLabel("Iterations (frequency)")
        .tickFormat(d3.format("d"));
      Chart._render(node, data, chart)
    }
  };

  return {
    restrict: "A",
    scope: { data: "=" },
    link: function(scope, element, attrs) {
      scope.$watch("data", function(data) {
        if (! data) { return console.log("Chart has no data to render!") }
        if (attrs.widget === "Table") {
          var template = "<table class='striped'><thead>" +
            "<tr><th ng-repeat='i in data.cols track by $index'>{{i}}<tr>" +
            "</thead><tbody>" +
            "<tr ng-class='data.styles[$index] ? data.styles[$index] : \"\"' ng-repeat='row in data.rows track by $index'>" +
            "<td ng-repeat='i in row track by $index'>{{i}}" +
            "<tr>" +
            "</tbody></table>";
          var el = element.empty().append($compile(template)(scope)).children()[0]
        } else if (attrs.widget === "TextArea") {
          var template = "<div style='padding:0 0 5px' ng-repeat='str in data track by $index'>{{str}}</div><div style='height:10px'></div>";
          var el = element.empty().append($compile(template)(scope)).children()[0]
        }
        else if (attrs.widget == "EmbedChart") {

          /* NOTE(chenxu): tag <\/script> in javascript string will be parsed incorrectly.
             so we convert <\/script> to <\\/script> in python and convert it back here. */
          data = data.replace(/\\\/script>/ig, "\/script>");
          var template = "<iframe scrolling='no' id='embedchart' frameborder='0' onload='changeFrameHeight()' style='width:100%;'></iframe>"
          var el = element.empty().append($compile(template)(scope)).children()[0];
          var iframe = el.contentWindow || ( el.contentDocument.document || el.contentDocument);
          iframe.document.open();
          iframe.document.write(data);
          iframe.document.close();
        }
        else {
          var el_chart = element.addClass("chart").css({display:"block"});
          var el = el_chart.html("<svg></svg>").children()[0];

          var do_after = null;

          if (attrs.widget in {StackedArea:0, Lines:0}) {

            /* Hide widget if not enough data */
            if ((! data.length) || (data[0].length < 1) || (data[0][1].length < 2)) {
              return element.empty().css({display:"none"})
            }

            /* NOTE(amaretskiy): Dirty fix for changing chart width in case
               if there are too long Y values that overlaps chart box. */
            var do_after = function(node, chart){
              var g_box = angular.element(el_chart[0].querySelector(".nv-y.nv-axis"));

              if (g_box && g_box[0] && g_box[0].getBBox) {

                try {
                  // 30 is padding aroung graphs
                  var width = g_box[0].getBBox().width + 30;
                } catch (err) {
                  // This happens sometimes, just skip silently
                  return
                }

                // 890 is chart width (set by CSS)
                if (typeof width === "number" && width > 890) {
                  width = (890 * 2) - width;
                  if (width > 0) {
                    angular.element(node).css({width:width+"px"});
                    chart.update()
                  }
                }
              }
            }
          }
          else if (attrs.widget === "Pie") {
            if (! data.length) {
              return element.empty().css({display:"none"})
            }
          }

          var opts = {
            xname: attrs.nameX || "",
            xrotate: attrs.rotateX || 0,
            yformat: attrs.formatY || ",.3f",
            controls: attrs.controls === "true",
            guide: attrs.guide === "true",
            showmaxmin: attrs.showmaxmin === "true"
          };
          if (attrs.formatDateX) {
            opts.xformat = function(d) { return d3.time.format(attrs.formatDateX)(new Date(d)) }
          } else {
            opts.xformat = d3.format(attrs.formatX || "d")
          }
          Chart.get_chart(attrs.widget)(el, data, opts, do_after);
        }

        if (attrs.nameY) {
          /* NOTE(amaretskiy): Dirty fix for displaying Y-axis label correctly.
             I believe sometimes NVD3 will allow doing this in normal way */
          var label_y = angular.element("<div>").addClass("chart-label-y").text(attrs.nameY);
          angular.element(el).parent().prepend(label_y)
        }

        if (attrs.description) {
          var desc_el = angular.element("<div>").addClass(attrs.descriptionClass || "h3").text(attrs.description);
          angular.element(el).parent().prepend(desc_el)
        }

        if (attrs.title) {
          var title_el = angular.element("<div>").addClass(attrs.titleClass || "h2").text(attrs.title);
          angular.element(el).parent().prepend(title_el)
        }

        angular.element(el).parent().append(angular.element("<div style='clear:both'>"))
      });
    }
  }
};

    var controllerFunction = function($scope, $location) {
        $scope.source = "{\n  \"version\": 2, \n  \"title\": \"\", \n  \"description\": \"\", \n  \"subtasks\": [\n    {\n      \"title\": \"Keystone Stress test\", \n      \"description\": \"Include just one scenario:\\n1. Keystone.create_tenant_with_users\\n\", \n      \"workloads\": [\n        {\n          \"scenario\": {\n            \"MyKeystone.create_tenant_with_users\": {\n              \"users_per_tenant\": 2, \n              \"tenant_create_kwargs\": {}\n            }\n          }, \n          \"description\": \"Create a keystone tenant and several users belonging to it.\", \n          \"contexts\": {}, \n          \"runner\": {\n            \"constant\": {\n              \"concurrency\": 30, \n              \"times\": 30\n            }\n          }, \n          \"hooks\": [], \n          \"sla\": {\n            \"failure_rate\": {\n              \"max\": 0\n            }\n          }\n        }\n      ]\n    }\n  ]\n}";
        $scope.scenarios = [{"runner": "constant", "hooks": [], "pos": "0", "atomic": {"pie": [["keystone_v3.create_project", 3.0065311670303343], ["keystone_v3.create_users", 8.380455621083577], ["keystone_v3.delete_project", 1.6337514321009319], ["keystone_v3.delete_user (x2)", 0.0]], "iter": [["keystone_v3.create_project", [[1, 2.2113780975341797], [2, 2.21000599861145], [3, 2.330120086669922], [4, 2.6334121227264404], [5, 2.274358034133911], [6, 2.500403881072998], [7, 2.388368844985962], [8, 2.468366861343384], [9, 2.571887969970703], [10, 2.6796231269836426], [11, 2.6970629692077637], [12, 2.7890169620513916], [13, 2.7749760150909424], [14, 2.8870809078216553], [15, 3.0319578647613525], [16, 2.895848035812378], [17, 3.0011789798736572], [18, 3.279954195022583], [19, 3.1331570148468018], [20, 3.1362478733062744], [21, 3.481701135635376], [22, 3.2214138507843018], [23, 3.3474369049072266], [24, 3.546994924545288], [25, 3.681241989135742], [26, 3.6265439987182617], [27, 3.5327260494232178], [28, 3.7595322132110596], [29, 3.9046740531921387], [30, 4.199264049530029]]], ["keystone_v3.create_users", [[1, 8.243757009506226], [2, 8.34080195426941], [3, 8.201565980911255], [4, 8.456898927688599], [5, 8.373337030410767], [6, 8.415534973144531], [7, 8.391545057296753], [8, 8.16620397567749], [9, 8.170379877090454], [10, 8.324055910110474], [11, 8.460821866989136], [12, 8.472800970077515], [13, 8.08069896697998], [14, 8.21428108215332], [15, 8.22156810760498], [16, 8.60503101348877], [17, 8.402001857757568], [18, 8.638685941696167], [19, 8.373394966125488], [20, 8.505361080169678], [21, 8.26113510131836], [22, 8.37944483757019], [23, 8.510555982589722], [24, 8.468441009521484], [25, 8.323575973510742], [26, 8.495818138122559], [27, 8.57745099067688], [28, 8.484786987304688], [29, 8.504270076751709], [30, 8.349462985992432]]], ["keystone_v3.delete_project", [[1, 0.498790979385376], [2, 0.5447878837585449], [3, 0.5579931735992432], [4, 1.3090879917144775], [5, 0.7295291423797607], [6, 1.0596702098846436], [7, 0.8741919994354248], [8, 0.7192480564117432], [9, 0.8800740242004395], [10, 1.1872978210449219], [11, 1.4093239307403564], [12, 1.560474157333374], [13, 1.0454859733581543], [14, 1.413517951965332], [15, 1.561885118484497], [16, 1.7011539936065674], [17, 1.704395055770874], [18, 2.1940579414367676], [19, 1.8815350532531738], [20, 2.025434970855713], [21, 2.0376601219177246], [22, 1.8532671928405762], [23, 2.180605888366699], [24, 2.349637031555176], [25, 2.379059076309204], [26, 2.4975931644439697], [27, 2.5356059074401855], [28, 2.6340880393981934], [29, 2.7896029949188232], [30, 2.8974881172180176]]], ["keystone_v3.delete_user (x2)", [[1, 0], [2, 0], [3, 0], [4, 0], [5, 0], [6, 0], [7, 0], [8, 0], [9, 0], [10, 0], [11, 0], [12, 0], [13, 0], [14, 0], [15, 0], [16, 0], [17, 0], [18, 0], [19, 0], [20, 0], [21, 0], [22, 0], [23, 0], [24, 0], [25, 0], [26, 0], [27, 0], [28, 0], [29, 0], [30, 0]]]], "histogram": {"data": [[{"disabled": 0, "values": [{"y": 7, "x": 2.5415}, {"y": 6, "x": 2.8729999999999998}, {"y": 6, "x": 3.2045}, {"y": 5, "x": 3.5359999999999996}, {"y": 4, "x": 3.8674999999999997}, {"y": 1, "x": 4.199}], "key": "keystone_v3.create_project", "view": "Square Root Choice"}, {"disabled": 1, "values": [{"y": 3, "x": 8.174}, {"y": 5, "x": 8.267}, {"y": 4, "x": 8.36}, {"y": 6, "x": 8.453}, {"y": 9, "x": 8.546}, {"y": 3, "x": 8.639}], "key": "keystone_v3.create_users", "view": "Square Root Choice"}, {"disabled": 2, "values": [{"y": 7, "x": 0.8986666666666666}, {"y": 3, "x": 1.2983333333333333}, {"y": 5, "x": 1.698}, {"y": 6, "x": 2.0976666666666666}, {"y": 4, "x": 2.497333333333333}, {"y": 4, "x": 2.897}], "key": "keystone_v3.delete_project", "view": "Square Root Choice"}, {"disabled": 3, "values": [{"y": 30, "x": 4.062333333333333}, {"y": 0, "x": 4.360666666666667}, {"y": 0, "x": 4.659}, {"y": 0, "x": 4.957333333333334}, {"y": 0, "x": 5.2556666666666665}, {"y": 0, "x": 5.554}], "key": "keystone_v3.delete_user (x2)", "view": "Square Root Choice"}], [{"disabled": 0, "values": [{"y": 7, "x": 2.5415}, {"y": 6, "x": 2.8729999999999998}, {"y": 6, "x": 3.2045}, {"y": 5, "x": 3.5359999999999996}, {"y": 4, "x": 3.8674999999999997}, {"y": 1, "x": 4.199}], "key": "keystone_v3.create_project", "view": "Sturges Formula"}, {"disabled": 1, "values": [{"y": 3, "x": 8.174}, {"y": 5, "x": 8.267}, {"y": 4, "x": 8.36}, {"y": 6, "x": 8.453}, {"y": 9, "x": 8.546}, {"y": 3, "x": 8.639}], "key": "keystone_v3.create_users", "view": "Sturges Formula"}, {"disabled": 2, "values": [{"y": 7, "x": 0.8986666666666666}, {"y": 3, "x": 1.2983333333333333}, {"y": 5, "x": 1.698}, {"y": 6, "x": 2.0976666666666666}, {"y": 4, "x": 2.497333333333333}, {"y": 4, "x": 2.897}], "key": "keystone_v3.delete_project", "view": "Sturges Formula"}, {"disabled": 3, "values": [{"y": 30, "x": 4.062333333333333}, {"y": 0, "x": 4.360666666666667}, {"y": 0, "x": 4.659}, {"y": 0, "x": 4.957333333333334}, {"y": 0, "x": 5.2556666666666665}, {"y": 0, "x": 5.554}], "key": "keystone_v3.delete_user (x2)", "view": "Sturges Formula"}], [{"disabled": 0, "values": [{"y": 6, "x": 2.494142857142857}, {"y": 6, "x": 2.7782857142857145}, {"y": 5, "x": 3.0624285714285713}, {"y": 4, "x": 3.3465714285714285}, {"y": 5, "x": 3.630714285714286}, {"y": 3, "x": 3.9148571428571426}, {"y": 0, "x": 4.199}], "key": "keystone_v3.create_project", "view": "Rice Rule"}, {"disabled": 1, "values": [{"y": 1, "x": 8.160714285714285}, {"y": 5, "x": 8.240428571428572}, {"y": 2, "x": 8.320142857142857}, {"y": 8, "x": 8.399857142857142}, {"y": 6, "x": 8.479571428571427}, {"y": 5, "x": 8.559285714285714}, {"y": 3, "x": 8.639}], "key": "keystone_v3.create_users", "view": "Rice Rule"}, {"disabled": 2, "values": [{"y": 5, "x": 0.8415714285714285}, {"y": 4, "x": 1.1841428571428572}, {"y": 4, "x": 1.5267142857142857}, {"y": 5, "x": 1.8692857142857142}, {"y": 5, "x": 2.2118571428571427}, {"y": 4, "x": 2.5544285714285713}, {"y": 2, "x": 2.897}], "key": "keystone_v3.delete_project", "view": "Rice Rule"}, {"disabled": 3, "values": [{"y": 30, "x": 4.019714285714286}, {"y": 0, "x": 4.275428571428572}, {"y": 0, "x": 4.531142857142857}, {"y": 0, "x": 4.7868571428571425}, {"y": 0, "x": 5.042571428571429}, {"y": 0, "x": 5.298285714285715}, {"y": 0, "x": 5.554}], "key": "keystone_v3.delete_user (x2)", "view": "Rice Rule"}]], "views": [{"id": 0, "name": "Square Root Choice"}, {"id": 1, "name": "Sturges Formula"}, {"id": 2, "name": "Rice Rule"}]}}, "iterations": {"pie": [["success", 30], ["errors", 0]], "iter": [["duration", [[1, 18.926992177963257], [2, 18.77045202255249], [3, 18.89152216911316], [4, 19.773704051971436], [5, 19.043776035308838], [6, 19.408771991729736], [7, 19.37925386428833], [8, 19.2375910282135], [9, 19.17642593383789], [10, 19.5294029712677], [11, 19.891823053359985], [12, 20.043603897094727], [13, 19.517888069152832], [14, 19.847069025039673], [15, 20.017849922180176], [16, 20.377471923828125], [17, 20.18323588371277], [18, 20.69246506690979], [19, 20.53389000892639], [20, 20.692053079605103], [21, 20.498968839645386], [22, 20.302504062652588], [23, 20.837501049041748], [24, 20.821858167648315], [25, 21.016592979431152], [26, 20.96345591545105], [27, 21.145408153533936], [28, 21.136462926864624], [29, 21.312477827072144], [30, 21.254405975341797]]], ["idle_duration", [[1, 0.0], [2, 0.0], [3, 0.0], [4, 0.0], [5, 0.0], [6, 0.0], [7, 0.0], [8, 0.0], [9, 0.0], [10, 0.0], [11, 0.0], [12, 0.0], [13, 0.0], [14, 0.0], [15, 0.0], [16, 0.0], [17, 0.0], [18, 0.0], [19, 0.0], [20, 0.0], [21, 0.0], [22, 0.0], [23, 0.0], [24, 0.0], [25, 0.0], [26, 0.0], [27, 0.0], [28, 0.0], [29, 0.0], [30, 0.0]]]], "histogram": {"data": [[{"disabled": null, "values": [{"y": 5, "x": 19.19412298997243}, {"y": 5, "x": 19.617793957392376}, {"y": 4, "x": 20.041464924812317}, {"y": 4, "x": 20.465135892232258}, {"y": 6, "x": 20.888806859652203}, {"y": 6, "x": 21.312477827072144}], "key": "task", "view": "Square Root Choice"}], [{"disabled": null, "values": [{"y": 5, "x": 19.19412298997243}, {"y": 5, "x": 19.617793957392376}, {"y": 4, "x": 20.041464924812317}, {"y": 4, "x": 20.465135892232258}, {"y": 6, "x": 20.888806859652203}, {"y": 6, "x": 21.312477827072144}], "key": "task", "view": "Sturges Formula"}], [{"disabled": null, "values": [{"y": 4, "x": 19.133598566055298}, {"y": 4, "x": 19.496745109558105}, {"y": 4, "x": 19.859891653060913}, {"y": 4, "x": 20.22303819656372}, {"y": 4, "x": 20.58618474006653}, {"y": 4, "x": 20.949331283569336}, {"y": 6, "x": 21.312477827072144}], "key": "task", "view": "Rice Rule"}]], "views": [{"id": 0, "name": "Square Root Choice"}, {"id": 1, "name": "Sturges Formula"}, {"id": 2, "name": "Rice Rule"}]}}, "table": {"styles": {"2": "oblique", "3": "oblique", "4": "oblique", "7": "rich", "8": "oblique", "9": "oblique"}, "rows": [["keystone_v3.create_project", 2.21, 2.949, 3.689, 3.839, 4.199, 3.007, "100.0%", 30], ["keystone_v3.create_users", 8.081, 8.385, 8.517, 8.593, 8.639, 8.38, "100.0%", 30], [" -> keystone_v3.create_user (x2)", 8.081, 8.385, 8.517, 8.593, 8.639, 8.38, "100.0%", 30], [" --> keystone_v3.list_roles (x2)", 0.927, 1.064, 1.224, 1.39, 2.423, 1.123, "100.0%", 30], [" --> keystone_v3.add_role (x2)", 0.981, 2.448, 3.451, 3.579, 3.714, 2.362, "100.0%", 30], ["keystone_v3.delete_project", 0.499, 1.632, 2.545, 2.72, 2.897, 1.634, "100.0%", 30], ["keystone_v3.delete_user (x2)", 3.764, 5.359, 5.525, 5.533, 5.554, 5.29, "100.0%", 30], ["total", 18.77, 20.113, 21.137, 21.205, 21.312, 20.107, "100.0%", 30], [" -> duration", 18.77, 20.113, 21.137, 21.205, 21.312, 20.107, "100.0%", 30], [" -> idle_duration", 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, "100.0%", 30]], "cols": ["Action", "Min (sec)", "Median (sec)", "90%ile (sec)", "95%ile (sec)", "Max (sec)", "Avg (sec)", "Success", "Count"]}, "errors": [], "iterations_count": 30, "load_duration": 21.551141023635864, "complete_output": [[], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], []], "config": "{\n  \"version\": 2, \n  \"title\": \"A cropped version of a bigger task.\", \n  \"description\": \"Auto-generated task from a single workload (uuid=fe0b8641-7800-432c-845c-1e9b761d2d89)\", \n  \"subtasks\": [\n    {\n      \"title\": \"MyKeystone.create_tenant_with_users\", \n      \"description\": \"Create a keystone tenant and several users belonging to it.\", \n      \"scenario\": {\n        \"MyKeystone.create_tenant_with_users\": {\n          \"users_per_tenant\": 2, \n          \"tenant_create_kwargs\": {}\n        }\n      }, \n      \"contexts\": {}, \n      \"runner\": {\n        \"constant\": {\n          \"concurrency\": 30, \n          \"times\": 30\n        }\n      }, \n      \"hooks\": [], \n      \"sla\": {\n        \"failure_rate\": {\n          \"max\": 0\n        }\n      }\n    }\n  ]\n}", "sla_success": true, "output_errors": [], "cls": "MyKeystone", "description": "Create a keystone tenant and several users belonging to it.", "met": "create_tenant_with_users", "has_output": false, "full_duration": 30.724693059921265, "load_profile": [["parallel iterations", [[0.0, 0], [0.2198216384410858, 12.12345749668019], [0.4396432768821716, 29.62673196946042], [0.6594649153232574, 30], [0.8792865537643432, 30], [1.0991081922054289, 30], [1.3189298306465147, 30], [1.5387514690876005, 30], [1.7585731075286863, 30], [1.9783947459697722, 30], [2.1982163844108578, 30], [2.4180380228519436, 30], [2.6378596612930294, 30], [2.857681299734115, 30], [3.077502938175201, 30], [3.297324576616287, 30], [3.5171462150573727, 30], [3.7369678534984585, 30], [3.9567894919395443, 30], [4.17661113038063, 30], [4.3964327688217155, 30], [4.616254407262802, 30], [4.836076045703887, 30], [5.055897684144973, 30], [5.275719322586059, 30], [5.495540961027145, 30], [5.71536259946823, 30], [5.935184237909317, 30], [6.155005876350402, 30], [6.374827514791488, 30], [6.594649153232574, 30], [6.81447079167366, 30], [7.034292430114745, 30], [7.254114068555831, 30], [7.473935706996917, 30], [7.693757345438002, 30], [7.913578983879089, 30], [8.133400622320174, 30], [8.35322226076126, 30], [8.573043899202347, 30], [8.792865537643431, 30], [9.012687176084517, 30], [9.232508814525604, 30], [9.45233045296669, 30], [9.672152091407774, 30], [9.89197372984886, 30], [10.111795368289947, 30], [10.331617006731033, 30], [10.551438645172118, 30], [10.771260283613204, 30], [10.99108192205429, 30], [11.210903560495375, 30], [11.43072519893646, 30], [11.650546837377547, 30], [11.870368475818633, 30], [12.090190114259718, 30], [12.310011752700804, 30], [12.52983339114189, 30], [12.749655029582977, 30], [12.969476668024061, 30], [13.189298306465147, 30], [13.409119944906234, 30], [13.62894158334732, 30], [13.848763221788404, 30], [14.06858486022949, 30], [14.288406498670577, 30], [14.508228137111661, 30], [14.728049775552748, 30], [14.947871413993834, 30], [15.16769305243492, 30], [15.387514690876005, 30], [15.607336329317091, 30], [15.827157967758177, 30], [16.046979606199262, 30], [16.266801244640348, 30], [16.486622883081434, 30], [16.70644452152252, 30], [16.926266159963607, 30], [17.146087798404693, 30], [17.36590943684578, 30], [17.585731075286862, 30], [17.80555271372795, 30], [18.025374352169035, 30], [18.24519599061012, 30], [18.465017629051207, 30], [18.684839267492293, 30], [18.90466090593338, 29.451078603566927], [19.124482544374462, 27.01764172990107], [19.34430418281555, 25.40271957414857], [19.564125821256635, 22.973242264084618], [19.78394745969772, 20.610897364081495], [20.003769098138807, 18.95662743402682], [20.223590736579894, 16.39946987439467], [20.44341237502098, 14.498155193323802], [20.663234013462066, 12.54782328998781], [20.88305565190315, 9.971299466063703], [21.102877290344235, 7.312122449241796], [21.32269892878532, 4.903362086388842], [21.542520567226408, 2.3222010771399892], [21.762342205667494, 0.03921568627451971], [21.98216384410858, 0]]]], "name": "create_tenant_with_users", "created_at": "2019-06-12T18:29:29", "additive_output": [], "sla": [{"criterion": "failure_rate", "detail": "Failure rate criteria 0.00% <= 0.00% <= 0.00% - Passed", "success": true}]}];

      $scope.location = {
        /* #/path/hash/sub/div */
        normalize: function(str) {
          /* Remove unwanted characters from string */
          if (typeof str !== "string") { return "" }
          return str.replace(/[^\w\-\.]/g, "")
        },
        uri: function(obj) {
          /* Getter/Setter */
          if (! obj) {
            var uri = {path: "", hash: "", sub: "", div: ""};
            var arr = ["div", "sub", "hash", "path"];
            angular.forEach($location.url().split("/"), function(value){
              var v = $scope.location.normalize(value);
              if (v) { var k = arr.pop(); if (k) { this[k] = v }}
            }, uri);
            return uri
          }
          var arr = [obj.path, obj.hash, obj.sub, obj.div], res = [];
          for (var i in arr) { if (! arr[i]) { break }; res.push(arr[i]) }
          return $location.url("/" + res.join("/"))
        },
        path: function(path, hash) {
          /* Getter/Setter */
          if (path === "") { return this.uri({}) }
          path = this.normalize(path);
          var uri = this.uri();
          if (! path) { return uri.path }
          uri.path = path;
          var _hash = this.normalize(hash);
          if (_hash || hash === "") { uri.hash = _hash }
          return this.uri(uri)
        },
        hash: function(hash) {
          /* Getter/Setter */
          if (hash) { this.uri({path:this.uri().path, hash:hash}) }
          return this.uri().hash
        }
      }

      /* Dispatch */

      $scope.route = function(uri) {
        if (! $scope.scenarios_map) { return }

        // Expand menu if there is only one menu group
        if ($scope.nav.length === 1) {
          $scope.nav_idx = $scope.nav[0].idx;
        }

        if (uri.path in $scope.scenarios_map) {
          $scope.view = {is_scenario:true};
          $scope.scenario = $scope.scenarios_map[uri.path];
          $scope.nav_idx = $scope.nav_map[uri.path];
          if ($scope.scenario.iterations.histogram.views.length) {
            $scope.mainHistogram = $scope.scenario.iterations.histogram.views[0]
          }
          if ($scope.scenario.atomic.histogram.views.length) {
            $scope.atomicHistogram = $scope.scenario.atomic.histogram.views[0]
          }
          $scope.outputIteration = 0;
          $scope.showTab(uri);
        } else {
          $scope.scenario = null;
          if (uri.path === "source") {
            $scope.view = {is_source:true}
          } else {
            $scope.view = {is_main:true}
          }
        }
      }

      $scope.$on("$locationChangeSuccess", function (event, newUrl, oldUrl) {
        $scope.route($scope.location.uri())
      });

      $scope.showNav = function(nav_idx) { $scope.nav_idx = nav_idx }

      /* Tabs */

      $scope.tabs = [
        {
          id: "overview",
          name: "Overview",
          visible: function(){ return !! $scope.scenario.iterations.pie.length }
        },{
          id: "details",
          name: "Details",
          visible: function(){ return !! $scope.scenario.atomic.pie.length }
        },{
          id: "output",
          name: "Scenario Data",
          visible: function(){ return $scope.scenario.has_output }
        },{
          id: "hooks",
          name: "Hooks",
          visible: function(){ return $scope.scenario.hooks.length }
        },{
          id: "failures",
          name: "Failures",
          visible: function(){ return !! $scope.scenario.errors.length }
        },{
          id: "task",
          name: "Input task",
          visible: function(){ return !! $scope.scenario.config }
        }
      ];
      $scope.tabs_map = {};
      angular.forEach($scope.tabs,
                      function(tab){ this[tab.id] = tab }, $scope.tabs_map);

      $scope.showTab = function(uri) {
        $scope.tab = uri.hash in $scope.tabs_map ? uri.hash : "overview";
        if (uri.hash === "output") {
          if (typeof $scope.scenario.output === "undefined") {
            var has_additive = !! $scope.scenario.additive_output.length;
            var has_complete = !! ($scope.scenario.complete_output.length
                                   && $scope.scenario.complete_output[0].length);
            $scope.scenario.output = {
              has_additive: has_additive,
              has_complete: has_complete,
              length: has_additive + has_complete,
              active: has_additive ? "additive" : (has_complete ? "complete" : "")
            }
          }
          if (uri.sub && $scope.scenario.output["has_" + uri.sub]) {
            $scope.scenario.output.active = uri.sub
          }
        }
        else if (uri.hash === "hooks") {
          if ($scope.scenario.hooks.length) {
            var hook_idx = parseInt(uri.sub);

            if (isNaN(hook_idx) || ($scope.scenario.hooks.length - hook_idx) <= 0) {
              hook_idx = 0
            }

            if ($scope.scenario.hook_idx === hook_idx) {
              return
            }

            $scope.scenario.hooks.cur = $scope.scenario.hooks[hook_idx];
            $scope.scenario.hook_idx = hook_idx;
            if (typeof $scope.scenario.hooks.cur.active === "undefined") {
              if ($scope.scenario.hooks.cur.additive.length) {
                $scope.scenario.hooks.cur.active = "additive"
              }
              if ($scope.scenario.hooks.cur.complete.length) {
                if (typeof $scope.scenario.hooks.cur.active === "undefined") {
                  $scope.scenario.hooks.cur.active = "complete"
                }
                $scope.set_hook_run()
              }
            }
          }
        }
      }

      for (var i in $scope.tabs) {
        if ($scope.tabs[i].id === $scope.location.hash()) {
          $scope.tab = $scope.tabs[i].id
        }
        $scope.tabs[i].isVisible = function() {
          if ($scope.scenario) {
            if (this.visible()) { return true }
            /* If tab should be hidden but is selected - show another one */
            if (this.id === $scope.location.hash()) {
              for (var i in $scope.tabs) {
                var tab = $scope.tabs[i];
                if (tab.id != this.id && tab.visible()) {
                  $scope.tab = tab.id;
                  return false
                }
              }
            }
          }
          return false
        }
      }

      $scope.set_hook_run = function(idx) {
        if (typeof idx !== "undefined") {
          $scope.scenario.hooks.cur.run_idx = idx
        }
        else if (typeof $scope.scenario.hooks.cur.run_idx === "undefined") {
          $scope.scenario.hooks.cur.run_idx = 0
        }
        idx = $scope.scenario.hooks.cur.run_idx;
        if (($scope.scenario.hooks.cur.complete.length - idx) > 0) {
          $scope.scenario.hooks.cur.run = $scope.scenario.hooks.cur.complete[idx]
        }
      }

      $scope.complete_hooks_as_dropdown = function() {
        return $scope.scenario.hooks.cur.complete.length > 10
      }

      /* Other helpers */

      $scope.showError = function(message) {
          return (function (e) {
            e.style.display = "block";
            e.textContent = message
          })(document.getElementById("page-error"))
      }

      $scope.compact_atomics = function() {
        return ($scope.scenario && $scope.scenario.atomic.iter.length < 9)
      }

      /* Initialization */

      angular.element(document).ready(function(){
        if (! $scope.scenarios.length) {
          return $scope.showError("No data...")
        }

        /* Compose data mapping */

        $scope.nav = [];
        $scope.nav_map = {};
        $scope.scenarios_map = {};
        var met = [], itr = 0, cls_idx = 0;
        var prev_cls, prev_met;

        for (var idx in $scope.scenarios) {
          var sc = $scope.scenarios[idx];
          if (! prev_cls) {
            prev_cls = sc.cls
          }
          else if (prev_cls !== sc.cls) {
            $scope.nav.push({cls:prev_cls, met:met, idx:cls_idx});
            prev_cls = sc.cls;
            met = [];
            itr = 1;
            cls_idx += 1
          }

          if (prev_met !== sc.met) { itr = 1 };
          sc.ref = $scope.location.normalize(sc.cls+"."+sc.met+(itr > 1 ? "-"+itr : ""));
          $scope.scenarios_map[sc.ref] = sc;
          $scope.nav_map[sc.ref] = cls_idx;
          met.push({name:sc.name, itr:itr, idx:idx, ref:sc.ref});
          prev_met = sc.met;
          itr += 1;
        }

        if (met.length) {
          $scope.nav.push({cls:prev_cls, met:met, idx:cls_idx})
        }

        /* Start */

        var uri = $scope.location.uri();
        uri.path = $scope.location.path();
        $scope.route(uri);
        $scope.$digest()
      })
    };

    if (typeof angular === "object") {
      angular.module("App", [])
        .controller("Controller", ["$scope", "$location", controllerFunction])
        .directive("widget", widgetDirective)
    }


</script>
  <style>
    body { margin:0; padding:0 0 50px; font-size:14px; font-family:Helvetica,Arial,sans-serif }
    a, a:active, a:focus, a:visited { text-decoration:none; outline:none }
    p { margin:0; padding:5px 0 }
    p.thesis { padding:10px 0 }
    h1 { color:#666; margin:0 0 20px; font-size:30px; font-weight:normal }
    h2, .h2 { color:#666; margin:24px 0 6px; font-size:25px; font-weight:normal }
    h3, .h3 { color:#777; margin:12px 0 4px; font-size:18px; font-weight:normal }
    table { border-collapse:collapse; border-spacing:0; width:100%; font-size:12px; margin:0 0 10px }
    table th { text-align:left; padding:8px; color:#000; border:2px solid #ddd; border-width:0 0 2px 0 }
    table th.sortable { cursor:pointer }
    table td { text-align:left; border-top:1px solid #ddd; padding:8px; color:#333 }
    table.compact td { padding:4px 8px }
    table.striped tr:nth-child(odd) td { background:#f9f9f9 }
    table.linked tbody tr:hover { background:#f9f9f9; cursor:pointer }
    .pointer { cursor:pointer }
    .rich, .rich td { font-weight:bold }
    .oblique { font-style:italic }
    .code { padding:10px; font-size:13px; color:#333; background:#f6f6f6; border:1px solid #e5e5e5; border-radius:4px }

    .header { text-align:left; background:#333; font-size:18px; padding:13px 0; margin-bottom:20px; color:#fff; background-image:linear-gradient(to bottom, #444 0px, #222 100%) }
    .header a, .header a:visited, .header a:focus { color:#999 }

    .notify-error { padding:5px 10px; background:#fee; color:red }
    .status-skip, .status-skip td { color:grey }
    .status-pass, .status-pass td { color:green }
    .status-fail, .status-fail td { color:red }
    .capitalize { text-transform:capitalize }
    
    .aside { margin:0 20px 0 0; display:block; width:255px; float:left }
    .aside > div { margin-bottom: 15px }
    .aside > div div:first-child { border-top-left-radius:4px; border-top-right-radius:4px }
    .aside > div div:last-child { border-bottom-left-radius:4px; border-bottom-right-radius:4px }
    .navcls { color:#678; background:#eee; border:1px solid #ddd; margin-bottom:-1px; display:block; padding:8px 9px; font-weight:bold; text-align:left; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; cursor:pointer }
    .navcls.expanded { color:#469 }
    .navcls.active { background:#428bca; background-image:linear-gradient(to bottom, #428bca 0px, #3278b3 100%); border-color:#3278b3; color:#fff }
    .navmet { color:#555; background:#fff; border:1px solid #ddd; font-size:12px; display:block; margin-bottom:-1px; padding:8px 10px; text-align:left; text-overflow:ellipsis; white-space:nowrap; overflow:hidden; cursor:pointer }
    .navmet:hover { background:#f8f8f8 }
    .navmet.active, .navmet.active:hover { background:#428bca; background-image:linear-gradient(to bottom, #428bca 0px, #3278b3 100%); border-color:#3278b3; color:#fff }

    .buttn { color:#555; background:#fff; border:1px solid #ddd; border-radius:5px; font-size:12px; margin-bottom:-1px; padding:5px 7px; text-align:left; text-overflow:ellipsis; white-space:nowrap; overflow:hidden; cursor:pointer }
    .buttn:hover { background:#f8f8f8 }
    .buttn.active, .bttn.active:hover { background:#428bca; background-image:linear-gradient(to bottom, #428bca 0px, #3278b3 100%); border-color:#3278b3; color:#fff; cursor:default }

    .tabs { list-style:outside none none; margin:0 0 5px; padding:0; border-bottom:1px solid #ddd }
    .tabs:after { clear:both }
    .tabs li { float:left; margin-bottom:-1px; display:block; position:relative }
    .tabs li div { border:1px solid transparent; border-radius:4px 4px 0 0; line-height:20px; margin-right:2px; padding:10px 15px; color:#428bca }
    .tabs li div:hover { border-color:#eee #eee #ddd; background:#eee; cursor:pointer; }
    .tabs li.active div { background:#fff; border-color:#ddd #ddd transparent; border-style:solid; border-width:1px; color:#555; cursor:default }
    .failure-mesg { color:#900 }
    .failure-trace { color:#333; white-space:pre; overflow:auto }

    .link { color:#428BCA; padding:5px 15px 5px 5px; text-decoration:underline; cursor:pointer }
    .link.active { color:#333; text-decoration:none; cursor:default }

    .chart { padding:0; margin:0; width:890px }
    .chart svg { height:300px; padding:0; margin:0; overflow:visible; float:right }
    .chart.lower svg { height:180px }
    .chart-label-y { font-size:12px; position:relative; top:5px; padding:0; margin:0 }

    .expandable { cursor:pointer }
    .clearfix { clear:both }
    .sortable > .arrow { display:inline-block; width:12px; height:inherit; color:#c90 }
    .content-main { margin:0 5px; display:block; float:left }

    .content-wrap {  margin:0 auto; padding:0 5px;  }
    
    @media only screen and (min-width: 320px)  { .content-wrap { width:900px  } .content-main { width:600px } }
    @media only screen and (min-width: 900px)  { .content-wrap { width:880px  } .content-main { width:590px } }
    @media only screen and (min-width: 1000px) { .content-wrap { width:980px  } .content-main { width:690px } }
    @media only screen and (min-width: 1100px) { .content-wrap { width:1080px } .content-main { width:790px } }
    @media only screen and (min-width: 1200px) { .content-wrap { width:1180px } .content-main { width:890px } }

  </style>
</head>
<body ng-controller="Controller">

  <div class="header" id="page-header">
    <div class="content-wrap">
      <a href="https://github.com/openstack/rally">Rally</a> 
      <span>task results</span>
    </div>
  </div>

  <div class="content-wrap" id="page-content">
    

    <p id="page-error" class="notify-error" style="display:none"></p>

    <div id="content-nav" class="aside" ng-show="scenarios.length" ng-cloack>
      <div>
        <div class="navcls"
             ng-class="{active:view.is_main}"
             ng-click="location.path('')">Task overview</div>
        <div class="navcls"
             ng-class="{active:view.is_source}"
             ng-click="location.path('source', '')">Input file</div>
      </div>
      <div>
        <div class="navcls" title="{{n.cls}}"
             ng-repeat-start="n in nav track by $index"
             ng-click="showNav(n.idx)"
             ng-class="{expanded:n.idx==nav_idx}">
                <span ng-hide="n.idx==nav_idx">►</span>
                <span ng-show="n.idx==nav_idx">▼</span>
                {{n.cls}}</div>
        <div class="navmet" title="{{m.name}}"
             ng-show="n.idx==nav_idx"
             ng-class="{active:m.ref==scenario.ref}"
             ng-click="location.path(m.ref)"
             ng-repeat="m in n.met track by $index"
             ng-repeat-end>{{m.name}}</div>
      </div>
    </div>

    <div id="content-main" class="content-main" ng-show="scenarios.length" ng-cloak>

      <div ng-show="view.is_main">
        <h1>Task overview</h1>
        <table class="linked compact"
               ng-init="ov_srt='ref'; ov_dir=false">
          <thead>
            <tr>
              <th class="sortable"
                  title="Scenario name, with optional suffix of call number"
                  ng-click="ov_srt='ref'; ov_dir=!ov_dir">
                Scenario
                <span class="arrow">
                  <b ng-show="ov_srt=='ref' && !ov_dir">&#x25b4;</b>
                  <b ng-show="ov_srt=='ref' && ov_dir">&#x25be;</b>
                </span>
              <th class="sortable"
                  title="How long the scenario run, without context duration"
                  ng-click="ov_srt='load_duration'; ov_dir=!ov_dir">
                Load duration (s)
                <span class="arrow">
                  <b ng-show="ov_srt=='load_duration' && !ov_dir">&#x25b4;</b>
                  <b ng-show="ov_srt=='load_duration' && ov_dir">&#x25be;</b>
                </span>
              <th class="sortable"
                  title="Scenario duration plus context duration"
                  ng-click="ov_srt='full_duration'; ov_dir=!ov_dir">
                Full duration (s)
                <span class="arrow">
                  <b ng-show="ov_srt=='full_duration' && !ov_dir">&#x25b4;</b>
                  <b ng-show="ov_srt=='full_duration' && ov_dir">&#x25be;</b>
                </span>
              <th class="sortable" title="Number of iterations"
                  ng-click="ov_srt='iterations_count'; ov_dir=!ov_dir">
                Iterations
                <span class="arrow">
                  <b ng-show="ov_srt=='iterations_count' && !ov_dir">&#x25b4;</b>
                  <b ng-show="ov_srt=='iterations_count' && ov_dir">&#x25be;</b>
                </span>
              <th class="sortable" title="Scenario runner type"
                  ng-click="ov_srt='runner'; ov_dir=!ov_dir">
                Runner
                <span class="arrow">
                  <b ng-show="ov_srt=='runner' && !ov_dir">&#x25b4;</b>
                  <b ng-show="ov_srt=='runner' && ov_dir">&#x25be;</b>
                </span>
              <th class="sortable" title="Number of errors occurred"
                  ng-click="ov_srt='errors.length'; ov_dir=!ov_dir">
                Errors
                <span class="arrow">
                  <b ng-show="ov_srt=='errors.length' && !ov_dir">&#x25b4;</b>
                  <b ng-show="ov_srt=='errors.length' && ov_dir">&#x25be;</b>
                </span>
              <th class="sortable" title="Number of hooks"
                  ng-click="ov_srt='hooks.length'; ov_dir=!ov_dir">
                Hooks
                <span class="arrow">
                  <b ng-show="ov_srt=='hooks.length' && !ov_dir">&#x25b4;</b>
                  <b ng-show="ov_srt=='hooks.length' && ov_dir">&#x25be;</b>
                </span>
              <th class="sortable" title="Whether SLA check is successful"
                  ng-click="ov_srt='sla_success'; ov_dir=!ov_dir">
                Success (SLA)
                <span class="arrow">
                  <b ng-show="ov_srt=='sla_success' && !ov_dir">&#x25b4;</b>
                  <b ng-show="ov_srt=='sla_success' && ov_dir">&#x25be;</b>
                </span>
            <tr>
          </thead>
          <tbody>
            <tr ng-repeat="sc in scenarios | orderBy:ov_srt:ov_dir"
                ng-click="location.path(sc.ref)">
              <td>{{sc.ref}}
              <td>{{sc.load_duration | number:3}}
              <td>{{sc.full_duration | number:3}}
              <td>{{sc.iterations_count}}
              <td>{{sc.runner}}
              <td>{{sc.errors.length}}
              <td>{{sc.hooks.length}}
              <td>
                <span ng-show="sc.sla_success" class="status-pass">&#x2714;</span>
                <span ng-hide="sc.sla_success" class="status-fail">&#x2716;</span>
            <tr>
          </tbody>
        </table>
      </div>

      <div ng-show="view.is_source">
        <h1>Input file</h1>
        <pre class="code">{{source}}</pre>
      </div>

      <div ng-show="view.is_scenario">
        <h1>{{scenario.cls}}.<wbr>{{scenario.name}} ({{scenario.full_duration | number:3}}s)</h1>
        <div ng-show="scenario.description" style="margin-bottom: 20px;">
            <i>{{scenario.description}}</i>
        </div>
        <ul class="tabs">
          <li ng-repeat="t in tabs"
              ng-show="t.isVisible()"
              ng-class="{active:t.id == tab}"
              ng-click="location.hash(t.id)">
            <div>{{t.name}}</div>
          </li>
          <div class="clearfix"></div>
        </ul>
        <div ng-include="tab"></div>

        <script type="text/ng-template" id="overview">
          <p class="thesis">
            Load duration: <b>{{scenario.load_duration | number:3}} s</b>  
            Full duration: <b>{{scenario.full_duration | number:3}} s</b>  
            Iterations: <b>{{scenario.iterations_count}}</b>  
            Failures: <b>{{scenario.errors.length}}</b>  
            Started at: <b>{{scenario.created_at}}</b>
          </p>

          <div ng-show="scenario.sla.length">
            <h2>Service-level agreement</h2>
            <table class="striped">
              <thead>
                <tr>
                  <th>Criterion
                  <th>Detail
                  <th>Success
                <tr>
              </thead>
              <tbody>
                <tr class="rich"
                    ng-repeat="row in scenario.sla track by $index"
                    ng-class="{'status-fail':!row.success, 'status-pass':row.success}">
                  <td>{{row.criterion}}
                  <td>{{row.detail}}
                  <td class="capitalize">{{row.success}}
                <tr>
              </tbody>
            </table>
          </div>

          <div widget="Table"
               data="scenario.table"
               lastrow-class="rich"
               title="Total durations">
          </div>

          <div widget="StackedArea"
               data="scenario.iterations.iter"
               name-x="Iteration sequence number"
               controls="true"
               guide="true">
          </div>

          <div widget="StackedArea"
               data="scenario.load_profile"
               title="Load Profile"
               title-class="h3"
               name-x="Timeline (seconds)"
               format-y="d"
               format-x=",.2f"
               class="lower">
          </div>

          <div widget="Pie"
               data="scenario.iterations.pie"
               title="Distribution"
               title-class="h3"
               style="float:left; width:40%; margin-top:15px">
          </div>

          <div widget="Histogram"
               ng-if="scenario.iterations.histogram.data.length"
               data="scenario.iterations.histogram.data[mainHistogram.id]"
               style="float:left; width:59%; margin-top:15px; position:relative; top:40px">
          </div>

          <select ng-model="mainHistogram"
                  ng-show="scenario.iterations.histogram.data.length"
                  ng-options="i.name for i in scenario.iterations.histogram.views track by i.id"
                  style="float:right; margin:45px 35px 0">
          </select>

          <div class="clearfix"></div>

        </script>

        <script type="text/ng-template" id="details">

          <div widget="StackedArea"
               data="scenario.atomic.iter"
               title="Atomic Action Durations"
               name-x="Iteration sequence number"
               controls="true"
               guide="true">
          </div>

          <div widget="Pie"
               data="scenario.atomic.pie"
               title="Distribution"
               title-class="h3"
               style="float:left; margin-top:15px"
               ng-style="compact_atomics() ? {width:'40%'} : {}">
          </div>

          <div widget="Histogram" data="scenario.atomic.histogram.data[atomicHistogram.id]"
               ng-if="scenario.atomic.histogram.data.length"
               style="float:left; position:relative; top:40px"
               ng-style="compact_atomics() ? {width:'59%', 'margin-top':'15px'} : {}">
          </div>

          <select ng-show="scenario.atomic.histogram.data.length"
                  ng-model="atomicHistogram"
                  ng-options="i.name for i in scenario.atomic.histogram.views track by i.id"
                  style="float:right; margin:45px 35px 0">
          </select>

          <div class="clearfix"></div>

        </script>

        <script type="text/ng-template" id="output">

          <div style="padding:10px 0 0">
            <span class="link"
                  ng-click="location.hash('output/additive')"
                  ng-class="{active:scenario.output.active === 'additive'}"
                  ng-if="scenario.output.has_additive">Aggregated</span>
            <span class="link"
                  ng-click="location.hash('output/complete')"
                  ng-class="{active:scenario.output.active === 'complete'}"
                  ng-if="scenario.output.has_complete">Per iteration</span>
          </div>

          <div ng-repeat="chart in scenario.additive_output"
               ng-if="scenario.output.active === 'additive'">
            <div widget="{{chart.widget}}"
                 title="{{chart.title}}"
                 description="{{chart.description}}"
                 name-x="{{chart.axis_label}}"
                 name-y="{{chart.label}}"
                 data="chart.data">
            </div>
          </div>

          <div ng-if="scenario.output.active === 'complete'" style="padding:10px 0 0">
            <select ng-model="outputIteration">
              <option ng-repeat="i in scenario.complete_output track by $index"
                      value="{{$index}}">
                Iteration {{$index}}
            </select>

            <div ng-repeat="chart in scenario.complete_output[outputIteration]">
              <div widget="{{chart.widget}}"
                   title="{{chart.title}}"
                   description="{{chart.description}}"
                   name-x="{{chart.axis_label}}"
                   name-y="{{chart.label}}"
                   data="chart.data">
              </div>
            </div>
          </div>
        </script>

        <script type="text/ng-template" id="hooks">

          <div style="padding:15px 0">
            <span ng-repeat="h in scenario.hooks track by $index"
                  class="buttn"
                  title="{{h.desc}}"
                  style="margin:0 10px 0 0"
                  ng-click="location.hash('hooks/'+$index)"
                  ng-class="{active:scenario.hook_idx===$index}">
              {{h.name}}
            </span>
          </div>

          <table class="striped" style="margin:5px 0 25px">
            <thead>
              <tr>
                <th>Plugin
                <th>Description
            </thead>
            <tbody>
              <tr>
                <td>{{scenario.hooks.cur.name}}
                <td>{{scenario.hooks.cur.desc}}
            </tbody>
          </table>

          <div>
            <span class="link"
                  ng-click="scenario.hooks.cur.active = 'additive'"
                  ng-class="{active:scenario.hooks.cur.active === 'additive'}"
                  ng-if="scenario.hooks.cur.additive.length">Aggregated</span>
            <span class="link"
                  ng-click="scenario.hooks.cur.active = 'complete'"
                  ng-class="{active:scenario.hooks.cur.active === 'complete'}"
                  ng-if="scenario.hooks.cur.complete.length">Per hook run</span>
          </div>

          <div ng-repeat="chart in scenario.hooks.cur.additive"
               ng-if="scenario.hooks.cur.active === 'additive'">
            <div widget="{{chart.widget}}"
                 title="{{chart.title}}"
                 description="{{chart.description}}"
                 name-x="{{chart.axis_label}}"
                 name-y="{{chart.label}}"
                 data="chart.data">
            </div>
          </div>

          <div ng-if="scenario.hooks.cur.active === 'complete'" style="padding:10px 0 0">

            <select ng-if="complete_hooks_as_dropdown()"
                    ng-model="scenario.hooks.cur.run_idx"
                    ng-change="set_hook_run()">
              <option ng-repeat="h in scenario.hooks.cur.complete track by $index"
                      ng-selected="scenario.hooks.cur.run_idx == $index"
                      value="{{$index}}">
                {{h.triggered_by}}
            </select>

            <div ng-if="! complete_hooks_as_dropdown()"
                 style="border:#ccc solid; border-width:1px 0 0; padding:5px 0 0">
              <span ng-repeat="h in scenario.hooks.cur.complete track by $index"
                    class="link"
                    ng-class="{active:scenario.hooks.cur.run_idx == $index}"
                    ng-click="set_hook_run($index)">
                {{h.triggered_by}}
              </span>
            </div>

            <table class="striped" style="margin:15px 0 15px">
              <thead>
                <tr>
                  <th>Status
                  <th>Triggered by
                  <th>Started at
                  <th>Finished at
              </thead>
              <tbody>
                <tr>
                  <td ng-style="scenario.hooks.cur.run.status === 'success' ? {color:'green'} : {color:'red'}">
                    <b>{{scenario.hooks.cur.run.status}}</b>
                  <td>{{scenario.hooks.cur.run.triggered_by}}
                  <td>{{scenario.hooks.cur.run.started_at}}
                  <td>{{scenario.hooks.cur.run.finished_at}}
              </tbody>
            </table>

            <div ng-repeat="chart in scenario.hooks.cur.run.charts">
              <div widget="{{chart.widget}}"
                   title="{{chart.title}}"
                   description="{{chart.description}}"
                   name-x="{{chart.axis_label}}"
                   name-y="{{chart.label}}"
                   data="chart.data">
              </div>
            </div>
          </div>
        </script>

        <script type="text/ng-template" id="failures">
          <h2>Task failures (<ng-pluralize
            count="scenario.errors.length"
            when="{'1': '1 iteration', 'other': '{} iterations'}"></ng-pluralize> failed)
          </h2>
          <table class="striped">
            <thead>
              <tr>
                <th>
                <th>Timestamp
                <th>Iteration
                <th>Exception type
                <th>Exception message
              </tr>
            </thead>
            <tbody>
              <tr class="expandable"
                  ng-repeat-start="i in scenario.errors track by $index"
                  ng-click="i.expanded = ! i.expanded">
                <td>
                  <span ng-hide="i.expanded">►</span>
                  <span ng-show="i.expanded">▼</span>
                <td>{{i.timestamp}}
                <td>{{i.iteration}}
                <td>{{i.type}}
                <td class="failure-mesg">{{i.message}}
              </tr>
              <tr ng-show="i.expanded" ng-repeat-end>
                <td colspan="4" class="failure-trace">{{i.traceback}}
              </tr>
            </tbody>
          </table>
        </script>

        <script type="text/ng-template" id="task">
          <h2>The Workload Configuration</h2>
          <pre class="code">{{scenario.config}}</pre>
        </script>
      </div>

    </div>
    <div class="clearfix"></div>


  </div>

  <script type="text/javascript">
    if (! window.angular) {(function(f){
      f(document.getElementById("content-nav"), "none");
      f(document.getElementById("content-main"), "none");
      f(document.getElementById("page-error"), "block").textContent = "Failed to load AngularJS framework"
    })(function(e, s){e.style.display = s; return e})}
</script>
</body>
</html>