<commit_before>(function(suggestions, $) {
	suggestions.codesFromindex = [];
	suggestions.matrix = [];
	suggestions.indexFromCodes = {};
	suggestions.current = [];
	suggestions.exclusions = [];
	suggestions.number;

	suggestions.query = function(side) {
		suggestions.promise = $.ajax('/'+side+'.json', {
			dataType: 'json',
			success: function (data) {
				suggestions.codesFromindex = data.index;
				suggestions.matrix = data.matrix;
				// reconstitute the full matrix from the lower half matrix
				for(var i=0; i<suggestions.matrix.length; i++) {
					for(var j=i; j<suggestions.matrix.length; j++) {
						suggestions.matrix[i][j] = suggestions.matrix[j][i];
					}
				}
				for(var i=0; i<suggestions.codesFromindex.length; i++) {
					suggestions.indexFromCodes[suggestions.codesFromindex[i]] = i;
				}
			},
			error: function( jqXHR, textStatus, errorThrown ) {
				console.log('['+moment().format('YYYY-MM-DD HH:mm:ss')+'] Error on '+this.url, textStatus, errorThrown);
			}
		});
		suggestions.promise.done(suggestions.compute);
	};

        suggestions.refresh = function () {
                suggestions.number = parseInt(NRDB.settings.getItem('show-suggestions'), 10);
        }

	suggestions.compute = function() {
		suggestions.refresh();

                // init current suggestions
                suggestions.codesFromindex.forEach(function (code, index) {
                        suggestions.current[index] = {
                                code: code,
                                proba: 0
                        };
                });
                // find used cards
                var indexes = NRDB.data.cards.find({indeck:{'$gt':0}}).map(function (card) {
                        return suggestions.indexFromCodes[card.code];
                });
                // add suggestions of all used cards
                indexes.forEach(function (i) {
                        if(suggestions.matrix[i]) {
                                suggestions.matrix[i].forEach(function (value, j) {
                                        suggestions.current[j].proba += (value || 0);
                                });
                        }
                });
                // remove suggestions of already used cards
                indexes.forEach(function (i) {
                        if(suggestions.current[i]) suggestions.current[i].proba = 0;
                });
                // remove suggestions of identity
                NRDB.data.cards.find({type_code:'identity'}).map(function (card) {
                        return suggestions.indexFromCodes[card.code];
                }).forEach(function (i) {
                        if(suggestions.current[i]) suggestions.current[i].proba = 0;
                });
                // remove suggestions of excluded cards
                suggestions.exclusions.forEach(function (i) {
                        suggestions.current[i].proba = 0;
                });
                // sort suggestions
                suggestions.current.sort(function (a, b) {
                        return (b.proba - a.proba);
                });

		suggestions.show();
	};

	suggestions.show = function() {
                suggestions.refresh();

                var table = $('#table-suggestions');
		var tbody = table.children('tbody');
		tbody.empty();
		if(!suggestions.number && table.is(':visible')) {
			table.hide();
			return;
		}
		if(suggestions.number && !table.is(':visible')) {
			table.show();
		}
		var nb = 0;
		for(var i=0; i<suggestions.current.length; i++) {
			if(suggestions.current[i].proba === 0) continue;
			var card = NRDB.data.cards.findById(suggestions.current[i].code);
			if(is_card_usable(card) && Filters.pack_code.indexOf(card.pack_code) > -1) {
				var div = suggestions.div(card);
				div.on('click', 'button.close', suggestions.exclude.bind(this, card.code));
				tbody.append(div);
				if(++nb >= suggestions.number) break;
			}
		}
	};

	suggestions.div = function(record) {
		var faction = record.faction_code;
		var influ = "";
		for (var i = 0; i < record.factioncost; i++)
			influ += "●";

		var radios = '';
		for (var i = 0; i <= record.maxqty; i++) {
			radios += '<input type="radio" name="qty-' + record.code
					+ '" value="' + i + '">' + i + '';
		}

		var imgsrc = record.faction_code.substr(0,7) === "neutral" ? "" : '';
		var div = $('
<button type="button" class="close">×Remove</button>	'
					+ '
'
					+ radios
					+ '
	'
					+ record.title + '	' + influ + '	'
					+ '	'
					+ imgsrc + '
');

		return div;
	};

	suggestions.exclude = function(code) {
		suggestions.exclusions.push(suggestions.indexFromCodes[code]);
		suggestions.compute();
	};

	suggestions.pick = function(event) {
		InputByTitle = false;
		var input = this;
		$(input).closest('tr').animate({
			opacity: 0
		}, function() {
			handle_quantity_change.call(input, event);
		});
	};

	$(function() {

		$('#table-suggestions').on({
			change : suggestions.pick
		}, 'input[type=radio]');

	});

})(NRDB.suggestions = {}, jQuery);
<commit_msg>Remove extra .png at the end of the faction images in the suggestion box.<commit_after>(function(suggestions, $) {
	suggestions.codesFromindex = [];
	suggestions.matrix = [];
	suggestions.indexFromCodes = {};
	suggestions.current = [];
	suggestions.exclusions = [];
	suggestions.number;

	suggestions.query = function(side) {
		suggestions.promise = $.ajax('/'+side+'.json', {
			dataType: 'json',
			success: function (data) {
				suggestions.codesFromindex = data.index;
				suggestions.matrix = data.matrix;
				// reconstitute the full matrix from the lower half matrix
				for(var i=0; i<suggestions.matrix.length; i++) {
					for(var j=i; j<suggestions.matrix.length; j++) {
						suggestions.matrix[i][j] = suggestions.matrix[j][i];
					}
				}
				for(var i=0; i<suggestions.codesFromindex.length; i++) {
					suggestions.indexFromCodes[suggestions.codesFromindex[i]] = i;
				}
			},
			error: function( jqXHR, textStatus, errorThrown ) {
				console.log('['+moment().format('YYYY-MM-DD HH:mm:ss')+'] Error on '+this.url, textStatus, errorThrown);
			}
		});
		suggestions.promise.done(suggestions.compute);
	};

        suggestions.refresh = function () {
                suggestions.number = parseInt(NRDB.settings.getItem('show-suggestions'), 10);
        }

	suggestions.compute = function() {
		suggestions.refresh();

                // init current suggestions
                suggestions.codesFromindex.forEach(function (code, index) {
                        suggestions.current[index] = {
                                code: code,
                                proba: 0
                        };
                });
                // find used cards
                var indexes = NRDB.data.cards.find({indeck:{'$gt':0}}).map(function (card) {
                        return suggestions.indexFromCodes[card.code];
                });
                // add suggestions of all used cards
                indexes.forEach(function (i) {
                        if(suggestions.matrix[i]) {
                                suggestions.matrix[i].forEach(function (value, j) {
                                        suggestions.current[j].proba += (value || 0);
                                });
                        }
                });
                // remove suggestions of already used cards
                indexes.forEach(function (i) {
                        if(suggestions.current[i]) suggestions.current[i].proba = 0;
                });
                // remove suggestions of identity
                NRDB.data.cards.find({type_code:'identity'}).map(function (card) {
                        return suggestions.indexFromCodes[card.code];
                }).forEach(function (i) {
                        if(suggestions.current[i]) suggestions.current[i].proba = 0;
                });
                // remove suggestions of excluded cards
                suggestions.exclusions.forEach(function (i) {
                        suggestions.current[i].proba = 0;
                });
                // sort suggestions
                suggestions.current.sort(function (a, b) {
                        return (b.proba - a.proba);
                });

		suggestions.show();
	};

	suggestions.show = function() {
                suggestions.refresh();

                var table = $('#table-suggestions');
		var tbody = table.children('tbody');
		tbody.empty();
		if(!suggestions.number && table.is(':visible')) {
			table.hide();
			return;
		}
		if(suggestions.number && !table.is(':visible')) {
			table.show();
		}
		var nb = 0;
		for(var i=0; i<suggestions.current.length; i++) {
			if(suggestions.current[i].proba === 0) continue;
			var card = NRDB.data.cards.findById(suggestions.current[i].code);
			if(is_card_usable(card) && Filters.pack_code.indexOf(card.pack_code) > -1) {
				var div = suggestions.div(card);
				div.on('click', 'button.close', suggestions.exclude.bind(this, card.code));
				tbody.append(div);
				if(++nb >= suggestions.number) break;
			}
		}
	};

	suggestions.div = function(record) {
		var faction = record.faction_code;
		var influ = "";
		for (var i = 0; i < record.factioncost; i++)
			influ += "●";

		var radios = '';
		for (var i = 0; i <= record.maxqty; i++) {
			radios += '<input type="radio" name="qty-' + record.code
					+ '" value="' + i + '">' + i + '';
		}

		var imgsrc = record.faction_code.substr(0,7) === "neutral" ? "" : '';
		var div = $('
<button type="button" class="close">×Remove</button>	'
					+ '
'
					+ radios
					+ '
	'
					+ record.title + '	' + influ + '	'
					+ '	'
					+ imgsrc + '
');

		return div;
	};

	suggestions.exclude = function(code) {
		suggestions.exclusions.push(suggestions.indexFromCodes[code]);
		suggestions.compute();
	};

	suggestions.pick = function(event) {
		InputByTitle = false;
		var input = this;
		$(input).closest('tr').animate({
			opacity: 0
		}, function() {
			handle_quantity_change.call(input, event);
		});
	};

	$(function() {

		$('#table-suggestions').on({
			change : suggestions.pick
		}, 'input[type=radio]');

	});

})(NRDB.suggestions = {}, jQuery);
<|endoftext|>


<commit_before>/*
 *contextMenu.js v 1.2.0
 *Author: Sudhanshu Yadav
 *s-yadav.github.com
 *Copyright (c) 2013 Sudhanshu Yadav.
 *Dual licensed under the MIT and GPL licenses
 */
;(function(e,t,n,r){"use strict";e.fn.contextMenu=function(t,n,r){if(!i[t]){r=n;n=t;t="popup"}else if(n){if(!(n instanceof Array||typeof n==="string"||n.nodeType||n.jquery)){r=n;n=null}}if(n instanceof Array&&t!="update"){t="menu"}var o=r;if(t!="update"){r=s.optionOtimizer(t,r);o=e.extend({},e.fn.contextMenu.defaults,r);if(!o.baseTrigger){o.baseTrigger=this}}i[t].call(this,n,o);return this};e.fn.contextMenu.defaults={triggerOn:"click",displayAround:"cursor",mouseClick:"left",verAdjust:0,horAdjust:0,top:"auto",left:"auto",closeOther:true,containment:t,winEventClose:true,sizeStyle:"auto",position:"auto",closeOnClick:true,onOpen:function(e,t){},afterOpen:function(e,t){},onClose:function(e,t){}};var i={menu:function(t,n){var r=e(this);t=s.createMenuList(r,t,n);s.contextMenuBind.call(this,t,n,"menu")},popup:function(t,n){e(t).addClass("iw-contextMenu");s.contextMenuBind.call(this,t,n,"popup")},update:function(t,n){var r=this;this.each(function(){var i=e(this),o=i.data("iw-menuData");if(!o){r.contextMenu("refresh");o=i.data("iw-menuData")}var u=o.menu;if(typeof t==="object"){for(var a=0;a<t.length;a++){var f=t[a].name,l=t[a].disable,c=u.children("li").filter(function(){return e(this).contents().filter(function(){return this.nodeType==3}).text()==f}),h=t[a].subMenu;if(l=="true"){c.addClass("iw-mDisable")}else{c.removeClass("iw-mDisable")}if(h){c.contextMenu("update",h)}}}s.onOff(u);o.option=e.extend({},o.option,n);i.data("iw-menuData",o);var p=o.option.triggerOn;if(n){if(p!=n.triggerOn){i.unbind(".contextMenu");i.bind(p+".contextMenu",s.eventHandler)}}})},refresh:function(){var t=this.filter(function(){return!!e(this).data("iw-menuData")}).data("iw-menuData"),n=this.filter(function(){return!e(this).data("iw-menuData")});t.option.baseTrigger=this;s.contextMenuBind.call(n,t.menuSelector,t.option)},close:function(){var e=this.data("iw-menuData");if(e){s.closeContextMenu(e.option,this,e.menu,null)}},value:function(e){var t=this.data("iw-menuData");if(t[e]){return t[e]}else if(t.option){return t.option[e]}return null},destroy:function(){this.each(function(){var t=e(this),n=t.data("iw-menuData").menuId,r=e(".iw-contextMenu[menuId="+n+"]"),i=r.data("iw-menuData");if(!i)return;if(i.noTrigger==1){if(r.hasClass("iw-created")){r.remove()}else{r.removeClass("iw-contextMenu "+n).removeAttr("menuId").removeData("iw-menuData");r.find("li.iw-mTrigger").contextMenu("destroy")}}else{i.noTrigger--;r.data("iw-menuData",i)}t.unbind(".contextMenu").removeClass("iw-mTrigger").removeData("iw-menuData")})}};var s={contextMenuBind:function(t,n,r){var i=this,o=e(t),u=o.data("iw-menuData");if(o.length==0){o=i.find(t);if(o.length==0){return}}if(r=="menu"){s.menuHover(o)}var a=n.baseTrigger;if(!u){var f;if(!a.data("iw-menuData")){f=Math.ceil(Math.random()*1e5);a.data("iw-menuData",{menuId:f})}else{f=a.data("iw-menuData").menuId}var l=o.clone();l.appendTo("body");u={menuId:f,menuWidth:l.outerWidth(true),menuHeight:l.outerHeight(true),noTrigger:1,trigger:i};o.data("iw-menuData",u).attr("menuId",f);l.remove()}else{u.noTrigger++;o.data("iw-menuData",u)}i.addClass("iw-mTrigger").data("iw-menuData",{menuId:u.menuId,option:n,menu:o,menuSelector:t,method:r});var c;if(n.triggerOn=="hover"){c="mouseenter";if(a.index(i)!=-1){a.add(o).bind("mouseleave.contextMenu",function(t){if(e(t.relatedTarget).closest(".iw-contextMenu").length==0){e('.iw-contextMenu[menuId="'+u.menuId+'"]').hide(100)}})}}else{c=n.triggerOn}i.bind(c+".contextMenu",s.eventHandler);o.bind("click mouseenter",function(e){e.stopPropagation()});o.delegate("li","click",function(e){if(n.closeOnClick)s.closeContextMenu(n,i,o,e)})},eventHandler:function(r){r.preventDefault();var i=e(this),o=i.data("iw-menuData"),u=o.menu,a=u.data("iw-menuData"),f=o.option,l=f.containment,c={trigger:i,menu:u},h=l==t,p=f.baseTrigger.index(i)==-1;if(!p&&f.closeOther){e(".iw-contextMenu").css("display","none")}u.find(".iw-mSelected").removeClass("iw-mSelected");f.onOpen.call(this,c,r);var d=e(l),v=d.innerHeight(),m=d.innerWidth(),g=0,y=0,b=a.menuHeight,w=a.menuWidth,E,S,x=0,T=0,N,C,k=E=parseInt(f.verAdjust),L=S=parseInt(f.horAdjust);if(!h){g=d.offset().top;y=d.offset().left;if(d.css("position")=="static"){d.css("position","relative")}}if(f.sizeStyle=="auto"){b=Math.min(b,v);w=Math.min(w,m);w=w+20}if(f.displayAround=="cursor"){x=h?r.clientX:r.clientX+e(t).scrollLeft()-y;T=h?r.clientY:r.clientY+e(t).scrollTop()-g;N=T+b;C=x+w;if(N>v){if(T-b<0){if(N-vm){if(x-w<0){if(C-m<w-x){x=m-w;S=-1*S}else{x=0;S=0}}else{x=x-w;S=-1*S}}}else if(f.displayAround=="trigger"){var A=i.outerHeight(true),O=i.outerWidth(true),M=h?i.offset().left-d.scrollLeft():i.offset().left-y,_=h?i.offset().top-d.scrollTop():i.offset().top-g,D=O;x=M+O;T=_;N=T+b;C=x+w;if(N>v){if(T-b<0){if(N-vm){if(x-w<0){if(C-m<w-x){x=m-w;S=-1*S;D=-O}else{x=0;S=0;D=0}}else{x=x-w-O;S=-1*S;D=-O}}if(f.position=="top"){b=Math.min(a.menuHeight,_);T=_-b;E=k;x=x-D}else if(f.position=="left"){w=Math.min(a.menuWidth,M);x=M-w;S=L}else if(f.position=="bottom"){b=Math.min(a.menuHeight,v-_-A);T=_+A;E=k;x=x-D}else if(f.position=="right"){w=Math.min(a.menuWidth,m-M-O);x=M+O;S=L}}var P=u.outerWidth(true)-u.width(),H=u.outerHeight(true)-u.height();var B={position:h||p?"fixed":"absolute",display:"inline-block",height:"",width:"","overflow-y":b!=a.menuHeight?"auto":"hidden","overflow-x":w!=a.menuWidth?"auto":"hidden"};if(f.sizeStyle=="auto"){B.height=b-H+"px";B.width=w-P+"px"}if(f.left!="auto"){x=s.getPxSize(f.left,m)}if(f.top!="auto"){T=s.getPxSize(f.top,v)}if(!h){var j=i.offsetParent().offset();if(p){x=x+y-e(t).scrollLeft();T=T+g-e(t).scrollTop()}else{x=x-(y-j.left);T=T-(g-j.top)}}B.left=x+S+"px";B.top=T+E+"px";u.css(B);f.afterOpen.call(this,c,r);if(i.closest(".iw-contextMenu").length==0){e(".iw-curMenu").removeClass("iw-curMenu");u.addClass("iw-curMenu")}var F={trigger:i,menu:u,option:f,method:o.method};e("html").unbind("click",s.clickEvent).click(F,s.clickEvent);e(n).unbind("keydown",s.keyEvent).keydown(F,s.keyEvent);if(f.winEventClose){e(t).bind("scroll resize",F,s.scrollEvent)}},scrollEvent:function(e){s.closeContextMenu(e.data.option,e.data.trigger,e.data.menu,e)},clickEvent:function(t){var n=t.data.trigger.get(0);if(n!==t.target&&e(t.target).closest(".iw-contextMenu").length==0){s.closeContextMenu(t.data.option,t.data.trigger,t.data.menu,t)}},keyEvent:function(t){t.preventDefault();var n=t.data.menu,r=t.data.option,i=t.keyCode;if(i==27){s.closeContextMenu(r,t.data.trigger,n,t)}if(t.data.method=="menu"){var o=e(".iw-curMenu"),u=o.children("li:not(.iw-mDisable)"),a=u.filter(".iw-mSelected"),f=u.index(a),l=function(e){a.removeClass("iw-mSelected");e.addClass("iw-mSelected")},c=function(){l(u.filter(":first"))},h=function(){l(u.filter(":last"))},p=function(){l(u.filter(":eq("+(f+1)+")"))},d=function(){l(u.filter(":eq("+(f-1)+")"))},v=function(){var e=a.data("iw-menuData");if(e){a.triggerHandler("mouseenter.contextMenu");var t=e.menu;t.addClass("iw-curMenu");o.removeClass("iw-curMenu");o=t;u=o.children("li:not(.iw-mDisable)");a=u.filter(".iw-mSelected");c()}},m=function(){var e=o.data("iw-menuData").trigger;var t=e.closest(".iw-contextMenu");if(t.length!=0){o.removeClass("iw-curMenu").css("display","none");t.addClass("iw-curMenu")}};switch(i){case 13:a.click();break;case 40:f==u.length-1||a.length==0?c():p();break;case 38:f==0||a.length==0?h():d();break;case 33:c();break;case 34:h();break;case 37:m();break;case 39:v();break}}},closeContextMenu:function(r,i,o,u){e(n).unbind("keydown",s.keyEvent);e("html").unbind("click",s.clickEvent);e(t).unbind("scroll resize",s.scrollEvent);e(".iw-contextMenu").hide();e(n).focus();r.onClose.call(this,{trigger:i,menu:o},u)},getPxSize:function(e,t){if(!isNaN(e)){return e}if(e.indexOf("%")!=-1){return parseInt(e)*t/100}else{return parseInt(e)}},menuHover:function(t){t.children("li").bind("mouseenter",function(n){e(".iw-curMenu").removeClass("iw-curMenu");t.addClass("iw-curMenu");var r=t.find("li.iw-mSelected"),i=r.find(".iw-contextMenu");if(i.length!=0&&r[0]!=this){i.hide(100)}r.removeClass("iw-mSelected");e(this).addClass("iw-mSelected")})},createMenuList:function(n,r,i){var o=i.baseTrigger,u=Math.floor(Math.random()*1e4);if(typeof r=="object"&&!r.nodeType&&!r.jquery){var a=e('

');for(var f=0;f<r.length;f++){var l=r[f],c=l.name,h=l.fun,p=l.subMenu,d=l.img||"",v=l.title||"",m=l.className||"",g=l.disable,y=e('
'+c+"
");if(d){y.prepend('')}if(g=="true"){y.addClass("iw-mDisable")}y.bind("click",h);a.append(y);if(p){y.append('
');s.subMenu(y,p,o,i)}}if(o.index(n[0])==-1){n.append(a)}else{var b=i.containment==t?"body":i.containment;e(b).append(a)}s.onOff(e("#iw-contextMenu"+u));return"#iw-contextMenu"+u}else if(e(r).length!=0){var w=e(r);w.removeClass("iw-contextMenuCurrent").addClass("iw-contextMenu iw-cm-menu iw-contextMenu"+u).attr("menuId","iw-contextMenu"+u).css("display","none");w.find("ul").each(function(t,n){var r=e(this),u=r.parent("li");u.append('
');r.addClass("iw-contextMenuCurrent");s.subMenu(u,".iw-contextMenuCurrent",o,i)});s.onOff(e(".iw-contextMenu"+u));return".iw-contextMenu"+u}},subMenu:function(e,t,n,r){e.contextMenu("menu",t,{triggerOn:"hover",displayAround:"trigger",position:"auto",baseTrigger:n,containment:r.containment})},onOff:function(t){t.find(".iw-mOverlay").remove();t.find(".iw-mDisable").each(function(){var t=e(this);t.append('
');t.find(".iw-mOverlay").bind("click mouseenter",function(e){e.stopPropagation()})})},optionOtimizer:function(t,n){if(!n){return}if(t=="menu"){if(!n.mouseClick){n.mouseClick="right"}}if(n.mouseClick=="right"&&n.triggerOn=="click"){n.triggerOn="contextmenu"}if(e.inArray(n.triggerOn,["hover","mouseenter","mouseover","mouseleave","mouseout","focusin","focusout"])!=-1){n.displayAround="trigger"}return n}}})(jQuery,window,document);<commit_msg>added context menu<commit_after><|endoftext|>


<commit_before>var express = require('express');
var router = express.Router();
var moment = require('moment');

var VersionModel = require('../model/version_model');
var IterationModel = require('../model/iteration_model');
var ProjectModel = require('../model/project_model');
var RouterService = require('../service/router_service');

// 列表
router.get('/', function(req, res) {
  var where = {};
  if (req.query.status) {
    where.status = req.query.status.split(',');
  } else {
    where.status = IterationModel.statusOnline;
  }
  if (req.query.version_id) {
    where.version_id = req.query.version_id;
  }
  IterationModel
    .findAndCount({
      where: where,
      offset: req.query.offset || 0,
      limit: req.query.limit || 10,
      order: 'id DESC',
      include: [
        {model: VersionModel, include: [{model: ProjectModel}]}
      ]
    })
    .then(function(result) {
      res.json(result);
    });
});

// 新增
router.post('/', checkVersionId, checkUniqVN);
router.post('/', function(req, res) {
  IterationModel
    .build(req.body)
    .save()
    .then(function(iteration) {
      res.json({id: iteration.id});
    })
    .catch(function(err) {
      RouterService.json(err, res);
    });
});

router.use('/:id', function(req, res, next) {
  IterationModel
    .find(req.params.id)
    .then(function(iteration) {
      if (iteration === null) {
        res.status(400);
        res.json({msg: '迭代不存在'});
      } else {
        req.iteration = iteration;
        next();
      }
    });
});

// 编辑
router.put('/:id', checkVersionId);
router.put('/:id', function(req, res, next) {
  if ((req.iteration.name !== req.body.name) || (req.iteration.version_id !== req.body.version_id)) {
    checkUniqVN(req, res, next);
  } else {
    next();
  }
});
router.put('/:id', function(req, res) {
  var iteration = req.iteration;
  iteration
    .updateAttributes(req.body)
    .then(function() {
      res.json({id: iteration.id});
    })
    .catch(function(err) {
      RouterService.json(err, res);
    });
});

// 关闭
router.put('/:id/toggle', function (req, res) {
  req.iteration
    .toggle()
    .then(function () {
      res.json({msg: '操作成功'});
    })
    .catch(function (err) {
      RouterService.json(err, res);
    });
});

// 删除
router.delete('/:id', function(req, res) {
  var iteration = req.iteration;
  iteration.status = IterationModel.statusDeleted;
  iteration
    .save()
    .then(function() {
      res.json({msg: '删除成功'});
    });
});

function checkVersionId(req, res, next) { // 检查版本ID是否存在
  VersionModel
    .find(req.body.version_id)
    .then(function(version) {
      if (version) {
        next();
      } else {
        res.status(400);
        res.json({msg: '版本号不存在'});
      }
    });
}
function checkUniqVN(req, res, next) { // 校验迭代名称是否存在
  IterationModel
    .find({
      where: {
        version_id: req.body.version_id,
        name: req.body.name,
      }
    })
    .then(function(iteration) {
      if (iteration) {
        res.status(400);
        res.json({msg: '迭代名称存在'});
      } else {
        next();
      }
    });
}

module.exports = router;<commit_msg>* 修改排序 * 修改分页<commit_after>var express = require('express');
var router = express.Router();
var moment = require('moment');

var VersionModel = require('../model/version_model');
var IterationModel = require('../model/iteration_model');
var ProjectModel = require('../model/project_model');
var RouterService = require('../service/router_service');

// 列表
router.get('/', function(req, res) {
  var where = {};
  if (req.query.status) {
    where.status = req.query.status.split(',');
  } else {
    where.status = IterationModel.statusOnline;
  }
  if (req.query.version_id) {
    where.version_id = req.query.version_id;
  }
  IterationModel
    .findAndCount({
      where: where,
      offset: req.query.offset || 0,
      limit: req.query.size || 10,
      order: 'id ASC',
      include: [
        {model: VersionModel, include: [{model: ProjectModel}]}
      ]
    })
    .then(function(result) {
      res.json(result);
    });
});

// 新增
router.post('/', checkVersionId, checkUniqVN);
router.post('/', function(req, res) {
  IterationModel
    .build(req.body)
    .save()
    .then(function(iteration) {
      res.json({id: iteration.id});
    })
    .catch(function(err) {
      RouterService.json(err, res);
    });
});

router.use('/:id', function(req, res, next) {
  IterationModel
    .find(req.params.id)
    .then(function(iteration) {
      if (iteration === null) {
        res.status(400);
        res.json({msg: '迭代不存在'});
      } else {
        req.iteration = iteration;
        next();
      }
    });
});

// 编辑
router.put('/:id', checkVersionId);
router.put('/:id', function(req, res, next) {
  if ((req.iteration.name !== req.body.name) || (req.iteration.version_id !== req.body.version_id)) {
    checkUniqVN(req, res, next);
  } else {
    next();
  }
});
router.put('/:id', function(req, res) {
  var iteration = req.iteration;
  iteration
    .updateAttributes(req.body)
    .then(function() {
      res.json({id: iteration.id});
    })
    .catch(function(err) {
      RouterService.json(err, res);
    });
});

// 关闭
router.put('/:id/toggle', function (req, res) {
  req.iteration
    .toggle()
    .then(function () {
      res.json({msg: '操作成功'});
    })
    .catch(function (err) {
      RouterService.json(err, res);
    });
});

// 删除
router.delete('/:id', function(req, res) {
  var iteration = req.iteration;
  iteration.status = IterationModel.statusDeleted;
  iteration
    .save()
    .then(function() {
      res.json({msg: '删除成功'});
    });
});

function checkVersionId(req, res, next) { // 检查版本ID是否存在
  VersionModel
    .find(req.body.version_id)
    .then(function(version) {
      if (version) {
        next();
      } else {
        res.status(400);
        res.json({msg: '版本号不存在'});
      }
    });
}
function checkUniqVN(req, res, next) { // 校验迭代名称是否存在
  IterationModel
    .find({
      where: {
        version_id: req.body.version_id,
        name: req.body.name,
      }
    })
    .then(function(iteration) {
      if (iteration) {
        res.status(400);
        res.json({msg: '迭代名称存在'});
      } else {
        next();
      }
    });
}

module.exports = router;<|endoftext|>


<commit_before>#!/usr/bin/env node
'use strict'

const program = require('commander')
const inquirer = require('inquirer')
const parallel = require('async/parallel')
const chalk = require('chalk')
const miteApi = require('mite-api')

const pkg = require('./../package.json')
const config = require('./config.js')
const mite = miteApi(config.get())
const miteTracker = require('./lib/mite-tracker')(config.get())

program
  .version(pkg.version)
  .description('interactively create a new time entry')
  .parse(process.argv)

parallel({
  projects: mite.getProjects,
  services: mite.getServices
}, (err, results) => {
  if (err) {
    throw err;
  }

  const questions = [
    {
      type: 'list',
      name: 'project_id',
      message: 'Choose Project',
      choices: results.projects
        .map(function(data) {
          var nameParts = [data.project.name];
          if (data.project.customer_name) {
            nameParts.push('(' + data.project.customer_name + ')')
          }
          return {
            name: nameParts.join(' '),
            value: data.project.id
          };
        })
        .sort()
    },
    {
      type: 'input',
      name: 'note',
      message: 'What was done?'
    },
    {
      type: 'input',
      name: 'minutes',
      message: 'How long did it take in minutes?'
    },
    {
      type: 'list',
      name: 'service_id',
      message: 'What service?',
      choices: results.services
        .map((data) => {
          let name = data.service.name;
          if (data.service.billable) {
            name += chalk.yellow.bold('$')
          }
          return {
            name: name,
            value: data.service.id
          };
        })
        .sort()
    },
    {
      type: 'input',
      name: 'date_at',
      message: 'Date?',
      default: (new Date()).toISOString().slice(0,10)
    }
  ];

  inquirer.prompt(questions).then((entry) => {
    // do not create an entry when project_id or minutes are empty
    if (!entry.project_id || !entry.minutes) {
      console.log('no time entry created due to empty project id or empty minutes')
      return;
    }

    // detect the "+" at the duration value and start a tracker for the time
    // entry
    let startTracker = false
    if (entry.minutes.substr(-1, 1) === '+') {
      startTracker = true
      entry.minutes = entry.minutes.substr(0, entry.minutes.length - 1)
    }

    // http://mite.yo.lk/en/api/time-entries.html#create
    mite.addTimeEntry({ time_entry: entry }, (response) => {
      console.log('Successfully created new time entry')
      if (startTracker) {
        var data = JSON.parse(response);
        miteTracker.start(data.time_entry.id).then(() => {
          console.log('Successfully started tracker for time entry')
        })
      }
    })
  }) // inquirer
}) // parallel
<commit_msg>fix(new): show error message when creation fails<commit_after>#!/usr/bin/env node
'use strict'

const program = require('commander')
const inquirer = require('inquirer')
const parallel = require('async/parallel')
const chalk = require('chalk')
const miteApi = require('mite-api')

const pkg = require('./../package.json')
const config = require('./config.js')
const mite = miteApi(config.get())
const miteTracker = require('./lib/mite-tracker')(config.get())

program
  .version(pkg.version)
  .description('interactively create a new time entry')
  .parse(process.argv)

parallel({
  projects: mite.getProjects,
  services: mite.getServices
}, (err, results) => {
  if (err) {
    throw err;
  }

  const questions = [
    {
      type: 'list',
      name: 'project_id',
      message: 'Choose Project',
      choices: results.projects
        .map(function(data) {
          var nameParts = [data.project.name];
          if (data.project.customer_name) {
            nameParts.push('(' + data.project.customer_name + ')')
          }
          return {
            name: nameParts.join(' '),
            value: data.project.id
          };
        })
        .sort()
    },
    {
      type: 'input',
      name: 'note',
      message: 'What was done?'
    },
    {
      type: 'input',
      name: 'minutes',
      message: 'How long did it take in minutes?'
    },
    {
      type: 'list',
      name: 'service_id',
      message: 'What service?',
      choices: results.services
        .map((data) => {
          let name = data.service.name;
          if (data.service.billable) {
            name += chalk.yellow.bold('$')
          }
          return {
            name: name,
            value: data.service.id
          };
        })
        .sort()
    },
    {
      type: 'input',
      name: 'date_at',
      message: 'Date?',
      default: (new Date()).toISOString().slice(0,10)
    }
  ];

  inquirer.prompt(questions).then((entry) => {
    // do not create an entry when project_id or minutes are empty
    if (!entry.project_id || !entry.minutes) {
      console.log('no time entry created due to empty project id or empty minutes')
      return;
    }

    // detect the "+" at the duration value and start a tracker for the time
    // entry
    let startTracker = false
    if (entry.minutes.substr(-1, 1) === '+') {
      startTracker = true
      entry.minutes = entry.minutes.substr(0, entry.minutes.length - 1)
    }

    // http://mite.yo.lk/en/api/time-entries.html#create
    mite.addTimeEntry({ time_entry: entry }, (response) => {
      var data = JSON.parse(response);
      if (data.error) {
        console.error('Error while creating new time entry:', data.error)
        process.exit(1)
        return
      }
      console.log('Successfully created new time entry')
      if (startTracker) {
        miteTracker.start(data.time_entry.id).then(() => {
          console.log('Successfully started tracker for time entry')
        })
      }
    })
  }) // inquirer
}) // parallel
<|endoftext|>


<commit_before>'use strict';

var emptyPromise     = require('deferred')(null)
  , genId            = require('time-uuid')
  , login            = require('mano-auth/server/authentication').login
  , registerSubmit   = require('mano-auth/controller/server-master/register-and-login').submit
  , mano             = require('mano')
  , sendNotification = require('../../server/email-notifications/create-account')
  , unserializeObjectRecord = require('../../server/utils/unserialize-object-record')

  , dbDriver = mano.dbDriver
  , maxage = 1000 * 60 * 60 * 24 * 7
  , customError      = require('es5-ext/error/custom')
  , promisify        = require('deferred').promisify
  , bcrypt           = require('bcrypt')
  , serializeValue   = require('dbjs/_setup/serialize/value')

  , genSalt = promisify(bcrypt.genSalt), hash = promisify(bcrypt.hash)
  , userStorage = mano.dbDriver.getStorage('user');

exports.login = require('mano-auth/controller/server-master/login');
exports.register = {
	submit: function (data) {
		if (data.isManager) {
			data['User#/roles'] = ['manager'];
			delete data.isManager;
		}

		return registerSubmit.apply(this, arguments)(function (result) {
			dbDriver.onDrain(function () { sendNotification(data).done(null, function (err) {
				console.log("Cannot send email", err, err.stack);
			}); });
		});
	}
};
exports['reset-password'] = require('mano-auth/controller/server-master/reset-password');
exports['request-reset-password'] =
	require('mano-auth/controller/server-master/request-reset-password');

exports['create-managed-account'] = {
	submit: function (data) {
		var that = this;
		return userStorage.searchOne({ keyPath: 'createManagedAccountToken',
			value: serializeValue(data['create-managed-account-token']) }, function (id) {
			return id.split('/')[0];
		}).then(function (userId) {
			if (!userId) {
				throw customError("Cannot process request", "MALFORMED_EMAIL", { statusCode: 400 });
			}
			return hash(data.password, genSalt())(function (password) {
				return userStorage.storeMany([
					{ id: userId + '/createManagedAccountToken', data: { value: '' } },
					{ id: userId + '/password', data: { value: serializeValue(password) } }
				]).then(function () {
					userStorage.getObject(userId,
						{ keyPaths: ['firstName', 'lastName', 'email'] }
						).done(function (resultRaw) {
						sendNotification(unserializeObjectRecord(resultRaw)).done(null, function (err) {
							console.log("Cannot send email", err.stack);
						});
					});
					login(userId, that.req, that.res);
				});
			});
		});
	}
};

exports['init-demo'] = {
	validate: Function.prototype,
	submit: function () {
		var cookieName = 'demoUser'
		  , userId     = this.res.cookies.get(cookieName)
		  , promise, storage;

		storage = dbDriver.getStorage('user');
		if (userId) promise = storage.get(userId + '/isDemo');
		else promise = emptyPromise;
		return promise(function (data) {
			var records, promise;
			if (!data || (data.value !== '11')) {
				userId = genId();
				records = [
					{ id: userId, data: { value: '7User#' } },
					{ id: userId + '/isDemo', data: { value: '11' } },
					{ id: userId + '/roles*user', data: { value: '11' } }
				];
				promise = storage.storeMany(records);
			} else {
				promise = emptyPromise;
			}
			return promise(function () {
				this.res.cookies.set(cookieName, userId, { maxage: maxage });
				login(userId, this.req, this.res);
			}.bind(this));
		}.bind(this));
	},
	redirectUrl: '/'
};
<commit_msg>Expose userId on context<commit_after>'use strict';

var emptyPromise     = require('deferred')(null)
  , genId            = require('time-uuid')
  , login            = require('mano-auth/server/authentication').login
  , registerSubmit   = require('mano-auth/controller/server-master/register-and-login').submit
  , mano             = require('mano')
  , sendNotification = require('../../server/email-notifications/create-account')
  , unserializeObjectRecord = require('../../server/utils/unserialize-object-record')

  , dbDriver = mano.dbDriver
  , maxage = 1000 * 60 * 60 * 24 * 7
  , customError      = require('es5-ext/error/custom')
  , promisify        = require('deferred').promisify
  , bcrypt           = require('bcrypt')
  , serializeValue   = require('dbjs/_setup/serialize/value')

  , genSalt = promisify(bcrypt.genSalt), hash = promisify(bcrypt.hash)
  , userStorage = mano.dbDriver.getStorage('user');

exports.login = require('mano-auth/controller/server-master/login');
exports.register = {
	submit: function (data) {
		if (data.isManager) {
			data['User#/roles'] = ['manager'];
			delete data.isManager;
		}

		return registerSubmit.apply(this, arguments)(function (result) {
			dbDriver.onDrain(function () { sendNotification(data).done(null, function (err) {
				console.log("Cannot send email", err, err.stack);
			}); });
		});
	}
};
exports['reset-password'] = require('mano-auth/controller/server-master/reset-password');
exports['request-reset-password'] =
	require('mano-auth/controller/server-master/request-reset-password');

exports['create-managed-account'] = {
	submit: function (data) {
		var that = this;
		return userStorage.searchOne({ keyPath: 'createManagedAccountToken',
			value: serializeValue(data['create-managed-account-token']) }, function (id) {
			return id.split('/')[0];
		}).then(function (userId) {
			if (!userId) {
				throw customError("Cannot process request", "MALFORMED_EMAIL", { statusCode: 400 });
			}
			return hash(data.password, genSalt())(function (password) {
				return userStorage.storeMany([
					{ id: userId + '/createManagedAccountToken', data: { value: '' } },
					{ id: userId + '/password', data: { value: serializeValue(password) } }
				]).then(function () {
					userStorage.getObject(userId,
						{ keyPaths: ['firstName', 'lastName', 'email'] }
						).done(function (resultRaw) {
						sendNotification(unserializeObjectRecord(resultRaw)).done(null, function (err) {
							console.log("Cannot send email", err.stack);
						});
					});
					login(userId, that.req, that.res);
				});
			});
		});
	}
};

exports['init-demo'] = {
	validate: Function.prototype,
	submit: function () {
		var cookieName = 'demoUser'
		  , userId     = this.res.cookies.get(cookieName)
		  , promise, storage;

		storage = dbDriver.getStorage('user');
		if (userId) promise = storage.get(userId + '/isDemo');
		else promise = emptyPromise;
		return promise(function (data) {
			var records, promise;
			if (!data || (data.value !== '11')) {
				userId = genId();
				records = [
					{ id: userId, data: { value: '7User#' } },
					{ id: userId + '/isDemo', data: { value: '11' } },
					{ id: userId + '/roles*user', data: { value: '11' } }
				];
				promise = storage.storeMany(records);
			} else {
				promise = emptyPromise;
			}
			this.userId = userId;
			return promise(function () {
				this.res.cookies.set(cookieName, userId, { maxage: maxage });
				login(userId, this.req, this.res);
			}.bind(this));
		}.bind(this));
	},
	redirectUrl: '/'
};
<|endoftext|>


<commit_before>"use strict";

define([
	'debug', 'distance', 'flight', 'utils', 'waypoints', 'vnav-profile'
], function (debug, distance, flight, utils, waypoints, vnavProfile) {

	// Autopilot++ Dependencies
	var apModes = autopilot_pp.require('autopilot').modes;

	return {
		timer: null,

		/**
		 * Controls VNAV, plane's vertical navigation, set on a timer
		 */
		update: function () {
			if (!flight.vnavEnabled()) return;

			var route = waypoints.route();

			var params = getFlightParameters();

			var next = waypoints.nextWptAltRes();
			var hasRestriction = next !== -1;

			var todDist = flight.todDist();
			var cruiseAlt = flight.cruiseAlt();
			var fieldElev = flight.fieldElev();
			var todCalc = flight.todCalc();

			var currentAlt = geofs.aircraft.instance.animationValue.altitude;
			var targetAlt, deltaAlt, nextDist, targetDist;
			if (hasRestriction) {
				targetAlt = route[next].alt();
				deltaAlt = targetAlt - currentAlt;
				nextDist = distance.route(next + 1);
				targetDist = distance.target(deltaAlt);
				debug.log('targetAlt: ' + targetAlt + ', deltaAlt: ' + deltaAlt + ', nextDist: ' + nextDist + ', targetDist: ' + targetDist);
			}

			var spd = params[0], vs, alt;

			/**********************
			 * Flight Phase Logic *
			 **********************/
			var lat1 = geofs.aircraft.instance.llaLocation[0] || null;
			var lon1 = geofs.aircraft.instance.llaLocation[1] || null;
			var lat2 = flight.arrival.coords()[0] || null;
			var lon2 = flight.arrival.coords()[1] || null;
			var flightDist;

			// Checks if the whole route is complete
			for (var i = 0, valid = true; i < route.length; i++) {
				if (!route[i].lat() || !route[i].lon()) valid = false;
			}
			if (valid) flightDist = distance.route(route.length);
			else flightDist = utils.getDistance(lat1, lon1, lat2, lon2);

			// Invalid distance, phase resets to default = climb
			if (isNaN(flightDist)) flight.phase(0);

			// Total route dist is less than T/D distance, phase = descent
			else if (flightDist < todDist) flight.phase(2);

			// If current altitude is close to the cruise altitude, phase = cruise
			else if (Math.abs(cruiseAlt - currentAlt) <= 100) flight.phase(1);

			// If current altitude is less than cruise altitude, phase = climb
			else if (currentAlt < cruiseAlt) flight.phase(0);

			// If current altitude is greater than cruise altitude
			// This means that cruise altitude is lowered during cruise
			// Phase still is cruise, but assign V/S value
			else if (currentAlt > cruiseAlt) {
				flight.phase(1);
				vs = -1000;
			}

			// Else, resets to default phase = climb
			else flight.phase(0);

			// ==============================

			// If the aircraft is climbing
			if (flight.phase() === 0) {

				// If there is an altitude restriction somewhere on the route
				if (hasRestriction) {
					var totalDist = distance.target(cruiseAlt - currentAlt) + distance.target(targetAlt - cruiseAlt);
					debug.log('totalDist: ' + totalDist);

					// Checks to see if the altitude restriction is on the climbing phase or descent phase
					if (nextDist < totalDist) {
						if (nextDist < targetDist) vs = utils.getClimbrate(deltaAlt, nextDist);
						else vs = params[1];
						alt = targetAlt;
					} else {
						vs = params[1];
						alt = cruiseAlt;
					}
				}

				// If there are no altitude restrictions left on the route
				else {
					vs = params[1];
					alt = cruiseAlt;
				}
			}

			// If the aircraft is on descent
			else if (flight.phase() === 2) {

				// If there is an altitude restriction somewhere on the route
				if (hasRestriction) {

					// If targetDist has been reached
					if (nextDist < targetDist) {
						vs = utils.getClimbrate(deltaAlt, nextDist);
						alt = targetAlt;
					}

					// If targetDist hasn't been reached do nothing until it has been reached
				}

				// If there are no altitude restrictions left on the route
				else {
					vs = params[1];
					if (currentAlt > 12000 + fieldElev) alt = 100 * Math.round((12000 + fieldElev) / 100);
				}
			}

			// Calculates Top of Descent
			if (flight.phase() === 1 && (todCalc || !todDist)) {
				if (hasRestriction) {
					todDist = distance.route(route.length) - nextDist;
					todDist += distance.target(targetAlt - cruiseAlt);
				} else {
					todDist = distance.target(fieldElev - cruiseAlt);
				}
				todDist = Math.round(todDist);
				flight.todDist(todDist);
				debug.log('TOD changed to ' + todDist);
			}

			// Updates SPD, VS, and ALT in Autopilot++ if new values exist
			if (spd) apModes.speed.value(spd);
			if (vs) apModes.vs.value(vs);
			if (alt) apModes.altitude.value(alt);
		}
	};

	/**
	 * Gets each plane's flight parameters, for VNAV
	 *
	 * @returns {Array} [speed, vertical speed]
	 */
	function getFlightParameters () {
		var spd, vs;
		var a = geofs.aircraft.instance.animationValue.altitude;

		// CLIMB
		if (flight.phase() === 0) {
			var profile = getVNAVProfile().climb;

			for (var i = 0, index = 0; i < profile.length; i++) {
				if (a > profile[i][0] && a <= profile[i][1]) {
					index = i;
					break;
				}
			}

			if (flight.spdControl()) {
				spd = profile[index][2];
				switchSpeedMode(spd);
			}

			vs = profile[index][3];
		}

		// DESCENT
		else if (flight.phase() === 2) {
			var profile = getVNAVProfile().descent;

			for (var i = 0, index = 0; i < profile.length; i++) {
				if (a > profile[i][0] && a <= profile[i][1]) {
					index = i;
					break;
				}
			}

			if (flight.spdControl()) {
				spd = profile[index][2];
				switchSpeedMode(spd);
			}

			vs = profile[index][3];
		}

		return [spd, vs];
	}

	/**
	 * @private
	 * Gets the climb/descent profile for VNAV
	 *
	 * @returns {Object} The profile needed by VNAV
	 */
	function getVNAVProfile () {
		return geofs.aircraft.instance.setup.fmc
			|| vnavProfile[geofs.aircraft.instance.id]
			|| vnavProfile.DEFAULT;
	}

	/**
	 * @private
	 * Checks if the speed input is mach and switches mode
	 *
	 * @param {Number} spd The speed to be checked
	 */
	function switchSpeedMode (spd) {
		if (spd <= 10) apModes.speed.isMach(true);
		else apModes.speed.isMach(false);
	}
});
<commit_msg>Fixed bug where VNAV profile becomes first descent profile while below 10,000 ft<commit_after>"use strict";

define([
	'debug', 'distance', 'flight', 'utils', 'waypoints', 'vnav-profile'
], function (debug, distance, flight, utils, waypoints, vnavProfile) {

	// Autopilot++ Dependencies
	var apModes = autopilot_pp.require('autopilot').modes;

	return {
		timer: null,

		/**
		 * Controls VNAV, plane's vertical navigation, set on a timer
		 */
		update: function () {
			if (!flight.vnavEnabled()) return;

			var route = waypoints.route();

			var params = getFlightParameters();

			var next = waypoints.nextWptAltRes();
			var hasRestriction = next !== -1;

			var todDist = flight.todDist();
			var cruiseAlt = flight.cruiseAlt();
			var fieldElev = flight.fieldElev();
			var todCalc = flight.todCalc();

			var currentAlt = geofs.aircraft.instance.animationValue.altitude;
			var targetAlt, deltaAlt, nextDist, targetDist;
			if (hasRestriction) {
				targetAlt = route[next].alt();
				deltaAlt = targetAlt - currentAlt;
				nextDist = distance.route(next + 1);
				targetDist = distance.target(deltaAlt);
				debug.log('targetAlt: ' + targetAlt + ', deltaAlt: ' + deltaAlt + ', nextDist: ' + nextDist + ', targetDist: ' + targetDist);
			}

			var spd = params[0], vs, alt;

			/**********************
			 * Flight Phase Logic *
			 **********************/
			var lat1 = geofs.aircraft.instance.llaLocation[0] || null;
			var lon1 = geofs.aircraft.instance.llaLocation[1] || null;
			var lat2 = flight.arrival.coords()[0] || null;
			var lon2 = flight.arrival.coords()[1] || null;
			var flightDist;

			// Checks if the whole route is complete
			for (var i = 0, valid = true; i < route.length; i++) {
				if (!route[i].lat() || !route[i].lon()) valid = false;
			}
			if (valid) flightDist = distance.route(route.length);
			else flightDist = utils.getDistance(lat1, lon1, lat2, lon2);

			// Invalid distance, phase resets to default = climb
			if (isNaN(flightDist)) flight.phase(0);

			// Total route dist is less than T/D distance, phase = descent
			else if (flightDist < todDist) flight.phase(2);

			// If current altitude is close to the cruise altitude, phase = cruise
			else if (Math.abs(cruiseAlt - currentAlt) <= 100) flight.phase(1);

			// If current altitude is less than cruise altitude, phase = climb
			else if (currentAlt < cruiseAlt) flight.phase(0);

			// If current altitude is greater than cruise altitude
			// This means that cruise altitude is lowered during cruise
			// Phase still is cruise, but assign V/S value
			else if (currentAlt > cruiseAlt) {
				flight.phase(1);
				vs = -1000;
			}

			// Else, resets to default phase = climb
			else flight.phase(0);

			// ==============================

			// If the aircraft is climbing
			if (flight.phase() === 0) {

				// If there is an altitude restriction somewhere on the route
				if (hasRestriction) {
					var totalDist = distance.target(cruiseAlt - currentAlt) + distance.target(targetAlt - cruiseAlt);
					debug.log('totalDist: ' + totalDist);

					// Checks to see if the altitude restriction is on the climbing phase or descent phase
					if (nextDist < totalDist) {
						if (nextDist < targetDist) vs = utils.getClimbrate(deltaAlt, nextDist);
						else vs = params[1];
						alt = targetAlt;
					} else {
						vs = params[1];
						alt = cruiseAlt;
					}
				}

				// If there are no altitude restrictions left on the route
				else {
					vs = params[1];
					alt = cruiseAlt;
				}
			}

			// If the aircraft is on descent
			else if (flight.phase() === 2) {

				// If there is an altitude restriction somewhere on the route
				if (hasRestriction) {

					// If targetDist has been reached
					if (nextDist < targetDist) {
						vs = utils.getClimbrate(deltaAlt, nextDist);
						alt = targetAlt;
					}

					// If targetDist hasn't been reached do nothing until it has been reached
				}

				// If there are no altitude restrictions left on the route
				else {
					vs = params[1];
					if (currentAlt > 12000 + fieldElev) alt = 100 * Math.round((12000 + fieldElev) / 100);
				}
			}

			// Calculates Top of Descent
			if (flight.phase() === 1 && (todCalc || !todDist)) {
				if (hasRestriction) {
					todDist = distance.route(route.length) - nextDist;
					todDist += distance.target(targetAlt - cruiseAlt);
				} else {
					todDist = distance.target(fieldElev - cruiseAlt);
				}
				todDist = Math.round(todDist);
				flight.todDist(todDist);
				debug.log('TOD changed to ' + todDist);
			}

			// Updates SPD, VS, and ALT in Autopilot++ if new values exist
			if (spd !== undefined) apModes.speed.value(spd);
			if (vs !== undefined) apModes.vs.value(vs);
			if (alt !== undefined) apModes.altitude.value(alt);
		}
	};

	/**
	 * @private
	 * Gets each plane's flight parameters, for VNAV
	 *
	 * @returns {Array} [speed, vertical speed]
	 */
	function getFlightParameters () {
		var spd, vs;
		var a = geofs.aircraft.instance.animationValue.altitude;

		// CLIMB
		if (flight.phase() === 0) {
			var profile = getVNAVProfile().climb;

			for (var index, i = 0; i < profile.length; i++) {
				if (a > profile[i][0] && a <= profile[i][1]) {
					index = i;
					break;
				}
			}

			if (flight.spdControl()) {
				spd = profile[index][2];
				if (index < profile.length - 1) vs = profile[index][3];
				switchSpeedMode(spd);
			}
		}

		// DESCENT
		else if (flight.phase() === 2) {
			var profile = getVNAVProfile().descent;

			for (var index, i = 0; i < profile.length; i++) {
				if (a > profile[i][0] && a <= profile[i][1]) {
					index = i;
					break;
				}
			}

			var belowLastAlt = index === undefined;

			// If current alt below lowest alt in profile
			// SPD and V/S will not be restricted
			if (flight.spdControl() && !belowLastAlt) {
				spd = profile[index][2];
				vs = profile[index][3];
				switchSpeedMode(spd);
			}
		}

		return [spd, vs];
	}

	/**
	 * @private
	 * Gets the climb/descent profile for VNAV
	 *
	 * @returns {Object} The profile needed by VNAV
	 */
	function getVNAVProfile () {
		return geofs.aircraft.instance.setup.fmc
			|| vnavProfile[geofs.aircraft.instance.id]
			|| vnavProfile.DEFAULT;
	}

	/**
	 * @private
	 * Checks if the speed input is mach and switches mode
	 *
	 * @param {Number} spd The speed to be checked
	 */
	function switchSpeedMode (spd) {
		if (!spd) return;
		if (spd <= 10) apModes.speed.isMach(true);
		else apModes.speed.isMach(false);
	}
});
<|endoftext|>


<commit_before>import minimatch from "minimatch";

function handleResponseCode(response) {
    const status = parseInt(response.status, 10);
    let err;
    if (status >= 400) {
        err = new Error("Invalid response: " + status + " " + response.statusText);
        err.status = status;
        throw err;
    }
    return response;
}

function processResponsePayload(response, data, isDetailed = false) {
    return isDetailed
        ? {
              data,
              headers: response.headers || {}
          }
        : data;
}

function processGlobFilter(files, glob) {
    return files.filter(file => minimatch(file.filename, glob.pattern, { matchBase: true }));
}

module.exports = {
    handleResponseCode,
    processResponsePayload,
    processGlobFilter
};
<commit_msg>changed to commonjs require<commit_after>const minimatch = require("minimatch");

function handleResponseCode(response) {
    const status = parseInt(response.status, 10);
    let err;
    if (status >= 400) {
        err = new Error("Invalid response: " + status + " " + response.statusText);
        err.status = status;
        throw err;
    }
    return response;
}

function processResponsePayload(response, data, isDetailed = false) {
    return isDetailed
        ? {
              data,
              headers: response.headers || {}
          }
        : data;
}

function processGlobFilter(files, glob) {
    return files.filter(file => minimatch(file.filename, glob.pattern, { matchBase: true }));
}

module.exports = {
    handleResponseCode,
    processResponsePayload,
    processGlobFilter
};
<|endoftext|>


<commit_before>/*!
 * Copyright (c) 2015-2019 Cisco Systems, Inc. See LICENSE file.
 */

import {InvalidUserCreation} from '@webex/internal-plugin-conversation';
import {patterns} from '@webex/common';
import WebexCore, {WebexHttpError} from '@webex/webex-core';
import {assert} from '@webex/test-helper-chai';
import testUsers from '@webex/test-helper-test-users';
import {find, last, map} from 'lodash';
import uuid from 'uuid';
import fh from '@webex/test-helper-file';

describe('plugin-conversation', function () {
  this.timeout(60000);
  describe('#create()', () => {
    let checkov, kirk, mccoy, participants, webex, spock;

    before(() => testUsers.create({count: 4})
      .then(async (users) => {
        [spock, mccoy, checkov, kirk] = users;
        participants = [spock, mccoy, checkov];

        // Pause for 5 seconds for CI
        await new Promise((done) => setTimeout(done, 5000));

        webex = new WebexCore({
          credentials: {
            authorization: spock.token
          }
        });

        webex.config.conversation.allowedOutboundTags = {
          strong: []
        };
        webex.config.conversation.allowedInboundTags = {
          strong: []
        };

        mccoy.webex = new WebexCore({
          credentials: {
            authorization: mccoy.token
          }
        });

        return Promise.all([
          webex.internal.mercury.connect(),
          mccoy.webex.internal.mercury.connect()
        ]);
      }));

    let sampleTextOne = 'sample-text-one.txt';

    before(() => fh.fetch(sampleTextOne)
      .then((f) => { sampleTextOne = f; }));

    after(() => Promise.all([
      webex && webex.internal.mercury.disconnect(),
      mccoy && mccoy.webex.internal.mercury.disconnect()
    ]));

    function makeEmailAddress() {
      return `webex-js-sdk--test-${uuid.v4()}@example.com`;
    }

    describe('when there is only one other participant', () => {
      it('creates a 1:1 conversation', () => webex.internal.conversation.create({participants: [mccoy]})
        .then((conversation) => {
          assert.isConversation(conversation);
          assert.isOneOnOneConversation(conversation);
          assert.isNewEncryptedConversation(conversation);

          assert.lengthOf(conversation.participants.items, 2);
          assert.lengthOf(conversation.activities.items, 1);
        }));

      describe('when the other user doesn\'t exist', () => {
        let email;

        beforeEach(() => { email = makeEmailAddress(); });

        it('invites the other user', () => webex.internal.conversation.create({participants: [email]})
          .then((conversation) => {
            assert.isConversation(conversation);
            assert.isOneOnOneConversation(conversation);
            assert.isNewEncryptedConversation(conversation);

            const participant = find(conversation.participants.items, {emailAddress: email});

            assert.include(participant.tags, 'SIDE_BOARDED');
            assert.match(participant.id, patterns.uuid);
          }));
      });

      describe('when the conversation already exists', () => {
        describe('with skipOneOnOneFetch=true', () => {
          it('fails to create a 1:1 conversation that already exists', () => assert.isRejected(webex.internal.conversation.create({participants: [mccoy]}, {skipOneOnOneFetch: true}))
            .then((reason) => assert.instanceOf(reason, WebexHttpError.Conflict)));
        });

        it('returns the preexisting conversation', () => webex.internal.conversation.create({participants: [checkov]})
          .then((conversation) => webex.internal.conversation.create({participants: [checkov]})
            .then((conversation2) => {
              assert.equal(conversation2.url, conversation.url);
              assert.lengthOf(conversation.activities.items, 1);
              assert.equal(conversation.activities.items[0].verb, 'create');
            })));

        it('returns the preexisting conversation and posts a comment', () => webex.internal.conversation.create({participants: [checkov], comment: 'hi'})
          .then((conversation) => webex.internal.conversation.create({participants: [checkov]})
            .then((conversation2) => {
              assert.equal(conversation2.url, conversation.url);
              assert.lengthOf(conversation.activities.items, 1);
              assert.equal(conversation.activities.items[0].verb, 'post');
              assert.equal(conversation.activities.items[0].object.displayName, 'hi');
            })));

        it('returns the preexisting conversation and posts a comment with html', () => webex.internal.conversation.create({participants: [checkov], comment: '**hi**', html: 'hi'})
          .then((conversation) => webex.internal.conversation.create({participants: [checkov]})
            .then((conversation2) => {
              assert.equal(conversation2.url, conversation.url);
              assert.lengthOf(conversation.activities.items, 1);
              assert.equal(conversation.activities.items[0].verb, 'post');
              assert.equal(conversation.activities.items[0].object.displayName, '**hi**');
              assert.equal(conversation.activities.items[0].object.content, 'hi');
            })));
      });

      describe('when {forceGrouped: true} is specified', () => {
        it('creates a grouped conversation @canary', () => webex.internal.conversation.create({participants: [mccoy]}, {forceGrouped: true})
          .then((conversation) => {
            assert.isConversation(conversation);
            assert.isGroupConversation(conversation);
            assert.isNewEncryptedConversation(conversation);

            assert.lengthOf(conversation.participants.items, 2);
            assert.lengthOf(conversation.activities.items, 1);
          }));
      });
    });

    describe('when there is an invalid user in the participants list', () => {
      describe('with allowPartialCreation', () => {
        it('creates a group conversation', () => webex.internal.conversation.create({participants: [mccoy, 'invalidUser']}, {allowPartialCreation: true})
          .then((conversation) => {
            assert.isConversation(conversation);
            assert.isGroupConversation(conversation);
            assert.isNewEncryptedConversation(conversation);

            assert.lengthOf(conversation.participants.items, 2);
            assert.lengthOf(conversation.activities.items, 1);
          }));

        it('creates a group conversation with invalid uuid', () => testUsers.remove([kirk])
          .then(() => webex.internal.conversation.create({participants: [mccoy.id, kirk.id]}, {allowPartialCreation: true}))
          .then((conversation) => {
            assert.isConversation(conversation);
            assert.isGroupConversation(conversation);
            assert.isNewEncryptedConversation(conversation);

            assert.lengthOf(conversation.participants.items, 2);
            assert.lengthOf(conversation.activities.items, 1);
          }));

        it('fails to create a 1:1 conversation', () => assert.isRejected(webex.internal.conversation.create({participants: ['invalidUser']}, {allowPartialCreation: true}))
          .then((reason) => assert.instanceOf(reason, InvalidUserCreation)));
      });

      describe('without allowPartialCreation', () => {
        it('fails to create a group conversation without allowPartialCreation param', () => assert.isRejected(webex.internal.conversation.create({participants: [mccoy, 'invalidUser']})));
      });
    });

    describe('when {compact: ?} is not specified', () => {
      it('creates a compact conversation', () => webex.internal.conversation.create({participants})
        .then((c) => webex.internal.conversation.get(c, {activitiesLimit: 5}))
        .then((c) => assert.lengthOf(c.activities.items, 1)));
    });

    it('creates a conversation with a name', () => webex.internal.conversation.create({displayName: 'displayName', participants})
      .then((c) => webex.internal.conversation.get(c))
      .then((c) => assert.equal(c.displayName, 'displayName')));

    it('creates a conversation with a comment', () => webex.internal.conversation.create({comment: 'comment', participants})
      .then((c) => webex.internal.conversation.get(c, {activitiesLimit: 2}))
      .then((c) => assert.equal(c.activities.items[1].object.displayName, 'comment')));

    it('creates a conversation with a comment with html', () => webex.internal.conversation.create({comment: '**comment**', html: 'comment', participants})
      .then((c) => webex.internal.conversation.get(c, {activitiesLimit: 2}))
      .then((c) => {
        assert.equal(c.activities.items[1].object.displayName, '**comment**');
        assert.equal(c.activities.items[1].object.content, 'comment');
      }));

    it('creates a conversation with a share', () => webex.internal.conversation.create({participants, files: [sampleTextOne]})
      .then((c) => webex.internal.conversation.get(c, {activitiesLimit: 10}))
      .then((c) => {
        assert.equal(last(c.activities.items).verb, 'share');

        return webex.internal.conversation.download(last(c.activities.items).object.files.items[0]);
      })
      .then((file) => fh.isMatchingFile(file, sampleTextOne)));

    it('ensures the current user is in the participants list', () => webex.internal.conversation.create({comment: 'comment', participants: [mccoy, checkov]})
      .then((c) => webex.internal.conversation.get(c, {includeParticipants: true}))
      .then((c) => assert.include(map(c.participants.items, 'id'), spock.id)));

    it('does not allow me to create a conversation with zero participants', () => assert.isRejected(webex.internal.conversation.create({participants: []}, /`params.participants` is required/)));
  });
});
<commit_msg>test(i-p-conversation): fix conversation creation tests<commit_after>/*!
 * Copyright (c) 2015-2019 Cisco Systems, Inc. See LICENSE file.
 */

import {InvalidUserCreation} from '@webex/internal-plugin-conversation';
import {patterns} from '@webex/common';
import WebexCore, {WebexHttpError} from '@webex/webex-core';
import {assert} from '@webex/test-helper-chai';
import testUsers from '@webex/test-helper-test-users';
import {find, last, map} from 'lodash';
import uuid from 'uuid';
import fh from '@webex/test-helper-file';

describe('plugin-conversation', function () {
  this.timeout(60000);
  describe('#create()', () => {
    let checkov, kirk, mccoy, participants, webex, spock;

    before(() => testUsers.create({count: 4})
      .then(async (users) => {
        [spock, mccoy, checkov, kirk] = users;
        participants = [spock, mccoy, checkov];

        // Pause for 5 seconds for CI
        await new Promise((done) => setTimeout(done, 5000));

        webex = new WebexCore({
          credentials: {
            authorization: spock.token
          }
        });

        webex.config.conversation.allowedOutboundTags = {
          strong: []
        };
        webex.config.conversation.allowedInboundTags = {
          strong: []
        };

        mccoy.webex = new WebexCore({
          credentials: {
            authorization: mccoy.token
          }
        });

        return Promise.all([
          webex.internal.mercury.connect(),
          mccoy.webex.internal.mercury.connect()
        ]);
      }));

    let sampleTextOne = 'sample-text-one.txt';

    before(() => fh.fetch(sampleTextOne)
      .then((f) => { sampleTextOne = f; }));

    after(() => Promise.all([
      webex && webex.internal.mercury.disconnect(),
      mccoy && mccoy.webex.internal.mercury.disconnect()
    ]));

    function makeEmailAddress() {
      return `webex-js-sdk--test-${uuid.v4()}@example.com`;
    }

    describe('when there is only one other participant', () => {
      it('creates a 1:1 conversation', () => webex.internal.conversation.create({participants: [mccoy]})
        .then((conversation) => {
          assert.isConversation(conversation);
          assert.isOneOnOneConversation(conversation);
          assert.isNewEncryptedConversation(conversation);

          assert.lengthOf(conversation.participants.items, 2);
          assert.lengthOf(conversation.activities.items, 1);
        }));

      describe('when the other user doesn\'t exist', () => {
        let email;

        beforeEach(() => { email = makeEmailAddress(); });

        it('invites the other user', () => webex.internal.conversation.create({participants: [email]})
          .then((conversation) => {
            assert.isConversation(conversation);
            assert.isOneOnOneConversation(conversation);
            assert.isNewEncryptedConversation(conversation);

            const participant = find(conversation.participants.items, {emailAddress: email});

            assert.include(participant.tags, 'SIDE_BOARDED');
            assert.match(participant.id, patterns.uuid);
          }));
      });

      describe('when the conversation already exists', () => {
        describe('with skipOneOnOneFetch=true', () => {
          it('fails to create a 1:1 conversation that already exists', () => assert.isRejected(webex.internal.conversation.create({participants: [mccoy]}, {skipOneOnOneFetch: true}))
            .then((reason) => assert.instanceOf(reason, WebexHttpError.Conflict)));
        });

        it('returns the preexisting conversation', () => webex.internal.conversation.create({participants: [checkov]})
          .then((conversation) => webex.internal.conversation.create({participants: [checkov]})
            .then((conversation2) => {
              assert.equal(conversation2.url, conversation.url);
              assert.lengthOf(conversation.activities.items, 1);
              assert.equal(conversation.activities.items[0].verb, 'create');
            })));

        it('returns the preexisting conversation and posts a comment', () => webex.internal.conversation.create({participants: [checkov], comment: 'hi'})
          .then((conversation) => webex.internal.conversation.create({participants: [checkov]})
            .then((conversation2) => {
              assert.equal(conversation2.id, conversation.id);
              // the first activity is "create"; get the "post"
              const activity = conversation.activities.items.pop();

              assert.equal(activity.verb, 'post');
              assert.equal(activity.object.displayName, 'hi');
            })));

        it('returns the preexisting conversation and posts a comment with html', () => webex.internal.conversation.create({participants: [checkov], comment: '**hi**', html: 'hi'})
          .then((conversation) => webex.internal.conversation.create({participants: [checkov]})
            .then((conversation2) => {
              assert.equal(conversation2.id, conversation.id);
              // the first activity is "create"; get the "post"
              const activity = conversation.activities.items.pop();

              assert.equal(activity.verb, 'post');
              assert.equal(activity.object.displayName, '**hi**');
              assert.equal(activity.object.content, 'hi');
            })));
      });

      describe('when {forceGrouped: true} is specified', () => {
        it('creates a grouped conversation @canary', () => webex.internal.conversation.create({participants: [mccoy]}, {forceGrouped: true})
          .then((conversation) => {
            assert.isConversation(conversation);
            assert.isGroupConversation(conversation);
            assert.isNewEncryptedConversation(conversation);

            assert.lengthOf(conversation.participants.items, 2);
            assert.lengthOf(conversation.activities.items, 1);
          }));
      });
    });

    describe('when there is an invalid user in the participants list', () => {
      describe('with allowPartialCreation', () => {
        it('creates a group conversation', () => webex.internal.conversation.create({participants: [mccoy, 'invalidUser']}, {allowPartialCreation: true})
          .then((conversation) => {
            assert.isConversation(conversation);
            assert.isGroupConversation(conversation);
            assert.isNewEncryptedConversation(conversation);

            assert.lengthOf(conversation.participants.items, 2);
            assert.lengthOf(conversation.activities.items, 1);
          }));

        it('creates a group conversation with invalid uuid', () => testUsers.remove([kirk])
          .then(() => webex.internal.conversation.create({participants: [mccoy.id, kirk.id]}, {allowPartialCreation: true}))
          .then((conversation) => {
            assert.isConversation(conversation);
            assert.isGroupConversation(conversation);
            assert.isNewEncryptedConversation(conversation);

            assert.lengthOf(conversation.participants.items, 2);
            assert.lengthOf(conversation.activities.items, 1);
          }));

        it('fails to create a 1:1 conversation', () => assert.isRejected(webex.internal.conversation.create({participants: ['invalidUser']}, {allowPartialCreation: true}))
          .then((reason) => assert.instanceOf(reason, InvalidUserCreation)));
      });

      describe('without allowPartialCreation', () => {
        it('fails to create a group conversation without allowPartialCreation param', () => assert.isRejected(webex.internal.conversation.create({participants: [mccoy, 'invalidUser']})));
      });
    });

    describe('when {compact: ?} is not specified', () => {
      it('creates a compact conversation', () => webex.internal.conversation.create({participants})
        .then((c) => webex.internal.conversation.get(c, {activitiesLimit: 5}))
        .then((c) => assert.lengthOf(c.activities.items, 1)));
    });

    it('creates a conversation with a name', () => webex.internal.conversation.create({displayName: 'displayName', participants})
      .then((c) => webex.internal.conversation.get(c))
      .then((c) => assert.equal(c.displayName, 'displayName')));

    it('creates a conversation with a comment', () => webex.internal.conversation.create({comment: 'comment', participants})
      .then((c) => webex.internal.conversation.get(c, {activitiesLimit: 2}))
      .then((c) => assert.equal(c.activities.items[1].object.displayName, 'comment')));

    it('creates a conversation with a comment with html', () => webex.internal.conversation.create({comment: '**comment**', html: 'comment', participants})
      .then((c) => webex.internal.conversation.get(c, {activitiesLimit: 2}))
      .then((c) => {
        assert.equal(c.activities.items[1].object.displayName, '**comment**');
        assert.equal(c.activities.items[1].object.content, 'comment');
      }));

    it('creates a conversation with a share', () => webex.internal.conversation.create({participants, files: [sampleTextOne]})
      .then((c) => webex.internal.conversation.get(c, {activitiesLimit: 10}))
      .then((c) => {
        assert.equal(last(c.activities.items).verb, 'share');

        return webex.internal.conversation.download(last(c.activities.items).object.files.items[0]);
      })
      .then((file) => fh.isMatchingFile(file, sampleTextOne)));

    it('ensures the current user is in the participants list', () => webex.internal.conversation.create({comment: 'comment', participants: [mccoy, checkov]})
      .then((c) => webex.internal.conversation.get(c, {includeParticipants: true}))
      .then((c) => assert.include(map(c.participants.items, 'id'), spock.id)));

    it('does not allow me to create a conversation with zero participants', () => assert.isRejected(webex.internal.conversation.create({participants: []}, /`params.participants` is required/)));
  });
});
<|endoftext|>


<commit_before>var Location = require('../models/Location');
var instagram = require('../api/instagram');

//this will render ALL locations
var index = function(req, res, next) {
  Location
    .find({})
    .then(
      function(locations) {
        res.render(
          'locations/index',
          {
            location: locations,
            user:     req.user
        });
      }, function(err) {
        return next(err);
    });
};

var create = function(req, res){
  var newLocation = req.body.location;
  newLocation.username = req.user.name;

  Location
      .create(newLocation)
      .then(
          function(location){
            res.redirect('/locations/' + location.id);
          }, function(err) {
            return next(err);
          });
};

var show = function(req, res, next) {
  var instagramData;
  instagram.get(req.params.id, function(stringdata){
    instagramData = JSON.parse(stringdata);
    console.log('instagramData: ' + instagramData)
    instagramData = instagramData.data.map(function(post){
      return post.images.standard_resolution.url
    });
    console.log('instagramData mapped: ' + instagramData);
    Location.findById(req.params.id, function(location) {
          res.render('locations/show',
            {
              location: location,
              user:    req.user,
              instagramData: instagramData
            });
    });
  });
};

module.exports = {
  index:  index,
  show:   show,
  create: create
};
<commit_msg>fixing minor syntax fix in locationsController to stop npm start from quitting unexpectedly<commit_after>var Location = require('../models/Location');
var instagram = require('../api/instagram');

//this will render ALL locations
var index = function(req, res, next) {
  Location
    .find({})
    .then(
      function(locations) {
        res.render(
          'locations/index',
          {
            location: locations,
            user:     req.user
        });
      }, function(err) {
        return next(err);
    });
};

var create = function(req, res){
  var newLocation = req.body.location;
  newLocation.username = req.user.name;

  Location
      .create(newLocation)
      .then(
          function(location){
            res.redirect('/locations/' + location.id);
          }, function(err) {
            return next(err);
          });
};

var show = function(req, res, next) {
  var instagramData;
  instagram.get(req.params.id, function(stringdata){
    instagramData = JSON.parse(stringdata);
    console.log('instagramData: ' + instagramData);
    instagramData = instagramData.data.map(function(post){
      return post.images.standard_resolution.url;
    });
    console.log('instagramData mapped: ' + instagramData);
    Location.findById(req.params.id, function(location) {
          res.render('locations/show',
            {
              location: location,
              user:    req.user,
              instagramData: instagramData
            });
    });
  });
};

module.exports = {
  index:  index,
  show:   show,
  create: create
};
<|endoftext|>


<commit_before>
require('core/string');
require('core/array');
include('binary');
include('./util');
include('./parameters');

export('isFileUpload', 'parseFileUpload');

var log = require('helma/logging').getLogger(module.id);

var HYPHEN  = "-".charCodeAt(0);
var CRLF = new ByteString("\r\n", "ASCII");
var EMPTY_LINE = new ByteString("\r\n\r\n", "ASCII");

/**
 * Find out whether the content type denotes a format this module can parse.
 * @param contentType a HTTP request Content-Type header
 * @return true if the content type can be parsed as form data by this module
 */
function isFileUpload(contentType) {
    return contentType && String(contentType)
            .toLowerCase().startsWith("multipart/form-data");
}

/**
 * Rough but working first draft of file upload support.
 * Everything's done in memory so beware of large files.
 * @param env the JSGI env object
 * @param params the parameter object to parse into
 * @param encoding the encoding to apply to non-file parameters
 */
function parseFileUpload(env, params, encoding) {
    encoding = encoding || "UTF-8";
    var boundary = getMimeParameter(env.CONTENT_TYPE, "boundary");
    if (!boundary) {
        return;
    }
    boundary = new ByteArray("--" + boundary, "ASCII");
    var body = env["jsgi.input"].read();
    var start = body.indexOf(boundary), end;
    while (start > -1) {
        start += boundary.length + 1;
        if (body[start++] == HYPHEN &&  body[start++] == HYPHEN)
            break;
        end = body.indexOf(boundary, start);
        if (end < 0)
            break;
        var part = body.slice(start, end - 2);
        var delim = part.indexOf(EMPTY_LINE);
        if (delim > 0) {
            var data = {};
            var headers = [];
            part.slice(0, delim).split(CRLF).forEach(function(line) {
                line = line.decodeToString(encoding);
                // unfold multiline headers
                if ((line.startsWith(" ") || line.startsWith("\t")) && headers.length) {
                    headers.peek() += line;
                } else {
                    headers.push(line);
                }
            });
            for each (var header in headers) {
                if (header.toLowerCase().startsWith("content-disposition:")) {
                    data.name = getMimeParameter(header, "name");
                    data.filename = getMimeParameter(header, "filename");
                } else if (header.toLowerCase().startsWith("content-type:")) {
                    data.contentType = header.substring(13).trim();
                }
            }
            data.value = part.slice(delim + 4);
            // use parameters.mergeParameter() to group and slice parameters
            if (data.filename) {
                mergeParameter(params, data.name, data);
            } else {
                mergeParameter(params, data.name, data.value.decodeToString(encoding));
            }
        }
        start = end;
    }
}<commit_msg>Rewrite file upload to use fixed-length buffer<commit_after>
require('core/string');
require('core/array');
include('binary');
include('./util');
include('./parameters');

export('isFileUpload', 'parseFileUpload');

var log = require('helma/logging').getLogger(module.id);

var HYPHEN  = "-".charCodeAt(0);
var CRLF = new ByteString("\r\n", "ASCII");
var EMPTY_LINE = new ByteString("\r\n\r\n", "ASCII");

/**
 * Find out whether the content type denotes a format this module can parse.
 * @param contentType a HTTP request Content-Type header
 * @return true if the content type can be parsed as form data by this module
 */
function isFileUpload(contentType) {
    return contentType && String(contentType)
            .toLowerCase().startsWith("multipart/form-data");
}

/**
 * Rough but working first draft of file upload support.
 * Everything's done in memory so beware of large files.
 * @param env the JSGI env object
 * @param params the parameter object to parse into
 * @param encoding the encoding to apply to non-file parameters
 */
function parseFileUpload(env, params, encoding) {
    encoding = encoding || "UTF-8";
    var boundary = getMimeParameter(env.CONTENT_TYPE, "boundary");
    if (!boundary) {
        return;
    }
    boundary = new ByteArray("--" + boundary, "ASCII");
    var input = env["jsgi.input"];
    var buflen = 8192;
    var refillThreshold = 6144;
    var buffer = new ByteArray(buflen);
    var data;
    var eof = false;
    var position = 0, end = 0;

    var refill = function() {
        if (position < end) {
            buffer.copy(position, end, buffer, 0);
            end -= position;
            position = 0;
        } else {
            position = end = 0;
        }
        var read = input.readInto(buffer, end)
        if (read > -1) {
            end += read;
        } else {
            eof = true;
        }
        return read;
    }
    refill();

    while (!eof) {
        if (!data) {
            var a = buffer.indexOf(boundary, position, end);
            if (a < 0) {
                throw new Error("boundary not found in multipart stream");
            }
            a += boundary.length;
            if (buffer[a++] == HYPHEN &&  buffer[a++] == HYPHEN) {
                break;
            }
            position = a + 1;
            var b = buffer.indexOf(EMPTY_LINE, position, end);
            if (b < 0) {
                throw new Error("could not parse headers");
            }
            data = {value: new ByteArray(0)};
            var headers = [];
            buffer.slice(position, b).split(CRLF).forEach(function(line) {
                line = line.decodeToString(encoding);
                // unfold multiline headers
                if ((line.startsWith(" ") || line.startsWith("\t")) && headers.length) {
                    headers.peek() += line;
                } else {
                    headers.push(line);
                }
            });
            for each (var header in headers) {
                if (header.toLowerCase().startsWith("content-disposition:")) {
                    data.name = getMimeParameter(header, "name");
                    data.filename = getMimeParameter(header, "filename");
                } else if (header.toLowerCase().startsWith("content-type:")) {
                    data.contentType = header.substring(13).trim();
                }
            }
            // move position after the empty line that separates headers from body
            position = b + 4;
        }
        var c = buffer.indexOf(boundary, position, end);
        // no
        if (c < 0) {
            // no terminating boundary found, slurp bytes and check for
            // partial boundary at buffer end which we know starts with "--".
            var hyphen = buffer.indexOf(HYPHEN, end - boundary.length, end);
            var copyTo =  (hyphen < 0) ? end : hyphen;
            buffer.copy(position, copyTo, data.value, data.value.length)
            position = copyTo;
            if (!eof) {
                refill();
            }
        } else {
            // found terminating boundary, complete data and merge into parameters
            buffer.copy(position, c - 2, data.value, data.value.length);
            position = c;
            if (data.filename) {
                mergeParameter(params, data.name, data);
            } else {
                mergeParameter(params, data.name, data.value.decodeToString(encoding));
            }
            data = null;
            if (position > refillThreshold && !eof) {
                refill();
            }
        }
    }
}<|endoftext|>