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

  Function.prototype.method = function (name, func) {
    this.prototype[name] = func;
    return this;
  };

  Function.method('curry', function () {
    var slice = Array.prototype.slice,
        args = slice.apply(arguments),
        that = this;

    return function () {
      return that.apply(null, args.concat(slice.apply(arguments)));
    };
  });

  /**
   * @ngdoc directive
   * @name multiselectApp.directive:multiSelect
   * @description
   * # Angular Multi Select directive
   */
  ng.module('shalotelli-angular-multiselect', [])
    .provider('multiSelectConfig', function MultiSelectConfig () {
      var defaults = {
        templatePath: 'bower_components/shalotelli-angular-multiselect/views/directives/multi-select.html',
        otherField: 'isOther',
        otherNgModel: 'other',
        closeOnSelect: false
      };

      /**
       * Set defaults
       * @param {Object} settings Settings object
       */
      this.setDefaults = function (settings) {
        angular.extend(defaults, settings || {});
      };

      this.$get = [ function () {
        return defaults;
      }];
    })
    .directive('multiSelect', [ 'multiSelectConfig', '$timeout', '$log',  function (multiSelectConfig, $timeout, $log) {
      return {
        templateUrl: function (element, attrs) {
          if (attrs.templatePath !== undefined) {
            return attrs.templatePath;
          }

          return multiSelectConfig.templatePath;
        },

        restrict: 'E',
        replace: true,

        scope: {
          values: '=',
          model: '=',
          name: '@',
          showFilters: '@',
          showOther: '@',
          isSelected: '&',
          otherNgModel: '@',
          otherField: '@',
          otherEvent: '@',
          valueField: '@',
          labelField: '@',
          templatePath: '@',
          closeOnSelect: '@'
        },

        link: function multiSelectLink (scope, element, attrs) {
          // dropdown element
          var $dropdown = element.find('.multi-select-dropdown'),

             /**
              * Display options in textbox
              * @return {String} Display string
              */
              displayOptions = function displayOptions () {
                var broadcastkey = 'multiSelectUpdate',
                    label = '';

                if (scope.model.length === 1) {
                  label = scope.model[0][scope.labelField];
                } else if (scope.areAllSelected()) {
                  label = 'All Selected';
                } else if (scope.model.length > 1) {
                  label = scope.model.length + ' Selected';
                } else {
                  label = 'None Selected';
                }

                if (attrs.name !== undefined) {
                  broadcastkey += '_' + attrs.name;
                }

                // emit data
                scope.$emit(broadcastkey, label);

                return label;
              };

          scope.displayOptions = displayOptions;

          var watch = scope.$watch('model', function (newVal, oldVal) {
            if (ng.isDefined(newVal)) {
              if (newVal.length) {
                // if we have something display
                // first time intiialized go ahead an sync other
                var other = findOther();
                if (other) {
                  scope.shared.other = other[scope.otherNgModel] || '';
                }
              }

              // kill watch
              watch();
            }
          });

          // show filters default value
          attrs.$observe('showFilters', function (showFilters) {
            scope.showFilters = showFilters || true;
          });

          // show other default value
          attrs.$observe('showOther', function (showOther) {
            scope.showOther = showOther || false;
          });

          // other box event binding
          attrs.$observe('otherEvent', function (otherEvent) {
            if (otherEvent === undefined || ! otherEvent.match(/blur|keyup|enter/)) {
              otherEvent = 'keyup';
            }

            switch (otherEvent.toLowerCase()) {
              case 'blur':
              case 'keyup':
                ng.element('.multi-select-other').on(otherEvent, function () {
                  displayOptions();
                });
                break;

              case 'enter':
                ng.element('.multi-select-other').on('keydown keypress', function (e) {
                  if (e.which === 13) {
                    e.preventDefault();
                    displayOptions();
                  }
                });
                break;

              default:
                break;
            }
          });

          // value field default value
          attrs.$observe('valueField', function (valueField) {
            scope.valueField = valueField || 'value';
          });

          attrs.$observe('otherField', function (otherField) {
            scope.otherField = otherField || multiSelectConfig.otherField;
          });

          attrs.$observe('closeOnSelect', function (closeOnSelect) {
            scope.closeOnSelect = (closeOnSelect === 'true') || multiSelectConfig.closeOnSelect;
          });

          /**
           * Is item the Other field
           * @param  {Object}  item Item object
           * @return {Boolean}      Is other
           */
          function isOther (item) {
            return item[scope.otherField] === true;
          }

          scope.isOther = isOther;

          // label field default value
          attrs.$observe('otherNgModel', function (otherNgModel) {
            scope.otherNgModel = otherNgModel || multiSelectConfig.otherNgModel;
          });

          // label field default value
          attrs.$observe('labelField', function (labelField) {
            scope.labelField = labelField || 'label';
          });

          // hide dropdown when clicking away
          ng.element(document).on('click', function (e) {
            if (e.target.className.indexOf('multi-select') === -1) {
              $dropdown.removeClass('show').addClass('hide');
            }
          });

          /**
           * Close dropdown when user presses Enter key
           * @param  {Object} $event Event
           */
          scope.close = function ($event) {
            //this should be migrated to use angualar
            if ($event.which === 13) {
              $event.preventDefault();
              $dropdown.removeClass('show').addClass('hide');
            }
          };

          /**
           * Show/hide dropdown
           */
          scope.toggleDropdown = function toggleDropdown () {
            if ($dropdown.hasClass('hide')) {
              // close all other dropdowns on the page before showing the selected one
              ng.element('body').find('.multi-select-dropdown').removeClass('show').addClass('hide');
              $dropdown.removeClass('hide').addClass('show');
            } else {
              $dropdown.removeClass('show').addClass('hide');
            }
          };

          /**
           * Select/Deselect all options
           */
          scope.selectAll = function selectAll () {
            var areAllSelected = scope.areAllSelected();

            //clear all first
            scope.model.length = 0;

            if (! areAllSelected) {
              ng.forEach(scope.values, function (item) {
                if (isOther(item)) {
                  return;
                }

                scope.selectOption(item);
              });
            } else {
              scope.allSelected = scope.areAllSelected();
              clearOther();
            }
          };

          /**
           * Click select all checkbox
           * @param  {Object} $event Event
           */
          scope.clickSelectAllCheckbox = function clickSelectAllCheckbox ($event) {
            $event.stopPropagation();
            scope.selectAll();
          };

          /**
           * Check if all values are selected
           * @return {Boolean}
           */
          scope.areAllSelected = function areAllSelected () {
            var values = angular.copy(scope.values),
                model = angular.copy(scope.model),
                areAllSelected = false,
                $checkbox = $dropdown.find('.multi-select-select-all-checkbox');

            for (var i=0;i<values.length;i++) {
              if (values[i].isOther && values[i].isOther === true) {
                values.splice(i, 1);
              }
            }

            for (var j=0;j<model.length;j++) {
              if (model[j].isOther && model[j].isOther === true) {
                model.splice(j, 1);
              }
            }

            areAllSelected = (values.length === model.length);

            // if some are selected, put checkbox in indeterminate mode
            if (! (areAllSelected) && model.length > 0) {
              $checkbox.prop('indeterminate', true);
            } else {
              $checkbox.prop('indeterminate', false);
            }

            return areAllSelected;
          };

          /**
           * Find other value
           * @return {Object} Other object
           */
          var findOther = function () {
            var selected;

            for (var i=0;i< scope.model.length;i++) {
              selected = scope.model[i];

              if (isOther(selected)) {
                return selected;
              }
            }
          };

          /**
           * Helper to find object in array
           * @param  {Array} collection  Haystack
           * @param  {Object} item       Needle
           * @return {Object}            Found object
           */
          var _find = function (collection, item) {
            var selected;

            collection  = collection || [];

            for (var i=0;i<collection.length;i++) {
              selected = collection[i];

              if (item[scope.valueField] === selected[scope.valueField]) {
                return selected;
              }
            }
          };

          var findItem = _find.curry(scope.model);
          var findInSelect = _find.curry(scope.values);

          scope.shared = { other : '' };

          /**
           * Clear other option
           */
          function clearOther () {
            scope.shared = { other : '' };
          }

          /**
           * Sync other value
           * @param  {Object} option Option object
           */
          scope.syncOther = function (option) {
            var selected = findItem(option);

            if (selected) {
              //toggle it off
              if (! scope.shared.other) {
                selected = scope.selectOption(option);
              }
            } else {
              if (scope.shared.other) {
                //only select it if there is text
                selected = scope.selectOption(option);
              }
            }

            if (selected) {
              selected[scope.otherNgModel] = scope.shared.other;
            }
          };

          // returns whether or not its selected
          // is to default the select to checked when input changes but they dont click it
          if (! attrs.isSelected) {
            scope.isSelected = function (item) {
              var found = findItem(item);

              if (found) {
                return true;
              }

              return false;
            };
          }

          /**
           * Click option checkbox
           * @param  {Object} $event Event
           * @param  {Object} value  Option object
           */
          scope.clickCheckbox = function ($event, value) {
            $event.stopPropagation();
            scope.selectOption(value);
          };

          /**
           * select/deselect option
           * @param  {Object} option Option object
           * @return {Object}        Item object
           */
          scope.selectOption = function selectOption (option) {
            var item = findItem(option);

            if (item) {
               scope.model.splice(scope.model.indexOf(item), 1);

               if (isOther(item)) {
                 clearOther();
               }
            } else {
              item = ng.copy(option);
              scope.model.push(item);
            }

            // close dropdown?
            if (scope.closeOnSelect) {
              $dropdown.removeClass('show').addClass('hide');
            }

            scope.allSelected = scope.areAllSelected();

            return item;
          };

          if (scope.model.length > 0) {
            scope.allSelected = scope.areAllSelected();
          }
        }
      };
    }]);
})(angular);
<commit_msg>clear & clear all listeners<commit_after>(function (ng) {
  'use strict';

  Function.prototype.method = function (name, func) {
    this.prototype[name] = func;
    return this;
  };

  Function.method('curry', function () {
    var slice = Array.prototype.slice,
        args = slice.apply(arguments),
        that = this;

    return function () {
      return that.apply(null, args.concat(slice.apply(arguments)));
    };
  });

  /**
   * @ngdoc directive
   * @name multiselectApp.directive:multiSelect
   * @description
   * # Angular Multi Select directive
   */
  ng.module('shalotelli-angular-multiselect', [])
    .provider('multiSelectConfig', function MultiSelectConfig () {
      var defaults = {
        templatePath: 'bower_components/shalotelli-angular-multiselect/views/directives/multi-select.html',
        otherField: 'isOther',
        otherNgModel: 'other',
        closeOnSelect: false
      };

      /**
       * Set defaults
       * @param {Object} settings Settings object
       */
      this.setDefaults = function (settings) {
        angular.extend(defaults, settings || {});
      };

      this.$get = [ function () {
        return defaults;
      }];
    })
    .directive('multiSelect', [ 'multiSelectConfig', '$timeout', '$log',  function (multiSelectConfig, $timeout, $log) {
      return {
        templateUrl: function (element, attrs) {
          if (attrs.templatePath !== undefined) {
            return attrs.templatePath;
          }

          return multiSelectConfig.templatePath;
        },

        restrict: 'E',
        replace: true,

        scope: {
          values: '=',
          model: '=',
          name: '@',
          showFilters: '@',
          showOther: '@',
          isSelected: '&',
          otherNgModel: '@',
          otherField: '@',
          otherEvent: '@',
          valueField: '@',
          labelField: '@',
          templatePath: '@',
          closeOnSelect: '@'
        },

        link: function multiSelectLink (scope, element, attrs) {
          // dropdown element
          var $dropdown = element.find('.multi-select-dropdown'),

             /**
              * Display options in textbox
              * @return {String} Display string
              */
              displayOptions = function displayOptions () {
                var broadcastkey = 'multiSelectUpdate',
                    label = '';

                if (scope.model.length === 1) {
                  label = scope.model[0][scope.labelField];
                } else if (scope.areAllSelected()) {
                  label = 'All Selected';
                } else if (scope.model.length > 1) {
                  label = scope.model.length + ' Selected';
                } else {
                  label = 'None Selected';
                }

                if (attrs.name !== undefined) {
                  broadcastkey += '_' + attrs.name;
                }

                // emit data
                scope.$emit(broadcastkey, label);

                return label;
              };

          scope.displayOptions = displayOptions;

          var watch = scope.$watch('model', function (newVal, oldVal) {
            if (ng.isDefined(newVal)) {
              if (newVal.length) {
                // if we have something display
                // first time intiialized go ahead an sync other
                var other = findOther();
                if (other) {
                  scope.shared.other = other[scope.otherNgModel] || '';
                }
              }

              // kill watch
              watch();
            }
          });

          // show filters default value
          attrs.$observe('showFilters', function (showFilters) {
            scope.showFilters = showFilters || true;
          });

          // show other default value
          attrs.$observe('showOther', function (showOther) {
            scope.showOther = showOther || false;
          });

          // other box event binding
          attrs.$observe('otherEvent', function (otherEvent) {
            if (otherEvent === undefined || ! otherEvent.match(/blur|keyup|enter/)) {
              otherEvent = 'keyup';
            }

            switch (otherEvent.toLowerCase()) {
              case 'blur':
              case 'keyup':
                ng.element('.multi-select-other').on(otherEvent, function () {
                  displayOptions();
                });
                break;

              case 'enter':
                ng.element('.multi-select-other').on('keydown keypress', function (e) {
                  if (e.which === 13) {
                    e.preventDefault();
                    displayOptions();
                  }
                });
                break;

              default:
                break;
            }
          });

          // value field default value
          attrs.$observe('valueField', function (valueField) {
            scope.valueField = valueField || 'value';
          });

          attrs.$observe('otherField', function (otherField) {
            scope.otherField = otherField || multiSelectConfig.otherField;
          });

          attrs.$observe('closeOnSelect', function (closeOnSelect) {
            scope.closeOnSelect = (closeOnSelect === 'true') || multiSelectConfig.closeOnSelect;
          });

          /**
           * Is item the Other field
           * @param  {Object}  item Item object
           * @return {Boolean}      Is other
           */
          function isOther (item) {
            return item[scope.otherField] === true;
          }

          scope.isOther = isOther;

          // label field default value
          attrs.$observe('otherNgModel', function (otherNgModel) {
            scope.otherNgModel = otherNgModel || multiSelectConfig.otherNgModel;
          });

          // label field default value
          attrs.$observe('labelField', function (labelField) {
            scope.labelField = labelField || 'label';
          });

          // hide dropdown when clicking away
          ng.element(document).on('click', function (e) {
            if (e.target.className.indexOf('multi-select') === -1) {
              $dropdown.removeClass('show').addClass('hide');
            }
          });

          /**
           * Close dropdown when user presses Enter key
           * @param  {Object} $event Event
           */
          scope.close = function ($event) {
            //this should be migrated to use angualar
            if ($event.which === 13) {
              $event.preventDefault();
              $dropdown.removeClass('show').addClass('hide');
            }
          };

          /**
           * Show/hide dropdown
           */
          scope.toggleDropdown = function toggleDropdown () {
            if ($dropdown.hasClass('hide')) {
              // close all other dropdowns on the page before showing the selected one
              ng.element('body').find('.multi-select-dropdown').removeClass('show').addClass('hide');
              $dropdown.removeClass('hide').addClass('show');
            } else {
              $dropdown.removeClass('show').addClass('hide');
            }
          };

          /**
           * Select/Deselect all options
           */
          scope.selectAll = function selectAll () {
            var areAllSelected = scope.areAllSelected();

            //clear all first
            scope.model.length = 0;

            if (! areAllSelected) {
              ng.forEach(scope.values, function (item) {
                if (isOther(item)) {
                  return;
                }

                scope.selectOption(item);
              });
            } else {
              scope.allSelected = scope.areAllSelected();
              clearOther();
            }
          };

          /**
           * Click select all checkbox
           * @param  {Object} $event Event
           */
          scope.clickSelectAllCheckbox = function clickSelectAllCheckbox ($event) {
            $event.stopPropagation();
            scope.selectAll();
          };

          /**
           * Check if all values are selected
           * @return {Boolean}
           */
          scope.areAllSelected = function areAllSelected () {
            var values = angular.copy(scope.values),
                model = angular.copy(scope.model),
                areAllSelected = false,
                $checkbox = $dropdown.find('.multi-select-select-all-checkbox');

            for (var i=0;i<values.length;i++) {
              if (values[i].isOther && values[i].isOther === true) {
                values.splice(i, 1);
              }
            }

            for (var j=0;j<model.length;j++) {
              if (model[j].isOther && model[j].isOther === true) {
                model.splice(j, 1);
              }
            }

            areAllSelected = (values.length === model.length);

            // if some are selected, put checkbox in indeterminate mode
            if (! (areAllSelected) && model.length > 0) {
              $checkbox.prop('indeterminate', true);
            } else {
              $checkbox.prop('indeterminate', false);
            }

            return areAllSelected;
          };

          /**
           * Find other value
           * @return {Object} Other object
           */
          var findOther = function () {
            var selected;

            for (var i=0;i< scope.model.length;i++) {
              selected = scope.model[i];

              if (isOther(selected)) {
                return selected;
              }
            }
          };

          /**
           * Helper to find object in array
           * @param  {Array} collection  Haystack
           * @param  {Object} item       Needle
           * @return {Object}            Found object
           */
          var _find = function (collection, item) {
            var selected;

            collection  = collection || [];

            for (var i=0;i<collection.length;i++) {
              selected = collection[i];

              if (item[scope.valueField] === selected[scope.valueField]) {
                return selected;
              }
            }
          };

          var findItem = _find.curry(scope.model);
          var findInSelect = _find.curry(scope.values);

          scope.shared = { other : '' };

          /**
           * Clear other option
           */
          function clearOther () {
            scope.shared = { other : '' };
          }

          /**
           * Sync other value
           * @param  {Object} option Option object
           */
          scope.syncOther = function (option) {
            var selected = findItem(option);

            if (selected) {
              //toggle it off
              if (! scope.shared.other) {
                selected = scope.selectOption(option);
              }
            } else {
              if (scope.shared.other) {
                //only select it if there is text
                selected = scope.selectOption(option);
              }
            }

            if (selected) {
              selected[scope.otherNgModel] = scope.shared.other;
            }
          };

          // returns whether or not its selected
          // is to default the select to checked when input changes but they dont click it
          if (! attrs.isSelected) {
            scope.isSelected = function (item) {
              var found = findItem(item);

              if (found) {
                return true;
              }

              return false;
            };
          }

          /**
           * Click option checkbox
           * @param  {Object} $event Event
           * @param  {Object} value  Option object
           */
          scope.clickCheckbox = function ($event, value) {
            $event.stopPropagation();
            scope.selectOption(value);
          };

          /**
           * select/deselect option
           * @param  {Object} option Option object
           * @return {Object}        Item object
           */
          scope.selectOption = function selectOption (option) {
            var item = findItem(option);

            if (item) {
               scope.model.splice(scope.model.indexOf(item), 1);

               if (isOther(item)) {
                 clearOther();
               }
            } else {
              item = ng.copy(option);
              scope.model.push(item);
            }

            // close dropdown?
            if (scope.closeOnSelect) {
              $dropdown.removeClass('show').addClass('hide');
            }

            scope.allSelected = scope.areAllSelected();

            return item;
          };

          if (scope.model.length > 0) {
            scope.allSelected = scope.areAllSelected();
          }

          scope.$on('multiSelectClearAll', function () {
            scope.model.length = 0;
            scope.allSelected = scope.areAllSelected();
            clearOther();
          });

          scope.$on('multiSelectClear', function (event, name) {
            if (scope.name && scope.name === name) {
              scope.model.length = 0;
              scope.allSelected = scope.areAllSelected();
              clearOther();
            }
          });
        }
      };
    }]);
})(angular);
<|endoftext|>


<commit_before>'use strict';

describe('Controller: MainCtrl', function() {

  var ctrl,
    scope,
    httpBackend,
    localstorage,
    variablesService,
    styleguideData = {
      sections: {
        data: [
          {
            header: 'Section header text',
            reference: '1'
          },
          {
            header: 'Sub section header text',
            parentReference: '1',
            reference: '1.1'
          }
        ]
      },
      config: {
        data: {
          title: 'Page Title'
        }
      }
    };

  // Load the controller's module
  beforeEach(angular.mock.module('sgApp'));

  beforeEach(function() {
    module(function($provide) {
      $provide.value('Styleguide', styleguideData);
      $provide.value('Variables', {
        init: function() {}
      });
    });
  });

  // Initialize the controller and a mock scope
  beforeEach(inject(function($controller, $rootScope, Variables, $httpBackend, localStorageService) {
    localstorage = localStorageService;
    httpBackend = $httpBackend;
    variablesService = Variables;
    scope = $rootScope.$new();
    ctrl = $controller('MainCtrl', {
      $scope: scope,
      Variables: variablesService
    });

    httpBackend.whenGET('overview.html').respond('');
    httpBackend.whenGET('views/main.html').respond('');
    httpBackend.whenGET('views/sections.html').respond('');
    httpBackend.whenGET('views/404.html').respond('');
    httpBackend.flush();
    localStorageService.clearAll();
  }));

  it('should be defined', function() {
    expect(ctrl).not.to.equal(null);
  });

  it('search parameter should be cleared after search', function() {
    scope.search = 'test';
    scope.clearSearch();
    expect(scope.search).to.be.empty;
  });

  it('should get section data from styleguide data', function() {
    expect(scope.sections).to.eql(styleguideData.sections);
  });

  it('should have markup shown by default', function() {
    expect(scope.markupSection.isVisible).to.eql(true);
  });

  describe('toggle sideNav', function() {
    it('should inverse boolean', function() {
      scope.showMenu = true;
      expect(scope.toggleSideNav(scope.showMenu)).to.eql(false);
    });
  });

  describe('sideNav configuration option true', function() {
    it('should return true if sideNav configuration option is set true', function() {
      scope.config.data.sideNav = true;
      expect(scope.isSideNav()).to.eql(true);
    });
  });

  it('should change markup visibility when toggling state', function() {
    scope.toggleMarkup();
    expect(scope.markupSection.isVisible).to.eql(false);
  });

  it('should persist new state when toggling state', function() {
    scope.toggleMarkup();
    scope.$digest();
    expect(localstorage.get('markupSection').isVisible).to.eql(false);
  });

  it('should hide designer tool by default', function() {
    expect(scope.designerTool.isVisible).to.eql(false);
  });

  it('should persist new state when designer tool visibility is changed', function() {
    scope.designerTool.isVisible = true;
    scope.$digest();
    expect(localstorage.get('designerTool').isVisible).to.eql(true);
  });

  describe('main section filtering', function() {
    it('should return true for main sections', function() {
      expect(scope.filterMainSections()({reference: '1'})).to.eql(true);
    });

    it('should return false for sub sections', function() {
      expect(scope.filterMainSections()({reference: '1.2'})).to.eql(false);
      expect(scope.filterMainSections()({reference: '1.1.2'})).to.eql(false);
    });

    it('should return true if section has sub section', function() {
      expect(scope.hasSubsections({reference: '1'})).to.eql(true);
    });

    it('should return false for undefined reference', function() {
      expect(scope.filterMainSections()({})).to.eql(false);
    });
  });

  describe('subsection filtering', function() {
    it('should return true when section is subsection of defined section', function() {
      expect(scope.filterSubsections({reference: '1'})({reference: '1.1'})).to.eql(true);
    });

    it('should return false when section is subsubsection of defined section', function() {
      expect(scope.filterSubsections({reference: '1'})({reference: '1.1.2'})).to.eql(false);
    });

    it('should return true when section is subsubsection of defined subsection', function() {
      expect(scope.filterSubsections({reference: '1.1'})({reference: '1.1.2'})).to.eql(true);
    });

    it('should return false for sections on the same lever', function() {
      expect(scope.filterSubsections({reference: '1'})({reference: '2'})).to.eql(false);
    });

    it('should return false for undefined parent section', function() {
      expect(scope.filterSubsections({})({reference: '1.1'})).to.eql(false);
    });

    it('should return false for undefined child section', function() {
      expect(scope.filterSubsections({reference: '1.1'})({})).to.eql(false);
    });
  });
});
<commit_msg>add changes to test<commit_after>'use strict';

describe('Controller: MainCtrl', function() {

  var ctrl,
    scope,
    httpBackend,
    localstorage,
    variablesService,
    styleguideData = {
      sections: {
        data: [
          {
            header: 'Section header text',
            reference: '1'
          },
          {
            header: 'Sub section header text',
            parentReference: '1',
            reference: '1.1'
          }
        ]
      },
      config: {
        data: {
          title: 'Page Title'
        }
      }
    };

  // Load the controller's module
  beforeEach(angular.mock.module('sgApp'));

  beforeEach(function() {
    module(function($provide) {
      $provide.value('Styleguide', styleguideData);
      $provide.value('Variables', {
        init: function() {}
      });
    });
  });

  // Initialize the controller and a mock scope
  beforeEach(inject(function($controller, $rootScope, Variables, $httpBackend, localStorageService) {
    localstorage = localStorageService;
    httpBackend = $httpBackend;
    variablesService = Variables;
    scope = $rootScope.$new();
    ctrl = $controller('MainCtrl', {
      $scope: scope,
      Variables: variablesService
    });

    httpBackend.whenGET('overview.html').respond('');
    httpBackend.whenGET('views/main.html').respond('');
    httpBackend.whenGET('views/sections.html').respond('');
    httpBackend.whenGET('views/404.html').respond('');
    httpBackend.flush();
    localStorageService.clearAll();
  }));

  it('should be defined', function() {
    expect(ctrl).not.to.equal(null);
  });

  it('search parameter should be cleared after search', function() {
    scope.search = 'test';
    scope.clearSearch();
    expect(scope.search).to.be.empty;
  });

  it('should get section data from styleguide data', function() {
    expect(scope.sections).to.eql(styleguideData.sections);
  });

  it('should have markup shown by default', function() {
    expect(scope.markupSection.isVisible).to.eql(true);
  });

  describe('toggle sideNav', function() {
    it('should inverse boolean', function() {
      scope.showMenu = true;
      expect(scope.toggleSideNav(scope.showMenu)).to.eql(false);
    });
  });

  describe('sideNav configuration option true', function() {
    it('should return true if sideNav configuration option is set true', function() {
      scope.config.data.sideNav = true;
      expect(scope.isSideNav()).to.eql('sideNav');
    });
  });

  it('should change markup visibility when toggling state', function() {
    scope.toggleMarkup();
    expect(scope.markupSection.isVisible).to.eql(false);
  });

  it('should persist new state when toggling state', function() {
    scope.toggleMarkup();
    scope.$digest();
    expect(localstorage.get('markupSection').isVisible).to.eql(false);
  });

  it('should hide designer tool by default', function() {
    expect(scope.designerTool.isVisible).to.eql(false);
  });

  it('should persist new state when designer tool visibility is changed', function() {
    scope.designerTool.isVisible = true;
    scope.$digest();
    expect(localstorage.get('designerTool').isVisible).to.eql(true);
  });

  describe('main section filtering', function() {
    it('should return true for main sections', function() {
      expect(scope.filterMainSections()({reference: '1'})).to.eql(true);
    });

    it('should return false for sub sections', function() {
      expect(scope.filterMainSections()({reference: '1.2'})).to.eql(false);
      expect(scope.filterMainSections()({reference: '1.1.2'})).to.eql(false);
    });

    it('should return true if section has sub section', function() {
      expect(scope.hasSubsections({reference: '1'})).to.eql(true);
    });

    it('should return false for undefined reference', function() {
      expect(scope.filterMainSections()({})).to.eql(false);
    });
  });

  describe('subsection filtering', function() {
    it('should return true when section is subsection of defined section', function() {
      expect(scope.filterSubsections({reference: '1'})({reference: '1.1'})).to.eql(true);
    });

    it('should return false when section is subsubsection of defined section', function() {
      expect(scope.filterSubsections({reference: '1'})({reference: '1.1.2'})).to.eql(false);
    });

    it('should return true when section is subsubsection of defined subsection', function() {
      expect(scope.filterSubsections({reference: '1.1'})({reference: '1.1.2'})).to.eql(true);
    });

    it('should return false for sections on the same lever', function() {
      expect(scope.filterSubsections({reference: '1'})({reference: '2'})).to.eql(false);
    });

    it('should return false for undefined parent section', function() {
      expect(scope.filterSubsections({})({reference: '1.1'})).to.eql(false);
    });

    it('should return false for undefined child section', function() {
      expect(scope.filterSubsections({reference: '1.1'})({})).to.eql(false);
    });
  });
});
<|endoftext|>


<commit_before> $(document).ready(function () {
        var time1 = 0;
        var show = false;
        var names = new Array(); //文章名字等
        var urls = new Array(); //文章地址
        $(document).keyup(function (e) {
            var time2 = new Date().getTime();
            if (e.keyCode == 17) {
                var gap = time2 - time1;
                time1 = time2;
                if (gap < 500) {
                    if (show) {
                        $(".cb-search-tool").css("display", "none");
                        show = false;
                    } else {
                        $(".cb-search-tool").css("display", "block");
                        show = true;
                        $("#cb-search-content").val("");
                        $("#cb-search-content").focus();
                    }
                    time1 = 0;
                }
			}else if(e.keyCode == 27){
                    $(".cb-search-tool").css("display", "none");
                    show = false;
                    time1 = 0;
                }
        });

 		$("#cb-search-content").keyup(function (e) {
            var time2 = new Date().getTime();
            if (window.event.keyCode == 17) {
                var gap = time2 - time1;
                time1 = time2;
                if (gap < 500) {
                    if (show) {
                        $(".cb-search-tool").css("display", "none");
                        show = false;
                    } else {
                        $(".cb-search-tool").css("display", "block");
                        show = true;
                        $("#cb-search-content").val("");
                        $("#cb-search-content").focus();
                    }
                    time1 = 0;
                }
            }
        });

        $("#cb-close-btn").click(function () {
            $(".cb-search-tool").css("display", "none");
            show = false;
            time1 = 0;
        });

        $("#cb-search-btn").click(function(){
            $(".cb-search-tool").css("display", "block");
            show = true;
            $("#cb-search-content").val("");
            $("#cb-search-content").focus();
            time1 = 0;
        });

        $.getJSON("/search/cb-search.json").done(function (data) {
            if (data.code == 0) {
                var shift = Math.floor(Math.random()*10);
                for (var index in data.data) {
                    idx = (index + shift)%data.data.length;
                    var item = data.data[idx];
                    names.push(item.title);
                    urls.push(item.url);
                }

                $("#cb-search-content").typeahead({
                    source: names,

                    afterSelect: function (item) {
						$(".cb-search-tool").css("display", "none");
                        show = false;
                        window.location.href = (urls[names.indexOf(item)]);
                        return item;
                    }
                });
            }
        });

    });
<commit_msg>shift to search<commit_after> $(document).ready(function () {
        var time1 = 0;
        var show = false;
        var names = new Array(); //文章名字等
        var urls = new Array(); //文章地址
        $(document).keyup(function (e) {
            var time2 = new Date().getTime();
            if (e.keyCode == 17) {
                var gap = time2 - time1;
                time1 = time2;
                if (gap < 500) {
                    if (show) {
                        $(".cb-search-tool").css("display", "none");
                        show = false;
                    } else {
                        $(".cb-search-tool").css("display", "block");
                        show = true;
                        $("#cb-search-content").val("");
                        $("#cb-search-content").focus();
                    }
                    time1 = 0;
                }
			}else if(e.keyCode == 27){
                    $(".cb-search-tool").css("display", "none");
                    show = false;
                    time1 = 0;
                }
        });

 		$("#cb-search-content").keyup(function (e) {
            var time2 = new Date().getTime();
            if (window.event.keyCode == 17) {
                var gap = time2 - time1;
                time1 = time2;
                if (gap < 500) {
                    if (show) {
                        $(".cb-search-tool").css("display", "none");
                        show = false;
                    } else {
                        $(".cb-search-tool").css("display", "block");
                        show = true;
                        $("#cb-search-content").val("");
                        $("#cb-search-content").focus();
                    }
                    time1 = 0;
                }
            }
        });

        $("#cb-close-btn").click(function () {
            $(".cb-search-tool").css("display", "none");
            show = false;
            time1 = 0;
        });

        $("#cb-search-btn").click(function(){
            $(".cb-search-tool").css("display", "block");
            show = true;
            $("#cb-search-content").val("");
            $("#cb-search-content").focus();
            time1 = 0;
        });

        $.getJSON("/search/cb-search.json").done(function (data) {
            if (data.code == 0) {
                var shift = Math.floor(Math.random()*10);
                for (var index in data.data) {
                    idx = (index + shift)%data.data.length;
                    var item = data.data[idx];
                    names.push(item.title);
                    urls.push(item.url);
                }

                $("#cb-search-content").typeahead({
                    source: names,

                    afterSelect: function (item) {
						$(".cb-search-tool").css("display", "none");
                        show = false;
                        window.location.href = (urls[names.indexOf(item)]);
                        return item;
                    },
                    sorter: function(items){
                        shuffleFunc = function (array) {
                              var currentIndex = array.length, temporaryValue, randomIndex;

                              // While there remain elements to shuffle...
                              while (0 !== currentIndex) {

                                // Pick a remaining element...
                                randomIndex = Math.floor(Math.random() * currentIndex);
                                currentIndex -= 1;

                                // And swap it with the current element.
                                temporaryValue = array[currentIndex];
                                array[currentIndex] = array[randomIndex];
                                array[randomIndex] = temporaryValue;
                              }

                              return array;
                            }
                        items = shuffleFunc(items);
                        return items;
                    }
                });
            }
        });

    });
<|endoftext|>


<commit_before>const services = require('./services')

console.log('#!/bin/bash')
console.log('set -ex')

switch (process.argv.pop()) {
  case 'checkout':
    for (const service of services) {
      console.log(`git clone ${service.repo} ${service.name}`)
      console.log(`git -C ${service.name} checkout ${service.version}`)
    }
    break
  case 'revisions':
    for (const service of services) {
      console.log(`git -C ${service.name} rev-parse HEAD`)
    }
    break
  case 'cleanup-git':
    for (const service of services) {
      console.log(`rm -rf ${service.name}/.git`)
    }
    break
  case 'install':
    for (const service of services) {
      console.log('pushd', service.name)
      switch (service.name) {
        case 'web':
          console.log('npm ci')
          break
        default:
          console.log('npm ci --only=production')
      }
      console.log('popd')
    }
    break
  case 'compile':
    for (const service of services) {
      console.log('pushd', service.name)
      switch (service.name) {
        case 'web':
          console.log('npm run webpack:production')
          // drop webpack/babel cache
          console.log('rm -rf node_modules/.cache')
          break
        default:
          console.log(`echo ${service.name} does not require a compilation`)
      }
      console.log('popd')
    }
    break
  default:
    console.error('unknown command')
    console.log('exit 101')
    process.exit(101)
}

console.log('set +x')
console.log(
  'rm -rf /root/.cache /root/.npm $(find /tmp/ -mindepth 1 -maxdepth 1)'
)
<commit_msg>[misc] work around broken 'npm ci --only=production'<commit_after>const services = require('./services')

console.log('#!/bin/bash')
console.log('set -ex')

switch (process.argv.pop()) {
  case 'checkout':
    for (const service of services) {
      console.log(`git clone ${service.repo} ${service.name}`)
      console.log(`git -C ${service.name} checkout ${service.version}`)
    }
    break
  case 'revisions':
    for (const service of services) {
      console.log(`git -C ${service.name} rev-parse HEAD`)
    }
    break
  case 'cleanup-git':
    for (const service of services) {
      console.log(`rm -rf ${service.name}/.git`)
    }
    break
  case 'install':
    for (const service of services) {
      console.log('pushd', service.name)
      switch (service.name) {
        case 'web':
          console.log('npm ci')
          break
        default:
          // TODO(das7pad): revert back to npm ci --only=production (https://github.com/overleaf/issues/issues/4544)
          console.log('npm ci')
      }
      console.log('popd')
    }
    break
  case 'compile':
    for (const service of services) {
      console.log('pushd', service.name)
      switch (service.name) {
        case 'web':
          console.log('npm run webpack:production')
          // drop webpack/babel cache
          console.log('rm -rf node_modules/.cache')
          break
        default:
          console.log(`echo ${service.name} does not require a compilation`)
      }
      console.log('popd')
    }
    break
  default:
    console.error('unknown command')
    console.log('exit 101')
    process.exit(101)
}

console.log('set +x')
console.log(
  'rm -rf /root/.cache /root/.npm $(find /tmp/ -mindepth 1 -maxdepth 1)'
)
<|endoftext|>


<commit_before>'use strict';

/**
*	Endpoints for managing data pipes connectors
*	@Author: David Taieb
*/

var fs = require('fs');
var global = require('bluemix-helper-config').global;
var pipesSDK = require('pipes-sdk');
var connector = pipesSDK.connector;
var _ = require('lodash');
var path = require("path");
var pipesDb = pipesSDK.pipesDb;

function connectorAPI(){

	var connectors = null;

	/**
	 * loadConnector: private API for loading a connector from a specified path
	 */
	var loadConnector = function( connectorPath ){
		try{
			var connector = require( connectorPath );
			//Determine the path for the connector which is the parent directory of the module main js file
			connector.path = path.join( require.resolve( connectorPath ), "..");
			//Read any custom tab controller provided by the connector
			readCustomControllers( path.join(connector.path, "controllers"), connector );
			return connector;
		}catch(e){
			console.log("Invalid connector found at location %s. Make sure to export an object that inherit from connector object", parentDirPath );
			console.log(e.stack);
			return null;
		}
	}

	/**
	 * readCustomController: private API for reading controllers provided by a custom connector
	 */
	var readCustomControllers = function( controllersPath, connector ){
		var customControllers = connector.getOption("customControllers") || {};
		if ( fs.existsSync(controllersPath) ){
			var files = fs.readdirSync( controllersPath);
			files = _.chain( files )
			.filter( function( file ){
				var ret = fs.lstatSync( path.join( controllersPath, file ) ).isFile() && _.endsWith(file, ".js");
				return ret;
			})
			.map(function(file){
				//Extract the tab name from the file name. convention is <<tab>.js
				var tabName = file.substring(0, file.length - ".js".length );
				customControllers[tabName] = fs.readFileSync(path.join( controllersPath, file ), "utf8" );
			})
			.value()

			connector.setOption("customControllers", customControllers);
		}
	}

	//load connectors with source installed within the main app
	var connectorPath = path.join( __dirname, "connectors" );
	fs.readdir( connectorPath, function(err, files){
		if ( err ){
			throw new Error( err );
		}

		connectors = _.chain( files )
		.filter( function(file){
			return fs.lstatSync(path.join(connectorPath, file)).isDirectory();
		})
		.map( function( file ){
			//Load the connector
			var connector = loadConnector( path.join(connectorPath, file) );
			if ( connector ){
				console.log("Loaded built-in connector", connector.getId());
			}
			return connector;
		})
		.filter( function( connector ){
			//One more pass to remove any invalid connector
			return connector != null;
		})
		.value();

		//Load connectors installed as node modules
		var npm = require("npm");
		npm.load({ parseable: true, depth:0 }, function (err, npm) {
			if (err) {
				return console.log("Unable to load npm programmatically: ", err);
			}
			npm.commands.ls([], true, function( err, data, lite){
				if (err) {
					return console.log("Error running npm ls: ", err);
				}
				//console.log("ls data: ", data)
				_.forEach(data.dependencies, function(value, key ){
					if ( value.hasOwnProperty("pipes-connector-name") ){
						//Found a pipe connector module, load it now
						var connector = loadConnector( value.path );
						if ( connector ){
							console.log("Loaded npm dependency connector", connector.getId());
							connectors.push( connector );
						}
					}
				})
			})
		});
	});

	//Public APIs
	/**
	 * InitEndPoints
	 * @param app: express app
	 */
	this.initEndPoints = function( app ){
		/**
		 * return list of registered connectors
		 */
		app.get('/connectors', function(req, res) {
			if ( !connectors ){
				return global.jsonError( res, "Unable to load registered connectors");
			}
			return res.json( connectors );
		});
	};

	/**
	 * getConnectorForPipeId: return the connector for the pipe identified by its id
	 * @param pipeId: id for the pipe
	 * @param callback(err, connector)
	 */
	this.getConnectorForPipeId = function( pipeId, callback ){
		pipesDb.getPipe( pipeId, function( err, pipe ){
			if ( err ){
				return callback(err);
			}
			var connector = this.getConnector( pipe );
			if ( !connector ){
				return callback( "Unable to get Connector for " + pipeId );
			}
			return callback( null, connector );
		}.bind(this));
	}

	/**
	 * getConnector: return the connector associated with a pipe
	 */
	this.getConnector = function(pipe){
		var connectorId = _.isString( pipe ) ? pipe : pipe.connectorId;
		return _.find( connectors, function( connector ){
			return connector.getId() === connectorId;
		});
	};
}

//Singleton
module.exports = new connectorAPI();<commit_msg>undefined variable in logging<commit_after>'use strict';

/**
*	Endpoints for managing data pipes connectors
*	@Author: David Taieb
*/

var fs = require('fs');
var global = require('bluemix-helper-config').global;
var pipesSDK = require('pipes-sdk');
var connector = pipesSDK.connector;
var _ = require('lodash');
var path = require("path");
var pipesDb = pipesSDK.pipesDb;

function connectorAPI(){

	var connectors = null;

	/**
	 * loadConnector: private API for loading a connector from a specified path
	 */
	var loadConnector = function( connectorPath ){
		try{
			var connector = require( connectorPath );
			//Determine the path for the connector which is the parent directory of the module main js file
			connector.path = path.join( require.resolve( connectorPath ), "..");
			//Read any custom tab controller provided by the connector
			readCustomControllers( path.join(connector.path, "controllers"), connector );
			return connector;
		}catch(e){
			console.log("Invalid connector found at location %s. Make sure to export an object that inherit from connector object", connectorPath );
			console.log(e.stack);
			return null;
		}
	}

	/**
	 * readCustomController: private API for reading controllers provided by a custom connector
	 */
	var readCustomControllers = function( controllersPath, connector ){
		var customControllers = connector.getOption("customControllers") || {};
		if ( fs.existsSync(controllersPath) ){
			var files = fs.readdirSync( controllersPath);
			files = _.chain( files )
			.filter( function( file ){
				var ret = fs.lstatSync( path.join( controllersPath, file ) ).isFile() && _.endsWith(file, ".js");
				return ret;
			})
			.map(function(file){
				//Extract the tab name from the file name. convention is <<tab>.js
				var tabName = file.substring(0, file.length - ".js".length );
				customControllers[tabName] = fs.readFileSync(path.join( controllersPath, file ), "utf8" );
			})
			.value()

			connector.setOption("customControllers", customControllers);
		}
	}

	//load connectors with source installed within the main app
	var connectorPath = path.join( __dirname, "connectors" );
	fs.readdir( connectorPath, function(err, files){
		if ( err ){
			throw new Error( err );
		}

		connectors = _.chain( files )
		.filter( function(file){
			return fs.lstatSync(path.join(connectorPath, file)).isDirectory();
		})
		.map( function( file ){
			//Load the connector
			var connector = loadConnector( path.join(connectorPath, file) );
			if ( connector ){
				console.log("Loaded built-in connector", connector.getId());
			}
			return connector;
		})
		.filter( function( connector ){
			//One more pass to remove any invalid connector
			return connector != null;
		})
		.value();

		//Load connectors installed as node modules
		var npm = require("npm");
		npm.load({ parseable: true, depth:0 }, function (err, npm) {
			if (err) {
				return console.log("Unable to load npm programmatically: ", err);
			}
			npm.commands.ls([], true, function( err, data, lite){
				if (err) {
					return console.log("Error running npm ls: ", err);
				}
				//console.log("ls data: ", data)
				_.forEach(data.dependencies, function(value, key ){
					if ( value.hasOwnProperty("pipes-connector-name") ){
						//Found a pipe connector module, load it now
						var connector = loadConnector( value.path );
						if ( connector ){
							console.log("Loaded npm dependency connector", connector.getId());
							connectors.push( connector );
						}
					}
				})
			})
		});
	});

	//Public APIs
	/**
	 * InitEndPoints
	 * @param app: express app
	 */
	this.initEndPoints = function( app ){
		/**
		 * return list of registered connectors
		 */
		app.get('/connectors', function(req, res) {
			if ( !connectors ){
				return global.jsonError( res, "Unable to load registered connectors");
			}
			return res.json( connectors );
		});
	};

	/**
	 * getConnectorForPipeId: return the connector for the pipe identified by its id
	 * @param pipeId: id for the pipe
	 * @param callback(err, connector)
	 */
	this.getConnectorForPipeId = function( pipeId, callback ){
		pipesDb.getPipe( pipeId, function( err, pipe ){
			if ( err ){
				return callback(err);
			}
			var connector = this.getConnector( pipe );
			if ( !connector ){
				return callback( "Unable to get Connector for " + pipeId );
			}
			return callback( null, connector );
		}.bind(this));
	}

	/**
	 * getConnector: return the connector associated with a pipe
	 */
	this.getConnector = function(pipe){
		var connectorId = _.isString( pipe ) ? pipe : pipe.connectorId;
		return _.find( connectors, function( connector ){
			return connector.getId() === connectorId;
		});
	};
}

//Singleton
module.exports = new connectorAPI();<|endoftext|>


<commit_before>
/**
 * Module dependencies.
 */
var mongoose   = require('mongoose');
mongoose.connect('mongodb://localhost/bears'); // connect to our database

var Bear     = require('../models/bears');

var restpress = require('restpress');

// Create a RESTful resource
var resource = new restpress('bears', require('./bears-actions.json'));

resource.all(function(req, res, next) {
	console.log('Something is happening.');
	next();
});

// get all the bears
resource.list(function(req, res) {
	Bear.find(function(err, bears) {
		if (err)
			res.send(err);

		res.json(bears);
	});
});

// get the bear with that id
resource.read(function(req, res) {
	Bear.findById(req.params.id, function(err, bear) {
		if (err)
			res.send(err);
		res.json(bear);
	});
});

// create a bear
resource.create(function(req, res) {
	var bear = new Bear(); 		// create a new instance of the Bear model
	bear.name = req.body.name;  // set the bears name (comes from the request)

	// save the bear and check for errors
	bear.save(function(err) {
		if (err)
			res.send(err);

		res.json({ message: 'Bear created!' });
	});
});

// update bears service endpoint
resource.update(function(req, res) {
  res.json({"action": "update", "data": "update data from stub"});
});

// delete bears service endpoint
resource.delete(function(req, res) {
  res.json({"action": "delete", "data": "delete data from stub"});
});

module.exports = resource;
<commit_msg>Updating a Bear’s Info<commit_after>
/**
 * Module dependencies.
 */
var mongoose   = require('mongoose');
mongoose.connect('mongodb://localhost/bears'); // connect to our database

var Bear     = require('../models/bears');

var restpress = require('restpress');

// Create a RESTful resource
var resource = new restpress('bears', require('./bears-actions.json'));

resource.all(function(req, res, next) {
	console.log('Something is happening.');
	next();
});

// get all the bears
resource.list(function(req, res) {
	Bear.find(function(err, bears) {
		if (err)
			res.send(err);

		res.json(bears);
	});
});

// get the bear with that id
resource.read(function(req, res) {
	Bear.findById(req.params.id, function(err, bear) {
		if (err)
			res.send(err);
		res.json(bear);
	});
});

// create a bear
resource.create(function(req, res) {
	var bear = new Bear(); 		// create a new instance of the Bear model
	bear.name = req.body.name;  // set the bears name (comes from the request)

	// save the bear and check for errors
	bear.save(function(err) {
		if (err)
			res.send(err);

		res.json({ message: 'Bear created!' });
	});
});

// update the bear with this id
resource.update(function(req, res) {
	// use our bear model to find the bear we want
	Bear.findById(req.params.id, function(err, bear) {

		if (err)
			res.send(err);

		bear.name = req.body.name; 	// update the bears info

		// save the bear
		bear.save(function(err) {
			if (err)
				res.send(err);

			res.json({ message: 'Bear updated!' });
		});

	});

});

// delete bears service endpoint
resource.delete(function(req, res) {
  res.json({"action": "delete", "data": "delete data from stub"});
});

module.exports = resource;
<|endoftext|>


<commit_before>"use strict";
// Observable class extensions
require('rxjs/add/observable/of');
require('rxjs/add/observable/throw');
// Observable operators
require('rxjs/add/operator/catch');
require('rxjs/add/operator/debounceTime');
require('rxjs/add/operator/distinctUntilChanged');
require('rxjs/add/operator/do');
require('rxjs/add/operator/filter');
require('rxjs/add/operator/map');
require('rxjs/add/operator/switchMap');
//# sourceMappingURL=rxjs-extensions.js.map<commit_msg>Delete rxjs-extensions.js<commit_after><|endoftext|>


<commit_before>var User = require("user");
var async = require("async");
var backup = require("./backup");
var dailyUpdate = require("./daily");
var email = require("helper/email");
var clfdate = require("helper/clfdate");
var warmCache = require("./warmCache");
var schedule = require("node-schedule").scheduleJob;
var checkFeatuedSites = require("../brochure/routes/featured/check");
var publishScheduledEntries = require("./publish-scheduled-entries");
const os = require("os");
const fs = require("fs-extra");
const exec = require("child_process").exec;

module.exports = function () {
  schedule("* * * * *", function () {
    exec("ps -eo pmem,pcpu,comm,args | sort -k 1 -nr | head -10", function (
      err,
      stdout
    ) {
      if (err || !stdout) return;
      console.log(clfdate(), "[STATS]", "top");
      console.log(stdout);
    });
  });

  // Every minute look
  schedule("* * * * *", function () {
    fs.readFile("/proc/meminfo", "utf-8", function (err, contents) {
      // This won't work on MacOS
      if (err || !contents) return;

      let stats = contents.split("\n").forEach((line) => {
        stats[line.split(":")[0].trim()] = parseInt(line.split(":")[1].trim());
      });

      let loadavg = os.loadavg()[0];
      let totalCPUs = os.cpus().length;
      let totalmem = stats.MemTotal;
      let freemem = stats.MemAvailable;
      let pretty = (num) => (100 * num).toFixed(3) + "%";

      console.log(
        clfdate(),
        "[STATS]",
        "cpuuse=" + pretty(loadavg / totalCPUs),
        "memuse=" + pretty((totalmem - freemem) / totalmem)
      );
    });
  });

  // Bash the cache for scheduled posts
  publishScheduledEntries(function (err) {
    if (err) throw err;
    console.log(clfdate(), "Scheduled entries for future publication");
  });

  // Warm the cache for the brochure site
  warmCache(function (err) {
    if (err) throw err;
  });

  // Warn users about impending subscriptions
  User.getAllIds(function (err, uids) {
    async.each(uids, User.scheduleSubscriptionEmail, function (err) {
      if (err) {
        console.error("Error scheduling subscription emails:", err);
      } else {
        console.log(clfdate(), "Scheduled emails for renewals and expiries!");
      }
    });
  });

  console.log(
    clfdate(),
    "Scheduled daily check of storage disk usage for 6am!"
  );
  schedule({ hour: 10, minute: 0 }, function () {
    console.log(clfdate(), "Scheduler: Checking available disk space");

    exec("df -h", function (err, stdout) {
      if (err) throw err;

      var disk = stdout.split("\n")[1].replace(/\s+/g, " ").split(" ");
      var usage = disk[4];
      var available = disk[3];

      if (parseInt(usage) < 90) {
        console.log(
          clfdate(),
          "Scheduler: Disk usage check passed! Usage:",
          usage,
          "Space available:",
          available
        );
        return;
      }

      console.log(
        clfdate(),
        "Scheduler: Disk usage check failed! Usage:",
        usage,
        "Space available:",
        available
      );

      email.WARNING_LOW_DISK_SPACE(
        null,
        { usage: usage, available: available },
        function (err) {
          if (err) console.log(clfdate(), err);
        }
      );
    });
  });

  console.log(clfdate(), "Scheduled daily backups for 3am!");
  schedule({ hour: 11, minute: 0 }, function () {
    // Start the backup daemon
    console.log(clfdate(), "Backup: Starting backup");
    backup(function (err) {
      if (err) {
        console.log(clfdate(), "Backup: Error:" + err);
      } else {
        console.log(clfdate(), "Backup: Successfully backed up");
      }
    });
  });

  console.log(clfdate(), "Scheduled daily check of featured sites");
  schedule({ hour: 8, minute: 0 }, function () {
    console.log(clfdate(), "Checking featured sites");
    checkFeatuedSites(function (err) {
      if (err) {
        console.log(clfdate(), "Error: Checking featured sites".err);
      } else {
        console.log(clfdate(), "Checked featured sites");
      }
    });
  });

  // At some point I should check this doesnt consume too much memory
  console.log(clfdate(), "Scheduled daily update email for 6:05am!");
  schedule({ hour: 10, minute: 5 }, function () {
    console.log(clfdate(), "Generating daily update email...");
    dailyUpdate(function () {
      console.log(clfdate(), "Daily update email update was sent.");
    });
  });
};
<commit_msg>Updates stats polling<commit_after>var User = require("user");
var async = require("async");
var backup = require("./backup");
var dailyUpdate = require("./daily");
var email = require("helper/email");
var clfdate = require("helper/clfdate");
var warmCache = require("./warmCache");
var schedule = require("node-schedule").scheduleJob;
var checkFeatuedSites = require("../brochure/routes/featured/check");
var publishScheduledEntries = require("./publish-scheduled-entries");
const os = require("os");
const fs = require("fs-extra");
const exec = require("child_process").exec;

module.exports = function () {

  // Log useful system information, once per minute
  schedule("* * * * *", function () {

    // Print most memory-intensive processes
    exec("ps -eo pmem,pcpu,comm,args | sort -k 1 -nr | head -10", function (
      err,
      stdout
    ) {
      if (err || !stdout) return;
      console.log(clfdate(), "[STATS]", "top");
      console.log(stdout);
    });

    // Print cpu and memory information
    fs.readFile("/proc/meminfo", "utf-8", function (err, contents) {
      // This won't work on MacOS
      if (err || !contents) return;

      let stats = contents.split("\n").forEach((line) => {
        stats[line.split(":")[0].trim()] = parseInt(line.split(":")[1].trim());
      });

      let loadavg = os.loadavg()[0];
      let totalCPUs = os.cpus().length;
      let totalmem = stats.MemTotal;
      let freemem = stats.MemAvailable;
      let pretty = (num) => (100 * num).toFixed(3) + "%";

      console.log(
        clfdate(),
        "[STATS]",
        "cpuuse=" + pretty(loadavg / totalCPUs),
        "memuse=" + pretty((totalmem - freemem) / totalmem)
      );
    });
  });

  // Bash the cache for scheduled posts
  publishScheduledEntries(function (err) {
    if (err) throw err;
    console.log(clfdate(), "Scheduled entries for future publication");
  });

  // Warm the cache for the brochure site
  warmCache(function (err) {
    if (err) throw err;
  });

  // Warn users about impending subscriptions
  User.getAllIds(function (err, uids) {
    async.each(uids, User.scheduleSubscriptionEmail, function (err) {
      if (err) {
        console.error("Error scheduling subscription emails:", err);
      } else {
        console.log(clfdate(), "Scheduled emails for renewals and expiries!");
      }
    });
  });

  console.log(
    clfdate(),
    "Scheduled daily check of storage disk usage for 6am!"
  );
  schedule({ hour: 10, minute: 0 }, function () {
    console.log(clfdate(), "Scheduler: Checking available disk space");

    exec("df -h", function (err, stdout) {
      if (err) throw err;

      var disk = stdout.split("\n")[1].replace(/\s+/g, " ").split(" ");
      var usage = disk[4];
      var available = disk[3];

      if (parseInt(usage) < 90) {
        console.log(
          clfdate(),
          "Scheduler: Disk usage check passed! Usage:",
          usage,
          "Space available:",
          available
        );
        return;
      }

      console.log(
        clfdate(),
        "Scheduler: Disk usage check failed! Usage:",
        usage,
        "Space available:",
        available
      );

      email.WARNING_LOW_DISK_SPACE(
        null,
        { usage: usage, available: available },
        function (err) {
          if (err) console.log(clfdate(), err);
        }
      );
    });
  });

  console.log(clfdate(), "Scheduled daily backups for 3am!");
  schedule({ hour: 11, minute: 0 }, function () {
    // Start the backup daemon
    console.log(clfdate(), "Backup: Starting backup");
    backup(function (err) {
      if (err) {
        console.log(clfdate(), "Backup: Error:" + err);
      } else {
        console.log(clfdate(), "Backup: Successfully backed up");
      }
    });
  });

  console.log(clfdate(), "Scheduled daily check of featured sites");
  schedule({ hour: 8, minute: 0 }, function () {
    console.log(clfdate(), "Checking featured sites");
    checkFeatuedSites(function (err) {
      if (err) {
        console.log(clfdate(), "Error: Checking featured sites".err);
      } else {
        console.log(clfdate(), "Checked featured sites");
      }
    });
  });

  // At some point I should check this doesnt consume too much memory
  console.log(clfdate(), "Scheduled daily update email for 6:05am!");
  schedule({ hour: 10, minute: 5 }, function () {
    console.log(clfdate(), "Generating daily update email...");
    dailyUpdate(function () {
      console.log(clfdate(), "Daily update email update was sent.");
    });
  });
};
<|endoftext|>


<commit_before>"use strict";

function matchKey(ev, keyCode, mods) {
  if (ev.keyCode != keyCode)
    return false;
  mods = mods || { };
  var modifiers = ["altKey", "altGraphKey", "ctrlKey", "metaKey", "shiftKey"];
  for (var i = 0; i < modifiers.length; i++) {
    if (Boolean(ev[modifiers[i]]) != Boolean(mods[modifiers[i]]))
      return false;
  }
  return true;
}

// TODO(davidben): Make all this code not terrible. Seriously.

var roostApp = angular.module("roostApp", []);

roostApp.value("config", CONFIG);

roostApp.service("localStorage", [function() {
  return new LocalStorageWrapper();
}]);

roostApp.service("storageManager", ["localStorage", function(localStorage) {
  return new StorageManager(localStorage);
}]);

roostApp.service("ticketManager", ["storageManager", "config",
function(storageManager, config) {
  return new TicketManager(config.webathena, storageManager);
}]);

roostApp.service("api", ["config", "storageManager", "ticketManager",
function(config, storageManager, ticketManager) {
  return new API(config.server, config.serverPrincipal,
                 storageManager, ticketManager);
}]);

roostApp.directive("showModal", [function() {
  return {
    restrict: "A",
    link: function(scope, element, attrs) {
      scope.$watch(attrs.showModal, function(value) {
        element.modal(value ? "show" : "hide");
      });
    }
  };
}]);

roostApp.directive("focusOn", ["$parse", function($parse) {
  return {
    restrict: "A",
    link: function(scope, element, attrs) {
      var idx = attrs.focusOn.indexOf(";");
      var wait, condition;
      if (idx < 0) {
        wait = attrs.focusOn;
        condition = null;
      } else {
        wait = attrs.focusOn.substring(0, idx);
        condition = $parse(attrs.focusOn.substring(idx + 1));
      }

      scope.$watch(wait, function(newValue, oldValue) {
        newValue = !!newValue; oldValue = !!oldValue;
        if (newValue && newValue !== oldValue) {
          if (!condition || scope.$eval(condition)) {
            // Do it in an $evalAsync so that the DOM has had a chance
            // to react too.
            scope.$evalAsync(function() {
              element.focus();
            });
          }
        }
      });
    }
  }
}]);

roostApp.directive("onKeydown", ["$parse", function($parse) {
  return {
    restrict: "A",
    link: function(scope, element, attrs) {
      var fn = $parse(attrs.onKeydown);
      element.on("keydown", function(event) {
        scope.$apply(function() {
          fn(scope, {$event:event});
        });
      });
    }
  }
}]);

// TODO(davidben): Dumb thing to get rid of later.
roostApp.directive("randomColorKey", [function() {
  var COLORS = ["black", "maroon", "red",
                "purple", "fuchsia", "green", "blue"];
  return {
    restrict: "A",
    link: function(scope, element, attrs) {
      if (element[0].nodeType !== Node.ELEMENT_NODE)
        return;
      attrs.$observe("randomColorKey", function(value) {
        var hash = 0;
        for (var i = 0; i < value.length; i++) {
          // Dunno, borrowed from some random thing on the Internet
          // that claims to be Java's.
          hash = ((hash << 5) - hash + value.charCodeAt(i)) | 0;
        }
        hash = hash % COLORS.length;
        if (hash < 0)
          hash += COLORS.length;
        element[0].style.color = COLORS[hash];
      });
    }
  };
}]);

roostApp.directive("bindZtext", [function() {
  return {
    restrict: "A",
    link: function(scope, element, attrs) {
      attrs.$observe("bindZtext", function(value) {
        element.text("");
        element.append(ztextToDOM(parseZtext(value)));
      });
    }
  };
}]);

roostApp.filter("shortZuser", [function() {
  return shortZuser;
}]);
roostApp.filter("longZuser", [function() {
  return longZuser;
}]);
roostApp.filter("urlencode", [function() {
  return encodeURIComponent;
}]);

roostApp.controller("RoostController",
                    ["$scope", "storageManager", "ticketManager", "api",
function($scope, storageManager, ticketManager, api) {
  window.storageManager = storageManager;  // DEBUG
  window.ticketManager = ticketManager;  // DEBUG
  window.api = api;  // DEBUG

  $scope.principal = undefined;
  $scope.isLoggedIn = false;
  storageManager.principal().then(function(principal) {
    $scope.$apply(function() {
      $scope.principal = principal;
      $scope.isLoggedIn = true;
    });
  }).done();

  $scope.refreshTicketsInteractive = function() {
    ticketManager.refreshTickets({interactive: true});
  };

  $scope.ticketNeeded = false;
  ticketManager.addEventListener("ticket-needed", function(ev) {
    $scope.$apply(function() {
      $scope.ticketNeeded = true;
    });
    // Ticket no longer needed when we get our tickets.
    Q.all(
      [ticketManager.getTicket("server"), ticketManager.getTicket("zephyr")]
    ).then(function() {
      $scope.$apply(function() {
        $scope.ticketNeeded = false;
      });
    }).done();

    // TODO(davidben): check ev.data.nonModal for whether we should
    // pop open a modal dialog or not.
  });

  ticketManager.addEventListener("webathena-error", function() {
    console.log("Webathena error do something useful");
  });
  storageManager.addEventListener("usermismatch", function() {
    console.log("User mismatch do something useful");
  });

  // TODO(davidben): Move this to a separate controller?
  $scope.showReplyBox = false;
  $scope.focusClass = false;
  $scope.focusMessage = false;
  $scope.replyClass = "";
  $scope.replyInstance = "";
  $scope.replyRecipient = "";
  $scope.replyMessage = "";

  $scope.hideReplyBox = function() {
    $scope.showReplyBox = false;
    $scope.focusClass = $scope.focusMessage = false;

    $scope.replyClass = "";
    $scope.replyInstance = "";
    $scope.replyRecipient = "";
    $scope.replyMessage = "";
  };

  $scope.sendZwrite = function(msg) {
    var data = api.userInfo().ready().then(function() {
      var zsig = api.userInfo().get("zsig");
      zsig = (zsig == undefined) ? "Sent from Roost" : zsig;
      return {
        message: {
          class: msg.class,
          instance: msg.instance,
          recipient: msg.recipient,
          opcode: "",
          signature: zsig,
          message: msg.message
        }
      };
    });
    return api.post("/v1/zwrite", data, {
      withZephyr: true,
      interactive: true
    }).then(function(ret) {
      console.log("Sent:", ret.ack);
    }).finally(function() {
      $scope.$apply(function() {
        $scope.hideReplyBox();
      });
    }).done();
  };

  // TODO(davidben): This is a silly thing to put in a
  // controller. Pull in some fancy directive like angular-ui's
  // keypress.
  $scope.replyBoxKeydown = function(ev) {
    if (matchKey(ev, 27 /* ESC */)) {
      ev.preventDefault();
      $scope.hideReplyBox();
    }
  };

  $scope.model = new MessageModel(api);
  window.model = $scope.model;  // DEBUG

  window.addEventListener("keydown", function(ev) {
    if (ev.target !== document.body)
      return;

    if (matchKey(ev, 82 /* r */)) {
      var msg = $scope.selection;
      if (msg) {
        ev.preventDefault();
        $scope.$broadcast("ensureSelectionVisible");

        $scope.$apply(function() {
          $scope.showReplyBox = true;
          $scope.focusMessage = true;

          $scope.replyClass = (msg.classKey === "message") ? "" : msg.class;
          $scope.replyInstance =
            (msg.instanceKey === "personal") ? "" : msg.instance;
          if (msg.isPersonal && !msg.isOutgoing) {
            $scope.replyRecipient = msg.sender;
          } else {
            $scope.replyRecipient = msg.recipient;
          }
          $scope.replyRecipient = shortZuser($scope.replyRecipient);
        });
      }
    } else if (matchKey(ev, 90 /* z */)) {
      ev.preventDefault();

      $scope.$apply(function() {
        $scope.showReplyBox = true;
        $scope.focusClass = true;
      });
    }
  });

  $scope.scrollStates = [];
  api.userInfo().addEventListener("change", function() {
    $scope.$apply(function() {
      $scope.scrollStates = api.userInfo().scrollStates();
    });
  });

  var loadState = true;

  $scope.setScrollState = function(state) {
    $scope.$broadcast("setScrollState", state);
  };

  // Only save state when the user info is ready.
  api.userInfo().ready().then(function() {
    // Bootstrap everything, if needed.
    if (loadState) {
      var states = api.userInfo().scrollStates();
      if (states.length) {
        $scope.$broadcast("setScrollState", states[0]);
      } else {
        $scope.$broadcast("scrollToBottom");
      }
    }
    $scope.$broadcast("apiReady");
  }).done();

  $scope.$on("replaceScrollState", function(ev, oldState, state) {
    api.userInfo().replaceScrollState(oldState, state);
  });

  $scope.resetView = function() {
    // TODO(davidben): Figure out the right anchor! Probably the last
    // guy you clicked on if it's still in view? I dunno.
    $scope.$broadcast("changeFilter", new Filter({}));
  };

  if (/#msg-/.test(location.hash)) {
    loadState = false;
    $scope.$broadcast("scrollToMessage", location.hash.substring(5));
  }
  // Otherwise, we'll wait for api.ready() to tell us where to scroll
  // to.

  window.addEventListener("hashchange", function(ev) {
    if (/#msg-/.test(location.hash)) {
      $scope.$broadcast("scrollToMessage", location.hash.substring(5));
    }
  });
}]);
<commit_msg>Fix focus<commit_after>"use strict";

function matchKey(ev, keyCode, mods) {
  if (ev.keyCode != keyCode)
    return false;
  mods = mods || { };
  var modifiers = ["altKey", "altGraphKey", "ctrlKey", "metaKey", "shiftKey"];
  for (var i = 0; i < modifiers.length; i++) {
    if (Boolean(ev[modifiers[i]]) != Boolean(mods[modifiers[i]]))
      return false;
  }
  return true;
}

// TODO(davidben): Make all this code not terrible. Seriously.

var roostApp = angular.module("roostApp", []);

roostApp.value("config", CONFIG);

roostApp.service("localStorage", [function() {
  return new LocalStorageWrapper();
}]);

roostApp.service("storageManager", ["localStorage", function(localStorage) {
  return new StorageManager(localStorage);
}]);

roostApp.service("ticketManager", ["storageManager", "config",
function(storageManager, config) {
  return new TicketManager(config.webathena, storageManager);
}]);

roostApp.service("api", ["config", "storageManager", "ticketManager",
function(config, storageManager, ticketManager) {
  return new API(config.server, config.serverPrincipal,
                 storageManager, ticketManager);
}]);

roostApp.directive("showModal", [function() {
  return {
    restrict: "A",
    link: function(scope, element, attrs) {
      scope.$watch(attrs.showModal, function(value) {
        element.modal(value ? "show" : "hide");
      });
    }
  };
}]);

roostApp.directive("focusOn", ["$parse", function($parse) {
  return {
    restrict: "A",
    link: function(scope, element, attrs) {
      var idx = attrs.focusOn.indexOf(";");
      var wait, condition;
      if (idx < 0) {
        wait = attrs.focusOn;
        condition = null;
      } else {
        wait = attrs.focusOn.substring(0, idx);
        condition = $parse(attrs.focusOn.substring(idx + 1));
      }

      scope.$watch(wait, function(newValue, oldValue) {
        newValue = !!newValue; oldValue = !!oldValue;
        if (newValue && newValue !== oldValue) {
          if (!condition || scope.$eval(condition)) {
            // Do it in an $evalAsync so that the DOM has had a chance
            // to react too.
            scope.$evalAsync(function() {
              element.focus();
            });
          }
        }
      });
    }
  }
}]);

roostApp.directive("onKeydown", ["$parse", function($parse) {
  return {
    restrict: "A",
    link: function(scope, element, attrs) {
      var fn = $parse(attrs.onKeydown);
      element.on("keydown", function(event) {
        scope.$apply(function() {
          fn(scope, {$event:event});
        });
      });
    }
  }
}]);

// TODO(davidben): Dumb thing to get rid of later.
roostApp.directive("randomColorKey", [function() {
  var COLORS = ["black", "maroon", "red",
                "purple", "fuchsia", "green", "blue"];
  return {
    restrict: "A",
    link: function(scope, element, attrs) {
      if (element[0].nodeType !== Node.ELEMENT_NODE)
        return;
      attrs.$observe("randomColorKey", function(value) {
        var hash = 0;
        for (var i = 0; i < value.length; i++) {
          // Dunno, borrowed from some random thing on the Internet
          // that claims to be Java's.
          hash = ((hash << 5) - hash + value.charCodeAt(i)) | 0;
        }
        hash = hash % COLORS.length;
        if (hash < 0)
          hash += COLORS.length;
        element[0].style.color = COLORS[hash];
      });
    }
  };
}]);

roostApp.directive("bindZtext", [function() {
  return {
    restrict: "A",
    link: function(scope, element, attrs) {
      attrs.$observe("bindZtext", function(value) {
        element.text("");
        element.append(ztextToDOM(parseZtext(value)));
      });
    }
  };
}]);

roostApp.filter("shortZuser", [function() {
  return shortZuser;
}]);
roostApp.filter("longZuser", [function() {
  return longZuser;
}]);
roostApp.filter("urlencode", [function() {
  return encodeURIComponent;
}]);

roostApp.controller("RoostController",
                    ["$scope", "storageManager", "ticketManager", "api",
function($scope, storageManager, ticketManager, api) {
  window.storageManager = storageManager;  // DEBUG
  window.ticketManager = ticketManager;  // DEBUG
  window.api = api;  // DEBUG

  $scope.principal = undefined;
  $scope.isLoggedIn = false;
  storageManager.principal().then(function(principal) {
    $scope.$apply(function() {
      $scope.principal = principal;
      $scope.isLoggedIn = true;
    });
  }).done();

  $scope.refreshTicketsInteractive = function() {
    ticketManager.refreshTickets({interactive: true});
  };

  $scope.ticketNeeded = false;
  ticketManager.addEventListener("ticket-needed", function(ev) {
    $scope.$apply(function() {
      $scope.ticketNeeded = true;
    });
    // Ticket no longer needed when we get our tickets.
    Q.all(
      [ticketManager.getTicket("server"), ticketManager.getTicket("zephyr")]
    ).then(function() {
      $scope.$apply(function() {
        $scope.ticketNeeded = false;
      });
    }).done();

    // TODO(davidben): check ev.data.nonModal for whether we should
    // pop open a modal dialog or not.
  });

  ticketManager.addEventListener("webathena-error", function() {
    console.log("Webathena error do something useful");
  });
  storageManager.addEventListener("usermismatch", function() {
    console.log("User mismatch do something useful");
  });

  // TODO(davidben): Move this to a separate controller?
  $scope.showReplyBox = false;
  $scope.focusClass = false;
  $scope.focusMessage = false;
  $scope.replyClass = "";
  $scope.replyInstance = "";
  $scope.replyRecipient = "";
  $scope.replyMessage = "";

  $scope.hideReplyBox = function() {
    $scope.showReplyBox = false;
    $scope.focusClass = $scope.focusMessage = false;

    $scope.replyClass = "";
    $scope.replyInstance = "";
    $scope.replyRecipient = "";
    $scope.replyMessage = "";

    // TODO(davidben): Ugh, really?
    document.activeElement.blur();
  };

  $scope.sendZwrite = function(msg) {
    var data = api.userInfo().ready().then(function() {
      var zsig = api.userInfo().get("zsig");
      zsig = (zsig == undefined) ? "Sent from Roost" : zsig;
      return {
        message: {
          class: msg.class,
          instance: msg.instance,
          recipient: msg.recipient,
          opcode: "",
          signature: zsig,
          message: msg.message
        }
      };
    });
    return api.post("/v1/zwrite", data, {
      withZephyr: true,
      interactive: true
    }).then(function(ret) {
      console.log("Sent:", ret.ack);
    }).finally(function() {
      $scope.$apply(function() {
        $scope.hideReplyBox();
      });
    }).done();
  };

  // TODO(davidben): This is a silly thing to put in a
  // controller. Pull in some fancy directive like angular-ui's
  // keypress.
  $scope.replyBoxKeydown = function(ev) {
    if (matchKey(ev, 27 /* ESC */)) {
      ev.preventDefault();
      $scope.hideReplyBox();
    }
  };

  $scope.model = new MessageModel(api);
  window.model = $scope.model;  // DEBUG

  window.addEventListener("keydown", function(ev) {
    if (ev.target !== document.body)
      return;

    if (matchKey(ev, 82 /* r */)) {
      var msg = $scope.selection;
      if (msg) {
        ev.preventDefault();
        $scope.$broadcast("ensureSelectionVisible");

        $scope.$apply(function() {
          $scope.showReplyBox = true;
          $scope.focusMessage = true;

          $scope.replyClass = (msg.classKey === "message") ? "" : msg.class;
          $scope.replyInstance =
            (msg.instanceKey === "personal") ? "" : msg.instance;
          if (msg.isPersonal && !msg.isOutgoing) {
            $scope.replyRecipient = msg.sender;
          } else {
            $scope.replyRecipient = msg.recipient;
          }
          $scope.replyRecipient = shortZuser($scope.replyRecipient);
        });
      }
    } else if (matchKey(ev, 90 /* z */)) {
      ev.preventDefault();

      $scope.$apply(function() {
        $scope.showReplyBox = true;
        $scope.focusClass = true;
      });
    }
  });

  $scope.scrollStates = [];
  api.userInfo().addEventListener("change", function() {
    $scope.$apply(function() {
      $scope.scrollStates = api.userInfo().scrollStates();
    });
  });

  var loadState = true;

  $scope.setScrollState = function(state) {
    $scope.$broadcast("setScrollState", state);
  };

  // Only save state when the user info is ready.
  api.userInfo().ready().then(function() {
    // Bootstrap everything, if needed.
    if (loadState) {
      var states = api.userInfo().scrollStates();
      if (states.length) {
        $scope.$broadcast("setScrollState", states[0]);
      } else {
        $scope.$broadcast("scrollToBottom");
      }
    }
    $scope.$broadcast("apiReady");
  }).done();

  $scope.$on("replaceScrollState", function(ev, oldState, state) {
    api.userInfo().replaceScrollState(oldState, state);
  });

  $scope.resetView = function() {
    // TODO(davidben): Figure out the right anchor! Probably the last
    // guy you clicked on if it's still in view? I dunno.
    $scope.$broadcast("changeFilter", new Filter({}));
  };

  if (/#msg-/.test(location.hash)) {
    loadState = false;
    $scope.$broadcast("scrollToMessage", location.hash.substring(5));
  }
  // Otherwise, we'll wait for api.ready() to tell us where to scroll
  // to.

  window.addEventListener("hashchange", function(ev) {
    if (/#msg-/.test(location.hash)) {
      $scope.$broadcast("scrollToMessage", location.hash.substring(5));
    }
  });
}]);
<|endoftext|>


<commit_before>'use strict';

const db = require('./db');

const tokens = require('../tokens');
const Big = require('big.js');

const networks = [
  'bitcoin',
  'bitcoincash',
  'bitcoinsv',
  'litecoin',
  'dogecoin',
  'dash',
];

function get(network) {
  if (networks.indexOf(network) === -1) {
    return Promise.reject({ error: 'Currency cs fee is not supported' });
  }

  const collection = db().collection('cs_fee');

  return Promise.all([
    tokens.getTicker(network),
    collection.find({ _id: network }).limit(1).next(),
  ]).then((results) => {
    const rate = results[0]['prices']['USD'];
    let minFee = 0;
    let maxFee = 0;
    let rbfFee = 0;
    if (rate > 0) {
      minFee = parseInt(Big(1).div(rate).times(results[1].min_usd).times(1e8), 10);
      maxFee = parseInt(Big(1).div(rate).times(results[1].max_usd).times(1e8), 10);
      rbfFee = parseInt(Big(1).div(rate).times(results[1].rbf_usd).times(1e8), 10);
    }
    return {
      minFee,
      maxFee,
      fee: results[1].fee,
      rbfFee,
      addresses: results[1].addresses,
      whitelist: results[1].whitelist,
    };
  });
}

module.exports = {
  get,
};
<commit_msg>fix: csFee BigError<commit_after>'use strict';

const db = require('./db');

const tokens = require('../tokens');
const Big = require('big.js');

const networks = [
  'bitcoin',
  'bitcoincash',
  'bitcoinsv',
  'litecoin',
  'dogecoin',
  'dash',
];

function get(network) {
  if (networks.indexOf(network) === -1) {
    return Promise.reject({ error: 'Currency cs fee is not supported' });
  }

  const collection = db().collection('cs_fee');

  return Promise.all([
    tokens.getTicker(network),
    collection.find({ _id: network }).limit(1).next(),
  ]).then((results) => {
    const rate = results[0]['prices']['USD'];
    let minFee = 0;
    let maxFee = 0;
    let rbfFee = 0;
    if (rate > 0) {
      minFee = parseInt(Big(1).div(rate).times(results[1].min_usd).times(1e8), 10);
      maxFee = parseInt(Big(1).div(rate).times(results[1].max_usd).times(1e8), 10);
      rbfFee = parseInt(Big(1).div(rate).times(results[1].rbf_usd || 0).times(1e8), 10);
    }
    return {
      minFee,
      maxFee,
      fee: results[1].fee,
      rbfFee,
      addresses: results[1].addresses,
      whitelist: results[1].whitelist,
    };
  });
}

module.exports = {
  get,
};
<|endoftext|>


<commit_before>/* globals Meteor, fileUpload, Tracker, RocketChat */
'use strict';

var IPC = require('electron').ipcRenderer;

class Notification extends window.Notification {
    get onclick() {
        return super.onclick;
    }

    set onclick(fn) {
        var result = super.onclick = () => {
            IPC.sendToHost('focus');
            fn.apply(this, arguments);
        };
        return result;
    }
}

window.Notification = Notification;

function dataURItoArrayBuffer(dataURI) {
    var byteString = atob(dataURI.split(',')[1]);

    var ab = new ArrayBuffer(byteString.length);
    var ia = new Uint8Array(ab);
    for (var i = 0; i < byteString.length; i++) {
      ia[i] = byteString.charCodeAt(i);
    }

    return ab;
}

IPC.on('upload-file', function(sender, value) {
    value.forEach(function(item) {
        item.file = new File([dataURItoArrayBuffer(item.dataUrl)], item.name, {type: item.type});
    });
    console.log(value);
    fileUpload(value);
    document.querySelector('.dropzone').classList.remove('over');
});

var events = ['unread-changed'];

events.forEach(function(e) {
    window.addEventListener(e, function(event) {
        IPC.sendToHost(e, event.detail);
    });
});

window.addEventListener('load', function() {
    Meteor.startup(function() {
        Tracker.autorun(function() {
            var siteName = RocketChat.settings.get('Site_Name');
            if (siteName) {
                IPC.sendToHost('title-changed', siteName);
            }
        });
    });
});

var shell = require('shell');

var supportExternalLinks = function(e) {
    var href;
    var isExternal = false;

    var checkDomElement = function(element) {
        if (element.nodeName === 'A') {
            if (element.classList.contains('swipebox') === false) {
                href = element.getAttribute('href') || '';
            }
        }

        if (/^https?:\/\/.+/.test(href) === true /*&& RegExp('^https?:\/\/'+location.host).test(href) === false*/ ) {
            isExternal = true;
        }

        if (href && isExternal) {
            shell.openExternal(href);
            e.preventDefault();
        } else if (element.parentElement) {
            checkDomElement(element.parentElement);
        }
    };

    checkDomElement(e.target);
};

document.addEventListener('click', supportExternalLinks, false);

var webFrame = require('web-frame');
var remote = require('remote');
var webContents = remote.getCurrentWebContents();
var Menu = remote.require('menu');
var menu = new Menu();

// set the initial context menu so that a context menu exists even before spellcheck is called
var getTemplate = function() {
    return [
        {
            label: 'Undo',
            selector: 'undo:'
        },
        {
            label: 'Redo',
            selector: 'redo:'
        },
        {
            type: 'separator'
        },
        {
            label: 'Cut',
            selector: 'cut:'
        },
        {
            label: 'Copy',
            selector: 'copy:'
        },
        {
            label: 'Paste',
            selector: 'paste:'
        },
        {
            label: 'Select All',
            selector: 'selectAll:'
        }
    ];
};

var template = getTemplate();
menu = Menu.buildFromTemplate(getTemplate());

window.addEventListener('contextmenu', function(){
    menu.popup(remote.getCurrentWindow());
    menu = Menu.buildFromTemplate(template);
}, false);

try {
    var checker = require('spellchecker');

    webFrame.setSpellCheckProvider((localStorage.getItem('userLanguage') || 'en'), false, {
        spellCheck: function(text) {
            if (localStorage.getItem('userLanguage')) {
                checker.setDictionary(localStorage.getItem('userLanguage'));
            }

            var isMisspelled = checker.isMisspelled(text);

            if (isMisspelled) {
                var options = checker.getCorrectionsForMisspelling(text);
                var maxItems = Math.min(options.length, 5);
                template.unshift({type: 'separator'});
                if (maxItems > 0) {
                    var onClick = function(menuItem) {
                        webContents.replaceMisspelling(menuItem.label);
                    };
                    for (var i = maxItems-1; i >= 0; i--) {
                        var item = options[i];
                        template.unshift({ label: item, click: onClick});
                    }
                } else {
                    template.unshift({ label: 'no suggestions', click: function() { } });
                }
            }
            menu = Menu.buildFromTemplate(template);
            template = getTemplate();

            return !isMisspelled;
        }
    });
} catch(e) {
    console.log('Spellchecker unavailble');
}
<commit_msg>Only set spell check dictionary if there are dictionaries<commit_after>/* globals Meteor, fileUpload, Tracker, RocketChat */
'use strict';

var IPC = require('electron').ipcRenderer;

class Notification extends window.Notification {
    get onclick() {
        return super.onclick;
    }

    set onclick(fn) {
        var result = super.onclick = () => {
            IPC.sendToHost('focus');
            fn.apply(this, arguments);
        };
        return result;
    }
}

window.Notification = Notification;

function dataURItoArrayBuffer(dataURI) {
    var byteString = atob(dataURI.split(',')[1]);

    var ab = new ArrayBuffer(byteString.length);
    var ia = new Uint8Array(ab);
    for (var i = 0; i < byteString.length; i++) {
      ia[i] = byteString.charCodeAt(i);
    }

    return ab;
}

IPC.on('upload-file', function(sender, value) {
    value.forEach(function(item) {
        item.file = new File([dataURItoArrayBuffer(item.dataUrl)], item.name, {type: item.type});
    });
    console.log(value);
    fileUpload(value);
    document.querySelector('.dropzone').classList.remove('over');
});

var events = ['unread-changed'];

events.forEach(function(e) {
    window.addEventListener(e, function(event) {
        IPC.sendToHost(e, event.detail);
    });
});

window.addEventListener('load', function() {
    Meteor.startup(function() {
        Tracker.autorun(function() {
            var siteName = RocketChat.settings.get('Site_Name');
            if (siteName) {
                IPC.sendToHost('title-changed', siteName);
            }
        });
    });
});

var shell = require('shell');

var supportExternalLinks = function(e) {
    var href;
    var isExternal = false;

    var checkDomElement = function(element) {
        if (element.nodeName === 'A') {
            if (element.classList.contains('swipebox') === false) {
                href = element.getAttribute('href') || '';
            }
        }

        if (/^https?:\/\/.+/.test(href) === true /*&& RegExp('^https?:\/\/'+location.host).test(href) === false*/ ) {
            isExternal = true;
        }

        if (href && isExternal) {
            shell.openExternal(href);
            e.preventDefault();
        } else if (element.parentElement) {
            checkDomElement(element.parentElement);
        }
    };

    checkDomElement(e.target);
};

document.addEventListener('click', supportExternalLinks, false);

var webFrame = require('web-frame');
var remote = require('remote');
var webContents = remote.getCurrentWebContents();
var Menu = remote.require('menu');
var menu = new Menu();

// set the initial context menu so that a context menu exists even before spellcheck is called
var getTemplate = function() {
    return [
        {
            label: 'Undo',
            selector: 'undo:'
        },
        {
            label: 'Redo',
            selector: 'redo:'
        },
        {
            type: 'separator'
        },
        {
            label: 'Cut',
            selector: 'cut:'
        },
        {
            label: 'Copy',
            selector: 'copy:'
        },
        {
            label: 'Paste',
            selector: 'paste:'
        },
        {
            label: 'Select All',
            selector: 'selectAll:'
        }
    ];
};

var template = getTemplate();
menu = Menu.buildFromTemplate(getTemplate());

window.addEventListener('contextmenu', function(){
    menu.popup(remote.getCurrentWindow());
    menu = Menu.buildFromTemplate(template);
}, false);

try {
    var checker = require('spellchecker');

    webFrame.setSpellCheckProvider((localStorage.getItem('userLanguage') || 'en'), false, {
        spellCheck: function(text) {
            if (localStorage.getItem('userLanguage') && checker.getAvailableDictionaries().length > 0) {
                checker.setDictionary(localStorage.getItem('userLanguage'));
            }

            var isMisspelled = checker.isMisspelled(text);

            if (isMisspelled) {
                var options = checker.getCorrectionsForMisspelling(text);
                var maxItems = Math.min(options.length, 5);
                template.unshift({type: 'separator'});
                if (maxItems > 0) {
                    var onClick = function(menuItem) {
                        webContents.replaceMisspelling(menuItem.label);
                    };
                    for (var i = maxItems-1; i >= 0; i--) {
                        var item = options[i];
                        template.unshift({ label: item, click: onClick});
                    }
                } else {
                    template.unshift({ label: 'no suggestions', click: function() { } });
                }
            }
            menu = Menu.buildFromTemplate(template);
            template = getTemplate();

            return !isMisspelled;
        }
    });
} catch(e) {
    console.log('Spellchecker unavailble');
}
<|endoftext|>