<commit_before>/**
 * Count how many times something is getting called, then display the result in
 * the console once the calls have slowed down.
 *
 * This is a reasonable alternative to console.trace() or console.count(), since
 * those both slow down the browser a ton if you've got 1000+ calls.
 *
 * Usage:
 *
 *  function somethingCool() {
 *    countMe("somethingCool");
 *    someStuff();
 *  };
 */
window.countMe = (function() {
  var count = {};
  var logger = {};
  return function(msg) {
    require(['ext/underscore'], function(_) {
      if (!logger[msg]) {
        logger[msg] = _.debounce(function() {
          console.log(msg, count[msg]);
        }, 100);
      }
      count[msg] = (count[msg] || 0) + 1;
      logger[msg]();
    });
  };
})();

require.config({
  shim: {
    'ext/backbone': {
      deps: ['ext/jquery', 'ext/underscore'],
      exports: 'Backbone'
    },
    // Not really needed since jQuery is already AMD-compliant, but just for
    // the sake of completeness
    'ext/jquery': {
      exports: '$'
    },
    'ext/jqueryui': {
      deps: ['ext/jquery']
    },
    'ext/bootstrap': {
      deps: ['ext/jquery']
    },
    'ext/select2': {
      deps: ['ext/jquery']
    },
    'ext/autosize': {
      deps: ['ext/jquery']
    },
    'ext/cookie': {
      deps: ['ext/jquery']
    },
    'ext/moment': {
      exports: 'moment'
    },
    'ext/slimScroll': {
      deps: ['ext/jquery', 'ext/jqueryui']
    },
    'ext/toastr': {
      deps: ['ext/jquery'],
      exports: 'toastr'
    },
    'ext/underscore': {
      exports: '_'
    },
    'ext/underscore.string': {
      deps: ['ext/underscore'],
      exports: function(_) {
        return _.string;
      }
    }
  },

  baseUrl: '/static/js/',

  paths: {
    'ext/backbone': 'ext/backbone-0.9.2',
    'ext/jquery': 'ext/jquery-1.8.1',
    'ext/bootstrap': 'ext/bootstrap-2.1.1',
    'ext/select2': 'ext/select2.min',
    'ext/autosize': 'ext/jquery.autosize',
    'ext/cookie': 'ext/jquery.cookie',
    'ext/slimScroll': 'ext/slimScroll-0.6.0',
    'ext/jqueryui': 'ext/jquery-ui-1.8.23.custom.min',
    'ext/toastr': 'ext/toastr',
    'ext/underscore': 'ext/underscore-1.3.3',
    'ext/underscore.string': 'ext/underscore.string-2.0.0',

    'moment': 'ext/moment',
    'moment-timezone': 'ext/moment-timezone'
  }
});

// Underscore and jQuery need to be loaded first, otherwise RequireJS might try
// to execute things that depend on them first since loading is async
require(['ext/underscore', 'ext/jquery'], function(_, $) {

window._ = _;
window.$ = $;
window.jQuery = $;

require(['ext/underscore.string', 'util', 'rmc_moment',
    'ext/backbone', 'ext/bootstrap', 'ext/cookie', 'ext/toastr',
    'points', 'user', 'facebook', 'work_queue'],
function(_s, util, moment, Backbone, __, __, toastr, _points,
  _user, _facebook) {

  // Add helpers functions to all templates
  (function() {
    var template = _.template;

    // TODO(mack): move templateHelpers into own file
    var templateHelpers = {
      _: _,
      _s: _s,
      pluralize: util.pluralize,
      getDisplayRating: util.getDisplayRating,
      moment: moment,
      capitalize: util.capitalize,
      humanizeTermId: util.humanizeTermId,
      humanizeProfId: util.humanizeProfId,
      sectionTypeToCssClass: util.sectionTypeToCssClass,
      splitCourseId: util.splitCourseId,
      termIdToQuestId: util.termIdToQuestId
    };

    _.template = function(templateString, data, settings) {
      templateString = templateString || '';
      if (data) {
        data = _.extend({}, templateHelpers, data);
        return template(templateString, data, settings);
      } else {
        var compiled = template(templateString);
        return function(data, settings) {
          data = _.extend({}, templateHelpers, data);
          return compiled(data, settings);
        };
      }
    };
  })();

  // Set defaults for toastr notifications
  toastr.options = {
    timeOut: 3000
  };

  (function() {
    if ($.fn.tooltip !== undefined && $.fn.popover !== undefined) {
      // Override bootstrap with saner defaults
      var overrides = {
        animation: false
      };
      _.extend($.fn.tooltip.defaults, overrides);
      _.extend($.fn.popover.defaults, overrides);
    }
  })();

  // TODO(mack): separate code inside into functions
  var onDomReady = function() {
    $('.navbar [title]').tooltip({ placement: 'bottom' });
    $('.navbar .signout-btn').click(function() {
      window.location.href = '/?logout=1';
    });

    if (window.pageData.userObjs) {
      _user.UserCollection.addToCache(window.pageData.userObjs);
    }

    var currentUser = _user.getCurrentUser();
    if (currentUser) {
      var userPointsView = new _points.PointsView({ model: currentUser });
      $('#user-points-placeholder').replaceWith(userPointsView.render().$el);
    }

    if (window.pageData.pageScript) {
      require([window.pageData.pageScript]);
    }

    var $footer = $('footer');
    if ($footer.length &&
          !_.contains(['/', '/courses'], window.location.pathname)) {
      // TODO(david): Use jpg and have it fade out into bg color
      $footer.css('background',
        'url(/static/img/footer_uw_sphere_short.png) right top no-repeat');
    }

    $(document.body).on('pageScriptComplete', function(evt) {
      $('[rel="tooltip"]').tooltip();
      $(document.body).data('rendered', true);
    });

    // TODO(Sandy): Uncomment this after testing the new login stuff a bit
    // TODO(Sandy): We don't use these cookies anymore, so remove them from the
    // client. This code block can be removed in a few months (Sept 29, 2013)
    //$.removeCookie('fbid', { path: '/' });
    //$.removeCookie('fb_access_token', { path: '/' });
    //$.removeCookie('fb_access_token_expires_on', { path: '/' });
  };

  // IF the dom ready event has already occurred, binding to jQuery's dom
  // ready listener waits until the loaded event before firing.
  // So manually check if domready has occurred, and if it has execute
  // right away. In IE, gotta wait for state === 'complete' since
  // state === 'interactive' could fire before dom is ready. See
  // https://github.com/divad12/rmc/commit/56af16db497db5b8d4e210e784e9f63051fcce32
  // for more info.
  var state = document.readyState;
  if (document.attachEvent ? state === 'complete' : state !== 'loading' ) {
    onDomReady();
  } else {
    $(onDomReady);
  }

});

});
<commit_msg>Remove cookies for fbid and fb_access_token<commit_after>/**
 * Count how many times something is getting called, then display the result in
 * the console once the calls have slowed down.
 *
 * This is a reasonable alternative to console.trace() or console.count(), since
 * those both slow down the browser a ton if you've got 1000+ calls.
 *
 * Usage:
 *
 *  function somethingCool() {
 *    countMe("somethingCool");
 *    someStuff();
 *  };
 */
window.countMe = (function() {
  var count = {};
  var logger = {};
  return function(msg) {
    require(['ext/underscore'], function(_) {
      if (!logger[msg]) {
        logger[msg] = _.debounce(function() {
          console.log(msg, count[msg]);
        }, 100);
      }
      count[msg] = (count[msg] || 0) + 1;
      logger[msg]();
    });
  };
})();

require.config({
  shim: {
    'ext/backbone': {
      deps: ['ext/jquery', 'ext/underscore'],
      exports: 'Backbone'
    },
    // Not really needed since jQuery is already AMD-compliant, but just for
    // the sake of completeness
    'ext/jquery': {
      exports: '$'
    },
    'ext/jqueryui': {
      deps: ['ext/jquery']
    },
    'ext/bootstrap': {
      deps: ['ext/jquery']
    },
    'ext/select2': {
      deps: ['ext/jquery']
    },
    'ext/autosize': {
      deps: ['ext/jquery']
    },
    'ext/cookie': {
      deps: ['ext/jquery']
    },
    'ext/moment': {
      exports: 'moment'
    },
    'ext/slimScroll': {
      deps: ['ext/jquery', 'ext/jqueryui']
    },
    'ext/toastr': {
      deps: ['ext/jquery'],
      exports: 'toastr'
    },
    'ext/underscore': {
      exports: '_'
    },
    'ext/underscore.string': {
      deps: ['ext/underscore'],
      exports: function(_) {
        return _.string;
      }
    }
  },

  baseUrl: '/static/js/',

  paths: {
    'ext/backbone': 'ext/backbone-0.9.2',
    'ext/jquery': 'ext/jquery-1.8.1',
    'ext/bootstrap': 'ext/bootstrap-2.1.1',
    'ext/select2': 'ext/select2.min',
    'ext/autosize': 'ext/jquery.autosize',
    'ext/cookie': 'ext/jquery.cookie',
    'ext/slimScroll': 'ext/slimScroll-0.6.0',
    'ext/jqueryui': 'ext/jquery-ui-1.8.23.custom.min',
    'ext/toastr': 'ext/toastr',
    'ext/underscore': 'ext/underscore-1.3.3',
    'ext/underscore.string': 'ext/underscore.string-2.0.0',

    'moment': 'ext/moment',
    'moment-timezone': 'ext/moment-timezone'
  }
});

// Underscore and jQuery need to be loaded first, otherwise RequireJS might try
// to execute things that depend on them first since loading is async
require(['ext/underscore', 'ext/jquery'], function(_, $) {

window._ = _;
window.$ = $;
window.jQuery = $;

require(['ext/underscore.string', 'util', 'rmc_moment',
    'ext/backbone', 'ext/bootstrap', 'ext/cookie', 'ext/toastr',
    'points', 'user', 'facebook', 'work_queue'],
function(_s, util, moment, Backbone, __, __, toastr, _points,
  _user, _facebook) {

  // Add helpers functions to all templates
  (function() {
    var template = _.template;

    // TODO(mack): move templateHelpers into own file
    var templateHelpers = {
      _: _,
      _s: _s,
      pluralize: util.pluralize,
      getDisplayRating: util.getDisplayRating,
      moment: moment,
      capitalize: util.capitalize,
      humanizeTermId: util.humanizeTermId,
      humanizeProfId: util.humanizeProfId,
      sectionTypeToCssClass: util.sectionTypeToCssClass,
      splitCourseId: util.splitCourseId,
      termIdToQuestId: util.termIdToQuestId
    };

    _.template = function(templateString, data, settings) {
      templateString = templateString || '';
      if (data) {
        data = _.extend({}, templateHelpers, data);
        return template(templateString, data, settings);
      } else {
        var compiled = template(templateString);
        return function(data, settings) {
          data = _.extend({}, templateHelpers, data);
          return compiled(data, settings);
        };
      }
    };
  })();

  // Set defaults for toastr notifications
  toastr.options = {
    timeOut: 3000
  };

  (function() {
    if ($.fn.tooltip !== undefined && $.fn.popover !== undefined) {
      // Override bootstrap with saner defaults
      var overrides = {
        animation: false
      };
      _.extend($.fn.tooltip.defaults, overrides);
      _.extend($.fn.popover.defaults, overrides);
    }
  })();

  // TODO(mack): separate code inside into functions
  var onDomReady = function() {
    $('.navbar [title]').tooltip({ placement: 'bottom' });
    $('.navbar .signout-btn').click(function() {
      window.location.href = '/?logout=1';
    });

    if (window.pageData.userObjs) {
      _user.UserCollection.addToCache(window.pageData.userObjs);
    }

    var currentUser = _user.getCurrentUser();
    if (currentUser) {
      var userPointsView = new _points.PointsView({ model: currentUser });
      $('#user-points-placeholder').replaceWith(userPointsView.render().$el);
    }

    if (window.pageData.pageScript) {
      require([window.pageData.pageScript]);
    }

    var $footer = $('footer');
    if ($footer.length &&
          !_.contains(['/', '/courses'], window.location.pathname)) {
      // TODO(david): Use jpg and have it fade out into bg color
      $footer.css('background',
        'url(/static/img/footer_uw_sphere_short.png) right top no-repeat');
    }

    $(document.body).on('pageScriptComplete', function(evt) {
      $('[rel="tooltip"]').tooltip();
      $(document.body).data('rendered', true);
    });

    // TODO(Sandy): We don't use these cookies anymore, so remove them from the
    // client. Though this doesn't matter as much anymore, now that we're on
    // HTTPS. This code block can be removed in a few months (Feb. 19, 2014)
    $.removeCookie('fbid', { path: '/' });
    $.removeCookie('fb_access_token', { path: '/' });
    $.removeCookie('fb_access_token_expires_on', { path: '/' });
  };

  // IF the dom ready event has already occurred, binding to jQuery's dom
  // ready listener waits until the loaded event before firing.
  // So manually check if domready has occurred, and if it has execute
  // right away. In IE, gotta wait for state === 'complete' since
  // state === 'interactive' could fire before dom is ready. See
  // https://github.com/divad12/rmc/commit/56af16db497db5b8d4e210e784e9f63051fcce32
  // for more info.
  var state = document.readyState;
  if (document.attachEvent ? state === 'complete' : state !== 'loading' ) {
    onDomReady();
  } else {
    $(onDomReady);
  }

});

});
<|endoftext|>


<commit_before>/**
 * @license
 * priest 0.0.1 <https://ianramosc.github.io/priest>
 * Copyright 2016 Ian Ramos <https://github.com/ianramosc>
 * Available under MIT license <https://github.com/ianramosc/priest>
 */
;(function() {

	'use strict';

	/**
	 * Semantic Version
	 * @const {string}
	 */
	var VERSION = '0.0.1';

	/**
	 * @private
	 * @param {string} msg
	 * @returns {object} Error
	 */
	var error = function(msg) {
		throw new Error(msg);
	};

	/**
	 * @private
	 * @param {string} msg
	 */
	var warn = function(msg) {
		console.log('WARNING:', msg);
	};

	/**
	 * @private
	 * @param {*} value The value to test
	 * @returns {number} `value` itself if it's not a number, throws an error otherwise
	 * @example
	 *
	 *     isValidNum(8173); //=> 8173
	 *     isValidNum(true); //=> Error
	 */
	var isValidNum = function(value) {
		// First test if `value` isn't null
		if ( value !== null ) {
			if ( !isNaN(value) ) {
				return value;
			} else {
				error("This function only accept numbers.");
			}
		} else {
			error("You can't convert a null value.");
		}
	};

	var UNITS = {

		distance: {
			'ly': {
				name: 'light-year',
				base: 9.460731e+15
			},
			'km': {
				name: 'kilometer',
				base: 1000,
			},
			'hm': {
				name: 'hectometer',
				base: 100,
			},
			'dam': {
				name: 'decameter',
				base: 10,
			},
			'm': {
				name: 'meter',
				base: 1
			},
			'dm': {
				name: 'decimeter',
				base: 0.1
			},
			'cm': {
				name: 'centimeter',
				base: 0.01
			},
			'mm': {
				name: 'milimeter',
				base: 0.001
			},
      'um': {
        name: 'micrometer',
        base: 0.000001
      },

			//SI
			'mi': {
				name: 'mile',
				base: 1609.344
			},
			'in': {
				name: 'inch',
				base: 0.0254
			},
			'ft': {
				name: 'feet',
				base: 0.3048
			},
			'yd': {
				name: 'yard',
				base: 0.9144
			}
		},

		time: {
			'y': {
				name: 'year',
				base: 31536000
			},
			'w': {
				name: 'week',
				base: 604800
			},
			'd': {
				name: 'day',
				base: 86400
			},
			'hr': {
				name: 'hour',
				base: 3600
			},
			'min': {
				name: 'minute',
				base: 60,
			},
			's': {
				name: 'second',
				base: 1,
			},
			'ds': {
				name: 'decisecond',
				base: 0.1,
			},
			'cs': {
				name: 'centisecond',
				base: 0.01,
			},
			'ms': {
				name: 'miliseconds',
				base: 0.001,
			}
		},

	};

	var basicConversion = function(toName){
		var baseTo = UNITS[Priest.value.type][toName];
		var baseFrom = UNITS[Priest.value.type][Priest.value.name];

		return (Priest.value.value * baseFrom.base) / baseTo.base;
	};

	var basicConverterCreator = function(name) {
		return function() {
			return basicConversion(name);
		};
	};

	var converter = {};

	converter.distance = {
		toLightyears: basicConverterCreator('ly'),
		toKilometers: basicConverterCreator('km'),
		toHectometers: basicConverterCreator('hm'),
		toDecameters: basicConverterCreator('dam'),
		toMeters: basicConverterCreator('m'),
		toDecimeters: basicConverterCreator('dm'),
		toCentimeters: basicConverterCreator('cm'),
		toMilimimeters: basicConverterCreator('mm'),
    toMicrometers: basicConverterCreator('um'),

		toMiles: basicConverterCreator('mi'),
		toInches: basicConverterCreator('in'),
		toFeets: basicConverterCreator('ft'),
		toYards: basicConverterCreator('yd'),
	};

	converter.time = {
		toYears: basicConverterCreator('y'),
		toWeeks: basicConverterCreator('w'),
		toDays: basicConverterCreator('d'),
		toHours: basicConverterCreator('hr'),
		toMinutes: basicConverterCreator('min'),
		toSeconds: basicConverterCreator('s'),
		toDeciseconds: basicConverterCreator('ds'),
		toCentiseconds: basicConverterCreator('cs'),
		toMiliseconds: basicConverterCreator('ms'),
	};

	var helperCreator = function(name, type) {
		return function(value) {
			var _this  = this;

			if (isValidNum(value)) {
				_this.setValue({
					name: name,
					value: value,
					type: type
				});
			}

			return converter[type];
		}
	};

	var helpers = {
		//Distance
		Lightyears: helperCreator('ly', 'distance'),
		Kilometers: helperCreator('km', 'distance'),
		Hectometers: helperCreator('hm', 'distance'),
		Decameters: helperCreator('dam', 'distance'),
		Meters: helperCreator('m', 'distance'),
		Decimeters: helperCreator('dm', 'distance'),
		Centimeters: helperCreator('cm', 'distance'),
		Milimeters: helperCreator('mm', 'distance'),
    Micrometers: helpers('um', 'distance'),
		//SI
		Miles: helperCreator('mi', 'distance'),
		Inches: helperCreator('in', 'distance'),
		Feets: helperCreator('ft', 'distance'),
		Yards: helperCreator('yd', 'distance'),

		//Time
		Years: helperCreator('y', 'time'),
		Weeks: helperCreator('w', 'time'),
		Days: helperCreator('d', 'time'),
		Hours: helperCreator('hr', 'time'),
		Minutes: helperCreator('min', 'time'),
		Seconds: helperCreator('s', 'time'),
		Deciseconds: helperCreator('ds', 'time'),
		Centiseconds: helperCreator('cs', 'time'),
		Miliseconds: helperCreator('ms', 'time'),

	}

	var PriestConstructor = function() {
		this.value = '';

		this.setValue = function(obj) {
			if ( typeof obj === 'object' && !!obj ) {
				if(!!obj.name && !!obj.value && !!obj.type) {
					this.value = obj;
				}
			} else {
				error('Expected an object');
			}
		};
	};

	PriestConstructor.prototype = helpers;

	var Priest = new PriestConstructor();

	window.Priest = Priest;
	window.Priest.version = VERSION;

})();
<commit_msg>fixed function name within 'helpers' and added NauticalMiles<commit_after>/**
 * @license
 * priest 0.0.1 <https://ianramosc.github.io/priest>
 * Copyright 2016 Ian Ramos <https://github.com/ianramosc>
 * Available under MIT license <https://github.com/ianramosc/priest>
 */
;(function() {

	'use strict';

	/**
	 * Semantic Version
	 * @const {string}
	 */
	var VERSION = '0.0.1';

	/**
	 * @private
	 * @param {string} msg
	 * @returns {object} Error
	 */
	var error = function(msg) {
		throw new Error(msg);
	};

	/**
	 * @private
	 * @param {string} msg
	 */
	var warn = function(msg) {
		console.log('WARNING:', msg);
	};

	/**
	 * @private
	 * @param {*} value The value to test
	 * @returns {number} `value` itself if it's not a number, throws an error otherwise
	 * @example
	 *
	 *     isValidNum(8173); //=> 8173
	 *     isValidNum(true); //=> Error
	 */
	var isValidNum = function(value) {
		// First test if `value` isn't null
		if ( value !== null ) {
			if ( !isNaN(value) ) {
				return value;
			} else {
				error("This function only accept numbers.");
			}
		} else {
			error("You can't convert a null value.");
		}
	};

	var UNITS = {

		distance: {
			'ly': {
				name: 'light-year',
				base: 9.460731e+15
			},
			'km': {
				name: 'kilometer',
				base: 1000,
			},
			'hm': {
				name: 'hectometer',
				base: 100,
			},
			'dam': {
				name: 'decameter',
				base: 10,
			},
			'm': {
				name: 'meter',
				base: 1
			},
			'dm': {
				name: 'decimeter',
				base: 0.1
			},
			'cm': {
				name: 'centimeter',
				base: 0.01
			},
			'mm': {
				name: 'milimeter',
				base: 0.001
			},
      'um': {
        name: 'micrometer',
        base: 0.000001
      },

			//SI
			'mi': {
				name: 'mile',
				base: 1609.344
			},
      'nmi': {
        name: 'nautical mile',
        base: 1852
      },
			'in': {
				name: 'inch',
				base: 0.0254
			},
			'ft': {
				name: 'feet',
				base: 0.3048
			},
			'yd': {
				name: 'yard',
				base: 0.9144
			}
		},

		time: {
			'y': {
				name: 'year',
				base: 31536000
			},
			'w': {
				name: 'week',
				base: 604800
			},
			'd': {
				name: 'day',
				base: 86400
			},
			'hr': {
				name: 'hour',
				base: 3600
			},
			'min': {
				name: 'minute',
				base: 60,
			},
			's': {
				name: 'second',
				base: 1,
			},
			'ds': {
				name: 'decisecond',
				base: 0.1,
			},
			'cs': {
				name: 'centisecond',
				base: 0.01,
			},
			'ms': {
				name: 'miliseconds',
				base: 0.001,
			}
		},

	};

	var basicConversion = function(toName){
		var baseTo = UNITS[Priest.value.type][toName];
		var baseFrom = UNITS[Priest.value.type][Priest.value.name];

		return (Priest.value.value * baseFrom.base) / baseTo.base;
	};

	var basicConverterCreator = function(name) {
		return function() {
			return basicConversion(name);
		};
	};

	var converter = {};

	converter.distance = {
		toLightyears: basicConverterCreator('ly'),
		toKilometers: basicConverterCreator('km'),
		toHectometers: basicConverterCreator('hm'),
		toDecameters: basicConverterCreator('dam'),
		toMeters: basicConverterCreator('m'),
		toDecimeters: basicConverterCreator('dm'),
		toCentimeters: basicConverterCreator('cm'),
		toMilimimeters: basicConverterCreator('mm'),
    toMicrometers: basicConverterCreator('um'),

		toMiles: basicConverterCreator('mi'),
    toNauticalMiles: basicConverterCreator('nmi'),
		toInches: basicConverterCreator('in'),
		toFeets: basicConverterCreator('ft'),
		toYards: basicConverterCreator('yd'),
	};

	converter.time = {
		toYears: basicConverterCreator('y'),
		toWeeks: basicConverterCreator('w'),
		toDays: basicConverterCreator('d'),
		toHours: basicConverterCreator('hr'),
		toMinutes: basicConverterCreator('min'),
		toSeconds: basicConverterCreator('s'),
		toDeciseconds: basicConverterCreator('ds'),
		toCentiseconds: basicConverterCreator('cs'),
		toMiliseconds: basicConverterCreator('ms'),
	};

	var helperCreator = function(name, type) {
		return function(value) {
			var _this  = this;

			if (isValidNum(value)) {
				_this.setValue({
					name: name,
					value: value,
					type: type
				});
			}

			return converter[type];
		}
	};

	var helpers = {
		//Distance
		Lightyears: helperCreator('ly', 'distance'),
		Kilometers: helperCreator('km', 'distance'),
		Hectometers: helperCreator('hm', 'distance'),
		Decameters: helperCreator('dam', 'distance'),
		Meters: helperCreator('m', 'distance'),
		Decimeters: helperCreator('dm', 'distance'),
		Centimeters: helperCreator('cm', 'distance'),
		Milimeters: helperCreator('mm', 'distance'),
    Micrometers: helperCreator('um', 'distance'),
		//SI
		Miles: helperCreator('mi', 'distance'),
    NauticalMiles: helperCreator('nmi', 'distance'),
		Inches: helperCreator('in', 'distance'),
		Feets: helperCreator('ft', 'distance'),
		Yards: helperCreator('yd', 'distance'),

		//Time
		Years: helperCreator('y', 'time'),
		Weeks: helperCreator('w', 'time'),
		Days: helperCreator('d', 'time'),
		Hours: helperCreator('hr', 'time'),
		Minutes: helperCreator('min', 'time'),
		Seconds: helperCreator('s', 'time'),
		Deciseconds: helperCreator('ds', 'time'),
		Centiseconds: helperCreator('cs', 'time'),
		Miliseconds: helperCreator('ms', 'time'),

	}

	var PriestConstructor = function() {
		this.value = '';

		this.setValue = function(obj) {
			if ( typeof obj === 'object' && !!obj ) {
				if(!!obj.name && !!obj.value && !!obj.type) {
					this.value = obj;
				}
			} else {
				error('Expected an object');
			}
		};
	};

	PriestConstructor.prototype = helpers;

	var Priest = new PriestConstructor();

	window.Priest = Priest;
	window.Priest.version = VERSION;

})();
<|endoftext|>


<commit_before>/**
 Allows user to send messages to the Telegram API.
 */

const TelegramBot = require('node-telegram-bot-api');
const config = require('../../config');

const token = config.telegram.authToken;

const bot = new TelegramBot(token, { polling: false });

module.exports = {
  sendMessage(subarea, message) {
    bot.sendMessage(config.telegram.chats[subarea], message);
  },
  sendHint(subarea, lat, lng, address) {
    bot.sendMessage(config.telegram.chats[subarea], `🧩 ${subarea} naar ${address}. Toon op Google Maps: https://www.google.com/maps/search/?api=1&query=${lat},${lng}`);
    bot.sendLocation(config.telegram.chats[subarea], lat, lng);
  },
  sendHunt(subarea, lat, lng, address, createdAt) {
    // Get next hunt time
    createdAtDate = new Date(createdAt);
    createdAtDate.setHours(createdAtDate.getHours() + 1)
    const time = (createdAtDate.getHours()+2) + ':' + createdAtDate.getMinutes();

    bot.sendMessage(config.telegram.chats[subarea], `🔫 Hunt op ${address} voor ${subarea}!
      1. Geef correcte tijd en locatie door aan de thuisbasis.
      2. Vul je hunt in via www.jotihunt.net met gebruikersnaam \`jotihunt@scouting-ijsselgroep.nl\` en wachtwoord
\`scouting70lordbaden\`.
      3. De vossen mogen pas om ${time} uur weer gehunt worden.
      4. Bepaal de taktiek voor het komende uur.`);
    // bot.sendLocation(config.telegram.chats[subarea], lat, lng);
  },
  sendSimpleLocation(subarea, lat, lng, address) {
    bot.sendMessage(config.telegram.chats[subarea], `Een tussenstop op ${address}. Toon op Google Maps: https://www.google.com/maps/search/?api=1&query=${lat},${lng}`);
    bot.sendLocation(config.telegram.chats[subarea], lat, lng);
  },
};
<commit_msg>Update index.js<commit_after>/**
 Allows user to send messages to the Telegram API.
 */

const TelegramBot = require('node-telegram-bot-api');
const config = require('../../config');

const token = config.telegram.authToken;

const bot = new TelegramBot(token, { polling: false });

module.exports = {
  sendMessage(subarea, message) {
    bot.sendMessage(config.telegram.chats[subarea], message);
  },
  sendHint(subarea, lat, lng, address) {
    bot.sendMessage(config.telegram.chats[subarea], `🧩 ${subarea} naar ${address}. Toon op Google Maps: https://www.google.com/maps/search/?api=1&query=${lat},${lng}`);
    bot.sendLocation(config.telegram.chats[subarea], lat, lng);
  },
  sendHunt(subarea, lat, lng, address, createdAt) {
    // Get next hunt time
    createdAtDate = new Date(createdAt);
    createdAtDate.setHours(createdAtDate.getHours() + 1)
    const time = (createdAtDate.getHours()+2) + ':' + createdAtDate.getMinutes();

    bot.sendMessage(config.telegram.chats[subarea], `🔫 Hunt op ${address} voor ${subarea}!
      1. Geef correcte tijd en locatie door aan de thuisbasis.
      2. Vul je hunt in via www.jotihunt.net met gebruikersnaam \`jotihunt@scouting-ijsselgroep.nl\` en wachtwoord
\`scouting70lordbaden\`.
      3. De vossen mogen pas om ${time} uur weer gehunt worden.
      4. Bepaal de taktiek voor het komende uur.`);
    // bot.sendLocation(config.telegram.chats[subarea], lat, lng);
  },
  sendSimpleLocation(subarea, lat, lng, address) {
    bot.sendMessage(config.telegram.chats[subarea], `${subarea} op ${address}. Toon op Google Maps: https://www.google.com/maps/search/?api=1&query=${lat},${lng}`);
    bot.sendLocation(config.telegram.chats[subarea], lat, lng);
  },
};
<|endoftext|>


<commit_before>var Comment = require('../models/comments');
var Idea = require('../models/ideas');
var User = require('../models/users');
var Vote = require('../models/votes');
var request = require('request');

function slackInt (req, res){
  // TO-DOs
  // parse req.body.text --> parse out title, parse out text
  // need to return text with unique id
    // create hyperlink for unique id
  // making a descriptive unique id from the title itself
  // also include a slash command to return a list of all active ideas with their info

  // Need to return: "Idea posted to IdeaList! " +'|'+ <uniqueIdeaId> +'|'+ ideaText;
  var parsed = req.body.text.split("|");

  User.findOne({ sUserName: req.body.user_name }, function (err, user) {
        req.body.userId = user._id;
    }
  );

  // logic for inserting idea vs comment vs vote into db
  switch(req.body.command){
    case '/idea':
      req.body.shortId = parsed[0].split(" ").join("_")+"_"+req.body.user_name;
      req.body.body = parsed[1];
      req.body.title = parsed[0];
      var reply = { 'text': 'Idea posted to ideaList: ' + req.body.shortId + ' ' + req.body.body };
      createIdea(req, res);
      break;
    case '/comment':

      break;
    case '/upvote':

      break;
    case '/downvote':

      break;
    default:
      console.log("No dice.");
  }

  request({ method: 'POST',
    uri: process.env.SLACK_WEBHOOK,
    body: JSON.stringify(reply)
    },
    function (error, response, body) {
      if(error) console.log(error);
    }
  );
}

function getIdeas (req, res) {
  req.headers.query = req.headers.query || "";
  var ideas;

  var selectFields = 'createdAt updatedAt shortId userId slackId sUserName title body tags active voters upvotes downvotes rating';

  switch (req.headers.query) {
    case 'dateFirst':
      ideas = Idea.find()
                .select(selectFields)
                .sort('-updatedAt')
                .limit(10);
      break;
    case 'dateLast':
      ideas = Idea.find()
                .select(selectFields)
                .sort('updatedAt')
                .limit(10);
      break;
    case 'votes':
      ideas = Idea.find()
                .select(selectFields)
                .sort('-rating')
                .limit(10);
      break;
    case 'tags':
    //add username to tags array for easy find of people also.
      ideas = Idea.find({ tags: { $in:req.headers.tags } })
                .select(selectFields)
                .limit(10);
      break;
    case 'userId':
      ideas = Idea.find({ userId:req.headers.userId })
                .select(selectFields);
      break;
    default:
    //custom query (to do when need arises)
      console.log('cant cant cant');
  }

  var results = [];

  ideas.exec(function (data) {
    results.push(data);
  });

  res.end(JSON.stringify(results));
} // end getIdeas

function createIdea (req, res) {
  var now = Date.now();

  var idea = new Idea({
    createdAt    : now,
    updatedAt    : now,
    shortId      : req.body.shortId,
    userId       : req.body.userId,
    slackId      : slackId || req.body.slackId, // <-- slackId?
    sUserName    : req.body.user_name || null,
    sTeamId      : req.body.team_id || null,
    sChannelId   : req.body.channel_id || null,
    sChannelName : req.body.channel_name || null,
    sTeamDomain  : req.body.team_domain || null,
    sCommand     : req.body.command || null,
    title        : title || req.body.title || null,
    body         : text || req.body.body || null,
    tags         : req.body.tags,
    active       : true
  });

  idea.save(function (err) {
    if (err) console.log(err);
    console.log('New idea', idea.title, 'saved');
  });

  res.end();
} // end createIdea

function createComment (req, res) {
  var now = Date.now();

  User.findOne({ sUserName: req.body.user_name }, function (err, user) {
    console.log('User:', user.sUserName);

    if (!req.body.userId) {
      req.body.userId = user._id;
    }
  });

  // If from Slack, assign text to body
  if (!req.body.body) {
    req.body.body = req.body.text;
  }

  // If from Slack, set req.body.parentId to mongo _id (looked up from shortId)

  var newComment = new Comment({
    createdAt : now,
    updatedAt : now,
    parentId  : req.body.parentId,
    userId    : req.body.userId,
    slackId   : req.body.slackId,
    body      : req.body.body
  });

  // Assumes comment request comes with a parentType
  if (req.body.parentType === 'idea') {
    Idea.findOne({ _id: req.body.parentId }, function (err, idea) {
      console.log('Idea shortId:', idea.shortId);

      idea.comments.push(newComment);
    });
  }

  if (req.body.parentType === 'comment') {
    Idea.findOne({ _id: req.body.rootId }, function (err, idea) {
      console.log('Root idea shortId:', idea.shortId);

      insertComment(idea);

      // Traverse comment tree to find parent of comment
      function insertComment (node) {
        node.comments.map(function (comment) {
          if (comment._id === req.body.parentId) {
            comment.comments.push(newComment);
            res.end();
            return;
          } else {
            insertComment(comment);
          }
        });
      }
    });
  }
  //   console.log('New comment "' + comment.body.substr(0, 10) + '"saved')

  res.end();
} // end createComment

function downvote (req, res) {
  var now = Date.now();

  var newDownvote = new Vote({
    createdAt : now,
    voter     : req.body.user_name // Slack username
  });

  if (req.body.type === 'idea') {
    Idea.find({ shortId: req.body.shortId }, function (err, idea) {
      idea.voters.map(function (voter) {
        if (voter === req.body.slackId) {
          res.status(403).send('Voting only allowed once');
        }
      });

      idea.voters.push(req.body.slackId);
      idea.downvotes.push(newDownvote);
      idea.rating = idea.upvotes.length - idea.downvotes.length;
    });
  }

  if (req.body.type === 'comment') {
    Comment.find({ shortId: req.body.shortId }, function (err, comment) {
      comment.voters.map(function (voter) {
        if (voter === req.body.slackId) {
          res.status(403).send('Voting only allowed once');
        }
      });

      comment.voters.push(req.body.slackId);
      comment.downvotes.push(downvote);
      comment.rating = comment.upvotes.length - comment.downvotes.length;
    });
  }

  res.end();
} // end downvote

function upvote (req, res) {
  var now = Date.now();

  var newUpvote = new Vote({
    createdAt : now,
    voter     : req.body.user_name // Slack username
  });

  if (req.body.type === 'idea') {
    Idea.find({ shortId: req.body.shortId }, function (err, idea) {
      idea.voters.map(function (voter) {
        if (voter === req.body.slackId) {
          res.status(403).send('Voting only allowed once');
        }
      });

      idea.voters.push(req.body.slackId);
      idea.upvotes.push(newUpvote);
      idea.rating = idea.upvotes.length - idea.downvotes.length;
    });
  }

  if (req.body.type === 'comment') {
    Comment.find({ shortId: req.body.shortId }, function (err, comment) {
      comment.voters.map(function (voter) {
        if (voter === req.body.slackId) {
          res.status(403).send('Voting only allowed once');
        }
      });

      comment.voters.push(req.body.slackId);
      comment.upvotes.push(upvote);
      comment.rating = comment.upvotes.length - comment.downvotes.length;
    });
  }

  res.end();
} // end upvote

// expose functions
module.exports = {
  getIdeas: getIdeas,
  createIdea: createIdea,
  createComment: createComment,
  downvote: downvote,
  upvote: upvote,
  slackInt: slackInt
};
<commit_msg>Idea creation bug fixes<commit_after>var Comment = require('../models/comments');
var Idea = require('../models/ideas');
var User = require('../models/users');
var Vote = require('../models/votes');
var request = require('request');

function slackInt (req, res){
  // TO-DOs
  // parse req.body.text --> parse out title, parse out text
  // need to return text with unique id
    // create hyperlink for unique id
  // making a descriptive unique id from the title itself
  // also include a slash command to return a list of all active ideas with their info

  // Need to return: "Idea posted to IdeaList! " +'|'+ <uniqueIdeaId> +'|'+ ideaText;
  var parsed = req.body.text.split("|");

  User.findOne({ sUserName: req.body.user_name }, function (err, user) {
        req.body.userId = user._id;
    }
  );

  // logic for inserting idea vs comment vs vote into db
  switch(req.body.command){
    case '/idea':
      req.body.shortId = parsed[0].split(" ").join("_")+"_"+req.body.user_name;
      req.body.title = parsed[0];
      req.body.body = parsed[1];
      if (parsed.length === 3) {
        req.body.tags = parsed[2].split(' ');
      }
      var reply = { 'text': 'Idea posted to ideaList: ' + req.body.shortId + ' ' + req.body.body };
      createIdea(req, res);
      break;
    case '/comment':

      break;
    case '/upvote':

      break;
    case '/downvote':

      break;
    default:
      console.log("No dice.");
  }

  request({ method: 'POST',
    uri: process.env.SLACK_WEBHOOK,
    body: JSON.stringify(reply)
    },
    function (error, response, body) {
      if(error) console.log(error);
    }
  );
}

function getIdeas (req, res) {
  req.headers.query = req.headers.query || "";
  var ideas;

  var selectFields = 'createdAt updatedAt shortId userId slackId sUserName title body tags active voters upvotes downvotes rating';

  switch (req.headers.query) {
    case 'dateFirst':
      ideas = Idea.find()
                .select(selectFields)
                .sort('-updatedAt')
                .limit(10);
      break;
    case 'dateLast':
      ideas = Idea.find()
                .select(selectFields)
                .sort('updatedAt')
                .limit(10);
      break;
    case 'votes':
      ideas = Idea.find()
                .select(selectFields)
                .sort('-rating')
                .limit(10);
      break;
    case 'tags':
    //add username to tags array for easy find of people also.
      ideas = Idea.find({ tags: { $in:req.headers.tags } })
                .select(selectFields)
                .limit(10);
      break;
    case 'userId':
      ideas = Idea.find({ userId:req.headers.userId })
                .select(selectFields);
      break;
    default:
    //custom query (to do when need arises)
      console.log('cant cant cant');
  }

  var results = [];

  ideas.exec(function (data) {
    results.push(data);
  });

  res.end(JSON.stringify(results));
} // end getIdeas

function createIdea (req, res) {
  var now = Date.now();

  var idea = new Idea({
    createdAt    : now,
    updatedAt    : now,
    shortId      : req.body.shortId,
    userId       : req.body.userId,
    slackId      : req.body.slackId,
    sUserName    : req.body.user_name,
    sTeamId      : req.body.team_id || null,
    sChannelId   : req.body.channel_id || null,
    sChannelName : req.body.channel_name || null,
    sTeamDomain  : req.body.team_domain || null,
    sCommand     : req.body.command || null,
    title        : req.body.title,
    body         : req.body.body,
    tags         : req.body.tags || [],
    active       : true
  });

  idea.save(function (err) {
    if (err) console.log(err);
    console.log('New idea', idea.title, 'saved');
  });

  res.end();
} // end createIdea

function createComment (req, res) {
  var now = Date.now();

  User.findOne({ sUserName: req.body.user_name }, function (err, user) {
    console.log('User:', user.sUserName);

    if (!req.body.userId) {
      req.body.userId = user._id;
    }
  });

  // If from Slack, assign text to body
  if (!req.body.body) {
    req.body.body = req.body.text;
  }

  // If from Slack, set req.body.parentId to mongo _id (looked up from shortId)

  var newComment = new Comment({
    createdAt : now,
    updatedAt : now,
    parentId  : req.body.parentId,
    userId    : req.body.userId,
    slackId   : req.body.slackId,
    body      : req.body.body
  });

  // Assumes comment request comes with a parentType
  if (req.body.parentType === 'idea') {
    Idea.findOne({ _id: req.body.parentId }, function (err, idea) {
      console.log('Idea shortId:', idea.shortId);

      idea.comments.push(newComment);
    });
  }

  if (req.body.parentType === 'comment') {
    Idea.findOne({ _id: req.body.rootId }, function (err, idea) {
      console.log('Root idea shortId:', idea.shortId);

      insertComment(idea);

      // Traverse comment tree to find parent of comment
      function insertComment (node) {
        node.comments.map(function (comment) {
          if (comment._id === req.body.parentId) {
            comment.comments.push(newComment);
            res.end();
            return;
          } else {
            insertComment(comment);
          }
        });
      }
    });
  }
  //   console.log('New comment "' + comment.body.substr(0, 10) + '"saved')

  res.end();
} // end createComment

function downvote (req, res) {
  var now = Date.now();

  var newDownvote = new Vote({
    createdAt : now,
    voter     : req.body.user_name // Slack username
  });

  if (req.body.type === 'idea') {
    Idea.find({ shortId: req.body.shortId }, function (err, idea) {
      idea.voters.map(function (voter) {
        if (voter === req.body.slackId) {
          res.status(403).send('Voting only allowed once');
        }
      });

      idea.voters.push(req.body.slackId);
      idea.downvotes.push(newDownvote);
      idea.rating = idea.upvotes.length - idea.downvotes.length;
    });
  }

  if (req.body.type === 'comment') {
    Comment.find({ shortId: req.body.shortId }, function (err, comment) {
      comment.voters.map(function (voter) {
        if (voter === req.body.slackId) {
          res.status(403).send('Voting only allowed once');
        }
      });

      comment.voters.push(req.body.slackId);
      comment.downvotes.push(downvote);
      comment.rating = comment.upvotes.length - comment.downvotes.length;
    });
  }

  res.end();
} // end downvote

function upvote (req, res) {
  var now = Date.now();

  var newUpvote = new Vote({
    createdAt : now,
    voter     : req.body.user_name // Slack username
  });

  if (req.body.type === 'idea') {
    Idea.find({ shortId: req.body.shortId }, function (err, idea) {
      idea.voters.map(function (voter) {
        if (voter === req.body.slackId) {
          res.status(403).send('Voting only allowed once');
        }
      });

      idea.voters.push(req.body.slackId);
      idea.upvotes.push(newUpvote);
      idea.rating = idea.upvotes.length - idea.downvotes.length;
    });
  }

  if (req.body.type === 'comment') {
    Comment.find({ shortId: req.body.shortId }, function (err, comment) {
      comment.voters.map(function (voter) {
        if (voter === req.body.slackId) {
          res.status(403).send('Voting only allowed once');
        }
      });

      comment.voters.push(req.body.slackId);
      comment.upvotes.push(upvote);
      comment.rating = comment.upvotes.length - comment.downvotes.length;
    });
  }

  res.end();
} // end upvote

// expose functions
module.exports = {
  getIdeas: getIdeas,
  createIdea: createIdea,
  createComment: createComment,
  downvote: downvote,
  upvote: upvote,
  slackInt: slackInt
};
<|endoftext|>


<commit_before>
const router = require('express').Router();
const jsonParser = require('body-parser').json();
const userFood = require('../models/Userfood');

router
    .get('/', (req, res, next) => {
        userFood.find({})
        .then(userfoods => res.send(userfoods))
        .catch(next);
    })

    .post('/', jsonParser, (req, res, next) => {
        new userFood(req.body).save()
            .then(saved => res.send(saved))
            .catch(next);
    });

module.exports = router;
<commit_msg>f to F<commit_after>
const router = require('express').Router();
const jsonParser = require('body-parser').json();
const userFood = require('../models/UserFood');

router
    .get('/', (req, res, next) => {
        userFood.find({})
        .then(userfoods => res.send(userfoods))
        .catch(next);
    })

    .post('/', jsonParser, (req, res, next) => {
        new userFood(req.body).save()
            .then(saved => res.send(saved))
            .catch(next);
    });

module.exports = router;
<|endoftext|>


<commit_before>/*
 * recursion.js
 * Written by Michael Albinson 2/15/17
 *
 * A (hopefully growing) collection of recursive promise functions to
 * ease getting large numbers of rows and doing the same things to them.
 */

"use strict";

var DBRow = require('./DBRow').DBRow;
var lit = require('./Literals');
var voter = require('./actions/Voter');
var rater = require('./actions/Rater');
var searcher = require('./actions/Searcher');
var log = require('./log');

/** recursiveGet(resolve, reject, rowsToGet, action, actionArgs)
 * NOTE: the action function MUST be synchronous
 *
 * @param resolve: the resolve function of the calling function's promise
 * @param reject: the reject function of the calling function's promise
 * @param rowsToGet: the DBRow object containing ids of the rows to get
 * @param action: the function to execute after each row is retrieved
 * @param actionArgs: the function arguments, if any, that need to be passed to the action function
 */

exports.recursiveGet = function (resolve, reject, rowsToGet, action, actionArgs) {
    if (!rowsToGet.next())
        resolve(actionArgs);
    else {
        var item = new DBRow(rowsToGet.getValue(lit.TYPE));
        item.getRow(rowsToGet.getValue(lit.FIELD_ITEM_ID)).then(function () {
            action(rowsToGet, item, actionArgs);
            exports.recursiveGet(resolve, reject, rowsToGet, action, actionArgs)

        }, function (err) {
            reject(actionArgs, err);

        });
    }
};

/** recursiveGetWithVotes(resolve, reject, rowsToGet, action, actionArgs)
 * A modified version of recursive get that gets the vote or comment associated with the item.
 *
 * @param resolve: the resolve function of the calling function's promise
 * @param reject: the reject function of the calling function's promise
 * @param rowsToGet: the DBRow object containing ids of the rows to get
 * @param action: the function to execute after each row is retrieved
 * @param actionArgs: the function arguments, if any, that need to be passed to the action function
 * @param userID: the userID of the user to get votes for
 */

exports.recursiveGetWithVotes = function (resolve, reject, rowsToGet, action, userID, actionArgs) {
    if (!rowsToGet.next())
        resolve(actionArgs);
    else {
        var type = rowsToGet.getValue(lit.FIELD_TYPE);
        var item = new DBRow(type);
        item.getRow(rowsToGet.getValue(lit.FIELD_ITEM_ID)).then(function () {
            if (type == 'link' || type == 'post') {
                voter.getVote(userID, rowsToGet.getValue(lit.FIELD_ITEM_ID)).then(function (vote) {
                    if (vote)
                        action(item, vote, type, actionArgs);
                    else
                        action(item, undefined, type, actionArgs);

                    exports.recursiveGetWithVotes(resolve, reject, rowsToGet, action, userID, actionArgs)
                }, function (err) {
                    reject(actionArgs, err);
                });
            }
            else {
                var u = new DBRow(lit.USER_TABLE);
                u.getRow(userID).then(function () {
                    rater.getRating(u.getValue(lit.FIELD_USERNAME), item.getValue(lit.FIELD_ID)).then(function (rating) {
                        if (rating)
                            action(item, rating, type, actionArgs);
                        else
                            action(item, undefined, type, actionArgs);

                        exports.recursiveGetWithVotes(resolve, reject, rowsToGet, action, userID, actionArgs)
                    }, function (err) {
                        reject(actionArgs, err);
                    });
                })
            }

        }, function (err) {
            reject(actionArgs, err);

        });
    }
};

exports.recursiveGetListWithVotes = function (resolve, reject, rowList, tableList, action, userID, actionArgs, index) {
    if (index > rowList.length) //tableList and rowList have the same length
        resolve(actionArgs);
    else {
        var current = rowList[index];
        if (!current)
            return exports.recursiveGetListWithVotes(resolve, reject, rowList, tableList, action, userID, actionArgs, ++index);
        var content = new DBRow(tableList[index]);
        content.getRow(current).then(function () {
            voter.getVote(userID, current).then(function (vote) {
                if (vote)
                    action(content, vote, tableList[index], actionArgs);
                else {
                    action(content, undefined, tableList[index], actionArgs);
                }
                exports.recursiveGetListWithVotes(resolve, reject, rowList, tableList, action, userID, actionArgs, ++index)
            }, function (err) {
                reject(actionArgs, err);
            });
        });
    }
};

/**
 * Function that recursively queries multiple tables for each row of each table's generated tags.
 * @param resolve The Promise resolve used to make the code act synchronously.
 * @param reject The Promise reject used to pass errors up the Promise chains.
 * @param tables The tables to be queried.
 * @param index The current table to be queried within tables.
 * @param allDocInfo One information object (id, measure, table) is added for each row of each table.
 * @param queryOneTable Function parameter that queries one table and gets the generated tags for each row in that table.
 */
exports.recursiveGetTagsMultiTables = function (resolve, reject, tables, index, allDocInfo, queryOneTable) {
    if (index > tables.length - 1) {
        resolve(allDocInfo);
    } else {
        queryOneTable(tables[index]).then(function (oneDoc) {
            allDocInfo = allDocInfo.concat(oneDoc);
            exports.recursiveGetTagsMultiTables(resolve, reject, tables, ++index, allDocInfo, queryOneTable);
        }).catch(function (err) {
            log.error("recursiveGetTagsMultiTables error: " + err);
            reject(err);
        });
    }
};

/**
 * Function that recursively retrieves the generated tags for each row from a given table.
 * @param resolve The Promise resolve used to make the code act synchronously.
 * @param reject The Promise reject used to pass errors up the Promise chains.
 * @param row The individual row of a table that each recursive call is using.
 * @param addDocument Function to add the tags to the wordRelater in Searcher.js.
 * @param table The table row is in.
 * @param docInfo An object holding a placeholder measure for wordRelater and the ID of the row.
 * @returns {*} An array is built with each recursive call to eventually be an array of all docInfo's made
 */
exports.recursiveGetTags = function (resolve, reject, row, addDocument, table, docInfo) {
    if (!row.next()) {
        resolve(docInfo);
    } else {
        var genTags = row.getValue(lit.FIELD_GEN_TAGS);
        if (genTags !== null) {
            docInfo.push(addDocument(genTags, row, table));
            return exports.recursiveGetTags(resolve, reject, row, addDocument, table, docInfo);
        } else {
            searcher.generateTags(row, table).then(function (tags) {
                addDocument(tags, row, table);
                return exports.recursiveGetTags(resolve, reject, row, addDocument, table, docInfo);
            }).catch(function (err) {
                log.error("recursiveGetTags error: " + err);
                reject(err);
            });
        }
    }
};<commit_msg>fixed poor recursion with promises<commit_after>/*
 * recursion.js
 * Written by Michael Albinson 2/15/17
 *
 * A (hopefully growing) collection of recursive promise functions to
 * ease getting large numbers of rows and doing the same things to them.
 */

"use strict";

var DBRow = require('./DBRow').DBRow;
var lit = require('./Literals');
var voter = require('./actions/Voter');
var rater = require('./actions/Rater');
var searcher = require('./actions/Searcher');
var log = require('./log');

/** recursiveGet(resolve, reject, rowsToGet, action, actionArgs)
 * NOTE: the action function MUST be synchronous
 *
 * @param resolve: the resolve function of the calling function's promise
 * @param reject: the reject function of the calling function's promise
 * @param rowsToGet: the DBRow object containing ids of the rows to get
 * @param action: the function to execute after each row is retrieved
 * @param actionArgs: the function arguments, if any, that need to be passed to the action function
 */

exports.recursiveGet = function (resolve, reject, rowsToGet, action, actionArgs) {
    if (!rowsToGet.next())
        resolve(actionArgs);
    else {
        var item = new DBRow(rowsToGet.getValue(lit.TYPE));
        item.getRow(rowsToGet.getValue(lit.FIELD_ITEM_ID)).then(function () {
            action(rowsToGet, item, actionArgs);
            exports.recursiveGet(resolve, reject, rowsToGet, action, actionArgs)

        }, function (err) {
            reject(actionArgs, err);

        });
    }
};

/** recursiveGetWithVotes(resolve, reject, rowsToGet, action, actionArgs)
 * A modified version of recursive get that gets the vote or comment associated with the item.
 *
 * @param resolve: the resolve function of the calling function's promise
 * @param reject: the reject function of the calling function's promise
 * @param rowsToGet: the DBRow object containing ids of the rows to get
 * @param action: the function to execute after each row is retrieved
 * @param actionArgs: the function arguments, if any, that need to be passed to the action function
 * @param userID: the userID of the user to get votes for
 */

exports.recursiveGetWithVotes = function (resolve, reject, rowsToGet, action, userID, actionArgs) {
    if (!rowsToGet.next())
        resolve(actionArgs);
    else {
        var type = rowsToGet.getValue(lit.FIELD_TYPE);
        var item = new DBRow(type);
        item.getRow(rowsToGet.getValue(lit.FIELD_ITEM_ID)).then(function () {
            if (type == 'link' || type == 'post') {
                voter.getVote(userID, rowsToGet.getValue(lit.FIELD_ITEM_ID)).then(function (vote) {
                    if (vote)
                        action(item, vote, type, actionArgs);
                    else
                        action(item, undefined, type, actionArgs);

                    exports.recursiveGetWithVotes(resolve, reject, rowsToGet, action, userID, actionArgs)
                }, function (err) {
                    reject(actionArgs, err);
                });
            }
            else {
                var u = new DBRow(lit.USER_TABLE);
                u.getRow(userID).then(function () {
                    rater.getRating(u.getValue(lit.FIELD_USERNAME), item.getValue(lit.FIELD_ID)).then(function (rating) {
                        if (rating)
                            action(item, rating, type, actionArgs);
                        else
                            action(item, undefined, type, actionArgs);

                        exports.recursiveGetWithVotes(resolve, reject, rowsToGet, action, userID, actionArgs)
                    }, function (err) {
                        reject(actionArgs, err);
                    });
                })
            }

        }, function (err) {
            reject(actionArgs, err);

        });
    }
};

exports.recursiveGetListWithVotes = function (resolve, reject, rowList, tableList, action, userID, actionArgs, index) {
    if (index > rowList.length) //tableList and rowList have the same length
        resolve(actionArgs);
    else {
        var current = rowList[index];
        if (!current)
            return exports.recursiveGetListWithVotes(resolve, reject, rowList, tableList, action, userID, actionArgs, ++index);
        var content = new DBRow(tableList[index]);
        content.getRow(current).then(function () {
            voter.getVote(userID, current).then(function (vote) {
                if (vote)
                    action(content, vote, tableList[index], actionArgs);
                else {
                    action(content, undefined, tableList[index], actionArgs);
                }
                exports.recursiveGetListWithVotes(resolve, reject, rowList, tableList, action, userID, actionArgs, ++index)
            }, function (err) {
                reject(actionArgs, err);
            });
        });
    }
};

/**
 * Function that recursively queries multiple tables for each row of each table's generated tags.
 * @param resolve The Promise resolve used to make the code act synchronously.
 * @param reject The Promise reject used to pass errors up the Promise chains.
 * @param tables The tables to be queried.
 * @param index The current table to be queried within tables.
 * @param allDocInfo One information object (id, measure, table) is added for each row of each table.
 * @param queryOneTable Function parameter that queries one table and gets the generated tags for each row in that table.
 */
exports.recursiveGetTagsMultiTables = function (resolve, reject, tables, index, allDocInfo, queryOneTable) {
    if (index > tables.length - 1) {
        resolve(allDocInfo);
    } else {
        queryOneTable(tables[index]).then(function (oneDoc) {
            allDocInfo = allDocInfo.concat(oneDoc);
            exports.recursiveGetTagsMultiTables(resolve, reject, tables, ++index, allDocInfo, queryOneTable);
        }).catch(function (err) {
            log.error("recursiveGetTagsMultiTables error: " + err);
            reject(err);
        });
    }
};

/**
 * Function that recursively retrieves the generated tags for each row from a given table.
 * @param resolve The Promise resolve used to make the code act synchronously.
 * @param reject The Promise reject used to pass errors up the Promise chains.
 * @param row The individual row of a table that each recursive call is using.
 * @param addDocument Function to add the tags to the wordRelater in Searcher.js.
 * @param table The table row is in.
 * @param docInfo An object holding a placeholder measure for wordRelater and the ID of the row.
 * @returns {*} An array is built with each recursive call to eventually be an array of all docInfo's made
 */
exports.recursiveGetTags = function (resolve, reject, row, addDocument, table, docInfo) {
    if (!row.next()) {
        resolve(docInfo);
    } else {
        var genTags = row.getValue(lit.FIELD_GEN_TAGS);
        if (genTags !== null) {
            docInfo.push(addDocument(genTags, row, table));
            return exports.recursiveGetTags(resolve, reject, row, addDocument, table, docInfo);
        } else {
            searcher.generateTags(row, table).then(function (tags) {
                addDocument(tags, row, table);
                exports.recursiveGetTags(resolve, reject, row, addDocument, table, docInfo);
            }).catch(function (err) {
                log.error("recursiveGetTags error: " + err);
                reject(err);
            });
        }
    }
};<|endoftext|>


<commit_before>import rethink from 'connections/rethink'
import palisade from 'palisade'
const { type } = rethink

const Model = rethink.createModel('User', {
  // core fields
  id: type.string(),
  role: type.string().enum([
    'pleb',
    'admin'
  ]).default('pleb'),

  created: type.date().default(Date.now),
  lastModified: type.date().default(Date.now),
  lastLogin: type.date().default(Date.now),

  // auth info
  facebook: {
    id: type.string(),
    accessToken: type.string()
  },
  google: {
    id: type.string(),
    accessToken: type.string()
  },
  github: {
    id: type.string(),
    accessToken: type.string()
  },
  local: {
    id: type.string(),
    accessToken: type.string()
  },

  // user info
  name: type.string(),
  email: type.string().email(),
  count: type.number().default(0),
  location: type.string()
})

Model.ready().then(() => {
  // import and set up relationships here
})

palisade(Model, {
  document: {
    read: [ 'loggedIn' ],
    list: [ 'loggedIn' ],
    create: [ 'admin' ],
    update: [ 'admin', 'self' ],
    replace: [ 'admin' ],
    delete: [ 'admin' ]
  },
  read: {
    id: [ 'loggedIn' ],
    role: [ 'loggedIn' ],
    name: [ 'loggedIn' ],
    location: [ 'loggedIn' ],
    count: [ 'loggedIn' ],
    created: [ 'loggedIn' ],
    lastModified: [ 'admin', 'self' ],
    lastLogin: [ 'admin', 'self' ],
    email: [ 'admin', 'self' ]
  },
  write: {
    role: [ 'admin' ],
    name: [ 'admin', 'self' ],
    email: [ 'admin', 'self' ],
    location: [ 'admin', 'self' ],
    count: [ 'loggedIn' ]
  }
})

// other junk
Model.pre('save', function (next) {
  this.lastModified = Date.now()
  next()
})

export default Model
<commit_msg>add ensureIndex to allow r.orderBy({index: created})<commit_after>import rethink from 'connections/rethink'
import palisade from 'palisade'
const { type } = rethink

const Model = rethink.createModel('User', {
  // core fields
  id: type.string(),
  role: type.string().enum([
    'pleb',
    'admin'
  ]).default('pleb'),

  created: type.date().default(Date.now),
  lastModified: type.date().default(Date.now),
  lastLogin: type.date().default(Date.now),

  // auth info
  facebook: {
    id: type.string(),
    accessToken: type.string()
  },
  google: {
    id: type.string(),
    accessToken: type.string()
  },
  github: {
    id: type.string(),
    accessToken: type.string()
  },
  local: {
    id: type.string(),
    accessToken: type.string()
  },

  // user info
  name: type.string(),
  email: type.string().email(),
  count: type.number().default(0),
  location: type.string()
})

Model.ensureIndex('created')

Model.ready().then(() => {
  // import and set up relationships here
})

palisade(Model, {
  document: {
    read: [ 'loggedIn' ],
    list: [ 'loggedIn' ],
    create: [ 'admin' ],
    update: [ 'admin', 'self' ],
    replace: [ 'admin' ],
    delete: [ 'admin' ]
  },
  read: {
    id: [ 'loggedIn' ],
    role: [ 'loggedIn' ],
    name: [ 'loggedIn' ],
    location: [ 'loggedIn' ],
    count: [ 'loggedIn' ],
    created: [ 'loggedIn' ],
    lastModified: [ 'admin', 'self' ],
    lastLogin: [ 'admin', 'self' ],
    email: [ 'admin', 'self' ]
  },
  write: {
    role: [ 'admin' ],
    name: [ 'admin', 'self' ],
    email: [ 'admin', 'self' ],
    location: [ 'admin', 'self' ],
    count: [ 'loggedIn' ]
  }
})

// other junk
Model.pre('save', function (next) {
  this.lastModified = Date.now()
  next()
})

export default Model
<|endoftext|>


<commit_before>/**
 * @license MIT License
 *
 * Copyright (c) 2015 Tetsuharu OHZEKI <saneyuki.snyk@gmail.com>
 * Copyright (c) 2015 Yusuke Suzuki <utatane.tea@gmail.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

import * as React from 'react';

export class InputForm extends React.Component {

    constructor(props) {
        super(props);
    }

    render() {
        return (
            <form id='js-form' className='input-form' action=''>

                    <button className='submit' type='submit'>
                        Send
                    </button>

                        <input id='js-input'
                               className='input-form__input'
                               autoComplete='off'/>

            </form>
        );
    }
}
<commit_msg>Use single quote<commit_after>/**
 * @license MIT License
 *
 * Copyright (c) 2015 Tetsuharu OHZEKI <saneyuki.snyk@gmail.com>
 * Copyright (c) 2015 Yusuke Suzuki <utatane.tea@gmail.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

import * as React from 'react';

export class InputForm extends React.Component {

    constructor(props) {
        super(props);
    }

    render() {
        return (
            <form id='js-form' className='input-form' action=''>

                    <button className='submit' type='submit'>
                        Send
                    </button>

                        <input id='js-input'
                               className='input-form__input'
                               autoComplete='off'/>

            </form>
        );
    }
}
<|endoftext|>


<commit_before>var Joi = require('joi');
var log = require('server/helpers/logger');
var render = require('server/views/file');
var configUpload = require('config').upload;
var optionsUpload = require('server/options').upload;

var handlers = module.exports;

exports.create = {
  tags: ['api','file'],
  auth: {
    strategies: ['default', 'backup'],
    scope: ['admin']
  },
  validate: {
    payload: {
    	id: Joi.string().required().description('File id'),
      user: Joi.string().required().description('File user'),
    	name: Joi.string().required().description('File name'),
    	kind: Joi.string().required().description('File category'),
    	extension: Joi.string().required().description('File type')
    }
  },
  pre: [
    { method: 'file.create(payload)', assign: 'file' }
  ],
  handler: function (request, reply) {
    reply(render(request.pre.file)).created('/file/'+request.pre.file.id);
  },
  description: 'Creates a new file model'
};

exports.update = {
  tags: ['api','file'],
  auth: {
    strategies: ['default', 'backup'],
    scope: ['admin']
  },
  validate: {
    params: {
      id: Joi.string().required().description('Id of the file we want to update'),
    },
    payload: {
    	id: Joi.string().description('File id'),
      user: Joi.string().description('File user'),
    	name: Joi.string().description('File name'),
    	kind: Joi.string().description('File category'),
    	extension: Joi.string().description('File type'),
    }
  },
  pre: [
    { method: 'file.update(params.id, payload)', assign: 'file' }
  ],
  handler: function (request, reply) {
    reply(render(request.pre.file));
  },
  description: 'Updates a file model'
};

exports.get = {
  tags: ['api','file'],
  auth: {
    strategies: ['default', 'backup'],
    scope: ['admin']
  },
  validate: {
    params: {
      id: Joi.string().required().description('Id or user of the file we want to retrieve'),
    }
  },
  pre: [
    { method: 'file.get(params.id, query)', assign: 'file' }
  ],
  handler: function (request, reply) {
    reply(render(request.pre.file));
  },
  description: 'Gets the model of the file'
};

exports.getMe = {
  tags: ['api','file'],
  auth: {
    strategies: ['default', 'backup'],
    scope: ['user', 'admin']
  },
  pre: [
    { method: 'file.get(auth.credentials.user.id, query)', assign: 'file' }
  ],
  handler: function (request, reply) {
    reply(render(request.pre.file));
  },
  description: 'Gets the file model of the user'
};

exports.download = {
  tags: ['api','file'],
  auth: {
    strategies: ['default', 'backup'],
    scope: ['admin']
  },
  validate: {
    params: {
      id: Joi.string().required().description('Id or user of the file we want to retrieve'),
    }
  },
  pre: [
    { method: 'file.get(params.id, query)', assign: 'file' }
  ],
  handler: function (request, reply) {
    var path = configUpload.path + '/' + request.pre.file.id;
    var options = {
      filename: request.pre.file.name,
      mode: 'attachment'
    };
    reply.file(path, options);
  },
  description: 'Downloads the file'
};

exports.downloadMe = {
  tags: ['api','file'],
  auth: {
    strategies: ['default', 'backup'],
    scope: ['user', 'admin']
  },
  pre: [
    { method: 'file.get(auth.credentials.user.id, query)', assign: 'file' }
  ],
  handler: function (request, reply) {
    var path = configUpload.path + '/' + request.pre.file.id;
    var options = {
      filename: request.pre.file.name,
      mode: 'attachment'
    };
    reply.file(path, options);
  },
  description: 'Downloads the file of the user'
};

exports.list = {
  tags: ['api','file'],
  auth: {
    strategies: ['default', 'backup'],
    scope: ['admin']
  },
  pre: [
    { method: 'file.list(query)', assign: 'files' }
  ],
  handler: function (request, reply) {
    reply(render(request.pre.files));
  },
  description: 'Gets all the file models'
};

exports.remove = {
  tags: ['api','file'],
  auth: {
    strategies: ['default', 'backup'],
    scope: ['admin']

  },
  validate: {
    params: {
      id: Joi.string().required().description('Id of the file we want to remove'),
    }
  },
  pre: [
    { method: 'file.remove(params.id)', assign: 'file' }
  ],
  handler: function (request, reply) {
    reply(render(request.pre.file));
  },
  description: 'Removes a file'
};

exports.removeMe = {
  tags: ['api','file'],
  auth: {
    strategies: ['default', 'backup'],
    scope: ['user', 'admin']

  },
  pre: [
    { method: 'file.remove(auth.credentials.user.id)', assign: 'file' }
  ],
  handler: function (request, reply) {
    reply(render(request.pre.file));
  },
  description: 'Removes user file'
};

exports.upload = {
  tags: ['api','file'],
  auth: {
    strategies: ['default', 'backup'],
    scope: ['admin']
  },
  payload: {
    output: 'stream',
    parse: true,
    allow: 'multipart/form-data',
    maxBytes: configUpload.maxSize
  },
  validate: {
    query: {
      upsert: Joi.string().default('true'),
    },
    params: {
      id: Joi.string().required().description('Id of the user whose file we want to upload'),
    },
    payload: Joi.object().pattern(/(\w*\W*)*/,
      Joi.object({
        pipe: Joi.func().required().description('File stream'),
        hapi: Joi.object({
          filename: Joi.string().required().description('File name'),
          headers: Joi.object({
            'content-type': Joi.string().required().description('File mime type'),
            'content-disposition': Joi.string().required().regex(/\w*\W*filename\w*\W*/).description('File name')
          }).unknown().required().description('File headers')
        }).required().description('File')
      }).unknown()
    ).required().length(1)
  },
  pre: [
    { method: 'user.get(params.id)', assign: 'user' },
    { method: 'file.uploadCV(payload)', assign: 'file' },
    { method: 'file.get(auth.credentials.user.id)', assign: 'oldFile', failAction: 'log'},
    [
      { method: 'file.delete(pre.oldFile.id)', assign: 'deleteFile', failAction: 'log'},
      { method: 'file.update(pre.oldFile.id, pre.file, auth.credentials.user.id, query)', assign: 'fileInfo' }
    ]
  ],
  handler: function (request, reply) {
    reply(render(request.pre.fileInfo)).created('/api/file/'+request.pre.fileInfo.id);
  },
  description: 'Uploads a file'
};

exports.uploadMe = {
  tags: ['api','file'],
  auth: {
    strategies: ['default', 'backup'],
    scope: ['user', 'admin']
  },
  payload: {
    output: 'stream',
    parse: true,
    allow: 'multipart/form-data',
    maxBytes: configUpload.maxSize
  },
  validate: {
    query: {
      upsert: Joi.string().invalid('false').default('true'),
    },
    payload: Joi.object().pattern(/(\w*\W*)*/,
      Joi.object({
        pipe: Joi.func().required().description('File stream'),
        hapi: Joi.object({
          filename: Joi.string().required().description('File name'),
          headers: Joi.object({
            'content-type': Joi.string().required().description('File mime type'),
            'content-disposition': Joi.string().required().regex(/\w*\W*filename\w*\W*/).description('File name')
          }).unknown().required().description('File headers')
        }).required().description('File')
      }).unknown()
    ).required().length(1)
  },
  pre: [
    { method: 'file.uploadCV(payload)', assign: 'file' },
    { method: 'file.get(auth.credentials.user.id)', assign: 'oldFile', failAction: 'log'},
    [
      { method: 'file.delete(pre.oldFile.id)', assign: 'deleteFile', failAction: 'log'},
      { method: 'file.update(pre.oldFile.id, pre.file, auth.credentials.user.id, query)', assign: 'fileInfo' }
    ]
  ],
  handler: function (request, reply) {
    reply(render(request.pre.fileInfo)).created('/api/file/'+request.pre.fileInfo.id);
  },
  description: 'Uploads a file of the user'
};<commit_msg>Working on download me<commit_after>var Joi = require('joi');
var log = require('server/helpers/logger');
var render = require('server/views/file');
var configUpload = require('config').upload;
var optionsUpload = require('server/options').upload;

var handlers = module.exports;

exports.create = {
  tags: ['api','file'],
  auth: {
    strategies: ['default', 'backup'],
    scope: ['admin']
  },
  validate: {
    payload: {
    	id: Joi.string().required().description('File id'),
      user: Joi.string().required().description('File user'),
    	name: Joi.string().required().description('File name'),
    	kind: Joi.string().required().description('File category'),
    	extension: Joi.string().required().description('File type')
    }
  },
  pre: [
    { method: 'file.create(payload)', assign: 'file' }
  ],
  handler: function (request, reply) {
    reply(render(request.pre.file)).created('/file/'+request.pre.file.id);
  },
  description: 'Creates a new file model'
};

exports.update = {
  tags: ['api','file'],
  auth: {
    strategies: ['default', 'backup'],
    scope: ['admin']
  },
  validate: {
    params: {
      id: Joi.string().required().description('Id of the file we want to update'),
    },
    payload: {
    	id: Joi.string().description('File id'),
      user: Joi.string().description('File user'),
    	name: Joi.string().description('File name'),
    	kind: Joi.string().description('File category'),
    	extension: Joi.string().description('File type'),
    }
  },
  pre: [
    { method: 'file.update(params.id, payload)', assign: 'file' }
  ],
  handler: function (request, reply) {
    reply(render(request.pre.file));
  },
  description: 'Updates a file model'
};

exports.get = {
  tags: ['api','file'],
  auth: {
    strategies: ['default', 'backup'],
    scope: ['admin']
  },
  validate: {
    params: {
      id: Joi.string().required().description('Id or user of the file we want to retrieve'),
    }
  },
  pre: [
    { method: 'file.get(params.id, query)', assign: 'file' }
  ],
  handler: function (request, reply) {
    reply(render(request.pre.file));
  },
  description: 'Gets the model of the file'
};

exports.getMe = {
  tags: ['api','file'],
  auth: {
    strategies: ['default', 'backup'],
    scope: ['user', 'admin']
  },
  pre: [
    { method: 'file.get(auth.credentials.user.id, query)', assign: 'file' }
  ],
  handler: function (request, reply) {
    reply(render(request.pre.file));
  },
  description: 'Gets the file model of the user'
};

exports.download = {
  tags: ['api','file'],
  auth: {
    strategies: ['default', 'backup'],
    scope: ['admin']
  },
  validate: {
    params: {
      id: Joi.string().required().description('Id or user of the file we want to retrieve'),
    }
  },
  pre: [
    { method: 'file.get(params.id, query)', assign: 'file' }
  ],
  handler: function (request, reply) {
    var path = configUpload.path + '/' + request.pre.file.id;
    var options = {
      filename: request.pre.file.name,
      mode: 'attachment'
    };
    reply.file(path, options);
  },
  description: 'Downloads the file'
};

exports.downloadMe = {
  tags: ['api','file'],
  auth: {
    strategies: ['backup'],
    scope: ['user', 'admin']
  },
  pre: [
    { method: 'file.get(auth.credentials.user.id, query)', assign: 'file' }
  ],
  handler: function (request, reply) {
    var path = configUpload.path + '/' + request.pre.file.id;
    var options = {
      filename: request.pre.file.name,
      mode: 'attachment'
    };
    reply.file(path, options).type('application/pdf');
  },
  description: 'Downloads the file of the user'
};

exports.list = {
  tags: ['api','file'],
  auth: {
    strategies: ['default', 'backup'],
    scope: ['admin']
  },
  pre: [
    { method: 'file.list(query)', assign: 'files' }
  ],
  handler: function (request, reply) {
    reply(render(request.pre.files));
  },
  description: 'Gets all the file models'
};

exports.remove = {
  tags: ['api','file'],
  auth: {
    strategies: ['default', 'backup'],
    scope: ['admin']

  },
  validate: {
    params: {
      id: Joi.string().required().description('Id of the file we want to remove'),
    }
  },
  pre: [
    { method: 'file.remove(params.id)', assign: 'file' }
  ],
  handler: function (request, reply) {
    reply(render(request.pre.file));
  },
  description: 'Removes a file'
};

exports.removeMe = {
  tags: ['api','file'],
  auth: {
    strategies: ['default', 'backup'],
    scope: ['user', 'admin']

  },
  pre: [
    { method: 'file.remove(auth.credentials.user.id)', assign: 'file' }
  ],
  handler: function (request, reply) {
    reply(render(request.pre.file));
  },
  description: 'Removes user file'
};

exports.upload = {
  tags: ['api','file'],
  auth: {
    strategies: ['default', 'backup'],
    scope: ['admin']
  },
  payload: {
    output: 'stream',
    parse: true,
    allow: 'multipart/form-data',
    maxBytes: configUpload.maxSize
  },
  validate: {
    query: {
      upsert: Joi.string().default('true'),
    },
    params: {
      id: Joi.string().required().description('Id of the user whose file we want to upload'),
    },
    payload: Joi.object().pattern(/(\w*\W*)*/,
      Joi.object({
        pipe: Joi.func().required().description('File stream'),
        hapi: Joi.object({
          filename: Joi.string().required().description('File name'),
          headers: Joi.object({
            'content-type': Joi.string().required().description('File mime type'),
            'content-disposition': Joi.string().required().regex(/\w*\W*filename\w*\W*/).description('File name')
          }).unknown().required().description('File headers')
        }).required().description('File')
      }).unknown()
    ).required().length(1)
  },
  pre: [
    { method: 'user.get(params.id)', assign: 'user' },
    { method: 'file.uploadCV(payload)', assign: 'file' },
    { method: 'file.get(auth.credentials.user.id)', assign: 'oldFile', failAction: 'log'},
    [
      { method: 'file.delete(pre.oldFile.id)', assign: 'deleteFile', failAction: 'log'},
      { method: 'file.update(pre.oldFile.id, pre.file, auth.credentials.user.id, query)', assign: 'fileInfo' }
    ]
  ],
  handler: function (request, reply) {
    reply(render(request.pre.fileInfo)).created('/api/file/'+request.pre.fileInfo.id);
  },
  description: 'Uploads a file'
};

exports.uploadMe = {
  tags: ['api','file'],
  auth: {
    strategies: ['default', 'backup'],
    scope: ['user', 'admin']
  },
  payload: {
    output: 'stream',
    parse: true,
    allow: 'multipart/form-data',
    maxBytes: configUpload.maxSize
  },
  validate: {
    query: {
      upsert: Joi.string().invalid('false').default('true'),
    },
    payload: Joi.object().pattern(/(\w*\W*)*/,
      Joi.object({
        pipe: Joi.func().required().description('File stream'),
        hapi: Joi.object({
          filename: Joi.string().required().description('File name'),
          headers: Joi.object({
            'content-type': Joi.string().required().description('File mime type'),
            'content-disposition': Joi.string().required().regex(/\w*\W*filename\w*\W*/).description('File name')
          }).unknown().required().description('File headers')
        }).required().description('File')
      }).unknown()
    ).required().length(1)
  },
  pre: [
    { method: 'file.uploadCV(payload)', assign: 'file' },
    { method: 'file.get(auth.credentials.user.id)', assign: 'oldFile', failAction: 'log'},
    [
      { method: 'file.delete(pre.oldFile.id)', assign: 'deleteFile', failAction: 'log'},
      { method: 'file.update(pre.oldFile.id, pre.file, auth.credentials.user.id, query)', assign: 'fileInfo' }
    ]
  ],
  handler: function (request, reply) {
    reply(render(request.pre.fileInfo)).created('/api/file/'+request.pre.fileInfo.id);
  },
  description: 'Uploads a file of the user'
};<|endoftext|>


<commit_before>'use strict';

const bitcoin = require('multicoinjs-lib');
const utils = require('./utils.js');
const alerts = require('./alerts');
const $ = require('jquery');

exports.ChangeBalance = function(fNewBalance)
{
    if (fNewBalance < 1.e-12) fNewBalance = 0;

    $('#spanModalBalance').text(fNewBalance);

    $('.groupBalance').removeClass('has-error');
    $('.groupBalance').addClass('has-success');
    if (fNewBalance < 0)
    {
        $('.groupBalance').removeClass('has-success');
        $('.groupBalance').addClass('has-error');
    }

}

exports.onOpenDialog = function(network, address, strLabel, strCoinShortName)
{
    $('#inputModalSendAddressLabel').val(strLabel);
    $('#inputModalSendFee').val('');
    $("#inputModalSendAmount").val('');
    $('#spanModalAmountCoinName').text(strCoinShortName);
    $('#spanModalFeeCoinName').text(strCoinShortName);
    $('#spanModalBalance').text(utils.getSavedBalance(network));

    $('#inputModalSendNetwork').val(network);
    $('#inputModalSendAddress').val(address);

    function onChangeFee()
    {
        var fee = $( '#inputModalSendFee' ).val().replace(/[^\d.-]/g, '');
        var sendFee = parseFloat(fee);
        if (isNaN(sendFee))
            sendFee = parseFloat(utils.coinsInfo[network].fee.toPrecision(12));
        else
        {
            if ((sendFee+"").length >=12)
                sendFee = parseFloat(sendFee.toPrecision(12));
            else
                sendFee = fee;
        }

        $('#inputModalSendFee').val(sendFee);
        $('#inputModalSendFee')[0].placeholder = sendFee;
        $('.spanRecommendedFee').text('(recommended minimum '+sendFee+' )');

        var sendAmount = parseFloat($( "#inputModalSendAmount" ).val());
        if (isNaN(sendAmount))
            sendAmount = 0;

        exports.ChangeBalance(
            parseFloat( (utils.getSavedBalance(network)-sendAmount-sendFee).toPrecision(12)) );
    }

    $( "#inputModalSendFee" ).on('input', onChangeFee);

    onChangeFee();

    jQuery('#send_coins_to').modal('show');

};

$('#btnSendCoinsReady').click(function () {
    console.log('btnSendCoinsReady click');
    const password = $('#inputSendMoneyPassword').val();
    if (utils.getSavedEncodePassword().length && !utils.isValidEncodePassword(password))
    {
        console.log('Invalid send password: ' + password);
        alerts.Alert('Error', 'Invalid password!');
        return;
    }
    jQuery('#send_coins_to').modal('hide');

    var rowSentInfo = [];
    var dFullSentAmount = 0.0;
    for (var i=0; i<$('.rowAddressSendTo').length; i++)
    {
        const row = $('.rowAddressSendTo')[i];
        const sendAmount = parseFloat($(row).find('#inputModalSendAmount').val());
        if (isNaN(sendAmount) || sendAmount <= 0)
        {
            alerts.Alert('Error', 'Bad send amount');
            return;
        }
        dFullSentAmount += sendAmount;

        rowSentInfo.push({addressSendTo : $(row).find('.spanAddressTo').text(), sendAmount : sendAmount});
    }

    console.log('btnSendCoinsReady sent amount checked');

    /*const addressSendTo = $('.spanAddressTo')[0].textContent;

    const sendAmount = parseFloat($( "#inputModalSendAmount" ).val());
    if (isNaN(sendAmount) || sendAmount <= 0)
    {
        alert('ERROR: bad send amount');
        return;
    }*/

    var sendFee = parseFloat($( '#inputModalSendFee' ).val());
    if (isNaN(sendFee) || sendFee < 0)
        sendFee = 0.0;

    const network = $('#inputModalSendNetwork').val();
   // require('./app').RefreshKeyPairsBalance(network);

    var jsonSavedKeyPairs = utils.getItem("KeyPairs").value || {};

    var addresses = [];
    for (var key in jsonSavedKeyPairs)
    {
        if (utils.coinsInfo[jsonSavedKeyPairs[key].network] != utils.coinsInfo[network])
            continue;

        if (parseFloat(jsonSavedKeyPairs[key].balance) <= 0.0)
            continue;

        addresses.push(jsonSavedKeyPairs[key].address);
    }

    if (!addresses.length)
    {
        alerts.Alert("Error", "Bad balance or network.
Please check balance for the '"+utils.coinsInfo[network].name+"' network.");
        return;
    }

    console.log('call getUnspentTransactions');
    utils.getUnspentTransactions(network, addresses, function(netID, data) {
        if (!data || !data.status || data.status.localeCompare('success') != 0)
        {
            console.log("getUnspentTransaction failed data="+(data?JSON.stringify(data):"null"))
            alerts.Alert("Error", "Сan not find unspent transaction for the '"+utils.coinsInfo[network].name+"' network. Please try again later.");
            require('./app').RefreshKeyPairsBalance(network);
            return;
        }
        console.log("getUnspentTransactions success. data="+JSON.stringify(data));
        const networkCurrent = bitcoin.networks[utils.coinsInfo[network].name];

        var new_transaction = new bitcoin.TransactionBuilder(networkCurrent);

        //Inputs
        var address_for_change = "";
        var current_amount = 0.0;
        var aSignArray = [];
        //var mapIndexToPrivateKey = {};
        //var txIndex = 0;
        //console.log('data.data='+JSON.stringify([].concat(data.data)));
        var unspent = [].concat(data.data);
        for (var n=0; n<unspent.length; n++)
        {
            const element = unspent[n];

            console.log('element='+JSON.stringify(element));

            const keyPrivate = utils.getPrivateKey(element.address, password);
            const keyPair = bitcoin.ECPair.fromWIF(keyPrivate, networkCurrent);

            for (var i=0; i<element.unspent.length; i++)
            {
                if (!address_for_change.length)
                    address_for_change = element.address;

                new_transaction.addInput(element.unspent[i].tx, element.unspent[i].n);

                aSignArray.push(keyPair);

                current_amount += parseFloat(element.unspent[i].amount);
                if (current_amount >= dFullSentAmount+sendFee)
                {
                    //console.log("current_amount >= sendAmount+sendFee: " + current_amount + " >= " + sendAmount+sendFee);
                    break;
                }
            }
            if (current_amount >= dFullSentAmount+sendFee)
                break;
        }

        dFullSentAmount = utils.MakeFloat(dFullSentAmount);
        sendFee = utils.MakeFloat(sendFee);
        current_amount = utils.MakeFloat(current_amount);

        console.log('current_amount='+current_amount);

        if (current_amount < dFullSentAmount+sendFee)
        {
            alerts.Alert('Error', 'Bad (too big) send amount!');
            require('./app').RefreshKeyPairsBalance(network);
            return;
        }

       // privateKeys.forEach(function(element) {
       //     new_transaction.addInput(element.tx, 0);
       // });

        //Output
        var fRealSendAmount = 0.0;
        rowSentInfo.forEach(function(item){
            const amount = utils.coinsInfo[network].GetOutTxAmount(item.sendAmount);
            //new_transaction.addOutput(item.addressSendTo, parseInt(parseFloat(item.sendAmount)/0.00000001));
            new_transaction.addOutput(item.addressSendTo, amount);
            fRealSendAmount += parseFloat(item.sendAmount);
        });

        fRealSendAmount = utils.MakeFloat(fRealSendAmount);

        if (fRealSendAmount > current_amount)
            fRealSendAmount = current_amount;

        const fChange = utils.MakeFloat(parseFloat(current_amount) - fRealSendAmount - parseFloat(sendFee));

        if (fChange > 1.e-10 && address_for_change.length)
        {
            const amount = utils.coinsInfo[network].GetOutTxAmount(fChange);
            new_transaction.addOutput(address_for_change, amount);
        }

        //Sign
        for (var i=0; i<aSignArray.length; i++)
        {
            new_transaction.sign(i, aSignArray[i]);
        }

        utils.pushTransaction(network, new_transaction.build().toHex(), sendFee, function(e) {
            if (!e)
                jQuery('#send_coins_to').modal('show');
        });
    });
});<commit_msg>fix default tx fee<commit_after>'use strict';

const bitcoin = require('multicoinjs-lib');
const utils = require('./utils.js');
const alerts = require('./alerts');
const $ = require('jquery');

exports.ChangeBalance = function(fNewBalance)
{
    if (fNewBalance < 1.e-12) fNewBalance = 0;

    $('#spanModalBalance').text(fNewBalance);

    $('.groupBalance').removeClass('has-error');
    $('.groupBalance').addClass('has-success');
    if (fNewBalance < 0)
    {
        $('.groupBalance').removeClass('has-success');
        $('.groupBalance').addClass('has-error');
    }

}

exports.onOpenDialog = function(network, address, strLabel, strCoinShortName)
{
    $('#inputModalSendAddressLabel').val(strLabel);
    $('#inputModalSendFee').val('');
    $("#inputModalSendAmount").val('');
    $('#spanModalAmountCoinName').text(strCoinShortName);
    $('#spanModalFeeCoinName').text(strCoinShortName);
    $('#spanModalBalance').text(utils.getSavedBalance(network));

    $('#inputModalSendNetwork').val(network);
    $('#inputModalSendAddress').val(address);

    function onChangeFee()
    {
        var fee = $( '#inputModalSendFee' ).val().replace(/[^\d.-]/g, '');
        var sendFee = parseFloat(fee);
        if (isNaN(sendFee))
            sendFee = parseFloat(utils.coinsInfo[network].fee.toPrecision(12));
        else
        {
            if ((sendFee+"").length >=12)
                sendFee = parseFloat(sendFee.toPrecision(12));
            else
                sendFee = fee;
        }

        $('#inputModalSendFee').val(sendFee);
        $('#inputModalSendFee')[0].placeholder = sendFee;
        $('.spanRecommendedFee').text('(recommended minimum '+parseFloat(utils.coinsInfo[network].fee.toPrecision(12))+' )');

        var sendAmount = parseFloat($( "#inputModalSendAmount" ).val());
        if (isNaN(sendAmount))
            sendAmount = 0;

        exports.ChangeBalance(
            parseFloat( (utils.getSavedBalance(network)-sendAmount-sendFee).toPrecision(12)) );
    }

    $( "#inputModalSendFee" ).on('input', onChangeFee);

    onChangeFee();

    jQuery('#send_coins_to').modal('show');

};

$('#btnSendCoinsReady').click(function () {
    console.log('btnSendCoinsReady click');
    const password = $('#inputSendMoneyPassword').val();
    if (utils.getSavedEncodePassword().length && !utils.isValidEncodePassword(password))
    {
        console.log('Invalid send password: ' + password);
        alerts.Alert('Error', 'Invalid password!');
        return;
    }
    jQuery('#send_coins_to').modal('hide');

    var rowSentInfo = [];
    var dFullSentAmount = 0.0;
    for (var i=0; i<$('.rowAddressSendTo').length; i++)
    {
        const row = $('.rowAddressSendTo')[i];
        const sendAmount = parseFloat($(row).find('#inputModalSendAmount').val());
        if (isNaN(sendAmount) || sendAmount <= 0)
        {
            alerts.Alert('Error', 'Bad send amount');
            return;
        }
        dFullSentAmount += sendAmount;

        rowSentInfo.push({addressSendTo : $(row).find('.spanAddressTo').text(), sendAmount : sendAmount});
    }

    console.log('btnSendCoinsReady sent amount checked');

    /*const addressSendTo = $('.spanAddressTo')[0].textContent;

    const sendAmount = parseFloat($( "#inputModalSendAmount" ).val());
    if (isNaN(sendAmount) || sendAmount <= 0)
    {
        alert('ERROR: bad send amount');
        return;
    }*/

    var sendFee = parseFloat($( '#inputModalSendFee' ).val());
    if (isNaN(sendFee) || sendFee < 0)
        sendFee = 0.0;

    const network = $('#inputModalSendNetwork').val();
   // require('./app').RefreshKeyPairsBalance(network);

    var jsonSavedKeyPairs = utils.getItem("KeyPairs").value || {};

    var addresses = [];
    for (var key in jsonSavedKeyPairs)
    {
        if (utils.coinsInfo[jsonSavedKeyPairs[key].network] != utils.coinsInfo[network])
            continue;

        if (parseFloat(jsonSavedKeyPairs[key].balance) <= 0.0)
            continue;

        addresses.push(jsonSavedKeyPairs[key].address);
    }

    if (!addresses.length)
    {
        alerts.Alert("Error", "Bad balance or network.
Please check balance for the '"+utils.coinsInfo[network].name+"' network.");
        return;
    }

    console.log('call getUnspentTransactions');
    utils.getUnspentTransactions(network, addresses, function(netID, data) {
        if (!data || !data.status || data.status.localeCompare('success') != 0)
        {
            console.log("getUnspentTransaction failed data="+(data?JSON.stringify(data):"null"))
            alerts.Alert("Error", "Сan not find unspent transaction for the '"+utils.coinsInfo[network].name+"' network. Please try again later.");
            require('./app').RefreshKeyPairsBalance(network);
            return;
        }
        console.log("getUnspentTransactions success. data="+JSON.stringify(data));
        const networkCurrent = bitcoin.networks[utils.coinsInfo[network].name];

        var new_transaction = new bitcoin.TransactionBuilder(networkCurrent);

        //Inputs
        var address_for_change = "";
        var current_amount = 0.0;
        var aSignArray = [];
        //var mapIndexToPrivateKey = {};
        //var txIndex = 0;
        //console.log('data.data='+JSON.stringify([].concat(data.data)));
        var unspent = [].concat(data.data);
        for (var n=0; n<unspent.length; n++)
        {
            const element = unspent[n];

            console.log('element='+JSON.stringify(element));

            const keyPrivate = utils.getPrivateKey(element.address, password);
            const keyPair = bitcoin.ECPair.fromWIF(keyPrivate, networkCurrent);

            for (var i=0; i<element.unspent.length; i++)
            {
                if (!address_for_change.length)
                    address_for_change = element.address;

                new_transaction.addInput(element.unspent[i].tx, element.unspent[i].n);

                aSignArray.push(keyPair);

                current_amount += parseFloat(element.unspent[i].amount);
                if (current_amount >= dFullSentAmount+sendFee)
                {
                    //console.log("current_amount >= sendAmount+sendFee: " + current_amount + " >= " + sendAmount+sendFee);
                    break;
                }
            }
            if (current_amount >= dFullSentAmount+sendFee)
                break;
        }

        dFullSentAmount = utils.MakeFloat(dFullSentAmount);
        sendFee = utils.MakeFloat(sendFee);
        current_amount = utils.MakeFloat(current_amount);

        console.log('current_amount='+current_amount);

        if (current_amount < dFullSentAmount+sendFee)
        {
            alerts.Alert('Error', 'Bad (too big) send amount!');
            require('./app').RefreshKeyPairsBalance(network);
            return;
        }

       // privateKeys.forEach(function(element) {
       //     new_transaction.addInput(element.tx, 0);
       // });

        //Output
        var fRealSendAmount = 0.0;
        rowSentInfo.forEach(function(item){
            const amount = utils.coinsInfo[network].GetOutTxAmount(item.sendAmount);
            //new_transaction.addOutput(item.addressSendTo, parseInt(parseFloat(item.sendAmount)/0.00000001));
            new_transaction.addOutput(item.addressSendTo, amount);
            fRealSendAmount += parseFloat(item.sendAmount);
        });

        fRealSendAmount = utils.MakeFloat(fRealSendAmount);

        if (fRealSendAmount > current_amount)
            fRealSendAmount = current_amount;

        const fChange = utils.MakeFloat(parseFloat(current_amount) - fRealSendAmount - parseFloat(sendFee));

        if (fChange > 1.e-10 && address_for_change.length)
        {
            const amount = utils.coinsInfo[network].GetOutTxAmount(fChange);
            new_transaction.addOutput(address_for_change, amount);
        }

        //Sign
        for (var i=0; i<aSignArray.length; i++)
        {
            new_transaction.sign(i, aSignArray[i]);
        }

        utils.pushTransaction(network, new_transaction.build().toHex(), sendFee, function(e) {
            if (!e)
                jQuery('#send_coins_to').modal('show');
        });
    });
});<|endoftext|>