<commit_before>(function() {
  'use strict';

  var module = angular.module('bonitoTimepicker', []);

  module.directive('bonitoTimepicker', function(_, quickRanges) {
    return {
      restrict: 'E',
      templateUrl: 'timepicker/timepicker.html',
      controller: function(timefilter) {
        var self = this;
        self.time = timefilter.time;
        self.mode = 'quick';

        self.quickLists = _(quickRanges).groupBy('section').values().value();

        self.relativeOptions = [
          {text: 'Seconds ago', value: 's'},
          {text: 'Minutes ago', value: 'm'},
          {text: 'Hours ago', value: 'h'},
          {text: 'Days ago', value: 'd'},
          {text: 'Weeks ago', value: 'w'},
          {text: 'Months ago', value: 'M'},
          {text: 'Years ago', value: 'y'},
        ];

        self.relative = {
          count: 30,
          unit: 'm',
          valid: true
        };

        self.setMode = function(mode) {
          self.mode = mode;
        };

        self.setQuick = function(option) {
          timefilter.set({
            mode: 'quick',
            from: option.from,
            to: option.to,
            display: option.display
          });
        };

        self.setRelative = function() {
          var from = "now-" + self.relative.count + self.relative.unit,
            display = "Last " + self.relative.count + self.relative.unit;
          timefilter.set({
            from: from,
            to: 'now',
            display: display,
            mode: 'relative'
          });
        };

        self.relativeValidate = function() {
          var count = parseInt(self.relative.count);
          self.relative.valid = (!isNaN(count) && count > 0);
        };

      },
      controllerAs: 'timepicker'
    };
  });

  module.constant('defaultTime', {
    mode: 'quick',
    from: 'now-1h',
    to: 'now',
    display: 'Last 1 hour'
  });

  module.service('timepicker', ['_', 'quickRanges', 'defaultTime',
      function(_, quickRanges, defaultTime) {

    return {
      toUrlParameters: function(time) {
        return {
          "time-from": time.from,
          "time-to": time.to,
          "time-mode": time.mode
        };
      },

      fromUrlParameters: function(params) {
        var mode = params['time-mode'] || 'quick',
          from = params['time-from'] || 'now-1h',
          to = params['time-to'] || 'now';

        if (mode === 'quick') {
          var opt = _.find(quickRanges, function(d) {
            return d.from === from && d.to === to;
          });

          if (opt === undefined) {
            // potentially invalid values. Revert to defaults
            return defaultTime;
          }

          return {
            mode: 'quick',
            from: from,
            to: to,
            display: opt.display
          };
        } else if (mode === 'relative') {
          // TODO
        }

        // TODO: support for other modes
        return defaultTime;
      }
    };
  }]);

})();
<commit_msg>Use the relative URL parameters when present<commit_after>(function() {
  'use strict';

  var module = angular.module('bonitoTimepicker', []);

  module.directive('bonitoTimepicker', function(_, quickRanges) {
    return {
      restrict: 'E',
      templateUrl: 'timepicker/timepicker.html',
      controller: function(timefilter) {
        var self = this;
        self.time = timefilter.time;
        self.mode = 'quick';

        self.quickLists = _(quickRanges).groupBy('section').values().value();

        self.relativeOptions = [
          {text: 'Seconds ago', value: 's'},
          {text: 'Minutes ago', value: 'm'},
          {text: 'Hours ago', value: 'h'},
          {text: 'Days ago', value: 'd'},
          {text: 'Weeks ago', value: 'w'},
          {text: 'Months ago', value: 'M'},
          {text: 'Years ago', value: 'y'},
        ];

        self.relative = {
          count: 30,
          unit: 'm',
          valid: true
        };

        self.setMode = function(mode) {
          self.mode = mode;
        };

        self.setQuick = function(option) {
          timefilter.set({
            mode: 'quick',
            from: option.from,
            to: option.to,
            display: option.display
          });
        };

        self.setRelative = function() {
          var from = "now-" + self.relative.count + self.relative.unit,
            display = "Last " + self.relative.count + self.relative.unit;
          timefilter.set({
            from: from,
            to: 'now',
            display: display,
            mode: 'relative'
          });
        };

        self.relativeValidate = function() {
          var count = parseInt(self.relative.count);
          self.relative.valid = (!isNaN(count) && count > 0);
        };

      },
      controllerAs: 'timepicker'
    };
  });

  module.constant('defaultTime', {
    mode: 'quick',
    from: 'now-1h',
    to: 'now',
    display: 'Last 1 hour'
  });

  module.service('timepicker', ['_', 'quickRanges', 'defaultTime',
      function(_, quickRanges, defaultTime) {

    return {
      toUrlParameters: function(time) {
        return {
          "time-from": time.from,
          "time-to": time.to,
          "time-mode": time.mode
        };
      },

      fromUrlParameters: function(params) {
        var mode = params['time-mode'] || defaultTime.mode,
          from = params['time-from'] || defaultTime.from,
          to = params['time-to'] || defaultTime.to;

        if (mode === 'quick') {
          var opt = _.find(quickRanges, function(d) {
            return d.from === from && d.to === to;
          });

          if (opt === undefined) {
            // potentially invalid values. Revert to defaults
            return defaultTime;
          }

          return {
            mode: 'quick',
            from: from,
            to: to,
            display: opt.display
          };
        } else if (mode === 'relative') {
          var m = from.match(/now-([0-9]+)([smhdwMy])/);
          if (m === null) {
            return defaultTime;
          }
          var count = parseInt(m[1]), unit = m[2];
          if (isNaN(count) || unit === '') {
            return defaultTime;
          }

          return {
            mode: 'relative',
            from: from,
            to: 'now',
            display: 'Last ' + count + unit
          };

        }

        // TODO: support for other modes
        return defaultTime;
      }
    };
  }]);

})();

{'fraction_non_alphanumeric': 0.15270708005552985, 'fraction_numerical': 0.0023137436372049976, 'mean_word_length': 1.5884231536926148, 'pattern_counts': {'":': 6, '<': 3, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4418824', 'n_tokens_mistral': 1897, 'n_tokens_neox': 1853, 'n_words': 428}