<commit_before>// add commas
function addCommas(i){
	numWithCommas = i.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
	return numWithCommas;
};

var chartOptions = {
  chart: {
    renderTo: 'prediction',
    type: 'bar',
    height:200,
    backgroundColor:null
  },
  title: {
    text: ' ',
    style: {
      color: "#FFFFFF"
    }
  },
  subtitle: {
    text: ''
  },
  credits: {
    enabled: false
  },
  xAxis: {
    labels: {
      style: {
        color: "#FFFFFF"
      }
    }
  },
  yAxis: {
    min: 0,
    title: {
      text: 'Available Points'
    }
  },
  labels: {
    formatter: function(){
      return this.value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
    },
    plotLines: [{
      value: 0,
      width: 1,
      color: '#808080'
    }]
  },
  tooltip: {
    formatter: function() {
      return ''+ this.series.name +'
'+
        this.y +' points';
    }
  },
  plotOptions: {
    series: {
      stacking: 'normal',
      events: {
        legendItemClick: function(event){
          return false;
        }
      }
    }
  },
  legend: {
    backgroundColor: null,
    borderColor:null,
    reversed: true,
    itemStyle: {
      color: '#CCCCCC'
    }
  },
  series: []
};

var AssignmentType = Backbone.Model.extend();

var AssignmentTypesArray = Backbone.Collection.extend({
  model: AssignmentType
});

var PredictorView = Backbone.View.extend({
  el: '#predictorPage',
  initialize: function() {
    this.collection = new AssignmentTypesArray();
    this.createAssignmentTypes();
    this.calculateScores();
    this.setupChart();
    this.collection.bind('change',this.render,this);
    this.$el = $(this.el);
    this.render();
  },
  render: function() {
    var chart = this.model;
    chart.yAxis[0].setExtremes(0,this.calculateCourseTotal());
    var scoreTotal = 0;
    this.collection.forEach(function(assignmentType,i) {
      chart.series[i].setData([assignmentType.get('score')])
      scoreTotal += assignmentType.get('score');
    });
    $('#predictor-score-display').html(addCommas(scoreTotal));
    $('#predictor-course-total-display').html(addCommas(this.calculateCourseTotal()));
    $('#predictedCourseGrade').html();
  },
  createAssignmentTypes: function() {
    var assignmentTypes = this.collection;
    $.each(this.$el.find('.slides li').not('.clone'),function(i,slide) {
      $slide = $(slide);
      if ($slide.attr('id') == 'slide-required') {
        return true; // Required slide just duplicates assignments from other slides, so we can ignore it
      }
      var assignmentTypeName = $slide.data('assignment-type-name');
      var assignmentTypeId = $slide.data('assignment-type-id');
      assignmentTypes.add(new AssignmentType({ id: assignmentTypeId, name: assignmentTypeName, score: 0 }));
    });
  },
  setupChart: function() {
    this.collection.forEach(function(assignmentType,i) {
      chartOptions.series.push({ name: assignmentType.get('name'), data: [assignmentType.get('score')] });
    });
    chartOptions.xAxis.categories = ' ';
    chartOptions.yAxis.max = this.calculateCourseTotal();
    this.model = new Highcharts.Chart(chartOptions);
  },
  events: {
    'change input': 'calculateScores',
    'change select': 'calculateScores',
    'slidestop .slider': 'calculateScores'
  },
  calculateCourseTotal: function() {
    var courseTotal = 0;
    var $slide = this.$el.find('li#slide-badges')
    $.each($slide.find('input'), function(i,item) {
      var $item = $(item);
      if ($item.is(':checked')) {
        courseTotal += parseInt($item.val());
      }
    });
    courseTotal += parseInt(this.$el.data('course-total'));
    return courseTotal;
  },
  calculateScores: function(e) {
    var assignmentTypes = this.collection;
    $.each(this.$el.find('.slides li').not('.clone'),function(i,slide) {
      var $slide = $(slide);
      if ($slide.attr('id') == 'slide-required') {
        return true;
      }
      var assignmentTypeId = $slide.data('assignment-type-id');
      var score = 0;
      $.each($slide.find('input, select, .slider'), function(i,item) {
        var $item = $(item),
            itemScore = getScore($item);
        score += itemScore;
      });
      assignmentTypes.get(assignmentTypeId).set('score',score);
    });
    if (e) {
      var $item = $(e.target),
          $assignment = $item.closest('.assignment'),
          assignmentId = $assignment.data('assignment'),
          score = getScore($item),
          possibleScore = $assignment.data('possible-points');
      $.ajax('/analytics_events/predictor_event', {
        method: 'post',
        data: {
          assignment: assignmentId,
          score: score,
          possible: possibleScore
        }
      });
    }
  }
});

var getScore = function($item) {
  if($item.is(':checkbox') && $item.is(':checked')) {
    return parseInt($item.val());
  } else if ($item.is('select')) {
    return parseInt($item.children('option:selected').val() || 0);
  } else if ($item.is('input[type="hidden"]')) {
    return parseInt($item.val());
  } else if ($item.is('.ui-slider')) {
    return parseInt($item.slider('value'));
  }
}

$(document).ready(function() {
  var $wrapper = $('#prediction');
  if ($wrapper.length) {
    new PredictorView();
  }
});
<commit_msg>Fix predictor NaN error<commit_after>// add commas
function addCommas(i){
	numWithCommas = i.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
	return numWithCommas;
};

var chartOptions = {
  chart: {
    renderTo: 'prediction',
    type: 'bar',
    height:200,
    backgroundColor:null
  },
  title: {
    text: ' ',
    style: {
      color: "#FFFFFF"
    }
  },
  subtitle: {
    text: ''
  },
  credits: {
    enabled: false
  },
  xAxis: {
    labels: {
      style: {
        color: "#FFFFFF"
      }
    }
  },
  yAxis: {
    min: 0,
    title: {
      text: 'Available Points'
    }
  },
  labels: {
    formatter: function(){
      return this.value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
    },
    plotLines: [{
      value: 0,
      width: 1,
      color: '#808080'
    }]
  },
  tooltip: {
    formatter: function() {
      return ''+ this.series.name +'
'+
        this.y +' points';
    }
  },
  plotOptions: {
    series: {
      stacking: 'normal',
      events: {
        legendItemClick: function(event){
          return false;
        }
      }
    }
  },
  legend: {
    backgroundColor: null,
    borderColor:null,
    reversed: true,
    itemStyle: {
      color: '#CCCCCC'
    }
  },
  series: []
};

var AssignmentType = Backbone.Model.extend();

var AssignmentTypesArray = Backbone.Collection.extend({
  model: AssignmentType
});

var PredictorView = Backbone.View.extend({
  el: '#predictorPage',
  initialize: function() {
    this.collection = new AssignmentTypesArray();
    this.createAssignmentTypes();
    this.calculateScores();
    this.setupChart();
    this.collection.bind('change',this.render,this);
    this.$el = $(this.el);
    this.render();
  },
  render: function() {
    var chart = this.model;
    chart.yAxis[0].setExtremes(0,this.calculateCourseTotal());
    var scoreTotal = 0;
    this.collection.forEach(function(assignmentType,i) {
      chart.series[i].setData([assignmentType.get('score')])
      scoreTotal += assignmentType.get('score');
    });
    $('#predictor-score-display').html(addCommas(scoreTotal));
    $('#predictor-course-total-display').html(addCommas(this.calculateCourseTotal()));
    $('#predictedCourseGrade').html();
  },
  createAssignmentTypes: function() {
    var assignmentTypes = this.collection;
    $.each(this.$el.find('.slides li').not('.clone'),function(i,slide) {
      $slide = $(slide);
      if ($slide.attr('id') == 'slide-required') {
        return true; // Required slide just duplicates assignments from other slides, so we can ignore it
      }
      var assignmentTypeName = $slide.data('assignment-type-name');
      var assignmentTypeId = $slide.data('assignment-type-id');
      assignmentTypes.add(new AssignmentType({ id: assignmentTypeId, name: assignmentTypeName, score: 0 }));
    });
  },
  setupChart: function() {
    this.collection.forEach(function(assignmentType,i) {
      chartOptions.series.push({ name: assignmentType.get('name'), data: [assignmentType.get('score')] });
    });
    chartOptions.xAxis.categories = ' ';
    chartOptions.yAxis.max = this.calculateCourseTotal();
    this.model = new Highcharts.Chart(chartOptions);
  },
  events: {
    'change input': 'calculateScores',
    'change select': 'calculateScores',
    'slidestop .slider': 'calculateScores'
  },
  calculateCourseTotal: function() {
    var courseTotal = 0;
    var $slide = this.$el.find('li#slide-badges')
    $.each($slide.find('input'), function(i,item) {
      var $item = $(item);
      if ($item.is(':checked')) {
        courseTotal += parseInt($item.val());
      }
    });
    courseTotal += parseInt(this.$el.data('course-total'));
    return courseTotal;
  },
  calculateScores: function(e) {
    var assignmentTypes = this.collection;
    $.each(this.$el.find('.slides li').not('.clone'),function(i,slide) {
      var $slide = $(slide);
      if ($slide.attr('id') == 'slide-required') {
        return true;
      }
      var assignmentTypeId = $slide.data('assignment-type-id');
      var score = 0;
      $.each($slide.find('input, select, .slider'), function(i,item) {
        var $item = $(item),
            itemScore = getScore($item);
        score += itemScore;
      });
      assignmentTypes.get(assignmentTypeId).set('score',score);
    });
    if (e) {
      var $item = $(e.target),
          $assignment = $item.closest('.assignment'),
          assignmentId = $assignment.data('assignment'),
          score = getScore($item),
          possibleScore = $assignment.data('possible-points');
      $.ajax('/analytics_events/predictor_event', {
        method: 'post',
        data: {
          assignment: assignmentId,
          score: score,
          possible: possibleScore
        }
      });
    }
  }
});

var getScore = function($item) {
  if($item.is(':checkbox') && $item.is(':checked')) {
    return parseInt($item.val());
  } else if ($item.is('select')) {
    return parseInt($item.children('option:selected').val() || 0);
  } else if ($item.is('input[type="hidden"]')) {
    return parseInt($item.val());
  } else if ($item.is('.ui-slider')) {
    return parseInt($item.slider('value'));
  } else {
    return 0;
  }
}

$(document).ready(function() {
  var $wrapper = $('#prediction');
  if ($wrapper.length) {
    new PredictorView();
  }
});
<|endoftext|>


<commit_before>/**
 * @fileOverview Usage model unit tests.
 */
var Promise = require('bluebird');
var chai = require('chai');
var sinon = require('sinon');
var floordate = require('floordate');
var expect = chai.expect;

var kansasError = require('../../lib/util/error');
var fixtures = require('../lib/fixtures-api');

describe('Usage Model', function() {
  this.timeout(4000);

  fixtures.setupCase();

  describe('Limit Policies', function () {
    it('consumes a unit', function(done) {
      this.kansas.consume(this.token).then(function(remaining) {
        expect(remaining).to.equal(9);
      }).then(done, done);
    });
    it('over limit returns error', function(done) {
      var self = this;
      // create an array with 10 elements of the token to consume.
      var consume = Array.apply(null, new Array(10)).map(function() {
        return self.token;
      });
      Promise.map(consume, function(token) {
        return self.kansas.consume(token);
      })
        .then(function() {
          return self.kansas.consume(self.token).then(function() {
            throw new Error('Should not allow to consume');
          }).catch(function(err) {
            expect(err).to.be.instanceOf(kansasError.UsageLimit);
          });
        }).then(done, done);
    });
    it('accepts units to consume', function(done) {
      var self = this;
      this.kansas.consume(this.token, 10)
        .then(function() {
          return self.kansas.consume(self.token).then(function() {
            throw new Error('Should not allow to consume');
          }).catch(function(err) {
            expect(err).to.be.instanceOf(kansasError.UsageLimit);
          });
        }).then(done, done);
    });
  });

  describe('Count Policies', function () {
    it('Counts a unit', function(done) {
      this.kansas.count(this.tokenItemCount.token).then(function(consumed) {
        expect(consumed).to.equal(1);
      }).then(done, done);
    });
    it('accepts units to count', function(done) {
      this.kansas.count(this.tokenItemCount.token, 10).then(function(consumed) {
        expect(consumed).to.equal(10);
      }).then(done, done);
    });
    it('counts three times', function(done) {
      var self = this;
      this.kansas.count(this.tokenItemCount.token).then(function() {
        return self.kansas.count(self.tokenItemCount.token).then(function() {
          return self.kansas.count(self.tokenItemCount.token).then(function(consumed) {
            expect(consumed).to.equal(3);
          });
        });
      }).then(done, done);
    });
  });

  describe('Check month period', function() {
    var clock;
    beforeEach(function() {
      var floored = floordate(Date.now(), 'month');
      clock = sinon.useFakeTimers(floored.getTime());
    });
    afterEach(function() {
      clock.restore();
    });
    it('Will roll over to next month and reset limit', function(done) {
      var self = this;
      var consume = Array.apply(null, new Array(10)).map(function() {
        return self.token;
      });

      Promise.map(consume, function(token) {
        return self.kansas.consume(token);
      })
        .then(function() {
          // move time fwd 40days.
          var moveFwd = 40 * 24 * 3600 * 1000;
          clock.tick(moveFwd);
          return self.kansas.consume(self.token).then(function(remaining) {
            expect(remaining).to.equal(9);
          });
        }).then(done, done);
    });
  });
});

<commit_msg>create test cases for getUsage()<commit_after>/**
 * @fileOverview Usage model unit tests.
 */
var Promise = require('bluebird');
var chai = require('chai');
var sinon = require('sinon');
var floordate = require('floordate');
var expect = chai.expect;

var kansasError = require('../../lib/util/error');
var fixtures = require('../lib/fixtures-api');

describe('Usage Model', function() {
  this.timeout(4000);

  fixtures.setupCase();

  describe('Limit Policies', function () {
    it('consumes a unit', function(done) {
      this.kansas.consume(this.token).then(function(remaining) {
        expect(remaining).to.equal(9);
      }).then(done, done);
    });
    it('over limit returns error', function(done) {
      var self = this;
      // create an array with 10 elements of the token to consume.
      var consume = Array.apply(null, new Array(10)).map(function() {
        return self.token;
      });
      Promise.map(consume, function(token) {
        return self.kansas.consume(token);
      })
        .then(function() {
          return self.kansas.consume(self.token).then(function() {
            throw new Error('Should not allow to consume');
          }).catch(function(err) {
            expect(err).to.be.instanceOf(kansasError.UsageLimit);
          });
        }).then(done, done);
    });
    it('accepts units to consume', function(done) {
      var self = this;
      this.kansas.consume(this.token, 10)
        .then(function() {
          return self.kansas.consume(self.token).then(function() {
            throw new Error('Should not allow to consume');
          }).catch(function(err) {
            expect(err).to.be.instanceOf(kansasError.UsageLimit);
          });
        }).then(done, done);
    });
  });

  describe('Count Policies', function () {
    it('Counts a unit', function(done) {
      this.kansas.count(this.tokenItemCount.token).then(function(consumed) {
        expect(consumed).to.equal(1);
      }).then(done, done);
    });
    it('accepts units to count', function(done) {
      this.kansas.count(this.tokenItemCount.token, 10).then(function(consumed) {
        expect(consumed).to.equal(10);
      }).then(done, done);
    });
    it('counts three times', function(done) {
      var self = this;
      this.kansas.count(this.tokenItemCount.token).then(function() {
        return self.kansas.count(self.tokenItemCount.token).then(function() {
          return self.kansas.count(self.tokenItemCount.token).then(function(consumed) {
            expect(consumed).to.equal(3);
          });
        });
      }).then(done, done);
    });
  });

  describe('Check month period', function() {
    var clock;
    beforeEach(function() {
      var floored = floordate(Date.now(), 'month');
      clock = sinon.useFakeTimers(floored.getTime());
    });
    afterEach(function() {
      clock.restore();
    });
    it('Will roll over to next month and reset limit', function(done) {
      var self = this;
      var consume = Array.apply(null, new Array(10)).map(function() {
        return self.token;
      });

      Promise.map(consume, function(token) {
        return self.kansas.consume(token);
      })
        .then(function() {
          // move time fwd 40days.
          var moveFwd = 40 * 24 * 3600 * 1000;
          clock.tick(moveFwd);
          return self.kansas.consume(self.token).then(function(remaining) {
            expect(remaining).to.equal(9);
          });
        }).then(done, done);
    });
  });

  describe.only('Getting Usage', function () {
    beforeEach(function (done) {
      this.kansas.consume(this.token, 3)
        .then(done.bind(null, null), done);
    });
    beforeEach(function (done) {
      this.kansas.count(this.tokenItemCount.token, 4)
        .then(done.bind(null, null), done);
    });

    it('Gets usage for a [limit] token', function(done) {
      this.kansas.getUsage(this.token).then(function(remaining) {
        expect(remaining).to.equal(7);
      }).then(done, done);
    });
    it('Gets usage for a [limit] user id', function(done) {
      this.kansas.getUsageByOwnerId(this.tokenItem.ownerId).then(function(remaining) {
        expect(remaining).to.equal(7);
      }).then(done, done);
    });
    it('Gets usage for a [count] token', function(done) {
      this.kansas.getUsage(this.tokenItemCount.token).then(function(used) {
        expect(used).to.equal(4);
      }).then(done, done);
    });
    it('Gets usage for a [count] user id', function(done) {
      this.kansas.getUsageByOwnerId(this.tokenItemCount.ownerId).then(function(used) {
        expect(used).to.equal(4);
      }).then(done, done);
    });
  });
});

<|endoftext|>


<commit_before>var EventEmitter = require('events').EventEmitter,
	Master = require('./Master'),
	Slave = require('./Slave')

module.exports = Cluster

function Cluster() {
	var vm = this

	EventEmitter.call(vm)
	vm.masters = []
	vm.num_masters = 0
	vm.last_master_used = 0

	vm.errors = {
		bad_sql:'Improperly formatted query string',
		bad_callback:'Must include a callback function as either the second or third argument \'function(err,rows)\'',
		bad_db_config:'Manager configuration must be included and must be an object. Please refer to documentation for more details'
	}
}

Cluster.prototype.query = function(sql,values,cb,options) {
	var vm = this,
		qry = null,
		callback = null,
		opts = null,
		type = 1

	if (typeof sql == 'string' && sql.length) {
		qry = sql
	} else {
		throw new Error(vm.errors.bad_sql)
	}

	if (typeof values == 'function') {
		callback = values
		if (typeof cb == 'object') {
			opts = cb
		}
	} else {
		if (typeof cb == 'function') {
			callback = cb
			opts = options || {}
		} else {
			throw new Error(vm.errors.bad_callback)
		}
		type = 2
	}

	vm.getAvailableMaster(function(index) {
		try {
			if (index > -1) {
				if (type == 1) {
					vm.masters[index].query(qry,[],callback,opts)
				} else {
					vm.masters[index].query(qry,values,callback,opts)
				}
			} else {
				callback('No active masters... Please ensure sql masters are live',null)
			}
		} catch(err) {
			console.log(vm.masters)
			console.log(vm.masters.length)
			console.log(err)
			console.log(index)
			try {
				if (type == 1) {
					vm.masters[0].query(qry,[],callback,opts)
				} else {
					vm.masters[0].query(qry,values,callback,opts)
				}
			}catch(err2) {
				callback('No active masters... Please ensure sql masters are live',null)
			}
		}
	})
}

Cluster.prototype.changeMasterData = function(sql,values,callback,options) {
	var vm = this

	function updateData(i) {
		if (i < vm.masters.length - 1) {
			vm.masters[i].pool.query(sql,values,function(){},options)
		} else {
			vm.masters[i].pool.query(sql,values,callback,options)
		}
	}

	for (var i = 0; i < vm.masters.length; i++) {
		updateData(i)
	}
}

/**
 * Create a new Pool instance.
 * @return int master_index
 *		   -1 No good masters
 *			* Index of available master
 * @public
 */
Cluster.prototype.getAvailableMaster = function(callback) {
	var vm = this,
		num = this.masters.length,
		index = -1,
		running_index = this.last_master_used

	function finish() {
		if (!(--num)) { callback(index) }
	}

	for (var i = 0; i < vm.masters.length;i++) {
		vm.masters[running_index].isAvailable(function(is_available,master_index) {
			if (index == -1 && is_available) {
				index = master_index
				vm.last_master_used = (master_index + 1) % (vm.masters.length)
			}
			finish()
		})
		if (running_index >= vm.masters.length) { running_index = 0 }
	}
}

Cluster.prototype.addMaster = function(name,manager_config,query_config,callback) {
	var vm = this,
		new_master = {
			name:name,
			master_index:0,
			manager_config:manager_config,
			query_config:query_config || manager_config,
			slaves:[]
		}

	if (!manager_config || typeof manager_config != 'object') {
		throw new Error(this.errors.bad_manager_config)
	}
	if (!callback) { callback = function(){} }

	var master = new Master(new_master)
	master.setIndex(vm.masters.length)
	master.init(vm,function() {
		vm.masters.push(master)
		vm.num_masters = vm.masters.length
		callback()
	})
}

Cluster.prototype.addSlave = function(name,master_name,manager_config,query_config,callback) {
	var vm = this,
		master_index = -1,
		new_slave = {
			name:name,
			manager_config:manager_config,
			query_config:query_config || manager_config
		}

	if (!manager_config || typeof manager_config != 'object') {
		throw new Error(this.errors.bad_db_config)
	}
	if (!callback) { callback = function(){} }

	for (var i = 0; i < vm.masters.length; i++) {
		if (master_name == vm.masters[i].name) {
			master_index = i
		}
	}

	if (master_index > -1) {
		var slave = new Slave(new_slave)
		vm.masters[master_index].addSlave(slave,function() {
			callback()
		})
	} else {
		throw new Error('Master ' + master_name + ' not found.')
	}
}<commit_msg>finished<commit_after>var EventEmitter = require('events').EventEmitter,
	Master = require('./Master'),
	Slave = require('./Slave')

module.exports = Cluster

function Cluster() {
	var vm = this

	EventEmitter.call(vm)
	vm.masters = []
	vm.num_masters = 0
	vm.last_master_used = 0

	vm.errors = {
		bad_sql:'Improperly formatted query string',
		bad_callback:'Must include a callback function as either the second or third argument \'function(err,rows)\'',
		bad_db_config:'Manager configuration must be included and must be an object. Please refer to documentation for more details'
	}
}

Cluster.prototype.query = function(sql,values,cb,options) {
	var vm = this,
		qry = null,
		callback = null,
		opts = null,
		type = 1

	if (typeof sql == 'string' && sql.length) {
		qry = sql
	} else {
		throw new Error(vm.errors.bad_sql)
	}

	if (typeof values == 'function') {
		callback = values
		if (typeof cb == 'object') {
			opts = cb
		}
	} else {
		if (typeof cb == 'function') {
			callback = cb
			opts = options || {}
		} else {
			throw new Error(vm.errors.bad_callback)
		}
		type = 2
	}

	vm.getAvailableMaster(function(index) {
		try {
			if (index > -1) {
				if (type == 1) {
					vm.masters[index].pool.query(qry,[],callback,opts)
				} else {
					vm.masters[index].pool.query(qry,values,callback,opts)
				}
			} else {
				callback('No active masters... Please ensure sql masters are live',null)
			}
		} catch(err) {
			console.log(vm.masters)
			console.log(vm.masters.length)
			console.log(err)
			console.log(index)
			try {
				if (type == 1) {
					vm.masters[0].pool.query(qry,[],callback,opts)
				} else {
					vm.masters[0].pool.query(qry,values,callback,opts)
				}
			}catch(err2) {
				callback('No active masters... Please ensure sql masters are live',null)
			}
		}
	})
}

Cluster.prototype.changeMasterData = function(sql,values,callback,options) {
	var vm = this

	function updateData(i) {
		if (i < vm.masters.length - 1) {
			vm.masters[i].pool.query(sql,values,function(){},options)
		} else {
			vm.masters[i].pool.query(sql,values,callback,options)
		}
	}

	for (var i = 0; i < vm.masters.length; i++) {
		updateData(i)
	}
}

/**
 * Create a new Pool instance.
 * @return int master_index
 *		   -1 No good masters
 *			* Index of available master
 * @public
 */
Cluster.prototype.getAvailableMaster = function(callback) {
	var vm = this,
		num = this.masters.length,
		index = -1,
		running_index = this.last_master_used

	function finish() {
		if (!(--num)) { callback(index) }
	}

	for (var i = 0; i < vm.masters.length;i++) {
		vm.masters[running_index].isAvailable(function(is_available,master_index) {
			if (index == -1 && is_available) {
				index = master_index
				vm.last_master_used = (master_index + 1) % (vm.masters.length)
			}
			finish()
		})
		if (running_index >= vm.masters.length) { running_index = 0 }
	}
}

Cluster.prototype.addMaster = function(name,manager_config,query_config,callback) {
	var vm = this,
		new_master = {
			name:name,
			master_index:0,
			manager_config:manager_config,
			query_config:query_config || manager_config,
			slaves:[]
		}

	if (!manager_config || typeof manager_config != 'object') {
		throw new Error(this.errors.bad_manager_config)
	}
	if (!callback) { callback = function(){} }

	var master = new Master(new_master)
	master.setIndex(vm.masters.length)
	master.init(vm,function() {
		vm.masters.push(master)
		vm.num_masters = vm.masters.length
		callback()
	})
}

Cluster.prototype.addSlave = function(name,master_name,manager_config,query_config,callback) {
	var vm = this,
		master_index = -1,
		new_slave = {
			name:name,
			manager_config:manager_config,
			query_config:query_config || manager_config
		}

	if (!manager_config || typeof manager_config != 'object') {
		throw new Error(this.errors.bad_db_config)
	}
	if (!callback) { callback = function(){} }

	for (var i = 0; i < vm.masters.length; i++) {
		if (master_name == vm.masters[i].name) {
			master_index = i
		}
	}

	if (master_index > -1) {
		var slave = new Slave(new_slave)
		vm.masters[master_index].addSlave(slave,function() {
			callback()
		})
	} else {
		throw new Error('Master ' + master_name + ' not found.')
	}
}<|endoftext|>


<commit_before>"use strict";
let vscode = require('vscode');
let linters = require('./lint/lint');
const severities = {
	refactor: vscode.DiagnosticSeverity.Hint,
	convention: vscode.DiagnosticSeverity.Information,
	info: vscode.DiagnosticSeverity.Information,
	warning: vscode.DiagnosticSeverity.Warning,
	error: vscode.DiagnosticSeverity.Error,
	fatal: vscode.DiagnosticSeverity.Error
};
let timer;

function deferReport(uri, lint, diagnostic) {
	if (lint.error) {
		console.log("Linter error:", lint.source, lint.error);
		return;
	}
	if ((!lint.result || !lint.result.length) && (!lint.lintError || !lint.lintError.length)) return;
	let allOf = lint.result.concat(lint.lintError)
		.map(offense => {
			let tail = offense.location.column + offense.location.length;
			let d = new vscode.Diagnostic(new vscode.Range(
					offense.location.line - 1, offense.location.column - 1,
					offense.location.line - 1, tail - 1),
				offense.message, severities[offense.severity] || vscode.DiagnosticSeverity.Error);
			d.source = offense.cop_name || lint.linter;
			return d;
		});
	diagnostic.set(uri, allOf);
}

const langConfig = {
	comments: {
		lineComment: "#",
		blockComment: ["=begin", "=end"]
	},
	brackets: [
		["{", "}"],
		["[", "]"],
		["(", ")"]
	],
	indentationRules: {
		increaseIndentPattern: /^\s*(begin|class|def|else|elsif|ensure|for|if|module|rescue|unless|until|when|while)\b[^\{;]*$/
	},
	wordPattern: /(-?\d+\.\d\w*)|([:]?[^\`\~\@\#\%\^\&\*\(\)\-\=\+\[\{\]\}\\\|\;\:\'\"\,\.\<\>\/\s\!\?]+[\!\?]?)/
};

let pairedEnds = [];

const highligher = {
	provideDocumentHighlights: (doc, pos) => {
		const word = doc.getText(doc.getWordRangeAtPosition(pos));
		let result;
		if (
			(/\b(begin|class|def|for|if|module|unless|until|case|while|do)\b/.test(doc.lineAt(pos.line)
					.text) &&
				pairedEnds.some(pair => (result = (pair.entry.start.line === pos.line) ? pair : null))) ||
			(word === 'end' && pairedEnds.some(pair => (result = (pair.end.start.line === pos.line) ? pair : null)))
		) {
			return [new vscode.DocumentHighlight(result.entry,2), new vscode.DocumentHighlight(result.end,2)];
		}
	}
};

function getEnd(line) {
	//end must be on a line by itself, or followed directly by a dot
	let match = line.text.match(/^(\s*)(end|(end\..*))\s*$/);
	if (match) {
		return new vscode.Range(line.lineNumber, match[1].length, line.lineNumber, match[1].length + 3);
	}
}

function getEntry(line) {
	//only lines that start with the entry
	let match = line.text.match(/^(\s*)(begin|class|def|for|if|module|unless|until|case|while)\b[^\{;]*$/);
	if (match) {
		return new vscode.Range(line.lineNumber, match[1].length, line.lineNumber, match[1].length + match[2].length);
	} else {
		//check for do
		match = line.text.match(/\b(do)\b\s*(\|.*\|[^;]*)?$/);
		if (match) {
			return new vscode.Range(line.lineNumber, match.index, line.lineNumber, match.index + 2);
		}
	}
}

function balancePairs(doc) {
	pairedEnds = [];
	if (doc.languageId !== 'ruby') return;

	let waitingEntries = [];
	let entry, end;
	for (let i = 0; i < doc.lineCount; i++) {
		if ((entry = getEntry(doc.lineAt(i)))) {
			waitingEntries.push(entry);
		} else if (waitingEntries.length && (end = getEnd(doc.lineAt(i)))) {
			pairedEnds.push({
				entry: waitingEntries.pop(),
				end: end
			});
		}
	}
}

function balanceEvent(event) {
	pairedEnds = [];
	if (event && event.document) balancePairs(event.document);
}

function activate(context) {
	//add language config
	vscode.languages.setLanguageConfiguration('ruby', langConfig);

	let activeLinters = {};
	let linterTimers = {};
	let activeDiagnostics = {};

	function changeTrigger(changed) {
		timer = process.hrtime();
		if (!changed || !changed.document) return;
		if (changed.document.languageId !== 'ruby') return;

		const doc = changed.document;
		let lintConfig = vscode.workspace.getConfiguration("ruby.lint");

		if (lintConfig) {
			clearTimeout(linterTimers[doc.fileName]);

			if (activeLinters[doc.fileName]) {
				try {
					activeLinters[doc.fileName].send('stop');
				} catch (e) {}
				delete activeLinters[doc.fileName];
			}
			linterTimers[doc.fileName] = setTimeout(() => {
				activeLinters[doc.fileName] = linters.runCollection(lintConfig, doc.fileName, doc.getText(), result => {
					if (!activeDiagnostics[result.linter]) {
						activeDiagnostics[result.linter] = vscode.languages.createDiagnosticCollection(result.linter);
						context.subscriptions.push(activeDiagnostics[result.linter]);
					}
					activeDiagnostics[result.linter].delete(doc.uri);
					deferReport(doc.uri, result, activeDiagnostics[result.linter]);
				});
			}, 200);
		}
	}
	context.subscriptions.push(vscode.languages.registerDocumentHighlightProvider('ruby', highligher));

	context.subscriptions.push(vscode.window.onDidChangeActiveTextEditor(changeTrigger));
	context.subscriptions.push(vscode.workspace.onDidChangeTextDocument(changeTrigger));
	context.subscriptions.push(vscode.workspace.onDidChangeConfiguration(
		() => vscode.window.visibleTextEditors.forEach(changeTrigger)));

	vscode.window.visibleTextEditors.forEach(changeTrigger);

	context.subscriptions.push(vscode.window.onDidChangeActiveTextEditor(balanceEvent));
	context.subscriptions.push(vscode.workspace.onDidChangeTextDocument(balanceEvent));
	context.subscriptions.push(vscode.workspace.onDidOpenTextDocument(balancePairs));

	balancePairs(vscode.window.activeTextEditor.document);

}

exports.activate = activate;
<commit_msg>Tidy regex, add `do` to indenter<commit_after>"use strict";
let vscode = require('vscode');
let linters = require('./lint/lint');
const severities = {
	refactor: vscode.DiagnosticSeverity.Hint,
	convention: vscode.DiagnosticSeverity.Information,
	info: vscode.DiagnosticSeverity.Information,
	warning: vscode.DiagnosticSeverity.Warning,
	error: vscode.DiagnosticSeverity.Error,
	fatal: vscode.DiagnosticSeverity.Error
};
let timer;

function deferReport(uri, lint, diagnostic) {
	if (lint.error) {
		console.log("Linter error:", lint.source, lint.error);
		return;
	}
	if ((!lint.result || !lint.result.length) && (!lint.lintError || !lint.lintError.length)) return;
	let allOf = lint.result.concat(lint.lintError)
		.map(offense => {
			let tail = offense.location.column + offense.location.length;
			let d = new vscode.Diagnostic(new vscode.Range(
					offense.location.line - 1, offense.location.column - 1,
					offense.location.line - 1, tail - 1),
				offense.message, severities[offense.severity] || vscode.DiagnosticSeverity.Error);
			d.source = offense.cop_name || lint.linter;
			return d;
		});
	diagnostic.set(uri, allOf);
}

const langConfig = {
	comments: {
		lineComment: "#",
		blockComment: ["=begin", "=end"]
	},
	brackets: [
		["{", "}"],
		["[", "]"],
		["(", ")"]
	],
	indentationRules: {
		increaseIndentPattern: /^\s*((begin|class|def|else|elsif|ensure|for|if|module|rescue|unless|until|when|while)|(.*\sdo\b))\b[^\{;]*$/
	},
	wordPattern: /(-?\d+(?:\.\d+))|(:?[A-Za-z][^-`~@#%^&()=+[{}|;:'",<>/\]\.\*\s\\!?]+[!?]?)/
};

let pairedEnds = [];

const highligher = {
	provideDocumentHighlights: (doc, pos) => {
		const word = doc.getText(doc.getWordRangeAtPosition(pos));
		let result;
		if (
			(/\b(begin|class|def|for|if|module|unless|until|case|while|do)\b/.test(doc.lineAt(pos.line)
					.text) &&
				pairedEnds.some(pair => (result = (pair.entry.start.line === pos.line) ? pair : null))) ||
			(word === 'end' && pairedEnds.some(pair => (result = (pair.end.start.line === pos.line) ? pair : null)))
		) {
			return [new vscode.DocumentHighlight(result.entry,2), new vscode.DocumentHighlight(result.end,2)];
		}
	}
};

function getEnd(line) {
	//end must be on a line by itself, or followed directly by a dot
	let match = line.text.match(/^(\s*)(end|(end\..*))\s*$/);
	if (match) {
		return new vscode.Range(line.lineNumber, match[1].length, line.lineNumber, match[1].length + 3);
	}
}

function getEntry(line) {
	//only lines that start with the entry
	let match = line.text.match(/^(\s*)(begin|class|def|for|if|module|unless|until|case|while)\b[^\{;]*$/);
	if (match) {
		return new vscode.Range(line.lineNumber, match[1].length, line.lineNumber, match[1].length + match[2].length);
	} else {
		//check for do
		match = line.text.match(/\b(do)\b\s*(\|.*\|[^;]*)?$/);
		if (match) {
			return new vscode.Range(line.lineNumber, match.index, line.lineNumber, match.index + 2);
		}
	}
}

function balancePairs(doc) {
	pairedEnds = [];
	if (doc.languageId !== 'ruby') return;

	let waitingEntries = [];
	let entry, end;
	for (let i = 0; i < doc.lineCount; i++) {
		if ((entry = getEntry(doc.lineAt(i)))) {
			waitingEntries.push(entry);
		} else if (waitingEntries.length && (end = getEnd(doc.lineAt(i)))) {
			pairedEnds.push({
				entry: waitingEntries.pop(),
				end: end
			});
		}
	}
}

function balanceEvent(event) {
	pairedEnds = [];
	if (event && event.document) balancePairs(event.document);
}

function activate(context) {
	//add language config
	vscode.languages.setLanguageConfiguration('ruby', langConfig);

	let activeLinters = {};
	let linterTimers = {};
	let activeDiagnostics = {};

	function changeTrigger(changed) {
		timer = process.hrtime();
		if (!changed || !changed.document) return;
		if (changed.document.languageId !== 'ruby') return;

		const doc = changed.document;
		let lintConfig = vscode.workspace.getConfiguration("ruby.lint");

		if (lintConfig) {
			clearTimeout(linterTimers[doc.fileName]);

			if (activeLinters[doc.fileName]) {
				try {
					activeLinters[doc.fileName].send('stop');
				} catch (e) {}
				delete activeLinters[doc.fileName];
			}
			linterTimers[doc.fileName] = setTimeout(() => {
				activeLinters[doc.fileName] = linters.runCollection(lintConfig, doc.fileName, doc.getText(), result => {
					if (!activeDiagnostics[result.linter]) {
						activeDiagnostics[result.linter] = vscode.languages.createDiagnosticCollection(result.linter);
						context.subscriptions.push(activeDiagnostics[result.linter]);
					}
					activeDiagnostics[result.linter].delete(doc.uri);
					deferReport(doc.uri, result, activeDiagnostics[result.linter]);
				});
			}, 200);
		}
	}
	context.subscriptions.push(vscode.languages.registerDocumentHighlightProvider('ruby', highligher));

	context.subscriptions.push(vscode.window.onDidChangeActiveTextEditor(changeTrigger));
	context.subscriptions.push(vscode.workspace.onDidChangeTextDocument(changeTrigger));
	context.subscriptions.push(vscode.workspace.onDidChangeConfiguration(
		() => vscode.window.visibleTextEditors.forEach(changeTrigger)));

	vscode.window.visibleTextEditors.forEach(changeTrigger);

	context.subscriptions.push(vscode.window.onDidChangeActiveTextEditor(balanceEvent));
	context.subscriptions.push(vscode.workspace.onDidChangeTextDocument(balanceEvent));
	context.subscriptions.push(vscode.workspace.onDidOpenTextDocument(balancePairs));

	balancePairs(vscode.window.activeTextEditor.document);

}

exports.activate = activate;
<|endoftext|>


<commit_before>/*
 * grunt-version-build
 * https://github.com/robwierzbowski/grunt-version-build
 *
 * Copyright (c) 2013 Rob Wierzbowski
 * Licensed under the MIT license.
 */

'use strict';

module.exports = function (grunt) {
  var fs = require('fs');
  var path = require('path');
  var shelljs = require('shelljs');

  grunt.registerMultiTask('version_build', 'Version built code next to your project\'s source.', function() {

    var done = this.async();
    var options = this.options({
      commit: false,
      // tag: false,
      push: false,
      commitMsg: 'Built from commit %sourceCommit% on branch %sourceBranch%',
      force: false
    });

    var sourceInfo = {
      branch: '(unavailable)',
      commit: '(unavailable)',
      name:   '(unavailable)'
    };

    var gruntDir = shelljs.pwd();

    // Check requirements
    function checkRequirements (next) {
      // Check that required options are set.
      ['branch', 'dir', 'remote'].forEach( function (element) {
        if (!options.hasOwnProperty(element)) {
          throw('The "' + element + '" option is required.');
        }
      });

      // Check that the dist directory exists
      if (!fs.existsSync(options.dir)) {
        grunt.log.writeln('Creating target directory "' + options.dir + '".');
        shelljs.mkdir(options.dir);
      }
    }

    // Get source project information for %tokens%
    function buildSourceInfo () {
      var sourceBranch = shelljs.exec('git symbolic-ref --quiet HEAD', {silent: true});
      var sourceCommit = shelljs.exec('git rev-parse --short HEAD', {silent: true});

      if (sourceBranch.code === 0) {
        sourceInfo.branch = sourceBranch.output.split('/').pop().replace(/\n/g, '');
      }

      if (sourceCommit.code === 0) {
        sourceInfo.commit = sourceCommit.output.replace(/\n/g, '');
      }

      if (shelljs.test('-f', 'package.json', {silent: true})) {
        sourceInfo.name = JSON.parse(fs.readFileSync('package.json', 'utf8')).name;
      }
    }

    // Initialize git repo if one doesn't exist
    function initGit () {
      if (!fs.existsSync(path.join(gruntDir, options.dir, '.git'))) {
        grunt.log.writeln('Creating git repository in ' + options.dir + '.');

        if (shelljs.exec('git init').code !== 0) {
          throw("Could not initialize the local git repo."); // TODO: show stderrs for easier debugging
        }
      }
    }

    // Create branch if it doesn't exist
    function initBranch () {

      // TODO: simplify this a bit
      // if branch does not exist
      //   if remote exists
      //     fetch remote
      //   else
      //     create branch
      //     create empty first commit
      // else
      //   return

      // If branch exists
      if (shelljs.exec('git show-ref --verify --quiet refs/heads/' + options.branch).code === 0) {
        return;
      }
      // If branch doesn't exist
      else {

        // Create branch if it doesn't exist
        if (shelljs.exec('git checkout --orphan ' + options.branch).code !== 0) {
          throw("Could not create branch."); // TODO: show stderrs for easier debugging
        }

        // Fetch remote branch if it exists
        grunt.log.writeln('Checking to see if the branch exists remotely...');

        // Check if remote branch exists
        if (shelljs.exec('git ls-remote --exit-code ' + options.remote + ' ' + options.branch).code === 0) {

          // TODO: fetch remote branch
          // grunt.log.writeln('Remote branch exists.');
          return;
        }

        // Initialize branch so we can move the HEAD ref around
        // TODO: get this workin

        //// Creating local branch with initial commit
        grunt.log.writeln('Remote branch does not exist. Adding an initial commit.');

        if (shelljs.exec('git commit --allow-empty -m "Initial Commit."').code !== 0) {
          throw('Could not create an initial commit.'); // TODO: show stderrs for easier debugging
        }

        // TODO: move push to push task, or do we need this?
        // if (shelljs.exec('git push --set-upstream ' + options.remote + ' HEAD:' + options.branch).code !== 0) {
        //   throw('Could not push initial branch.'); // TODO: show stderrs for easier debugging
        // }
      }
    }

    // Make the current working tree the branch HEAD without checking out files
    function safeCheckout () {

      // TODO: not sure why we're pulling in here
      // TODO: this should be safecheckout / move head ref
      grunt.log.writeln('Pulling latest from remote.');

      if (shelljs.exec('git pull ' + options.remote + ' ' + options.branch).code !== 0) {
        throw('Could not pull local branch.');
      }
    }

    // Stage and commit to a branch
    function gitCommit () {
      // TODO: Pull/fetch before each commit
      var commitMsg;
      var status = shelljs.exec('git status --porcelain');

      // Unstage any changes, just in case
      if (shelljs.exec('git reset').code !== 0) {
        grunt.log.writeln('Could not unstage local changes.');
      }

      // Make sure there are differneces to commit
      if (status.code !== 0) {
        throw('Could not execute git status.'); // TODO: show stderrs for easier debugging
      }

      if (status.output === '') {
        // No changes, skip commit
        grunt.log.writeln('There have been no changes, skipping commit.'); //// reword
        return;
      }

      // Parse tokens in commit message
      commitMsg = options.commitMsg
        .replace(/%sourceName%/g, sourceInfo.name)
        .replace(/%sourceCommit%/g, sourceInfo.commit)
        .replace(/%sourceBranch%/g, sourceInfo.branch);

      // Stage and commit
      if (shelljs.exec('git add -A . && git commit -m "' + commitMsg + '"').code !== 0) {
        throw('Unable to commit changes locally.'); // TODO: show stderrs for easier debugging
      }

      grunt.log.writeln('Committed changes to branch "' + options.branch + '".'); // TODO: show stdout for better reporting
    }

    // TODO: Implement tag option
    // Pronounced "gihttag"
    // function gitTag () {
    // }

    // Push portal branch to the remote
    function gitPush () {
      var args = '';

      if (options.force) {
        args += '-f ';
      }

      if (shelljs.exec('git push ' + args + options.remote + ' HEAD:' + options.branch).code !== 0) {
        throw('Unable to push changes to remote.'); // TODO: show stderr for better debugging
      }

      grunt.log.writeln('Pushed ' + options.branch + ' to ' + options.remote); // TODO: show stdout for better reporting
    }

    // Run task
    try {

      checkRequirements();
      buildSourceInfo();

      // Change working directory
      shelljs.cd(options.dir);

      initGit();
      initBranch();
      safeCheckout(); // TODO: this will change when safeChk is redefined

      if (options.commit) {
        gitCommit();
      }

      // if (options.tag) {
      //   gitCommit();
      // }

      if (options.push) {
        gitPush();
      }

      done(true);
    }
    catch (e) {
      grunt.fail.warn(e);
      done(false);
    }
    finally {
      shelljs.cd(gruntDir);
    }
  });
};
<commit_msg>Rename token object and assignment function<commit_after>/*
 * grunt-version-build
 * https://github.com/robwierzbowski/grunt-version-build
 *
 * Copyright (c) 2013 Rob Wierzbowski
 * Licensed under the MIT license.
 */

'use strict';

module.exports = function (grunt) {
  var fs = require('fs');
  var path = require('path');
  var shelljs = require('shelljs');

  grunt.registerMultiTask('version_build', 'Version built code next to your project\'s source.', function() {

    var done = this.async();
    var options = this.options({
      commit: false,
      // tag: false,
      push: false,
      commitMsg: 'Built from commit %sourceCommit% on branch %sourceBranch%',
      force: false
    });

    var tokens = {
      branch: '(unavailable)',
      commit: '(unavailable)',
      name:   '(unavailable)'
    };

    var gruntDir = shelljs.pwd();

    // Check requirements
    function checkRequirements (next) {
      // Check that required options are set.
      ['branch', 'dir', 'remote'].forEach( function (element) {
        if (!options.hasOwnProperty(element)) {
          throw('The "' + element + '" option is required.');
        }
      });

      // Check that the dist directory exists
      if (!fs.existsSync(options.dir)) {
        grunt.log.writeln('Creating target directory "' + options.dir + '".');
        shelljs.mkdir(options.dir);
      }
    }

    // Assign %token% values if available
    function assignTokens () {
      var sourceBranch = shelljs.exec('git symbolic-ref --quiet HEAD', {silent: true});
      var sourceCommit = shelljs.exec('git rev-parse --short HEAD', {silent: true});

      if (sourceBranch.code === 0) {
        tokens.branch = sourceBranch.output.split('/').pop().replace(/\n/g, '');
      }
      if (sourceCommit.code === 0) {
        tokens.commit = sourceCommit.output.replace(/\n/g, '');
      }
      if (shelljs.test('-f', 'package.json', {silent: true})) {
        tokens.name = JSON.parse(fs.readFileSync('package.json', 'utf8')).name;
      }
    }

    // Initialize git repo if one doesn't exist
    function initGit () {
      if (!fs.existsSync(path.join(gruntDir, options.dir, '.git'))) {
        grunt.log.writeln('Creating git repository in ' + options.dir + '.');

        if (shelljs.exec('git init').code !== 0) {
          throw("Could not initialize the local git repo."); // TODO: show stderrs for easier debugging
        }
      }
    }

    // Create branch if it doesn't exist
    function initBranch () {

      // TODO: simplify this a bit
      // if branch does not exist
      //   if remote exists
      //     fetch remote
      //   else
      //     create branch
      //     create empty first commit
      // else
      //   return

      // If branch exists
      if (shelljs.exec('git show-ref --verify --quiet refs/heads/' + options.branch).code === 0) {
        return;
      }
      // If branch doesn't exist
      else {

        // Create branch if it doesn't exist
        if (shelljs.exec('git checkout --orphan ' + options.branch).code !== 0) {
          throw("Could not create branch."); // TODO: show stderrs for easier debugging
        }

        // Fetch remote branch if it exists
        grunt.log.writeln('Checking to see if the branch exists remotely...');

        // Check if remote branch exists
        if (shelljs.exec('git ls-remote --exit-code ' + options.remote + ' ' + options.branch).code === 0) {

          // TODO: fetch remote branch
          // grunt.log.writeln('Remote branch exists.');
          return;
        }

        // Initialize branch so we can move the HEAD ref around
        // TODO: get this workin

        //// Creating local branch with initial commit
        grunt.log.writeln('Remote branch does not exist. Adding an initial commit.');

        if (shelljs.exec('git commit --allow-empty -m "Initial Commit."').code !== 0) {
          throw('Could not create an initial commit.'); // TODO: show stderrs for easier debugging
        }

        // TODO: move push to push task, or do we need this?
        // if (shelljs.exec('git push --set-upstream ' + options.remote + ' HEAD:' + options.branch).code !== 0) {
        //   throw('Could not push initial branch.'); // TODO: show stderrs for easier debugging
        // }
      }
    }

    // Make the current working tree the branch HEAD without checking out files
    function safeCheckout () {

      // TODO: not sure why we're pulling in here
      // TODO: this should be safecheckout / move head ref
      grunt.log.writeln('Pulling latest from remote.');

      if (shelljs.exec('git pull ' + options.remote + ' ' + options.branch).code !== 0) {
        throw('Could not pull local branch.');
      }
    }

    // Stage and commit to a branch
    function gitCommit () {
      // TODO: Pull/fetch before each commit
      var commitMsg;
      var status = shelljs.exec('git status --porcelain');

      // Unstage any changes, just in case
      if (shelljs.exec('git reset').code !== 0) {
        grunt.log.writeln('Could not unstage local changes.');
      }

      // Make sure there are differneces to commit
      if (status.code !== 0) {
        throw('Could not execute git status.'); // TODO: show stderrs for easier debugging
      }

      if (status.output === '') {
        // No changes, skip commit
        grunt.log.writeln('There have been no changes, skipping commit.'); //// reword
        return;
      }

      // Parse tokens in commit message
      commitMsg = options.commitMsg
        .replace(/%sourceName%/g, tokens.name)
        .replace(/%sourceCommit%/g, tokens.commit)
        .replace(/%sourceBranch%/g, tokens.branch);

      // Stage and commit
      if (shelljs.exec('git add -A . && git commit -m "' + commitMsg + '"').code !== 0) {
        throw('Unable to commit changes locally.'); // TODO: show stderrs for easier debugging
      }

      grunt.log.writeln('Committed changes to branch "' + options.branch + '".'); // TODO: show stdout for better reporting
    }

    // TODO: Implement tag option
    // Pronounced "gihttag"
    // function gitTag () {
    // }

    // Push portal branch to the remote
    function gitPush () {
      var args = '';

      if (options.force) {
        args += '-f ';
      }

      if (shelljs.exec('git push ' + args + options.remote + ' HEAD:' + options.branch).code !== 0) {
        throw('Unable to push changes to remote.'); // TODO: show stderr for better debugging
      }

      grunt.log.writeln('Pushed ' + options.branch + ' to ' + options.remote); // TODO: show stdout for better reporting
    }

    // Run task
    try {

      checkRequirements();
      assignTokens();

      // Change working directory
      shelljs.cd(options.dir);

      initGit();
      initBranch();
      safeCheckout(); // TODO: this will change when safeChk is redefined

      if (options.commit) {
        gitCommit();
      }

      // if (options.tag) {
      //   gitCommit();
      // }

      if (options.push) {
        gitPush();
      }

      done(true);
    }
    catch (e) {
      grunt.fail.warn(e);
      done(false);
    }
    finally {
      shelljs.cd(gruntDir);
    }
  });
};
<|endoftext|>


<commit_before><commit_msg>adding back the old endpoint for stranded guardians<commit_after><|endoftext|>


<commit_before>
/**
 * This task checks if the version of the badge-api or dashboard is correct according to the expectation.
 */

const path = require('path');

function httpClient() {
  if (url.startsWith('https://')) {
    return require('https').get;
  } else {
    return require('http').get;
  }
}

const [, , type, url, expectedVersion] = process.argv;
console.log(`Validating ${url} for version ${expectedVersion}`);
if (url && expectedVersion && type === 'dashboard' || type === 'badge-api') {
  tryCheckVersion();
} else {
  console.info(`Usage: node ${path.basename(__filename)} [badge-api/dashboard] url version`);
  console.info(`Example: node ${path.basename(__filename)} dashboard https://dashboard.stryker-mutator.io/api/version 1.0.0\``);
  process.exitCode = 1;
}

function tryCheckVersion(attemptsLeft = 20) {
  httpClient()(url, res => {
    checkResponse(res).catch(err => {
      if (attemptsLeft === 0) {
        console.error(err);
        process.exitCode = 1;
      } else {
        console.log(`Failed, ${err} trying ${attemptsLeft} more time(s)`);
        setTimeout(() => tryCheckVersion(attemptsLeft - 1), 10000);
      }
    });
  });
}

async function checkResponse(resp) {
  if (type === 'dashboard') {
    await verifyDashboardVersion(resp);
  } else {
    verifyBadgeApiVersion(resp);
  }
  console.log(`✅  ${expectedVersion} installed at ${url} ^-^`)
}

function verifyBadgeApiVersion(resp) {
  const actual = trimGitShaPostFix(resp.headers['x-badge-api-version']);
  if (actual !== expectedVersion) {
    throw new Error(`Expected ${actual} to equal ${expectedVersion}`);
  }
}

function trimGitShaPostFix(rawVersion){
  return rawVersion.split('+')[0];
}

function verifyDashboardVersion(resp) {
  return new Promise((res, rej) => {
    let data = '';
    resp.on('data', chunk => data += chunk);
    resp.on('end', () => {
      const actual = JSON.parse(data);
      const expected = {
        dashboard: expectedVersion,
        frontend: expectedVersion
      };
      try {
        if (actual.dashboard !== expected.dashboard || actual.frontend !== expected.frontend) {
          throw new Error(`Expected ${JSON.stringify(actual)} to equal ${JSON.stringify(expected)}`);
        }
        res();
      } catch (err) {
        rej(err);
      }
    });
    resp.on('err', err => rej(err));
  })
}<commit_msg>chore(check-version): add more retries to check-version<commit_after>
/**
 * This task checks if the version of the badge-api or dashboard is correct according to the expectation.
 */

const path = require('path');

function httpClient() {
  if (url.startsWith('https://')) {
    return require('https').get;
  } else {
    return require('http').get;
  }
}

const [, , type, url, expectedVersion] = process.argv;
console.log(`Validating ${url} for version ${expectedVersion}`);
if (url && expectedVersion && type === 'dashboard' || type === 'badge-api') {
  tryCheckVersion();
} else {
  console.info(`Usage: node ${path.basename(__filename)} [badge-api/dashboard] url version`);
  console.info(`Example: node ${path.basename(__filename)} dashboard https://dashboard.stryker-mutator.io/api/version 1.0.0\``);
  process.exitCode = 1;
}

function tryCheckVersion(attemptsLeft = 40) {
  httpClient()(url, res => {
    checkResponse(res).catch(err => {
      if (attemptsLeft === 0) {
        console.error(err);
        process.exitCode = 1;
      } else {
        console.log(`Failed, ${err} trying ${attemptsLeft} more time(s)`);
        setTimeout(() => tryCheckVersion(attemptsLeft - 1), 10000);
      }
    });
  });
}

async function checkResponse(resp) {
  if (type === 'dashboard') {
    await verifyDashboardVersion(resp);
  } else {
    verifyBadgeApiVersion(resp);
  }
  console.log(`✅  ${expectedVersion} installed at ${url} ^-^`)
}

function verifyBadgeApiVersion(resp) {
  const actual = trimGitShaPostFix(resp.headers['x-badge-api-version']);
  if (actual !== expectedVersion) {
    throw new Error(`Expected ${actual} to equal ${expectedVersion}`);
  }
}

function trimGitShaPostFix(rawVersion){
  return rawVersion.split('+')[0];
}

function verifyDashboardVersion(resp) {
  return new Promise((res, rej) => {
    let data = '';
    resp.on('data', chunk => data += chunk);
    resp.on('end', () => {
      const actual = JSON.parse(data);
      const expected = {
        dashboard: expectedVersion,
        frontend: expectedVersion
      };
      try {
        if (actual.dashboard !== expected.dashboard || actual.frontend !== expected.frontend) {
          throw new Error(`Expected ${JSON.stringify(actual)} to equal ${JSON.stringify(expected)}`);
        }
        res();
      } catch (err) {
        rej(err);
      }
    });
    resp.on('err', err => rej(err));
  })
}<|endoftext|>


<commit_before>// react-native
import 'react-devtools'; // Put it first!
import React, { Component } from 'react';
// redux
import { Provider } from 'react-redux';
// Container
import AppWithNavigationState from './routes/AppWithNavigationState';
// Store
import store from './store';

export default class App extends Component {
  render() {
    return (
      <Provider store={store}>
        <AppWithNavigationState />
      </Provider>
    );
  }
}
<commit_msg>run prettier<commit_after>// react-native
import "react-devtools"; // Put it first!
import React, { Component } from "react";
// redux
import { Provider } from "react-redux";
// Container
import AppWithNavigationState from "./routes/AppWithNavigationState";
// Store
import store from "./store";

export default class App extends Component {
  render() {
    return (
      <Provider store={store}>
        <AppWithNavigationState />
      </Provider>
    );
  }
}
<|endoftext|>


<commit_before>
import update from 'react-addons-update';
import codeWidget from './components/codeWidget.js';
import { registerWidget, registerReducer, warn, log } from '../../core';

const DOMAIN = 'code';

registerWidget('code', codeWidget);

registerReducer(DOMAIN, (state, action) => {
  switch (action.type) {
    case FLASH_START:
      return update(state, { widgets: { [action.widget.wid]: { flashed: { $set: true } } } });
    case FLASH_END:
      return update(state, { widgets: { [action.widget.wid]: { flashed: { $set: false } } } });
    default:
      warn('Unknown "code" action "', action, '".');
      return state;
  }
});

<commit_msg>just return state for now until we wire up code plugin<commit_after>
import update from 'react-addons-update';
import codeWidget from './components/codeWidget.js';
import { registerWidget, registerReducer, warn, log } from '../../core';

const DOMAIN = 'code';

registerWidget('code', codeWidget);

registerReducer(DOMAIN, (state, action) => {
  return state;
});

<|endoftext|>


<commit_before>const { exec } = require('child_process');
const EventEmitter = require('events');

class Execute extends EventEmitter {
  constructor(options) {
    super();
    let { fullCmd, params } = options;

    this.fullCmd = fullCmd;
    this.params = params;
  }

  run() {
    RunCmd(BuildCmd(this.fullCmd, this.params))
      .then((msg) => {
        this.emit('end', msg);
      })
      .catch((error) => {
        this.emit('error', error)
      });
  }

  static run(fullCmd) {
    return RunCmd(fullCmd);
  }

  static cmd(base, params) {
    return BuildCmd(base, params);
  }
}

module.exports = Execute;

function RunCmd(fullCmd) {
  return new Promise((resolve, reject) => {
    exec(fullCmd, (error, stdout, stderr) => {
      if (stderr || error) {
        reject(stderr || error);
      }
      resolve(stdout);
    });
  });
}

function BuildCmd(base, params) {
  if (!params && base) {
    return base;
  }
  if (params.constructor !== Array) {
    throw new Error('params must be an Array');
  }

  return base + ' ' + params.join(' ');
}
<commit_msg>Move returning promise up to test if it resolves messaging issue<commit_after>const { exec } = require('child_process');
const EventEmitter = require('events');

class Execute extends EventEmitter {
  constructor(options) {
    super();
    let { fullCmd, params } = options;

    this.fullCmd = fullCmd;
    this.params = params;
  }

  run() {
    RunCmd(BuildCmd(this.fullCmd, this.params))
      .then((msg) => {
        this.emit('end', msg);
      })
      .catch((error) => {
        this.emit('error', error)
      });
  }

  static run(fullCmd) {
    return new Promise((resolve, reject) => {
    exec(fullCmd, (error, stdout, stderr) => {
      if (stderr || error) {
        reject(stderr || error);
      }
      resolve(stdout);
    });
  });
  }

  static cmd(base, params) {
    return BuildCmd(base, params);
  }
}

module.exports = Execute;

function RunCmd(fullCmd) {
  return new Promise((resolve, reject) => {
    exec(fullCmd, (error, stdout, stderr) => {
      if (stderr || error) {
        reject(stderr || error);
      }
      resolve(stdout);
    });
  });
}

function BuildCmd(base, params) {
  if (!params && base) {
    return base;
  }
  if (params.constructor !== Array) {
    throw new Error('params must be an Array');
  }

  return base + ' ' + params.join(' ');
}
<|endoftext|>


<commit_before>/*
 * grunt-html-smoosher
 * https://github.com/motherjones/grunt-html-smoosher
 *
 * Copyright (c) 2013 Ben Breedlove
 * Licensed under the MIT license.
 */

module.exports = function(grunt) {

  'use strict';

  var cheerio = require('cheerio');
  var path = require('path');
  var url = require('url');
  var uglify = require('uglifyjs').init(grunt);

  grunt.registerMultiTask('smoosher', 'Turn your distribution into something pastable.', function() {

    var options = this.options({
      jsDir: "",
      cssDir: "",
      minify: false
    });
    var processInput = function(i){return i;};

    if (options.minify){
      processInput = function(input){
        return uglify.minify(input);
      };
    }

    this.files.forEach(function(filePair) {
      // Check that the source file exists
      if(filePair.src.length === 0) { return; }

      var $ = cheerio.load(grunt.file.read(filePair.src));

      grunt.log.writeln('Reading: ' + path.resolve(filePair.src.toString()));

      $('link[rel="stylesheet"]').each(function () {
        var style = $(this).attr('href');
        if(!style) { return; }
        if(style.match(/^\/\//)) { return; }
        if(url.parse(style).protocol) { return; }
        var filePath = (style.substr(0,1) === "/") ? path.resolve(options.cssDir, style.substr(1)) : path.join(path.dirname(filePair.src), style);
        grunt.log.writeln(('Including CSS: ').cyan + filePath);
        $(this).replaceWith('<style>' + processInput(grunt.file.read(filePath)) + '</style>');
      });

      $('script').each(function () {
        var script = $(this).attr('src');
        if(!script) { return; }
        if(script.match(/^\/\//)) { return; }
        if(url.parse(script).protocol) { return; }
        var filePath = (script.substr(0,1) === "/") ? path.resolve(options.jsDir, script.substr(1)) : path.join(path.dirname(filePair.src), script);
        grunt.log.writeln(('Including JS: ').cyan + filePath);
        $(this).replaceWith('<script>' + processInput(grunt.file.read(filePath)) + '</script>');
      });

      grunt.file.write(path.resolve(filePair.dest), $.html());
      grunt.log.writeln(('Created ').green + path.resolve(filePair.dest));
    });

  });

};
<commit_msg>added updated minification option<commit_after>/*
 * grunt-html-smoosher
 * https://github.com/motherjones/grunt-html-smoosher
 *
 * Copyright (c) 2013 Ben Breedlove
 * Licensed under the MIT license.
 */

module.exports = function(grunt) {

  'use strict';

  var cheerio = require('cheerio');
  var path = require('path');
  var url = require('url');
  var uglify = require('uglifyjs').init(grunt);

  grunt.registerMultiTask('smoosher', 'Turn your distribution into something pastable.', function() {

    var options = this.options({
      jsDir: "",
      cssDir: "",
      minify: false
    });
    var processInput = function(i){return i;};

    if (options.minify){
      processInput = function(input){
        return uglify.minify(input, {fromString: true});
      };
    }

    this.files.forEach(function(filePair) {
      // Check that the source file exists
      if(filePair.src.length === 0) { return; }

      var $ = cheerio.load(grunt.file.read(filePair.src));

      grunt.log.writeln('Reading: ' + path.resolve(filePair.src.toString()));

      $('link[rel="stylesheet"]').each(function () {
        var style = $(this).attr('href');
        if(!style) { return; }
        if(style.match(/^\/\//)) { return; }
        if(url.parse(style).protocol) { return; }
        var filePath = (style.substr(0,1) === "/") ? path.resolve(options.cssDir, style.substr(1)) : path.join(path.dirname(filePair.src), style);
        grunt.log.writeln(('Including CSS: ').cyan + filePath);
        $(this).replaceWith('<style>' + processInput(grunt.file.read(filePath)) + '</style>');
      });

      $('script').each(function () {
        var script = $(this).attr('src');
        if(!script) { return; }
        if(script.match(/^\/\//)) { return; }
        if(url.parse(script).protocol) { return; }
        var filePath = (script.substr(0,1) === "/") ? path.resolve(options.jsDir, script.substr(1)) : path.join(path.dirname(filePair.src), script);
        grunt.log.writeln(('Including JS: ').cyan + filePath);
        $(this).replaceWith('<script>' + processInput(grunt.file.read(filePath)) + '</script>');
      });

      grunt.file.write(path.resolve(filePair.dest), $.html());
      grunt.log.writeln(('Created ').green + path.resolve(filePair.dest));
    });

  });

};
<|endoftext|>


<commit_before>'use strict';

const startedAt = new Date();
const logger = require('./logger');
const pkg = require('../package.json');
const settings = require('../config/settings');
const quotes = require('./quotes');

quotes.load({
  type: settings.database.type,
  endpoint: settings.database.endpoint
}).catch(err => {
  logger.error(err);
});

const _ = require('underscore');
const express = require('express');
const api = express.Router();

exports.router = api;

api.get('/', (req, res) => {
  res.json({
    version: pkg.version,
    since: startedAt
  });
});

api.post('/quotes', (req, res) => {
  const quote = req.body;
  const errors = [];

  if (!('nickname' in quote)) {
    errors.push('required: nickname');
  }

  if (!('mask' in quote)) {
    errors.push('required: mask');
  }

  if (!('channel' in quote)) {
    errors.push('required: channel');
  }

  if (!('quote' in quote)) {
    errors.push('required: quote');
  }

  if (!_.isEmpty(errors)) {
    return res.status(422).json({
      errors: errors
    });
  }

  quotes.add(quote).then(id => {
    logger.info('added quote with id ' + id);

    res.status(201).json({
      id: id
    });
  }).catch(() => {
    res.status(500).json({
      message: 'something bad happened'
    });
  });
});

api.get('/quotes/random', (req, res) => {
  const search = req.query;

  if (search.type === "wildcard" && search.query) {
    search.query = "^" + search.query.split("*").join(".*") + "$";
  }

  quotes.get(search.query).then(result => {

    if (_.isEmpty(result)) {
      res.status(404).json({
        message: 'quote not found'
      });
    } else {
      res.json({
        total: result.total,
        quote: result.quote.quote
      });
    }
  }).catch(() => {
    res.status(500).json({
      message: 'something bad happened'
    });
  });
});

api.get('/quotes/:id', (req, res) => {
  quotes.getById(req.params.id).then(result => {
    if (_.isEmpty(result)) {
      res.status(404).json({
        message: 'quote not found'
      });
    } else {
      res.json({
        quote: result.quote.quote
      });
    }

  }).catch(() => {
    res.status(500).json({
      message: 'something bad happened'
    });
  });
});

api.get('/quotes/:id/info', (req, res) => {
  quotes.getById(req.params.id).then(result => {

    if (_.isEmpty(result)) {
      res.status(404).json({
        message: 'quote not found'
      });
    } else {
      const info = {
        nickname: result.quote.nickname,
        timestamp: new Date(result.quote.timestamp * 1000),
        channel: result.quote.channel
      };

      res.json(info);
    }
  }).catch(() => {
    res.status(500).json({
      message: 'something bad happened'
    });
  });
});

api.delete('/quotes/:id', (req, res) => {
  quotes.getById(req.params.id).then(result => {
    if (result === undefined) {
      res.status(404).json({
        message: 'quote not found'
      });
    } else {
      quotes.delete(result.quote).then(result => {
        logger.info('deleted quote with id ' + req.params.id);
        res.json({
          success: true
        });
      });
    }
  }).catch(() => {
    res.status(500).json({
      success: false
    });
  });
});<commit_msg>Returned id with quotes data when getting a random quote<commit_after>'use strict';

const startedAt = new Date();
const logger = require('./logger');
const pkg = require('../package.json');
const settings = require('../config/settings');
const quotes = require('./quotes');

quotes.load({
  type: settings.database.type,
  endpoint: settings.database.endpoint
}).catch(err => {
  logger.error(err);
});

const _ = require('underscore');
const express = require('express');
const api = express.Router();

exports.router = api;

api.get('/', (req, res) => {
  res.json({
    version: pkg.version,
    since: startedAt
  });
});

api.post('/quotes', (req, res) => {
  const quote = req.body;
  const errors = [];

  if (!('nickname' in quote)) {
    errors.push('required: nickname');
  }

  if (!('mask' in quote)) {
    errors.push('required: mask');
  }

  if (!('channel' in quote)) {
    errors.push('required: channel');
  }

  if (!('quote' in quote)) {
    errors.push('required: quote');
  }

  if (!_.isEmpty(errors)) {
    return res.status(422).json({
      errors: errors
    });
  }

  quotes.add(quote).then(id => {
    logger.info('added quote with id ' + id);

    res.status(201).json({
      id: id
    });
  }).catch(() => {
    res.status(500).json({
      message: 'something bad happened'
    });
  });
});

api.get('/quotes/random', (req, res) => {
  const search = req.query;

  if (search.type === "wildcard" && search.query) {
    search.query = "^" + search.query.split("*").join(".*") + "$";
  }

  quotes.get(search.query).then(result => {

    if (_.isEmpty(result)) {
      res.status(404).json({
        message: 'quote not found'
      });
    } else {
      res.json({
        total: result.total,
        quote: result.quote.quote,
        id: result.quote.id
      });
    }
  }).catch(() => {
    res.status(500).json({
      message: 'something bad happened'
    });
  });
});

api.get('/quotes/:id', (req, res) => {
  quotes.getById(req.params.id).then(result => {
    if (_.isEmpty(result)) {
      res.status(404).json({
        message: 'quote not found'
      });
    } else {
      res.json({
        quote: result.quote.quote
      });
    }

  }).catch(() => {
    res.status(500).json({
      message: 'something bad happened'
    });
  });
});

api.get('/quotes/:id/info', (req, res) => {
  quotes.getById(req.params.id).then(result => {

    if (_.isEmpty(result)) {
      res.status(404).json({
        message: 'quote not found'
      });
    } else {
      const info = {
        nickname: result.quote.nickname,
        timestamp: new Date(result.quote.timestamp * 1000),
        channel: result.quote.channel
      };

      res.json(info);
    }
  }).catch(() => {
    res.status(500).json({
      message: 'something bad happened'
    });
  });
});

api.delete('/quotes/:id', (req, res) => {
  quotes.getById(req.params.id).then(result => {
    if (result === undefined) {
      res.status(404).json({
        message: 'quote not found'
      });
    } else {
      quotes.delete(result.quote).then(result => {
        logger.info('deleted quote with id ' + req.params.id);
        res.json({
          success: true
        });
      });
    }
  }).catch(() => {
    res.status(500).json({
      success: false
    });
  });
});<|endoftext|>


<commit_before>
/*
 * jqGrid OData (WebApi v3/v4) support
 *
 * Authors:
 *  Mark Babayev (https://github.com/mirik123)
 *  Richard Bennett (https://gist.github.com/dealproc)
 *
 * License MIT (MIT-LICENSE.txt)
 *
 * based on Richard Bennett gist code: jqGrid.ODataExtensions.js
 * https://gist.github.com/dealproc/6678280
 *
 * the example of using plugin is shown in InitJqGridODataSample
 *
 * TODO: add OData v4 server side part that generates annotations.
 */

"use strict";
function InitJqGridODataSample() {
    var colModelDefinition = GetODataMetadata('http://localhost:59661/odata');

    //odata v3
    SetODataDefaults('grid', "http://localhost:59661/odata/ODClient", colModelDefinition, {
        annotations: false,
        inlinecount: true,
        count: false,
        top: false
    });

    //odata v4
    SetODataDefaults('grid', "http://localhost:59661/odata/ODClient", colModelDefinition, {
        annotations: true,
        inlinecount: false,
        count: true,
        top: true
    });

    $("#grid").jqGrid({
        height: '100%',
        pager: $('#gridpager'),
        sortname: 'id',
        viewrecords: true,
        sortorder: "asc",
        deepempty: true,
        altRows: true,
        footerrow: false,
        shrinkToFit: true,
        ignoreCase: true,
        gridview: true,
        headertitles: true,
        sortable: true,
        autowidth: true,
        toppager: true,
        toolbar: [true, 'top'],
        ondblClickRow: function (id) {
            $('#grid').jqGrid('editRow', id, {
                beforeEditRow: function (options, rowid) {
                    return true;
                }
            });
            $("#grid_ilsave").removeClass('ui-state-disabled');
        },
        multiSort: true,
        colModel: colModelDefinition
    })
    .jqGrid("navGrid", "#pg_grid_toppager", { add: true, del: true, edit: true, view: true, reload: true, search: false, cloneToTop: true },
        {
            //edit
            closeAfterEdit: true
        },
        {   //add
            closeAfterAdd: true
        })
    .jqGrid('inlineNav', "#pg_grid_toppager", { add: true, edit: false, save: true, cancel: false,
        editParams: {
            keys: true
        }
    })
    .jqGrid('filterToolbar', { searchOnEnter: false, enableClear: false, stringResult: true })
    .jqGrid('searchGrid', { multipleSearch: true, multipleGroup: false, overlay: 0 });
};

function GetODataMetadata(url) {
    var colModel = [];

    $.ajax({
        url: url+'/$metadata',
        type: 'GET',
        dataType: 'xml',
        async: false
    })
    .done(function (data, st, xhr) {

        //var xmldata = $.parseXML(xhr.responseText);
        var props = $('EntityType[Name!="Default"] Property', data);
        props.each(function (n, itm) {
            var name = $(itm).attr('Name');
            var type = $(itm).attr('Type').replace('Edm.', '');
            var isNullable = $(itm).attr('Nullable');
            colModel.push({ label: name, name: name, index: name, editable: true });
        });
    })
    .fail(function (jqXHR, st, err) {
        var title = err, message = jqXHR.responseText;

        if (jqXHR.responseJSON) {
            if (jqXHR.responseJSON.InnerException) {
                title = jqXHR.responseJSON.InnerException.ExceptionMessage;
                message = jqXHR.responseJSON.InnerException.StackTrace;
            }
            else {
                title = jqXHR.responseJSON.ExceptionMessage;
                message = jqXHR.responseJSON.StackTrace;
            }
        }

        $.jgrid.info_dialog($.jgrid.errors.errcap, "
Message: " + title + '

' + message + '
', $.jgrid.edit.bClose);
    });

    return colModel;
}

function SetODataDefaults(gID, url, colModel, options) {
    options = $.extend(true, {
        pageSize: 25,
        annotations: false,
        annotationName: "@jqgrid.GridModelAnnotate",
        inlinecount: true,
        count: false,
        top: false
    }, options);

    $.extend(true, $.jgrid.inlineEdit, {
        beforeSaveRow: function (options, rowid, frmoper) {
            if (options.extraparam.oper == 'edit') {
                options.url = url;
                options.mtype = "PATCH";
                options.url += '(' + rowid + ')';
            }
            else {
                options.url = url;
                options.mtype = "PUT";
            }

            return true;
        },
        serializeSaveData: function (postdata) {
            return JSON.stringify(postdata);
        }
    });

    $.extend(true, $.jgrid.edit, {
        onclickSubmit: function (options, postdata, frmoper) {
            if (frmoper == 'add') {
                options.url = url;
                options.mtype = "POST";
            }
            else if (frmoper == 'edit') {
                options.url = url + '(' + postdata[gID + "_id"] + ')';
                options.mtype = "PUT";
            }

            return postdata;
        },
        ajaxEditOptions: {
            contentType: 'application/json;charset=utf-8',
            datatype: 'json'
        },
        serializeEditData: function (postdata) {
            return JSON.stringify(postdata);
        }
    });

    $.extend(true, $.jgrid.del, {
        url: url,
        mtype: "DELETE",
        serializeDelData: function (postdata) {
            return "";
        },
        onclickSubmit: function (options, postdata) {
            options.url += '(' + postdata + ')';
            return '';
        },
        ajaxDelOptions: {
            contentType: 'application/json;charset=utf-8',
            datatype: 'json'
        }
    });

    $.extend(true, $.jgrid.defaults, {
        rowNum: options.pageSize,
        datatype: "json",
        url: url,
        colModel: colModel,
        mtype: 'GET',
        ajaxGridOptions: {
            contentType: "application/json;charset=utf-8",
            datatype: 'json'
        },
        loadBeforeSend: function(jqXHR) {
            jqXHR.setRequestHeader("Prefer", 'odata.include-annotations="*"');
        },
        serializeGridData: function (postData) {
            postData = setupWebServiceData(postData, colModel, options);
            return postData;
        },
        ajaxRowOptions: {
            contentType: "application/json;charset=utf-8",
            dataType: "json"
        },
        serializeRowData: function (postData) {
            return JSON.stringify(postData);
        },
        jsonReader: {
            root: "value",
            repeatitems: false,
            records: "odata.count",
            page: function (data) {
                if (data["odata.nextLink"] != undefined) {
                    var skip = data["odata.nextLink"].split('skip=')[1];
                    return Math.ceil(parseInt(skip) / pageSize);
                }
                else {
                    var total = data["odata.count"];
                    return Math.ceil(parseInt(total) / pageSize);
                }
            },
            total: function (data) {
                var total = data["odata.count"];
                return Math.ceil(parseInt(total) / pageSize);
            },
            userdata: "userdata"
        }
    });

    if (options.annotations) {
        $.extend(true, $.jgrid.defaults, {
            loadBeforeSend: function (jqXHR) {
                jqXHR.setRequestHeader("Prefer", 'odata.include-annotations="*"');
            },
            jsonReader: {
                root: "value",
                repeatitems: false,
                records: [options.annotationName, 'records'],
                page: [options.annotationName, 'page'],
                total: [options.annotationName, 'total'],
                userdata: [options.annotationName, 'userdata']
            }
        });
    }
}

function setupWebServiceData(postData, cols, options) {
    // basic posting parameters to the OData service.
    var params = {
        //$top: postData.rows, //- we cannot use $top because of it removes odata.nextLink parameter
        $skip: (parseInt(postData.page, options.pageSize) - 1) * options.pageSize,
        //$inlinecount: "allpages" //- not relevant for V4
    };

    if (options.count)
        params.$count = true;

    if (options.top)
        params.$top = postData.rows;

    if (options.inlinecount)
        params.$inlinecount = "allpages";

    // if we have an order-by clause to use, then we build it.
    if (postData.sidx) {
        // two columns have the following data:
        // postData.sidx = "{ColumnName} {order}, {ColumnName} "
        // postData.sord = "{order}"
        // we need to split sidx by the ", " and see if there are multiple columns.  If there are, we need to go through
        // each column and get its parts, then parse that for the appropriate columns to build for the sort.

        params.$orderby = postData.sidx + " " + postData.sord;
    }

    if (!postData._search)
        return params;

    // if we want to support "in" clauses, we need to follow this stackoverflow article:
    //http://stackoverflow.com/questions/7745231/odata-where-id-in-list-query/7745321#7745321
    // this is for basic searching, with a single term.
    if (postData.searchField && (postData.searchString != null || postData.searchOper == 'nu' || postData.searchOper == 'nn')) {
        //append '' when searched field is of the string type
        var col = GetGridColumn(cols, postData.searchField);
        if (col != null) {
            if (col.stype == 'select' && rule.data == '-1')
                return params;
            if (col.stype == 'select')
                postData.searchField = postData.searchField + '/Id';
            else if (col.searchrules == undefined || col.searchrules.integer != true)
                postData.searchString = "'" + postData.searchString + "'";
            else if (rule.searchString == '')
                return params;
        }

        params.$filter = ODataExpression(postData.searchOper, postData.searchField, postData.searchString);
    }

    // complex searching, with a groupOp.  This is for if we enable the form for multiple selection criteria.
    if (postData.filters) {
        var filterGroup = $.parseJSON(postData.filters);
        var groupSearch = parseFilterGroup(filterGroup, cols);

        if (groupSearch.length > 0)
            params.$filter = groupSearch;
    }

    return params;
}

function GetGridColumn(cols, field) {
    var col = $.grep(cols, function (n, i) { return n.name == field; });
    if (col.length == 0)
        return null;
    else
        return col[0];
}

// builds out OData expressions... the condition.
function ODataExpression(op, field, data) {
    switch (op) {
        case "cn":
            return "substringof(" + data + ", " + field + ") eq true";
        case "nc": // does not contain.
            return "substringof(" + data + ", " + field + ") eq false";
        case "bw":
            return "startswith(" + field + ", " + data + ") eq true";
        case "bn": // does not begin with
            return "startswith(" + field + ", " + data + ") eq false";
        case "ew":
            return "endswith(" + field + ", " + data + ") eq true";
        case "en": // does not end with.
            return "endswith(" + field + ", " + data + ") eq false";
        case "nu":
            return field + " eq null";
        case "nn":
            return field + " ne null";
        default:
            return field + " " + op + " " + data;
    }
};

// when dealing with the advanced query dialog, this parses the encapsulating Json object
// which we will then build the advanced OData expression from.
function parseFilterGroup(filterGroup, cols) {
    var filterText = "";
    if (filterGroup.groups) {
        if (filterGroup.groups.length) {
            for (var i = 0; i < filterGroup.groups.length; i++) {
                filterText += "(" + parseFilterGroup(filterGroup.groups[i]) + ")";

                if (i < filterGroup.groups.length - 1) {
                    filterText += " " + filterGroup.groupOp.toLowerCase() + " ";
                }
            }

            if (filterGroup.rules && filterGroup.rules.length) {
                filterText += " " + filterGroup.groupOp.toLowerCase() + " ";
            }
        }
    }

    if (filterGroup.rules.length) {
        for (var i = 0; i < filterGroup.rules.length; i++) {
            var rule = filterGroup.rules[i];

            if (rule.data == null && rule.op != 'nu' && rule.op != 'nn')
                continue;

            var col = GetGridColumn(cols, rule.field);
            if (col != null) {
                if (col.stype == 'select' && rule.data == '-1')
                    continue;
                if (col.stype == 'select')
                    rule.field = rule.field + '/Id';
                else if (col.searchrules == undefined || col.searchrules.integer != true)
                    rule.data = "'" + rule.data + "'";
                else if (rule.data == '')
                    continue;
            }
            filterText += ODataExpression(rule.op, rule.field, rule.data) + " " + filterGroup.groupOp.toLowerCase() + " ";
        }
    }

    filterText = filterText.trim().replace(/.(and|or)$/, '').trim();

    return filterText;
}
<commit_msg>Update grid.odata.js<commit_after>
(function($){
/*
 * jqGrid OData (WebApi v3/v4) support
 *
 * Authors:
 *  Mark Babayev (https://github.com/mirik123)
 *  Richard Bennett (https://gist.github.com/dealproc)
 *
 * License MIT (MIT-LICENSE.txt)
 *
 * based on Richard Bennett gist code: jqGrid.ODataExtensions.js
 * https://gist.github.com/dealproc/6678280
 *
 * the example of using plugin is shown in InitJqGridODataSample
 *
 * TODO: add OData v4 server side part that generates annotations.
 */

 "use strict";
$.jgrid.extend({
	setColModelMetadata: function (savecolfunc, successfunc, errorfunc) {
		var $t = this;
		if (!$t.grid ) { return; }

		$.ajax({
			url: $t.url+'/$metadata',
			type: 'GET',
			dataType: 'xml'
		})
		.done(function (data, st, xhr) {
			//var xmldata = $.parseXML(xhr.responseText);
			var props = $('EntityType[Name!="Default"] Property', data);
			if (props.length > 0) {
				$t.colModel = [];
				props.each(function (n, itm) {
					var name = $(itm).attr('Name');
					var type = $(itm).attr('Type').replace('Edm.', '');
					var nullable = $(itm).attr('Nullable');

					var origcol = { label: name, name: name, index: name, editable: true };
					var newcol = $self.triggerHandler("jqGridODataSaveColumnModel", origcol);
					if (newcol === undefined && $.isFunction(savecolfunc)) { newcol = savecolfunc(origcol); }
					if (newcol !== undefined) {
						$t.colModel.push(newcol);
					}
				});

				if($.isFunction(successfunc)) { successfunc(data, st, xhr); }
			}
			else
			{
				if($.isFunction(errorfunc)) { errorfunc(data, st, xhr); }
			}
		})
		.fail(function (jqXHR, st, err) {
			if($.isFunction(errorfunc)) { errorfunc(jqXHR, st, err); }
		});
	}

	initODataDefaults: function (p) {
		return this.each(function(){
			var $t = this;
			if (!$t.grid ) { return; }

			p = $.extend(true, {
				pageSize: $t.rowNum,
				annotations: false,
				annotationName: "@jqgrid.GridModelAnnotate",
				inlinecount: true,
				count: false,
				top: false
			}, p || {});

			$t.inlineEditing({
				beforeSaveRow: function (options, rowid, frmoper) {
					if (options.extraparam.oper === 'edit') {
						options.url = $t.url;
						options.mtype = "PATCH";
						options.url += '(' + rowid + ')';
					}
					else {
						options.url = $t.url;
						options.mtype = "PUT";
					}

					return true;
				},
				serializeSaveData: function (postdata) {
					return JSON.stringify(postdata);
				}
			});

			$t.formEditing({
				onclickSubmit: function (options, postdata, frmoper) {
					if (frmoper === 'add') {
						options.url = $t.url;
						options.mtype = "POST";
					}
					else if (frmoper === 'edit') {
						options.url = $t.url + '(' + postdata[$t.gID + "_id"] + ')';
						options.mtype = "PUT";
					}

					return postdata;
				},
				ajaxEditOptions: {
					contentType: 'application/json;charset=utf-8',
					datatype: 'json'
				},
				serializeEditData: function (postdata) {
					return JSON.stringify(postdata);
				}
			});

			$t.formDeleting({
				url: $t.url,
				mtype: "DELETE",
				serializeDelData: function (postdata) {
					return "";
				},
				onclickSubmit: function (options, postdata) {
					options.url += '(' + postdata + ')';
					return '';
				},
				ajaxDelOptions: {
					contentType: 'application/json;charset=utf-8',
					datatype: 'json'
				}
			});

			$t.p.serializeGridData = function (postData) {
					postData = setupWebServiceData(postData);
					return postData;
				};

			$t.p.ajaxGridOptions = {
					contentType: "application/json;charset=utf-8",
					datatype: 'json'
				};

			$.extend(true, $.jgrid.defaults, {
				datatype: "json",
				mtype: 'GET',
				rowNum: p.pageSize,
				jsonReader: {
					root: "value",
					repeatitems: false,
					records: "odata.count",
					page: function (data) {
						if (data["odata.nextLink"] !== undefined) {
							var skip = data["odata.nextLink"].split('skip=')[1];
							return Math.ceil(parseInt(skip, 0) / $t.rowNum);
						}
						else {
							var total = data["odata.count"];
							return Math.ceil(parseInt(total, 0) / $t.rowNum);
						}
					},
					total: function (data) {
						var total = data["odata.count"];
						return Math.ceil(parseInt(total, 0) / $t.rowNum);
					},
					userdata: "userdata"
				}
			});

			if (p.annotations) {
				$.extend(true, $.jgrid.defaults, {
					loadBeforeSend: function (jqXHR) {
						jqXHR.setRequestHeader("Prefer", 'odata.include-annotations="*"');
					},
					jsonReader: {
						root: "value",
						repeatitems: false,
						records: function(data) { return data[p.annotationName].records; },
						page: function(data) { return data[p.annotationName].page; },
						total: function(data) { return data[p.annotationName].total; },
						userdata: function(data) { return data[p.annotationName].userdata; }
					}
				});
			}
		});
	}

	setupWebServiceData: function (postData) {
		// basic posting parameters to the OData service.
		var params = {
			//$top: postData.rows, //- we cannot use $top because of it removes odata.nextLink parameter
			$skip: (parseInt(postData.page, $t.rowNum) - 1) * $t.rowNum,
			//$inlinecount: "allpages" //- not relevant for V4
		};

		if (p.count) {params.$count = true;}
		if (p.top) {params.$top = postData.rows;}
		if (p.inlinecount) {params.$inlinecount = "allpages";}

		// if we have an order-by clause to use, then we build it.
		if (postData.sidx) {
			// two columns have the following data:
			// postData.sidx = "{ColumnName} {order}, {ColumnName} "
			// postData.sord = "{order}"
			// we need to split sidx by the ", " and see if there are multiple columns.  If there are, we need to go through
			// each column and get its parts, then parse that for the appropriate columns to build for the sort.

			params.$orderby = postData.sidx + " " + postData.sord;
		}

		if (!postData._search) {return params;}

		// if we want to support "in" clauses, we need to follow this stackoverflow article:
		//http://stackoverflow.com/questions/7745231/odata-where-id-in-list-query/7745321#7745321
		// this is for basic searching, with a single term.
		if (postData.searchField && (postData.searchString !== null || postData.searchOper === 'nu' || postData.searchOper === 'nn')) {
			//append '' when searched field is of the string type
			//var col = getGridColumn(postData.searchField);
			var col = $.grep($t.colModel, function (n, i) { return n.name === postData.searchField; });
			if (col !== null && col.length > 0) {
				col = col[0];
				if (col.stype === 'select' && rule.data.length === 0){
					return params;
				}
				if (col.stype === 'select') {
					postData.searchField = postData.searchField + '/' + $t.jsonReader.id;
				}
				else if (col.searchrules === undefined || col.searchrules.integer !== true) {
					postData.searchString = "'" + postData.searchString + "'";
				}
				else if (rule.searchString === '') {
					return params;
				}
			}

			params.$filter = odataExpression(postData.searchOper, postData.searchField, postData.searchString);
		}

		// complex searching, with a groupOp.  This is for if we enable the form for multiple selection criteria.
		if (postData.filters) {
			var filterGroup = $.parseJSON(postData.filters);
			var groupSearch = parseFilterGroup(filterGroup);

			if (groupSearch.length > 0) {
				params.$filter = groupSearch;
			}
		}

		return params;
	}

	// builds out OData expressions... the condition.
	odataExpression: function (op, field, data) {
		switch (op) {
			case "cn":
				return "substringof(" + data + ", " + field + ") eq true";
			case "nc": // does not contain.
				return "substringof(" + data + ", " + field + ") eq false";
			case "bw":
				return "startswith(" + field + ", " + data + ") eq true";
			case "bn": // does not begin with
				return "startswith(" + field + ", " + data + ") eq false";
			case "ew":
				return "endswith(" + field + ", " + data + ") eq true";
			case "en": // does not end with.
				return "endswith(" + field + ", " + data + ") eq false";
			case "nu":
				return field + " eq null";
			case "nn":
				return field + " ne null";
			default:
				return field + " " + op + " " + data;
		}
	}

	// when dealing with the advanced query dialog, this parses the encapsulating Json object
	// which we will then build the advanced OData expression from.
	parseFilterGroup: function (filterGroup) {
		var filterText = "";
		if (filterGroup.groups) {
			if (filterGroup.groups.length) {
				for (var i = 0; i < filterGroup.groups.length; i++) {
					filterText += "(" + parseFilterGroup(filterGroup.groups[i]) + ")";

					if (i < filterGroup.groups.length - 1) {
						filterText += " " + filterGroup.groupOp.toLowerCase() + " ";
					}
				}

				if (filterGroup.rules && filterGroup.rules.length) {
					filterText += " " + filterGroup.groupOp.toLowerCase() + " ";
				}
			}
		}

		if (filterGroup.rules.length) {
			for (var i = 0; i < filterGroup.rules.length; i++) {
				var rule = filterGroup.rules[i];

				if (rule.data === null && rule.op !== 'nu' && rule.op !== 'nn') {
					continue;
				}

				var col = $.grep($t.colModel, function (n, i) { return n.name === rule.field; });
				if (col !== null && col.length > 0) {
					col = col[0];
					if (col.stype === 'select' && rule.data.length === 0) {
						continue;
					}
					if (col.stype === 'select') {
						rule.field = rule.field + '/' + $t.jsonReader.id;
					}
					else if (col.searchrules === undefined || col.searchrules.integer !== true) {
						rule.data = "'" + rule.data + "'";
					}
					else if (rule.data === '') {
						continue;
					}
				}
				filterText += odataExpression(rule.op, rule.field, rule.data) + " " + filterGroup.groupOp.toLowerCase() + " ";
			}
		}

		filterText = filterText.trim().replace(/.(and|or)$/, '').trim();

		return filterText;
	}
}(jQuery));
<|endoftext|>