<commit_before>
/**
 * IPC keys.
 * @type {Object}
 */
export const IPCKeys = {
  RequestShowMessage: 'requestShowMessage',
  FinishShowMessage:  'finishShowMessage',

  RequestShowOpenDialog: 'requestShowOpenDialog',
  FinishShowOpenDialog:  'finishShowOpenDialog',

  RequestReadMusicMetadata: 'requestReadMusicMetadata',
  FinishReadMusicMetadata:  'finishReadMusicMetadata',

  RequestShowGraphicEqualizer: 'requestShowGraphicEqualizer',
  FinishShowGraphicEqualizer:  'finishShowGraphicEqualizer',

  RequestConnectGraphicEqualizer: 'requestConnectGraphicEqualizer',
  FinishConnectGraphicEqualizer:  'finishConnectGraphicEqualizer',

  RequestUpdateGraphicEqualizer: 'requestUpdateGraphicEqualizer',
  FinishUpdateGraphicEqualizer:  'finishUpdateGraphicEqualizer'
};

/**
 * Defines the key of the Web Storage.
 * @type {Object}
 */
export const StorageKeys = {
  GraphicEqulizerParams: 'graphicEqulizerParams'
};

/**
 * Audio playback status.
 * @type {Object}
 */
export const PlaybackState = {
  Stopped: 0,
  Paused: 1,
  Playing: 2
};

/**
 * Define the parameters of graphic equalizer.
 * @type {Object}
 */
export const GraphicEqulizerParams = {
  GainMin: -40,
  GainMax: 40,
  GainStep: 5,
  CenterFrequency: 31.25,
  Bands: 10
};
<commit_msg>#45 Remove constants that are not used<commit_after>
/**
 * IPC keys.
 * @type {Object}
 */
export const IPCKeys = {
  RequestShowMessage: 'requestShowMessage',
  FinishShowMessage:  'finishShowMessage',

  RequestShowOpenDialog: 'requestShowOpenDialog',
  FinishShowOpenDialog:  'finishShowOpenDialog',

  RequestReadMusicMetadata: 'requestReadMusicMetadata',
  FinishReadMusicMetadata:  'finishReadMusicMetadata',

  RequestUpdateGraphicEqualizer: 'requestUpdateGraphicEqualizer',
  FinishUpdateGraphicEqualizer:  'finishUpdateGraphicEqualizer'
};

/**
 * Defines the key of the Web Storage.
 * @type {Object}
 */
export const StorageKeys = {
  GraphicEqulizerParams: 'graphicEqulizerParams'
};

/**
 * Audio playback status.
 * @type {Object}
 */
export const PlaybackState = {
  Stopped: 0,
  Paused: 1,
  Playing: 2
};

/**
 * Define the parameters of graphic equalizer.
 * @type {Object}
 */
export const GraphicEqulizerParams = {
  GainMin: -40,
  GainMax: 40,
  GainStep: 5,
  CenterFrequency: 31.25,
  Bands: 10
};
<|endoftext|>


<commit_before>'use strict';
//TODO it may be good to integrate d3 in a more 'angular', e.g. using directives
/* global d3: false */
/* global moment: false */

angular.module('openhimWebui2App')
  .controller('VisualizerCtrl', function ($scope, $http, $interval, login, Api, Alerting) {

    $scope.loadingVisualizer = true;
    $scope.loadingVisualizerError = false;
    $scope.loadingVisualizerErrorMsgs = [];

    // initialize global variables
    var registries = [];
    var endpoints = [];
    var himRect, himText, visW, visH, pad, himX, himY, himW, himH, inactiveColor, activeColor, errorColor, textColor;
    var visualizerUpdateInterval, updatePeriod, diffTime, lastUpdate, speed, maxSpeed, maxTimeout, vis;

    var consoleSession = localStorage.getItem('consoleSession');
    consoleSession = JSON.parse(consoleSession);
    $scope.consoleSession = consoleSession;

    // get the user settings to construct the visualizer
    Api.Users.get({ email: $scope.consoleSession.sessionUser }, function(user){

      // user doesnt have settings saved
      if ( !user.settings ){
        $scope.loadingVisualizerError = true;
        $scope.loadingVisualizer = false;
        $scope.loadingVisualizerErrorMsgs.push({ section: 'Settings Error', msg: 'There appear to be no settings saved for this user. Please save the user settings' });
        return
      }

      var visSettings = user.settings.visualizer;

      /********** Visualizations Management **********/
      // setup components (registries)
      angular.forEach(visSettings.components, function(component){
        registries.push({ comp: component.event, desc: component.desc });
      });

      // setup endpoints
      angular.forEach(visSettings.endpoints, function(endpoint){
        endpoints.push({ comp: endpoint.event, desc: endpoint.desc });
      });

      // check if components and registries have events
      if ( registries.length === 0 || endpoints.length === 0 ){
        $scope.loadingVisualizerError = true;
        $scope.loadingVisualizer = false;
        $scope.loadingVisualizerErrorMsgs.push({ section: 'Visualizations Management', msg: 'Please ensure your visualizer has atleast one Component and one Endpoint added!' });
      }
      /********** Visualizations Management **********/

      /********** Size Management **********/
      visW = parseInt( visSettings.size.width );
      visH = parseInt( visSettings.size.height );
      pad = parseInt( visSettings.size.padding );

      himX = 0 + pad;
      himY = visH/2.0;
      himW = visW - 2.0*pad;
      himH = visH/4.0 - 2.0*pad;

      // check if config not empty
      if ( !visW || !visH || !pad ){
        $scope.loadingVisualizerError = true;
        $scope.loadingVisualizer = false;
        $scope.loadingVisualizerErrorMsgs.push({ section: 'Size Management', msg: 'Please ensure all size management fields are supplied!' });
      }
      /********** Size Management **********/

      /********** Color Management **********/
      inactiveColor = '#'+visSettings.color.inactive;
      activeColor = '#'+visSettings.color.active;
      errorColor = '#'+visSettings.color.error;
      textColor = '#'+visSettings.color.text;

      // check if config not empty
      if ( inactiveColor === '#' || activeColor === '#' || errorColor === '#' || textColor === '#' ){
        $scope.loadingVisualizerError = true;
        $scope.loadingVisualizer = false;
        $scope.loadingVisualizerErrorMsgs.push({ section: 'Color Management', msg: 'Please ensure all color management fields are supplied!' });
      }
      /********** Color Management **********/

      /********** Time Management **********/
      //How often to fetch updates from the server (in millis)
      updatePeriod = parseInt( visSettings.time.updatePeriod );

      //play speed; 0 = normal, -1 = 2X slower, -2 = 3X slower, 1 = 2X faster, etc.
      speed = 0;
      maxSpeed = parseInt( visSettings.time.maxSpeed );
      maxTimeout = parseInt( visSettings.time.maxTimeout );

      // check if config not empty
      if ( !updatePeriod || !maxSpeed || !maxTimeout ){
        $scope.loadingVisualizerError = true;
        $scope.loadingVisualizer = false;
        $scope.loadingVisualizerErrorMsgs.push({ section: 'Speed Management', msg: 'Please ensure all speed management fields are supplied!' });
      }
      /********** Time Management **********/

      if ( $scope.loadingVisualizer === true ){

        // visualizer loaded - change state
        $scope.loadingVisualizer = false;

        /* execute the visualizer code */
        vis = d3.select('#visualizer')
          .append('svg:svg')
          .attr('width', visW)
          .attr('height', visH);

        setupHIM(vis);
        setupRegistries(vis);
        setupEndpoints(vis);

        sync();
        /* execute the visualizer code */
      }

    }, function(err){
      $scope.loadingVisualizer = false;
      // on error - add server error alert
      Alerting.AlertAddServerMsg(err.status);
    });

    var getRegistryRect = function getRegistryRect(name) {
      for (var i=0; i<registries.length; i++) {
        if (registries[i].comp.toLowerCase() === name.toLowerCase()) {
          return registries[i].rect;
        }
      }
      return null;
    };

    var getEndpointText = function getEndpointText(name) {
      for (var i=0; i<endpoints.length; i++) {
        if (endpoints[i].comp.toLowerCase() === name.toLowerCase()) {
          return endpoints[i].text;
        }
      }
      return null;
    };

    /* Component Drawing */

    var setupBasicComponent = function setupBasicComponent(compRect, compText, x, y, w, h, text) {
      compRect
        .attr('rx', 6)
        .attr('ry', 6)
        .attr('x', x)
        .attr('y', y)
        .attr('width', w)
        .attr('height', h)
        .style('fill', inactiveColor);

      var textSize = h/3.5;
      compText
        .attr('x', x + w/2.0)
        .attr('y', y + h/2.0 + textSize/2.0)
        .attr('text-anchor', 'middle')
        .attr('font-size', textSize)
        .text(text)
        .style('fill', textColor);
    };

    var setupRegistryComponent = function setupRegistryComponent(compRect, compText, compConnector, index, text) {
      var compW = visW/registries.length - 2.0*pad,
        compH = visH/4.0 - 2.0*pad;
      var compX = index*compW + pad + index*pad*2.0,
        compY = 0 + pad;

      setupBasicComponent(compRect, compText, compX, compY, compW, compH, text);

      compConnector
        .attr('x1', compX + compW/2.0)
        .attr('y1', compY + compH)
        .attr('x2', compX + compW/2.0)
        .attr('y2', himY)
        .style('stroke-width', visW/150.0)
        .style('stroke', '#ddd');
    };

    var setupEndpointText = function setupEndpointText(compText, index, text) {
      var compW = visW/endpoints.length - 2.0*pad,
        compH = (visH/4.0 - 2.0*pad) / 3.0;
      var compX = index*compW + pad + index*pad*2.0,
        compY = visH - pad;

      compText
        .attr('x', compX + compW/2.0)
        .attr('y', compY)
        .attr('text-anchor', 'middle')
        .attr('font-size', compH)
        .text(text)
        .style('fill', inactiveColor);
    };

    var setupHIM = function setupHIM(vis) {
      himRect = vis.append('svg:rect');
      himText = vis.append('svg:text');
      setupBasicComponent(himRect, himText, himX, himY, himW, himH, 'Health Information Mediator');

      vis.append('svg:rect')
        .attr('rx', 6)
        .attr('ry', 6)
        .attr('x', 0 + pad)
        .attr('y', visH*3.0/4.0)
        .attr('width', visW - 2.0*pad)
        .attr('height', visH/50.0)
        .style('fill', inactiveColor);
    };

    var setupRegistries = function setupRegistries(vis) {
      for (var i=0; i<registries.length; i++) {
        registries[i].rect = vis.append('svg:rect');
        registries[i].text = vis.append('svg:text');
        registries[i].line = vis.append('svg:line');
        setupRegistryComponent(registries[i].rect, registries[i].text, registries[i].line, i, registries[i].desc);
      }
    };

    var setupEndpoints = function setupEndpoints(vis) {
      for (var i=0; i<endpoints.length; i++) {
        endpoints[i].text = vis.append('svg:text');
        setupEndpointText(endpoints[i].text, i, endpoints[i].desc);
      }
    };

    /* Animation */

    var animateComp = function animateComp(comp, ev, delay, isError) {
      var color;
      var delayMultiplier = 1.0;

      if (ev.toLowerCase() === 'start') {
        color = activeColor;
      } else if (isError) {
        color = errorColor;
      } else {
        color = inactiveColor;
      }

      if (speed<0) {
        delayMultiplier = -1.0*speed + 1.0;
      } else if (speed>0) {
        delayMultiplier = 1.0 / (speed + 1.0);
      }

      comp
        .transition()
        .delay(delay * delayMultiplier)
        .style('fill', color);

      if (ev.toLowerCase() === 'start' || isError) {

        var timeout;
        if ( isError ){
          timeout = 1000;
        }else{
          timeout = maxTimeout;
        }

        comp
          .transition()
          .delay(delay * delayMultiplier + timeout)
          .style('fill', inactiveColor);
      }
    };

    var processEvents = function processEvents(data) {
      if (data.length === 0) {
        return;
      }

      var baseTime = data[0].ts;
      var isErrorStatus = function(status) {
        return typeof status !== 'undefined' && status !== null && status.toLowerCase() === 'error';
      };

      angular.forEach(data, function(item) {
        var comp = null;

        comp = getRegistryRect(item.comp);
        if (comp === null) {
          comp = getEndpointText(item.comp);
          if (typeof comp !== 'undefined' && comp !== null) {
            animateComp(comp, item.ev, item.ts-baseTime, isErrorStatus(item.status));
            animateComp(himRect, item.ev, item.ts-baseTime, isErrorStatus(item.status));
          }
        } else {
          animateComp(comp, item.ev, item.ts-baseTime, isErrorStatus(item.status));
        }
      });
    };

    var play = function play() {
      $scope.showPlay = false;
      $scope.showPause = true;

      lastUpdate = (Date.now()-diffTime);
      visualizerUpdateInterval = $interval( function() {
        Api.VisualizerEvents.get({ receivedTime: lastUpdate}, function (events) {
          processEvents(events.events);
          lastUpdate = (Date.now()-diffTime);
        });
      }, updatePeriod);
    };

    var cancelVisualizerUpdateInterval = function() {
      if (angular.isDefined(visualizerUpdateInterval)) {
        $interval.cancel(visualizerUpdateInterval);
        visualizerUpdateInterval = undefined;
      }
    };

    $scope.play = play;

    $scope.pause = function pause() {
      $scope.showPlay = true;
      $scope.showPause = false;
      cancelVisualizerUpdateInterval();
    };

    $scope.$on('$destroy', cancelVisualizerUpdateInterval);

    var sync = function sync() {
      Api.VisualizerSync.get(function (sync) {
        diffTime = Date.now() - moment(sync.now);
        play();
      });
    };

    $scope.slowDown = function slowDown() {
      if (speed>-1*maxSpeed+1) {
        speed--;
      }
      $scope.speedText = speedText();
    };

    $scope.speedUp = function speedUp() {
      if (speed<maxSpeed-1) {
        speed++;
      }
      $scope.speedText = speedText();
    };

    var speedText = function speedText() {
      if (speed === 0) {
        return '';
      } else if (speed<0) {
        return (-1*speed+1) + 'X Slower';
      } else if (speed>0) {
        return (speed+1) + 'X Faster';
      }
    };

  });
<commit_msg>Fixed JSHint error<commit_after>'use strict';
//TODO it may be good to integrate d3 in a more 'angular', e.g. using directives
/* global d3: false */
/* global moment: false */

angular.module('openhimWebui2App')
  .controller('VisualizerCtrl', function ($scope, $http, $interval, login, Api, Alerting) {

    $scope.loadingVisualizer = true;
    $scope.loadingVisualizerError = false;
    $scope.loadingVisualizerErrorMsgs = [];

    // initialize global variables
    var registries = [];
    var endpoints = [];
    var himRect, himText, visW, visH, pad, himX, himY, himW, himH, inactiveColor, activeColor, errorColor, textColor;
    var visualizerUpdateInterval, updatePeriod, diffTime, lastUpdate, speed, maxSpeed, maxTimeout, vis;

    var consoleSession = localStorage.getItem('consoleSession');
    consoleSession = JSON.parse(consoleSession);
    $scope.consoleSession = consoleSession;

    // get the user settings to construct the visualizer
    Api.Users.get({ email: $scope.consoleSession.sessionUser }, function(user){

      // user doesnt have settings saved
      if ( !user.settings ){
        $scope.loadingVisualizerError = true;
        $scope.loadingVisualizer = false;
        $scope.loadingVisualizerErrorMsgs.push({ section: 'Settings Error', msg: 'There appear to be no settings saved for this user. Please save the user settings' });
        return;
      }

      var visSettings = user.settings.visualizer;

      /********** Visualizations Management **********/
      // setup components (registries)
      angular.forEach(visSettings.components, function(component){
        registries.push({ comp: component.event, desc: component.desc });
      });

      // setup endpoints
      angular.forEach(visSettings.endpoints, function(endpoint){
        endpoints.push({ comp: endpoint.event, desc: endpoint.desc });
      });

      // check if components and registries have events
      if ( registries.length === 0 || endpoints.length === 0 ){
        $scope.loadingVisualizerError = true;
        $scope.loadingVisualizer = false;
        $scope.loadingVisualizerErrorMsgs.push({ section: 'Visualizations Management', msg: 'Please ensure your visualizer has atleast one Component and one Endpoint added!' });
      }
      /********** Visualizations Management **********/

      /********** Size Management **********/
      visW = parseInt( visSettings.size.width );
      visH = parseInt( visSettings.size.height );
      pad = parseInt( visSettings.size.padding );

      himX = 0 + pad;
      himY = visH/2.0;
      himW = visW - 2.0*pad;
      himH = visH/4.0 - 2.0*pad;

      // check if config not empty
      if ( !visW || !visH || !pad ){
        $scope.loadingVisualizerError = true;
        $scope.loadingVisualizer = false;
        $scope.loadingVisualizerErrorMsgs.push({ section: 'Size Management', msg: 'Please ensure all size management fields are supplied!' });
      }
      /********** Size Management **********/

      /********** Color Management **********/
      inactiveColor = '#'+visSettings.color.inactive;
      activeColor = '#'+visSettings.color.active;
      errorColor = '#'+visSettings.color.error;
      textColor = '#'+visSettings.color.text;

      // check if config not empty
      if ( inactiveColor === '#' || activeColor === '#' || errorColor === '#' || textColor === '#' ){
        $scope.loadingVisualizerError = true;
        $scope.loadingVisualizer = false;
        $scope.loadingVisualizerErrorMsgs.push({ section: 'Color Management', msg: 'Please ensure all color management fields are supplied!' });
      }
      /********** Color Management **********/

      /********** Time Management **********/
      //How often to fetch updates from the server (in millis)
      updatePeriod = parseInt( visSettings.time.updatePeriod );

      //play speed; 0 = normal, -1 = 2X slower, -2 = 3X slower, 1 = 2X faster, etc.
      speed = 0;
      maxSpeed = parseInt( visSettings.time.maxSpeed );
      maxTimeout = parseInt( visSettings.time.maxTimeout );

      // check if config not empty
      if ( !updatePeriod || !maxSpeed || !maxTimeout ){
        $scope.loadingVisualizerError = true;
        $scope.loadingVisualizer = false;
        $scope.loadingVisualizerErrorMsgs.push({ section: 'Speed Management', msg: 'Please ensure all speed management fields are supplied!' });
      }
      /********** Time Management **********/

      if ( $scope.loadingVisualizer === true ){

        // visualizer loaded - change state
        $scope.loadingVisualizer = false;

        /* execute the visualizer code */
        vis = d3.select('#visualizer')
          .append('svg:svg')
          .attr('width', visW)
          .attr('height', visH);

        setupHIM(vis);
        setupRegistries(vis);
        setupEndpoints(vis);

        sync();
        /* execute the visualizer code */
      }

    }, function(err){
      $scope.loadingVisualizer = false;
      // on error - add server error alert
      Alerting.AlertAddServerMsg(err.status);
    });

    var getRegistryRect = function getRegistryRect(name) {
      for (var i=0; i<registries.length; i++) {
        if (registries[i].comp.toLowerCase() === name.toLowerCase()) {
          return registries[i].rect;
        }
      }
      return null;
    };

    var getEndpointText = function getEndpointText(name) {
      for (var i=0; i<endpoints.length; i++) {
        if (endpoints[i].comp.toLowerCase() === name.toLowerCase()) {
          return endpoints[i].text;
        }
      }
      return null;
    };

    /* Component Drawing */

    var setupBasicComponent = function setupBasicComponent(compRect, compText, x, y, w, h, text) {
      compRect
        .attr('rx', 6)
        .attr('ry', 6)
        .attr('x', x)
        .attr('y', y)
        .attr('width', w)
        .attr('height', h)
        .style('fill', inactiveColor);

      var textSize = h/3.5;
      compText
        .attr('x', x + w/2.0)
        .attr('y', y + h/2.0 + textSize/2.0)
        .attr('text-anchor', 'middle')
        .attr('font-size', textSize)
        .text(text)
        .style('fill', textColor);
    };

    var setupRegistryComponent = function setupRegistryComponent(compRect, compText, compConnector, index, text) {
      var compW = visW/registries.length - 2.0*pad,
        compH = visH/4.0 - 2.0*pad;
      var compX = index*compW + pad + index*pad*2.0,
        compY = 0 + pad;

      setupBasicComponent(compRect, compText, compX, compY, compW, compH, text);

      compConnector
        .attr('x1', compX + compW/2.0)
        .attr('y1', compY + compH)
        .attr('x2', compX + compW/2.0)
        .attr('y2', himY)
        .style('stroke-width', visW/150.0)
        .style('stroke', '#ddd');
    };

    var setupEndpointText = function setupEndpointText(compText, index, text) {
      var compW = visW/endpoints.length - 2.0*pad,
        compH = (visH/4.0 - 2.0*pad) / 3.0;
      var compX = index*compW + pad + index*pad*2.0,
        compY = visH - pad;

      compText
        .attr('x', compX + compW/2.0)
        .attr('y', compY)
        .attr('text-anchor', 'middle')
        .attr('font-size', compH)
        .text(text)
        .style('fill', inactiveColor);
    };

    var setupHIM = function setupHIM(vis) {
      himRect = vis.append('svg:rect');
      himText = vis.append('svg:text');
      setupBasicComponent(himRect, himText, himX, himY, himW, himH, 'Health Information Mediator');

      vis.append('svg:rect')
        .attr('rx', 6)
        .attr('ry', 6)
        .attr('x', 0 + pad)
        .attr('y', visH*3.0/4.0)
        .attr('width', visW - 2.0*pad)
        .attr('height', visH/50.0)
        .style('fill', inactiveColor);
    };

    var setupRegistries = function setupRegistries(vis) {
      for (var i=0; i<registries.length; i++) {
        registries[i].rect = vis.append('svg:rect');
        registries[i].text = vis.append('svg:text');
        registries[i].line = vis.append('svg:line');
        setupRegistryComponent(registries[i].rect, registries[i].text, registries[i].line, i, registries[i].desc);
      }
    };

    var setupEndpoints = function setupEndpoints(vis) {
      for (var i=0; i<endpoints.length; i++) {
        endpoints[i].text = vis.append('svg:text');
        setupEndpointText(endpoints[i].text, i, endpoints[i].desc);
      }
    };

    /* Animation */

    var animateComp = function animateComp(comp, ev, delay, isError) {
      var color;
      var delayMultiplier = 1.0;

      if (ev.toLowerCase() === 'start') {
        color = activeColor;
      } else if (isError) {
        color = errorColor;
      } else {
        color = inactiveColor;
      }

      if (speed<0) {
        delayMultiplier = -1.0*speed + 1.0;
      } else if (speed>0) {
        delayMultiplier = 1.0 / (speed + 1.0);
      }

      comp
        .transition()
        .delay(delay * delayMultiplier)
        .style('fill', color);

      if (ev.toLowerCase() === 'start' || isError) {

        var timeout;
        if ( isError ){
          timeout = 1000;
        }else{
          timeout = maxTimeout;
        }

        comp
          .transition()
          .delay(delay * delayMultiplier + timeout)
          .style('fill', inactiveColor);
      }
    };

    var processEvents = function processEvents(data) {
      if (data.length === 0) {
        return;
      }

      var baseTime = data[0].ts;
      var isErrorStatus = function(status) {
        return typeof status !== 'undefined' && status !== null && status.toLowerCase() === 'error';
      };

      angular.forEach(data, function(item) {
        var comp = null;

        comp = getRegistryRect(item.comp);
        if (comp === null) {
          comp = getEndpointText(item.comp);
          if (typeof comp !== 'undefined' && comp !== null) {
            animateComp(comp, item.ev, item.ts-baseTime, isErrorStatus(item.status));
            animateComp(himRect, item.ev, item.ts-baseTime, isErrorStatus(item.status));
          }
        } else {
          animateComp(comp, item.ev, item.ts-baseTime, isErrorStatus(item.status));
        }
      });
    };

    var play = function play() {
      $scope.showPlay = false;
      $scope.showPause = true;

      lastUpdate = (Date.now()-diffTime);
      visualizerUpdateInterval = $interval( function() {
        Api.VisualizerEvents.get({ receivedTime: lastUpdate}, function (events) {
          processEvents(events.events);
          lastUpdate = (Date.now()-diffTime);
        });
      }, updatePeriod);
    };

    var cancelVisualizerUpdateInterval = function() {
      if (angular.isDefined(visualizerUpdateInterval)) {
        $interval.cancel(visualizerUpdateInterval);
        visualizerUpdateInterval = undefined;
      }
    };

    $scope.play = play;

    $scope.pause = function pause() {
      $scope.showPlay = true;
      $scope.showPause = false;
      cancelVisualizerUpdateInterval();
    };

    $scope.$on('$destroy', cancelVisualizerUpdateInterval);

    var sync = function sync() {
      Api.VisualizerSync.get(function (sync) {
        diffTime = Date.now() - moment(sync.now);
        play();
      });
    };

    $scope.slowDown = function slowDown() {
      if (speed>-1*maxSpeed+1) {
        speed--;
      }
      $scope.speedText = speedText();
    };

    $scope.speedUp = function speedUp() {
      if (speed<maxSpeed-1) {
        speed++;
      }
      $scope.speedText = speedText();
    };

    var speedText = function speedText() {
      if (speed === 0) {
        return '';
      } else if (speed<0) {
        return (-1*speed+1) + 'X Slower';
      } else if (speed>0) {
        return (speed+1) + 'X Faster';
      }
    };

  });
<|endoftext|>


<commit_before>// Copyright (c) 2013, Web Notes Technologies Pvt. Ltd.
// License: GNU General Public License v3. See license.txt

wn.pages['sales-analytics'].onload = function(wrapper) {
	wn.ui.make_app_page({
		parent: wrapper,
		title: wn._('Sales Analytics'),
		single_column: true
	});
	new erpnext.SalesAnalytics(wrapper);

	wrapper.appframe.add_home_breadcrumb()
	wrapper.appframe.add_module_icon("Selling")
	wrapper.appframe.add_breadcrumb("icon-bar-chart")
}

erpnext.SalesAnalytics = wn.views.TreeGridReport.extend({
	init: function(wrapper) {
		this._super({
			title: wn._("Sales Analytics"),
			page: wrapper,
			parent: $(wrapper).find('.layout-main'),
			appframe: wrapper.appframe,
			doctypes: ["Item", "Item Group", "Customer", "Customer Group", "Company", "Territory",
				"Fiscal Year", "Sales Invoice", "Sales Invoice Item",
				"Sales Order", "Sales Order Item[Sales Analytics]",
				"Delivery Note", "Delivery Note Item[Sales Analytics]"],
			tree_grid: { show: true }
		});

		this.tree_grids = {
			"Customer Group": {
				label: wn._("Customer Group / Customer"),
				show: true,
				item_key: "customer",
				parent_field: "parent_customer_group",
				formatter: function(item) { return item.name; }
			},
			"Customer": {
				label: wn._("Customer"),
				show: false,
				item_key: "customer",
				formatter: function(item) {
					return item.name;
				}
			},
			"Item Group": {
				label: wn._("Item"),
				show: true,
				parent_field: "parent_item_group",
				item_key: "item_code",
				formatter: function(item) {
					return item.name;
				}
			},
			"Item": {
				label: wn._("Item"),
				show: false,
				item_key: "item_code",
				formatter: function(item) {
					return item.name;
				}
			},
			"Territory": {
				label: wn._("Territory / Customer"),
				show: true,
				item_key: "customer",
				parent_field: "parent_territory",
				formatter: function(item) {
					return item.name;
				}
			}
		}
	},
	setup_columns: function() {
		this.tree_grid = this.tree_grids[this.tree_type];

		var std_columns = [
			{id: "check", name: "Plot", field: "check", width: 30,
				formatter: this.check_formatter},
			{id: "name", name: this.tree_grid.label, field: "name", width: 300,
				formatter: this.tree_formatter},
			{id: "total", name: "Total", field: "total", plot: false,
				formatter: this.currency_formatter}
		];

		this.make_date_range_columns();
		this.columns = std_columns.concat(this.columns);
	},
	filters: [
		{fieldtype:"Select", label: wn._("Tree Type"), options:["Customer Group", "Customer",
			"Item Group", "Item", "Territory"],
			filter: function(val, item, opts, me) {
				return me.apply_zero_filter(val, item, opts, me);
			}},
		{fieldtype:"Select", label: wn._("Based On"), options:["Sales Invoice",
			"Sales Order", "Delivery Note"]},
		{fieldtype:"Select", label:  wn._("Value or Qty"), options:["Value", "Quantity"]},
		{fieldtype:"Select", label: wn._("Company"), link:"Company",
			default_value: "Select Company..."},
		{fieldtype:"Date", label: wn._("From Date")},
		{fieldtype:"Label", label: wn._("To")},
		{fieldtype:"Date", label: wn._("To Date")},
		{fieldtype:"Select", label: wn._("Range"),
			options:["Daily", "Weekly", "Monthly", "Quarterly", "Yearly"]},
		{fieldtype:"Button", label: wn._("Refresh"), icon:"icon-refresh icon-white", cssClass:"btn-info"},
		{fieldtype:"Button", label: wn._("Reset Filters")}
	],
	setup_filters: function() {
		var me = this;
		this._super();

		this.trigger_refresh_on_change(["value_or_qty", "tree_type", "based_on", "company"]);

		this.show_zero_check()
		this.setup_plot_check();
	},
	init_filter_values: function() {
		this._super();
		this.filter_inputs.range.val('Monthly');
	},
	prepare_data: function() {
		var me = this;
		if (!this.tl) {
			// add 'Not Set' Customer & Item
			// (Customer / Item are not mandatory!!)
			wn.report_dump.data["Customer"].push({
				name: "Not Set",
				parent_customer_group: "All Customer Groups",
				parent_territory: "All Territories",
				id: "Not Set",
			});

			wn.report_dump.data["Item"].push({
				name: "Not Set",
				parent_item_group: "All Item Groups",
				id: "Not Set",
			});
		}

		if (!this.tl || !this.tl[this.based_on]) {
			this.make_transaction_list(this.based_on, this.based_on + " Item");
		}

		if(!this.data || me.item_type != me.tree_type) {
			if(me.tree_type=='Customer') {
				var items = wn.report_dump.data["Customer"];
			} if(me.tree_type=='Customer Group') {
				var items = this.prepare_tree("Customer", "Customer Group");
			} else if(me.tree_type=="Item Group") {
				var items = this.prepare_tree("Item", "Item Group");
			} else if(me.tree_type=="Item") {
				var items = wn.report_dump.data["Item"];
			} else if(me.tree_type=="Territory") {
				var items = this.prepare_tree("Customer", "Territory");
			}

			me.item_type = me.tree_type
			me.parent_map = {};
			me.item_by_name = {};
			me.data = [];

			$.each(items, function(i, v) {
				var d = copy_dict(v);

				me.data.push(d);
				me.item_by_name[d.name] = d;
				if(d[me.tree_grid.parent_field]) {
					me.parent_map[d.name] = d[me.tree_grid.parent_field];
				}
				me.reset_item_values(d);
			});

			this.set_indent();

		} else {
			// otherwise, only reset values
			$.each(this.data, function(i, d) {
				me.reset_item_values(d);
			});
		}

		this.prepare_balances();
		if(me.tree_grid.show) {
			this.set_totals(false);
			this.update_groups();
		} else {
			this.set_totals(true);
		}

	},
	prepare_balances: function() {
		var me = this;
		var from_date = dateutil.str_to_obj(this.from_date);
		var to_date = dateutil.str_to_obj(this.to_date);
		var is_val = this.value_or_qty == 'Value';

		$.each(this.tl[this.based_on], function(i, tl) {
			if (me.is_default('company') ? true : tl.company === me.company) {
				var posting_date = dateutil.str_to_obj(tl.posting_date);
				if (posting_date >= from_date && posting_date <= to_date) {
					var item = me.item_by_name[tl[me.tree_grid.item_key]] ||
						me.item_by_name['Not Set'];
					item[me.column_map[tl.posting_date].field] += (is_val ? tl.amount : tl.qty);
				}
			}
		});
	},
	update_groups: function() {
		var me = this;

		$.each(this.data, function(i, item) {
			var parent = me.parent_map[item.name];
			while(parent) {
				parent_group = me.item_by_name[parent];

				$.each(me.columns, function(c, col) {
					if (col.formatter == me.currency_formatter) {
						parent_group[col.field] =
							flt(parent_group[col.field])
							+ flt(item[col.field]);
					}
				});
				parent = me.parent_map[parent];
			}
		});
	},
	set_totals: function(sort) {
		var me = this;
		var checked = false;
		$.each(this.data, function(i, d) {
			d.total = 0.0;
			$.each(me.columns, function(i, col) {
				if(col.formatter==me.currency_formatter && !col.hidden && col.field!="total")
					d.total += d[col.field];
				if(d.checked) checked = true;
			})
		});

		if(sort)this.data = this.data.sort(function(a, b) { return a.total < b.total; });

		if(!this.checked) {
			this.data[0].checked = true;
		}
	},
	get_plot_points: function(item, col, idx) {
		return [[dateutil.str_to_obj(col.id).getTime(), item[col.field]],
			[dateutil.user_to_obj(col.name).getTime(), item[col.field]]];
	}
});<commit_msg>Update sales_analytics.js<commit_after>// Copyright (c) 2013, Web Notes Technologies Pvt. Ltd.
// License: GNU General Public License v3. See license.txt

wn.pages['sales-analytics'].onload = function(wrapper) {
	wn.ui.make_app_page({
		parent: wrapper,
		title: wn._('Sales Analytics'),
		single_column: true
	});
	new erpnext.SalesAnalytics(wrapper);

	wrapper.appframe.add_home_breadcrumb()
	wrapper.appframe.add_module_icon("Selling")
	wrapper.appframe.add_breadcrumb("icon-bar-chart")
}

erpnext.SalesAnalytics = wn.views.TreeGridReport.extend({
	init: function(wrapper) {
		this._super({
			title: wn._("Sales Analytics"),
			page: wrapper,
			parent: $(wrapper).find('.layout-main'),
			appframe: wrapper.appframe,
			doctypes: ["Item", "Item Group", "Customer", "Customer Group", "Company", "Territory",
				"Fiscal Year", "Sales Invoice", "Sales Invoice Item",
				"Sales Order", "Sales Order Item[Sales Analytics]",
				"Delivery Note", "Delivery Note Item[Sales Analytics]"],
			tree_grid: { show: true }
		});

		this.tree_grids = {
			"Customer Group": {
				label: wn._("Customer Group / Customer"),
				show: true,
				item_key: "customer",
				parent_field: "parent_customer_group",
				formatter: function(item) { return item.name; }
			},
			"Customer": {
				label: wn._("Customer"),
				show: false,
				item_key: "customer",
				formatter: function(item) {
					return item.name;
				}
			},
			"Item Group": {
				label: wn._("Item"),
				show: true,
				parent_field: "parent_item_group",
				item_key: "item_code",
				formatter: function(item) {
					return item.name;
				}
			},
			"Item": {
				label: wn._("Item"),
				show: false,
				item_key: "item_code",
				formatter: function(item) {
					return item.name;
				}
			},
			"Territory": {
				label: wn._("Territory / Customer"),
				show: true,
				item_key: "customer",
				parent_field: "parent_territory",
				formatter: function(item) {
					return item.name;
				}
			}
		}
	},
	setup_columns: function() {
		this.tree_grid = this.tree_grids[this.tree_type];

		var std_columns = [
			{id: "check", name: "Plot", field: "check", width: 30,
				formatter: this.check_formatter},
			{id: "name", name: this.tree_grid.label, field: "name", width: 300,
				formatter: this.tree_formatter},
			{id: "total", name: "Total", field: "total", plot: false,
				formatter: this.currency_formatter}
		];

		this.make_date_range_columns();
		this.columns = std_columns.concat(this.columns);
	},
	filters: [
		{fieldtype:"Select", fieldname: "treetype", label: wn._("Tree Type"), options:["Customer Group", "Customer",
			"Item Group", "Item", "Territory"],
			filter: function(val, item, opts, me) {
				return me.apply_zero_filter(val, item, opts, me);
			}},
		{fieldtype:"Select", fieldname: "based_on", label: wn._("Based On"), options:["Sales Invoice",
			"Sales Order", "Delivery Note"]},
		{fieldtype:"Select", fieldname: "value_or_qty", label:  wn._("Value or Qty"), options:["Value", "Quantity"]},
		{fieldtype:"Select", fieldname: "company", label: wn._("Company"), link:"Company",
			default_value: "Select Company..."},
		{fieldtype:"Date", fieldname: "from_date", label: wn._("From Date")},
		{fieldtype:"Label", fieldname: "to", label: wn._("To")},
		{fieldtype:"Date", fieldname: "to_date", label: wn._("To Date")},
		{fieldtype:"Select", fieldname: "range", label: wn._("Range"),
			options:["Daily", "Weekly", "Monthly", "Quarterly", "Yearly"]},
		{fieldtype:"Button", fieldname: "refresh", label: wn._("Refresh"), icon:"icon-refresh icon-white", cssClass:"btn-info"},
		{fieldtype:"Button", fieldname: "reset_filters", label: wn._("Reset Filters")}
	],
	setup_filters: function() {
		var me = this;
		this._super();

		this.trigger_refresh_on_change(["value_or_qty", "tree_type", "based_on", "company"]);

		this.show_zero_check()
		this.setup_plot_check();
	},
	init_filter_values: function() {
		this._super();
		this.filter_inputs.range.val('Monthly');
	},
	prepare_data: function() {
		var me = this;
		if (!this.tl) {
			// add 'Not Set' Customer & Item
			// (Customer / Item are not mandatory!!)
			wn.report_dump.data["Customer"].push({
				name: "Not Set",
				parent_customer_group: "All Customer Groups",
				parent_territory: "All Territories",
				id: "Not Set",
			});

			wn.report_dump.data["Item"].push({
				name: "Not Set",
				parent_item_group: "All Item Groups",
				id: "Not Set",
			});
		}

		if (!this.tl || !this.tl[this.based_on]) {
			this.make_transaction_list(this.based_on, this.based_on + " Item");
		}

		if(!this.data || me.item_type != me.tree_type) {
			if(me.tree_type=='Customer') {
				var items = wn.report_dump.data["Customer"];
			} if(me.tree_type=='Customer Group') {
				var items = this.prepare_tree("Customer", "Customer Group");
			} else if(me.tree_type=="Item Group") {
				var items = this.prepare_tree("Item", "Item Group");
			} else if(me.tree_type=="Item") {
				var items = wn.report_dump.data["Item"];
			} else if(me.tree_type=="Territory") {
				var items = this.prepare_tree("Customer", "Territory");
			}

			me.item_type = me.tree_type
			me.parent_map = {};
			me.item_by_name = {};
			me.data = [];

			$.each(items, function(i, v) {
				var d = copy_dict(v);

				me.data.push(d);
				me.item_by_name[d.name] = d;
				if(d[me.tree_grid.parent_field]) {
					me.parent_map[d.name] = d[me.tree_grid.parent_field];
				}
				me.reset_item_values(d);
			});

			this.set_indent();

		} else {
			// otherwise, only reset values
			$.each(this.data, function(i, d) {
				me.reset_item_values(d);
			});
		}

		this.prepare_balances();
		if(me.tree_grid.show) {
			this.set_totals(false);
			this.update_groups();
		} else {
			this.set_totals(true);
		}

	},
	prepare_balances: function() {
		var me = this;
		var from_date = dateutil.str_to_obj(this.from_date);
		var to_date = dateutil.str_to_obj(this.to_date);
		var is_val = this.value_or_qty == 'Value';

		$.each(this.tl[this.based_on], function(i, tl) {
			if (me.is_default('company') ? true : tl.company === me.company) {
				var posting_date = dateutil.str_to_obj(tl.posting_date);
				if (posting_date >= from_date && posting_date <= to_date) {
					var item = me.item_by_name[tl[me.tree_grid.item_key]] ||
						me.item_by_name['Not Set'];
					item[me.column_map[tl.posting_date].field] += (is_val ? tl.amount : tl.qty);
				}
			}
		});
	},
	update_groups: function() {
		var me = this;

		$.each(this.data, function(i, item) {
			var parent = me.parent_map[item.name];
			while(parent) {
				parent_group = me.item_by_name[parent];

				$.each(me.columns, function(c, col) {
					if (col.formatter == me.currency_formatter) {
						parent_group[col.field] =
							flt(parent_group[col.field])
							+ flt(item[col.field]);
					}
				});
				parent = me.parent_map[parent];
			}
		});
	},
	set_totals: function(sort) {
		var me = this;
		var checked = false;
		$.each(this.data, function(i, d) {
			d.total = 0.0;
			$.each(me.columns, function(i, col) {
				if(col.formatter==me.currency_formatter && !col.hidden && col.field!="total")
					d.total += d[col.field];
				if(d.checked) checked = true;
			})
		});

		if(sort)this.data = this.data.sort(function(a, b) { return a.total < b.total; });

		if(!this.checked) {
			this.data[0].checked = true;
		}
	},
	get_plot_points: function(item, col, idx) {
		return [[dateutil.str_to_obj(col.id).getTime(), item[col.field]],
			[dateutil.user_to_obj(col.name).getTime(), item[col.field]]];
	}
});
<|endoftext|>


<commit_before>'use strict';

const apiai = require('apiai');
const express = require('express');
const bodyParser = require('body-parser');
const uuid = require('node-uuid');
const request = require('request');

const REST_PORT = (process.env.PORT || 5000);
const APIAI_ACCESS_TOKEN = process.env.APIAI_ACCESS_TOKEN;
const APIAI_LANG = process.env.APIAI_LANG || 'en';
const FB_VERIFY_TOKEN = process.env.FB_VERIFY_TOKEN;
const FB_PAGE_ACCESS_TOKEN = process.env.FB_PAGE_ACCESS_TOKEN;

const apiAiService = apiai(APIAI_ACCESS_TOKEN, {language: APIAI_LANG, requestSource: "fb"});
const sessionIds = new Map();

function processEvent(event) {
    var sender = event.sender.id;

    if (event.message && event.message.text) {
        var text = event.message.text;
        // Handle a text message from this sender

        if (!sessionIds.has(sender)) {
            sessionIds.set(sender, uuid.v1());
        }

        console.log("Text", text);

        let apiaiRequest = apiAiService.textRequest(text,
            {
                sessionId: sessionIds.get(sender)
            });

        apiaiRequest.on('response', (response) => {
            if (isDefined(response.result)) {
                let responseText = response.result.fulfillment.speech;
                let responseData = response.result.fulfillment.data;
                let action = response.result.action;
                let parameters = response.result.parameters;

                if (action){
                    try {
                        var action_module = require('./'+ action);
                        console.log(action_module.get(parameters));
                    } catch(e) {
                        console.error(action +" is not found");
                    }
                }else{
                    console.error("no action");
                }

                if (isDefined(responseData) && isDefined(responseData.facebook)) {
                    try {
                        console.log('Response as formatted message');
                        sendFBMessage(sender, responseData.facebook);
                    } catch (err) {
                        sendFBMessage(sender, {text: err.message });
                    }
                } else if (isDefined(responseText)) {
                    console.log('Response as text message');
                    // facebook API limit for text length is 320,
                    // so we split message if needed
                    var splittedText = splitResponse(responseText);
                    /*
                    for (var i = 0; i < splittedText.length; i++) {
                        sendFBMessage(sender, {text: splittedText[i]});
                    }
                    */
                    var num_line = parameters.num_line
                    var action_module = require('./RATP_App.js');
                    action_module.info(function(result) {
                         var returedData = result;

                         sendFBMessage(sender, returedData);
                    },10);

                }

            }
        });

        apiaiRequest.on('error', (error) => console.error(error));
        apiaiRequest.end();
    }
}

function splitResponse(str) {
    if (str.length <= 320)
    {
        return [str];
    }

    var result = chunkString(str, 300);

    return result;

}

function chunkString(s, len)
{
    var curr = len, prev = 0;

    var output = [];

    while(s[curr]) {
        if(s[curr++] == ' ') {
            output.push(s.substring(prev,curr));
            prev = curr;
            curr += len;
        }
        else
        {
            var currReverse = curr;
            do {
                if(s.substring(currReverse - 1, currReverse) == ' ')
                {
                    output.push(s.substring(prev,currReverse));
                    prev = currReverse;
                    curr = currReverse + len;
                    break;
                }
                currReverse--;
            } while(currReverse > prev)
        }
    }
    output.push(s.substr(prev));
    return output;
}

function sendFBMessage(sender, messageData) {
    var to_string = JSON.stringify(messageData);
    var to_size = to_string.substring(0, 300);

    request({
        url: 'https://graph.facebook.com/v2.6/me/messages',
        qs: {access_token: FB_PAGE_ACCESS_TOKEN},
        method: 'POST',
        json: {
            recipient: {id: sender},
            message: {text : to_size}
        }
    }, function (error, response, body) {
        if (error) {
            console.log('Error sending message: ', error);
        } else if (response.body.error) {
            console.log('Error: ', response.body.error);
        }
    });
}

function doSubscribeRequest() {
    request({
            method: 'POST',
            uri: "https://graph.facebook.com/v2.6/me/subscribed_apps?access_token=" + FB_PAGE_ACCESS_TOKEN
        },
        function (error, response, body) {
            if (error) {
                console.error('Error while subscription: ', error);
            } else {
                console.log('Subscription result: ', response.body);
            }
        });
}

function isDefined(obj) {
    if (typeof obj == 'undefined') {
        return false;
    }

    if (!obj) {
        return false;
    }

    return obj != null;
}

const app = express();
app.use(bodyParser.json());
app.all('*', function (req, res, next) {
    // res.header("Access-Control-Allow-Origin", '*');
    // res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, content-type, accept");
    next();
});

app.get('/webhook/', function (req, res) {
    if (req.query['hub.verify_token'] == FB_VERIFY_TOKEN) {
        res.send(req.query['hub.challenge']);

        setTimeout(function () {
            doSubscribeRequest();
        }, 3000);
    } else {
        res.send('Error, wrong validation token');
    }
});

app.post('/webhook/', function (req, res) {
    try {
        var messaging_events = req.body.entry[0].messaging;
        for (var i = 0; i < messaging_events.length; i++) {
            var event = req.body.entry[0].messaging[i];
            processEvent(event);
        }
        return res.status(200).json({
            status: "ok"
        });
    } catch (err) {
        return res.status(400).json({
            status: "error",
            error: err
        });
    }

});

app.listen(REST_PORT, function () {
    console.log('Rest service ready on port ' + REST_PORT);
});

doSubscribeRequest();
<commit_msg>Update app.js<commit_after>'use strict';

const apiai = require('apiai');
const express = require('express');
const bodyParser = require('body-parser');
const uuid = require('node-uuid');
const request = require('request');

const REST_PORT = (process.env.PORT || 5000);
const APIAI_ACCESS_TOKEN = process.env.APIAI_ACCESS_TOKEN;
const APIAI_LANG = process.env.APIAI_LANG || 'en';
const FB_VERIFY_TOKEN = process.env.FB_VERIFY_TOKEN;
const FB_PAGE_ACCESS_TOKEN = process.env.FB_PAGE_ACCESS_TOKEN;

const apiAiService = apiai(APIAI_ACCESS_TOKEN, {language: APIAI_LANG, requestSource: "fb"});
const sessionIds = new Map();

function processEvent(event) {
    var sender = event.sender.id;

    if (event.message && event.message.text) {
        var text = event.message.text;
        // Handle a text message from this sender

        if (!sessionIds.has(sender)) {
            sessionIds.set(sender, uuid.v1());
        }

        console.log("Text", text);

        let apiaiRequest = apiAiService.textRequest(text,
            {
                sessionId: sessionIds.get(sender)
            });

        apiaiRequest.on('response', (response) => {
            if (isDefined(response.result)) {
                let responseText = response.result.fulfillment.speech;
                let responseData = response.result.fulfillment.data;
                let action = response.result.action;
                let parameters = response.result.parameters;

                if (action){
                    try {
                        var action_module = require('./'+ action);
                        console.log(action_module.get(parameters));
                    } catch(e) {
                        console.error(action +" is not found");
                    }
                }else{
                    console.error("no action");
                }

                if (isDefined(responseData) && isDefined(responseData.facebook)) {
                    try {
                        console.log('Response as formatted message');
                        sendFBMessage(sender, responseData.facebook);
                    } catch (err) {
                        sendFBMessage(sender, {text: err.message });
                    }
                } else if (isDefined(responseText)) {
                    console.log('Response as text message');
                    // facebook API limit for text length is 320,
                    // so we split message if needed
                    var splittedText = splitResponse(responseText);
                    /*
                    for (var i = 0; i < splittedText.length; i++) {
                        sendFBMessage(sender, {text: splittedText[i]});
                    }
                    */
                    var num_line = parameters.num_line
                    var action_module = require('./RATP_App.js');
                    action_module.info(function(result) {
                         var returedData = result;

                         sendFBMessage(sender, returedData);
                    },num_line);

                }

            }
        });

        apiaiRequest.on('error', (error) => console.error(error));
        apiaiRequest.end();
    }
}

function splitResponse(str) {
    if (str.length <= 320)
    {
        return [str];
    }

    var result = chunkString(str, 300);

    return result;

}

function chunkString(s, len)
{
    var curr = len, prev = 0;

    var output = [];

    while(s[curr]) {
        if(s[curr++] == ' ') {
            output.push(s.substring(prev,curr));
            prev = curr;
            curr += len;
        }
        else
        {
            var currReverse = curr;
            do {
                if(s.substring(currReverse - 1, currReverse) == ' ')
                {
                    output.push(s.substring(prev,currReverse));
                    prev = currReverse;
                    curr = currReverse + len;
                    break;
                }
                currReverse--;
            } while(currReverse > prev)
        }
    }
    output.push(s.substr(prev));
    return output;
}

function sendFBMessage(sender, messageData) {
    var to_string = JSON.stringify(messageData);
    var to_size = to_string.substring(0, 300);

    request({
        url: 'https://graph.facebook.com/v2.6/me/messages',
        qs: {access_token: FB_PAGE_ACCESS_TOKEN},
        method: 'POST',
        json: {
            recipient: {id: sender},
            message: {text : to_size}
        }
    }, function (error, response, body) {
        if (error) {
            console.log('Error sending message: ', error);
        } else if (response.body.error) {
            console.log('Error: ', response.body.error);
        }
    });
}

function doSubscribeRequest() {
    request({
            method: 'POST',
            uri: "https://graph.facebook.com/v2.6/me/subscribed_apps?access_token=" + FB_PAGE_ACCESS_TOKEN
        },
        function (error, response, body) {
            if (error) {
                console.error('Error while subscription: ', error);
            } else {
                console.log('Subscription result: ', response.body);
            }
        });
}

function isDefined(obj) {
    if (typeof obj == 'undefined') {
        return false;
    }

    if (!obj) {
        return false;
    }

    return obj != null;
}

const app = express();
app.use(bodyParser.json());
app.all('*', function (req, res, next) {
    // res.header("Access-Control-Allow-Origin", '*');
    // res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, content-type, accept");
    next();
});

app.get('/webhook/', function (req, res) {
    if (req.query['hub.verify_token'] == FB_VERIFY_TOKEN) {
        res.send(req.query['hub.challenge']);

        setTimeout(function () {
            doSubscribeRequest();
        }, 3000);
    } else {
        res.send('Error, wrong validation token');
    }
});

app.post('/webhook/', function (req, res) {
    try {
        var messaging_events = req.body.entry[0].messaging;
        for (var i = 0; i < messaging_events.length; i++) {
            var event = req.body.entry[0].messaging[i];
            processEvent(event);
        }
        return res.status(200).json({
            status: "ok"
        });
    } catch (err) {
        return res.status(400).json({
            status: "error",
            error: err
        });
    }

});

app.listen(REST_PORT, function () {
    console.log('Rest service ready on port ' + REST_PORT);
});

doSubscribeRequest();
<|endoftext|>


<commit_before><commit_msg>implement @iangilman 's fix<commit_after><|endoftext|>


<commit_before>'use strict';

angular.module('searchApp')
  .directive('searchForm', [ '$log', 'SolrService',
    function ($log, SolrService) {
    return {
      templateUrl: 'views/search-form.html',
      restrict: 'E',
      scope: {
          help: '@',
          searchType: '@'
      },
      link: function postLink(scope, element, attrs) {

          // handle the app being bootstrapped
          scope.$on('app-ready', function() {
              scope.searchBox = SolrService.query.term;
              scope.search();
          });

          // handle the update call
          scope.$on('reset-all-filters', function() {
              scope.searchBox = '*';
          });

          scope.search = function() {
              // args:
              // - start: 0 (record to start at)
              // - ditchSuggestion: true
              if (scope.searchBox === '') scope.searchBox = '*';
              SolrService.query.term = scope.searchBox;
              SolrService.search(0, true);
          };

          scope.reset = function() {
              SolrService.reset();
          };

      },
    };
  }]);
<commit_msg>use underscore for empty test<commit_after>'use strict';

angular.module('searchApp')
  .directive('searchForm', [ '$log', 'SolrService',
    function ($log, SolrService) {
    return {
      templateUrl: 'views/search-form.html',
      restrict: 'E',
      scope: {
          help: '@',
          searchType: '@'
      },
      link: function postLink(scope, element, attrs) {

          // handle the app being bootstrapped
          scope.$on('app-ready', function() {
              scope.searchBox = SolrService.query.term;
              scope.search();
          });

          // handle the update call
          scope.$on('reset-all-filters', function() {
              scope.searchBox = '*';
          });

          scope.search = function() {
              // args:
              // - start: 0 (record to start at)
              // - ditchSuggestion: true
              if (_.isEmpty(scope.searchBox)) scope.searchBox = '*';
              SolrService.query.term = scope.searchBox;
              SolrService.search(0, true);
          };

          scope.reset = function() {
              SolrService.reset();
          };

      },
    };
  }]);
<|endoftext|>


<commit_before>"use strict";

var Backbone = require('./backbone')
  , $ = require('jquery')
  , root = location.protocol + '//' + location.host
  , Router

$(document).ready(function () {
  var router = new Router();
  Backbone.history.start();
}).on('click a', function (e) {
  if (e.target.href.indexOf(root) === 0) {
    e.preventDefault();
    Backbone.history.navigate(e.target.getAttribute('href'), { trigger: true });
  }
});

Router = Backbone.Router.extend({
  routes: {
    '': 'index',
    'projects': 'allProjects',
    'projects/:project': 'project',
    'collections': 'allCollections',
    'collections/:collection': 'collection',
    'items': 'allItems',
    'items/:item': 'item'
  },

  _view: null,
  changeView: function (View, options) {
    if (this._view) this._view.remove();
    this._view = new View(options || {});
    this._view.$el.appendTo('#main');
  },

  index: function () {
    var IndexView = require('./views/index');
    this.changeView(IndexView);
  },
  allProjects: function () {
    var AllProjectsView = require('./views/all_projects');
    this.changeView(AllProjectsView);
  },
  project: function (project) {
    var ProjectView = require('./views/project');
    this.changeView(ProjectView);
  },
  allCollections: function() {
    var AllCollectionsView = require('./views/all_collections');
    this.changeView(AllCollectionsView);
  },
  collection: function(collection) {
    var CollectionView = require('./views/collection');
    this.changeView(CollectionView);
  },
  allItems: function () {
    var AllItemsView = require('./views/all_items');
    this.changeView(AllItemsView);
  },
  item: function (item) {
    var ItemView = require('./views/item');
    this.changeView(ItemView);
  }
});
<commit_msg>Fix bug in internal navigation<commit_after>"use strict";

var Backbone = require('./backbone')
  , $ = require('jquery')
  , root = location.protocol + '//' + location.host
  , Router

$(document).ready(function () {
  var router = new Router();
  Backbone.history.start();
}).on('click a', function (e) {
  if (e.target.href && e.target.href.indexOf(root) === 0) {
    e.preventDefault();
    Backbone.history.navigate(e.target.getAttribute('href'), { trigger: true });
  }
});

Router = Backbone.Router.extend({
  routes: {
    '': 'index',
    'projects': 'allProjects',
    'projects/:project': 'project',
    'collections': 'allCollections',
    'collections/:collection': 'collection',
    'items': 'allItems',
    'items/:item': 'item'
  },

  _view: null,
  changeView: function (View, options) {
    if (this._view) this._view.remove();
    this._view = new View(options || {});
    this._view.$el.appendTo('#main');
  },

  index: function () {
    var IndexView = require('./views/index');
    this.changeView(IndexView);
  },
  allProjects: function () {
    var AllProjectsView = require('./views/all_projects');
    this.changeView(AllProjectsView);
  },
  project: function (project) {
    var ProjectView = require('./views/project');
    this.changeView(ProjectView);
  },
  allCollections: function() {
    var AllCollectionsView = require('./views/all_collections');
    this.changeView(AllCollectionsView);
  },
  collection: function(collection) {
    var CollectionView = require('./views/collection');
    this.changeView(CollectionView);
  },
  allItems: function () {
    var AllItemsView = require('./views/all_items');
    this.changeView(AllItemsView);
  },
  item: function (item) {
    var ItemView = require('./views/item');
    this.changeView(ItemView);
  }
});
<|endoftext|>


<commit_before>export default {
  translations: {
    'en': {
      'months': {
        'original': ['January', 'Febrary', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
        'abbr': ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
      },
      'days': ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']
    },

    'es': {
      'months': {
        'original': ['Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre'],
        'abbr': ['Ene', 'Feb', 'Mar', 'Abr', 'May', 'Jun', 'Jul', 'Ago', 'Sep', 'Oct', 'Nov', 'Dic']
      },
      'days': ['Dom', 'Lun', 'Mar', 'Mié', 'Jue', 'Vie', 'Sab']
    },

    'fr': {
      'months': {
        'original': ['Janvier', 'Février', 'Mars', 'Avril', 'Mai', 'Juin', 'Juillet', 'Août', 'Septembre', 'Octobre', 'Novembre', 'Décembre'],
        'abbr': ['Jan', 'Fév', 'Mar', 'Avr', 'Mai', 'Jui', 'Juil', 'Aoû', 'Sep', 'Oct', 'Nov', 'Déc']
      },
      'days': ['Dim', 'Lun', 'Mar', 'Mer', 'Jeu', 'Ven', 'Sam']
    },

    'pt-br': {
      'months': {
        'original': ['Janeiro', 'Fevereiro', 'Março', 'Abril', 'Maio', 'Junho', 'Julho', 'Agosto', 'Setembro', 'Outubro', 'Novembro', 'Dezembro'],
        'abbr': ['Jan', 'Fev', 'Mar', 'Abr', 'Mai', 'Jun', 'Jul', 'Ago', 'Set', 'Out', 'Nov', 'Dez']
      },
      'days': ['Dom', 'Seg', 'Ter', 'Qua', 'Qui', 'Sex', 'Sab']
    }
  }
}
<commit_msg>Add vi locale<commit_after>export default {
  translations: {
    'en': {
      'months': {
        'original': ['January', 'Febrary', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
        'abbr': ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
      },
      'days': ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']
    },

    'es': {
      'months': {
        'original': ['Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre'],
        'abbr': ['Ene', 'Feb', 'Mar', 'Abr', 'May', 'Jun', 'Jul', 'Ago', 'Sep', 'Oct', 'Nov', 'Dic']
      },
      'days': ['Dom', 'Lun', 'Mar', 'Mié', 'Jue', 'Vie', 'Sab']
    },

    'fr': {
      'months': {
        'original': ['Janvier', 'Février', 'Mars', 'Avril', 'Mai', 'Juin', 'Juillet', 'Août', 'Septembre', 'Octobre', 'Novembre', 'Décembre'],
        'abbr': ['Jan', 'Fév', 'Mar', 'Avr', 'Mai', 'Jui', 'Juil', 'Aoû', 'Sep', 'Oct', 'Nov', 'Déc']
      },
      'days': ['Dim', 'Lun', 'Mar', 'Mer', 'Jeu', 'Ven', 'Sam']
    },

    'pt-br': {
      'months': {
        'original': ['Janeiro', 'Fevereiro', 'Março', 'Abril', 'Maio', 'Junho', 'Julho', 'Agosto', 'Setembro', 'Outubro', 'Novembro', 'Dezembro'],
        'abbr': ['Jan', 'Fev', 'Mar', 'Abr', 'Mai', 'Jun', 'Jul', 'Ago', 'Set', 'Out', 'Nov', 'Dez']
      },
      'days': ['Dom', 'Seg', 'Ter', 'Qua', 'Qui', 'Sex', 'Sab']
    }
  },

 'vi': {
      'months': {
        'original': ['Tháng 1', 'Tháng 2', 'Tháng 3', 'Tháng 4', 'Tháng 5', 'Tháng 6', 'Tháng 7', 'Tháng 8', 'Tháng 9', 'Tháng 10', 'Tháng 11', 'Tháng 12'],
        'abbr': ['T 01', 'T 02', 'T 03', 'T 04', 'T 05', 'T 06', 'T 07', 'T 08', 'T 09', 'T 10', 'T 11', 'T 12']
      },
      'days': ['CN', 'Thứ 2', 'Thứ 3', 'Thứ 4', 'Thứ 5', 'Thứ 6', 'Thứ 7']
    }
  }

}
<|endoftext|>


<commit_before><commit_msg>rename global variable<commit_after><|endoftext|>


<commit_before>import 'babel-polyfill'
import LFSR from './lfsr'

/**
 * A Galois implementation of a linear feedback shift register (LFSR).
 *
 * @class
 * @augments LFSR
 *
 * @example
A 3-tap m-sequence (maximum-length sequence)

 * var size = 3
 * var lfsr = new GaloisLFSR(size, [3, 2])
 * console.log(lfsr.current_state, lfsr.current_state.toString(2))
 * //=> 1, "1"
 *
 * for (var n = 1; n <= lfsr.maximum_sequence_length; n++) {
 *   var bit = lfsr.next()
 *
 *   console.log(bit, bit.toString(2))
 * }
 * //=> 6, "0"
 * //=> 3, "1"
 * //=> 7, "1"
 * //=> 5, "1"
 * //=> 4, "0"
 * //=> 2, "0"
 * //=> 1, "1"
 *
 * @see https://en.wikipedia.org/wiki/Linear_feedback_shift_register
 * @see http://www.newwaveinstruments.com/resources/articles/m_sequence_linear_feedback_shift_register_lfsr.htm
 */
class GaloisLFSR extends LFSR {
  /**
   * Generate the next state in the sequence.
   *
   * @returns {number} The output bit.
   * @override
   *
   * @example
How the next state is calculated

   * var lfsr = new GaloisLFSR(3, [3, 1], 6)
   * lfsr.current_state
   * //=> 0b110 (6)
   * lfsr.feedback_tap_mask
   * //=> 0b101
   * input = state & 1
   * // input = 0b0
   * //=> 0b0 (0)
   * state >>= 1
   * //=> 0b011 (3)
   * state ^= (-input) & this.feedback_tap_mask
   * // state ^= (0b11111111111111111111111111111111 & 0b101)
   * // state ^= 0b110
   * //=> 0b011 (3)
   * state & 1
   * //=> 0b1 (1)
   */
  next() {
    let state = this.current_state
    // Use the lowest bit in `state` as the input.
    const input = state & 1

    // Drop the current input bit so the lowest bit of the new state serves as
    // the next input bit.
    state >>= 1
    // JavaScript represents numbers in two's complement format: `0` and `-0`
    // are stored as `00000000`; `-1` is `11111111`. Because `input` is always
    // `0` or `1`, `-input` is a convenient way to get a bitmask to `&` against
    // when flipping bits for the next `state` value.
    //
    // @see https://en.wikipedia.org/w/index.php?title=Signed_number_representations&oldid=712932585#Two.27s_complement
    state ^= (-input) & this.feedback_tap_mask
    this.current_state = state

    return state & 1
  }
}

export default GaloisLFSR
<commit_msg>Fixed error in GaloisLFSR documentation<commit_after>import 'babel-polyfill'
import LFSR from './lfsr'

/**
 * A Galois implementation of a linear feedback shift register (LFSR).
 *
 * @class
 * @augments LFSR
 *
 * @example
A 3-tap m-sequence (maximum-length sequence)

 * var size = 3
 * var lfsr = new GaloisLFSR(size, [3, 2])
 * console.log(lfsr.current_state, lfsr.current_state.toString(2))
 * //=> 1, "1"
 *
 * for (var n = 1; n <= lfsr.maximum_sequence_length; n++) {
 *   var bit = lfsr.next()
 *
 *   console.log(lfsr.current_state, bit.toString(2))
 * }
 * //=> 6, "0"
 * //=> 3, "1"
 * //=> 7, "1"
 * //=> 5, "1"
 * //=> 4, "0"
 * //=> 2, "0"
 * //=> 1, "1"
 *
 * @see https://en.wikipedia.org/wiki/Linear_feedback_shift_register
 * @see http://www.newwaveinstruments.com/resources/articles/m_sequence_linear_feedback_shift_register_lfsr.htm
 */
class GaloisLFSR extends LFSR {
  /**
   * Generate the next state in the sequence.
   *
   * @returns {number} The output bit.
   * @override
   *
   * @example
How the next state is calculated

   * var lfsr = new GaloisLFSR(3, [3, 1], 6)
   * lfsr.current_state
   * //=> 0b110 (6)
   * lfsr.feedback_tap_mask
   * //=> 0b101
   * input = state & 1
   * // input = 0b0
   * //=> 0b0 (0)
   * state >>= 1
   * //=> 0b011 (3)
   * state ^= (-input) & this.feedback_tap_mask
   * // state ^= (0b11111111111111111111111111111111 & 0b101)
   * // state ^= 0b110
   * //=> 0b011 (3)
   * state & 1
   * //=> 0b1 (1)
   */
  next() {
    let state = this.current_state
    // Use the lowest bit in `state` as the input.
    const input = state & 1

    // Drop the current input bit so the lowest bit of the new state serves as
    // the next input bit.
    state >>= 1
    // JavaScript represents numbers in two's complement format: `0` and `-0`
    // are stored as `00000000`; `-1` is `11111111`. Because `input` is always
    // `0` or `1`, `-input` is a convenient way to get a bitmask to `&` against
    // when flipping bits for the next `state` value.
    //
    // @see https://en.wikipedia.org/w/index.php?title=Signed_number_representations&oldid=712932585#Two.27s_complement
    state ^= (-input) & this.feedback_tap_mask
    this.current_state = state

    return state & 1
  }
}

export default GaloisLFSR
<|endoftext|>