var app = angular.module('plunker', ['smart-table']);

app.controller('MainCtrl', function($scope) {
  
  $scope.probes = [
    { "type": "temperature", "name": "74 DP22000-15060", "value": "+12.7" },
    { "type": "temperature", "name": "Ambiance C8", "value": "+31.6°C" },
    { "type": "temperature", "name": "Ambiance ST", "value": "+33.6°C" },
    { "type": "temperature", "name": "ambiance C12", "value": "+23.6°C" },
    { "type": "temperature", "name": "Ambiance C10", "value": "+23.6°C" },
    { "type": "hygrometry", "name": "Congélateur", "value": "25%" },
    { "type": "hygrometry", "name": "Congélateur 2", "value": "53%" },
    { "type": "hygrometry", "name": "Congélateur 6", "value": "18%" },
    { "type": "hygrometry", "name": "Hygrometry 6", "value": "5%" },
    { "type": "temperature", "name": "Frigo 1", "value": "4°C" },
    { "type": "", "name": "mobile 05", "value": "#######" },
    { "type": "particle", "name": "Particule 420", "value": "555 p/m" },
    { "type": "particle", "name": "Ambiance C9", "value": "#######" },
    { "type": "particle", "name": "Salle blanche C1", "value": "#######" },
    { "type": "particle", "name": "salle blanche C8", "value": "-######" },
    { "type": "pressure", "name": "Salle blanche C7", "value": "-######" },
    { "type": "tor", "name": "TOR 75", "value": "ON" },
    { "type": "tor", "name": "TOR PRE", "value": "ON" }
  ];
  
  $scope.sortByName = function (row) {
    return row.name.toLowerCase();
  };
  
  $scope.rowCollection = [
    {firstName: 'Laurent', lastName: 'Renard', birthDate: new Date('1987-05-21'), balance: 102, email: 'whatever@gmail.com'},
    {firstName: 'Blandine', lastName: 'Faivre', birthDate: new Date('1987-04-25'), balance: -2323.22, email: 'oufblandou@gmail.com'},
    {firstName: 'Francoise', lastName: 'Frere', birthDate: new Date('1955-08-27'), balance: 42343, email: 'raymondef@gmail.com'}
  ];
    
  $scope.getters = {
    firstName: function (value) {
      //this will sort by the length of the first name string
      return value.firstName.length;
    }
  };
  
});
<!DOCTYPE html>
<html ng-app="plunker">

<head>
  <meta charset="utf-8" />
  <title>AngularJS Plunker</title>
  <script>
    document.write('<base href="' + document.location + '" />');
  </script>
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
  <link rel="stylesheet" href="style.css" />
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css" integrity="sha384-rHyoN1iRsVXV4nD0JutlnGaslCJuC7uwjduW9SVrLvRYooPp2bWYgmgJQIXwl/Sp" crossorigin="anonymous">
  <script data-require="angular.js@1.6.x" src="https://code.angularjs.org/1.6.8/angular.js" data-semver="1.6.8"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/angular-smart-table/2.1.11/smart-table.min.js"></script>
  <script src="st-multi-sort.js"></script>
  <script src="app.js"></script>
</head>

<body ng-controller="MainCtrl">
  <div class="container-fluid">
    <h1>Probes</h1>
    
    <table st-safe-src="probes" st-table="displayProbes" class="table table-striped">
      <thead>
        <tr>
          <th st-multi-sort="type">Type</th>
          <th st-multi-sort="sortByName" st-sort-default="true">Name</th>
          <th st-multi-sort="value">Value</th>
        </tr>
      </thead>
      <tbody>
        <tr ng-repeat="probe in displayProbes track by $index">
          <td><img src="./img/{{probe.type}}" alt="{{probe.type}}" /></td>
          <td>{{probe.name}}</td>
          <td>{{probe.value}}</td>
        </tr>
      </tbody>
    </table>
    
    <h2>Second exemple</h2>
    <table st-table="rowCollection" class="table table-striped">
      <thead>
        <tr>
          <th st-sort="getters.firstName" st-sort-default="true">first name</th>
          <th st-sort="lastName">last name</th>
          <th st-sort="birthDate">birth date</th>
          <th st-sort="balance">balance</th>
        <th>email</th>
        </tr>
      </thead>
      <tbody>
        <tr ng-repeat="row in rowCollection">
          <td>{{row.firstName | uppercase}}</td>
          <td>{{row.lastName}}</td>
          <td>{{row.birthDate | date}}</td>
          <td>{{row.balance | currency}}</td>
          <td><a ng-href="mailto:{{row.email}}">email</a></td>
        </tr>
      </tbody>
    </table>
  </div>
</body>
</html>
/* Styles go here */

.st-sort-ascent:before {
  content: '\25B2';
}

.st-sort-descent:before {
  content: '\25BC';
}
(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
// Generated by CoffeeScript 1.9.2
var compareProperty, dot;

module.exports = function(collection, expressions) {
  return collection.sort(function(a, b) {
    var expression, i, len, predicate, reverse, value;
    for (i = 0, len = expressions.length; i < len; i++) {
      expression = expressions[i];
      if (typeof expression === 'object') {
        predicate = expression.predicate;
        reverse = expression.reverse;
      } else {
        predicate = expression;
      }
      value = compareProperty(predicate, reverse)(a, b);
      if (value !== 0) {
        return value;
      }
    }
  });
};

dot = {
  get: function(obj, field) {
    var i, key, keys, len, value;
    keys = field.split('.');
    value = obj;
    for (i = 0, len = keys.length; i < len; i++) {
      key = keys[i];
      value = value[key];
    }
    return value;
  },
  set: function(obj, field, setValue) {
    var allButLastKey, i, key, keys, lastKey, len, value;
    keys = field.split('.');
    allButLastKey = keys.slice(0, -1);
    lastKey = keys[keys.length - 1];
    value = obj;
    for (i = 0, len = allButLastKey.length; i < len; i++) {
      key = allButLastKey[i];
      value = value[key] != null ? value[key] : value[key] = {};
    }
    return value[lastKey] = setValue;
  }
};

compareProperty = function(predicate, reverse) {
  var getter;
  getter = typeof predicate === 'function' ? function(obj) {
    return predicate(obj);
  } : function(obj) {
    return dot.get(obj, predicate);
  };
  getter;
  if (!reverse) {
    return function(a, b) {
      if (getter(a) < getter(b)) {
        return -1;
      } else if (getter(a) > getter(b)) {
        return 1;
      } else {
        return 0;
      }
    };
  } else {
    return function(a, b) {
      if (getter(a) > getter(b)) {
        return -1;
      } else if (getter(a) < getter(b)) {
        return 1;
      } else {
        return 0;
      }
    };
  }
};

},{}],2:[function(require,module,exports){
var ng;

require('./multi_order_by');

require('./st_element_id');

ng = angular;

angular.module('smart-table').directive('stMultiSort', [
  'stConfig', '$parse', '$rootScope', 'stUniqueId', function(stConfig, $parse, $rootScope, stUniqueId) {
    return {
      restrict: 'A',
      require: '^stTable',
      link: function(scope, element, attr, ctrl) {
        var classAscent, classDescent, elementId, getter, index, predicate, sort, sortDefault, stateClasses;
        predicate = attr.stMultiSort;
        getter = $parse(predicate);
        index = 0;
        classAscent = attr.stClassAscent || stConfig.sort.ascentClass;
        classDescent = attr.stClassDescent || stConfig.sort.descentClass;
        stateClasses = [classAscent, classDescent];
        sortDefault = void 0;
        elementId = stUniqueId.generate();

        /*
        Use our custom orderBy filter, which supports reversing rows independently
         */
        ctrl.setSortFunction('multiOrderBy');

        /*
        Sort the rows.
        @param {Boolean} holdingShiftKey
         */
        sort = function(holdingShiftKey) {
          var base, reverse, tableState;
          index++;
          tableState = ctrl.tableState();
          if ((base = tableState.sort).predicate == null) {
            base.predicate = [];
          }
          reverse = index % 2 === 0;
          predicate = ng.isFunction(getter(scope)) ? getter(scope) : attr.stMultiSort;
          (function() {
            var indexOfExistingSort;
            indexOfExistingSort = (function() {
              var i, ref, sortConfig;
              ref = ctrl.tableState().sort.predicate;
              for (i in ref) {
                sortConfig = ref[i];
                if (sortConfig.elementId === elementId) {
                  return i;
                }
              }
              return -1;
            })();
            if (indexOfExistingSort !== -1) {
              return tableState.sort.predicate.splice(indexOfExistingSort, 1);
            }
          })();
          (function() {
            index = index % 2 === 0 ? 2 : 1;
            element.removeClass(stateClasses[index % 2]).addClass(stateClasses[index - 1]);
            if (!holdingShiftKey) {
              return $rootScope.$broadcast('clearOtherSortClasses', elementId);
            }
          })();
          (function() {
            if (!holdingShiftKey) {
              tableState.sort.predicate.length = 0;
            }
            return tableState.sort.predicate.push({
              elementId: elementId,
              predicate: predicate,
              reverse: reverse === true
            });
          })();
          tableState.pagination.start = 0;
          return ctrl.pipe();
        };
        if (attr.stSortDefault) {
          sortDefault = scope.$eval(attr.stSortDefault) != null ? scope.$eval(attr.stSortDefault) : attr.stSortDefault;
        }
        if (sortDefault) {
          index = sortDefault === 'reverse' ? 1 : 0;
          sort();
        }
        element.bind('click', function(e) {
          if (!predicate) {
            return;
          }
          return scope.$apply(function() {
            return sort(e.shiftKey || e.ctrlKey);
          });
        });
        return scope.$on('clearOtherSortClasses', function(e, sortedElementId) {
          if (sortedElementId !== elementId) {
            index = 0;
            return element.removeClass(classAscent).removeClass(classDescent);
          }
        });
      }
    };
  }
]);


},{"./multi_order_by":3,"./st_element_id":4}],3:[function(require,module,exports){

/*
Like angular orderBy filter, but allows reversing each parameter individually (even getters)
 */
angular.module('smart-table').filter('multiOrderBy', function() {
  return require('orderby');
});


},{"orderby":1}],4:[function(require,module,exports){

/*
Generate unique ids to identify each sortable element on the page
 */
angular.module('smart-table').factory('stUniqueId', function() {
  var id;
  id = 0;
  return {
    generate: function() {
      return id++;
    }
  };
});


},{}]},{},[2])
//# sourceMappingURL=data:application/json;charset:utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIm5vZGVfbW9kdWxlcy9icm93c2VyLXBhY2svX3ByZWx1ZGUuanMiLCJub2RlX21vZHVsZXMvb3JkZXJieS9saWIvaW5kZXguanMiLCIvVXNlcnMvZGFubnluZWxzb24vUHJvamVjdHMvc3QtbXVsdGktc29ydC9zcmMvaW5kZXguY29mZmVlIiwiL1VzZXJzL2Rhbm55bmVsc29uL1Byb2plY3RzL3N0LW11bHRpLXNvcnQvc3JjL211bHRpX29yZGVyX2J5LmNvZmZlZSIsIi9Vc2Vycy9kYW5ueW5lbHNvbi9Qcm9qZWN0cy9zdC1tdWx0aS1zb3J0L3NyYy9zdF9lbGVtZW50X2lkLmNvZmZlZSJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTtBQ0FBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM3RUEsSUFBQTs7QUFBQSxPQUFBLENBQVEsa0JBQVI7O0FBQ0EsT0FBQSxDQUFRLGlCQUFSOztBQUVBLEVBQUEsR0FBSzs7QUFFTCxPQUFPLENBQUMsTUFBUixDQUFlLGFBQWYsQ0FBNkIsQ0FBQyxTQUE5QixDQUF3QyxhQUF4QyxFQUF1RDtFQUNyRCxVQURxRCxFQUVyRCxRQUZxRCxFQUdyRCxZQUhxRCxFQUlyRCxZ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VUFDaEQsSUFBQSxDQUFBLEVBRkY7O1FBSUEsT0FBTyxDQUFDLElBQVIsQ0FBYSxPQUFiLEVBQXNCLFNBQUMsQ0FBRDtVQUNwQixJQUFBLENBQWMsU0FBZDtBQUFBLG1CQUFBOztpQkFDQSxLQUFLLENBQUMsTUFBTixDQUFhLFNBQUE7bUJBQUcsSUFBQSxDQUFLLENBQUMsQ0FBQyxRQUFGLElBQWMsQ0FBQyxDQUFDLE9BQXJCO1VBQUgsQ0FBYjtRQUZvQixDQUF0QjtlQUlBLEtBQUssQ0FBQyxHQUFOLENBQVUsdUJBQVYsRUFBbUMsU0FBQyxDQUFELEVBQUksZUFBSjtVQUNqQyxJQUFHLGVBQUEsS0FBcUIsU0FBeEI7WUFDRSxLQUFBLEdBQVE7bUJBQ1IsT0FBTyxDQUFDLFdBQVIsQ0FBb0IsV0FBcEIsQ0FBZ0MsQ0FBQyxXQUFqQyxDQUE2QyxZQUE3QyxFQUZGOztRQURpQyxDQUFuQztNQWxFSSxDQUZOOztFQURGLENBTHFEO0NBQXZEOzs7OztBQ0xBOzs7QUFHQSxPQUFPLENBQUMsTUFBUixDQUFlLGFBQWYsQ0FBNkIsQ0FBQyxNQUE5QixDQUFxQyxjQUFyQyxFQUFxRCxTQUFBO1NBQ25ELE9BQUEsQ0FBUSxTQUFSO0FBRG1ELENBQXJEOzs7OztBQ0hBOzs7QUFHQSxPQUFPLENBQUMsTUFBUixDQUFlLGFBQWYsQ0FFQSxDQUFDLE9BRkQsQ0FFUyxZQUZULEVBRXVCLFNBQUE7QUFDckIsTUFBQTtFQUFBLEVBQUEsR0FBSztTQUVMO0lBQ0UsUUFBQSxFQUFVLFNBQUE7YUFBRyxFQUFBO0lBQUgsQ0FEWjs7QUFIcUIsQ0FGdkIiLCJmaWxlIjoiZ2VuZXJhdGVkLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXNDb250ZW50IjpbIihmdW5jdGlvbiBlKHQsbixyKXtmdW5jdGlvbiBzKG8sdSl7aWYoIW5bb10pe2lmKCF0W29dKXt2YXIgYT10eXBlb2YgcmVxdWlyZT09XCJmdW5jdGlvblwiJiZyZXF1aXJlO2lmKCF1JiZhKXJldHVybiBhKG8sITApO2lmKGkpcmV0dXJuIGkobywhMCk7dmFyIGY9bmV3IEVycm9yKFwiQ2Fubm90IGZpbmQgbW9kdWxlICdcIitvK1wiJ1wiKTt0aHJvdyBmLmNvZGU9XCJNT0RVTEVfTk9UX0ZPVU5EXCIsZn12YXIgbD1uW29dPXtleHBvcnRzOnt9fTt0W29dWzBdLmNhbGwobC5leHBvcnRzLGZ1bmN0aW9uKGUpe3ZhciBuPXRbb11bMV1bZV07cmV0dXJuIHMobj9uOmUpfSxsLGwuZXhwb3J0cyxlLHQsbixyKX1yZXR1cm4gbltvXS5leHBvcnRzfXZhciBpPXR5cGVvZiByZXF1aXJlPT1cImZ1bmN0aW9uXCImJnJlcXVpcmU7Zm9yKHZhciBvPTA7bzxyLmxlbmd0aDtvKyspcyhyW29dKTtyZXR1cm4gc30pIiwiLy8gR2VuZXJhdGVkIGJ5IENvZmZlZVNjcmlwdCAxLjkuMlxudmFyIGNvbXBhcmVQcm9wZXJ0eSwgZG90O1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uKGNvbGxlY3Rpb24sIGV4cHJlc3Npb25zKSB7XG4gIHJldHVybiBjb2xsZWN0aW9uLnNvcnQoZnVuY3Rpb24oYSwgYikge1xuICAgIHZhciBleHByZXNzaW9uLCBpLCBsZW4sIHByZWRpY2F0ZSwgcmV2ZXJzZSwgdmFsdWU7XG4gICAgZm9yIChpID0gMCwgbGVuID0gZXhwcmVzc2lvbnMubGVuZ3RoOyBpIDwgbGVuOyBpKyspIHtcbiAgICAgIGV4cHJlc3Npb24gPSBleHByZXNzaW9uc1tpXTtcbiAgICAgIGlmICh0eXBlb2YgZXhwcmVzc2lvbiA9PT0gJ29iamVjdCcpIHtcbiAgICAgICAgcHJlZGljYXRlID0gZXhwcmVzc2lvbi5wcmVkaWNhdGU7XG4gICAgICAgIHJldmVyc2UgPSBleHByZXNzaW9uLnJldmVyc2U7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBwcmVkaWNhdGUgPSBleHByZXNzaW9uO1xuICAgICAgfVxuICAgICAgdmFsdWUgPSBjb21wYXJlUHJvcGVydHkocHJlZGljYXRlLCByZXZlcnNlKShhLCBiKTtcbiAgICAgIGlmICh2YWx1ZSAhPT0gMCkge1xuICAgICAgICByZXR1cm4gdmFsdWU7XG4gICAgICB9XG4gICAgfVxuICB9KTtcbn07XG5cbmRvdCA9IHtcbiAgZ2V0OiBmdW5jdGlvbihvYmosIGZpZWxkKSB7XG4gICAgdmFyIGksIGtleSwga2V5cywgbGVuLCB2YWx1ZTtcbiAgICBrZXlzID0gZmllbGQuc3BsaXQoJy4nKTtcbiAgICB2YWx1ZSA9IG9iajtcbiAgICBmb3IgKGkgPSAwLCBsZW4gPSBrZXlzLmxlbmd0aDsgaSA8IGxlbjsgaSsrKSB7XG4gICAgICBrZXkgPSBrZXlzW2ldO1xuICAgICAgdmFsdWUgPSB2YWx1ZVtrZXldO1xuICAgIH1cbiAgICByZXR1cm4gdmFsdWU7XG4gIH0sXG4gIHNldDogZnVuY3Rpb24ob2JqLCBmaWVsZCwgc2V0VmFsdWUpIHtcbiAgICB2YXIgYWxsQnV0TGFzdEtleSwgaSwga2V5LCBrZXlzLCBsYXN0S2V5LCBsZW4sIHZhbHVlO1xuICAgIGtleXMgPSBmaWVsZC5zcGxpdCgnLicpO1xuICAgIGFsbEJ1dExhc3RLZXkgPSBrZXlzLnNsaWNlKDAsIC0xKTtcbiAgICBsYXN0S2V5ID0ga2V5c1trZXlzLmxlbmd0aCAtIDFdO1xuICAgIHZhbHVlID0gb2JqO1xuICAgIGZvciAoaSA9IDAsIGxlbiA9IGFsbEJ1dExhc3RLZXkubGVuZ3RoOyBpIDwgbGVuOyBpKyspIHtcbiAgICAgIGtleSA9IGFsbEJ1dExhc3RLZXlbaV07XG4gICAgICB2YWx1ZSA9IHZhbHVlW2tleV0gIT0gbnVsbCA/IHZhbHVlW2tleV0gOiB2YWx1ZVtrZXldID0ge307XG4gICAgfVxuICAgIHJldHVybiB2YWx1ZVtsYXN0S2V5XSA9IHNldFZhbHVlO1xuICB9XG59O1xuXG5jb21wYXJlUHJvcGVydHkgPSBmdW5jdGlvbihwcmVkaWNhdGUsIHJldmVyc2UpIHtcbiAgdmFyIGdldHRlcjtcbiAgZ2V0dGVyID0gdHlwZW9mIHByZWRpY2F0ZSA9PT0gJ2Z1bmN0aW9uJyA/IGZ1bmN0aW9uKG9iaikge1xuICAgIHJldHVybiBwcmVkaWNhdGUob2JqKTtcbiAgfSA6IGZ1bmN0aW9uKG9iaikge1xuICAgIHJldHVybiBkb3QuZ2V0KG9iaiwgcHJlZGljYXRlKTtcbiAgfTtcbiAgZ2V0dGVyO1xuICBpZiAoIXJldmVyc2UpIHtcbiAgICByZXR1cm4gZnVuY3Rpb24oYSwgYikge1xuICAgICAgaWYgKGdldHRlcihhKSA8IGdldHRlcihiKSkge1xuICAgICAgICByZXR1cm4gLTE7XG4gICAgICB9IGVsc2UgaWYgKGdldHRlcihhKSA+IGdldHRlcihiKSkge1xuICAgICAgICByZXR1cm4gMTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHJldHVybiAwO1xuICAgICAgfVxuICAgIH07XG4gIH0gZWxzZSB7XG4gICAgcmV0dXJuIGZ1bmN0aW9uKGEsIGIpIHtcbiAgICAgIGlmIChnZXR0ZXIoYSkgPiBnZXR0ZXIoYikpIHtcbiAgICAgICAgcmV0dXJuIC0xO1xuICAgICAgfSBlbHNlIGlmIChnZXR0ZXIoYSkgPCBnZXR0ZXIoYikpIHtcbiAgICAgICAgcmV0dXJuIDE7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICByZXR1cm4gMDtcbiAgICAgIH1cbiAgICB9O1xuICB9XG59O1xuIiwicmVxdWlyZSAnLi9tdWx0aV9vcmRlcl9ieSdcbnJlcXVpcmUgJy4vc3RfZWxlbWVudF9pZCdcblxubmcgPSBhbmd1bGFyXG5cbmFuZ3VsYXIubW9kdWxlKCdzbWFydC10YWJsZScpLmRpcmVjdGl2ZSAnc3RNdWx0aVNvcnQnLCBbXG4gICdzdENvbmZpZydcbiAgJyRwYXJzZSdcbiAgJyRyb290U2NvcGUnXG4gICdzdFVuaXF1ZUlkJ1xuICAoc3RDb25maWcsICRwYXJzZSwgJHJvb3RTY29wZSwgc3RVbmlxdWVJZCkgLT5cbiAgICByZXN0cmljdDogJ0EnXG4gICAgcmVxdWlyZTogJ15zdFRhYmxlJ1xuICAgIGxpbms6IChzY29wZSwgZWxlbWVudCwgYXR0ciwgY3RybCkgLT5cbiAgICAgIHByZWRpY2F0ZSA9IGF0dHIuc3RNdWx0aVNvcnRcbiAgICAgIGdldHRlciA9ICRwYXJzZShwcmVkaWNhdGUpXG4gICAgICBpbmRleCA9IDBcbiAgICAgIGNsYXNzQXNjZW50ID0gYXR0ci5zdENsYXNzQXNjZW50IG9yIHN0Q29uZmlnLnNvcnQuYXNjZW50Q2xhc3NcbiAgICAgIGNsYXNzRGVzY2VudCA9IGF0dHIuc3RDbGFzc0Rlc2NlbnQgb3Igc3RDb25maWcuc29ydC5kZXNjZW50Q2xhc3NcbiAgICAgIHN0YXRlQ2xhc3NlcyA9IFtcbiAgICAgICAgY2xhc3NBc2NlbnRcbiAgICAgICAgY2xhc3NEZXNjZW50XG4gICAgICBdXG4gICAgICBzb3J0RGVmYXVsdCA9IHVuZGVmaW5lZFxuICAgICAgZWxlbWVudElkID0gc3RVbmlxdWVJZC5nZW5lcmF0ZSgpXG5cbiAgICAgICMjI1xuICAgICAgVXNlIG91ciBjdXN0b20gb3JkZXJCeSBmaWx0ZXIsIHdoaWNoIHN1cHBvcnRzIHJldmVyc2luZyByb3dzIGluZGVwZW5kZW50bHlcbiAgICAgICMjI1xuICAgICAgY3RybC5zZXRTb3J0RnVuY3Rpb24gJ211bHRpT3JkZXJCeSdcblxuICAgICAgIyMjXG4gICAgICBTb3J0IHRoZSByb3dzLlxuICAgICAgQHBhcmFtIHtCb29sZWFufSBob2xkaW5nU2hpZnRLZXlcbiAgICAgICMjI1xuICAgICAgc29ydCA9IChob2xkaW5nU2hpZnRLZXkpIC0+XG4gICAgICAgIGluZGV4KytcbiAgICAgICAgdGFibGVTdGF0ZSA9IGN0cmwudGFibGVTdGF0ZSgpXG4gICAgICAgIHRhYmxlU3RhdGUuc29ydC5wcmVkaWNhdGUgPz0gW11cbiAgICAgICAgcmV2ZXJzZSA9IGluZGV4ICUgMiBpcyAwXG4gICAgICAgIHByZWRpY2F0ZSA9IGlmIG5nLmlzRnVuY3Rpb24oZ2V0dGVyKHNjb3BlKSkgdGhlbiBnZXR0ZXIoc2NvcGUpIGVsc2UgYXR0ci5zdE11bHRpU29ydFxuXG4gICAgICAgIGRvIC0+ICMgY2xlYXIgZXhpc3Rpbmcgc29ydFxuICAgICAgICAgIGluZGV4T2ZFeGlzdGluZ1NvcnQgPSBkbyAtPlxuICAgICAgICAgICAgZm9yIGksIHNvcnRDb25maWcgb2YgY3RybC50YWJsZVN0YXRlKCkuc29ydC5wcmVkaWNhdGVcbiAgICAgICAgICAgICAgaWYgc29ydENvbmZpZy5lbGVtZW50SWQgaXMgZWxlbWVudElkXG4gICAgICAgICAgICAgICAgcmV0dXJuIGlcbiAgICAgICAgICAgIHJldHVybiAtMVxuICAgICAgICAgIGlmIGluZGV4T2ZFeGlzdGluZ1NvcnQgaXNudCAtMVxuICAgICAgICAgICAgdGFibGVTdGF0ZS5zb3J0LnByZWRpY2F0ZS5zcGxpY2UgaW5kZXhPZkV4aXN0aW5nU29ydCwgMVxuXG4gICAgICAgIGRvIC0+ICMgdXBkYXRlIHNvcnQgY2xhc3Nlc1xuICAgICAgICAgIGluZGV4ID0gaWYgaW5kZXggJSAyID09IDAgdGhlbiAyIGVsc2UgMVxuICAgICAgICAgIGVsZW1lbnQucmVtb3ZlQ2xhc3Moc3RhdGVDbGFzc2VzW2luZGV4ICUgMl0pLmFkZENsYXNzIHN0YXRlQ2xhc3Nlc1tpbmRleCAtIDFdXG4gICAgICAgICAgaWYgIWhvbGRpbmdTaGlmdEtleVxuICAgICAgICAgICAgJHJvb3RTY29wZS4kYnJvYWRjYXN0ICdjbGVhck90aGVyU29ydENsYXNzZXMnLCBlbGVtZW50SWRcblxuICAgICAgICBkbyAtPiAjIHVwZGF0ZSBzb3J0XG4gICAgICAgICAgaWYgIWhvbGRpbmdTaGlmdEtleVxuICAgICAgICAgICAgdGFibGVTdGF0ZS5zb3J0LnByZWRpY2F0ZS5sZW5ndGggPSAwO1xuICAgICAgICAgIHRhYmxlU3RhdGUuc29ydC5wcmVkaWNhdGUucHVzaFxuICAgICAgICAgICAgZWxlbWVudElkOiBlbGVtZW50SWRcbiAgICAgICAgICAgIHByZWRpY2F0ZTogcHJlZGljYXRlXG4gICAgICAgICAgICByZXZlcnNlOiByZXZlcnNlID09IHRydWVcblxuICAgICAgICB0YWJsZVN0YXRlLnBhZ2luYXRpb24uc3RhcnQgPSAwXG4gICAgICAgIGN0cmwucGlwZSgpXG5cbiAgICAgIGlmIGF0dHIuc3RTb3J0RGVmYXVsdFxuICAgICAgICBzb3J0RGVmYXVsdCA9IGlmIHNjb3BlLiRldmFsKGF0dHIuc3RTb3J0RGVmYXVsdCk/IHRoZW4gc2NvcGUuJGV2YWwoYXR0ci5zdFNvcnREZWZhdWx0KSBlbHNlIGF0dHIuc3RTb3J0RGVmYXVsdFxuXG4gICAgICBpZiBzb3J0RGVmYXVsdFxuICAgICAgICBpbmRleCA9IGlmIHNvcnREZWZhdWx0ID09ICdyZXZlcnNlJyB0aGVuIDEgZWxzZSAwXG4gICAgICAgIHNvcnQoKVxuXG4gICAgICBlbGVtZW50LmJpbmQgJ2NsaWNrJywgKGUpIC0+XG4gICAgICAgIHJldHVybiB1bmxlc3MgcHJlZGljYXRlXG4gICAgICAgIHNjb3BlLiRhcHBseSAtPiBzb3J0KGUuc2hpZnRLZXkgb3IgZS5jdHJsS2V5KVxuXG4gICAgICBzY29wZS4kb24gJ2NsZWFyT3RoZXJTb3J0Q2xhc3NlcycsIChlLCBzb3J0ZWRFbGVtZW50SWQpIC0+XG4gICAgICAgIGlmIHNvcnRlZEVsZW1lbnRJZCBpc250IGVsZW1lbnRJZFxuICAgICAgICAgIGluZGV4ID0gMFxuICAgICAgICAgIGVsZW1lbnQucmVtb3ZlQ2xhc3MoY2xhc3NBc2NlbnQpLnJlbW92ZUNsYXNzKGNsYXNzRGVzY2VudClcbl1cbiIsIiMjI1xuTGlrZSBhbmd1bGFyIG9yZGVyQnkgZmlsdGVyLCBidXQgYWxsb3dzIHJldmVyc2luZyBlYWNoIHBhcmFtZXRlciBpbmRpdmlkdWFsbHkgKGV2ZW4gZ2V0dGVycylcbiMjI1xuYW5ndWxhci5tb2R1bGUoJ3NtYXJ0LXRhYmxlJykuZmlsdGVyICdtdWx0aU9yZGVyQnknLCAtPlxuICByZXF1aXJlICdvcmRlcmJ5J1xuIiwiIyMjXG5HZW5lcmF0ZSB1bmlxdWUgaWRzIHRvIGlkZW50aWZ5IGVhY2ggc29ydGFibGUgZWxlbWVudCBvbiB0aGUgcGFnZVxuIyMjXG5hbmd1bGFyLm1vZHVsZSgnc21hcnQtdGFibGUnKVxuXG4uZmFjdG9yeSAnc3RVbmlxdWVJZCcsIC0+XG4gIGlkID0gMFxuXG4gIHtcbiAgICBnZW5lcmF0ZTogLT4gaWQrK1xuICB9XG4iXX0=