<commit_before>/**
 * Functions, prototypes, and plugins useful in web development
 */

/**
 * Closure with jQuery wrapper
 */
(function ($) {
  /**
   * Get all attributes for the given element if there are no arguments, or apply the arguments as typically handled.
   * @returns {*}
   */
  $.fn.attr = function () {
    if (arguments.length === 0) {
      if (this.length === 0) {
        return null;
      }

      var obj = {};
      $.each(this[0].attributes, function () {
        if (this.specified) {
          obj[this.name] = this.value;
        }
      });
      return obj;
    }

    return $.apply(this, arguments);
  };

  /**
   * Get or set the contents of the specified iframe
   * @param content {string}
   * @returns string
   * @author Mike Rodarte
   */
  $.fn.iframeContents = function (content) {
    // be sure this is an iframe
    if (this[0].nodeName !== 'IFRAME') {
      return '';
    }

    if (content !== undefined && typeof content === 'string') {
      $($(this.contents()[0].body).contents().find('body').context).html(content);
    } else {
      return $($(this.contents()[0].body).contents().find('body').context).html();
    }
  };

  /**
   * Determine if an element is a child of a parent
   * Alias for jQuery.contains
   * @param parent string selector
   * @returns {*}
   */
  $.fn.isChildOf = function (parent) {
    return $.contains($(parent)[0], this[0]);
  };

  /**
   * Center an element according to the window, body, and element size.
   *
   * @author Mike Rodarte
   */
  $.fn.centerBox = function () {
    var $selector = this;
    if ($selector.length < 1) {
      return false;
    }

    // get widths of containers
    var windowWidth = $(window).width();
    var bodyWidth = $('body').width();
    var boxWidth = $selector.width();

    // calculate widths and positions
    var centeredLeft = (bodyWidth - boxWidth) / 2;
    var bodyMargin = windowWidth - bodyWidth;
    var left = bodyMargin / 2 + centeredLeft;

    // apply the left value to the selector
    $selector.css({
      left: Math.floor(left)
    });
  };

  /**
   * Debug class wrapper for console object
   * @constructor
   */
  function Debug() {
    /**
     * Public variable to determine if messages should display
     * @type {boolean}
     */
    this.debugging = false;
    /**
     * Reference to this object for use within method functions
     * @type {Debug}
     */
    var self = this;

    /**
     * Get line information for the caller (or whichever element is specified)
     * @returns {*}
     */
    this.lineInfo = function () {
      var e = new Error();
      if (!e.stack) {
        return {};
      }

      // this stack element would be 0, so its caller would be 1, which is typically going to be debug functions
      // 2 should be default to get the caller of the debug function that called this one
      var numBack = 2;
      if (arguments[0] !== undefined) {
        numBack = parseInt(arguments[0]);
      }

      // split the stack
      var stack = e.stack.toString().split(/\r\n|\n/);

      // use default value in case provided argument is bad
      if (!stack.hasOwnProperty(numBack) && stack.hasOwnProperty(2)) {
        numBack = 2;
      }

      // get the last function data
      var lastFunc = stack[numBack];
      // stack lines have a specific format we need to use to extract data
      var pattern = /(.+)@(.+):([\d]+):([\d]+)/;
      // get the matches from the stack line
      var matches = pattern.exec(lastFunc);

      // make the values easier for people to read
      return {
        function: matches[1],
        file: matches[2],
        line: matches[3],
        column: matches[4]
      };
    };

    /**
     * Print a trace from a given object
     * @param lineInfo
     */
    this.printCaller = function (lineInfo) {
      if (this.debugging && typeof console.info === 'function') {
        if (lineInfo === undefined) {
          lineInfo = self.lineInfo(3);
        }
        console.info(lineInfo.file + ' called ' + lineInfo.function + ' on line ' + lineInfo.line);
      }
    };

    /**
     * Alias for console.log that only displays if debugging is enabled
     */
    this.log = function () {
      if (this.debugging && typeof console.log === 'function') {
        console.log.apply(null, arguments);
      }
    };

    /**
     * Alias for console.info that only displays if debugging is enabled
     */
    this.info = function () {
      if (this.debugging && typeof console.info === 'function') {
        console.info.apply(null, arguments);
      }
    };

    /**
     * Alias for console.warn that only displays if debugging is enabled
     */
    this.warn = function () {
      if (this.debugging && typeof console.warn === 'function') {
        self.printCaller();
        console.warn.apply(null, arguments);
      }
    };

    /**
     * Alias for console.error that only displays if debugging is enabled
     */
    this.error = function () {
      if (this.debugging && typeof console.error === 'function') {
        console.error.apply(null, arguments);
      }
    };

    /**
     * Alias for console.dir that only displays if debugging is enabled
     */
    this.dir = function () {
      if (this.debugging && typeof console.dir === 'function') {
        console.dir.apply(null, arguments);
      }
    };

    /**
     * Display arguments based on their types
     */
    this.display = function () {
      if (!this.debugging) {
        return false;
      }
      $.each(arguments, function (index, arg) {
        if (typeof arg === 'object') {
          self.dir(arg);
        }
        else {
          self.log(arg);
        }
      });
    };
  }

  /**
   * Generate HTML for a group of radios or a select box
   *
   * @param {string} type radio|select Type of options to display
   * @param {{}} values Key-value pairs of values to include
   * @param {{}} containerAttributes HTML attributes to associate with the container
   * @param {{}} optionAttributes HTML attributes to associate with each option
   * @param {string} [inputName] Name for the input
   * @param {string} [labelClass] Class to add to the label of the radio option
   * @returns {*}
   */
  function buildOptions(type, values, containerAttributes, optionAttributes, inputName, labelClass) {
    // validate type
    if (['radio', 'select'].indexOf(type) === -1) {
      return '';
    }

    // set default value for inputName
    if (inputName === undefined) {
      inputName = type;
    }

    // set default value for labelClass
    if (labelClass === undefined) {
      labelClass = '';
    }

    // create a container
    var $container = type === 'select' ? $('<select>') : $('<div>');

    // apply all attributes to $container
    if (isObject(containerAttributes)) {
      $container.attr(containerAttributes);
    }

    // store the options in an array
    var options = [];

    // create a blank first option
    if (type === 'select') {
      $container.attr('name', inputName);
      options.push($('<option value="-1"></option>'));
    }

    // prepare the values
    $.each(values, function (key, value) {
      var $row = null;
      // radios should be wrapped in a label to allow for clicking on the label to select
      if (type === 'radio') {
        $row = $('<label class="row-radio">');

        // add another label class if desired
        if (labelClass.length > 0) {
          $row.addClass(labelClass);
        }
      }

      // get the option ready
      var $option = null;
      switch (type) {
        case 'radio':
          $option = $('<input type="radio" value="' + value + '" />');
          // ensure radio $option will have a name
          if ((isObject(optionAttributes) && !optionAttributes.hasOwnProperty('name')) || !isObject(optionAttributes)) {
            $option.attr('name', inputName);
          }
          break;
        case 'select':
          $option = $('<option value="' + value + '">' + value + '</option>');
          break;
      }

      // apply all attributes to $option
      if (isObject(optionAttributes)) {
        $option.attr(optionAttributes);
      }

      // add this option to the array
      switch (type) {
        case 'radio':
          $row.append([$option, value]);
          options.push($row);
          break;
        case 'select':
          options.push($option);
          break;
      }
    });

    // put the options into the container
    $container.append(options);

    // return the container
    return $container;
  }
})(jQuery);

/**
 * Get unique values from an array, not differentiating between types.
 * This was tested alongside of 3 other functions and was found to be the fastest (that ignored type).
 * For a solution that maintains types, do this: return Array.from(new Set(a));
 * Using filter and indexOf is slower than these 2 methods and unsupported in older browsers.
 * phpjs' array_unique was extremely slow in all tests and should be avoided.
 *
 * @returns {Array}
 * @see http://stackoverflow.com/questions/1960473/unique-values-in-an-array#answer-1961068
 */
Array.prototype.unique = function () {
  var u = {}, b = [];
  for (var i = 0, l = this.length; i < l; ++i) {
    if (u.hasOwnProperty(this[i])) {
      continue;
    }
    b.push(this[i]);
    u[this[i]] = 1;
  }
  return b;
};

/**
 * Uppercase the first character of the string
 * @returns {string}
 */
String.prototype.ucfirst = function () {
  return this[0].toUpperCase() + this.substr(1);
};

/**
 * Uppercase the first character of each word
 * @returns {string}
 * @see String.prototype.ucfirst()
 */
String.prototype.ucwords = function () {
  var words = this.split(' ');
  var str = '';
  for (var i in words) {
    if (!words.hasOwnProperty(i)) {
      continue;
    }

    str += words[i].ucfirst() + ' ';
  }

  return str.trim();
};

/**
 * Generate a random integer between the start and end values.
 *
 * @param start {number}
 * @param end {number}
 * @returns {number}
 * @see http://www.w3schools.com/jsref/jsref_random.asp
 */
function getRandom(start, end) {
  if (!isNaN(start) || !isNaN(end) || start > end) {
    return -1;
  }
  return Math.floor((Math.random() * end) + start);
}

/**
 * Determine if the variable is an actual object
 * @param obj
 * @returns {boolean}
 * @see https://stackoverflow.com/questions/8511281/check-if-a-value-is-an-object-in-javascript#answer-42250981
 */
function isObject(obj) {
  return Object.prototype.toString.call(obj) === '[object Object]';
}
<commit_msg>added screenSize function<commit_after>/**
 * Functions, prototypes, and plugins useful in web development
 */

/**
 * Closure with jQuery wrapper
 */
(function ($) {
  /**
   * Get all attributes for the given element if there are no arguments, or apply the arguments as typically handled.
   * @returns {*}
   */
  $.fn.attr = function () {
    if (arguments.length === 0) {
      if (this.length === 0) {
        return null;
      }

      var obj = {};
      $.each(this[0].attributes, function () {
        if (this.specified) {
          obj[this.name] = this.value;
        }
      });
      return obj;
    }

    return $.apply(this, arguments);
  };

  /**
   * Get or set the contents of the specified iframe
   * @param content {string}
   * @returns string
   * @author Mike Rodarte
   */
  $.fn.iframeContents = function (content) {
    // be sure this is an iframe
    if (this[0].nodeName !== 'IFRAME') {
      return '';
    }

    if (content !== undefined && typeof content === 'string') {
      $($(this.contents()[0].body).contents().find('body').context).html(content);
    } else {
      return $($(this.contents()[0].body).contents().find('body').context).html();
    }
  };

  /**
   * Determine if an element is a child of a parent
   * Alias for jQuery.contains
   * @param parent string selector
   * @returns {*}
   */
  $.fn.isChildOf = function (parent) {
    return $.contains($(parent)[0], this[0]);
  };

  /**
   * Center an element according to the window, body, and element size.
   *
   * @author Mike Rodarte
   */
  $.fn.centerBox = function () {
    var $selector = this;
    if ($selector.length < 1) {
      return false;
    }

    // get widths of containers
    var windowWidth = $(window).width();
    var bodyWidth = $('body').width();
    var boxWidth = $selector.width();

    // calculate widths and positions
    var centeredLeft = (bodyWidth - boxWidth) / 2;
    var bodyMargin = windowWidth - bodyWidth;
    var left = bodyMargin / 2 + centeredLeft;

    // apply the left value to the selector
    $selector.css({
      left: Math.floor(left)
    });
  };

  /**
   * Debug class wrapper for console object
   * @constructor
   */
  function Debug() {
    /**
     * Public variable to determine if messages should display
     * @type {boolean}
     */
    this.debugging = false;
    /**
     * Reference to this object for use within method functions
     * @type {Debug}
     */
    var self = this;

    /**
     * Get line information for the caller (or whichever element is specified)
     * @returns {*}
     */
    this.lineInfo = function () {
      var e = new Error();
      if (!e.stack) {
        return {};
      }

      // this stack element would be 0, so its caller would be 1, which is typically going to be debug functions
      // 2 should be default to get the caller of the debug function that called this one
      var numBack = 2;
      if (arguments[0] !== undefined) {
        numBack = parseInt(arguments[0]);
      }

      // split the stack
      var stack = e.stack.toString().split(/\r\n|\n/);

      // use default value in case provided argument is bad
      if (!stack.hasOwnProperty(numBack) && stack.hasOwnProperty(2)) {
        numBack = 2;
      }

      // get the last function data
      var lastFunc = stack[numBack];
      // stack lines have a specific format we need to use to extract data
      var pattern = /(.+)@(.+):([\d]+):([\d]+)/;
      // get the matches from the stack line
      var matches = pattern.exec(lastFunc);

      // make the values easier for people to read
      return {
        function: matches[1],
        file: matches[2],
        line: matches[3],
        column: matches[4]
      };
    };

    /**
     * Print a trace from a given object
     * @param lineInfo
     */
    this.printCaller = function (lineInfo) {
      if (this.debugging && typeof console.info === 'function') {
        if (lineInfo === undefined) {
          lineInfo = self.lineInfo(3);
        }
        console.info(lineInfo.file + ' called ' + lineInfo.function + ' on line ' + lineInfo.line);
      }
    };

    /**
     * Alias for console.log that only displays if debugging is enabled
     */
    this.log = function () {
      if (this.debugging && typeof console.log === 'function') {
        console.log.apply(null, arguments);
      }
    };

    /**
     * Alias for console.info that only displays if debugging is enabled
     */
    this.info = function () {
      if (this.debugging && typeof console.info === 'function') {
        console.info.apply(null, arguments);
      }
    };

    /**
     * Alias for console.warn that only displays if debugging is enabled
     */
    this.warn = function () {
      if (this.debugging && typeof console.warn === 'function') {
        self.printCaller();
        console.warn.apply(null, arguments);
      }
    };

    /**
     * Alias for console.error that only displays if debugging is enabled
     */
    this.error = function () {
      if (this.debugging && typeof console.error === 'function') {
        console.error.apply(null, arguments);
      }
    };

    /**
     * Alias for console.dir that only displays if debugging is enabled
     */
    this.dir = function () {
      if (this.debugging && typeof console.dir === 'function') {
        console.dir.apply(null, arguments);
      }
    };

    /**
     * Display arguments based on their types
     */
    this.display = function () {
      if (!this.debugging) {
        return false;
      }
      $.each(arguments, function (index, arg) {
        if (typeof arg === 'object') {
          self.dir(arg);
        }
        else {
          self.log(arg);
        }
      });
    };
  }

  /**
   * Generate HTML for a group of radios or a select box
   *
   * @param {string} type radio|select Type of options to display
   * @param {{}} values Key-value pairs of values to include
   * @param {{}} containerAttributes HTML attributes to associate with the container
   * @param {{}} optionAttributes HTML attributes to associate with each option
   * @param {string} [inputName] Name for the input
   * @param {string} [labelClass] Class to add to the label of the radio option
   * @returns {*}
   */
  function buildOptions(type, values, containerAttributes, optionAttributes, inputName, labelClass) {
    // validate type
    if (['radio', 'select'].indexOf(type) === -1) {
      return '';
    }

    // set default value for inputName
    if (inputName === undefined) {
      inputName = type;
    }

    // set default value for labelClass
    if (labelClass === undefined) {
      labelClass = '';
    }

    // create a container
    var $container = type === 'select' ? $('<select>') : $('<div>');

    // apply all attributes to $container
    if (isObject(containerAttributes)) {
      $container.attr(containerAttributes);
    }

    // store the options in an array
    var options = [];

    // create a blank first option
    if (type === 'select') {
      $container.attr('name', inputName);
      options.push($('<option value="-1"></option>'));
    }

    // prepare the values
    $.each(values, function (key, value) {
      var $row = null;
      // radios should be wrapped in a label to allow for clicking on the label to select
      if (type === 'radio') {
        $row = $('<label class="row-radio">');

        // add another label class if desired
        if (labelClass.length > 0) {
          $row.addClass(labelClass);
        }
      }

      // get the option ready
      var $option = null;
      switch (type) {
        case 'radio':
          $option = $('<input type="radio" value="' + value + '" />');
          // ensure radio $option will have a name
          if ((isObject(optionAttributes) && !optionAttributes.hasOwnProperty('name')) || !isObject(optionAttributes)) {
            $option.attr('name', inputName);
          }
          break;
        case 'select':
          $option = $('<option value="' + value + '">' + value + '</option>');
          break;
      }

      // apply all attributes to $option
      if (isObject(optionAttributes)) {
        $option.attr(optionAttributes);
      }

      // add this option to the array
      switch (type) {
        case 'radio':
          $row.append([$option, value]);
          options.push($row);
          break;
        case 'select':
          options.push($option);
          break;
      }
    });

    // put the options into the container
    $container.append(options);

    // return the container
    return $container;
  }
})(jQuery);

/**
 * Get unique values from an array, not differentiating between types.
 * This was tested alongside of 3 other functions and was found to be the fastest (that ignored type).
 * For a solution that maintains types, do this: return Array.from(new Set(a));
 * Using filter and indexOf is slower than these 2 methods and unsupported in older browsers.
 * phpjs' array_unique was extremely slow in all tests and should be avoided.
 *
 * @returns {Array}
 * @see http://stackoverflow.com/questions/1960473/unique-values-in-an-array#answer-1961068
 */
Array.prototype.unique = function () {
  var u = {}, b = [];
  for (var i = 0, l = this.length; i < l; ++i) {
    if (u.hasOwnProperty(this[i])) {
      continue;
    }
    b.push(this[i]);
    u[this[i]] = 1;
  }
  return b;
};

/**
 * Uppercase the first character of the string
 * @returns {string}
 */
String.prototype.ucfirst = function () {
  return this[0].toUpperCase() + this.substr(1);
};

/**
 * Uppercase the first character of each word
 * @returns {string}
 * @see String.prototype.ucfirst()
 */
String.prototype.ucwords = function () {
  var words = this.split(' ');
  var str = '';
  for (var i in words) {
    if (!words.hasOwnProperty(i)) {
      continue;
    }

    str += words[i].ucfirst() + ' ';
  }

  return str.trim();
};

/**
 * Generate a random integer between the start and end values.
 *
 * @param start {number}
 * @param end {number}
 * @returns {number}
 * @see http://www.w3schools.com/jsref/jsref_random.asp
 */
function getRandom(start, end) {
  if (!isNaN(start) || !isNaN(end) || start > end) {
    return -1;
  }
  return Math.floor((Math.random() * end) + start);
}

/**
 * Determine if the variable is an actual object
 * @param obj
 * @returns {boolean}
 * @see https://stackoverflow.com/questions/8511281/check-if-a-value-is-an-object-in-javascript#answer-42250981
 */
function isObject(obj) {
  return Object.prototype.toString.call(obj) === '[object Object]';
}

/**
 * Determine sizes of the screen and return them to the caller.
 * Outer is the size of the window (plus a little extra).
 * Screen is the full sizes of the display device.
 * Available is the size of the window.
 * Inner is actual space available to web pages.
 * Banana.
 *  @returns {{availableHeight: Number, availableWidth: Number, screenHeight: Number, screenWidth: Number, innerHeight: Number, innerWidth: Number, outerHeight: Number, outerWidth: Number, orientation: string, orientationDegrees: *, dpi: string, devicePixelRatio: *, retina: string}}
 */
function screenSize() {
  var aHeight = window.screen.availHeight;
  var aWidth = window.screen.availWidth;
  var iWidth = window.innerWidth;
  var orientation = window.orientation;
  var retina = window.devicePixelRatio >= 2 ? 'Retina' : 'Not Retina';
  var higherDpi = iWidth > aWidth;
  var hiDpi = higherDpi || retina === 'Retina' ? 'High DPI' : 'Low DPI';

  var orientationText = '';
  if (orientation !== undefined) {
    switch (orientation) {
      case -90:
      case 90:
        orientationText = 'landscape';
        break;
      default:
        orientationText = 'portrait';
        break;
    }
  } else {
    orientationText = aHeight > aWidth ? 'portrait' : 'landscape';
  }

  return {
    availableHeight: aHeight,
    availableWidth: aWidth,
    screenHeight: window.screen.height,
    screenWidth: window.screen.width,
    innerHeight: window.innerHeight,
    innerWidth: iWidth,
    outerHeight: window.outerHeight,
    outerWidth: window.outerWidth,
    orientation: orientationText,
    orientationDegrees: orientation,
    dpi: hiDpi,
    devicePixelRatio: window.devicePixelRatio,
    retina: retina
  };
}
<|endoftext|>


<commit_before>angular.module('npact')
  .directive('npactGraphContainer', function() {
    'use strict';
    return {
      restrict: 'A',
      scope: true,
      controller: 'npactGraphContainerCtrl as ctrl'
    };
  })
  .controller('npactGraphContainerCtrl', function($scope, $element, $window, $log, $timeout,
                                           npactConstants, Utils, GraphConfig, Evt,
                                           GraphingCalculator) {
    'use strict';
    var $win = angular.element($window),
        getWidth =  function() { return $element.width(); },
        baseOpts = {
          width: null,
          m: null,
          tracks: null,
          onDragMove: function (dx) {
          $scope.$broadcast('offset', dx);
          },
          onDragEnd: function (dx) {
            $scope.$evalAsync(function () {
              GraphConfig.offset += Math.round(dx);
              $log.log("Finished dragging, new offset is", GraphConfig.offset);
          });
          },
          onRegionSelected: function (data) { $scope.$emit('region-selected', data); },
          onOrfSelected: function (data) {  $scope.$emit('ORF-selected', data); },
          onHitSelected: function (data) {  $scope.$emit('hit-selected', data); }
        },
        updateMetrics = function () {
          baseOpts.width = getWidth();
          baseOpts.m = GraphingCalculator.chart(baseOpts);
          $scope.graphHeight = baseOpts.m.height;
        },
        redraw = function (clearing) { $scope.$broadcast(Evt.REDRAW, clearing); };

    $scope.baseOpts = baseOpts;
    this.winHeight = $win.height();

    var onResize = _.throttle(_.bind(function () {
      this.winHeight = $win.height();
      if(getWidth() !== baseOpts.width) {
        updateMetrics();
        redraw();
      }
      $scope.$applyAsync();
    }, this), 1000/30);
    $win.on('resize', onResize);
    $scope.$on('$destroy', function () { $win.off('resize', onResize); });
    $timeout(onResize, 100, false);

    $scope.$watch(function () { return GraphConfig.basesPerGraph; }, updateMetrics);
    $scope.$watchCollection(GraphConfig.activeTracks, function (val, old) {
      //Find headers and headerY
      baseOpts.tracks = val;
      updateMetrics();
      $scope.$broadcast('updateRowHeight', baseOpts.m.height);
      redraw({headers: true});
    });

    $scope.$on('printresize', function(event, printing) {
      if(printing) {
        $element.css({width: '7in'});
        onResize();
      }
      else {
        $element.css({width: 'auto'});
        onResize();
      }
    });

    $scope.$watch(function() { return GraphConfig.nucleotides; },
                  function() { redraw({nProfiles: true, headers: true}); },
                  true);
    $scope.$watch(function() { return GraphConfig.colorBlindFriendly; }, redraw);
  })

  .directive('npactGraphScroller', function ($log, $window, Evt) {
    'use strict';
    return {
      restrict: 'A',
      require: 'npactGraphContainer',
      link: function ($scope, $element, $attrs, npactGraphContainerCtrl) {
        var $win = angular.element($window),
        graphHeight = 0, graphRowHeight = null,
        slack = 20, // how many pixels outside of viewport to render
        topOffset = 0,
        topIdx = 0, bottomIdx = 0;

        var updateVisibility = function () {
          if(!graphRowHeight) return;
          slack = graphRowHeight / 4;
          var scrollDist = $window.scrollY - topOffset - slack;
          topIdx = Math.floor(scrollDist / graphRowHeight);
          bottomIdx = topIdx + Math.ceil(
            (npactGraphContainerCtrl.winHeight + slack) / graphRowHeight);
        };

        $scope.visible = function(idx) { return idx >= topIdx && idx <= bottomIdx; };

        var draw = _.throttle(function () {
          updateVisibility();
          $scope.$broadcast(Evt.DRAW);
        }, 1000/20);

        $scope.$on('updateRowHeight', function ($evt, height) {
          $log.debug("Updating graphHeight to", height);
          topOffset = $element.offset().top;
          topOffset += _.parseInt($element.css('padding-top'));
          topOffset = Math.floor(topOffset);

          // Keep the topIdx at the top through the height change
          var delta = Math.max(0, topIdx) * (height - graphHeight);
          if (delta) { $window.scrollBy(0, delta); }
          graphHeight = height;
          $scope.$evalAsync(function () {
            //This code won't work until after the `$scope.graphHeight`
            //above has a chance to take effect. Hence the async.
            try {
              // Find the height including the padding+border for
              // graphRowHeight visibility calculations
              graphRowHeight = angular.element('.graph', $element).outerHeight();
            }
            catch(e) {
              graphRowHeight = 0; // There are no rows
            }
            draw();
          });
        });

        $win.on('scroll', draw);
        $scope.$on('$destroy', function () { $win.off('scroll', draw); });
      }
    };
  })

  .directive('npactKeyHandlers', function($window, $log, GraphConfig) {
    'use strict';
    return {
      restrict: 'A',
      link: function ($scope, $element, $attrs) {
        var $win = angular.element($window),
        onKeyDown = _.throttle(function(event) {
          //Ignore keys while the user is typing in input controls
          if(event.target.nodeName == "INPUT") return;
          var keyCode = event.which, delta;
          switch(keyCode) {
          case 37: // left key
            delta = -GraphConfig.basesPerGraph / 100;
            GraphConfig.offset += delta;
            $scope.$broadcast('offset', delta);
            break;
          case 39: // right key
            delta = GraphConfig.basesPerGraph / 100;
            GraphConfig.offset += delta;
            $scope.$broadcast('offset', delta);
            break;
          }
        }, 40, {leading:true}),
        onKeyUp = _.debounce(function(event) {
          var keyCode = event.which;
          switch(keyCode) {
          case 37: // left key
          case 39: // right key
            $scope.$apply();
            break;
          }
        }, 800);
        $win.on('keydown', onKeyDown);
        $win.on('keyup', onKeyUp);
        $scope.$on('$destroy', function() {
          $win.off('keydown', onKeyDown);
          $win.off('keyup', onKeyUp);
        });
      }
    };
  })

  .directive('npactGraph', function (Grapher, Evt, GraphingCalculator, GraphConfig,
                              $log, $timeout, $window) {
    'use strict';
    return {
      restrict: 'A',
      scope: {
        startBase: '&',
        endBase: '&',
        visible: '&',
        graphOptions: '&'
      },
      link: function($scope, $element, $attrs) {
        var g = null, scheduledOn = null,
        startBase = $scope.startBase(),
        endBase = $scope.endBase(),
        visible = $scope.visible,
        id = $attrs.id,
        // redraw gets set for all graphs once (e.g. a new track
        // triggers broadcasts redraw), but only gets cleared as
        // the currently visible ones are drawn
        redraw = false,
        draw = function(force) {
          var t1 = scheduledOn;
          scheduledOn = null;
          if(!redraw || (!force && !visible())) { return null; }
          var opts = _.clone($scope.graphOptions());
          opts.startBase = startBase;
          opts.endBase = endBase;

          //However long it actually takes to draw, we have the
          //latest options as of this point
          redraw = false;
          return (g || (g = new Grapher($element, $scope, opts)))
            .draw(opts)
            .then(function () {
              $log.log("Finished draw at", opts.startBase, "in", new Date() - t1);
            })
            .catch(function() {
              //something went wrong, we will still need to redraw this
              redraw = true;
            });
        },
        schedule = function(force) {
          if(redraw && (force || (visible() && scheduledOn !== null))) {
            scheduledOn = new Date();
            return $timeout(_.partial(draw, force), 0, false);
          }
          return null;
        },
        discard = function() { if(g) { g.destroy(); g = null; } },
        scrollToHere = function() {
          $log.log('scrolling to', $element);
          $window.scrollTo(0, $element.offset().top);
        };
        $scope.$on(Evt.DRAW, _.partial(schedule, false));
        $scope.$on(Evt.REDRAW, function(evt, cachesToClear) {
          redraw = true;
          if(g && cachesToClear) {
            if(cachesToClear.nProfiles) { g.clearProfilePoints(); }
            if(cachesToClear.headers) { g.clearLeftLayerCache(); }
          }
          schedule();
        });
        $scope.$on(Evt.REBUILD, function() {
          discard();
          startBase = $scope.startBase();
          endBase = $scope.endBase();
          redraw = true;
          schedule();
        });
        $scope.$on('offset', function(event, dx) {
          if(g && g.offset && visible()) { g.offset(dx); }
        });
        $scope.$on('$destroy', discard);

        $scope.$on('print', function(evt, callback) {
          var p = schedule(true);
          if(p) {
            callback(p.then(function() { return g.replaceWithImage(); }));
          }
          else { callback(g.replaceWithImage()); }
        });
        $scope.$watch(function() { return GraphConfig.gotoBase; }, function(gotoBase, fromBase) {
          if (_.isFinite(gotoBase) && startBase <= gotoBase && gotoBase <= endBase) {
            $log.log('gotoBase triggered redraw:', startBase, id);
            redraw = true;
            schedule();
            $timeout(scrollToHere, 0, false);
          }
          else if(_.isFinite(fromBase) && startBase <= fromBase && fromBase <= endBase) {
            redraw = true;
          }
        });
      }
    };
  })
;
<commit_msg>Fix redraw logic bug from "Add draw timing logic"<commit_after>angular.module('npact')
  .directive('npactGraphContainer', function() {
    'use strict';
    return {
      restrict: 'A',
      scope: true,
      controller: 'npactGraphContainerCtrl as ctrl'
    };
  })
  .controller('npactGraphContainerCtrl', function($scope, $element, $window, $log, $timeout,
                                           npactConstants, Utils, GraphConfig, Evt,
                                           GraphingCalculator) {
    'use strict';
    var $win = angular.element($window),
        getWidth =  function() { return $element.width(); },
        baseOpts = {
          width: null,
          m: null,
          tracks: null,
          onDragMove: function (dx) {
          $scope.$broadcast('offset', dx);
          },
          onDragEnd: function (dx) {
            $scope.$evalAsync(function () {
              GraphConfig.offset += Math.round(dx);
              $log.log("Finished dragging, new offset is", GraphConfig.offset);
          });
          },
          onRegionSelected: function (data) { $scope.$emit('region-selected', data); },
          onOrfSelected: function (data) {  $scope.$emit('ORF-selected', data); },
          onHitSelected: function (data) {  $scope.$emit('hit-selected', data); }
        },
        updateMetrics = function () {
          baseOpts.width = getWidth();
          baseOpts.m = GraphingCalculator.chart(baseOpts);
          $scope.graphHeight = baseOpts.m.height;
        },
        redraw = function (clearing) { $scope.$broadcast(Evt.REDRAW, clearing); };

    $scope.baseOpts = baseOpts;
    this.winHeight = $win.height();

    var onResize = _.throttle(_.bind(function () {
      this.winHeight = $win.height();
      if(getWidth() !== baseOpts.width) {
        updateMetrics();
        redraw();
      }
      $scope.$applyAsync();
    }, this), 1000/30);
    $win.on('resize', onResize);
    $scope.$on('$destroy', function () { $win.off('resize', onResize); });
    $timeout(onResize, 100, false);

    $scope.$watch(function () { return GraphConfig.basesPerGraph; }, updateMetrics);
    $scope.$watchCollection(GraphConfig.activeTracks, function (val, old) {
      //Find headers and headerY
      baseOpts.tracks = val;
      updateMetrics();
      $scope.$broadcast('updateRowHeight', baseOpts.m.height);
      redraw({headers: true});
    });

    $scope.$on('printresize', function(event, printing) {
      if(printing) {
        $element.css({width: '7in'});
        onResize();
      }
      else {
        $element.css({width: 'auto'});
        onResize();
      }
    });

    $scope.$watch(function() { return GraphConfig.nucleotides; },
                  function() { redraw({nProfiles: true, headers: true}); },
                  true);
    $scope.$watch(function() { return GraphConfig.colorBlindFriendly; }, redraw);
  })

  .directive('npactGraphScroller', function ($log, $window, Evt) {
    'use strict';
    return {
      restrict: 'A',
      require: 'npactGraphContainer',
      link: function ($scope, $element, $attrs, npactGraphContainerCtrl) {
        var $win = angular.element($window),
        graphHeight = 0, graphRowHeight = null,
        slack = 20, // how many pixels outside of viewport to render
        topOffset = 0,
        topIdx = 0, bottomIdx = 0;

        var updateVisibility = function () {
          if(!graphRowHeight) return;
          slack = graphRowHeight / 4;
          var scrollDist = $window.scrollY - topOffset - slack;
          topIdx = Math.floor(scrollDist / graphRowHeight);
          bottomIdx = topIdx + Math.ceil(
            (npactGraphContainerCtrl.winHeight + slack) / graphRowHeight);
        };

        $scope.visible = function(idx) { return idx >= topIdx && idx <= bottomIdx; };

        var draw = _.throttle(function () {
          updateVisibility();
          $scope.$broadcast(Evt.DRAW);
        }, 1000/20);

        $scope.$on('updateRowHeight', function ($evt, height) {
          $log.debug("Updating graphHeight to", height);
          topOffset = $element.offset().top;
          topOffset += _.parseInt($element.css('padding-top'));
          topOffset = Math.floor(topOffset);

          // Keep the topIdx at the top through the height change
          var delta = Math.max(0, topIdx) * (height - graphHeight);
          if (delta) { $window.scrollBy(0, delta); }
          graphHeight = height;
          $scope.$evalAsync(function () {
            //This code won't work until after the `$scope.graphHeight`
            //above has a chance to take effect. Hence the async.
            try {
              // Find the height including the padding+border for
              // graphRowHeight visibility calculations
              graphRowHeight = angular.element('.graph', $element).outerHeight();
            }
            catch(e) {
              graphRowHeight = 0; // There are no rows
            }
            draw();
          });
        });

        $win.on('scroll', draw);
        $scope.$on('$destroy', function () { $win.off('scroll', draw); });
      }
    };
  })

  .directive('npactKeyHandlers', function($window, $log, GraphConfig) {
    'use strict';
    return {
      restrict: 'A',
      link: function ($scope, $element, $attrs) {
        var $win = angular.element($window),
        onKeyDown = _.throttle(function(event) {
          //Ignore keys while the user is typing in input controls
          if(event.target.nodeName == "INPUT") return;
          var keyCode = event.which, delta;
          switch(keyCode) {
          case 37: // left key
            delta = -GraphConfig.basesPerGraph / 100;
            GraphConfig.offset += delta;
            $scope.$broadcast('offset', delta);
            break;
          case 39: // right key
            delta = GraphConfig.basesPerGraph / 100;
            GraphConfig.offset += delta;
            $scope.$broadcast('offset', delta);
            break;
          }
        }, 40, {leading:true}),
        onKeyUp = _.debounce(function(event) {
          var keyCode = event.which;
          switch(keyCode) {
          case 37: // left key
          case 39: // right key
            $scope.$apply();
            break;
          }
        }, 800);
        $win.on('keydown', onKeyDown);
        $win.on('keyup', onKeyUp);
        $scope.$on('$destroy', function() {
          $win.off('keydown', onKeyDown);
          $win.off('keyup', onKeyUp);
        });
      }
    };
  })

  .directive('npactGraph', function (Grapher, Evt, GraphingCalculator, GraphConfig,
                              $log, $timeout, $window) {
    'use strict';
    return {
      restrict: 'A',
      scope: {
        startBase: '&',
        endBase: '&',
        visible: '&',
        graphOptions: '&'
      },
      link: function($scope, $element, $attrs) {
        var g = null, scheduledOn = null,
        startBase = $scope.startBase(),
        endBase = $scope.endBase(),
        visible = $scope.visible,
        id = $attrs.id,
        // redraw gets set for all graphs once (e.g. a new track
        // triggers broadcasts redraw), but only gets cleared as
        // the currently visible ones are drawn
        redraw = false,
        draw = function(force) {
          var t1 = scheduledOn;
          scheduledOn = null;
          if(!redraw || (!force && !visible())) { return null; }
          var opts = _.clone($scope.graphOptions());
          opts.startBase = startBase;
          opts.endBase = endBase;

          //However long it actually takes to draw, we have the
          //latest options as of this point
          redraw = false;
          return (g || (g = new Grapher($element, $scope, opts)))
            .draw(opts)
            .then(function () {
              $log.log("Finished draw at", opts.startBase, "in", new Date() - t1);
            })
            .catch(function() {
              //something went wrong, we will still need to redraw this
              redraw = true;
            });
        },
        schedule = function(force) {
          if(redraw && (force || (visible() && scheduledOn === null))) {
            scheduledOn = new Date();
            return $timeout(_.partial(draw, force), 0, false);
          }
          return null;
        },
        discard = function() { if(g) { g.destroy(); g = null; } },
        scrollToHere = function() {
          $log.log('scrolling to', $element);
          $window.scrollTo(0, $element.offset().top);
        };
        $scope.$on(Evt.DRAW, _.partial(schedule, false));
        $scope.$on(Evt.REDRAW, function(evt, cachesToClear) {
          redraw = true;
          if(g && cachesToClear) {
            if(cachesToClear.nProfiles) { g.clearProfilePoints(); }
            if(cachesToClear.headers) { g.clearLeftLayerCache(); }
          }
          schedule();
        });
        $scope.$on(Evt.REBUILD, function() {
          discard();
          startBase = $scope.startBase();
          endBase = $scope.endBase();
          redraw = true;
          schedule();
        });
        $scope.$on('offset', function(event, dx) {
          if(g && g.offset && visible()) { g.offset(dx); }
        });
        $scope.$on('$destroy', discard);

        $scope.$on('print', function(evt, callback) {
          var p = schedule(true);
          if(p) {
            callback(p.then(function() { return g.replaceWithImage(); }));
          }
          else { callback(g.replaceWithImage()); }
        });
        $scope.$watch(function() { return GraphConfig.gotoBase; }, function(gotoBase, fromBase) {
          if (_.isFinite(gotoBase) && startBase <= gotoBase && gotoBase <= endBase) {
            $log.log('gotoBase triggered redraw:', startBase, id);
            redraw = true;
            schedule();
            $timeout(scrollToHere, 0, false);
          }
          else if(_.isFinite(fromBase) && startBase <= fromBase && fromBase <= endBase) {
            redraw = true;
          }
        });
      }
    };
  })
;
<|endoftext|>


<commit_before>function loadSchemeKernelJS(after) {
    loadJSSeq([
        "jsscheme/object",
        "jsscheme/read",
        "jsscheme/print",
        "jsscheme/env",
        "jsscheme/error",
        "jsscheme/bool",
        "jsscheme/symbol",
        "jsscheme/number",
        "jsscheme/numcomp",
        "jsscheme/numarith",
        "jsscheme/numstr",
        "jsscheme/char",
        "jsscheme/string",
        "jsscheme/list",
        "jsscheme/vector",
        "jsscheme/fun",
        "jsscheme/syntax",
        "jsscheme/eval",
        "lib/browserjs",
        "lib/alib.scm"], after);

    function loadJSSeq(jsseq, after) {
        loadNextJS(0);
        function loadNextJS(index) {
            if(index > jsseq.length - 1) {
                after && after();
                return;
            }
            var s = document.createElement("script");
            s.src = "./" + jsseq[index] + ".js?v=" + new Date().getTime();
            s.onload = function() { loadNextJS(index + 1); }
            document.body.appendChild(s);
        }
    }
}
<commit_msg>update<commit_after>function loadSchemeKernelJS(after) {
    loadJSSeq([
        "jsscheme/object",
        "jsscheme/read",
        "jsscheme/print",
        "jsscheme/env",
        "jsscheme/error",
        "jsscheme/bool",
        "jsscheme/symbol",
        "jsscheme/number",
        "jsscheme/numcomp",
        "jsscheme/numarith",
        "jsscheme/numstr",
        "jsscheme/char",
        "jsscheme/string",
        "jsscheme/list",
        "jsscheme/vector",
        "jsscheme/fun",
        "jsscheme/syntax",
        "jsscheme/eval",
        "lib/browserjs",
        "lib/lib.scm"], after);

    function loadJSSeq(jsseq, after) {
        loadNextJS(0);
        function loadNextJS(index) {
            if(index > jsseq.length - 1) {
                after && after();
                return;
            }
            var s = document.createElement("script");
            s.src = "./" + jsseq[index] + ".js?v=" + new Date().getTime();
            s.onload = function() { loadNextJS(index + 1); }
            document.body.appendChild(s);
        }
    }
}
<|endoftext|>


<commit_before>var fuzzyMode = (function() {
  var fuzzyBox = null;  // the dialog instance for this window
  var completers = {};  // completer cache

  function createCompleter(name) {
    if (name === 'smart')
      return new completion.SmartCompleter({
        'wiki ': [ 'Wikipedia (en)', 'http://en.wikipedia.org/wiki/%s' ],
        'luck ': [ 'Google Lucky (en)', 'http://www.google.com/search?q=%s&btnI=I%27m+Feeling+Lucky' ],
        'cc '  : [ 'dict.cc',        'http://www.dict.cc/?s=%s' ],
        ';'    : [ 'goto',           '%s' ],
        '?'    : [ 'search',         function(query) { return utils.createSearchUrl(query) } ],
        });
    else if (name === 'history')
      return new completion.FuzzyHistoryCompleter(1500);
    else if (name === 'bookmarks')
      return new completion.FuzzyBookmarkCompleter();
    else if (name === 'tabs')
      return new completion.FuzzyTabCompleter();
    else if (name === 'tabsSorted')
      return new completion.MergingCompleter([getCompleter('tabs')], 0);
    else if (name === 'all')
      return new completion.MergingCompleter([
        getCompleter('smart'),
        getCompleter('bookmarks'),
        getCompleter('history'),
        getCompleter('tabs'),
        ], 1);
  }
  function getCompleter(name) {
    if (!(name in completers))
      completers[name] = createCompleter(name);
    return completers[name];
  }

  /** Trigger the fuzzy mode dialog */
  function start(name, reverseAction, refreshInterval) {
    var completer = getCompleter(name);
    if (!fuzzyBox)
      fuzzyBox = new FuzzyBox(10);
    completer.refresh();
    fuzzyBox.setCompleter(completer);
    fuzzyBox.setRefreshInterval(refreshInterval);
    fuzzyBox.show(reverseAction);
  }

  /** User interface for fuzzy completion */
  var FuzzyBox = function(maxResults) {
    this.prompt = '>';
    this.maxResults = maxResults;
    this.refreshInterval = 0;
    this.initDom();
  }
  FuzzyBox.prototype = {
    setCompleter: function(completer) {
      this.completer = completer;
      this.reset();
    },

    setRefreshInterval: function(refreshInterval) {
      this.refreshInterval = refreshInterval;
    },

    show: function(reverseAction) {
      this.reverseAction = reverseAction;
      this.box.style.display = 'block';
      var self = this;
      handlerStack.push({ keydown: function(event) { self.onKeydown(event); }});
    },

    hide: function() {
      this.box.style.display = 'none';
      handlerStack.pop();
    },

    reset: function() {
      this.query = '';
      // query used to filter the last completion result. We need this for asynchronous updating
      this.lastQuery = null;
      this.completions = [];
      this.selection = 0;
      // force synchronous updating so that the old results will not be flash up shortly
      this.update(true);
    },

    updateSelection: function() {
      this.selection = Math.min(this.selection, this.completions.length - 1)
      for (var i = 0; i < this.completionList.children.length; ++i)
        this.completionList.children[i].className = (i == this.selection) ? 'selected' : '';
    },

    onKeydown: function(event) {
      var keyChar = getKeyChar(event);

      if (isEscape(event)) {
        this.hide();
      }

      // move selection with Up/Down, Tab/Shift-Tab, Ctrl-k/Ctrl-j
      else if (keyChar === 'up' || (event.keyCode == 9 && event.shiftKey)
              || (keyChar === 'k' && event.ctrlKey)) {
        if (this.selection > 0)
          this.selection -= 1;
        this.updateSelection();
      }
      else if (keyChar === 'down' || (event.keyCode == 9 && !event.shiftKey)
              || (keyChar === 'j' && isPrimaryModifierKey(event))) {
        if (this.selection < this.completions.length - 1)
          this.selection += 1;
        this.updateSelection();
      }

      else if (event.keyCode == keyCodes.backspace) {
        if (this.query.length > 0) {
          this.query = this.query.substr(0, this.query.length-1);
          this.update();
        }
      }

      // refresh with F5
      else if (keyChar == 'f5') {
        this.completer.refresh();
        this.lastQuery = null;
        this.update();
      }

      // use primary action with Enter. Holding down Shift/Ctrl uses the alternative action
      // (opening in new tab)
      else if (event.keyCode == keyCodes.enter) {
        this.update(true); // force synchronous update

        var alternative = (event.shiftKey || isPrimaryModifierKey(event));
        if (this.reverseAction)
          alternative = !alternative;
        this.completions[this.selection].action[alternative ? 1 : 0]();
        this.hide();
        this.reset();
      }

      else if (keyChar.length == 1) {
        this.query += keyChar;
        this.update();
      }

      event.stopPropagation();
      event.preventDefault();
      return true;
    },

    updateCompletions: function() {
      var self = this;
      this.completer.filter(this.query, function(completions) {
        self.completions = completions.slice(0, self.maxResults);

        // clear completions
        self.completionList.innerHTML = self.completions.map(function(completion) {
          return '
' + completion.render() + '
';
        }).join('');

        self.completionList.style.display = self.completions.length > 0 ? 'block' : 'none';
        self.updateSelection();
      });
    },

    update: function(sync) {
      sync = sync || false; // explicitely default to asynchronous updating

      this.query = this.query.replace(/^\s*/, '');
      this.input.textContent = this.query;

      if (sync) {
        this.updateCompletions();
      } else {
        var self = this;
        // always update asynchronously for better user experience and to take some load off the CPU
        // (not every keystroke will cause a dedicated update)
        setTimeout(function() {
          if (self.query === self.lastQuery)
            return;
          self.lastQuery = self.query;
          self.updateCompletions();
        }, this.refreshInterval);
      }
    },

    initDom: function() {
      this.box = utils.createElementFromHtml(
        '
'+
          '
'+
            '' + utils.escapeHtml(this.prompt) + ' '+
            '
'+
          '

');
      this.box.style.display = 'none';
      document.body.appendChild(this.box);

      this.input          = document.querySelector("#fuzzybox .query");
      this.completionList = document.querySelector("#fuzzybox ul");
    },
  }

  // public interface
  return {
    activateAll:       function() { start('all',        false, 300); },
    activateAllNewTab: function() { start('all',        true,  300);  },
    activateTabs:      function() { start('tabsSorted', false, 0); },
  }

})();
<commit_msg>fix small bug with selected item<commit_after>var fuzzyMode = (function() {
  var fuzzyBox = null;  // the dialog instance for this window
  var completers = {};  // completer cache

  function createCompleter(name) {
    if (name === 'smart')
      return new completion.SmartCompleter({
        'wiki ': [ 'Wikipedia (en)', 'http://en.wikipedia.org/wiki/%s' ],
        'luck ': [ 'Google Lucky (en)', 'http://www.google.com/search?q=%s&btnI=I%27m+Feeling+Lucky' ],
        'cc '  : [ 'dict.cc',        'http://www.dict.cc/?s=%s' ],
        ';'    : [ 'goto',           '%s' ],
        '?'    : [ 'search',         function(query) { return utils.createSearchUrl(query) } ],
        });
    else if (name === 'history')
      return new completion.FuzzyHistoryCompleter(1500);
    else if (name === 'bookmarks')
      return new completion.FuzzyBookmarkCompleter();
    else if (name === 'tabs')
      return new completion.FuzzyTabCompleter();
    else if (name === 'tabsSorted')
      return new completion.MergingCompleter([getCompleter('tabs')], 0);
    else if (name === 'all')
      return new completion.MergingCompleter([
        getCompleter('smart'),
        getCompleter('bookmarks'),
        getCompleter('history'),
        getCompleter('tabs'),
        ], 1);
  }
  function getCompleter(name) {
    if (!(name in completers))
      completers[name] = createCompleter(name);
    return completers[name];
  }

  /** Trigger the fuzzy mode dialog */
  function start(name, reverseAction, refreshInterval) {
    var completer = getCompleter(name);
    if (!fuzzyBox)
      fuzzyBox = new FuzzyBox(10);
    completer.refresh();
    fuzzyBox.setCompleter(completer);
    fuzzyBox.setRefreshInterval(refreshInterval);
    fuzzyBox.show(reverseAction);
  }

  /** User interface for fuzzy completion */
  var FuzzyBox = function(maxResults) {
    this.prompt = '>';
    this.maxResults = maxResults;
    this.refreshInterval = 0;
    this.initDom();
  }
  FuzzyBox.prototype = {
    setCompleter: function(completer) {
      this.completer = completer;
      this.reset();
    },

    setRefreshInterval: function(refreshInterval) {
      this.refreshInterval = refreshInterval;
    },

    show: function(reverseAction) {
      this.reverseAction = reverseAction;
      this.box.style.display = 'block';
      var self = this;
      handlerStack.push({ keydown: function(event) { self.onKeydown(event); }});
    },

    hide: function() {
      this.box.style.display = 'none';
      handlerStack.pop();
    },

    reset: function() {
      this.query = '';
      // query used to filter the last completion result. We need this for asynchronous updating
      this.lastQuery = null;
      this.completions = [];
      this.selection = 0;
      // force synchronous updating so that the old results will not be flash up shortly
      this.update(true);
    },

    updateSelection: function() {
      if (this.completions.length > 0)
        this.selection = Math.min(this.selection, this.completions.length - 1);
      for (var i = 0; i < this.completionList.children.length; ++i)
        this.completionList.children[i].className = (i == this.selection) ? 'selected' : '';
    },

    onKeydown: function(event) {
      var keyChar = getKeyChar(event);

      if (isEscape(event)) {
        this.hide();
      }

      // move selection with Up/Down, Tab/Shift-Tab, Ctrl-k/Ctrl-j
      else if (keyChar === 'up' || (event.keyCode == 9 && event.shiftKey)
              || (keyChar === 'k' && event.ctrlKey)) {
        if (this.selection > 0)
          this.selection -= 1;
        this.updateSelection();
      }
      else if (keyChar === 'down' || (event.keyCode == 9 && !event.shiftKey)
              || (keyChar === 'j' && isPrimaryModifierKey(event))) {
        if (this.selection < this.completions.length - 1)
          this.selection += 1;
        this.updateSelection();
      }

      else if (event.keyCode == keyCodes.backspace) {
        if (this.query.length > 0) {
          this.query = this.query.substr(0, this.query.length-1);
          this.update();
        }
      }

      // refresh with F5
      else if (keyChar == 'f5') {
        this.completer.refresh();
        this.lastQuery = null;
        this.update();
      }

      // use primary action with Enter. Holding down Shift/Ctrl uses the alternative action
      // (opening in new tab)
      else if (event.keyCode == keyCodes.enter) {
        this.update(true); // force synchronous update

        var alternative = (event.shiftKey || isPrimaryModifierKey(event));
        if (this.reverseAction)
          alternative = !alternative;
        this.completions[this.selection].action[alternative ? 1 : 0]();
        this.hide();
        this.reset();
      }

      else if (keyChar.length == 1) {
        this.query += keyChar;
        this.update();
      }

      event.stopPropagation();
      event.preventDefault();
      return true;
    },

    updateCompletions: function() {
      var self = this;
      this.completer.filter(this.query, function(completions) {
        self.completions = completions.slice(0, self.maxResults);

        // clear completions
        self.completionList.innerHTML = self.completions.map(function(completion) {
          return '
' + completion.render() + '
';
        }).join('');

        self.completionList.style.display = self.completions.length > 0 ? 'block' : 'none';
        self.updateSelection();
      });
    },

    update: function(sync) {
      sync = sync || false; // explicitely default to asynchronous updating

      this.query = this.query.replace(/^\s*/, '');
      this.input.textContent = this.query;

      if (sync) {
        this.updateCompletions();
      } else {
        var self = this;
        // always update asynchronously for better user experience and to take some load off the CPU
        // (not every keystroke will cause a dedicated update)
        setTimeout(function() {
          if (self.query === self.lastQuery)
            return;
          self.lastQuery = self.query;
          self.updateCompletions();
        }, this.refreshInterval);
      }
    },

    initDom: function() {
      this.box = utils.createElementFromHtml(
        '
'+
          '
'+
            '' + utils.escapeHtml(this.prompt) + ' '+
            '
'+
          '

');
      this.box.style.display = 'none';
      document.body.appendChild(this.box);

      this.input          = document.querySelector("#fuzzybox .query");
      this.completionList = document.querySelector("#fuzzybox ul");
    },
  }

  // public interface
  return {
    activateAll:       function() { start('all',        false, 300); },
    activateAllNewTab: function() { start('all',        true,  300);  },
    activateTabs:      function() { start('tabsSorted', false, 0); },
  }

})();
<|endoftext|>


<commit_before>import React from "react"

class Footer extends React.Component {
  render () {
    return (

                   Twitter

                 ·

                   Facebook

                 ·

                   GitHub

            Notebook.ai © 2016-2022
              Indent Labs, LLC

    );
  }
}

export default Footer;
<commit_msg>add discord link to footer<commit_after>import React from "react"

class Footer extends React.Component {
  render () {
    return (

                   Twitter

                 ·

                   Facebook

                 ·

                   GitHub

                 ·

                   Discord

            Notebook.ai © 2016-2022
              Indent Labs, LLC

    );
  }
}

export default Footer;
<|endoftext|>


<commit_before>// This file is automatically compiled by Webpack, along with any other files
// present in this directory. You're encouraged to place your actual application logic in
// a relevant structure within app/javascript and only use these pack files to reference
// that code so it'll be compiled.

import * as Sentry from "@sentry/browser";

Sentry.init({
  dsn: "https://185a236f4b994411a9f33c3c714cb34e@sentry.io/1424888",
});

import Rails from "@rails/ujs";
import Turbolinks from "turbolinks";
import LocalTime from "local-time";
import { install } from "@github/hotkey";
import "channels";

Rails.start();
Turbolinks.start();
LocalTime.start();

import "bootstrap/js/src/dropdown";
import "bootstrap/js/src/collapse";
import "bootstrap/js/src/tooltip";
import "bootstrap/js/src/modal";

import "../stylesheets/application";

// import ApexCharts from "apexcharts";

// window.ApexCharts = ApexCharts;
window.$ = $;

// Uncomment to copy all static images under ../images to the output folder and reference
// them with the image_pack_tag helper in views (e.g <%= image_pack_tag 'rails.png' %>)
// or the `imagePath` JavaScript helper below.
//
// const images = require.context('../images', true)
// const imagePath = (name) => images(name, true)

document.addEventListener("turbolinks:load", () => {
  $('[data-toggle="tooltip"]').tooltip();

  // Install all the hotkeys on the page
  for (const el of document.querySelectorAll("[data-hotkey]")) {
    install(el);
  }
});

// import "controllers";
<commit_msg>Migrate to turbo<commit_after>// This file is automatically compiled by Webpack, along with any other files
// present in this directory. You're encouraged to place your actual application logic in
// a relevant structure within app/javascript and only use these pack files to reference
// that code so it'll be compiled.

import * as Sentry from "@sentry/browser";

Sentry.init({
  dsn: "https://185a236f4b994411a9f33c3c714cb34e@sentry.io/1424888",
});

import Rails from "@rails/ujs";
import Turbo from "@hotwired/turbo"
import LocalTime from "local-time";
import { install } from "@github/hotkey";
import "channels";

Rails.start();
LocalTime.start();

import "bootstrap/js/src/dropdown";
import "bootstrap/js/src/collapse";
import "bootstrap/js/src/tooltip";
import "bootstrap/js/src/modal";

import "../stylesheets/application";

// import ApexCharts from "apexcharts";

// window.ApexCharts = ApexCharts;
window.$ = $;

// Uncomment to copy all static images under ../images to the output folder and reference
// them with the image_pack_tag helper in views (e.g <%= image_pack_tag 'rails.png' %>)
// or the `imagePath` JavaScript helper below.
//
// const images = require.context('../images', true)
// const imagePath = (name) => images(name, true)

document.addEventListener("turbo:load", () => {
  $('[data-toggle="tooltip"]').tooltip();

  // Install all the hotkeys on the page
  for (const el of document.querySelectorAll("[data-hotkey]")) {
    install(el);
  }
});

// import "controllers";
<|endoftext|>


<commit_before>/*
 * Controller :: my_controller1.js
 * Info : The entry point of the project.
 */
define(function () {
	'use strict';

  return ['$scope', 'LocaleService', 'Config1Service', '$firebase', function ($scope, LocaleService, Config1Service, $firebase) {

  	$scope.locale = Config1Service.getLocale(Config1Service.getLang());

    console.dir(Config1Service.firebase.url);

  	$scope.lang = Config1Service.getLang();

  	$scope.setStringMessagesIntoCurrentLocale = function () {
  		$scope.MSG_HELLO = $scope.locale['MSG_HELLO'];
  		$scope.MSG_HOW_ARE_YOU = $scope.locale['MSG_HOW_ARE_YOU'];
  		$scope.MSG_THANK_YOU = $scope.locale['MSG_THANK_YOU'];
  		$scope.MSG_CONTENT = $scope.locale['MSG_CONTENT'];
  	}

  	$scope.changeLocale = function (lang) {
  		$scope.setLang(lang);
  		$scope.locale = Config1Service.getLocale(lang);
  		$scope.setStringMessagesIntoCurrentLocale();
  	}

  	$scope.setLang = function(lang) {
  		Config1Service.setLang(lang);
  		$scope.lang = lang;
  	}

  	$scope.setStringMessagesIntoCurrentLocale();

    var ref = new Firebase(Config1Service.firebase.url);

    var sync = $firebase(ref);

    $scope.data = sync.$asObject();

    console.log($scope.data);

  }];

});
<commit_msg>Changed the invoking object properties for locales as dot notation<commit_after>/*
 * Controller :: my_controller1.js
 * Info : The entry point of the project.
 */
define(function () {
	'use strict';

  return ['$scope', 'LocaleService', 'Config1Service', '$firebase', function ($scope, LocaleService, Config1Service, $firebase) {

  	$scope.locale = Config1Service.getLocale(Config1Service.getLang());

    console.dir(Config1Service.firebase.url);

  	$scope.lang = Config1Service.getLang();

  	$scope.setStringMessagesIntoCurrentLocale = function () {
  		$scope.MSG_HELLO = $scope.locale.MSG_HELLO;
  		$scope.MSG_HOW_ARE_YOU = $scope.locale.MSG_HOW_ARE_YOU;
  		$scope.MSG_THANK_YOU = $scope.locale.MSG_THANK_YOU;
  		$scope.MSG_CONTENT = $scope.locale.MSG_CONTENT;
  	}

  	$scope.changeLocale = function (lang) {
  		$scope.setLang(lang);
  		$scope.locale = Config1Service.getLocale(lang);
  		$scope.setStringMessagesIntoCurrentLocale();
  	}

  	$scope.setLang = function(lang) {
  		Config1Service.setLang(lang);
  		$scope.lang = lang;
  	}

  	$scope.setStringMessagesIntoCurrentLocale();

    var ref = new Firebase(Config1Service.firebase.url);

    var sync = $firebase(ref);

    $scope.data = sync.$asObject();

    console.log($scope.data);

  }];

});
<|endoftext|>


<commit_before>'use strict';
/**
 * AvailableClassesService
 * A Service, which gets the available SPARQL classes from the Server.
 *
 * @namespace data.results.bindings
 *
 */

angular.module('GSB.services.availableClasses', ['GSB.config'])
  .factory('AvailableClassesService', ['$http', '$log', 'globalConfig', function ($http, $log, globalConfig) {
    var factory = {};

    /**
     * Writes available SPARQL-Classes into a given array.
     *
     * @param asc the array into which the availableClasses will be written
     */
    factory.getAvailableClasses = function (asc) {

      // Get Available Subject Classes from Server

      $http.get(globalConfig.baseURL + 'mockup/classes.json')
        .success(function (data) {

          $log.info('Available Classes loaded from server.');

          var availClasses = data.results.bindings;

          for(var key in availClasses) {
            if (availClasses.hasOwnProperty(key)) {
              asc.push(
                {
                  alias: availClasses[key].alias.value,
                  uri: availClasses[key].class.value,
                  comment: availClasses[key].comment ? availClasses[key].comment.value : 'No description available.'
                }
              );
            }
          }
        })
        .error(function () {
          $log.error('Available Classes could not be loaded from server.');
        });
    };

    return factory;

  }])
  .factory('AvailablePropertiesService', ['$http', '$log', 'globalConfig', function ($http, $log, globalConfig) {
    var factory = {};

    var createAvailablePropertyObject = function(data) {
      var ret = {};
      for(var key in data) {
        if(data.hasOwnProperty(key)){
          var property = data[key];
          var propertyURI = property.propertyURI.value,
          propertyRange = property.propertyRange.value,
          isObjectProperty = (isObjProp(propertyRange));
          if(ret.hasOwnProperty(propertyURI)){
            ret[propertyURI].propertyRange.push(propertyRange);
          } else {
            ret[propertyURI] = {
              alias: property.propertyAlias.value,
              uri: propertyURI,
              type: isObjectProperty ? 'OBJECT_PROPERTY' : 'DATATYPE_PROPERTY',
              isObjectProperty: isObjectProperty,
              propertyRange: [propertyRange],
              view: true,
              operator: "MUST", //Vorprojekt okay
              link : {direction: "TO", linkPartner: null}, //Vorprojekt okay
              arithmetic : {} , //Vorprojekt leave empty
              compare : {} //Vorprojekt leave empty
            };
          }
        }
      }
      return ret;
    }

    /**
     * Returns whether an property is an objectProperty
     * @param propertyRange
     * @returns {boolean}
     */
    var isObjProp = function (propertyRange) {
      var dataTypeURIs = globalConfig['dataTypeURIs'];
      for(var key in dataTypeURIs){
        if(dataTypeURIs.hasOwnProperty(key) && propertyRange.startsWith(dataTypeURIs[key])){
          return false;
        }
      }
      return true;
    };

    /**
     * Returns properties of a SPARQL-Class given by the classes uri.
     * In other words: the properties have the given class as their 'propertyDomain'.
     *
     * @param uri the uri identifiying the SPARQL-Class.
     */
    factory.getProperties = function (uri) {
      $log.info('Lade die Properties von ' + uri);

      //Retrieve Properties from Server and add them to availableProperties
      return $http.get(globalConfig.baseURL + uri)
        .then(function(response) {
          $log.info('Response: ', response);
          var availableProperties = createAvailablePropertyObject(response.data.results.bindings);
          $log.info(' Properties loaded from: ' + uri, response);

          $log.info('getaP', availableProperties);
          return availableProperties;

        }, function(response) {
          $log.error('Error loading properties from: ' + uri)
        });

    };

    return factory;

  }]);
<commit_msg>Made a promise.<commit_after>'use strict';
/**
 * AvailableClassesService
 * A Service, which gets the available SPARQL classes from the Server.
 *
 * @namespace data.results.bindings
 *
 */

angular.module('GSB.services.availableClasses', ['GSB.config'])
  .factory('AvailableClassesService', ['$http', '$log', 'globalConfig', function ($http, $log, globalConfig) {
    var factory = {};

    /**
     * Writes available SPARQL-Classes into a given array.
     *
     * @param asc the array into which the availableClasses will be written
     */
    factory.getAvailableClasses = function (asc) {

      // Get Available Subject Classes from Server

      return $http.get(globalConfig.baseURL + 'mockup/classes.json')
        .then(function (response) {

          $log.info('Available Classes loaded from server.');

          var availClasses = response.data.results.bindings;

          for(var key in availClasses) {
            if (availClasses.hasOwnProperty(key)) {
              asc.push(
                {
                  alias: availClasses[key].alias.value,
                  uri: availClasses[key].class.value,
                  comment: availClasses[key].comment ? availClasses[key].comment.value : 'No description available.'
                }
              );
            }
          }

        }, function(error) {
          $log.error(error, 'Available Classes could not be loaded from server.');
        });
    };

    return factory;

  }])
  .factory('AvailablePropertiesService', ['$http', '$log', 'globalConfig', function ($http, $log, globalConfig) {
    var factory = {};

    var createAvailablePropertyObject = function(data) {
      var ret = {};
      for(var key in data) {
        if(data.hasOwnProperty(key)){
          var property = data[key];
          var propertyURI = property.propertyURI.value,
          propertyRange = property.propertyRange.value,
          isObjectProperty = (isObjProp(propertyRange));
          if(ret.hasOwnProperty(propertyURI)){
            ret[propertyURI].propertyRange.push(propertyRange);
          } else {
            ret[propertyURI] = {
              alias: property.propertyAlias.value,
              uri: propertyURI,
              type: isObjectProperty ? 'OBJECT_PROPERTY' : 'DATATYPE_PROPERTY',
              isObjectProperty: isObjectProperty,
              propertyRange: [propertyRange],
              view: true,
              operator: "MUST", //Vorprojekt okay
              link : {direction: "TO", linkPartner: null}, //Vorprojekt okay
              arithmetic : {} , //Vorprojekt leave empty
              compare : {} //Vorprojekt leave empty
            };
          }
        }
      }
      return ret;
    }

    /**
     * Returns whether an property is an objectProperty
     * @param propertyRange
     * @returns {boolean}
     */
    var isObjProp = function (propertyRange) {
      var dataTypeURIs = globalConfig['dataTypeURIs'];
      for(var key in dataTypeURIs){
        if(dataTypeURIs.hasOwnProperty(key) && propertyRange.startsWith(dataTypeURIs[key])){
          return false;
        }
      }
      return true;
    };

    /**
     * Returns properties of a SPARQL-Class given by the classes uri.
     * In other words: the properties have the given class as their 'propertyDomain'.
     *
     * @param uri the uri identifiying the SPARQL-Class.
     */
    factory.getProperties = function (uri) {
      $log.info('Lade die Properties von ' + uri);

      //Retrieve Properties from Server and add them to availableProperties
      return $http.get(globalConfig.baseURL + uri)
        .then(function(response) {
          var availableProperties = createAvailablePropertyObject(response.data.results.bindings);
          $log.info(' Properties loaded from: ' + uri, response);

          return availableProperties;

        }, function(response) {
          $log.error('Error loading properties from: ' + uri)
        });

    };

    return factory;

  }]);
<|endoftext|>


<commit_before>'use strict';

angular.module('ddsCommon').factory('RessourceService', function($http, MonthService, categoriesRnc, ressourceTypes) {

    function getPeriodKeysForCurrentYear(dateDeValeur, ressourceType) {
        var periodKeys = [];
        var lastYear = moment(dateDeValeur).subtract(1, 'years').format('YYYY');
        if (ressourceType.isMontantAnnuel)
        {
            periodKeys.push(lastYear);
            return periodKeys;
        }
        if (ressourceType.id == 'tns_auto_entrepreneur_chiffre_affaires')
        {
            periodKeys.push(lastYear);
            periodKeys = periodKeys.concat(_.map(MonthService.getMonths(dateDeValeur, 3), 'id'));
        } else {
            periodKeys = periodKeys.concat(_.map(MonthService.getMonths(dateDeValeur, 12), 'id'));
        }

        if (! ressourceType.revenuExceptionnel) {
            periodKeys.push(moment(dateDeValeur).format('YYYY-MM'));
        }

        return periodKeys;
    }

    function setDefaultValueForCurrentYear(dateDeValeur, individu, ressourceType) {
        var ressourceId = ressourceType.id;
        individu[ressourceId] = individu[ressourceId] || {};
        var ressource = individu[ressourceId];
        var periodKeys = getPeriodKeysForCurrentYear(dateDeValeur, ressourceType);

        if (_.some(periodKeys, function(periodKey) { return _.isNumber(ressource[periodKey]); })) {
            return;
        }

        periodKeys.forEach(function(periodKey) {
            ressource[periodKey] = ressource[periodKey] || 0;
        });
    }

    function unsetForCurrentYear(dateDeValeur, entity, ressourceType) {
        var ressourceId = ressourceType.id;
        entity[ressourceId] = entity[ressourceId] || {};
        var ressource = entity[ressourceId];
        var periodKeys = getPeriodKeysForCurrentYear(dateDeValeur, ressourceType);
        periodKeys.forEach(function(periodKey) {
            delete ressource[periodKey];
        });

        if (_.isEmpty(ressource)) {
            delete entity[ressourceId];
        }
    }

    function isSelectedForCurrentYear(ressource, ressourceIdOrType) {
        // pensions_alimentaires_percues is a YM2 and current year ressource
        // Hence that special treatment:
        // A single value means that a YM2 value has been specified
        // Multiple values means that CY values were specified
        if ((ressourceIdOrType.id || ressourceIdOrType) == 'pensions_alimentaires_percues') {
            return _.keys(ressource).length > 1;
        }

        return Boolean(ressource);
    }

    function extractIndividuSelectedRessourceTypes(individu) {
        var result = {};
        _.chain(ressourceTypes)
            .filter(isRessourceOnMainScreen)
            .filter(function(ressourceType) { return isSelectedForCurrentYear(individu[ressourceType.id], ressourceType); })
            .forEach(function(ressourceType) { result[ressourceType.id] = true; })
            .value();

        return result;
    }

    function isRessourceOnMainScreen(ressourceOrType) {
        // Make this function robust so that it can be called with a type from the ressourceTypes constant, or just a string.
        var type = ressourceOrType.id || ressourceOrType;
        return type != 'pensions_alimentaires_versees_individu';
    }

    function getParameterFromOpenfisca(parameterId) {
        return $http.get('/api/parameters/' + parameterId)
            .then(function(resp) {
                var values = resp.data.values;
                var sortedByDates = Object.keys(values).sort();
                var latestValue = values[sortedByDates.pop()];
                return latestValue;
            });
    }

    return {
        getPeriodKeysForCurrentYear: getPeriodKeysForCurrentYear,
        isRessourceOnMainScreen: isRessourceOnMainScreen,
        isSelectedForCurrentYear: isSelectedForCurrentYear,
        extractIndividuSelectedRessourceTypes: extractIndividuSelectedRessourceTypes,
        setDefaultValueForCurrentYear: setDefaultValueForCurrentYear,
        unsetForCurrentYear: unsetForCurrentYear,
        getParameterFromOpenfisca: getParameterFromOpenfisca
    };
});
<commit_msg>Améliore la gestion des ressources fiscales et netttes<commit_after>'use strict';

angular.module('ddsCommon').factory('RessourceService', function($http, MonthService, categoriesRnc, ressourceTypes) {

    function getPeriodKeysForCurrentYear(dateDeValeur, ressourceType) {
        var periodKeys = [];
        var lastYear = moment(dateDeValeur).subtract(1, 'years').format('YYYY');
        if (ressourceType.isMontantAnnuel)
        {
            periodKeys.push(lastYear);
            return periodKeys;
        }
        if (ressourceType.id == 'tns_auto_entrepreneur_chiffre_affaires')
        {
            periodKeys.push(lastYear);
            periodKeys = periodKeys.concat(_.map(MonthService.getMonths(dateDeValeur, 3), 'id'));
        } else {
            periodKeys = periodKeys.concat(_.map(MonthService.getMonths(dateDeValeur, 12), 'id'));
        }

        if (! ressourceType.revenuExceptionnel) {
            periodKeys.push(moment(dateDeValeur).format('YYYY-MM'));
        }

        return periodKeys;
    }

    function setDefaultValueForCurrentYear(dateDeValeur, individu, ressourceType) {
        var ressourceId = ressourceType.id;
        individu[ressourceId] = individu[ressourceId] || {};
        var ressource = individu[ressourceId];
        var periodKeys = getPeriodKeysForCurrentYear(dateDeValeur, ressourceType);

        if (_.some(periodKeys, function(periodKey) { return _.isNumber(ressource[periodKey]); })) {
            return;
        }

        periodKeys.forEach(function(periodKey) {
            ressource[periodKey] = ressource[periodKey] || 0;
        });
    }

    function unsetForCurrentYear(dateDeValeur, entity, ressourceType) {
        var ressourceId = ressourceType.id;
        entity[ressourceId] = entity[ressourceId] || {};
        var ressource = entity[ressourceId];
        var periodKeys = getPeriodKeysForCurrentYear(dateDeValeur, ressourceType);
        periodKeys.forEach(function(periodKey) {
            delete ressource[periodKey];
        });

        if (_.isEmpty(ressource)) {
            delete entity[ressourceId];
        }
    }

    var ressourcesForTrailingMonthsAndFiscalYear = categoriesRnc.filter(function(fiscalRessource) {
        return fiscalRessource.sources && fiscalRessource.sources.indexOf(fiscalRessource.id) >= 0;
    }).map(function(fiscalRessource) { return fiscalRessource.id; });

    function isSelectedForCurrentYear(ressource, ressourceIdOrType) {
        // A single value means that ONLY a YM2 value has been specified
        // Multiple values means that CY values were specified
        if (ressourcesForTrailingMonthsAndFiscalYear.indexOf(ressourceIdOrType.id || ressourceIdOrType) >= 0) {
            return _.keys(ressource).length > 1;
        }

        return Boolean(ressource);
    }

    function extractIndividuSelectedRessourceTypes(individu) {
        var result = {};
        _.chain(ressourceTypes)
            .filter(isRessourceOnMainScreen)
            .filter(function(ressourceType) { return isSelectedForCurrentYear(individu[ressourceType.id], ressourceType); })
            .forEach(function(ressourceType) { result[ressourceType.id] = true; })
            .value();

        return result;
    }

    function isRessourceOnMainScreen(ressourceOrType) {
        // Make this function robust so that it can be called with a type from the ressourceTypes constant, or just a string.
        var type = ressourceOrType.id || ressourceOrType;
        return type != 'pensions_alimentaires_versees_individu';
    }

    function getParameterFromOpenfisca(parameterId) {
        return $http.get('/api/parameters/' + parameterId)
            .then(function(resp) {
                var values = resp.data.values;
                var sortedByDates = Object.keys(values).sort();
                var latestValue = values[sortedByDates.pop()];
                return latestValue;
            });
    }

    return {
        getPeriodKeysForCurrentYear: getPeriodKeysForCurrentYear,
        isRessourceOnMainScreen: isRessourceOnMainScreen,
        isSelectedForCurrentYear: isSelectedForCurrentYear,
        extractIndividuSelectedRessourceTypes: extractIndividuSelectedRessourceTypes,
        setDefaultValueForCurrentYear: setDefaultValueForCurrentYear,
        unsetForCurrentYear: unsetForCurrentYear,
        getParameterFromOpenfisca: getParameterFromOpenfisca
    };
});
<|endoftext|>