<commit_before>/* jslint browser:true */

define([
	'squire',
	'jquery',
	'backbone'
], function(Squire, $, Backbone, BaseView) {
	"use strict";

	describe('SearchFilterRowView', function() {
		var SearchFilterRowView, testView, testModel;
		var fetchPubTypeSpy, fetchPubTypeDeferred;

		beforeEach(function (done) {
			var injector = new Squire();

			$('body').append('

');
			testModel = new Backbone.Model();

			fetchPubTypeDeferred = $.Deferred();
			fetchPubTypeSpy = jasmine.createSpy('fetchPubTypeSpy').and.returnValue(fetchPubTypeDeferred);

			injector.mock('models/PublicationTypeCollection', Backbone.Collection.extend({
				fetch: fetchPubTypeSpy
			}));
			spyOn($.fn, 'select2');
			injector.mock('jquery', $); // Needed to spy on select2 initialization.

			injector.require(['views/SearchFilterRowView'], function (view) {
				SearchFilterRowView = view;
				testView = new SearchFilterRowView({
					el: '#test-div',
					model: testModel
				});
				done();
			});

		});

		afterEach(function () {
			$('#test-div').remove();
		});

		it('Expect the publication type collection to be fetched at initialization', function () {
			expect(fetchPubTypeSpy).toHaveBeenCalled();
		});

		describe('Tests for render', function () {
			it('Expects that if the model has some filter categories set, those category options will be disabled', function () {
				testModel.set({
					prodId: '1234',
					subtypeName: 'Subtype 1'
				});
				testView.render();
				expect(testView.$('.search-category-input option[value="prodId"]').is(':disabled')).toBe(true);
				expect(testView.$('.search-category-input option[value="indexId"]').is(':disabled')).toBe(false);
				expect(testView.$('.search-category-input option[value="ipdsId"]').is(':disabled')).toBe(false);
				expect(testView.$('.search-category-input option[value="contributor"]').is(':disabled')).toBe(false);
				expect(testView.$('.search-category-input option[value="title"]').is(':disabled')).toBe(false);
				expect(testView.$('.search-category-input option[value="typeName"]').is(':disabled')).toBe(false);
				expect(testView.$('.search-category-input option[value="subtypeName"]').is(':disabled')).toBe(true);
				expect(testView.$('.search-category-input option[value="seriesName"]').is(':disabled')).toBe(false);
				expect(testView.$('.search-category-input option[value="year"]').is(':disabled')).toBe(false);
			});
		});

		describe('Tests for remove', function () {
			it('Expects that if the category has been set for the row that the correpsonding model property is cleared', function () {
				testView.render();
				testView.$('.search-category-input').val('prodId').trigger('change');
				testView.$('.value-text-input').val('1234').trigger('change');
				expect(testModel.get('prodId')).toEqual('1234');

				testView.remove();

				expect(testModel.has('prodId')).toBe(false);
			});
		});

		describe('Tests for model event handlers', function () {
			beforeEach(function () {
				testView.render();
			});

			it('Expects that if a filter model attribute is set, then that option is disabled', function () {
				var $prodIdOption = testView.$('.search-category-input option[value="prodId"]');
				expect($prodIdOption.is(':disabled')).toBe(false);
				testModel.set('prodId', '', {changedAttribute : 'prodId'});
				expect($prodIdOption.is(':disabled')).toBe(true);
			});

			it('Expects that if a filter model attribute is unset, then that option becomes enabled', function() {
				var $prodIdOption = testView.$('.search-category-input option[value="prodId"]');
				testModel.set('prodId', '', {changedAttribute : 'prodId'});
				expect($prodIdOption.is(':disabled')).toBe(true);
				testModel.unset('prodId', {changedAttribute : 'prodId'});
				expect($prodIdOption.is(':disabled')).toBe(false);
			});
		});

		describe('Tests for DOM event handlers', function() {
			beforeEach(function() {
				testView
				testView.render();
			});

			it('Expects that if the category select option is set, the model property is set and the previous value is unset', function() {
				var $categorySelect = testView.$('.search-category-input');
				$categorySelect.val('prodId').trigger('change');
				expect(testModel.has('prodId')).toBe(true);

				$categorySelect.val('subtypeName').trigger('change');
				expect(testModel.has('prodId')).toBe(false);
				expect(testModel.has('subtypeName')).toBe(true);

				$categorySelect.val('').trigger('change');
				expect(testModel.has('subtypeName')).toBe(false);
			});

			it('Expects that if the category select option is set, the appropriate input element is shown and initialized and that both inputs are cleared', function() {
				var $categorySelect = testView.$('.search-category-input');
				var $textInput = testView.$('.value-text-input');
				var $selectInput = testView.$('.value-select-input');
				var select2Count = $.fn.select2.calls.count();

				$categorySelect.val('prodId').trigger('change');
				expect($textInput.is(':visible')).toBe(true);
				expect($selectInput.is(':visible')).toBe(false);
				expect($.fn.select2.calls.count()).toEqual(select2Count);

				$textInput.val('1234');
				$categorySelect.val('subtypeName').trigger('change');
				expect($textInput.is(':visible')).toBe(false);
				expect($textInput.val()).toBe('');
				expect($selectInput.is(':visible')).toBe(true);
				expect($.fn.select2.calls.count()).toEqual(select2Count + 2); // calls destroy and then initialize

				$selectInput.val('Subtype 1');
				$categorySelect.val('year').trigger('change');
				expect($textInput.is(':visible')).toBe(true);
				expect($selectInput.is(':visible')).toBe(false);
				expect($selectInput.val()).toBe(null);
				expect($.fn.select2.calls.count()).toEqual(select2Count + 2);
			});

			it('Expects that if the category is changed to typeName the select2 will not be initialized until after the publication type collection is fetched', function() {
				var $categorySelect = testView.$('.search-category-input');
				var select2Count;

				$categorySelect.val('typeName').trigger('change');
				select2Count = $.fn.select2.calls.count();

				fetchPubTypeDeferred.resolve();
				expect($.fn.select2.calls.count()).toEqual(select2Count + 1);
			});

			// This test does not work in phantomjs but does in the browser
			xit('Expect that if the text or selected value changes the selected category value is updated in the model', function() {
				var $categorySelect = testView.$('.search-category-input');
				var $textInput = testView.$('.value-text-input');
				var $selectInput = testView.$('.value-select-input');

				$categorySelect.val('prodId').trigger('change');
				$textInput.val('1234').trigger('change');
				expect(testModel.get('prodId')).toEqual('1234');

				$textInput.val('4567').trigger('change');
				expect(testModel.get('prodId')).toEqual('4567');

				$categorySelect.val('subtypeName').trigger('select2:select');
				// Have to add the options to the DOM
				$selectInput.append('<option id="1">Subtype 1</option><option id="2">Subtype 2</option>');
				$selectInput.val('Subtype 1').trigger('change');
				expect(testModel.get('subtypeName')).toEqual(['Subtype 1']);
				$selectInput.val(['Subtype 1', 'Subtype 2']).trigger('change');
				expect(testModel.get('subtypeName')).toEqual(['Subtype 1', 'Subtype 2']);
			});
		});
	});
});
<commit_msg>Increasing the timeouts and disabling a test that doesn't work in phantomjs<commit_after>/* jslint browser:true */

define([
	'squire',
	'jquery',
	'backbone'
], function(Squire, $, Backbone, BaseView) {
	"use strict";

	describe('SearchFilterRowView', function() {
		var SearchFilterRowView, testView, testModel;
		var fetchPubTypeSpy, fetchPubTypeDeferred;

		beforeEach(function (done) {
			var injector = new Squire();

			$('body').append('

');
			testModel = new Backbone.Model();

			fetchPubTypeDeferred = $.Deferred();
			fetchPubTypeSpy = jasmine.createSpy('fetchPubTypeSpy').and.returnValue(fetchPubTypeDeferred);

			injector.mock('models/PublicationTypeCollection', Backbone.Collection.extend({
				fetch: fetchPubTypeSpy
			}));
			spyOn($.fn, 'select2');
			injector.mock('jquery', $); // Needed to spy on select2 initialization.

			injector.require(['views/SearchFilterRowView'], function (view) {
				SearchFilterRowView = view;
				testView = new SearchFilterRowView({
					el: '#test-div',
					model: testModel
				});
				done();
			});

		});

		afterEach(function () {
			$('#test-div').remove();
		});

		it('Expect the publication type collection to be fetched at initialization', function () {
			expect(fetchPubTypeSpy).toHaveBeenCalled();
		});

		describe('Tests for render', function () {
			it('Expects that if the model has some filter categories set, those category options will be disabled', function () {
				testModel.set({
					prodId: '1234',
					subtypeName: 'Subtype 1'
				});
				testView.render();
				expect(testView.$('.search-category-input option[value="prodId"]').is(':disabled')).toBe(true);
				expect(testView.$('.search-category-input option[value="indexId"]').is(':disabled')).toBe(false);
				expect(testView.$('.search-category-input option[value="ipdsId"]').is(':disabled')).toBe(false);
				expect(testView.$('.search-category-input option[value="contributor"]').is(':disabled')).toBe(false);
				expect(testView.$('.search-category-input option[value="title"]').is(':disabled')).toBe(false);
				expect(testView.$('.search-category-input option[value="typeName"]').is(':disabled')).toBe(false);
				expect(testView.$('.search-category-input option[value="subtypeName"]').is(':disabled')).toBe(true);
				expect(testView.$('.search-category-input option[value="seriesName"]').is(':disabled')).toBe(false);
				expect(testView.$('.search-category-input option[value="year"]').is(':disabled')).toBe(false);
			});
		});

		describe('Tests for remove', function () {
			it('Expects that if the category has been set for the row that the correpsonding model property is cleared', function () {
				testView.render();
				testView.$('.search-category-input').val('prodId').trigger('change');
				testView.$('.value-text-input').val('1234').trigger('change');
				expect(testModel.get('prodId')).toEqual('1234');

				testView.remove();

				expect(testModel.has('prodId')).toBe(false);
			});
		});

		describe('Tests for model event handlers', function () {
			beforeEach(function () {
				testView.render();
			});

			it('Expects that if a filter model attribute is set, then that option is disabled', function () {
				var $prodIdOption = testView.$('.search-category-input option[value="prodId"]');
				expect($prodIdOption.is(':disabled')).toBe(false);
				testModel.set('prodId', '', {changedAttribute : 'prodId'});
				expect($prodIdOption.is(':disabled')).toBe(true);
			});

			it('Expects that if a filter model attribute is unset, then that option becomes enabled', function() {
				var $prodIdOption = testView.$('.search-category-input option[value="prodId"]');
				testModel.set('prodId', '', {changedAttribute : 'prodId'});
				expect($prodIdOption.is(':disabled')).toBe(true);
				testModel.unset('prodId', {changedAttribute : 'prodId'});
				expect($prodIdOption.is(':disabled')).toBe(false);
			});
		});

		describe('Tests for DOM event handlers', function() {
			beforeEach(function() {
				testView
				testView.render();
			});

			it('Expects that if the category select option is set, the model property is set and the previous value is unset', function() {
				var $categorySelect = testView.$('.search-category-input');
				$categorySelect.val('prodId').trigger('change');
				expect(testModel.has('prodId')).toBe(true);

				$categorySelect.val('subtypeName').trigger('change');
				expect(testModel.has('prodId')).toBe(false);
				expect(testModel.has('subtypeName')).toBe(true);

				$categorySelect.val('').trigger('change');
				expect(testModel.has('subtypeName')).toBe(false);
			});

			it('Expects that if the category select option is set, the appropriate input element is shown and initialized and that both inputs are cleared', function() {
				var $categorySelect = testView.$('.search-category-input');
				var $textInput = testView.$('.value-text-input');
				var $selectInput = testView.$('.value-select-input');
				var select2Count = $.fn.select2.calls.count();

				$categorySelect.val('prodId').trigger('change');
				expect($textInput.is(':visible')).toBe(true);
				expect($selectInput.is(':visible')).toBe(false);
				expect($.fn.select2.calls.count()).toEqual(select2Count);

				$textInput.val('1234');
				$categorySelect.val('subtypeName').trigger('change');
				expect($textInput.is(':visible')).toBe(false);
				expect($textInput.val()).toBe('');
				expect($selectInput.is(':visible')).toBe(true);
				expect($.fn.select2.calls.count()).toEqual(select2Count + 2); // calls destroy and then initialize

				$selectInput.val('Subtype 1');
				$categorySelect.val('year').trigger('change');
				expect($textInput.is(':visible')).toBe(true);
				expect($selectInput.is(':visible')).toBe(false);
				expect($selectInput.val()).toBe(null);
				expect($.fn.select2.calls.count()).toEqual(select2Count + 2);
			});

			it('Expects that if the category is changed to typeName the select2 will not be initialized until after the publication type collection is fetched', function() {
				var $categorySelect = testView.$('.search-category-input');
				var select2Count;

				$categorySelect.val('typeName').trigger('change');
				select2Count = $.fn.select2.calls.count();

				fetchPubTypeDeferred.resolve();
				expect($.fn.select2.calls.count()).toEqual(select2Count + 1);
			});

			// This test does not work in phantomjs but does in the browser
			xit('Expect that if the text or selected value changes the selected category value is updated in the model', function() {
				var $categorySelect = testView.$('.search-category-input');
				var $textInput = testView.$('.value-text-input');
				var $selectInput = testView.$('.value-select-input');

				$categorySelect.val('prodId').trigger('change');
				$textInput.val('1234').trigger('change');
				expect(testModel.get('prodId')).toEqual('1234');

				$textInput.val('4567').trigger('change');
				expect(testModel.get('prodId')).toEqual('4567');

				$categorySelect.val('subtypeName').trigger('change');
				// Have to add the options to the DOM
				$selectInput.append('<option id="1">Subtype 1</option><option id="2">Subtype 2</option>');
				$selectInput.val('Subtype 1').trigger('change');
				expect(testModel.get('subtypeName')).toEqual(['Subtype 1']);
				$selectInput.val(['Subtype 1', 'Subtype 2']).trigger('change');
				expect(testModel.get('subtypeName')).toEqual(['Subtype 1', 'Subtype 2']);
			});
		});
	});
});
<|endoftext|>


<commit_before>"use strict";

var domready = require('matterhorn-standard/js/domready')

var syncApi = require('./sync_api')
var update = require('./minnow_update_websocket')

var listenForMinnow;

(function(){

var api;
var root;

var listeners = [];
global.listenForMinnow = function(listener){
	if(api === undefined){
		listeners.push(listener);
	}else{
		listener(api);
	}
}

exports.listen = global.listenForMinnow

var schema;

var snapsRemaining = [].concat(snapshotIds);

for(var i=0;i<snapshotIds.length;++i){
	var id = snapshotIds[i];
	console.log('snap id: ' + id);
}

var snaps = [];
global.gotSnapshot = function(snap){
	var index;
	for(var i=0;i<snapsRemaining.length;++i){
		if(snapsRemaining[i] === snap.id){
			index = i;
			break;
		}
	}
	if(index === undefined) throw "error, invalid snap id or already received: " + snap.id;

	snapsRemaining.splice(i, 1);

	snaps.push(snap);

	console.log('received snap: ' + snap.id);

	tryLoad();
}

global.gotSchema = function(s){

	schema = s;

	tryLoad();
}

function tryLoad(){
	if(snapsRemaining.length === 0 && schema !== undefined){
		loadMinnowView();
	}
}

function mergeSnapshots(snaps){

	var result = {version: snaps[snaps.length-1].endVersion, objects: []};

	var taken = {};
	for(var i=snaps.length-1;i>=0;--i){
		var m = snaps[i].objects;

		var objs = m

		var t = taken

		var resObjs = result.objects

		for(var j=0;j<objs.length;++j){
			var obj = objs[j];
			var id = obj.object.meta.id

			if(!t[id]){
				t[id] = true;
				resObjs.push(obj)
			}
		}
	}

	return result;
}

var snapshot;

global.getRoot = function(){
	_.errout('too soon to getRoot - minnow is not finished loading.  Use listenForMinnow(function(root){...}) to get it as soon as it is loaded.');
}

function loadMinnowView(){
	console.log('got all snapshot parts, loading minnow');
	/*
	var sendFacade = {
		editBuffer: [],
		persistEdit: function(typeCode, id, path, edit){
			sendFacade.editBuffer.push([typeCode, id, path, edit]);
		}
	};*/

	snapshot = mergeSnapshots(snaps);

	console.log('version loaded: ' + snapshot.version);

	var host = window.location.protocol + '//' + window.location.host// + ':' + minnowSocketPort
	var viewName = schema._byCode[baseTypeCode].name

	update.establishSocket(applicationName, schema, host, function(syncHandle){
		syncHandle._openViewWithSnapshots(baseTypeCode, snapshot.version, snaps, viewName, mainViewParams, function(root){

			getRoot = function(){return root;}

			console.log('got main view api')
			api = root

			//domready.domready(function(){
			//	console.log('dom ready')
				listeners.forEach(function(listener){
					listener(root);
				});
			//});

		})
	})
}

})();
<commit_msg>improved error reporting for xhr and websocket transports<commit_after>"use strict";

var domready = require('matterhorn-standard/js/domready')

var syncApi = require('./sync_api')
var update = require('./minnow_update_websocket')

var listenForMinnow;

(function(){

var api;
var root;

var listeners = [];
global.listenForMinnow = function(listener){
	if(api === undefined){
		listeners.push(listener);
	}else{
		listener(api);
	}
}

exports.listen = global.listenForMinnow

var schema;

var snapsRemaining = [].concat(snapshotIds);

for(var i=0;i<snapshotIds.length;++i){
	var id = snapshotIds[i];
	console.log('snap id: ' + id);
}

var snaps = [];
global.gotSnapshot = function(snap){
	var index;
	for(var i=0;i<snapsRemaining.length;++i){
		if(snapsRemaining[i] === snap.id){
			index = i;
			break;
		}
	}
	if(index === undefined) throw "error, invalid snap id or already received: " + snap.id;

	snapsRemaining.splice(i, 1);

	snaps.push(snap);

	console.log('received snap: ' + snap.id);

	tryLoad();
}

global.gotSchema = function(s){

	schema = s;

	tryLoad();
}

function tryLoad(){
	if(snapsRemaining.length === 0 && schema !== undefined){
		loadMinnowView();
	}
}

function mergeSnapshots(snaps){

	var result = {version: snaps[snaps.length-1].endVersion, objects: []};

	var taken = {};
	for(var i=snaps.length-1;i>=0;--i){
		var m = snaps[i].objects;

		var objs = m

		var t = taken

		var resObjs = result.objects

		for(var j=0;j<objs.length;++j){
			var obj = objs[j];
			var id = obj.object.meta.id

			if(!t[id]){
				t[id] = true;
				resObjs.push(obj)
			}
		}
	}

	return result;
}

var snapshot;

global.getRoot = function(){
	_.errout('too soon to getRoot - minnow is not finished loading.  Use listenForMinnow(function(root){...}) to get it as soon as it is loaded.');
}

function loadMinnowView(){
	console.log('got all snapshot parts, loading minnow');
	/*
	var sendFacade = {
		editBuffer: [],
		persistEdit: function(typeCode, id, path, edit){
			sendFacade.editBuffer.push([typeCode, id, path, edit]);
		}
	};*/

	snapshot = mergeSnapshots(snaps);

	console.log('version loaded: ' + snapshot.version);

	var host = window.location.protocol + '//' + window.location.host// + ':' + minnowSocketPort
	var viewName = schema._byCode[baseTypeCode].name

	update.establishSocket(applicationName, schema, host, function(syncHandle){
		syncHandle._openViewWithSnapshots(baseTypeCode, snapshot.version, snaps, viewName, mainViewParams, function(err, root){
			if(err) _.errout('Error: ' + err)

			getRoot = function(){return root;}

			console.log('got main view api')
			api = root

			//domready.domready(function(){
			//	console.log('dom ready')
				listeners.forEach(function(listener){
					listener(root);
				});
			//});

		})
	})
}

})();
<|endoftext|>


<commit_before>var makeUnicorn = function () {
    var step = 0;
    var pos = {
        x: -700,
        y: 500
    };
    var dx = 50;

    // Steps at which the colors appear.
    var start = {
        blue: 0,
        green: 10,
        darkblue: 12,
        yellow: 15,
        violet: 16,
        red: 20,
    };

    // Steps at which the colors finish appearing.
    var end = {
        blue: start.blue + 20,
        green: start.green + 13,
        darkblue: start.darkblue + 13,
        yellow: start.yellow + 12,
        violet: start.violet + 11,
        red: start.red + 10,
    };

    // The colors.
    var fill = {
        blue: "#00aaff",
        green: "#00ffaa",
        darkblue: "#000077",
        yellow: "#ffff00",
        violet: "#ff00ff",
        red: "#ff0000",
    };

    // A fuzz number to make things pretty.
    var offset = {
        blue: 0,
        green: 15,
        darkblue: 14,
        yellow: 40,
        violet: 43,
        red: 50,
    };

    // True if a color appears on the top of the dash.
    var top = {
        blue: true,
        green: true,
        yellow: true,
        red: true,
    };

    // True if a color also appears on the bottom of the dash.
    var bottom = {
        blue: true,
        red: true,
    };

    // Color names, in order of drawing.
    var colors = [
        "red",
        "violet",
        "yellow",
        "darkblue",
        "green",
        "blue",
    ];

    var endpoint = function(color) {
        var p = (step - start[color]) / (end[color] - start[color]);
        if (step > end[color]) p = 1;

        return {
            r: 400 * p * p,
            theta: 3 * Math.PI / 2 - (Math.PI/2) * p,
        };
    }

    return {
        draw: function () {
            context.save();
            var s = 0, p = 0, o = 0;
            var x = cx(pos.x);
            var y = cy(pos.y);

            var ep, er;

            colors.each(function (color) {
                if (step >= start[color]) {
                    context.fillStyle = fill[color];
                    p = (step - start[color]) / (end[color] - start[color]);
                    if (p > 1) p = 1;
                    o = offset[color];

                    context.globalAlpha = p * p * p;

                    ep = endpoint(color);
                    er = rect(ep.r, ep.theta);

                    context.beginPath();
                    context.moveTo(x, y);

                    if (top[color]) {
                        context.bezierCurveTo(x + 10, y - o - 30 * p,
                                              x + er.x, y + er.y - o * (1-p),
                                              x + er.x, y + er.y - o * (1-p));
                        if (color === "blue") context.lineTo(x + er.x, y);
                        context.moveTo(x, y);
                    }
                    if (!top[color] || bottom[color]) {
                        context.bezierCurveTo(x + 10, y + o + 30 * p,
                                              x + er.x, y - er.y + o * (1-p),
                                              x + er.x, y - er.y + o * (1-p));
                        if (color === "blue") context.lineTo(x + er.x, y);
                    }
                    context.fill();
                    context.closePath();
                }
            });

            context.restore();
            step += 1;
            if (pos.x > 400) starBroken = true;
            pos.x += dx;
        },
    };
};

<commit_msg>Move the dash less stupidly.<commit_after>var makeUnicorn = function () {
    var step = 18;
    var pos = {
        x: 000,
        y: 500
    };
    var dx = 50;

    // Steps at which the colors appear.
    var start = {
        blue: 0,
        green: 10,
        darkblue: 12,
        yellow: 15,
        violet: 16,
        red: 20,
    };

    // Steps at which the colors finish appearing.
    var end = {
        blue: start.blue + 20,
        green: start.green + 13,
        darkblue: start.darkblue + 13,
        yellow: start.yellow + 12,
        violet: start.violet + 11,
        red: start.red + 10,
    };

    // The colors.
    var fill = {
        blue: "#00aaff",
        green: "#00ffaa",
        darkblue: "#000077",
        yellow: "#ffff00",
        violet: "#ff00ff",
        red: "#ff0000",
    };

    // A fuzz number to make things pretty.
    var offset = {
        blue: 0,
        green: 15,
        darkblue: 14,
        yellow: 40,
        violet: 43,
        red: 50,
    };

    // True if a color appears on the top of the dash.
    var top = {
        blue: true,
        green: true,
        yellow: true,
        red: true,
    };

    // True if a color also appears on the bottom of the dash.
    var bottom = {
        blue: true,
        red: true,
    };

    // Color names, in order of drawing.
    var colors = [
        "red",
        "violet",
        "yellow",
        "darkblue",
        "green",
        "blue",
    ];

    var endpoint = function(color) {
        var p = (step - start[color]) / (end[color] - start[color]);
        if (step > end[color]) p = 1;

        return {
            r: 400 * p * p,
            theta: 3 * Math.PI / 2 - (Math.PI/2) * p,
        };
    }

    return {
        draw: function () {
            context.save();
            var s = 0, p = 0, o = 0;
            var x = cx(pos.x);
            var y = cy(pos.y);

            var ep, er;

            colors.each(function (color) {
                if (step >= start[color]) {
                    context.fillStyle = fill[color];
                    p = (step - start[color]) / (end[color] - start[color]);
                    if (p > 1) p = 1;
                    o = offset[color];

                    context.globalAlpha = p * p * p;

                    ep = endpoint(color);
                    er = rect(ep.r, ep.theta);

                    context.beginPath();
                    context.moveTo(x, y);

                    if (top[color]) {
                        context.bezierCurveTo(x + 10, y - o - 30 * p,
                                              x + er.x, y + er.y - o * (1-p),
                                              x + er.x, y + er.y - o * (1-p));
                        if (color === "blue") context.lineTo(x + er.x, y);
                        context.moveTo(x, y);
                    }
                    if (!top[color] || bottom[color]) {
                        context.bezierCurveTo(x + 10, y + o + 30 * p,
                                              x + er.x, y - er.y + o * (1-p),
                                              x + er.x, y - er.y + o * (1-p));
                        if (color === "blue") context.lineTo(x + er.x, y);
                    }
                    context.fill();
                    context.closePath();
                }
            });

            context.restore();
            step += 1;
            if (pos.x > 400) starBroken = true;
            pos.x += dx;
        },
    };
};

<|endoftext|>


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

  function listenToClick(element, name, fn) {
    if (document.addEventListener) {
      element.addEventListener(name, fn, false);
    } else {
      element.attachEvent((name === 'click') ? 'onclick' : name, fn);
    }
  }

  function hasClass(el, className) {
    if (el.classList)
      return el.classList.contains(className)
    else
      return !!el.className.match(new RegExp('(\\s|^)' + className + '(\\s|$)'))
  }

  function my_addClass(el, className) {
    if (el.classList)
      el.classList.add(className)
    else if (!hasClass(el, className)) el.className += " " + className
  }

  function my_removeClass(el, className) {
    if (el.classList)
      el.classList.remove(className)
    else if (hasClass(el, className)) {
      var reg = new RegExp('(\\s|^)' + className + '(\\s|$)')
      el.className=el.className.replace(reg, ' ')
    }
  }

  function scrollTop(element, to, duration) {
    var start = element.scrollTop,
        change = to - start,
        currentTime = 0,
        increment = 20;

    var animateScroll = function(){
      currentTime += increment;
      var val = Math.easeInOutQuad(currentTime, start, change, duration);
      element.scrollTop = val;
      if(currentTime < duration) {
        setTimeout(animateScroll, increment);
      }
    };
    animateScroll();
  }

  //t = current time
  //b = start value
  //c = change in value
  //d = duration
  Math.easeInOutQuad = function (t, b, c, d) {
    t /= d/2;
    if (t < 1) return c/2*t*t + b;
    t--;
    return -c/2 * (t*(t-2) - 1) + b;
  }

  function each(o, cb, s){
    var n;
    if (!o){
      return 0;
    }
    s = !s ? o : s;
    if (o instanceof Array){
      // Indexed arrays, needed for Safari
      for (n=0; n<o.length; n++) {
        if (cb.call(s, o[n], n, o) === false){
          return 0;
        }
      }
    } else {
      // Hashtables
      for (n in o){
        if (o.hasOwnProperty(n)) {
          if (cb.call(s, o[n], n, o) === false){
            return 0;
          }
        }
      }
    }
    return 1;
  }

  domready(function() {
    var
      scrollElements,
      inValidRange,
      setVisibility,
      setVisibilityAll,
      resetScroll;

    scrollElements = document.querySelectorAll('[data-scroll-element]');

    inValidRange = function(offset, limit) {
      return offset >= 0 && offset < limit;
    };

    setVisibility = function(element, nextOffset, limit) {
      if(inValidRange(nextOffset, limit)) {
        my_removeClass(element, 'disabled');
      } else {
        my_addClass(element, 'disabled');
      }
    };

    setVisibilityAll = function(elements, newOffset) {
      var
        scrollElement,
        increment,
        nextOffset,
        limit;

      each(elements, function(el) {
        scrollElement = document.querySelector(el.dataset.scrollElement);
        increment  = parseInt(el.dataset.scrollIncrement);
        nextOffset = newOffset + increment;
        limit      = parseInt(scrollElement.dataset.scrollLimit);

        setVisibility(el, nextOffset, limit);
      });
    };

    resetScroll = function(element) {
      element.scrollTop = 0;
      element.dataset.scrollOffset = 0;
    };

    each(document.querySelectorAll('[data-clipboard-target]'), function(el) {
      var
        clipboard,
        notification;

      clipboard = new Clipboard(el);

      var notify = function(clipboardNotification, notificationText) {
        notification = document.getElementById(clipboardNotification.slice(1));
        notification.textContent = notificationText;
        my_addClass(notification, 'in');
        setTimeout(function() {
          my_removeClass(notification, 'in');
        }, 1400);
      };

      var notifySuccess = function(e) {
        notify(e.trigger.dataset.clipboardNotification, "Copied!");
      };

      var notifyFailure = function(e) {
        //if the copy function failed the text should still be selected, so just ask the user to hit ctrl+c
        notify(e.trigger.dataset.clipboardNotification, "Press Ctrl+C to copy");
      };

      clipboard.on('success', notifySuccess);
      clipboard.on('error', notifyFailure);
    });

    each(scrollElements, function(el) {
      var
        element,
        increment,
        limit,
        offset,
        nextOffset,
        newOffset;

      element = document.querySelector(el.dataset.scrollElement);
      increment = parseInt(el.dataset.scrollIncrement);
      limit     = parseInt(element.dataset.scrollLimit.valueOf());
      offset    = parseInt(element.dataset.scrollOffset.valueOf());

      element.dataset.scrollLimit = limit;

      nextOffset = offset + increment;

      setVisibility(el, nextOffset, limit);

      // Force IE to forget previous scroll top value
      resetScroll(element);

      listenToClick(el, 'click', function() {
        offset = parseInt(element.dataset.scrollOffset);

        newOffset = offset + increment;

        if (inValidRange(newOffset, limit)) {
          scrollTop(element, document.getElementById(newOffset).offsetTop, 400);
          element.dataset.scrollOffset = newOffset;

          setVisibilityAll(scrollElements, newOffset);
        }
      });
    });

    each(document.querySelectorAll('[data-moment]'), function(el) {
      var time = moment(parseInt(el.textContent));
      el.textContent = time.fromNow();
    });

    each(document.querySelectorAll('[data-clipboard-target]', funtction() {
      console.log(window.squatch);
    });
  });

})();
<commit_msg>Start testing event bus<commit_after>(function() {
  'use strict';

  function listenToClick(element, name, fn) {
    if (document.addEventListener) {
      element.addEventListener(name, fn, false);
    } else {
      element.attachEvent((name === 'click') ? 'onclick' : name, fn);
    }
  }

  function hasClass(el, className) {
    if (el.classList)
      return el.classList.contains(className)
    else
      return !!el.className.match(new RegExp('(\\s|^)' + className + '(\\s|$)'))
  }

  function my_addClass(el, className) {
    if (el.classList)
      el.classList.add(className)
    else if (!hasClass(el, className)) el.className += " " + className
  }

  function my_removeClass(el, className) {
    if (el.classList)
      el.classList.remove(className)
    else if (hasClass(el, className)) {
      var reg = new RegExp('(\\s|^)' + className + '(\\s|$)')
      el.className=el.className.replace(reg, ' ')
    }
  }

  function scrollTop(element, to, duration) {
    var start = element.scrollTop,
        change = to - start,
        currentTime = 0,
        increment = 20;

    var animateScroll = function(){
      currentTime += increment;
      var val = Math.easeInOutQuad(currentTime, start, change, duration);
      element.scrollTop = val;
      if(currentTime < duration) {
        setTimeout(animateScroll, increment);
      }
    };
    animateScroll();
  }

  //t = current time
  //b = start value
  //c = change in value
  //d = duration
  Math.easeInOutQuad = function (t, b, c, d) {
    t /= d/2;
    if (t < 1) return c/2*t*t + b;
    t--;
    return -c/2 * (t*(t-2) - 1) + b;
  }

  function each(o, cb, s){
    var n;
    if (!o){
      return 0;
    }
    s = !s ? o : s;
    if (o instanceof Array){
      // Indexed arrays, needed for Safari
      for (n=0; n<o.length; n++) {
        if (cb.call(s, o[n], n, o) === false){
          return 0;
        }
      }
    } else {
      // Hashtables
      for (n in o){
        if (o.hasOwnProperty(n)) {
          if (cb.call(s, o[n], n, o) === false){
            return 0;
          }
        }
      }
    }
    return 1;
  }

  domready(function() {
    var
      scrollElements,
      inValidRange,
      setVisibility,
      setVisibilityAll,
      resetScroll;

    scrollElements = document.querySelectorAll('[data-scroll-element]');

    inValidRange = function(offset, limit) {
      return offset >= 0 && offset < limit;
    };

    setVisibility = function(element, nextOffset, limit) {
      if(inValidRange(nextOffset, limit)) {
        my_removeClass(element, 'disabled');
      } else {
        my_addClass(element, 'disabled');
      }
    };

    setVisibilityAll = function(elements, newOffset) {
      var
        scrollElement,
        increment,
        nextOffset,
        limit;

      each(elements, function(el) {
        scrollElement = document.querySelector(el.dataset.scrollElement);
        increment  = parseInt(el.dataset.scrollIncrement);
        nextOffset = newOffset + increment;
        limit      = parseInt(scrollElement.dataset.scrollLimit);

        setVisibility(el, nextOffset, limit);
      });
    };

    resetScroll = function(element) {
      element.scrollTop = 0;
      element.dataset.scrollOffset = 0;
    };

    each(document.querySelectorAll('[data-clipboard-target]'), function(el) {
      var
        clipboard,
        notification;

      clipboard = new Clipboard(el);

      var notify = function(clipboardNotification, notificationText) {
        notification = document.getElementById(clipboardNotification.slice(1));
        notification.textContent = notificationText;
        my_addClass(notification, 'in');
        setTimeout(function() {
          my_removeClass(notification, 'in');
        }, 1400);
      };

      var notifySuccess = function(e) {
        notify(e.trigger.dataset.clipboardNotification, "Copied!");
      };

      var notifyFailure = function(e) {
        //if the copy function failed the text should still be selected, so just ask the user to hit ctrl+c
        notify(e.trigger.dataset.clipboardNotification, "Press Ctrl+C to copy");
      };

      clipboard.on('success', notifySuccess);
      clipboard.on('error', notifyFailure);
    });

    each(scrollElements, function(el) {
      var
        element,
        increment,
        limit,
        offset,
        nextOffset,
        newOffset;

      element = document.querySelector(el.dataset.scrollElement);
      increment = parseInt(el.dataset.scrollIncrement);
      limit     = parseInt(element.dataset.scrollLimit.valueOf());
      offset    = parseInt(element.dataset.scrollOffset.valueOf());

      element.dataset.scrollLimit = limit;

      nextOffset = offset + increment;

      setVisibility(el, nextOffset, limit);

      // Force IE to forget previous scroll top value
      resetScroll(element);

      listenToClick(el, 'click', function() {
        offset = parseInt(element.dataset.scrollOffset);

        newOffset = offset + increment;

        if (inValidRange(newOffset, limit)) {
          scrollTop(element, document.getElementById(newOffset).offsetTop, 400);
          element.dataset.scrollOffset = newOffset;

          setVisibilityAll(scrollElements, newOffset);
        }
      });
    });

    each(document.querySelectorAll('[data-moment]'), function(el) {
      var time = moment(parseInt(el.textContent));
      el.textContent = time.fromNow();
    });

    each(document.querySelectorAll('[data-clipboard-target]'), funtction() {
      console.log(window.squatch);
    });
  });

})();
<|endoftext|>


<commit_before><commit_msg>added unshiftRe<commit_after>Array.prototype.unshiftRe = function(x) {
  for (var i = (this.length - 1); i >= 0; i--) {
    this[i + 1] = this[i];
  }
  this[0] = x;
  return this.length;
}
<|endoftext|>


<commit_before>var fs = requi<commit_msg>Update character<commit_after>var fs = requir<|endoftext|>


<commit_before>'use strict';

var Week = require('./week.model');
var User = require('./../user/user.model');
var Task = require('./../task/task.model');
var config = require('../../config/environment');
var moment = require('moment');
var getWeekNumber = function(user, target_date) {
  for(var i = 0; i < 7; i++) {
    var endOfWeek = moment(user.start_date).endOf('week').add(i, 'weeks').format("YYYY-MM-DD");
    var target = moment(endOfWeek).startOf('week').format("YYYY-MM-DD");
    for(var j = 0; j < 7; j++) {
      console.log(moment(target_date).format("YYYY-MM-DD"));
      if(target == moment(target_date).format("YYYY-MM-DD")) {
        return i+1;
      }
      target = moment(target).add(1, 'days').format("YYYY-MM-DD")
    };
  }
}

/**
 * Get a week based on week number
 */
exports.index = function (req, res, next) {
  Week.findOne({token: req.headers.token}, function (err, weeks) {
    if (err) return next(err);
    res.json(weeks);
  });
};

exports.current_week = function (req, res, next) {
  User
    .findOne({token: req.headers.token}, function (err, user) {
      if (err) return next(err);
      if (!user) return res.send(404, "No user found");
      if (!req.body.date) return res.send(422, "Please provide the current date");
      var weekNumber = getWeekNumber(user, req.body.date);
      Week
        .findOne({name: weekNumber})
        .populate("tasks")
        .exec(function (err, week) {
          res.json(week);
        });
  });
};
<commit_msg>console log<commit_after>'use strict';

var Week = require('./week.model');
var User = require('./../user/user.model');
var Task = require('./../task/task.model');
var config = require('../../config/environment');
var moment = require('moment');
var getWeekNumber = function(user, target_date) {
  for(var i = 0; i < 7; i++) {
    var endOfWeek = moment(user.start_date).endOf('week').add(i, 'weeks').format("YYYY-MM-DD");
    var target = moment(endOfWeek).startOf('week').format("YYYY-MM-DD");
    for(var j = 0; j < 7; j++) {
      if(target == moment(target_date).format("YYYY-MM-DD")) {
        return i+1;
      }
      target = moment(target).add(1, 'days').format("YYYY-MM-DD")
    };
  }
}

/**
 * Get a week based on week number
 */
exports.index = function (req, res, next) {
  Week.findOne({token: req.headers.token}, function (err, weeks) {
    if (err) return next(err);
    res.json(weeks);
  });
};

exports.current_week = function (req, res, next) {
  User
    .findOne({token: req.headers.token}, function (err, user) {
      if (err) return next(err);
      if (!user) return res.send(404, "No user found");
      if (!req.body.date) return res.send(422, "Please provide the current date");
      console.log(req.body);
      var weekNumber = getWeekNumber(user, req.body.date);
      Week
        .findOne({name: weekNumber})
        .populate("tasks")
        .exec(function (err, week) {
          res.json(week);
        });
  });
};
<|endoftext|>


<commit_before>/**
 * Comment sign-in and comment form actions:
 * Uses XMLHttpRequests and the history.api
 */
//check for history api support
function supports_history_api() {
  return !!(window.history && history.pushState);
}

//Initiating AlaAuth object to hold form related functions
var AlaAuth = {

	alertMsg: function(msg){
		//create and append a simple modal for form success / error msgs.
		$('.commenter-signin').append(
			"

" + msg + '
Press any key or click anywhere to close this
' + "

"
		);
		//vertically center the modal content
		var innerEl = $(".custom-modal .container");
		var innerElHeight = innerEl.outerHeight();
		innerEl.css('margin-top', '-' + innerElHeight/2 + 'px');
		//close the modal: click anywhere to close it, or hit any key
		$(document).on('keyup click', function(){ //
		    $(".custom-modal").remove();
		});
	},

	loadTemplate: function(state) {
		//hide current template
		ajaxContainer.addClass('none');
		//load new template
	  	$.get(states.site_url + states.tmpl_path + state + states.entry_id + states.segments, function(ret){
			ajaxContainer.replaceWith(ret);
		}, false);
	},

	spinnerInit: function(){
		//initiate spinner
		var spinnerOpts = {
			className: 'js-spinner none'  // CSS class to assign to the element
		};
		var spinnerTarget = document.getElementById('comment-submit-holder');
		var spinner = new Spinner(spinnerOpts).spin(spinnerTarget);
	},

	spinnerStart: function(){
		$('.js-spinner').removeClass('none');
		$('#comment-submit-holder input').addClass('inactive');
	},

	spinnerStop: function(){
		$('.js-spinner').addClass('none');
		$('#comment-submit-holder input').removeClass('inactive');
	},

	resetValue: function(){
		var resetText =  $(window).width() <= 420 ? 'Reset' : 'Reset password';
		$('#reset-password').attr('value', resetText);
	}

}; //end AlaAuth object

//AlaAuth vars
var ajaxContainer = $('.ajax-container');

$(document).ready(function(){

	//this is a function in form.js that mutually excludes EE server validation and our js custom validation
	EEValidateSync();

	//Initiate spinner
	AlaAuth.spinnerInit();

	//check for history.api support
	if (!supports_history_api()) { return; }

	//check that we're on an entry page and the states object exists
	if(typeof states != "undefined") {
		/**
		* when the document loads and while the user is signed in,
		* use replaceState to apply a state to the current document,
		* so event.state is never null, and the use gets to see the comment form
		*/
		if (states.currentstate == 'comment-form') {
			//hide social sign-in btns
			$('#login-buttons').addClass('none');
			//apply a state: replace the current document's state and url
			history.replaceState(
				states.commentform,
				'on ' + states.commentform,
				states.site_url + states.segments //no need to add the comment-form url to each entry if logged in
			);
			return false;
		}

		//history.api nav clickhandler
		$('.history-nav').on('click', function(event){

			var goToUrl = $(this).attr('id');

			event.preventDefault();
			//hide current template and load new template
			AlaAuth.loadTemplate(
				goToUrl
			);
			// Add an entry to the history stack and push the url
			history.pushState(
				goToUrl,
				'on ' + goToUrl,
				states.site_url + states.segments + '/' + goToUrl
			);

		});

	} //end typeof states check

});// end document ready

//handle the popstate event
$(window).on('load', function() {
	//check for history.api support
	if (!supports_history_api()) { return; }
	//Using setTimeout is a necessary hack to avoid multiple file loads in webkit
	setTimeout(function() {
	    $(window).on('popstate', function(e) {
	    	//check if there are modified entries in the history stack
	    	if (e.originalEvent.state === null) {
				//load the comment sign in form
				AlaAuth.loadTemplate(
					states.commentsignin
				);
			}
			if (e.originalEvent.state !== null) {
				//load the right content
				AlaAuth.loadTemplate(
					e.originalEvent.state
				);
			}
		});
	}, 0);

}); //end window onload
/*
* Using setTimeout with popstate is a necessary hack
* because WebKit fires a popstate event on document load,
* so then we get multiple file loads.
* https://code.google.com/p/chromium/issues/detail?id=63040
* https://bugs.webkit.org/process_bug.cgi
*/

$(window).on("load resize scroll",function(){
	//Change input value based on screen resolution
	AlaAuth.resetValue();
});

<commit_msg>add touchstart to modal events<commit_after>/**
 * Comment sign-in and comment form actions:
 * Uses XMLHttpRequests and the history.api
 */
//check for history api support
function supports_history_api() {
  return !!(window.history && history.pushState);
}

//AlaAuth vars
var ajaxContainer = $('.ajax-container');

//Initiating AlaAuth object to hold form related functions
var AlaAuth = {

	alertMsg: function(msg){
		//create and append a simple modal for form success / error msgs.
		$('.commenter-signin').append(
			"

" + msg + '
Press any key or click anywhere to close this
' + "

"
		);
		//vertically center the modal content
		var innerEl = $(".custom-modal .container");
		var innerElHeight = innerEl.outerHeight();
		innerEl.css('margin-top', '-' + innerElHeight/2 + 'px');
		//close the modal: click anywhere to close it, or hit any key
		$(document).on('keyup click touchstart', function(){ //
		    $(".custom-modal").remove();
		});
	},

	loadTemplate: function(state) {
		//hide current template
		ajaxContainer.addClass('none');
		//load new template
	  	$.get(states.site_url + states.tmpl_path + state + states.entry_id + states.segments, function(ret){
			ajaxContainer.replaceWith(ret);
		}, false);
	},

	spinnerInit: function(){
		//initiate spinner
		var spinnerOpts = {
			className: 'js-spinner none'  // CSS class to assign to the element
		};
		var spinnerTarget = document.getElementById('comment-submit-holder');
		var spinner = new Spinner(spinnerOpts).spin(spinnerTarget);
	},

	spinnerStart: function(){
		$('.js-spinner').removeClass('none');
		$('#comment-submit-holder input').addClass('inactive');
	},

	spinnerStop: function(){
		$('.js-spinner').addClass('none');
		$('#comment-submit-holder input').removeClass('inactive');
	},

	resetValue: function(){
		var resetText =  $(window).width() <= 420 ? 'Reset' : 'Reset password';
		$('#reset-password').attr('value', resetText);
	}

}; //end AlaAuth object

$(document).ready(function(){

	//this is a function in form.js that mutually excludes EE server validation and our js custom validation
	EEValidateSync();

	//Initiate spinner
	AlaAuth.spinnerInit();

	//check for history.api support
	if (!supports_history_api()) { return; }

	//check that we're on an entry page and the states object exists
	if(typeof states != "undefined") {
		/**
		* when the document loads and while the user is signed in,
		* use replaceState to apply a state to the current document,
		* so event.state is never null, and the use gets to see the comment form
		*/
		if (states.currentstate == 'comment-form') {
			//hide social sign-in btns
			$('#login-buttons').addClass('none');
			//apply a state: replace the current document's state and url
			history.replaceState(
				states.commentform,
				'on ' + states.commentform,
				states.site_url + states.segments //no need to add the comment-form url to each entry if logged in
			);
			return false;
		}

		//history.api nav clickhandler
		$('.history-nav').on('click', function(event){

			var goToUrl = $(this).attr('id');

			event.preventDefault();
			//hide current template and load new template
			AlaAuth.loadTemplate(
				goToUrl
			);
			// Add an entry to the history stack and push the url
			history.pushState(
				goToUrl,
				'on ' + goToUrl,
				states.site_url + states.segments + '/' + goToUrl
			);

		});

	} //end typeof states check

});// end document ready

//handle the popstate event
$(window).on('load', function() {
	//check for history.api support
	if (!supports_history_api()) { return; }
	//Using setTimeout is a necessary hack to avoid multiple file loads in webkit
	setTimeout(function() {
	    $(window).on('popstate', function(e) {
	    	//check if there are modified entries in the history stack
	    	if (e.originalEvent.state === null) {
				//load the comment sign in form
				AlaAuth.loadTemplate(
					states.commentsignin
				);
			}
			if (e.originalEvent.state !== null) {
				//load the right content
				AlaAuth.loadTemplate(
					e.originalEvent.state
				);
			}
		});
	}, 0);

}); //end window onload
/*
* Using setTimeout with popstate is a necessary hack
* because WebKit fires a popstate event on document load,
* so then we get multiple file loads.
* https://code.google.com/p/chromium/issues/detail?id=63040
* https://bugs.webkit.org/process_bug.cgi
*/

$(window).on('load resize scroll', function(){
	//Change input value based on screen resolution
	AlaAuth.resetValue();
});

<|endoftext|>


<commit_before>/*
 * == BSD2 LICENSE ==
 * Copyright (c) 2015, Tidepool Project
 *
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the associated License, which is identical to the BSD 2-Clause
 * License as published by the Open Source Initiative at opensource.org.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the License for more details.
 *
 * You should have received a copy of the License along with this program; if
 * not, you can obtain one from Tidepool Project at tidepool.org.
 * == BSD2 LICENSE ==
 */

var _ = require('lodash');
var sundial = require('sundial');
var util = require('util');

var annotate = require('../eventAnnotations');

/**
 * Creates a new "simulator" for Animas pump data.
 *
 * Once all input activities are collected, the simulator will have accumulated events that the Tidepool Platform
 * will understand into a local "events" array.  You can retrieve the events by calling `getEvents()`
 *
 */
exports.make = function(config){
  if (config == null) {
    config = {};
  }
  var settings = config.settings || null;
  var events = [];

  var currBasal = null;
  var currBolus = null;
  var currStatus = null;
  var currTimestamp = null;
  var currSMBG = null;
  var lastAlarm = null;

  function setCurrBasal(basal) {
    currBasal = basal;
  }

  function setCurrBolus(bolus) {
    currBolus = bolus;
  }

  function setCurrStatus(status) {
    currStatus = status;
  }

  function setCurrSMBG(smbg) {
    currSMBG = smbg;
  }

  function setLastAlarm(alarm) {
    lastAlarm = alarm;
  }

  function ensureTimestamp(e){
    if (currTimestamp > e.time) {
      throw new Error(
        util.format('Timestamps must be in order.  Current timestamp was[%s], but got[%j]', currTimestamp, e)
      );
    }
    currTimestamp = e.time;
    return e;
  }

  function simpleSimulate(e) {
    ensureTimestamp(e);
    events.push(e);
  }

  function markIfBasalSuspendedByAlarm(alarm,basal) {
    if ((basal != null) && (alarm != null) &&
        (basal.rate === 0) && (basal.deliveryType !== 'suspend')) {

      // Animas does not generate suspend/resume events for alarms,
      // so we check if an alarm occurred recently or at the same time.
      // If so, we mark the basal as suspended and generate a new suspend event.

      var duration = Date.parse(basal.time) - Date.parse(alarm.time);
      var twoHours = (120 * sundial.MIN_TO_MSEC);
      if(duration < twoHours) {

        var type = alarm.alarmType;
        if(type === 'occlusion' || type === 'auto_off' || type === 'no_insulin' || type === 'no_power') {

          //this basal is suspended
          basal.deliveryType = 'suspend';
          annotate.annotateEvent(basal, 'animas/basal/marked-suspended-from-alarm');

          var status = {
            time: basal.time,
            deviceTime: basal.deviceTime,
            timezoneOffset: basal.timezoneOffset,
            conversionOffset: basal.conversionOffset,
            deviceId: basal.deviceId,
            type: 'deviceEvent',
            subType: 'status',
            status: 'suspended',
            reason: {suspended: 'automatic'},
            payload: {cause: type}
          };

          ensureTimestamp(status);
          setCurrStatus(status);
          setLastAlarm(null); //reset alarm as not to re-use for other zero-rate basals
          setCurrBasal(basal);
        }
      }
    }
  }

  return {
    alarm: function(event) {
      setLastAlarm(event);
      markIfBasalSuspendedByAlarm(event,currBasal);
      simpleSimulate(event);
    },
    basal: function(event){
      ensureTimestamp(event);

      if(currBasal !== null && (currBasal.time !== event.time)) {
        if (currBasal.index < event.index) {
          annotate.annotateEvent(event,'animas/out-of-sequence');
        }

        if((currBasal.rate === 0) && (currBasal.deliveryType !== 'suspend') && (currStatus === null)) {
          // As only the 30 most recent suspend/resume events are stored,
          // we can't be sure if older basals with 0.0 rate are suspends or not
          annotate.annotateEvent(currBasal, 'animas/basal/possible-suspend');
        }

        if (!currBasal.isAssigned('duration')) {
          var duration = Date.parse(event.time) - Date.parse(currBasal.time);
          var fiveDays = (5 * 1440 * sundial.MIN_TO_MSEC);
          if(duration > fiveDays) {
            //flat-rate basal
            duration = fiveDays;
            annotate.annotateEvent(currBasal, 'animas/basal/flat-rate');
          }
          currBasal.with_duration(duration);
        }
        currBasal = currBasal.done();
        events.push(currBasal);
      }

      if(currStatus !== null) {
        if (event.rate === 0 ) {
          // categorize the basal we're processing as a suspend basal if its rate
          // is zero and its start falls within the suspend event we have on deck
          var resumed = Date.parse(currStatus.time) + currStatus.duration;
          if (resumed > Date.parse(event.time)) {
            //this basal is suspended
            event.deliveryType = 'suspend';
          }
        }
        else {
          // basal is non-zero
          // is this a suspend event we created from an alarm?
          // If so, we should update the joined suspend/resume event
          if(currStatus.reason.suspended === 'automatic') {

            currStatus.duration = currBasal.duration;
            currStatus.reason.resumed = 'automatic';
            annotate.annotateEvent(currStatus, 'animas/status/fabricated-from-alarm');

            events.push(currStatus);
            setCurrStatus(null);
          }
        }
      }

      setCurrBasal(event);
      markIfBasalSuspendedByAlarm(lastAlarm,event);

    },
    bolus: function(event) {
      delete event.syncCounter; //wizard events already synced up
      delete event.requiredAmount;
      delete event.jsDate;
      simpleSimulate(event);
      setCurrBolus(event);
    },
    changeReservoir: function(event) {
      simpleSimulate(event);
    },
    pumpSettings: function(event) {
      simpleSimulate(event);
    },
    smbg: function(event) {
      if(currSMBG != null && currSMBG.value === event.value) {
        console.log('Duplicate SMBG value (',event.value,')',currSMBG.subType,currSMBG.time,'/',event.subType,event.time);
        var duration = Date.parse(event.time) - Date.parse(currSMBG.time);
        if ((duration < (15 * sundial.MIN_TO_MSEC)) && (event.subType === 'manual')) {
          console.log('Dropping duplicate manual value');
          return;
        }
      }
      simpleSimulate(event);
      setCurrSMBG(event);
    },
    suspend: function(event) {
      ensureTimestamp(event);
      if (currStatus != null && currStatus.index < event.index) {
        annotate.annotateEvent(event,'animas/out-of-sequence');
      }

      if (currBasal != null && currBasal.rate === 0) {
        //this basal is suspended
        currBasal.deliveryType = 'suspend';
      }
      events.push(event);
      setCurrStatus(event);
    },
    wizard: function(event) {
      simpleSimulate(event);
    },
    getEvents: function() {
      function filterOutZeroBoluses() {
        return _.filter(events, function(event) {
          // we include the index on all objects to be able to sort accurately in
          // pump-event order despite date & time settings changes, but it's not
          // part of our data model, so we delete before uploading
          delete event.index;
          if (event.type === 'bolus') {
            if (event.normal === 0 && !event.expectedNormal) {
              return false;
            }
            else {
              return true;
            }
          }
          else if (event.type === 'wizard') {
            var bolus = event.bolus || null;
            if (bolus != null) {
              if (bolus.normal === 0 && !bolus.expectedNormal) {
                return false;
              }
              else {
                return true;
              }
            }
          }
          return true;
        });
      }
      // because we have to wait for the *next* basal to determine the duration of a current
      // basal, basal events get added to `events` out of order wrt other events
      // (although within their own type all the basals are always in order)
      // end result: we have to sort events again before we try to upload them
      var orderedEvents = _.sortBy(filterOutZeroBoluses(), function(e) { return e.time; });

      return orderedEvents;
    }
  };
};
<commit_msg>removing rate from suspend events<commit_after>/*
 * == BSD2 LICENSE ==
 * Copyright (c) 2015, Tidepool Project
 *
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the associated License, which is identical to the BSD 2-Clause
 * License as published by the Open Source Initiative at opensource.org.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the License for more details.
 *
 * You should have received a copy of the License along with this program; if
 * not, you can obtain one from Tidepool Project at tidepool.org.
 * == BSD2 LICENSE ==
 */

var _ = require('lodash');
var sundial = require('sundial');
var util = require('util');

var annotate = require('../eventAnnotations');

/**
 * Creates a new "simulator" for Animas pump data.
 *
 * Once all input activities are collected, the simulator will have accumulated events that the Tidepool Platform
 * will understand into a local "events" array.  You can retrieve the events by calling `getEvents()`
 *
 */
exports.make = function(config){
  if (config == null) {
    config = {};
  }
  var settings = config.settings || null;
  var events = [];

  var currBasal = null;
  var currBolus = null;
  var currStatus = null;
  var currTimestamp = null;
  var currSMBG = null;
  var lastAlarm = null;

  function setCurrBasal(basal) {
    currBasal = basal;
  }

  function setCurrBolus(bolus) {
    currBolus = bolus;
  }

  function setCurrStatus(status) {
    currStatus = status;
  }

  function setCurrSMBG(smbg) {
    currSMBG = smbg;
  }

  function setLastAlarm(alarm) {
    lastAlarm = alarm;
  }

  function ensureTimestamp(e){
    if (currTimestamp > e.time) {
      throw new Error(
        util.format('Timestamps must be in order.  Current timestamp was[%s], but got[%j]', currTimestamp, e)
      );
    }
    currTimestamp = e.time;
    return e;
  }

  function simpleSimulate(e) {
    ensureTimestamp(e);
    events.push(e);
  }

  function markIfBasalSuspendedByAlarm(alarm,basal) {
    if ((basal != null) && (alarm != null) &&
        (basal.rate === 0) && (basal.deliveryType !== 'suspend')) {

      // Animas does not generate suspend/resume events for alarms,
      // so we check if an alarm occurred recently or at the same time.
      // If so, we mark the basal as suspended and generate a new suspend event.

      var duration = Date.parse(basal.time) - Date.parse(alarm.time);
      var twoHours = (120 * sundial.MIN_TO_MSEC);
      if(duration < twoHours) {

        var type = alarm.alarmType;
        if(type === 'occlusion' || type === 'auto_off' || type === 'no_insulin' || type === 'no_power') {

          //this basal is suspended
          basal.deliveryType = 'suspend';
          delete basal.rate;
          annotate.annotateEvent(basal, 'animas/basal/marked-suspended-from-alarm');

          var status = {
            time: basal.time,
            deviceTime: basal.deviceTime,
            timezoneOffset: basal.timezoneOffset,
            conversionOffset: basal.conversionOffset,
            deviceId: basal.deviceId,
            type: 'deviceEvent',
            subType: 'status',
            status: 'suspended',
            reason: {suspended: 'automatic'},
            payload: {cause: type}
          };

          ensureTimestamp(status);
          setCurrStatus(status);
          setLastAlarm(null); //reset alarm as not to re-use for other zero-rate basals
          setCurrBasal(basal);
        }
      }
    }
  }

  return {
    alarm: function(event) {
      setLastAlarm(event);
      markIfBasalSuspendedByAlarm(event,currBasal);
      simpleSimulate(event);
    },
    basal: function(event){
      ensureTimestamp(event);

      if(currBasal !== null && (currBasal.time !== event.time)) {
        if (currBasal.index < event.index) {
          annotate.annotateEvent(event,'animas/out-of-sequence');
        }

        if((currBasal.rate === 0) && (currBasal.deliveryType !== 'suspend') && (currStatus === null)) {
          // As only the 30 most recent suspend/resume events are stored,
          // we can't be sure if older basals with 0.0 rate are suspends or not
          annotate.annotateEvent(currBasal, 'animas/basal/possible-suspend');
        }

        if (!currBasal.isAssigned('duration')) {
          var duration = Date.parse(event.time) - Date.parse(currBasal.time);
          var fiveDays = (5 * 1440 * sundial.MIN_TO_MSEC);
          if(duration > fiveDays) {
            //flat-rate basal
            duration = fiveDays;
            annotate.annotateEvent(currBasal, 'animas/basal/flat-rate');
          }
          currBasal.with_duration(duration);
        }
        currBasal = currBasal.done();
        events.push(currBasal);
      }

      if(currStatus !== null) {
        if (event.rate === 0 ) {
          // categorize the basal we're processing as a suspend basal if its rate
          // is zero and its start falls within the suspend event we have on deck
          var resumed = Date.parse(currStatus.time) + currStatus.duration;
          if (resumed > Date.parse(event.time)) {
            //this basal is suspended
            event.deliveryType = 'suspend';
            delete event.rate;
          }
        }
        else {
          // basal is non-zero
          // Are we resuming from a suspend event we created from an alarm?
          // If so, we should update the joined suspend/resume event
          if(currStatus.reason.suspended === 'automatic') {

            currStatus.duration = currBasal.duration;
            currStatus.reason.resumed = 'automatic';
            annotate.annotateEvent(currStatus, 'animas/status/fabricated-from-alarm');

            events.push(currStatus);
            setCurrStatus(null);
          }
        }
      }

      setCurrBasal(event);
      markIfBasalSuspendedByAlarm(lastAlarm,event);

    },
    bolus: function(event) {
      delete event.syncCounter; //wizard events already synced up
      delete event.requiredAmount;
      delete event.jsDate;
      simpleSimulate(event);
      setCurrBolus(event);
    },
    changeReservoir: function(event) {
      simpleSimulate(event);
    },
    pumpSettings: function(event) {
      simpleSimulate(event);
    },
    smbg: function(event) {
      if(currSMBG != null && currSMBG.value === event.value) {
        console.log('Duplicate SMBG value (',event.value,')',currSMBG.subType,currSMBG.time,'/',event.subType,event.time);
        var duration = Date.parse(event.time) - Date.parse(currSMBG.time);
        if ((duration < (15 * sundial.MIN_TO_MSEC)) && (event.subType === 'manual')) {
          console.log('Dropping duplicate manual value');
          return;
        }
      }
      simpleSimulate(event);
      setCurrSMBG(event);
    },
    suspend: function(event) {
      ensureTimestamp(event);
      if (currStatus != null && currStatus.index < event.index) {
        annotate.annotateEvent(event,'animas/out-of-sequence');
      }

      if (currBasal != null && currBasal.rate === 0) {
        //this basal is suspended
        currBasal.deliveryType = 'suspend';
        delete currBasal.rate;
      }
      events.push(event);
      setCurrStatus(event);
    },
    wizard: function(event) {
      simpleSimulate(event);
    },
    getEvents: function() {
      function filterOutZeroBoluses() {
        return _.filter(events, function(event) {
          // we include the index on all objects to be able to sort accurately in
          // pump-event order despite date & time settings changes, but it's not
          // part of our data model, so we delete before uploading
          delete event.index;
          if (event.type === 'bolus') {
            if (event.normal === 0 && !event.expectedNormal) {
              return false;
            }
            else {
              return true;
            }
          }
          else if (event.type === 'wizard') {
            var bolus = event.bolus || null;
            if (bolus != null) {
              if (bolus.normal === 0 && !bolus.expectedNormal) {
                return false;
              }
              else {
                return true;
              }
            }
          }
          return true;
        });
      }
      // because we have to wait for the *next* basal to determine the duration of a current
      // basal, basal events get added to `events` out of order wrt other events
      // (although within their own type all the basals are always in order)
      // end result: we have to sort events again before we try to upload them
      var orderedEvents = _.sortBy(filterOutZeroBoluses(), function(e) { return e.time; });

      return orderedEvents;
    }
  };
};
<|endoftext|>


<commit_before>// customize-home.js

// logo spin
$('#logo').hover(function () {
    $(this).addClass('fa-spin text-yellow-inverted');
}, function () {
    $(this).removeClass('fa-spin text-yellow-inverted');
});

// progress bar
$('#page-loading-progress').progress({
    total: 1,
    onSuccess: function () {
        $('#page-loading-progress').fadeOut(1000, function () {
            $('#page-loading-progress').remove();
        });
    }
});

// GitHub
function updateGitHub() {
    $('#github-watch img').attr('src', 'https://img.shields.io/github/watchers/iROCKBUNNY/BYR-Navi.svg?style=social&label=Watch');
    $('#github-star img').attr('src', 'https://img.shields.io/github/stars/iROCKBUNNY/BYR-Navi.svg?style=social&label=Star');
    $('#github-fork img').attr('src', 'https://img.shields.io/github/forks/iROCKBUNNY/BYR-Navi.svg?style=social&label=Fork');
};
updateGitHub();
setInterval(function () {
    updateGitHub();
}, 15000);

// version
moment.locale('zh-cn');
function updateVersion(timestamp) {
    $('#version img').attr('src', 'https://img.shields.io/badge/%E6%9B%B4%E6%96%B0%E4%BA%8E-' + encodeURIComponent(moment(timestamp).fromNow()) + '-brightgreen.svg');
};
var updateAt = $('#version').attr('data-update-at');
updateVersion(updateAt);
setInterval(function () {
    updateVersion(updateAt);
}, 15000);

// visit
function updateVisit(updateProgressBar) {
    $.getJSON(analyticsAPI.url, {
        'module': 'API',
        'method': 'VisitsSummary.getUniqueVisitors',
        'idSite': analyticsAPI.id,
        'period': 'day',
        'date': 'today',
        'format': 'JSON',
        'token_auth': analyticsAPI.token
    }, function (data) {
        $('#visit img').attr('src', 'https://img.shields.io/badge/%E4%BB%8A%E6%97%A5%E8%AE%BF%E5%AE%A2-' + encodeURIComponent(data.value) + '-brightgreen.svg');
        if (updateProgressBar) {
            $('#page-loading-progress').progress('increment');
        };
    });
};
updateVisit(true);
setInterval(function () {
    updateVisit(false);
}, 15000);

// search
$('#search-services').dropdown();
if (Cookies.get('byr_navi_previous_search_service_option') == undefined || $('#' + Cookies.get('byr_navi_previous_search_service_option')).length === 0) {
    Cookies.set('byr_navi_previous_search_service_option', $('#search-services').val(), { expires: 365 });
} else {
    $('#search-services').dropdown('set selected', Cookies.get('byr_navi_previous_search_service_option'));
};

$('#search-button').click(function () {
    var service = $('#' + $('#search-services').val());
    var query = $('#search-query').val();
    query = encodeURIComponent(query);
    if (query) {
        Cookies.set('byr_navi_previous_search_service_option', service.val(), { expires: 365 });
        window.open(service.attr('data-url') + query + service.attr('data-suffix'), '_blank');
    } else {
        $('#search-div').addClass('error');
        $('#search-query').attr('placeholder', '请输入搜索内容');
    };
});

$('#search-query').click(function () {
    $(this).select();
});

$(document).ready(function () {
    $('#search-query').focus();
});

$(window).keyup(function (event) {
    var windowTop = $(window).scrollTop();
    var windowHeight = $(window).innerHeight();
    var windowBottom = windowTop + windowHeight;
    var searchBoxTop = $('#search-div').offset().top;
    var searchBoxHeight = $('#search-div').innerHeight();
    var searchBoxBottom = searchBoxTop + searchBoxHeight;
    if (event.key === 'Enter' && searchBoxBottom > windowTop && searchBoxTop < windowBottom) {
        var service = $('#' + $('#search-services').val());
        var query = $('#search-query').val();
        query = encodeURIComponent(query);
        if (query) {
            if ($('#search-query:focus').length > 0) {
                Cookies.set('byr_navi_previous_search_service_option', service.val(), { expires: 365 });
                window.open(service.attr('data-url') + query + service.attr('data-suffix'), '_blank');
            } else {
                $('#search-query').focus().select();
            };
        } else {
            $('#search-div').addClass('error');
            $('#search-query').attr('placeholder', '请输入搜索内容').focus();
        };
    };
});

$('#search-query').keyup(function (event) {
    if (event.key) {
        if ($('#search-query').val()) {
            $('#search-div').removeClass('error');
            $('#search-query').attr('placeholder', '立即搜索');
        };
    };
});

$('.shortcuts .ui.label').each(function () {
    $(this).click(function () {
        var service = $('#' + $(this).attr('data-search-service-id'));
        var query = $('#search-query').val();
        query = encodeURIComponent(query);
        if (query) {
            Cookies.set('byr_navi_previous_search_service_option', service.val(), { expires: 365 });
            $('#search-services').dropdown('set selected', service.val());
            window.open(service.attr('data-url') + query + service.attr('data-suffix'), '_blank');
        } else {
            $('#search-div').addClass('error');
            $('#search-query').attr('placeholder', '请输入搜索内容');
        };
    });
});

// query suggestions
var sugParams = {
    "XOffset": -3, //提示框位置横向偏移量,单位px
    "YOffset": -2, //提示框位置纵向偏移量,单位px
    // "width": $('#search-query').innerWidth(), //提示框宽度，单位px
    "fontColor": "rgba(0, 0, 0, 0.87)", //提示框文字颜色
    "fontColorHI": "rgba(0, 0, 0, 0.87)", //提示框高亮选择时文字颜色
    "fontSize": "14px", //文字大小
    "fontFamily": "Lato, 'Helvetica Neue', Arial, Helvetica, sans-serif", //文字字体
    "borderColor": "rgba(34, 36, 38, 0.14902)", //提示框的边框颜色
    "bgcolorHI": "rgba(0, 0, 0, 0.05)", //提示框高亮选择的颜色
    "sugSubmit": false //选中提示框中词条时是否提交表单
};
BaiduSuggestion.bind('search-query', sugParams);<commit_msg>Update<commit_after>// customize-home.js

// logo spin
$('#logo').hover(function () {
    $(this).addClass('fa-spin text-yellow-inverted');
}, function () {
    $(this).removeClass('fa-spin text-yellow-inverted');
});

// progress bar
$('#page-loading-progress').progress({
    total: 1,
    onSuccess: function () {
        $('#page-loading-progress').fadeOut(1000, function () {
            $('#page-loading-progress').remove();
        });
    }
});

// GitHub
function updateGitHub() {
    $('#github-watch img').attr('src', 'https://img.shields.io/github/watchers/iROCKBUNNY/BYR-Navi.svg?style=social&label=Watch');
    $('#github-star img').attr('src', 'https://img.shields.io/github/stars/iROCKBUNNY/BYR-Navi.svg?style=social&label=Star');
    $('#github-fork img').attr('src', 'https://img.shields.io/github/forks/iROCKBUNNY/BYR-Navi.svg?style=social&label=Fork');
};
updateGitHub();
setInterval(function () {
    updateGitHub();
}, 15000);

// version
moment.locale('zh-cn');
function updateVersion(timestamp) {
    $('#version img').attr('src', 'https://img.shields.io/badge/%E6%9B%B4%E6%96%B0%E4%BA%8E-' + encodeURIComponent(moment(timestamp).fromNow()) + '-brightgreen.svg');
};
var updateAt = $('#version').attr('data-update-at');
updateVersion(updateAt);
setInterval(function () {
    updateVersion(updateAt);
}, 15000);

// visit
function updateVisit(updateProgressBar) {
    $.getJSON(analyticsAPI.url, {
        'module': 'API',
        'method': 'VisitsSummary.getUniqueVisitors',
        'idSite': analyticsAPI.id,
        'period': 'day',
        'date': 'today',
        'format': 'JSON',
        'token_auth': analyticsAPI.token
    }, function (data) {
        $('#visit img').attr('src', 'https://img.shields.io/badge/%E4%BB%8A%E6%97%A5%E8%AE%BF%E5%AE%A2-' + encodeURIComponent(data.value) + '-brightgreen.svg');
        if (updateProgressBar) {
            $('#page-loading-progress').progress('increment');
        };
    });
};
updateVisit(true);
setInterval(function () {
    updateVisit(false);
}, 15000);

// search
$('#search-services').dropdown();
if (Cookies.get('byr_navi_previous_search_service_option') === undefined || Cookies.get('byr_navi_previous_search_service_option') === '' || $('#' + Cookies.get('byr_navi_previous_search_service_option')).length === 0) {
    Cookies.set('byr_navi_previous_search_service_option', $('#search-services').val(), { expires: 365 });
} else {
    $('#search-services').dropdown('set selected', Cookies.get('byr_navi_previous_search_service_option'));
};

$('#search-button').click(function () {
    var service = $('#' + $('#search-services').val());
    var query = $('#search-query').val();
    query = encodeURIComponent(query);
    if (query) {
        Cookies.set('byr_navi_previous_search_service_option', service.val(), { expires: 365 });
        window.open('redirect?next=' + encodeURIComponent(service.attr('data-url') + query + service.attr('data-suffix')), '_blank');
    } else {
        $('#search-div').addClass('error');
        $('#search-query').attr('placeholder', '请输入搜索内容');
    };
});

$('#search-query').click(function () {
    $(this).select();
});

$(document).ready(function () {
    $('#search-query').focus();
});

$(window).keyup(function (event) {
    var windowTop = $(window).scrollTop();
    var windowHeight = $(window).innerHeight();
    var windowBottom = windowTop + windowHeight;
    var searchBoxTop = $('#search-div').offset().top;
    var searchBoxHeight = $('#search-div').innerHeight();
    var searchBoxBottom = searchBoxTop + searchBoxHeight;
    if (event.key === 'Enter' && searchBoxBottom > windowTop && searchBoxTop < windowBottom) {
        var service = $('#' + $('#search-services').val());
        var query = $('#search-query').val();
        query = encodeURIComponent(query);
        if (query) {
            if ($('#search-query:focus').length > 0) {
                Cookies.set('byr_navi_previous_search_service_option', service.val(), { expires: 365 });
                window.open('redirect?next=' + encodeURIComponent(service.attr('data-url') + query + service.attr('data-suffix')), '_blank');
            } else {
                $('#search-query').focus().select();
            };
        } else {
            $('#search-div').addClass('error');
            $('#search-query').attr('placeholder', '请输入搜索内容').focus();
        };
    };
});

$('#search-query').keyup(function (event) {
    if (event.key) {
        if ($('#search-query').val()) {
            $('#search-div').removeClass('error');
            $('#search-query').attr('placeholder', '立即搜索');
        };
    };
});

$('.shortcuts .ui.label').each(function () {
    $(this).click(function () {
        var service = $('#' + $(this).attr('data-search-service-id'));
        var query = $('#search-query').val();
        query = encodeURIComponent(query);
        if (query) {
            Cookies.set('byr_navi_previous_search_service_option', service.val(), { expires: 365 });
            $('#search-services').dropdown('set selected', service.val());
            window.open('redirect?next=' + encodeURIComponent(service.attr('data-url') + query + service.attr('data-suffix')), '_blank');
        } else {
            $('#search-div').addClass('error');
            $('#search-query').attr('placeholder', '请输入搜索内容');
        };
    });
});

// query suggestions
var sugParams = {
    "XOffset": -3, //提示框位置横向偏移量,单位px
    "YOffset": -2, //提示框位置纵向偏移量,单位px
    // "width": $('#search-query').innerWidth(), //提示框宽度，单位px
    "fontColor": "rgba(0, 0, 0, 0.87)", //提示框文字颜色
    "fontColorHI": "rgba(0, 0, 0, 0.87)", //提示框高亮选择时文字颜色
    "fontSize": "14px", //文字大小
    "fontFamily": "Lato, 'Helvetica Neue', Arial, Helvetica, sans-serif", //文字字体
    "borderColor": "rgba(34, 36, 38, 0.14902)", //提示框的边框颜色
    "bgcolorHI": "rgba(0, 0, 0, 0.05)", //提示框高亮选择的颜色
    "sugSubmit": false //选中提示框中词条时是否提交表单
};
BaiduSuggestion.bind('search-query', sugParams);<|endoftext|>


<commit_before>const moment = require('moment');
const debug = require('debug')('app:server:components:CalendarUtils');
require('moment-range');

/**
 * Finds the number of working days in a given date range that also fall within the target month.
 * Holidays are not taken into account.
 *
 * Note that the targetMonth is zero-based (0=Jan, 11=Dec).
 *
 * startDate and endDate MUST be in UTC.  It is expected that both have zero for hours, minutes, seconds, and milliseconds.
 *
 * Sample google calendar date range:
 * "startDate" : ISODate("2015-12-14T00:00:00Z"), "endDate" : ISODate("2015-12-19T00:00:00Z")
 * This range is for an event that starts on 2015-12-14 and runs through the full day of 2015-12-18.  Notice
 * that Google handles full-day events by making the endDate midnight on the day AFTER the last day of the event.
 *
 * @param startDate Start date of the date range (inclusive).  Must be in UTC.
 * @param endDate End date of the date range (exclusive).  Must be in UTC.
 * @param targetMonth Zero-based month to search.  This is specified incase the range is not limited to a given month.
 * @param targetYear Year of the month to search.
 * @returns {number} Number of working days in the month.
 */
function findWorkdaysInRange(startDate, endDate, targetMonth, targetYear) {
  // Find the start and end of the target month.  Use UTC.
  const targetMonthStartDate = moment().utc().year(targetYear).month(targetMonth).startOf('month');
  const targetMonthEndDate = moment().utc().year(targetYear).month(targetMonth).endOf('month');
  const wholeMonthRange = moment.range(targetMonthStartDate, targetMonthEndDate);

  console.log('start date: ' + startDate.toISOString());
  console.log('end date: ' + endDate.toISOString());
  console.log('Month Range: ' + wholeMonthRange.toString());

  debug('Start Date %s End Date %s', startDate, endDate);
  debug('Whole month range "%s"', wholeMonthRange.toString());

  // Find the part of the date range that is completely within the month.
  let range = moment.range(moment(startDate).utc(), moment(endDate).utc().subtract(1, 'ms'));
  debug('Date range "%s"', range.toString());
  console.log('Date range: ', range.toString());

  range = range.intersect(wholeMonthRange);

  if (range === null) {
    debug('Dates are not within the specified month');
    return 0;
  }

  debug('Intersected date range "%s"', range.toString());

  let workdays = 0;
  range.by('days', (currentMoment) => {
    const currentDay = currentMoment.day();
    console.log('Day: ' + currentDay);
    if (currentDay !== 0 && currentDay !== 6) {
      // Increment all days that are not Saturday or Sunday
      workdays++;
    }
  });

  console.log('workdays: ' + workdays);

  return workdays;
}

module.exports = {findWorkdaysInRange};

<commit_msg>Removed debug console.log statements that snuck into the last branch<commit_after>const moment = require('moment');
const debug = require('debug')('app:server:components:CalendarUtils');
require('moment-range');

/**
 * Finds the number of working days in a given date range that also fall within the target month.
 * Holidays are not taken into account.
 *
 * Note that the targetMonth is zero-based (0=Jan, 11=Dec).
 *
 * startDate and endDate MUST be in UTC.  It is expected that both have zero for hours, minutes, seconds, and milliseconds.
 *
 * Sample google calendar date range:
 * "startDate" : ISODate("2015-12-14T00:00:00Z"), "endDate" : ISODate("2015-12-19T00:00:00Z")
 * This range is for an event that starts on 2015-12-14 and runs through the full day of 2015-12-18.  Notice
 * that Google handles full-day events by making the endDate midnight on the day AFTER the last day of the event.
 *
 * @param startDate Start date of the date range (inclusive).  Must be in UTC.
 * @param endDate End date of the date range (exclusive).  Must be in UTC.
 * @param targetMonth Zero-based month to search.  This is specified incase the range is not limited to a given month.
 * @param targetYear Year of the month to search.
 * @returns {number} Number of working days in the month.
 */
function findWorkdaysInRange(startDate, endDate, targetMonth, targetYear) {
  // Find the start and end of the target month.  Use UTC.
  const targetMonthStartDate = moment().utc().year(targetYear).month(targetMonth).startOf('month');
  const targetMonthEndDate = moment().utc().year(targetYear).month(targetMonth).endOf('month');
  const wholeMonthRange = moment.range(targetMonthStartDate, targetMonthEndDate);

  debug('Start Date %s End Date %s', startDate, endDate);
  debug('Whole month range "%s"', wholeMonthRange.toString());

  // Find the part of the date range that is completely within the month.
  let range = moment.range(moment(startDate).utc(), moment(endDate).utc().subtract(1, 'ms'));
  debug('Date range "%s"', range.toString());

  range = range.intersect(wholeMonthRange);

  if (range === null) {
    debug('Dates are not within the specified month');
    return 0;
  }

  debug('Intersected date range "%s"', range.toString());

  let workdays = 0;
  range.by('days', (currentMoment) => {
    const currentDay = currentMoment.day();
    if (currentDay !== 0 && currentDay !== 6) {
      // Increment all days that are not Saturday or Sunday
      workdays++;
    }
  });

  return workdays;
}

module.exports = {findWorkdaysInRange};

<|endoftext|>


<commit_before>import { Helmet } from "react-helmet";
import PropTypes from "prop-types";
import React from "react";
import styled from "styled-components";

import style from "@agir/front/genericComponents/_variables.scss";
import Link from "@agir/front/app/Link";
import Button from "@agir/front/genericComponents/Button";
import { Hide } from "@agir/front/genericComponents/grid";

const CONFIG = {
  events: {
    title: "Carte des événements",
    backLabel: "Liste des événements",
    backRoute: "events",
  },
  groups: {
    title: "Carte des groupes",
    backLabel: "Liste des groupes",
    backRoute: "groups",
  },
};
const Header = styled.header`
  width: 100%;
  height: 100px;
  text-align: center;
  position: relative;
  display: flex;
  flex-flow: column nowrap;
  align-items: center;
  justify-content: center;
  background-color: white;

  & > h1 {
    text-align: center;
    font-size: 1.25rem;
    line-height: 1.5;
    color: ${style.black1000};
    font-weight: 700;
    margin: 0;
  }

  & > ${Button} {
    position: absolute;
    left: 1.5rem;
    top: 50%;
    transform: translateY(-50%);

    @media (max-width: ${style.collapse}px) {
      display: none;
    }
  }

  & > a:last-child {
    font-size: 13px;
  }
`;

const Map = styled.iframe`
  margin: 0;
  padding: 0;
  width: 100%;
  height: 100%;
  height: calc(100vh - 172px);
  border: none;
  overflow: hidden;
`;

const MapPage = (props) => {
  const { user, type, mapURL, createLinkProps } = props;
  const { title, backRoute, backLabel } = CONFIG[type];

  return (

      <Helmet>
        <title>{title} - Action populaire</title>
      </Helmet>

        {user && (
          <Button link route={backRoute} icon="arrow-left">
            {backLabel}
          </Button>
        )}
        <Hide under as="h1">
          {title}
        </Hide>
        {user && <Link {...createLinkProps} />}

      <Map src={mapURL}></Map>

  );
};

MapPage.propTypes = {
  user: PropTypes.object,
  type: PropTypes.oneOf(["events", "groups"]),
  backRoute: PropTypes.string,
  mapURL: PropTypes.string,
  createLinkProps: PropTypes.shape({
    as: PropTypes.oneOf(["Link", "a"]),
    href: PropTypes.string,
    to: PropTypes.string,
    route: PropTypes.string,
    children: PropTypes.string,
  }),
};
export default MapPage;
<commit_msg>styles: fix map iframe to stick bottom of page<commit_after>import { Helmet } from "react-helmet";
import PropTypes from "prop-types";
import React from "react";
import styled from "styled-components";

import style from "@agir/front/genericComponents/_variables.scss";
import Link from "@agir/front/app/Link";
import Button from "@agir/front/genericComponents/Button";
import { Hide } from "@agir/front/genericComponents/grid";

const CONFIG = {
  events: {
    title: "Carte des événements",
    backLabel: "Liste des événements",
    backRoute: "events",
  },
  groups: {
    title: "Carte des groupes",
    backLabel: "Liste des groupes",
    backRoute: "groups",
  },
};
const Header = styled.header`
  width: 100%;
  height: 100px;
  text-align: center;
  position: relative;
  display: flex;
  flex-flow: column nowrap;
  align-items: center;
  justify-content: center;
  background-color: white;

  & > h1 {
    text-align: center;
    font-size: 1.25rem;
    line-height: 1.5;
    color: ${style.black1000};
    font-weight: 700;
    margin: 0;
  }

  & > ${Button} {
    position: absolute;
    left: 1.5rem;
    top: 50%;
    transform: translateY(-50%);

    @media (max-width: ${style.collapse}px) {
      display: none;
    }
  }

  & > a:last-child {
    font-size: 13px;
  }
`;

const Map = styled.iframe`
  margin: 0;
  padding: 0;
  border: none;
  overflow: hidden;
  width: 100%;
  height: 100%;
  height: calc(100vh - 172px);
  display: block;
  @media (max-width: ${style.collapse}px) {
    height: calc(100vh - 156px);
  }
`;

const MapPage = (props) => {
  const { user, type, mapURL, createLinkProps } = props;
  const { title, backRoute, backLabel } = CONFIG[type];

  return (

      <Helmet>
        <title>{title} - Action populaire</title>
      </Helmet>

        {user && (
          <Button link route={backRoute} icon="arrow-left">
            {backLabel}
          </Button>
        )}
        <Hide under as="h1">
          {title}
        </Hide>
        {user && <Link {...createLinkProps} />}

      <Map src={mapURL}></Map>

  );
};

MapPage.propTypes = {
  user: PropTypes.object,
  type: PropTypes.oneOf(["events", "groups"]),
  backRoute: PropTypes.string,
  mapURL: PropTypes.string,
  createLinkProps: PropTypes.shape({
    as: PropTypes.oneOf(["Link", "a"]),
    href: PropTypes.string,
    to: PropTypes.string,
    route: PropTypes.string,
    children: PropTypes.string,
  }),
};
export default MapPage;
<|endoftext|>