<commit_before>describe('buttons', function() {

  var $scope, $compile;

  beforeEach(module('ui.bootstrap.buttons'));
  beforeEach(inject(function(_$rootScope_, _$compile_) {
    $scope = _$rootScope_;
    $compile = _$compile_;
  }));

  describe('checkbox', function() {
    var compileButton = function(markup, scope) {
      var el = $compile(markup)(scope);
      scope.$digest();
      return el;
    };

    it('should expose the controller to the view', inject(function($templateCache) {
      var btn = compileButton('<button ng-model="model" uib-btn-checkbox>{{button.text}}</button>', $scope);
      var ctrl = btn.controller('uibBtnCheckbox');
      expect(ctrl).toBeDefined();

      ctrl.text = 'foo';
      $scope.$digest();

      expect(btn.html()).toBe('foo');
    }));

    //model -> UI
    it('should work correctly with default model values', function() {
      $scope.model = false;
      var btn = compileButton('<button ng-model="model" uib-btn-checkbox>click</button>', $scope);
      expect(btn).not.toHaveClass('active');

      $scope.model = true;
      $scope.$digest();
      expect(btn).toHaveClass('active');
    });

    it('should bind custom model values', function() {
      $scope.model = 1;
      var btn = compileButton('<button ng-model="model" uib-btn-checkbox btn-checkbox-true="1" btn-checkbox-false="0">click</button>', $scope);
      expect(btn).toHaveClass('active');

      $scope.model = 0;
      $scope.$digest();
      expect(btn).not.toHaveClass('active');
    });

    //UI-> model
    it('should toggle default model values on click', function() {
      $scope.model = false;
      var btn = compileButton('<button ng-model="model" uib-btn-checkbox>click</button>', $scope);

      btn.click();
      expect($scope.model).toEqual(true);
      expect(btn).toHaveClass('active');

      btn.click();
      expect($scope.model).toEqual(false);
      expect(btn).not.toHaveClass('active');
    });

    it('should toggle custom model values on click', function() {
      $scope.model = 0;
      var btn = compileButton('<button ng-model="model" uib-btn-checkbox btn-checkbox-true="1" btn-checkbox-false="0">click</button>', $scope);

      btn.click();
      expect($scope.model).toEqual(1);
      expect(btn).toHaveClass('active');

      btn.click();
      expect($scope.model).toEqual(0);
      expect(btn).not.toHaveClass('active');
    });

    it('should monitor true / false value changes - issue 666', function() {

      $scope.model = 1;
      $scope.trueVal = 1;
      var btn = compileButton('<button ng-model="model" uib-btn-checkbox btn-checkbox-true="trueVal">click</button>', $scope);

      expect(btn).toHaveClass('active');
      expect($scope.model).toEqual(1);

      $scope.model = 2;
      $scope.trueVal = 2;
      $scope.$digest();

      expect(btn).toHaveClass('active');
      expect($scope.model).toEqual(2);
    });

    it('should not toggle when disabled - issue 4013', function() {
      $scope.model = 1;
      $scope.falseVal = 0;
      var btn = compileButton('<button disabled ng-model="model" uib-btn-checkbox btn-checkbox-true="falseVal">click</button>', $scope);

      expect(btn).not.toHaveClass('active');
      expect($scope.model).toEqual(1);

      btn.click();

      expect(btn).not.toHaveClass('active');

      $scope.$digest();

      expect(btn).not.toHaveClass('active');
    });

    describe('setting buttonConfig', function() {
      var uibButtonConfig, originalActiveClass, originalToggleEvent;

      beforeEach(inject(function(_uibButtonConfig_) {
        uibButtonConfig = _uibButtonConfig_;
        originalActiveClass = uibButtonConfig.activeClass;
        originalToggleEvent = uibButtonConfig.toggleEvent;
        uibButtonConfig.activeClass = false;
        uibButtonConfig.toggleEvent = false;
      }));

      afterEach(function() {
        // return it to the original value
        uibButtonConfig.activeClass = originalActiveClass;
        uibButtonConfig.toggleEvent = originalToggleEvent;
      });

      it('should use default config when buttonConfig.activeClass and buttonConfig.toggleEvent is false', function() {
        $scope.model = false;
        var btn = compileButton('<button ng-model="model" uib-btn-checkbox>click</button>', $scope);
        expect(btn).not.toHaveClass('active');

        $scope.model = true;
        $scope.$digest();
        expect(btn).toHaveClass('active');
      });

      it('should be able to use a different active class', function() {
        uibButtonConfig.activeClass = 'foo';
        $scope.model = false;
        var btn = compileButton('<button ng-model="model" uib-btn-checkbox>click</button>', $scope);
        expect(btn).not.toHaveClass('foo');

        $scope.model = true;
        $scope.$digest();
        expect(btn).toHaveClass('foo');
      });

      it('should be able to use a different toggle event', function() {
        uibButtonConfig.toggleEvent = 'mouseenter';
        $scope.model = false;
        var btn = compileButton('<button ng-model="model" uib-btn-checkbox>click</button>', $scope);
        expect(btn).not.toHaveClass('active');

        btn.trigger('mouseenter');

        $scope.$digest();
        expect(btn).toHaveClass('active');
      });
    });

  });

  describe('radio', function() {

    var compileButtons = function(markup, scope) {
      var el = $compile('
'+markup+'
')(scope);
      scope.$digest();
      return el.find('button');
    };

    it('should expose the controller to the view', inject(function($templateCache) {
      var btn = compileButtons('<button ng-model="model" uib-btn-radio="1">{{buttons.text}}</button>', $scope);
      var ctrl = btn.controller('uibBtnRadio');
      expect(ctrl).toBeDefined();

      ctrl.text = 'foo';
      $scope.$digest();

      expect(btn.html()).toBe('foo');
    }));

    //model -> UI
    it('should set active class based on model', function() {
      var btns = compileButtons('<button ng-model="model" uib-btn-radio="1">click1</button><button ng-model="model" uib-btn-radio="2">click2</button>', $scope);
      expect(btns.eq(0)).not.toHaveClass('active');
      expect(btns.eq(1)).not.toHaveClass('active');

      $scope.model = 2;
      $scope.$digest();
      expect(btns.eq(0)).not.toHaveClass('active');
      expect(btns.eq(1)).toHaveClass('active');
    });

    //UI->model
    it('should set active class via click', function() {
      var btns = compileButtons('<button ng-model="model" uib-btn-radio="1">click1</button><button ng-model="model" uib-btn-radio="2">click2</button>', $scope);
      expect($scope.model).toBeUndefined();

      btns.eq(0).click();
      expect($scope.model).toEqual(1);
      expect(btns.eq(0)).toHaveClass('active');
      expect(btns.eq(1)).not.toHaveClass('active');

      btns.eq(1).click();
      expect($scope.model).toEqual(2);
      expect(btns.eq(1)).toHaveClass('active');
      expect(btns.eq(0)).not.toHaveClass('active');
    });

    it('should watch uib-btn-radio values and update state accordingly', function() {
      $scope.values = ['value1', 'value2'];

      var btns = compileButtons('<button ng-model="model" uib-btn-radio="values[0]">click1</button><button ng-model="model" uib-btn-radio="values[1]">click2</button>', $scope);
      expect(btns.eq(0)).not.toHaveClass('active');
      expect(btns.eq(1)).not.toHaveClass('active');

      $scope.model = 'value2';
      $scope.$digest();
      expect(btns.eq(0)).not.toHaveClass('active');
      expect(btns.eq(1)).toHaveClass('active');

      $scope.values[1] = 'value3';
      $scope.model = 'value3';
      $scope.$digest();
      expect(btns.eq(0)).not.toHaveClass('active');
      expect(btns.eq(1)).toHaveClass('active');
    });

    it('should do nothing when clicking an active radio', function() {
      $scope.model = 1;
      var btns = compileButtons('<button ng-model="model" uib-btn-radio="1">click1</button><button ng-model="model" uib-btn-radio="2">click2</button>', $scope);
      expect(btns.eq(0)).toHaveClass('active');
      expect(btns.eq(1)).not.toHaveClass('active');

      btns.eq(0).click();
      $scope.$digest();
      expect(btns.eq(0)).toHaveClass('active');
      expect(btns.eq(1)).not.toHaveClass('active');
    });

    it('should not toggle when disabled - issue 4013', function() {
      $scope.model = 1;
      var btns = compileButtons('<button ng-model="model" uib-btn-radio="1">click1</button><button disabled ng-model="model" uib-btn-radio="2">click2</button>', $scope);

      expect(btns.eq(0)).toHaveClass('active');
      expect(btns.eq(1)).not.toHaveClass('active');

      btns.eq(1).click();

      expect(btns.eq(0)).toHaveClass('active');
      expect(btns.eq(1)).not.toHaveClass('active');

      $scope.$digest();

      expect(btns.eq(0)).toHaveClass('active');
      expect(btns.eq(1)).not.toHaveClass('active');
    });

    it('should handle string values in uib-btn-radio value', function() {
      $scope.model = 'Two';
      var btns = compileButtons('<button ng-model="model" uib-btn-radio="\'One\'">click1</button><button ng-model="model" uib-btn-radio="\'Two\'">click2</button>', $scope);

      expect(btns.eq(0)).not.toHaveClass('active');
      expect(btns.eq(1)).toHaveClass('active');

      btns.eq(0).click();
      expect(btns.eq(0)).toHaveClass('active');
      expect(btns.eq(1)).not.toHaveClass('active');
      expect($scope.model).toEqual('One');

      $scope.$digest();

      expect(btns.eq(0)).toHaveClass('active');
      expect(btns.eq(1)).not.toHaveClass('active');
      expect($scope.model).toEqual('One');
    });

    describe('uncheckable', function() {
      //model -> UI
      it('should set active class based on model', function() {
        var btns = compileButtons('<button ng-model="model" uib-btn-radio="1" uncheckable>click1</button><button ng-model="model" uib-btn-radio="2" uncheckable>click2</button>', $scope);
        expect(btns.eq(0)).not.toHaveClass('active');
        expect(btns.eq(1)).not.toHaveClass('active');

        $scope.model = 2;
        $scope.$digest();
        expect(btns.eq(0)).not.toHaveClass('active');
        expect(btns.eq(1)).toHaveClass('active');
      });

      //UI->model
      it('should unset active class via click', function() {
        var btns = compileButtons('<button ng-model="model" uib-btn-radio="1" uncheckable>click1</button><button ng-model="model" uib-btn-radio="2" uncheckable>click2</button>', $scope);
        expect($scope.model).toBeUndefined();

        btns.eq(0).click();
        expect($scope.model).toEqual(1);
        expect(btns.eq(0)).toHaveClass('active');
        expect(btns.eq(1)).not.toHaveClass('active');

        btns.eq(0).click();
        expect($scope.model).toBeNull();
        expect(btns.eq(1)).not.toHaveClass('active');
        expect(btns.eq(0)).not.toHaveClass('active');
      });

      it('should watch uib-btn-radio values and update state', function() {
        $scope.values = ['value1', 'value2'];

        var btns = compileButtons('<button ng-model="model" uib-btn-radio="values[0]" uncheckable>click1</button><button ng-model="model" uib-btn-radio="values[1]" uncheckable>click2</button>', $scope);
        expect(btns.eq(0)).not.toHaveClass('active');
        expect(btns.eq(1)).not.toHaveClass('active');

        $scope.model = 'value2';
        $scope.$digest();
        expect(btns.eq(0)).not.toHaveClass('active');
        expect(btns.eq(1)).toHaveClass('active');

        $scope.model = undefined;
        $scope.$digest();
        expect(btns.eq(0)).not.toHaveClass('active');
        expect(btns.eq(1)).not.toHaveClass('active');
      });
    });
  });
});
<commit_msg>chore(buttons): clean up code style<commit_after>describe('buttons', function() {

  var $scope, $compile;

  beforeEach(module('ui.bootstrap.buttons'));
  beforeEach(inject(function(_$rootScope_, _$compile_) {
    $scope = _$rootScope_;
    $compile = _$compile_;
  }));

  describe('checkbox', function() {
    var compileButton = function(markup, scope) {
      var el = $compile(markup)(scope);
      scope.$digest();
      return el;
    };

    it('should expose the controller to the view', inject(function($templateCache) {
      var btn = compileButton('<button ng-model="model" uib-btn-checkbox>{{button.text}}</button>', $scope);
      var ctrl = btn.controller('uibBtnCheckbox');
      expect(ctrl).toBeDefined();

      ctrl.text = 'foo';
      $scope.$digest();

      expect(btn.html()).toBe('foo');
    }));

    //model -> UI
    it('should work correctly with default model values', function() {
      $scope.model = false;
      var btn = compileButton('<button ng-model="model" uib-btn-checkbox>click</button>', $scope);
      expect(btn).not.toHaveClass('active');

      $scope.model = true;
      $scope.$digest();
      expect(btn).toHaveClass('active');
    });

    it('should bind custom model values', function() {
      $scope.model = 1;
      var btn = compileButton('<button ng-model="model" uib-btn-checkbox btn-checkbox-true="1" btn-checkbox-false="0">click</button>', $scope);
      expect(btn).toHaveClass('active');

      $scope.model = 0;
      $scope.$digest();
      expect(btn).not.toHaveClass('active');
    });

    //UI-> model
    it('should toggle default model values on click', function() {
      $scope.model = false;
      var btn = compileButton('<button ng-model="model" uib-btn-checkbox>click</button>', $scope);

      btn.click();
      expect($scope.model).toEqual(true);
      expect(btn).toHaveClass('active');

      btn.click();
      expect($scope.model).toEqual(false);
      expect(btn).not.toHaveClass('active');
    });

    it('should toggle custom model values on click', function() {
      $scope.model = 0;
      var btn = compileButton('<button ng-model="model" uib-btn-checkbox btn-checkbox-true="1" btn-checkbox-false="0">click</button>', $scope);

      btn.click();
      expect($scope.model).toEqual(1);
      expect(btn).toHaveClass('active');

      btn.click();
      expect($scope.model).toEqual(0);
      expect(btn).not.toHaveClass('active');
    });

    it('should monitor true / false value changes - issue 666', function() {

      $scope.model = 1;
      $scope.trueVal = 1;
      var btn = compileButton('<button ng-model="model" uib-btn-checkbox btn-checkbox-true="trueVal">click</button>', $scope);

      expect(btn).toHaveClass('active');
      expect($scope.model).toEqual(1);

      $scope.model = 2;
      $scope.trueVal = 2;
      $scope.$digest();

      expect(btn).toHaveClass('active');
      expect($scope.model).toEqual(2);
    });

    it('should not toggle when disabled - issue 4013', function() {
      $scope.model = 1;
      $scope.falseVal = 0;
      var btn = compileButton('<button disabled ng-model="model" uib-btn-checkbox btn-checkbox-true="falseVal">click</button>', $scope);

      expect(btn).not.toHaveClass('active');
      expect($scope.model).toEqual(1);

      btn.click();

      expect(btn).not.toHaveClass('active');

      $scope.$digest();

      expect(btn).not.toHaveClass('active');
    });

    describe('setting buttonConfig', function() {
      var uibButtonConfig, originalActiveClass, originalToggleEvent;

      beforeEach(inject(function(_uibButtonConfig_) {
        uibButtonConfig = _uibButtonConfig_;
        originalActiveClass = uibButtonConfig.activeClass;
        originalToggleEvent = uibButtonConfig.toggleEvent;
        uibButtonConfig.activeClass = false;
        uibButtonConfig.toggleEvent = false;
      }));

      afterEach(function() {
        // return it to the original value
        uibButtonConfig.activeClass = originalActiveClass;
        uibButtonConfig.toggleEvent = originalToggleEvent;
      });

      it('should use default config when buttonConfig.activeClass and buttonConfig.toggleEvent is false', function() {
        $scope.model = false;
        var btn = compileButton('<button ng-model="model" uib-btn-checkbox>click</button>', $scope);
        expect(btn).not.toHaveClass('active');

        $scope.model = true;
        $scope.$digest();
        expect(btn).toHaveClass('active');
      });

      it('should be able to use a different active class', function() {
        uibButtonConfig.activeClass = 'foo';
        $scope.model = false;
        var btn = compileButton('<button ng-model="model" uib-btn-checkbox>click</button>', $scope);
        expect(btn).not.toHaveClass('foo');

        $scope.model = true;
        $scope.$digest();
        expect(btn).toHaveClass('foo');
      });

      it('should be able to use a different toggle event', function() {
        uibButtonConfig.toggleEvent = 'mouseenter';
        $scope.model = false;
        var btn = compileButton('<button ng-model="model" uib-btn-checkbox>click</button>', $scope);
        expect(btn).not.toHaveClass('active');

        btn.trigger('mouseenter');

        $scope.$digest();
        expect(btn).toHaveClass('active');
      });
    });

  });

  describe('radio', function() {
    var compileButtons = function(markup, scope) {
      var el = $compile('
'+markup+'
')(scope);
      scope.$digest();
      return el.find('button');
    };

    it('should expose the controller to the view', inject(function($templateCache) {
      var btn = compileButtons('<button ng-model="model" uib-btn-radio="1">{{buttons.text}}</button>', $scope);
      var ctrl = btn.controller('uibBtnRadio');
      expect(ctrl).toBeDefined();

      ctrl.text = 'foo';
      $scope.$digest();

      expect(btn.html()).toBe('foo');
    }));

    //model -> UI
    it('should set active class based on model', function() {
      var btns = compileButtons('<button ng-model="model" uib-btn-radio="1">click1</button><button ng-model="model" uib-btn-radio="2">click2</button>', $scope);
      expect(btns.eq(0)).not.toHaveClass('active');
      expect(btns.eq(1)).not.toHaveClass('active');

      $scope.model = 2;
      $scope.$digest();
      expect(btns.eq(0)).not.toHaveClass('active');
      expect(btns.eq(1)).toHaveClass('active');
    });

    //UI->model
    it('should set active class via click', function() {
      var btns = compileButtons('<button ng-model="model" uib-btn-radio="1">click1</button><button ng-model="model" uib-btn-radio="2">click2</button>', $scope);
      expect($scope.model).toBeUndefined();

      btns.eq(0).click();
      expect($scope.model).toEqual(1);
      expect(btns.eq(0)).toHaveClass('active');
      expect(btns.eq(1)).not.toHaveClass('active');

      btns.eq(1).click();
      expect($scope.model).toEqual(2);
      expect(btns.eq(1)).toHaveClass('active');
      expect(btns.eq(0)).not.toHaveClass('active');
    });

    it('should watch uib-btn-radio values and update state accordingly', function() {
      $scope.values = ['value1', 'value2'];

      var btns = compileButtons('<button ng-model="model" uib-btn-radio="values[0]">click1</button><button ng-model="model" uib-btn-radio="values[1]">click2</button>', $scope);
      expect(btns.eq(0)).not.toHaveClass('active');
      expect(btns.eq(1)).not.toHaveClass('active');

      $scope.model = 'value2';
      $scope.$digest();
      expect(btns.eq(0)).not.toHaveClass('active');
      expect(btns.eq(1)).toHaveClass('active');

      $scope.values[1] = 'value3';
      $scope.model = 'value3';
      $scope.$digest();
      expect(btns.eq(0)).not.toHaveClass('active');
      expect(btns.eq(1)).toHaveClass('active');
    });

    it('should do nothing when clicking an active radio', function() {
      $scope.model = 1;
      var btns = compileButtons('<button ng-model="model" uib-btn-radio="1">click1</button><button ng-model="model" uib-btn-radio="2">click2</button>', $scope);
      expect(btns.eq(0)).toHaveClass('active');
      expect(btns.eq(1)).not.toHaveClass('active');

      btns.eq(0).click();
      $scope.$digest();
      expect(btns.eq(0)).toHaveClass('active');
      expect(btns.eq(1)).not.toHaveClass('active');
    });

    it('should not toggle when disabled - issue 4013', function() {
      $scope.model = 1;
      var btns = compileButtons('<button ng-model="model" uib-btn-radio="1">click1</button><button disabled ng-model="model" uib-btn-radio="2">click2</button>', $scope);

      expect(btns.eq(0)).toHaveClass('active');
      expect(btns.eq(1)).not.toHaveClass('active');

      btns.eq(1).click();

      expect(btns.eq(0)).toHaveClass('active');
      expect(btns.eq(1)).not.toHaveClass('active');

      $scope.$digest();

      expect(btns.eq(0)).toHaveClass('active');
      expect(btns.eq(1)).not.toHaveClass('active');
    });

    it('should handle string values in uib-btn-radio value', function() {
      $scope.model = 'Two';
      var btns = compileButtons('<button ng-model="model" uib-btn-radio="\'One\'">click1</button><button ng-model="model" uib-btn-radio="\'Two\'">click2</button>', $scope);

      expect(btns.eq(0)).not.toHaveClass('active');
      expect(btns.eq(1)).toHaveClass('active');

      btns.eq(0).click();
      expect(btns.eq(0)).toHaveClass('active');
      expect(btns.eq(1)).not.toHaveClass('active');
      expect($scope.model).toEqual('One');

      $scope.$digest();

      expect(btns.eq(0)).toHaveClass('active');
      expect(btns.eq(1)).not.toHaveClass('active');
      expect($scope.model).toEqual('One');
    });

    describe('uncheckable', function() {
      //model -> UI
      it('should set active class based on model', function() {
        var btns = compileButtons('<button ng-model="model" uib-btn-radio="1" uncheckable>click1</button><button ng-model="model" uib-btn-radio="2" uncheckable>click2</button>', $scope);
        expect(btns.eq(0)).not.toHaveClass('active');
        expect(btns.eq(1)).not.toHaveClass('active');

        $scope.model = 2;
        $scope.$digest();
        expect(btns.eq(0)).not.toHaveClass('active');
        expect(btns.eq(1)).toHaveClass('active');
      });

      //UI->model
      it('should unset active class via click', function() {
        var btns = compileButtons('<button ng-model="model" uib-btn-radio="1" uncheckable>click1</button><button ng-model="model" uib-btn-radio="2" uncheckable>click2</button>', $scope);
        expect($scope.model).toBeUndefined();

        btns.eq(0).click();
        expect($scope.model).toEqual(1);
        expect(btns.eq(0)).toHaveClass('active');
        expect(btns.eq(1)).not.toHaveClass('active');

        btns.eq(0).click();
        expect($scope.model).toBeNull();
        expect(btns.eq(1)).not.toHaveClass('active');
        expect(btns.eq(0)).not.toHaveClass('active');
      });

      it('should watch uib-btn-radio values and update state', function() {
        $scope.values = ['value1', 'value2'];

        var btns = compileButtons('<button ng-model="model" uib-btn-radio="values[0]" uncheckable>click1</button><button ng-model="model" uib-btn-radio="values[1]" uncheckable>click2</button>', $scope);
        expect(btns.eq(0)).not.toHaveClass('active');
        expect(btns.eq(1)).not.toHaveClass('active');

        $scope.model = 'value2';
        $scope.$digest();
        expect(btns.eq(0)).not.toHaveClass('active');
        expect(btns.eq(1)).toHaveClass('active');

        $scope.model = undefined;
        $scope.$digest();
        expect(btns.eq(0)).not.toHaveClass('active');
        expect(btns.eq(1)).not.toHaveClass('active');
      });
    });
  });
});
<|endoftext|>


<commit_before>/* eslint-disable no-process-exit */

/**
 * Data creation script for academic data pushes. Run this script with
 * node seed/get-challenge-completion.js >> ~/output.json
 * For large data sets supply the flag --max_old_space_size=2000000 to node.
 * Run from the root FCC directory. Beware, this will generate a very large file
 * if you have a large user collection such as the production mongo db.
*/

require('dotenv').load();
var secrets = require('../config/secrets'),
    mongodb = require('mongodb'),
    MongoClient = mongodb.MongoClient;

MongoClient.connect(secrets.db, function(err, database) {
  if (err) {
    throw err;
  }
  var stream = database.collection('user')
        .find({'completedChallenges': { $ne: null },
               'isLocked': { $ne: true } },
              {'completedChallenges': true})
        .stream();
  console.log('[');
  stream.on('data', function(results) {
    if (!results.completedChallenges) {
      // dud
    } else {
      var dataOut = [];
      results.completedChallenges.forEach(function(challenge) {
        dataOut.push({
          name: challenge.name,
          completedDate: challenge.completedDate,
          solution: challenge.solution
        });
      });
      if (dataOut.length) {
          console.log(JSON.stringify(dataOut) + ',');
      }
    }
  }).on('end', function() {
    console.log(']');
    process.exit(0);
  });
});
<commit_msg>Fixes invalid JSON format data exporting<commit_after>/* eslint-disable no-process-exit */

/**
 * Data creation script for academic data pushes. Run this script with
 * node seed/get-challenge-completion.js >> ~/output.json
 * For large data sets supply the flag --max_old_space_size=2000000 to node.
 * Run from the root FCC directory. Beware, this will generate a very large file
 * if you have a large user collection such as the production mongo db.
*/

require('dotenv').load();
var secrets = require('../config/secrets'),
    mongodb = require('mongodb'),
    MongoClient = mongodb.MongoClient;

MongoClient.connect(secrets.db, function(err, database) {
  if (err) {
    throw err;
  }
  var firstTime = true;

  var stream = database.collection('user')
        .find({'completedChallenges': { $ne: null },
               'isLocked': { $ne: true } },
              {'completedChallenges': true})
        .stream();
  console.log('[');
  stream.on('data', function(results) {
    if (!results.completedChallenges) {
      // dud
    } else {
      var dataOut = [];
      results.completedChallenges.forEach(function(challenge) {
        dataOut.push({
          name: challenge.name,
          completedDate: challenge.completedDate,
          solution: challenge.solution
        });
      });
      if (dataOut.length) {
        if (!firstTime) {
          console.log(',' + JSON.stringify(dataOut));
        } else {
          firstTime = false;
          console.log(JSON.stringify(dataOut));
        }
      }
    }
  }).on('end', function() {
    console.log(']');
    process.exit(0);
  });
});
<|endoftext|>


<commit_before>module.exports = {
  localeCurrencyData: {
    'bn-IN': 'inr',
    'cs': 'czk',
    'da': 'ddk',
    'de': 'eur',
    'es': 'eur',
    'es-AR': 'ars',
    'es-CL': 'clp',
    'es-ES': 'eur',
    'es-MX': 'mxn',
    'es-XL': 'mxn',
    'en-AU': 'aud',
    'en-CA': 'cad',
    'en-GB': 'gbp',
    'en-IN': 'inr',
    'en-US': 'usd',
    'en-ZA': 'zar',
    'fi': 'eur',
    'fr': 'eur',
    'gu-IN': 'inr',
    'hi-IN': 'inr',
    'hu': 'huf',
    'id': 'idr',
    'it': 'eur',
    'ja': 'jpy',
    'lv': 'eur',
    'ml': 'inr',
    'mr': 'inr',
    'nl': 'eur',
    'pa-IN': 'inr',
    'pl': 'pln',
    'pt-BR': 'brl',
    'pt-PT': 'eur',
    'ru': 'rub',
    'sk': 'eur',
    'sl': 'eur',
    'sv-SE': 'sek',
    'te': 'inr',
    'uk': 'uah',
    'zh-CN': 'cny',
    'zh-TW': 'twd'
  },
  localeCountryData: {
    'bn-IN': 'IN',
    'cs': 'CS',
    'da': 'DA',
    'de': 'DE',
    'es': 'ES',
    'es-AR': 'AR',
    'es-CL': 'CL',
    'es-ES': 'ES',
    'es-MX': 'MX',
    'en-AU': 'AU',
    'en-CA': 'CA',
    'en-GB': 'GB',
    'en-IN': 'IN',
    'en-US': 'US',
    'en-ZA': 'ZA',
    'fi': 'FI',
    'fr': 'FR',
    'gu-IN': 'IN',
    'hi-IN': 'IN',
    'hu': 'HU',
    'id': 'ID',
    'it': 'IT',
    'ja': 'JP',
    'lv': 'LV',
    'ml': 'IN',
    'mr': 'IN',
    'nl': 'NL',
    'pa-IN': 'IN',
    'pt-BR': 'BR',
    'pt-PT': 'PT',
    'ru': 'RU',
    'sl': 'SL',
    'sv-SE': 'SE',
    'te': 'IN',
    'th': 'TH',
    'uk': 'UK',
    'zh-CN': 'CN',
    'zh-TW': 'TW'
  }
};
<commit_msg>Default currency for Hebrew (#1726)<commit_after>module.exports = {
  localeCurrencyData: {
    'bn-IN': 'inr',
    'cs': 'czk',
    'da': 'ddk',
    'de': 'eur',
    'es': 'eur',
    'es-AR': 'ars',
    'es-CL': 'clp',
    'es-ES': 'eur',
    'es-MX': 'mxn',
    'es-XL': 'mxn',
    'en-AU': 'aud',
    'en-CA': 'cad',
    'en-GB': 'gbp',
    'en-IN': 'inr',
    'en-US': 'usd',
    'en-ZA': 'zar',
    'fi': 'eur',
    'fr': 'eur',
    'gu-IN': 'inr',
    'he': 'ils',
    'hi-IN': 'inr',
    'hu': 'huf',
    'id': 'idr',
    'it': 'eur',
    'ja': 'jpy',
    'lv': 'eur',
    'ml': 'inr',
    'mr': 'inr',
    'nl': 'eur',
    'pa-IN': 'inr',
    'pl': 'pln',
    'pt-BR': 'brl',
    'pt-PT': 'eur',
    'ru': 'rub',
    'sk': 'eur',
    'sl': 'eur',
    'sv-SE': 'sek',
    'te': 'inr',
    'uk': 'uah',
    'zh-CN': 'cny',
    'zh-TW': 'twd'
  },
  localeCountryData: {
    'bn-IN': 'IN',
    'cs': 'CS',
    'da': 'DA',
    'de': 'DE',
    'es': 'ES',
    'es-AR': 'AR',
    'es-CL': 'CL',
    'es-ES': 'ES',
    'es-MX': 'MX',
    'en-AU': 'AU',
    'en-CA': 'CA',
    'en-GB': 'GB',
    'en-IN': 'IN',
    'en-US': 'US',
    'en-ZA': 'ZA',
    'fi': 'FI',
    'fr': 'FR',
    'gu-IN': 'IN',
    'he': 'IL',
    'hi-IN': 'IN',
    'hu': 'HU',
    'id': 'ID',
    'it': 'IT',
    'ja': 'JP',
    'lv': 'LV',
    'ml': 'IN',
    'mr': 'IN',
    'nl': 'NL',
    'pa-IN': 'IN',
    'pt-BR': 'BR',
    'pt-PT': 'PT',
    'ru': 'RU',
    'sl': 'SL',
    'sv-SE': 'SE',
    'te': 'IN',
    'th': 'TH',
    'uk': 'UK',
    'zh-CN': 'CN',
    'zh-TW': 'TW'
  }
};
<|endoftext|>


<commit_before>var request = require("request");

/*
 * DiscoveryClient constructor.
 * Creates a new uninitialized DiscoveryClient.
 */
function DiscoveryClient(host, options) {
  this.host = host;
  this.state = {announcements: {}};
  this.logger = (options && options.logger) || require("ot-logger");
  this.errorHandlers = [this.logger.log.bind(this.logger, 'error', 'Discovery error: ')];
  this.watchers = [this._update.bind(this), this.logger.log.bind(this.logger, 'debug', 'Discovery update: ')];
  this.announcements = [];
  this.backoff = 1;
}

/* Increase the watch backoff interval */
DiscoveryClient.prototype._backoff = function () {
  this.backoff = Math.min(this.backoff * 2, 10240);
};

/* Reset the watch backoff interval */
DiscoveryClient.prototype._unbackoff = function() {
  this.backoff = 1;
};

DiscoveryClient.prototype._randomServer = function() {
  return this.servers[Math.floor(Math.random()*this.servers.length)];
};

/* Consume a WatchResult from the discovery server and update internal state */
DiscoveryClient.prototype._update = function (update) {
  var disco = this;
  if (update.fullUpdate) {
    Object.keys(disco.state.announcements).forEach(function (id) { delete disco.state.announcements[id]; });
  }
  disco.state.index = update.index;
  update.deletes.forEach(function (id) { delete disco.state.announcements[id]; });
  update.updates.forEach(function (announcement) { disco.state.announcements[announcement.announcementId] = announcement; });
};

/* Connect to the Discovery servers given the endpoint of any one of them */
DiscoveryClient.prototype.connect = function (onComplete) {
  var disco = this;
  request({
    url: "http://" + this.host + "/watch",
    json: true
  }, function (error, response, update) {
    if (error) {
      onComplete(error);
      return;
    }
    if (response.statusCode != 200) {
      onComplete(new Error("Unable to initiate discovery: " + JSON.stringify(update)), undefined, undefined);
      return;
    }

    if (!update.fullUpdate) {
      onComplete(new Error("Expecting a full update: " + JSON.stringify(update)), undefined, undefined);
      return;
    }

    disco.logger.log('debug', 'Discovery update: %s', JSON.stringify(update));
    disco._update(update);

    disco.servers = [];

    Object.keys(disco.state.announcements).forEach(function (id) {
      var announcement = disco.state.announcements[id];
      if (announcement.serviceType == "discovery") {
        disco.servers.push(announcement.serviceUri);
      }
    });

    disco._schedulePoll();
    setInterval(disco._announce.bind(disco), 10000);
    onComplete(undefined, disco.host, disco.servers);
  });
};

DiscoveryClient.prototype.reconnect = function (onComplete) {
  var disco = this;
  disco.logger.log('info', 'Attempting to reconnect to Discovery on %s', disco.host);
  disco.reconnectScheduled = false;
  disco.state.index = -1;
  request({
    url: "http://" + disco.host + "/watch?since=" + (this.state.index),
    json: true
  }, function (error, response, update) {
    if (error) {
      disco.logger.log('error', 'Could not reconnect to Discovery on: %s', disco.host);
      disco._scheduleReconnect();
      return;
    }
    if (response.statusCode != 200) {
      disco.logger.log('error', 'Could not reconnect to Discovery on: %s', disco.host);
      disco._scheduleReconnect();
      return;
    }

    if (!update.fullUpdate) {
      disco.logger.log('error', 'Expecting a full update: %s', JSON.stringify(update));
      disco._scheduleReconnect();
      return;
    }

    disco.logger.log('info', 'Reconnected toDiscovery on %s', disco.host);

    disco._update(update);
    disco.servers = [];
    Object.keys(disco.state.announcements).forEach(function (id) {
      var announcement = disco.state.announcements[id];
      if (announcement.serviceType == "discovery") {
        disco.servers.push(announcement.serviceUri);
      }
    });

    disco._unbackoff();
    disco._schedulePoll();
  });
};

/* Register a callback on every discovery update */
DiscoveryClient.prototype.onUpdate = function (watcher) {
  this.watchers.push(watcher);
};

/* Register a callback on every error */
DiscoveryClient.prototype.onError = function (handler) {
  this.errorHandlers.push(handler);
};

/* Internal scheduling method.  Schedule the next poll in the event loop */
DiscoveryClient.prototype._schedulePoll = function () {
  if (!this.servers.length) {
    this._scheduleReconnect();
    return;
  }
  setImmediate(this.poll.bind(this));
};

DiscoveryClient.prototype._scheduleReconnect = function () {
  if (this.reconnectScheduled) {
    return;
  }

  this.reconnectScheduled = true;
  var c = this.reconnect.bind(this);
  if (this.backoff <= 1) {
    setImmediate(c);
  } else {
    setTimeout(c, this.backoff).unref();
  }
  this._backoff();
};

/* Long-poll the discovery server for changes */
DiscoveryClient.prototype.poll = function () {
  var disco = this;
  var server = this._randomServer();
  var url = server + "/watch?since=" + (this.state.index + 1);
  request({
    url: url,
    json: true
  }, function (error, response, body) {
    if (error) {
      disco.errorHandlers.forEach(function (h) { h(error); });
      disco.dropServer(server);
      disco._schedulePoll();
      return;
    }
    if (response.statusCode == 204) {
      disco._schedulePoll();
      return;
    }
    if (response.statusCode != 200) {
      var err = new Error("Bad status code " + response.statusCode + " from watch: " + response);
      disco.errorHandlers.forEach(function (h) { h(err); });
      disco.dropServer(server);
      disco._schedulePoll();
      return;
    }
    disco.watchers.forEach(function (w) { w(body); });
    disco._schedulePoll();
  });
};

DiscoveryClient.prototype.dropServer = function (server) {
  this.logger.log('info', 'Dropping discovery server %s', server);
  this.servers.splice(this.servers.indexOf(server), 1);
};

/* Lookup a service by service type!
 * Accepts one of:
 *   serviceType as string
 *   serviceType:feature as string
 *   predicate function over announcement object
 */
DiscoveryClient.prototype.findAll = function (predicate) {
  var disco = this;
  var candidates = [];

  if (typeof(predicate) != "function") {
    var serviceType = predicate;
    predicate = function(a) {
      return a.serviceType == serviceType || a.serviceType + ":" + a.feature == serviceType;
    };
  }

  Object.keys(disco.state.announcements).forEach(function (id) {
    var a = disco.state.announcements[id];
    if (predicate(a)) {
      candidates.push(a.serviceUri);
    }
  });

  return candidates;
};

DiscoveryClient.prototype.find = function (predicate) {
  var candidates = this.findAll(predicate);
  if (candidates.length === 0) {
    return undefined;
  }
  return candidates[Math.floor(Math.random()*candidates.length)];
};

DiscoveryClient.prototype._announce = function() {
  var disco = this;
  function cb(error, announcement) {
    if (error) {
      disco.errorHandlers.forEach(function (h) { h(error); });
    }
  }
  this.announcements.forEach(function (a) {
    disco._singleAnnounce(a, cb);
  });
};

DiscoveryClient.prototype._singleAnnounce = function (announcement, cb) {
  var server = this._randomServer();
  request({
    url: server + "/announcement",
    method: "POST",
    json: true,
    body: announcement
  }, function (error, response, body) {
    if (error) {
      cb(error);
      return;
    }
    if (response.statusCode != 201) {
      cb(new Error("During announce, bad status code " + response.statusCode + ": " + JSON.stringify(body)));
      return;
    }
    cb(undefined, body);
  });
};

/* Announce ourselves to the registry */
DiscoveryClient.prototype.announce = function (announcement, cb) {
  var disco = this;
  this._singleAnnounce(announcement, function(error, a) {
    if (error) {
      cb(error);
      return;
    }
    disco.logger.log("Announced as " + JSON.stringify(a));
    disco.announcements.push(a);
    cb(undefined, a);
  });
};

/* Remove a previous announcement.  The passed object *must* be the
 * lease as returned by the 'announce' callback. */
DiscoveryClient.prototype.unannounce = function (announcement, callback) {
  var disco = this;
  var server = disco._randomServer();
  var url = server + "/announcement/" + announcement.announcementId;
  disco.announcements.splice(disco.announcements.indexOf(announcement), 1);
  request({
    url: url,
    method: "DELETE"
  }, function (error, response, body) {
    if (error) {
      disco.logger.error(error);
    } else {
      disco.logger.log("Unannounce DELETE '" + url + "' returned " + response.statusCode + ": " + JSON.stringify(body));
    }
    if (callback) {
      callback();
    }
  });
};

module.exports = DiscoveryClient;
<commit_msg>Don't announce if there are no servers<commit_after>var request = require("request");

/*
 * DiscoveryClient constructor.
 * Creates a new uninitialized DiscoveryClient.
 */
function DiscoveryClient(host, options) {
  this.host = host;
  this.state = {announcements: {}};
  this.logger = (options && options.logger) || require("ot-logger");
  this.errorHandlers = [this.logger.log.bind(this.logger, 'error', 'Discovery error: ')];
  this.watchers = [this._update.bind(this), this.logger.log.bind(this.logger, 'debug', 'Discovery update: ')];
  this.announcements = [];
  this.backoff = 1;
}

/* Increase the watch backoff interval */
DiscoveryClient.prototype._backoff = function () {
  this.backoff = Math.min(this.backoff * 2, 10240);
};

/* Reset the watch backoff interval */
DiscoveryClient.prototype._unbackoff = function() {
  this.backoff = 1;
};

DiscoveryClient.prototype._randomServer = function() {
  return this.servers[Math.floor(Math.random()*this.servers.length)];
};

/* Consume a WatchResult from the discovery server and update internal state */
DiscoveryClient.prototype._update = function (update) {
  var disco = this;
  if (update.fullUpdate) {
    Object.keys(disco.state.announcements).forEach(function (id) { delete disco.state.announcements[id]; });
  }
  disco.state.index = update.index;
  update.deletes.forEach(function (id) { delete disco.state.announcements[id]; });
  update.updates.forEach(function (announcement) { disco.state.announcements[announcement.announcementId] = announcement; });
};

/* Connect to the Discovery servers given the endpoint of any one of them */
DiscoveryClient.prototype.connect = function (onComplete) {
  var disco = this;
  request({
    url: "http://" + this.host + "/watch",
    json: true
  }, function (error, response, update) {
    if (error) {
      onComplete(error);
      return;
    }
    if (response.statusCode != 200) {
      onComplete(new Error("Unable to initiate discovery: " + JSON.stringify(update)), undefined, undefined);
      return;
    }

    if (!update.fullUpdate) {
      onComplete(new Error("Expecting a full update: " + JSON.stringify(update)), undefined, undefined);
      return;
    }

    disco.logger.log('debug', 'Discovery update: %s', JSON.stringify(update));
    disco._update(update);

    disco.servers = [];

    Object.keys(disco.state.announcements).forEach(function (id) {
      var announcement = disco.state.announcements[id];
      if (announcement.serviceType == "discovery") {
        disco.servers.push(announcement.serviceUri);
      }
    });

    disco._schedulePoll();
    setInterval(disco._announce.bind(disco), 10000);
    onComplete(undefined, disco.host, disco.servers);
  });
};

DiscoveryClient.prototype.reconnect = function (onComplete) {
  var disco = this;
  disco.logger.log('info', 'Attempting to reconnect to Discovery on %s', disco.host);
  disco.reconnectScheduled = false;
  disco.state.index = -1;
  request({
    url: "http://" + disco.host + "/watch?since=" + (this.state.index),
    json: true
  }, function (error, response, update) {
    if (error) {
      disco.logger.log('error', 'Could not reconnect to Discovery on: %s', disco.host);
      disco._scheduleReconnect();
      return;
    }
    if (response.statusCode != 200) {
      disco.logger.log('error', 'Could not reconnect to Discovery on: %s', disco.host);
      disco._scheduleReconnect();
      return;
    }

    if (!update.fullUpdate) {
      disco.logger.log('error', 'Expecting a full update: %s', JSON.stringify(update));
      disco._scheduleReconnect();
      return;
    }

    disco.logger.log('info', 'Reconnected toDiscovery on %s', disco.host);

    disco._update(update);
    disco.servers = [];
    Object.keys(disco.state.announcements).forEach(function (id) {
      var announcement = disco.state.announcements[id];
      if (announcement.serviceType == "discovery") {
        disco.servers.push(announcement.serviceUri);
      }
    });

    disco._unbackoff();
    disco._schedulePoll();
  });
};

/* Register a callback on every discovery update */
DiscoveryClient.prototype.onUpdate = function (watcher) {
  this.watchers.push(watcher);
};

/* Register a callback on every error */
DiscoveryClient.prototype.onError = function (handler) {
  this.errorHandlers.push(handler);
};

/* Internal scheduling method.  Schedule the next poll in the event loop */
DiscoveryClient.prototype._schedulePoll = function () {
  if (!this.servers.length) {
    this._scheduleReconnect();
    return;
  }
  setImmediate(this.poll.bind(this));
};

DiscoveryClient.prototype._scheduleReconnect = function () {
  if (this.reconnectScheduled) {
    return;
  }

  this.reconnectScheduled = true;
  var c = this.reconnect.bind(this);
  if (this.backoff <= 1) {
    setImmediate(c);
  } else {
    setTimeout(c, this.backoff).unref();
  }
  this._backoff();
};

/* Long-poll the discovery server for changes */
DiscoveryClient.prototype.poll = function () {
  var disco = this;
  var server = this._randomServer();
  var url = server + "/watch?since=" + (this.state.index + 1);
  request({
    url: url,
    json: true
  }, function (error, response, body) {
    if (error) {
      disco.errorHandlers.forEach(function (h) { h(error); });
      disco.dropServer(server);
      disco._schedulePoll();
      return;
    }
    if (response.statusCode == 204) {
      disco._schedulePoll();
      return;
    }
    if (response.statusCode != 200) {
      var err = new Error("Bad status code " + response.statusCode + " from watch: " + response);
      disco.errorHandlers.forEach(function (h) { h(err); });
      disco.dropServer(server);
      disco._schedulePoll();
      return;
    }
    disco.watchers.forEach(function (w) { w(body); });
    disco._schedulePoll();
  });
};

DiscoveryClient.prototype.dropServer = function (server) {
  this.logger.log('info', 'Dropping discovery server %s', server);
  this.servers.splice(this.servers.indexOf(server), 1);
};

/* Lookup a service by service type!
 * Accepts one of:
 *   serviceType as string
 *   serviceType:feature as string
 *   predicate function over announcement object
 */
DiscoveryClient.prototype.findAll = function (predicate) {
  var disco = this;
  var candidates = [];

  if (typeof(predicate) != "function") {
    var serviceType = predicate;
    predicate = function(a) {
      return a.serviceType == serviceType || a.serviceType + ":" + a.feature == serviceType;
    };
  }

  Object.keys(disco.state.announcements).forEach(function (id) {
    var a = disco.state.announcements[id];
    if (predicate(a)) {
      candidates.push(a.serviceUri);
    }
  });

  return candidates;
};

DiscoveryClient.prototype.find = function (predicate) {
  var candidates = this.findAll(predicate);
  if (candidates.length === 0) {
    return undefined;
  }
  return candidates[Math.floor(Math.random()*candidates.length)];
};

DiscoveryClient.prototype._announce = function() {
  var disco = this;
  function cb(error, announcement) {
    if (error) {
      disco.errorHandlers.forEach(function (h) { h(error); });
    }
  }
  this.announcements.forEach(function (a) {
    disco._singleAnnounce(a, cb);
  });
};

DiscoveryClient.prototype._singleAnnounce = function (announcement, cb) {
  var server = this._randomServer();
  if (!server) {
    this.logger.log('info', 'Cannot announce. No discovery servers available');
    cb(new Error('Cannot announce. No discovery servers available'));
  }
  request({
    url: server + "/announcement",
    method: "POST",
    json: true,
    body: announcement
  }, function (error, response, body) {
    if (error) {
      cb(error);
      return;
    }
    if (response.statusCode != 201) {
      cb(new Error("During announce, bad status code " + response.statusCode + ": " + JSON.stringify(body)));
      return;
    }
    cb(undefined, body);
  });
};

/* Announce ourselves to the registry */
DiscoveryClient.prototype.announce = function (announcement, cb) {
  var disco = this;
  this._singleAnnounce(announcement, function(error, a) {
    if (error) {
      cb(error);
      return;
    }
    disco.logger.log("Announced as " + JSON.stringify(a));
    disco.announcements.push(a);
    cb(undefined, a);
  });
};

/* Remove a previous announcement.  The passed object *must* be the
 * lease as returned by the 'announce' callback. */
DiscoveryClient.prototype.unannounce = function (announcement, callback) {
  var disco = this;
  var server = disco._randomServer();
  var url = server + "/announcement/" + announcement.announcementId;
  disco.announcements.splice(disco.announcements.indexOf(announcement), 1);
  request({
    url: url,
    method: "DELETE"
  }, function (error, response, body) {
    if (error) {
      disco.logger.error(error);
    } else {
      disco.logger.log("Unannounce DELETE '" + url + "' returned " + response.statusCode + ": " + JSON.stringify(body));
    }
    if (callback) {
      callback();
    }
  });
};

module.exports = DiscoveryClient;
<|endoftext|>


<commit_before>/*
 * Implements the route panel
 */

var RouteManager = {
    _list: null,

    // Routes list
    _routesList: [],

    // Current active waypoint
    // {id, lat, lon}
    _currentWaypoint: null,
    _waypointIndex: 0,

    _distanceTilWaypoint: 0,
    _eta: 0,
    _totalDist: 0,

    init: function (content) {
        RouteManager._list = $('

');
        RouteManager._list
          .css('width', 'calc(50% - 4px)')
          .css('height', '286px')
          .css('float', 'left')
          .css('padding', '2px')
          .css('overflow-y', 'scroll');
    },

    _lookupId: function (id) {
      var target = id.toUpperCase();
      var key = LOCATION_DB.fixes[target];
      if (key !== undefined) {
        return key;
      }

      key = LOCATION_DB.airports[target];
      if (key !== undefined) {
        return key;
      }

      key = LOCATION_DB.navaids[target];
      if (key !== undefined) {
        return key;
      }

      return null;
    },

    _parseDirective: function (directive) {
      var status = {
        ok: false,
        msg: '',
        data: null
      };
      var findFirstDelim = function (data) {

      };

      // Parse waypoint ID

      return status;
    },

    load: function (lst) {
      var status = {
        ok: false,
        msg: ''
      };

      console.log(lst);
      for (var i = 0; i < lst.length; i++) {
        var ret = RouteManager._parseDirective(lst[i]);
        if (!ret.ok) {
          status.msg = ret.msg;
          return status;
        }

        // TODO: add to list
        RouteManager._add(ret.data);
      }

      return status;
    },

    _add: function (entry) {
      var item = $('

');
      item
        .css('margin-top', '1px')
        .css('margin-bottom', '1px')
        .css('padding', '2px')
        .css('background', '#333')
        .css('width', 'calc(100% - 5px)')
        .css('height', '40px');

    },

    _clear: function () {

    },

    getCurrentWaypoint: function () {

    },

    nextWaypoint: function () {

    },

    resetWaypoint: function () {

    }
};

var Route = {
  content: null,
  _dialog: null,
  _routeEntry: null,
  _submitRoute: null,
  _status: null,
  _info: null,
  _details: null,

  init: function (content) {
    Route.content = content;

    RouteManager.init(content);

    Route._setupMainDialog();
    Route._setupRouteDialog();

    Route.content
      .append(RouteManager._list)
      .append(Route._details)
      .append(Route._dialog);
  },

  // https://jsfiddle.net/7zthavz0/5/
  _setupMainDialog: function () {
    Route._details = $('

');
    Route._details
      .css('width', 'calc(50% - 4px)')
      .css('height', '286px')
      .css('float', 'left')
      .css('padding', '2px');

    Route._info = $('

');
    Route._info
      .css('width', '100%')
      .css('height', '90%');

    var controls = $('

');
    controls
      .css('width', '100%')
      .css('height', '10%')
      .css('text-align', 'center')
      .css('margin-left', '3px');

    var loadBtn = $('<button></button>');
    loadBtn
      .text('LOAD')
      .css('padding', '0px')
      .css('margin', '0px')
      .css('height', '100%')
      .css('width', '33%')
      .css('background', '#333')
      .css('border', '1px solid #0f0')
      .css('color', '#0f0')
      .click(function () {
        RouteManager._list
          .css('display', 'none');
        Route._details
          .css('display', 'none');
        Route._dialog.show();
      });
    var actBtn = $('<button></button>');
    actBtn
      .text('ACTV')
      .css('padding', '0px')
      .css('margin', '0px')
      .css('height', '100%')
      .css('width', '33%')
      .css('background', '#333')
      .css('border', '1px solid #0f0')
      .css('color', '#0f0')
      .click(function () {
        // TODO: activated PATH -> APS.mode = 'RTE'
        // TODO: setup current waypoint
        APS.rteBtn.click();
      });
    var deactBtn = $('<button></button>');
    deactBtn
      .text('DEACT')
      .css('padding', '0px')
      .css('margin', '0px')
      .css('height', '100%')
      .css('width', '33%')
      .css('background', '#333')
      .css('border', '1px solid #0f0')
      .css('color', '#0f0')
      .click(function () {
        // TODO:
        RouteManager._currentWaypoint = null;
      });

    controls
      .append(loadBtn)
      .append(actBtn)
      .append(deactBtn);
    Route._details
      .append(Route._info)
      .append(controls);
  },

  _setupRouteDialog: function () {
    Route._dialog = $('

');
    Route._dialog
      .css('display', 'none');

    var msg = $('

');
    msg
      .css('height', '20px')
      .text('Enter route information as specified by ')
      .append($('ROUTES.md'));

    Route._status = $('

');
    Route._status
      .css('height', '80px')
      .css('color', '#f00');

    Route._routeEntry = $('<textarea></textarea>');
    Route._routeEntry
      .css('width', 'calc(100% - 5px)')
      .css('height', '150px')
      .css('background', '#555')
      .css('color', '#0f9')
      .css('border', '1px solid #0f0')
      .css('margin', '0px')
      .css('font-family', 'Lucida Console, Monaco, monospace')
      .css('font-size', '8pt')
      .keyup(function(evt) {
            evt.stopImmediatePropagation();
      });

    Route._submitRoute = $('<button></button>');
    Route._submitRoute
      .text('SUBMIT')
      .css('border', '1px solid #0f0')
      .css('background', '#333')
      .css('color', '#0f0')
      .css('margin', '0px')
      .css('width', '50%')
      .css('text-align', 'center')
      .click(function () {
        var raw = Route._routeEntry.val();
        if (raw.length === 0) {
          Route._status
            .text('ERROR: Empty entry box!');
          return;
        }

        var rawList = raw.split(' ');
        if (rawList.length === 0) {
          Route._status
            .text('ERROR: Entry is not valid');
          return;
        }

        var points = [];
        for (var i = 0; i < rawList.length; i++) {
          if (rawList[i].length > 0) {
            points.push(rawList[i]);
          }
        }

        if (points.length === 0) {
          Route._status
            .text('ERROR: Invalid list format!');
          return;
        }

        var status = RouteManager.load(points);
        if (!status.ok) {
          Route._status
            .text('ERROR: ' + status.msg);
          return;
        }

        // On success, hide the dialog
        Route._routeEntry.text('');
        Route._status.text('');
        Route._dialog
          .fadeOut(function () {
            RouteManager._list
              .css('display', 'block');
            Route._details
              .css('display', 'block');
          });
      });

    var cancelBtn = $('<button></button>');
    cancelBtn
      .text('CANCEL')
      .css('border', '1px solid #0f0')
      .css('background', '#333')
      .css('color', '#0f0')
      .css('margin', '0px')
      .css('width', '50%')
      .css('text-align', 'center')
      .click(function () {
        Route._dialog
          .fadeOut(function () {
            RouteManager._list
              .css('display', 'block');
            Route._details
              .css('display', 'block');
          });
      });

    Route._dialog
      .append(msg)
      .append(Route._status)
      .append(Route._routeEntry)
      .append(cancelBtn)
      .append(Route._submitRoute);
  }
};
<commit_msg>Implementing more route navigation AP<commit_after>/*
 * Implements the route panel
 */

var RouteManager = {
    _list: null,

    // Routes list
    _routesList: [],

    // Current active waypoint
    // {id, lat, lon, altitude, ias}
    _currentWaypoint: null,
    _waypointIndex: 0,

    _distanceTilWaypoint: 0,
    _eta: 0,
    _totalDist: 0,

    init: function (content) {
        RouteManager._list = $('

');
        RouteManager._list
          .css('width', 'calc(50% - 4px)')
          .css('height', '286px')
          .css('float', 'left')
          .css('padding', '2px')
          .css('overflow-y', 'scroll');
    },

    _lookupId: function (id) {
      var target = id.toUpperCase();
      var key = LOCATION_DB.fixes[target];
      if (key !== undefined) {
        return key;
      }

      key = LOCATION_DB.airports[target];
      if (key !== undefined) {
        return key;
      }

      key = LOCATION_DB.navaids[target];
      if (key !== undefined) {
        return key;
      }

      return null;
    },

    _parseDirective: function (data) {
      var status = {
        ok: false,
        msg: '',
        data: null
      };

      var altDelim = data.indexOf('@');
      var iasDelim = data.indexOf(':');

      var obj = {
        id: null,
        altitude: null,
        ias: null,
        lat: null,
        lon: null
      };

      if (altDelim === -1 && iasDelim === -1) {
        obj.id = data;
      } else if (altDelim === -1) {
        obj.id = data.slice(0, iasDelim);
        obj.ias = parseInt(data.slice(iasDelim + 1));
      } else if (iasDelim === -1) {
        obj.id = data.slice(0, altDelim);
        obj.altitude = parseInt(data.slice(altDelim + 1));
      } else {
        if (altDelim > iasDelim) {
          obj.id = data.slice(0, iasDelim);
        } else {
          obj.id = data.slice(0, altDelim);
        }

        obj.altitude = parseInt(data.slice(altDelim + 1));
        obj.ias = parseInt(data.slice(iasDelim + 1));
      }

      var key = RouteManager._lookupId(obj.id);
      if (key === null) {
        status.msg = 'Invalid waypoint: ' + obj.id;
        return status;
      }

      if (isNaN(obj.altitude)) {
        status.msg = 'Invalid altitude for waypoint: ' + obj.id;
        return status;
      } else if (isNaN(obj.ias)) {
        status.msg = 'Invalid IAS for waypoint: ' + obj.id;
        return status;
      }

      obj.lat = key.lat;
      obj.lon = key.lon;

      status.ok = true;
      status.data = obj;

      return status;
    },

    load: function (lst) {
      var status = {
        ok: false,
        msg: ''
      };

      console.log(lst);
      for (var i = 0; i < lst.length; i++) {
        var ret = RouteManager._parseDirective(lst[i]);
        if (!ret.ok) {
          status.msg = ret.msg;
          return status;
        }

        RouteManager._add(ret.data);
      }

      return status;
    },

    _add: function (entry) {
      // TODO: entry is a
      // {
      //   id, lat, lon, altitude, ias
      // }
      var item = $('

');
      item
        .css('margin-top', '1px')
        .css('margin-bottom', '1px')
        .css('padding', '2px')
        .css('background', '#333')
        .css('width', 'calc(100% - 5px)')
        .css('height', '40px');

      console.log(entry);
    },

    _clear: function () {

    },

    getCurrentWaypoint: function () {

    },

    nextWaypoint: function () {

    },

    resetWaypoint: function () {

    }
};

var Route = {
  content: null,
  _dialog: null,
  _routeEntry: null,
  _submitRoute: null,
  _status: null,
  _info: null,
  _details: null,

  init: function (content) {
    Route.content = content;

    RouteManager.init(content);

    Route._setupMainDialog();
    Route._setupRouteDialog();

    Route.content
      .append(RouteManager._list)
      .append(Route._details)
      .append(Route._dialog);
  },

  // https://jsfiddle.net/7zthavz0/5/
  _setupMainDialog: function () {
    Route._details = $('

');
    Route._details
      .css('width', 'calc(50% - 4px)')
      .css('height', '286px')
      .css('float', 'left')
      .css('padding', '2px');

    Route._info = $('

');
    Route._info
      .css('width', '100%')
      .css('height', '90%');

    var controls = $('

');
    controls
      .css('width', '100%')
      .css('height', '10%')
      .css('text-align', 'center')
      .css('margin-left', '3px');

    var loadBtn = $('<button></button>');
    loadBtn
      .text('LOAD')
      .css('padding', '0px')
      .css('margin', '0px')
      .css('height', '100%')
      .css('width', '33%')
      .css('background', '#333')
      .css('border', '1px solid #0f0')
      .css('color', '#0f0')
      .click(function () {
        RouteManager._list
          .css('display', 'none');
        Route._details
          .css('display', 'none');
        Route._dialog.show();
      });
    var actBtn = $('<button></button>');
    actBtn
      .text('ACTV')
      .css('padding', '0px')
      .css('margin', '0px')
      .css('height', '100%')
      .css('width', '33%')
      .css('background', '#333')
      .css('border', '1px solid #0f0')
      .css('color', '#0f0')
      .click(function () {
        // TODO: activated PATH -> APS.mode = 'RTE'
        // TODO: setup current waypoint
        APS.rteBtn.click();
      });
    var deactBtn = $('<button></button>');
    deactBtn
      .text('DEACT')
      .css('padding', '0px')
      .css('margin', '0px')
      .css('height', '100%')
      .css('width', '33%')
      .css('background', '#333')
      .css('border', '1px solid #0f0')
      .css('color', '#0f0')
      .click(function () {
        // TODO:
        RouteManager._currentWaypoint = null;
      });

    controls
      .append(loadBtn)
      .append(actBtn)
      .append(deactBtn);
    Route._details
      .append(Route._info)
      .append(controls);
  },

  _setupRouteDialog: function () {
    Route._dialog = $('

');
    Route._dialog
      .css('display', 'none');

    var msg = $('

');
    msg
      .css('height', '20px')
      .text('Enter route information as specified by ')
      .append($('ROUTES.md'));

    Route._status = $('

');
    Route._status
      .css('height', '80px')
      .css('color', '#f00');

    Route._routeEntry = $('<textarea></textarea>');
    Route._routeEntry
      .css('width', 'calc(100% - 5px)')
      .css('height', '150px')
      .css('background', '#555')
      .css('color', '#0f9')
      .css('border', '1px solid #0f0')
      .css('margin', '0px')
      .css('font-family', 'Lucida Console, Monaco, monospace')
      .css('font-size', '8pt')
      .keyup(function(evt) {
            evt.stopImmediatePropagation();
      });

    Route._submitRoute = $('<button></button>');
    Route._submitRoute
      .text('SUBMIT')
      .css('border', '1px solid #0f0')
      .css('background', '#333')
      .css('color', '#0f0')
      .css('margin', '0px')
      .css('width', '50%')
      .css('text-align', 'center')
      .click(function () {
        var raw = Route._routeEntry.val();
        if (raw.length === 0) {
          Route._status
            .text('ERROR: Empty entry box!');
          return;
        }

        var rawList = raw.split(' ');
        if (rawList.length === 0) {
          Route._status
            .text('ERROR: Entry is not valid');
          return;
        }

        var points = [];
        for (var i = 0; i < rawList.length; i++) {
          if (rawList[i].length > 0) {
            points.push(rawList[i]);
          }
        }

        if (points.length === 0) {
          Route._status
            .text('ERROR: Invalid list format!');
          return;
        }

        var status = RouteManager.load(points);
        if (!status.ok) {
          Route._status
            .text('ERROR: ' + status.msg);
          return;
        }

        // On success, hide the dialog
        Route._routeEntry.text('');
        Route._status.text('');
        Route._dialog
          .fadeOut(function () {
            RouteManager._list
              .css('display', 'block');
            Route._details
              .css('display', 'block');
          });
      });

    var cancelBtn = $('<button></button>');
    cancelBtn
      .text('CANCEL')
      .css('border', '1px solid #0f0')
      .css('background', '#333')
      .css('color', '#0f0')
      .css('margin', '0px')
      .css('width', '50%')
      .css('text-align', 'center')
      .click(function () {
        Route._dialog
          .fadeOut(function () {
            RouteManager._list
              .css('display', 'block');
            Route._details
              .css('display', 'block');
          });
      });

    Route._dialog
      .append(msg)
      .append(Route._status)
      .append(Route._routeEntry)
      .append(cancelBtn)
      .append(Route._submitRoute);
  }
};
<|endoftext|>


<commit_before>
module.exports = {
	_loadedBannerAd: false,
	_loadedInterstitialAd: false,
	_isShowingBannerAd: false,
	_isShowingInterstitialAd: false,
	_fixCocoonIOCordovaAndroidAdMobIssue: false,
	//
	setLicenseKey: function(email, licenseKey) {
		var self = this;
        cordova.exec(
            null,
            null,
            'AdMobPlugin',
            'setLicenseKey',
            [email, licenseKey]
        );
    },
	setUp: function(bannerAdUnit, interstitialAdUnit, isOverlap, isTest) {
		var self = this;
        cordova.exec(
            function (result) {
				if (typeof result == "string") {
					if (result == "onBannerAdPreloaded") {
						if (self.onBannerAdPreloaded)
							self.onBannerAdPreloaded();
					}
					else if (result == "onBannerAdLoaded") {
						self._loadedBannerAd = true;

						if (self.onBannerAdLoaded)
							self.onBannerAdLoaded();

//fixCocoonIOCordovaAndroidAdMobIssue
if (typeof Cocoon != 'undefined' && navigator.userAgent.match(/Android/i) && !this._fixCocoonIOCordovaAndroidAdMobIssue) {
	//this.reloadBannerAd();
	function r() {
		this.reloadBannerAd();
	}
	setTimeout(r,1000);
	this._fixCocoonIOCordovaAndroidAdMobIssue=true;
}
					}
					else if (result == "onBannerAdShown") {
						self._loadedBannerAd = false;
						self._isShowingBannerAd = true;

						if (self.onBannerAdShown)
							self.onBannerAdShown();
					}
					else if (result == "onBannerAdHidden") {
						self._isShowingBannerAd = false;

						 if (self.onBannerAdHidden)
							self.onBannerAdHidden();
					}
					//
					else if (result == "onInterstitialAdPreloaded") {
//cranberrygame start; deprecated
						if (self.onFullScreenAdPreloaded)
							self.onFullScreenAdPreloaded();
//cranberrygame end
						if (self.onInterstitialAdPreloaded)
							self.onInterstitialAdPreloaded();
					}
					else if (result == "onInterstitialAdLoaded") {
						self._loadedInterstitialAd = true;

//cranberrygame start; deprecated
						if (self.onFullScreenAdLoaded)
							self.onFullScreenAdLoaded();
//cranberrygame end
						if (self.onInterstitialAdLoaded)
							self.onInterstitialAdLoaded();
					}
					else if (result == "onInterstitialAdShown") {
						self._loadedInterstitialAd = false;
						self._isShowingInterstitialAd = true;

//cranberrygame start; deprecated
						if (self.onFullScreenAdShown)
							self.onFullScreenAdShown();
//cranberrygame end
						if (self.onInterstitialAdShown)
							self.onInterstitialAdShown();
					}
					else if (result == "onInterstitialAdHidden") {
						self._isShowingInterstitialAd = false;

//cranberrygame start; deprecated
						if (self.onFullScreenAdHidden)
							self.onFullScreenAdHidden();
						if (self.onFullScreenAdClosed)
							self.onFullScreenAdClosed(); //deprecated
//cranberrygame end
						 if (self.onInterstitialAdHidden)
							self.onInterstitialAdHidden();
					}
				}
				else {
					//var event = result["event"];
					//var location = result["message"];
					//if (event == "onXXX") {
					//	if (self.onXXX)
					//		self.onXXX(location);
					//}
				}
			},
			function (error) {
			},
            'AdMobPlugin',
            'setUp',
            [bannerAdUnit, interstitialAdUnit, isOverlap, isTest]
        );
    },
	preloadBannerAd: function() {
		var self = this;
        cordova.exec(
            null,
            null,
            'AdMobPlugin',
            'preloadBannerAd',
            []
        );
    },
    showBannerAd: function(position, size) {
		var self = this;
        cordova.exec(
            null,
            null,
            'AdMobPlugin',
            'showBannerAd',
            [position, size]
        );
    },
	reloadBannerAd: function() {
		var self = this;
        cordova.exec(
            null,
            null,
            'AdMobPlugin',
            'reloadBannerAd',
            []
        );
    },
    hideBannerAd: function() {
		var self = this;
        cordova.exec(
            null,
            null,
            'AdMobPlugin',
            'hideBannerAd',
            []
        );
    },
	//
//cranberrygame start; deprecated
	preloadFullScreenAd: function() {
		var self = this;
        cordova.exec(
            null,
            null,
            'AdMobPlugin',
            'preloadInterstitialAd',
            []
        );
    },
    showFullScreenAd: function() {
		var self = this;
		cordova.exec(
            null,
            null,
            'AdMobPlugin',
            'showInterstitialAd',
            []
        );
    },
	reloadFullScreenAd: function() { //deprecated
    },
//cranberrygame end
	preloadInterstitialAd: function() {
        cordova.exec(
			null,
            null,
            'AdMobPlugin',
            'preloadInterstitialAd',
            []
        );
    },
    showInterstitialAd: function() {
		cordova.exec(
 			null,
            null,
            'AdMobPlugin',
            'showInterstitialAd',
            []
        );
    },
	loadedBannerAd: function() {
		return this._loadedBannerAd;
	},
//cranberrygame start; deprecated
	loadedFullScreenAd: function() {
		return this._loadedInterstitialAd;
	},
//cranberrygame end
	loadedInterstitialAd: function() {
		return this._loadedInterstitialAd;
	},
	isShowingBannerAd: function() {
		return this._isShowingBannerAd;
	},
//cranberrygame start; deprecated
	isShowingFullScreenAd: function() {
		return this._isShowingInterstitialAd;
	},
//cranberrygame end
	isShowingInterstitialAd: function() {
		return this._isShowingInterstitialAd;
	},
	onBannerAdPreloaded: null,
	onBannerAdLoaded: null,
	onBannerAdShown: null,
	onBannerAdHidden: null,
	//
//cranberrygame start; deprecated
	onFullScreenAdPreloaded: null,
	onFullScreenAdLoaded: null,
	onFullScreenAdShown: null,
	onFullScreenAdHidden: null,
	onFullScreenAdClosed: null, //deprecated
//cranberrygame end
	onInterstitialAdPreloaded: null,
	onInterstitialAdLoaded: null,
	onInterstitialAdShown: null,
	onInterstitialAdHidden: null
};
<commit_msg>Update admob.js<commit_after>
module.exports = {
	_loadedBannerAd: false,
	_loadedInterstitialAd: false,
	_isShowingBannerAd: false,
	_isShowingInterstitialAd: false,
	_fixCocoonIOCordovaAndroidAdMobIssue: false,
	//
	setLicenseKey: function(email, licenseKey) {
		var self = this;
        cordova.exec(
            null,
            null,
            'AdMobPlugin',
            'setLicenseKey',
            [email, licenseKey]
        );
    },
	setUp: function(bannerAdUnit, interstitialAdUnit, isOverlap, isTest) {
		var self = this;
        cordova.exec(
            function (result) {
				if (typeof result == "string") {
					if (result == "onBannerAdPreloaded") {
						if (self.onBannerAdPreloaded)
							self.onBannerAdPreloaded();
					}
					else if (result == "onBannerAdLoaded") {
						self._loadedBannerAd = true;

						if (self.onBannerAdLoaded)
							self.onBannerAdLoaded();

//fixCocoonIOCordovaAndroidAdMobIssue
if (typeof Cocoon != 'undefined' && navigator.userAgent.match(/Android/i) && !this._fixCocoonIOCordovaAndroidAdMobIssue) {
	//this.reloadBannerAd();
	function r() {
		this.reloadBannerAd();
	}
	setTimeout(r,500);
	this._fixCocoonIOCordovaAndroidAdMobIssue=true;
}
					}
					else if (result == "onBannerAdShown") {
						self._loadedBannerAd = false;
						self._isShowingBannerAd = true;

						if (self.onBannerAdShown)
							self.onBannerAdShown();
					}
					else if (result == "onBannerAdHidden") {
						self._isShowingBannerAd = false;

						 if (self.onBannerAdHidden)
							self.onBannerAdHidden();
					}
					//
					else if (result == "onInterstitialAdPreloaded") {
//cranberrygame start; deprecated
						if (self.onFullScreenAdPreloaded)
							self.onFullScreenAdPreloaded();
//cranberrygame end
						if (self.onInterstitialAdPreloaded)
							self.onInterstitialAdPreloaded();
					}
					else if (result == "onInterstitialAdLoaded") {
						self._loadedInterstitialAd = true;

//cranberrygame start; deprecated
						if (self.onFullScreenAdLoaded)
							self.onFullScreenAdLoaded();
//cranberrygame end
						if (self.onInterstitialAdLoaded)
							self.onInterstitialAdLoaded();
					}
					else if (result == "onInterstitialAdShown") {
						self._loadedInterstitialAd = false;
						self._isShowingInterstitialAd = true;

//cranberrygame start; deprecated
						if (self.onFullScreenAdShown)
							self.onFullScreenAdShown();
//cranberrygame end
						if (self.onInterstitialAdShown)
							self.onInterstitialAdShown();
					}
					else if (result == "onInterstitialAdHidden") {
						self._isShowingInterstitialAd = false;

//cranberrygame start; deprecated
						if (self.onFullScreenAdHidden)
							self.onFullScreenAdHidden();
						if (self.onFullScreenAdClosed)
							self.onFullScreenAdClosed(); //deprecated
//cranberrygame end
						 if (self.onInterstitialAdHidden)
							self.onInterstitialAdHidden();
					}
				}
				else {
					//var event = result["event"];
					//var location = result["message"];
					//if (event == "onXXX") {
					//	if (self.onXXX)
					//		self.onXXX(location);
					//}
				}
			},
			function (error) {
			},
            'AdMobPlugin',
            'setUp',
            [bannerAdUnit, interstitialAdUnit, isOverlap, isTest]
        );
    },
	preloadBannerAd: function() {
		var self = this;
        cordova.exec(
            null,
            null,
            'AdMobPlugin',
            'preloadBannerAd',
            []
        );
    },
    showBannerAd: function(position, size) {
		var self = this;
        cordova.exec(
            null,
            null,
            'AdMobPlugin',
            'showBannerAd',
            [position, size]
        );
    },
	reloadBannerAd: function() {
		var self = this;
        cordova.exec(
            null,
            null,
            'AdMobPlugin',
            'reloadBannerAd',
            []
        );
    },
    hideBannerAd: function() {
		var self = this;
        cordova.exec(
            null,
            null,
            'AdMobPlugin',
            'hideBannerAd',
            []
        );
    },
	//
//cranberrygame start; deprecated
	preloadFullScreenAd: function() {
		var self = this;
        cordova.exec(
            null,
            null,
            'AdMobPlugin',
            'preloadInterstitialAd',
            []
        );
    },
    showFullScreenAd: function() {
		var self = this;
		cordova.exec(
            null,
            null,
            'AdMobPlugin',
            'showInterstitialAd',
            []
        );
    },
	reloadFullScreenAd: function() { //deprecated
    },
//cranberrygame end
	preloadInterstitialAd: function() {
        cordova.exec(
			null,
            null,
            'AdMobPlugin',
            'preloadInterstitialAd',
            []
        );
    },
    showInterstitialAd: function() {
		cordova.exec(
 			null,
            null,
            'AdMobPlugin',
            'showInterstitialAd',
            []
        );
    },
	loadedBannerAd: function() {
		return this._loadedBannerAd;
	},
//cranberrygame start; deprecated
	loadedFullScreenAd: function() {
		return this._loadedInterstitialAd;
	},
//cranberrygame end
	loadedInterstitialAd: function() {
		return this._loadedInterstitialAd;
	},
	isShowingBannerAd: function() {
		return this._isShowingBannerAd;
	},
//cranberrygame start; deprecated
	isShowingFullScreenAd: function() {
		return this._isShowingInterstitialAd;
	},
//cranberrygame end
	isShowingInterstitialAd: function() {
		return this._isShowingInterstitialAd;
	},
	onBannerAdPreloaded: null,
	onBannerAdLoaded: null,
	onBannerAdShown: null,
	onBannerAdHidden: null,
	//
//cranberrygame start; deprecated
	onFullScreenAdPreloaded: null,
	onFullScreenAdLoaded: null,
	onFullScreenAdShown: null,
	onFullScreenAdHidden: null,
	onFullScreenAdClosed: null, //deprecated
//cranberrygame end
	onInterstitialAdPreloaded: null,
	onInterstitialAdLoaded: null,
	onInterstitialAdShown: null,
	onInterstitialAdHidden: null
};
<|endoftext|>


<commit_before>import knex from '../knex';
import Poll from './Poll';
import Proposal from './Proposal';
import Statement from './Statement';
import { canSee, canMutate, Models } from '../../core/accessControl';
import EventManager from '../../core/EventManager';

class Vote {
  constructor(data) {
    this.id = data.id;
    this.userId = data.user_id;
    this.position = data.position;
    this.pollId = data.poll_id;
  }
  static async gen(viewer, id, loaders) {
    if (!id) return null;
    const data = await loaders.votes.load(id);
    if (data === null) return null;
    const proposal = await Proposal.genByPoll(viewer, data.poll_id, loaders);
    data.proposal = proposal;
    if (!canSee(viewer, data, Models.VOTE)) return null;
    return new Vote(data);
  }

  static async validate(viewer, data, loaders, poll, trx, mutation = false) {
    if (!poll || !poll.isVotable()) return null;

    const proposal = await Proposal.genByPoll(viewer, poll.id, loaders);
    if (!proposal || !await proposal.isVotable(viewer)) return null;

    const voteInDB = await knex('votes')
      .transacting(trx)
      .forUpdate()
      .where({ poll_id: data.pollId, user_id: viewer.id })
      .select();

    if (mutation && voteInDB.length === 0) return null;
    if (voteInDB.length !== 0) return mutation ? { ...voteInDB[0] } : null;
    return true;
  }

  static async delete(viewer, data, loaders) {
    if (!data.id) return null;
    if (!data.pollId) return null;
    const proposal = await Proposal.genByPoll(viewer, data.pollId, loaders);
    if (!canMutate(viewer, { ...data, proposal }, Models.VOTE)) return null;
    const poll = await Poll.gen(viewer, data.pollId, loaders); // auth should happen here ...
    let deletedStatement;
    let deletedVote;
    try {
      deletedVote = await knex.transaction(async trx => {
        const oldVote = await Vote.validate(
          viewer,
          data,
          loaders,
          poll,
          trx,
          true,
        );
        if (!oldVote || !oldVote.position) throw Error('Request invalid!');
        // eslint-disable-next-line eqeqeq
        if (data.id != oldVote.id) throw Error('Request invalid!');
        const newPosition = data.position === 1 ? 'pro' : 'con'; // dangerous?
        if (newPosition !== oldVote.position) throw Error('Request invalid!');
        // eslint-disable-next-line newline-per-chained-call
        // check if statements exists, check if it can be deleted (cascading)

        let statementInDB = await knex('statements')
          .transacting(trx)
          .forUpdate()
          .where({ vote_id: data.id })
          .select();
        statementInDB = statementInDB[0] || {};
        if (statementInDB.id) {
          if (statementInDB.deleted_at) {
            throw Error('Cannot be modified!');
          }
          deletedStatement = new Statement(statementInDB);
          // statement gets deleted by cascading on delete
        }
        // eslint-disable-next-line newline-per-chained-call

        await knex('votes')
          .transacting(trx)
          .forUpdate()
          .where({ id: data.id })
          .del();
        // update votecount
        const columns = ['upvotes', 'downvotes'];
        const index = newPosition === 'con' ? 1 : 0;
        await knex('polls')
          .transacting(trx)
          .forUpdate()
          .where({ id: data.pollId })
          .decrement(columns[index], 1);
        return oldVote;
      });
    } catch (e) {
      return { deletedVote: null, deletedStatement: null };
    }
    const delVote = new Vote(deletedVote);
    if (deletedVote) {
      EventManager.publish('onVoteDeleted', {
        viewer,
        vote: delVote,
        ...(proposal.workTeamId && {
          groupId: proposal.workTeamId,
          info: { workTeamId: proposal.workTeamId },
        }),
      });
    }
    if (deletedStatement) {
      EventManager.publish('onStatementDeleted', {
        viewer,
        statement: deletedStatement,
        ...(proposal.workTeamId && {
          groupId: proposal.workTeamId,
          info: { workTeamId: proposal.workTeamId },
        }),
      });
    }
    return { deletedVote: delVote || null, deletedStatement };
  }

  static async update(viewer, data, loaders) {
    // throw Error('TESTERROR');

    if (!data.id) return null;
    if (!data.pollId) return null;
    const proposal = await Proposal.genByPoll(viewer, data.pollId, loaders);
    if (!canMutate(viewer, { ...data, proposal }, Models.VOTE)) return null;
    const poll = await Poll.gen(viewer, data.pollId, loaders); // auth should happen here ...
    if (await poll.isUnipolar(viewer, loaders)) {
      return null; // delete is the right method
    }

    let deletedStatement;
    try {
      await knex.transaction(async trx => {
        const oldVote = await Vote.validate(
          viewer,
          data,
          loaders,
          poll,
          trx,
          true,
        );
        if (!oldVote || !oldVote.position) throw Error('Position mismatch');
        // eslint-disable-next-line eqeqeq
        if (data.id != oldVote.id) throw Error('Id mismatch');

        let statementInDB = await knex('statements')
          .transacting(trx)
          .forUpdate()
          .where({ vote_id: data.id })
          .select();
        statementInDB = statementInDB[0] || {};
        if (statementInDB.id) {
          if (statementInDB.deleted_at) {
            throw Error('Cannot be modified!');
          }
          deletedStatement = new Statement(statementInDB);

          // eslint-disable-next-line newline-per-chained-call
          await knex('statements')
            .transacting(trx)
            .forUpdate()
            .where({ vote_id: data.id })
            .del();
        }

        const newPosition = data.position === 1 ? 'pro' : 'con'; // dangerous?
        if (newPosition === oldVote.position) throw Error('Request invalid');
        // eslint-disable-next-line newline-per-chained-call
        await knex('votes')
          .transacting(trx)
          .forUpdate()
          .where({ id: data.id })
          .update({
            position: newPosition,
            updated_at: new Date(),
          });
        // update votecount
        const columns = ['upvotes', 'downvotes'];
        let index = newPosition === 'con' ? 1 : 0;

        await knex('polls')
          .transacting(trx)
          .forUpdate()
          .where({ id: data.pollId })
          .increment(columns[index], 1);
        await knex('polls')
          .transacting(trx)
          .forUpdate()
          .where({ id: data.pollId })
          .decrement(columns[(index = 1 - index)], 1);
      });
    } catch (e) {
      return { updatedVote: null, deletedStatement: null };
    }
    const vote = await Vote.gen(viewer, data.id, loaders);
    if (vote) {
      EventManager.publish('onVoteUpdated', {
        viewer,
        vote,
        ...(proposal.workTeamId && {
          groupId: proposal.workTeamId,
          info: { workTeamId: proposal.workTeamId },
        }),
      });
    }
    if (deletedStatement) {
      EventManager.publish('onStatementDeleted', {
        viewer,
        subjectId: proposal.id,
        statemente: deletedStatement,
        ...(proposal.workTeamId && {
          groupId: proposal.workTeamId,
          info: { workTeamId: proposal.workTeamId },
        }),
      });
    }
    return {
      updatedVote: vote,
      deletedStatement,
    };
  }

  static async create(viewer, data, loaders) {
    // authenticate later?
    // throw Error('TESTERROR');
    // validate
    if (!data.pollId) return null;
    const proposal = await Proposal.genByPoll(viewer, data.pollId, loaders);

    if (!canMutate(viewer, { ...data, proposal }, Models.VOTE)) return null;

    const poll = await Poll.gen(viewer, data.pollId, loaders); // auth should happen here ...

    if (!poll || !poll.isVotable()) return null;

    if (!proposal || !await proposal.isVotable(viewer)) return null;

    let position = data.position === 1 ? 'pro' : 'con';

    if (await poll.isUnipolar(viewer, loaders)) {
      position = 'pro';
    }
    let newVoteId;
    try {
      newVoteId = await knex.transaction(async trx => {
        const voteInDB = await knex('votes') // TODO prob. superflue bc constraint
          .transacting(trx)
          .forUpdate()
          .where({ poll_id: data.pollId, user_id: viewer.id })
          .pluck('id');
        if (voteInDB.length !== 0) throw Error('Already voted!');
        const id = await knex('votes')
          .transacting(trx)
          .forUpdate()
          .insert(
            {
              user_id: viewer.id,
              poll_id: data.pollId,
              position,
              created_at: new Date(),
            },
            'id',
          );
        if (id.length === 0) throw Error('No Id returned');
        // update votecount;
        // TODO these updates are sequential - can db-ops be parallel in transactions?
        const columns = ['upvotes', 'downvotes'];
        const index = position === 'con' ? 1 : 0;
        await knex('polls')
          .transacting(trx)
          .forUpdate()
          .where({ id: data.pollId })
          .increment(columns[index], 1);
        return id[0];
      });
    } catch (e) {
      return null;
    }
    if (!newVoteId) return null;
    const newVote = await Vote.gen(viewer, newVoteId, loaders);
    if (newVote) {
      EventManager.publish('onVoteCreated', {
        viewer,
        vote: newVote,
        ...(proposal.workTeamId && {
          groupId: proposal.workTeamId,
          info: { workTeamId: proposal.workTeamId },
        }),
      });
    }
    return newVote;
  }
}

export default Vote;
<commit_msg>fixed typo (statemente) in Vote.js<commit_after>import knex from '../knex';
import Poll from './Poll';
import Proposal from './Proposal';
import Statement from './Statement';
import { canSee, canMutate, Models } from '../../core/accessControl';
import EventManager from '../../core/EventManager';

class Vote {
  constructor(data) {
    this.id = data.id;
    this.userId = data.user_id;
    this.position = data.position;
    this.pollId = data.poll_id;
  }
  static async gen(viewer, id, loaders) {
    if (!id) return null;
    const data = await loaders.votes.load(id);
    if (data === null) return null;
    const proposal = await Proposal.genByPoll(viewer, data.poll_id, loaders);
    data.proposal = proposal;
    if (!canSee(viewer, data, Models.VOTE)) return null;
    return new Vote(data);
  }

  static async validate(viewer, data, loaders, poll, trx, mutation = false) {
    if (!poll || !poll.isVotable()) return null;

    const proposal = await Proposal.genByPoll(viewer, poll.id, loaders);
    if (!proposal || !await proposal.isVotable(viewer)) return null;

    const voteInDB = await knex('votes')
      .transacting(trx)
      .forUpdate()
      .where({ poll_id: data.pollId, user_id: viewer.id })
      .select();

    if (mutation && voteInDB.length === 0) return null;
    if (voteInDB.length !== 0) return mutation ? { ...voteInDB[0] } : null;
    return true;
  }

  static async delete(viewer, data, loaders) {
    if (!data.id) return null;
    if (!data.pollId) return null;
    const proposal = await Proposal.genByPoll(viewer, data.pollId, loaders);
    if (!canMutate(viewer, { ...data, proposal }, Models.VOTE)) return null;
    const poll = await Poll.gen(viewer, data.pollId, loaders); // auth should happen here ...
    let deletedStatement;
    let deletedVote;
    try {
      deletedVote = await knex.transaction(async trx => {
        const oldVote = await Vote.validate(
          viewer,
          data,
          loaders,
          poll,
          trx,
          true,
        );
        if (!oldVote || !oldVote.position) throw Error('Request invalid!');
        // eslint-disable-next-line eqeqeq
        if (data.id != oldVote.id) throw Error('Request invalid!');
        const newPosition = data.position === 1 ? 'pro' : 'con'; // dangerous?
        if (newPosition !== oldVote.position) throw Error('Request invalid!');
        // eslint-disable-next-line newline-per-chained-call
        // check if statements exists, check if it can be deleted (cascading)

        let statementInDB = await knex('statements')
          .transacting(trx)
          .forUpdate()
          .where({ vote_id: data.id })
          .select();
        statementInDB = statementInDB[0] || {};
        if (statementInDB.id) {
          if (statementInDB.deleted_at) {
            throw Error('Cannot be modified!');
          }
          deletedStatement = new Statement(statementInDB);
          // statement gets deleted by cascading on delete
        }
        // eslint-disable-next-line newline-per-chained-call

        await knex('votes')
          .transacting(trx)
          .forUpdate()
          .where({ id: data.id })
          .del();
        // update votecount
        const columns = ['upvotes', 'downvotes'];
        const index = newPosition === 'con' ? 1 : 0;
        await knex('polls')
          .transacting(trx)
          .forUpdate()
          .where({ id: data.pollId })
          .decrement(columns[index], 1);
        return oldVote;
      });
    } catch (e) {
      return { deletedVote: null, deletedStatement: null };
    }
    const delVote = new Vote(deletedVote);
    if (deletedVote) {
      EventManager.publish('onVoteDeleted', {
        viewer,
        vote: delVote,
        ...(proposal.workTeamId && {
          groupId: proposal.workTeamId,
          info: { workTeamId: proposal.workTeamId },
        }),
      });
    }
    if (deletedStatement) {
      EventManager.publish('onStatementDeleted', {
        viewer,
        statement: deletedStatement,
        ...(proposal.workTeamId && {
          groupId: proposal.workTeamId,
          info: { workTeamId: proposal.workTeamId },
        }),
      });
    }
    return { deletedVote: delVote || null, deletedStatement };
  }

  static async update(viewer, data, loaders) {
    // throw Error('TESTERROR');

    if (!data.id) return null;
    if (!data.pollId) return null;
    const proposal = await Proposal.genByPoll(viewer, data.pollId, loaders);
    if (!canMutate(viewer, { ...data, proposal }, Models.VOTE)) return null;
    const poll = await Poll.gen(viewer, data.pollId, loaders); // auth should happen here ...
    if (await poll.isUnipolar(viewer, loaders)) {
      return null; // delete is the right method
    }

    let deletedStatement;
    try {
      await knex.transaction(async trx => {
        const oldVote = await Vote.validate(
          viewer,
          data,
          loaders,
          poll,
          trx,
          true,
        );
        if (!oldVote || !oldVote.position) throw Error('Position mismatch');
        // eslint-disable-next-line eqeqeq
        if (data.id != oldVote.id) throw Error('Id mismatch');

        let statementInDB = await knex('statements')
          .transacting(trx)
          .forUpdate()
          .where({ vote_id: data.id })
          .select();
        statementInDB = statementInDB[0] || {};
        if (statementInDB.id) {
          if (statementInDB.deleted_at) {
            throw Error('Cannot be modified!');
          }
          deletedStatement = new Statement(statementInDB);

          // eslint-disable-next-line newline-per-chained-call
          await knex('statements')
            .transacting(trx)
            .forUpdate()
            .where({ vote_id: data.id })
            .del();
        }

        const newPosition = data.position === 1 ? 'pro' : 'con'; // dangerous?
        if (newPosition === oldVote.position) throw Error('Request invalid');
        // eslint-disable-next-line newline-per-chained-call
        await knex('votes')
          .transacting(trx)
          .forUpdate()
          .where({ id: data.id })
          .update({
            position: newPosition,
            updated_at: new Date(),
          });
        // update votecount
        const columns = ['upvotes', 'downvotes'];
        let index = newPosition === 'con' ? 1 : 0;

        await knex('polls')
          .transacting(trx)
          .forUpdate()
          .where({ id: data.pollId })
          .increment(columns[index], 1);
        await knex('polls')
          .transacting(trx)
          .forUpdate()
          .where({ id: data.pollId })
          .decrement(columns[(index = 1 - index)], 1);
      });
    } catch (e) {
      return { updatedVote: null, deletedStatement: null };
    }
    const vote = await Vote.gen(viewer, data.id, loaders);
    if (vote) {
      EventManager.publish('onVoteUpdated', {
        viewer,
        vote,
        ...(proposal.workTeamId && {
          groupId: proposal.workTeamId,
          info: { workTeamId: proposal.workTeamId },
        }),
      });
    }
    if (deletedStatement) {
      EventManager.publish('onStatementDeleted', {
        viewer,
        subjectId: proposal.id,
        statement: deletedStatement,
        ...(proposal.workTeamId && {
          groupId: proposal.workTeamId,
          info: { workTeamId: proposal.workTeamId },
        }),
      });
    }
    return {
      updatedVote: vote,
      deletedStatement,
    };
  }

  static async create(viewer, data, loaders) {
    // authenticate later?
    // throw Error('TESTERROR');
    // validate
    if (!data.pollId) return null;
    const proposal = await Proposal.genByPoll(viewer, data.pollId, loaders);

    if (!canMutate(viewer, { ...data, proposal }, Models.VOTE)) return null;

    const poll = await Poll.gen(viewer, data.pollId, loaders); // auth should happen here ...

    if (!poll || !poll.isVotable()) return null;

    if (!proposal || !await proposal.isVotable(viewer)) return null;

    let position = data.position === 1 ? 'pro' : 'con';

    if (await poll.isUnipolar(viewer, loaders)) {
      position = 'pro';
    }
    let newVoteId;
    try {
      newVoteId = await knex.transaction(async trx => {
        const voteInDB = await knex('votes') // TODO prob. superflue bc constraint
          .transacting(trx)
          .forUpdate()
          .where({ poll_id: data.pollId, user_id: viewer.id })
          .pluck('id');
        if (voteInDB.length !== 0) throw Error('Already voted!');
        const id = await knex('votes')
          .transacting(trx)
          .forUpdate()
          .insert(
            {
              user_id: viewer.id,
              poll_id: data.pollId,
              position,
              created_at: new Date(),
            },
            'id',
          );
        if (id.length === 0) throw Error('No Id returned');
        // update votecount;
        // TODO these updates are sequential - can db-ops be parallel in transactions?
        const columns = ['upvotes', 'downvotes'];
        const index = position === 'con' ? 1 : 0;
        await knex('polls')
          .transacting(trx)
          .forUpdate()
          .where({ id: data.pollId })
          .increment(columns[index], 1);
        return id[0];
      });
    } catch (e) {
      return null;
    }
    if (!newVoteId) return null;
    const newVote = await Vote.gen(viewer, newVoteId, loaders);
    if (newVote) {
      EventManager.publish('onVoteCreated', {
        viewer,
        vote: newVote,
        ...(proposal.workTeamId && {
          groupId: proposal.workTeamId,
          info: { workTeamId: proposal.workTeamId },
        }),
      });
    }
    return newVote;
  }
}

export default Vote;
<|endoftext|>