<commit_before>function fireKeyup(el) {
    if (document.createEvent) {
        var evObj;
        if (window.KeyEvent) {
            evObj = document.createEvent('KeyEvents');
            evObj.initKeyEvent('keyup', true, true, window, false, false, false, false, 13, 0);
        } else {
            evObj = document.createEvent('UIEvents');
            evObj.initUIEvent('keyup', true, true, window, 1);
        }
        el.dispatchEvent(evObj);
    } else if( document.createEventObject ) {
        el.fireEvent('onkeyup');
    } else {
        // IE 5.0, seriously? :)
    }
}

// http://stackoverflow.com/questions/5658849/whats-the-equivalent-of-jquerys-trigger-method-without-jquery
function fireClick(el) {
    var evt;
    if (document.createEvent) {
        evt = document.createEvent("MouseEvents");
        evt.initMouseEvent("click", true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
    }
    (evt) ? el.dispatchEvent(evt) : (el.click && el.click());
}

describe('Button', function() {

    var list;

    beforeEach(function() {
        $('body').append($('
\
            <input class="search" />\
            Sort name\
            Sort name asc\
            Sort name desc\

\

Jonny1986
\

Jocke1985
\

\

'));

        list = new List('parse-list', {
            valueNames: ['name', 'born']
        });
    });

    afterEach(function() {
        $('#parse-list').remove();
    });

    describe('Sort', function() {
        it('should trigger sortStart', function(done) {
            list.on('sortComplete', function() {
                done();
            });
            fireClick($('#sort1')[0]);
        });
        it('should trigger sortComplete', function(done) {
            list.on('sortComplete', function() {
                done();
            });
            fireClick($('#sort1')[0]);
        });

        it('should switch sorting order when clicking multiple times', function(done) {
            var sortRun = 0;
            list.on('sortComplete', function() {
                sortRun++;
                if (sortRun == 1) {
                    expect($('#sort1').hasClass('asc')).to.be(true);
                    expect($('#sort1').hasClass('desc')).to.be(false);
                    fireClick($('#sort1')[0]);
                } else if (sortRun == 2) {
                    expect($('#sort1').hasClass('asc')).to.be(false);
                    expect($('#sort1').hasClass('desc')).to.be(true);
                    fireClick($('#sort1')[0]);
                } else if (sortRun == 3) {
                    expect($('#sort1').hasClass('asc')).to.be(true);
                    expect($('#sort1').hasClass('desc')).to.be(false);
                    done();
                }
            });
            expect($('#sort1').hasClass('asc')).to.be(false);
            expect($('#sort1').hasClass('desc')).to.be(false);
            fireClick($('#sort1')[0]);
        });

        it('should sort with predefined order', function(done) {
            var sortRun = 0;
            list.on('sortComplete', function() {
                sortRun++;
                if (sortRun == 1) {
                    expect($('#sort1').hasClass('asc')).to.be(false);
                    expect($('#sort1').hasClass('desc')).to.be(false);
                    expect($('#sort2').hasClass('asc')).to.be(true);
                    expect($('#sort2').hasClass('desc')).to.be(false);
                    expect($('#sort3').hasClass('asc')).to.be(false);
                    expect($('#sort3').hasClass('desc')).to.be(false);
                    fireClick($('#sort2')[0]);
                } else if (sortRun == 2) {
                    expect($('#sort1').hasClass('asc')).to.be(false);
                    expect($('#sort1').hasClass('desc')).to.be(false);
                    expect($('#sort2').hasClass('asc')).to.be(true);
                    expect($('#sort2').hasClass('desc')).to.be(false);
                    expect($('#sort3').hasClass('asc')).to.be(false);
                    expect($('#sort3').hasClass('desc')).to.be(false);
                    fireClick($('#sort2')[0]);
                } else if (sortRun == 3) {
                    expect($('#sort1').hasClass('asc')).to.be(false);
                    expect($('#sort1').hasClass('desc')).to.be(false);
                    expect($('#sort2').hasClass('asc')).to.be(true);
                    expect($('#sort2').hasClass('desc')).to.be(false);
                    expect($('#sort3').hasClass('asc')).to.be(false);
                    expect($('#sort3').hasClass('desc')).to.be(false);
                    fireClick($('#sort3')[0]);
                } else if (sortRun == 4) {
                    expect($('#sort1').hasClass('asc')).to.be(false);
                    expect($('#sort1').hasClass('desc')).to.be(false);
                    expect($('#sort2').hasClass('asc')).to.be(false);
                    expect($('#sort2').hasClass('desc')).to.be(false);
                    expect($('#sort3').hasClass('asc')).to.be(false);
                    expect($('#sort3').hasClass('desc')).to.be(true);
                    fireClick($('#sort3')[0]);
                } else if (sortRun == 5) {
                    expect($('#sort1').hasClass('asc')).to.be(false);
                    expect($('#sort1').hasClass('desc')).to.be(false);
                    expect($('#sort2').hasClass('asc')).to.be(false);
                    expect($('#sort2').hasClass('desc')).to.be(false);
                    expect($('#sort3').hasClass('asc')).to.be(false);
                    expect($('#sort3').hasClass('desc')).to.be(true);
                    done();
                }
            });
            expect($('#sort1').hasClass('asc')).to.be(false);
            expect($('#sort1').hasClass('desc')).to.be(false);
            expect($('#sort2').hasClass('asc')).to.be(false);
            expect($('#sort2').hasClass('desc')).to.be(false);
            expect($('#sort3').hasClass('asc')).to.be(false);
            expect($('#sort3').hasClass('desc')).to.be(false);
            fireClick($('#sort2')[0]);
        });
    });

    describe('Search', function() {
        it('should trigger searchStart', function(done) {
            list.on('searchStart', function() {
                done();
            });
            $('#parse-list .search').val('jon');
            fireKeyup($('#parse-list .search')[0]);
        });
        it('should trigger searchComplete', function(done) {
            list.on('searchComplete', function() {
                done();
            });
            $('#parse-list .search').val('jon');
            fireKeyup($('#parse-list .search')[0]);
        });
    });
});
<commit_msg>Set timeout for fireClick, otherwise IE8 breaks<commit_after>function fireKeyup(el) {
    if (document.createEvent) {
        var evObj;
        if (window.KeyEvent) {
            evObj = document.createEvent('KeyEvents');
            evObj.initKeyEvent('keyup', true, true, window, false, false, false, false, 13, 0);
        } else {
            evObj = document.createEvent('UIEvents');
            evObj.initUIEvent('keyup', true, true, window, 1);
        }
        el.dispatchEvent(evObj);
    } else if( document.createEventObject ) {
        el.fireEvent('onkeyup');
    } else {
        // IE 5.0, seriously? :)
    }
}

// http://stackoverflow.com/questions/5658849/whats-the-equivalent-of-jquerys-trigger-method-without-jquery
function fireClick(el) {
    var evt;
    if (document.createEvent) {
        evt = document.createEvent("MouseEvents");
        evt.initMouseEvent("click", true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
    }
    (evt) ? el.dispatchEvent(evt) : (el.click && el.click());
}

describe('Button', function() {

    var list;

    beforeEach(function() {
        $('body').append($('
\
            <input class="search" />\
            Sort name\
            Sort name asc\
            Sort name desc\

\

Jonny1986
\

Jocke1985
\

\

'));

        list = new List('parse-list', {
            valueNames: ['name', 'born']
        });
    });

    afterEach(function() {
        $('#parse-list').remove();
    });

    describe('Sort', function() {
        it('should trigger sortStart', function(done) {
            list.on('sortComplete', function() {
                done();
            });
            fireClick($('#sort1')[0]);
        });
        it('should trigger sortComplete', function(done) {
            list.on('sortComplete', function() {
                done();
            });
            fireClick($('#sort1')[0]);
        });

        it('should switch sorting order when clicking multiple times', function(done) {
            this.timeout(5000);
            var sortRun = 0;
            list.on('sortComplete', function() {
                sortRun++;
                if (sortRun == 1) {
                    expect($('#sort1').hasClass('asc')).to.be(true);
                    expect($('#sort1').hasClass('desc')).to.be(false);
                    setTimeout(function() {
                        fireClick($('#sort1')[0]);
                    }, 50);
                } else if (sortRun == 2) {
                    expect($('#sort1').hasClass('asc')).to.be(false);
                    expect($('#sort1').hasClass('desc')).to.be(true);
                    setTimeout(function() {
                        fireClick($('#sort1')[0]);
                    }, 50);
                } else if (sortRun == 3) {
                    expect($('#sort1').hasClass('asc')).to.be(true);
                    expect($('#sort1').hasClass('desc')).to.be(false);
                    done();
                }
            });
            expect($('#sort1').hasClass('asc')).to.be(false);
            expect($('#sort1').hasClass('desc')).to.be(false);
            fireClick($('#sort1')[0]);
        });

        it('should sort with predefined order', function(done) {
            this.timeout(10000);
            var sortRun = 0;
            list.on('sortComplete', function() {
                sortRun++;
                if (sortRun == 1) {
                    expect($('#sort1').hasClass('asc')).to.be(false);
                    expect($('#sort1').hasClass('desc')).to.be(false);
                    expect($('#sort2').hasClass('asc')).to.be(true);
                    expect($('#sort2').hasClass('desc')).to.be(false);
                    expect($('#sort3').hasClass('asc')).to.be(false);
                    expect($('#sort3').hasClass('desc')).to.be(false);
                    setTimeout(function() {
                        fireClick($('#sort2')[0]);
                    }, 50);
                } else if (sortRun == 2) {
                    expect($('#sort1').hasClass('asc')).to.be(false);
                    expect($('#sort1').hasClass('desc')).to.be(false);
                    expect($('#sort2').hasClass('asc')).to.be(true);
                    expect($('#sort2').hasClass('desc')).to.be(false);
                    expect($('#sort3').hasClass('asc')).to.be(false);
                    expect($('#sort3').hasClass('desc')).to.be(false);
                    setTimeout(function() {
                        fireClick($('#sort2')[0]);
                    }, 50);
                } else if (sortRun == 3) {
                    expect($('#sort1').hasClass('asc')).to.be(false);
                    expect($('#sort1').hasClass('desc')).to.be(false);
                    expect($('#sort2').hasClass('asc')).to.be(true);
                    expect($('#sort2').hasClass('desc')).to.be(false);
                    expect($('#sort3').hasClass('asc')).to.be(false);
                    expect($('#sort3').hasClass('desc')).to.be(false);
                    setTimeout(function() {
                        fireClick($('#sort3')[0]);
                    }, 50);
                } else if (sortRun == 4) {
                    expect($('#sort1').hasClass('asc')).to.be(false);
                    expect($('#sort1').hasClass('desc')).to.be(false);
                    expect($('#sort2').hasClass('asc')).to.be(false);
                    expect($('#sort2').hasClass('desc')).to.be(false);
                    expect($('#sort3').hasClass('asc')).to.be(false);
                    expect($('#sort3').hasClass('desc')).to.be(true);
                    setTimeout(function() {
                        fireClick($('#sort3')[0]);
                    }, 50);
                } else if (sortRun == 5) {
                    expect($('#sort1').hasClass('asc')).to.be(false);
                    expect($('#sort1').hasClass('desc')).to.be(false);
                    expect($('#sort2').hasClass('asc')).to.be(false);
                    expect($('#sort2').hasClass('desc')).to.be(false);
                    expect($('#sort3').hasClass('asc')).to.be(false);
                    expect($('#sort3').hasClass('desc')).to.be(true);
                    done();
                }
            });
            expect($('#sort1').hasClass('asc')).to.be(false);
            expect($('#sort1').hasClass('desc')).to.be(false);
            expect($('#sort2').hasClass('asc')).to.be(false);
            expect($('#sort2').hasClass('desc')).to.be(false);
            expect($('#sort3').hasClass('asc')).to.be(false);
            expect($('#sort3').hasClass('desc')).to.be(false);
            fireClick($('#sort2')[0]);
        });
    });

    describe('Search', function() {
        it('should trigger searchStart', function(done) {
            list.on('searchStart', function() {
                done();
            });
            $('#parse-list .search').val('jon');
            fireKeyup($('#parse-list .search')[0]);
        });
        it('should trigger searchComplete', function(done) {
            list.on('searchComplete', function() {
                done();
            });
            $('#parse-list .search').val('jon');
            fireKeyup($('#parse-list .search')[0]);
        });
    });
});
<|endoftext|>


<commit_before>
var parseString = require('xml2js').parseString;
var data2xml = require('data2xml');
var convert  = data2xml();

var config = require('../config.js');
var wxconfig = config.wx;  // 微信配置

var appid = wxconfig.appid; // 微信 apid
var appsecret = wxconfig.appsecret; // 微信 appsecret
var errorMessage = wxconfig.errorMessage; // 微信出错回复

var WechatAPI = require('wechat-api');
var api = new WechatAPI(appid, appsecret);

var Poster = require('./poster')
var poster = new Poster(); // 图片处理函数

var path = require('path');
var type = 'image';

// var filepath = path.join(__dirname, '../img/canvas.jpg');

// -----------------------------------------------------------------
function log(info) {
  console.log("-----------------------------------");
  var length = arguments.length;
  for (var i = 0; i < length; i++) {
    console.log(arguments[i]);
  }
}

// -----------------------------------------------------------------

function MessageServer() {
};
module.exports = MessageServer;

// -----------------------------------------------------------------
/**
 * 微信订阅号根据提供关键字返回图片
 * @param  {httpRequest}   req  http request
 * @param  {httpResponse}   res  http response
 * @param  {Function} next transfer to next handler
 */
// 1. 用户提供文字，微信POST一份xml消息，解析xml 到 json 结构获取用户的openid 和 content,
// 2. 获取用户信息，根据用户信息生成图片，存于 img 路径下，并返回地址 filepath,
// 2. 根据filepath 上传图片到微信服务器，得到 media_id
// 4. 根据 media_id 生成xml 信息返回给用户，则用户得到一张图片
// 5. 删除用户图片

MessageServer.prototype.getMessage = function(req, res, next) {
	log("getMessage: this function called");
	next();
	setTimeout(function() {
		res.send("");
	}, 5000);

	var self = this;
	var body = req.body;  //用户消息
	parseString(body, function (err, result) {
    if(err) {
    	log("getMessage: parsing xml error", err);
    	res.send("")
    } else {
    	log("getMessage: parsing xml succeed", result);
    	if(!result.hasOwnProperty('xml')) {
    		log("getMessage: parsing xml failed, not exists xml");
    		res.send("");
    	} else {
	    	var xml = result.xml;
	    	var ToUserName = xml.ToUserName[0];
	    	var FromUserName = xml.FromUserName[0];
	    	var MsgType = xml.MsgType[0];

	    	var generate_flag = false; // 是否进行

	    	if(MsgType === "event" && xml.hasOwnProperty("Event") && xml.Event[0] === "CLICK" && xml.EventKey[0] === "generate_card") {
	    		generate_flag = true;
	    	} else if(MsgType === "text" && xml.hasOwnProperty("Content") && (xml.Content[0] === "开业啦" || xml.Content[0] === "刘大哥")){
	    		generate_flag = true;
	    	}

	    	var imgLists = [];

	    	// 生成用户提示等待消息
	    	var errorXml = convert(
	    		'xml',
	    		{
	    			ToUserName: {
	    				_cdata: FromUserName,
	    			},
	    			FromUserName: {
	    				_cdata: ToUserName
	    			},
	    			CreateTime: Date.now(),
	    			MsgType: {
	    				_cdata: 'text'
	    			},
	    			Content: {
	    				_cdata: errorMessage
	    			}
	    		}
	  		);
	    	// 获取用户基本信息

	    	if(!generate_flag) {
	    		res.send(errorXml);
	    	} else {
		    	api.getUser({openid: FromUserName, lang: 'en'}, function(err, user) {
		    		if(err) {
		    			log("getMessage: get user information error", err);
		    			res.send(errorXml);
		    		} else {
		    			log("getMessage: get user information succeed");
		    			if(!user || !user.hasOwnProperty("nickname")) {
		    				log("getMessage: get user information failed", user);
		    				res.send(errorXml);
		    			} else {

		    				var wxImgOptions = {
		    					openid: FromUserName,
		    					headimgurl: user.headimgurl
		    				}

		    				// 下载用户图像
		    				poster.getWxUserImg(wxImgOptions, function(err, imgInfo) {
		    					if(err) {
		    						log("getMessage: get user wximage headimg error", err);
		    						res.send(errorXml);
		    					} else {
		    						var userimg = imgInfo.userimg;
		    						log("userimg: " + userimg);

		    						imgLists.push(imgInfo.userimg); // 存储用户图像

		    						// 随机选择背景图片
		    						var canvasNum = Math.floor(Math.random() * 10) + 1;
		    						var filepath = path.join(__dirname, '../img/', "canvas" + canvasNum + '.jpg');

		    						var fillWordOptions = {
		    							imagePath: filepath,
		    							username: user.nickname
		    						};

		    						// 背景图片填充文字
		    						poster.fillWord(fillWordOptions, function(err, image) {
		    							if(err) {
		    								log("getMessage: fillword error", err);
		    								res.send(errorXml);
		    							} else {
		    								log("image: " + image)

	 											imgLists.push(image);

		    								handlePhotoOptions = {
		    									image: image,
		    									userimage:userimg
		    								}

		    								// 合成图片
		    								poster.handlePhoto(handlePhotoOptions, function(err) {
		    									if(err) {
		    										log("getMessage: handle photo error", err);
		    										res.send(errorXml);
		    									} else {
		    										// 上传图片到微信服务器
														api.uploadMedia(image, type, function(err, result) {
															if(err) {
																log("upload image error", err);
																res.send(errorXml);
															} else {
																log("upload image succeed", result);
																var media_id = result.media_id;
																// 回复图片信息 xml 结构
													    	var replyXML = convert(
													    		'xml',
													    		{
													    			ToUserName: {
													    				_cdata: FromUserName,
													    			},
													    			FromUserName: {
													    				_cdata: ToUserName
													    			},
													    			CreateTime: Date.now(),
													    			MsgType: {
													    				_cdata: type
													    			},
													    			Image: {
													    				MediaId: {
													    					_cdata: media_id
													    				}
													    			}
													    		}
													  		);
													    	// 返回用户图片信息
													    	log("replyXML: ", replyXML);
													  		res.send(replyXML);

													  		// 移除用户图片信息
													  		poster.RemoveUserImg({imgLists: imgLists}, function(err) {
													  			if(err) {
													  				log("getMessage: remove user image error", err);
													  			} else {
													  				log("getMessage: remove user image succeed");
													  			}
													  		})

															}
														});
		    									}
		    								})
		    							}
		    						})
		    					}
		    				})
		    			}
		    		}
		    	});
	    	}
    	}
    }
  });
};	<commit_msg>ajust username<commit_after>
var parseString = require('xml2js').parseString;
var data2xml = require('data2xml');
var convert  = data2xml();

var config = require('../config.js');
var wxconfig = config.wx;  // 微信配置

var appid = wxconfig.appid; // 微信 apid
var appsecret = wxconfig.appsecret; // 微信 appsecret
var errorMessage = wxconfig.errorMessage; // 微信出错回复

var WechatAPI = require('wechat-api');
var api = new WechatAPI(appid, appsecret);

var Poster = require('./poster')
var poster = new Poster(); // 图片处理函数

var path = require('path');
var type = 'image';

// var filepath = path.join(__dirname, '../img/canvas.jpg');

// -----------------------------------------------------------------
function log(info) {
  console.log("-----------------------------------");
  var length = arguments.length;
  for (var i = 0; i < length; i++) {
    console.log(arguments[i]);
  }
}

// -----------------------------------------------------------------

function MessageServer() {
};
module.exports = MessageServer;

// -----------------------------------------------------------------
/**
 * 微信订阅号根据提供关键字返回图片
 * @param  {httpRequest}   req  http request
 * @param  {httpResponse}   res  http response
 * @param  {Function} next transfer to next handler
 */
// 1. 用户提供文字，微信POST一份xml消息，解析xml 到 json 结构获取用户的openid 和 content,
// 2. 获取用户信息，根据用户信息生成图片，存于 img 路径下，并返回地址 filepath,
// 2. 根据filepath 上传图片到微信服务器，得到 media_id
// 4. 根据 media_id 生成xml 信息返回给用户，则用户得到一张图片
// 5. 删除用户图片

MessageServer.prototype.getMessage = function(req, res, next) {
	log("getMessage: this function called");
	next();
	setTimeout(function() {
		res.send("");
	}, 4500);

	var self = this;
	var body = req.body;  //用户消息
	parseString(body, function (err, result) {
    if(err) {
    	log("getMessage: parsing xml error", err);
    	res.send("")
    } else {
    	log("getMessage: parsing xml succeed", result);

    	var xml = result.xml;
    	var ToUserName = xml.ToUserName[0];
    	var FromUserName = xml.FromUserName[0];
    	var MsgType = xml.MsgType[0];

    	var generate_flag = false; // 是否进行

    	if(MsgType === "event" && xml.Event[0] === "CLICK") {
    		generate_flag = true;
    	} else if(MsgType === "text" && (xml.Content[0] === "开业啦" || xml.Content[0] === "刘大哥")){
    		generate_flag = true;
    	}

    	var imgLists = [];

    	// 生成用户提示等待消息
    	var errorXml = convert(
    		'xml',
    		{
    			ToUserName: {
    				_cdata: FromUserName,
    			},
    			FromUserName: {
    				_cdata: ToUserName
    			},
    			CreateTime: Date.now(),
    			MsgType: {
    				_cdata: 'text'
    			},
    			Content: {
    				_cdata: errorMessage
    			}
    		}
  		);
    	// 获取用户基本信息

    	if(!generate_flag) {
    		res.send(errorXml);
    	} else {
	    	api.getUser({openid: FromUserName, lang: 'en'}, function(err, user) {
	    		if(err) {
	    			log("getMessage: get user information error", err);
	    			res.send(errorXml);
	    		} else {
	    			log("getMessage: get user information succeed");
	    			if(!user || !user.hasOwnProperty("nickname")) {
	    				log("getMessage: get user information failed", user);
	    				res.send(errorXml);
	    			} else {

	    				var wxImgOptions = {
	    					openid: FromUserName,
	    					headimgurl: user.headimgurl
	    				}

	    				// 下载用户图像
	    				poster.getWxUserImg(wxImgOptions, function(err, imgInfo) {
	    					if(err) {
	    						log("getMessage: get user wximage headimg error", err);
	    						res.send(errorXml);
	    					} else {
	    						var userimg = imgInfo.userimg;
	    						log("userimg: " + userimg);

	    						imgLists.push(imgInfo.userimg); // 存储用户图像

	    						// 随机选择背景图片
	    						var canvasNum = Math.floor(Math.random() * 10) + 1;
	    						var filepath = path.join(__dirname, '../img/', "canvas" + canvasNum + '.jpg');

	    						var fillWordOptions = {
	    							imagePath: filepath,
	    							username: user.nickname
	    						};

	    						// 背景图片填充文字
	    						poster.fillWord(fillWordOptions, function(err, image) {
	    							if(err) {
	    								log("getMessage: fillword error", err);
	    								res.send(errorXml);
	    							} else {
	    								log("image: " + image)

 											imgLists.push(image);

	    								handlePhotoOptions = {
	    									image: image,
	    									userimage:userimg
	    								}

	    								// 合成图片
	    								poster.handlePhoto(handlePhotoOptions, function(err) {
	    									if(err) {
	    										log("getMessage: handle photo error", err);
	    										res.send(errorXml);
	    									} else {
	    										// 上传图片到微信服务器
													api.uploadMedia(image, type, function(err, result) {
														if(err) {
															log("upload image error", err);
															res.send(errorXml);
														} else {
															log("upload image succeed", result);
															var media_id = result.media_id;
															// 回复图片信息 xml 结构
												    	var replyXML = convert(
												    		'xml',
												    		{
												    			ToUserName: {
												    				_cdata: FromUserName,
												    			},
												    			FromUserName: {
												    				_cdata: ToUserName
												    			},
												    			CreateTime: Date.now(),
												    			MsgType: {
												    				_cdata: type
												    			},
												    			Image: {
												    				MediaId: {
												    					_cdata: media_id
												    				}
												    			}
												    		}
												  		);
												    	// 返回用户图片信息
												    	log("replyXML: ", replyXML);
												  		res.send(replyXML);

												  		// 移除用户图片信息
												  		poster.RemoveUserImg({imgLists: imgLists}, function(err) {
												  			if(err) {
												  				log("getMessage: remove user image error", err);
												  			} else {
												  				log("getMessage: remove user image succeed");
												  			}
												  		})

														}
													});
	    									}
	    								})
	    							}
	    						})
	    					}
	    				})
	    			}
	    		}
	    	});
    	}

    }
  });
};	<|endoftext|>


<commit_before><commit_msg>Added generated schema<commit_after>module.exports = {
    "people": {
        "properties": {
            "name": {
                "type": "string",
                "index": "not_analyzed"
            },
            "appearances": {
                "type": "long"
            },
            "links": {
                "type": "nested",
                "properties": {
                    "pets": {
                        "type": "nested",
                        "properties": {
                            "name": {
                                "type": "string",
                                "index": "not_analyzed"
                            },
                            "appearances": {
                                "type": "long"
                            },
                            "links": {
                                "type": "nested",
                                "properties": {
                                    "toys": {
                                        "type": "nested",
                                        "properties": {
                                            "name": {
                                                "type": "string",
                                                "index": "not_analyzed"
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "soulmate": {
                        "type": "nested",
                        "properties": {
                            "name": {
                                "type": "string",
                                "index": "not_analyzed"
                            },
                            "appearances": {
                                "type": "long"
                            },
                            "links": {
                                "type": "nested",
                                "properties": {
                                    "pets": {
                                        "type": "nested",
                                        "properties": {
                                            "name": {
                                                "type": "string",
                                                "index": "not_analyzed"
                                            },
                                            "appearances": {
                                                "type": "long"
                                            },
                                            "links": {
                                                "type": "nested",
                                                "properties": {
                                                    "toys": {
                                                        "type": "nested",
                                                        "properties": {
                                                            "name": {
                                                                "type": "string",
                                                                "index": "not_analyzed"
                                                            }
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    },
                                    "soulmate": {
                                        "type": "nested",
                                        "properties": {
                                            "name": {
                                                "type": "string",
                                                "index": "not_analyzed"
                                            },
                                            "appearances": {
                                                "type": "long"
                                            },
                                            "links": {
                                                "type": "nested",
                                                "properties": {
                                                    "pets": {
                                                        "type": "nested",
                                                        "properties": {

                                                        }
                                                    },
                                                    "soulmate": {
                                                        "type": "nested",
                                                        "properties": {

                                                        }
                                                    },
                                                    "lovers": {
                                                        "type": "nested",
                                                        "properties": {

                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    },
                                    "lovers": {
                                        "type": "nested",
                                        "properties": {

                                        }
                                    }
                                }
                            }
                        }
                    },
                    "lovers": {
                        "type": "nested",
                        "properties": {

                        }
                    }
                }
            }
        }
    }
};<|endoftext|>


<commit_before>var _ = require('underscore')
  , utils = require('./utils')

module.exports = Message

function Message(segments) {
  if (!(this instanceof Message))
    return new Message()
  if (segments && Array.isArray(segments)) {
    this.segments = segments
    this.segmentTypes = _.unique(
      _.pluck(this.segments, 'SegmentType')
    )
  } else {
    this.segments = []
    this.segmentTypes = []
  }
}

Message.prototype.addSegment = function(segment) {
  this.segments.push(segment)
  var t = segment.SegmentType
  if (!(~this.segmentTypes.indexOf(t))) {
    this.segmentTypes.push(t)
  }
  if (utils.segmentTypeIsHeader(t)) {
    this.header = segment
  }
}

Message.prototype.getHeader = function() {
  return this.header
}

Message.prototype.getDelims = function() {
  if (!this.header) return {
    segment: '\r',
    field: '|',
    component: '^',
    subcomponent: '&',
    repetition: '~',
    escape: '\\'
  }

  var chars = this.header.EncodingCharacters
  return {
    segment: '\r',
    field: chars[0],
    component: chars[1],
    subcomponent: chars[2],
    repetition: chars[3],
    escape: chars[4]
  }
}
<commit_msg>Make sure we pass in the segments if this is not instanceof Message<commit_after>var _ = require('underscore')
  , utils = require('./utils')

module.exports = Message

function Message(segments) {
  if (!(this instanceof Message))
    return new Message(segments)
  if (segments && Array.isArray(segments)) {
    this.segments = segments
    this.segmentTypes = _.unique(
      _.pluck(this.segments, 'SegmentType')
    )
  } else {
    this.segments = []
    this.segmentTypes = []
  }
}

Message.prototype.addSegment = function(segment) {
  this.segments.push(segment)
  var t = segment.SegmentType
  if (!(~this.segmentTypes.indexOf(t))) {
    this.segmentTypes.push(t)
  }
  if (utils.segmentTypeIsHeader(t)) {
    this.header = segment
  }
}

Message.prototype.getHeader = function() {
  return this.header
}

Message.prototype.getDelims = function() {
  if (!this.header) return {
    segment: '\r',
    field: '|',
    component: '^',
    subcomponent: '&',
    repetition: '~',
    escape: '\\'
  }

  var chars = this.header.EncodingCharacters
  return {
    segment: '\r',
    field: chars[0],
    component: chars[1],
    subcomponent: chars[2],
    repetition: chars[3],
    escape: chars[4]
  }
}
<|endoftext|>


<commit_before>const client = require('prom-client');
const metric = {
  http: {
    requests: {
      total: new client.Counter('http_requests_total', 'total number of http requests', ['method', 'path', 'status']),
      duration: new client.Summary('http_request_duration_milliseconds', 'request duration in milliseconds', ['method', 'path', 'status']),
      buckets: new client.Histogram('http_request_duration_buckets_milliseconds_buckets', 'request duration buckets in milliseconds', ['method', 'path', 'status'], { buckets: [ 300, 1200 ] })
    }
  },
  node: {
    lag: new client.Gauge('node_lag_duration_milliseconds', 'the event loop lag in milliseconds'),
    memory: {
      rss: new client.Gauge('node_memory_rss_bytes', 'the resident set size in bytes'),
      heap: {
        total: new client.Gauge('node_memory_heap_total_bytes', 'the V8 heap total in bytes'),
        used: new client.Gauge('node_memory_heap_used_bytes', 'the V8 heap used in bytes')
      }
    }

  }
}

function ms(start) {
  var diff = process.hrtime(start);
  return Math.round((diff[0] * 1e9 + diff[1]) / 1000000);
}

function observe(method, path, statusCode, start) {
  var path = path.toLowerCase();
  if (path !== '/metrics' && path !== '/metrics/') {
    var duration = ms(start);
    var method = method.toLowerCase();
    metric.http.requests.total.labels(method, path, statusCode).inc();
    metric.http.requests.duration.labels(method, path, statusCode).observe(duration);
    metric.http.requests.buckets.labels(method, path, statusCode).observe(duration);
  }
};

function observeMemory(rss, heapTotal, heapUsed) {
  metric.node.memory.rss.set(rss);
  metric.node.memory.heap.total.set(heapTotal);
  metric.node.memory.heap.used.set(heapUsed);
};

function observeLag(start, interval) {
  var lag = ms(start) - interval;
  metric.node.lag.set(lag);
};

module.exports = {
  observe: observe,
  observeLag: observeLag,
  observeMemory: observeMemory,
  summary: client.register.metrics
};
<commit_msg>removed un-necessary counts<commit_after>const client = require('prom-client');
const metric = {
  http: {
    requests: {
      duration: new client.Summary('http_request_duration_milliseconds', 'request duration in milliseconds', ['method', 'path', 'status']),
      buckets: new client.Histogram('http_request_duration_buckets_milliseconds', 'request duration buckets in milliseconds. Bucket size set to 500 and 2000 ms to enable apdex calculations with a T of 300ms', ['method', 'path', 'status'], { buckets: [ 500, 2000 ] })
    }
  },
  node: {
    lag: new client.Gauge('node_lag_duration_milliseconds', 'the event loop lag in milliseconds'),
    memory: {
      rss: new client.Gauge('node_memory_rss_bytes', 'the resident set size in bytes'),
      heap: {
        total: new client.Gauge('node_memory_heap_total_bytes', 'the V8 heap total in bytes'),
        used: new client.Gauge('node_memory_heap_used_bytes', 'the V8 heap used in bytes')
      }
    }

  }
}

function ms(start) {
  var diff = process.hrtime(start);
  return Math.round((diff[0] * 1e9 + diff[1]) / 1000000);
}

function observe(method, path, statusCode, start) {
  var path = path.toLowerCase();
  if (path !== '/metrics' && path !== '/metrics/') {
    var duration = ms(start);
    var method = method.toLowerCase();
    metric.http.requests.duration.labels(method, path, statusCode).observe(duration);
    metric.http.requests.buckets.labels(method, path, statusCode).observe(duration);
  }
};

function observeMemory(rss, heapTotal, heapUsed) {
  metric.node.memory.rss.set(rss);
  metric.node.memory.heap.total.set(heapTotal);
  metric.node.memory.heap.used.set(heapUsed);
};

function observeLag(start, interval) {
  var lag = ms(start) - interval;
  metric.node.lag.set(lag);
};

module.exports = {
  observe: observe,
  observeLag: observeLag,
  observeMemory: observeMemory,
  summary: client.register.metrics
};
<|endoftext|>


<commit_before>'use strict';

// modules dependencies
var utilsHelper = require('../helpers/utils-helper');
var mongodb = require('mongodb');

/**
 * @namespace Mongoat
 */
var Mongoat = mongodb;

/**
 * @private
 * @constructor
 * @description to initialize some properties
 */
Mongoat.Collection.prototype.init = function () {
  this.datetime = {};
  this.hooks = {};
  this.versioning = {};
  this.hooks = {};
};

(function () {
  var opMethod = ['insert', 'update', 'findAndModify', 'remove'];
  var colPrototype = Mongoat.Collection.prototype;

  colPrototype.init();

  for (var i = 0; i < opMethod.length; ++i) {
    colPrototype[opMethod[i] + 'Method'] = colPrototype[opMethod[i]];
  }
})();

/**
 * @function before
 * @memberOf Mongoat
 * @description add before hook to Collection
 * @param {String} opName - operation name, can be insert/update/findAndModify or remove
 * @param {Function} callback - the callback to run after the before hook
 * @return {Void} Nothing
 */
Mongoat.Collection.prototype.before = function(opName, callback) {
  this.hooks[this.s.namespace] = this.hooks[this.s.namespace] ||
    utilsHelper.getHooksTemplate();

  this.hooks[this.s.namespace].before[opName].push(callback);
};

/**
 * @function after
 * @memberOf Mongoat
 * @description add after hook to Collection
 * @param {String} opName - operation name, can be insert/update/findAndModify or remove
 * @param {Function} callback - the callback to run after the after hook
 * @return {Void} Nothing
 */
Mongoat.Collection.prototype.after = function(opName, callback) {
  this.hooks[this.s.namespace] = this.hooks[this.s.namespace] ||
    utilsHelper.getHooksTemplate();

  this.hooks[this.s.namespace].after[opName].push(callback);
};

/**
 * @function insert
 * @memberOf Mongoat
 * @description overwrite the insert method
 * @param {Object} document - document to insert
 * @param {Object} options - options used on insert
 * @return {Promise} - returned mongodb object after insert
 */
Mongoat.Collection.prototype.insert = function(document, options, callback) {
  return this.query('insert', undefined, undefined, document, options, callback);
};

/**
 * @function update
 * @memberOf Mongoat
 * @description overwrite the update method
 * @param {Object} query - query to match
 * @param {Object} update - document to update
 * @param {Object} options - options used on update
 * @return {Promise} - returned mongodb object after update
 */
Mongoat.Collection.prototype.update = function(query, update, options, callback) {
  return this.query('update', query, undefined, update, options, callback);
};

/**
 * @function findAndModify
 * @memberOf Mongoat
 * @description overwrite the findAndModify method
 * @param {Object} query - query to match
 * @param {Object} sort - sort rules
 * @param {Object} update - document to update
 * @param {Object} options - options used on update
 * @return {Promise} - returned mongodb object after findAndModify
 */
Mongoat.Collection.prototype.findAndModify = function(query, sort, update, options, callback) {
  return this.query('findAndModify', query, sort, update, options, callback);
};

/**
 * @function remove
 * @memberOf Mongoat
 * @description overwrite the remove method
 * @param {Object} query - query to match
 * @param {Object} options - options used on update
 * @return {Promise} - returned mongodb object after remove
 */
Mongoat.Collection.prototype.remove = function(query, options, callback) {
  return this.query('remove', query, undefined, undefined, options, callback);
};

/**
 * @function query
 * @memberOf Mongoat
 * @description to make any query, can be insert/update/findAndModify or remove
 * @param {String} opName - operation name, can be insert/update/findAndModify or remove
 * @param {Object} query - query to match
 * @param {Object} sort - sort rules
 * @param {Object} update - document to update
 * @param {Object} options - options used on update
 * @return {Promise} - returned mongodb object after query depending on opName
 */
Mongoat.Collection.prototype.query = function(opName, query, sort, document, options, callback) {
  var promises = [];
  var _this = this;
  var colName = _this.s.namespace;
  var opName_X;

  _this.hooks[colName] = _this.hooks[colName] || utilsHelper.getHooksTemplate();

  if (options && typeof options === 'function') {
    callback = options;
    options = {};
  }

  options = options || {};
  opName_X = (opName !== 'findAndModify') ? opName : 'update';

  utilsHelper.setDatetime(opName_X, _this.datetime[colName], document);
  promises = utilsHelper.promisify(_this.hooks[colName].before[opName_X], query, document);

  if (_this.versioning[colName]) {
    promises.push(_this.commit(opName, query, document, options));
  }

  return Promise.all(promises)
  .then(function (docToProcess) {
    var params = utilsHelper.setParams(opName, query, sort, docToProcess[0], options);

    return _this[opName + 'Method'].apply(_this, params)
    .then(function (mongObject) {

      return utilsHelper.processUpdatedDocment(opName, _this, query, mongObject, options)
      .then(function (obj) {
        promises = [];
        promises = utilsHelper.promisify(_this.hooks[colName].after[opName_X], obj);
        Promise.all(promises);

        if (callback && typeof callback === 'function') {
          callback(null, mongObject);
        }

        return mongObject;
      });
    });
  })
  .catch(function (err) {
    if (callback && typeof callback === 'function') {
      callback(err, null);
    } else {
      throw err;
    }
  });
};

/**
 * @function datetime
 * @memberOf Mongoat
 * @description to enable datetime feature
 * @param {Boolean} isEnabled - to enable or disable feature
 * @return {Void} Nothing
 */
Mongoat.Collection.prototype.datetime = function (isEnabled) {
  if (typeof isEnabled === 'boolean') {
    this.datetime[this.s.namespace] = isEnabled;
  }
};

/**
 * @function version
 * @memberOf Mongoat
 * @description to enable versioning feature
 * @param {Boolean} isEnabled - to enable or disable feature
 * @return {Void} Nothing
 */
Mongoat.Collection.prototype.version = function (isEnabled) {
  if (typeof isEnabled === 'boolean') {
    this.versioning[this.s.namespace] = isEnabled;
  }
};

/**
 * @function commit
 * @memberOf Mongoat
 * @description to commit document version
 * @param {String} opName - operation name, can be insert/update or remove
 * @param {Object} query - query to match
 * @param {Object} document - document to commit
 * @param {Object} options - options used on update
 * @return {Promise} - the document to insert/update or remove
 */
Mongoat.Collection.prototype.commit = function (opName, query, document, options) {
  if (opName === 'insert') {
    document._version = 1;
    return document;
  }

  var _this  = this;
  var shadowCol = _this.s.db.collection(_this.s.name + '.vermongo');

  shadowCol.datetime(_this.datetime[_this.s.namespace]);

  /*jshint maxcomplexity:10 */
  return _this.findOne(query)
  .then(function (docToProcess) {
    if (docToProcess) {
      var id = docToProcess._id ;
      docToProcess._version = docToProcess._version || 1;
      docToProcess._id = { _id: id, _version: docToProcess._version };
    }
    if (opName === 'update' || opName === 'findAndModify') {
      if (!docToProcess && options.upsert) {
        if (!document.$setOnInsert) {
          document._version = 1;
        } else {
          document.$setOnInsert._version = 1;
        }

        return document;
      }
    } else if (opName === 'remove') {
      if (!docToProcess) {
        return query;
      }
      docToProcess._version = 'deleted:' + docToProcess._id._version;
    }
    return shadowCol.insertMethod(docToProcess)
    .then(function () {
      if (opName === 'update' || opName === 'findAndModify') {
        if (!document.$setOnInsert && !document.$set) {
          document._version = docToProcess._id._version + 1;
        } else {
          document.$set = document.$set || {};
          document.$setOnInsert = document.$setOnInsert || {};
          document.$set._version = docToProcess._id._version + 1;
          document.$setOnInsert._version = docToProcess._id._version + 1;
        }
        return document;
      } else if (opName === 'remove') {
        return query;
      }
    });
  });
};

/**
 * @function restore
 * @memberOf Mongoat
 * @description to resotre document by version, can +v => version, 0 => last version or -v => last version - v
 * @param {Object} id - id of the document to restore
 * @param {Number} version - version of the document to restore
 * @return {Promise} - the restored document
 */
Mongoat.Collection.prototype.restore = function (id, version) {
  var col = this.s.db.collection(this.s.name);
  var shadowCol = this.s.db.collection(this.s.name + '.vermongo');
  var aggregatePipeline = [{ $match: { '_id._id' : id } }];

  if (version <= 0) {
    aggregatePipeline.push({ $sort: { '_id._version': -1 } });
    aggregatePipeline.push({ $skip: Math.abs(version) });
  } else {
    aggregatePipeline.push({ $match: { '_id._version' : version } });
  }

  aggregatePipeline.push({ $limit: 1 });

  return shadowCol.aggregate(aggregatePipeline)
  .nextObject()
  .then(function (document) {
    if (!document) {
      return document;
    }

    var id = document._id._id;
    delete document._id;

    return col.update({ _id: id }, document, { upsert: true })
    .then(function (mongObject) {
      if (mongObject.result.ok === 1 && mongObject.result.n === 1) {
        return document;
      }
    });
  });
};

// export Mongoat object
module.exports = Mongoat;<commit_msg>Send isAfterHook param<commit_after>'use strict';

// modules dependencies
var utilsHelper = require('../helpers/utils-helper');
var mongodb = require('mongodb');

/**
 * @namespace Mongoat
 */
var Mongoat = mongodb;

/**
 * @private
 * @constructor
 * @description to initialize some properties
 */
Mongoat.Collection.prototype.init = function () {
  this.datetime = {};
  this.hooks = {};
  this.versioning = {};
  this.hooks = {};
};

(function () {
  var opMethod = ['insert', 'update', 'findAndModify', 'remove'];
  var colPrototype = Mongoat.Collection.prototype;

  colPrototype.init();

  for (var i = 0; i < opMethod.length; ++i) {
    colPrototype[opMethod[i] + 'Method'] = colPrototype[opMethod[i]];
  }
})();

/**
 * @function before
 * @memberOf Mongoat
 * @description add before hook to Collection
 * @param {String} opName - operation name, can be insert/update/findAndModify or remove
 * @param {Function} callback - the callback to run after the before hook
 * @return {Void} Nothing
 */
Mongoat.Collection.prototype.before = function(opName, callback) {
  this.hooks[this.s.namespace] = this.hooks[this.s.namespace] ||
    utilsHelper.getHooksTemplate();

  this.hooks[this.s.namespace].before[opName].push(callback);
};

/**
 * @function after
 * @memberOf Mongoat
 * @description add after hook to Collection
 * @param {String} opName - operation name, can be insert/update/findAndModify or remove
 * @param {Function} callback - the callback to run after the after hook
 * @return {Void} Nothing
 */
Mongoat.Collection.prototype.after = function(opName, callback) {
  this.hooks[this.s.namespace] = this.hooks[this.s.namespace] ||
    utilsHelper.getHooksTemplate();

  this.hooks[this.s.namespace].after[opName].push(callback);
};

/**
 * @function insert
 * @memberOf Mongoat
 * @description overwrite the insert method
 * @param {Object} document - document to insert
 * @param {Object} options - options used on insert
 * @return {Promise} - returned mongodb object after insert
 */
Mongoat.Collection.prototype.insert = function(document, options, callback) {
  return this.query('insert', undefined, undefined, document, options, callback);
};

/**
 * @function update
 * @memberOf Mongoat
 * @description overwrite the update method
 * @param {Object} query - query to match
 * @param {Object} update - document to update
 * @param {Object} options - options used on update
 * @return {Promise} - returned mongodb object after update
 */
Mongoat.Collection.prototype.update = function(query, update, options, callback) {
  return this.query('update', query, undefined, update, options, callback);
};

/**
 * @function findAndModify
 * @memberOf Mongoat
 * @description overwrite the findAndModify method
 * @param {Object} query - query to match
 * @param {Object} sort - sort rules
 * @param {Object} update - document to update
 * @param {Object} options - options used on update
 * @return {Promise} - returned mongodb object after findAndModify
 */
Mongoat.Collection.prototype.findAndModify = function(query, sort, update, options, callback) {
  return this.query('findAndModify', query, sort, update, options, callback);
};

/**
 * @function remove
 * @memberOf Mongoat
 * @description overwrite the remove method
 * @param {Object} query - query to match
 * @param {Object} options - options used on update
 * @return {Promise} - returned mongodb object after remove
 */
Mongoat.Collection.prototype.remove = function(query, options, callback) {
  return this.query('remove', query, undefined, undefined, options, callback);
};

/**
 * @function query
 * @memberOf Mongoat
 * @description to make any query, can be insert/update/findAndModify or remove
 * @param {String} opName - operation name, can be insert/update/findAndModify or remove
 * @param {Object} query - query to match
 * @param {Object} sort - sort rules
 * @param {Object} update - document to update
 * @param {Object} options - options used on update
 * @return {Promise} - returned mongodb object after query depending on opName
 */
Mongoat.Collection.prototype.query = function(opName, query, sort, document, options, callback) {
  var promises = [];
  var _this = this;
  var colName = _this.s.namespace;
  var opName_X;

  _this.hooks[colName] = _this.hooks[colName] || utilsHelper.getHooksTemplate();

  if (options && typeof options === 'function') {
    callback = options;
    options = {};
  }

  options = options || {};
  opName_X = (opName !== 'findAndModify') ? opName : 'update';

  utilsHelper.setDatetime(opName_X, _this.datetime[colName], document);
  promises = utilsHelper.promisify(_this.hooks[colName].before[opName_X], query, document);

  if (_this.versioning[colName]) {
    promises.push(_this.commit(opName, query, document, options));
  }

  return Promise.all(promises)
  .then(function (docToProcess) {
    var params = utilsHelper.setParams(opName, query, sort, docToProcess[0], options);

    return _this[opName + 'Method'].apply(_this, params)
    .then(function (mongObject) {

      var isAfterHook = (_this.hooks[colName].after[opName_X].length > 0) ? true : false;

      return utilsHelper.processUpdatedDocment(opName, _this, isAfterHook, query, mongObject, options)
      .then(function (obj) {
        promises = [];
        promises = utilsHelper.promisify(_this.hooks[colName].after[opName_X], obj);
        Promise.all(promises);

        if (callback && typeof callback === 'function') {
          callback(null, mongObject);
        }

        return mongObject;
      });
    });
  })
  .catch(function (err) {
    if (callback && typeof callback === 'function') {
      callback(err, null);
    } else {
      throw err;
    }
  });
};

/**
 * @function datetime
 * @memberOf Mongoat
 * @description to enable datetime feature
 * @param {Boolean} isEnabled - to enable or disable feature
 * @return {Void} Nothing
 */
Mongoat.Collection.prototype.datetime = function (isEnabled) {
  if (typeof isEnabled === 'boolean') {
    this.datetime[this.s.namespace] = isEnabled;
  }
};

/**
 * @function version
 * @memberOf Mongoat
 * @description to enable versioning feature
 * @param {Boolean} isEnabled - to enable or disable feature
 * @return {Void} Nothing
 */
Mongoat.Collection.prototype.version = function (isEnabled) {
  if (typeof isEnabled === 'boolean') {
    this.versioning[this.s.namespace] = isEnabled;
  }
};

/**
 * @function commit
 * @memberOf Mongoat
 * @description to commit document version
 * @param {String} opName - operation name, can be insert/update or remove
 * @param {Object} query - query to match
 * @param {Object} document - document to commit
 * @param {Object} options - options used on update
 * @return {Promise} - the document to insert/update or remove
 */
Mongoat.Collection.prototype.commit = function (opName, query, document, options) {
  if (opName === 'insert') {
    document._version = 1;
    return document;
  }

  var _this  = this;
  var shadowCol = _this.s.db.collection(_this.s.name + '.vermongo');

  shadowCol.datetime(_this.datetime[_this.s.namespace]);

  /*jshint maxcomplexity:10 */
  return _this.findOne(query)
  .then(function (docToProcess) {
    if (docToProcess) {
      var id = docToProcess._id ;
      docToProcess._version = docToProcess._version || 1;
      docToProcess._id = { _id: id, _version: docToProcess._version };
    }
    if (opName === 'update' || opName === 'findAndModify') {
      if (!docToProcess && options.upsert) {
        if (!document.$setOnInsert) {
          document._version = 1;
        } else {
          document.$setOnInsert._version = 1;
        }

        return document;
      }
    } else if (opName === 'remove') {
      if (!docToProcess) {
        return query;
      }
      docToProcess._version = 'deleted:' + docToProcess._id._version;
    }
    return shadowCol.insertMethod(docToProcess)
    .then(function () {
      if (opName === 'update' || opName === 'findAndModify') {
        if (!document.$setOnInsert && !document.$set) {
          document._version = docToProcess._id._version + 1;
        } else {
          document.$set = document.$set || {};
          document.$setOnInsert = document.$setOnInsert || {};
          document.$set._version = docToProcess._id._version + 1;
          document.$setOnInsert._version = docToProcess._id._version + 1;
        }
        return document;
      } else if (opName === 'remove') {
        return query;
      }
    });
  });
};

/**
 * @function restore
 * @memberOf Mongoat
 * @description to resotre document by version, can +v => version, 0 => last version or -v => last version - v
 * @param {Object} id - id of the document to restore
 * @param {Number} version - version of the document to restore
 * @return {Promise} - the restored document
 */
Mongoat.Collection.prototype.restore = function (id, version) {
  var col = this.s.db.collection(this.s.name);
  var shadowCol = this.s.db.collection(this.s.name + '.vermongo');
  var aggregatePipeline = [{ $match: { '_id._id' : id } }];

  if (version <= 0) {
    aggregatePipeline.push({ $sort: { '_id._version': -1 } });
    aggregatePipeline.push({ $skip: Math.abs(version) });
  } else {
    aggregatePipeline.push({ $match: { '_id._version' : version } });
  }

  aggregatePipeline.push({ $limit: 1 });

  return shadowCol.aggregate(aggregatePipeline)
  .nextObject()
  .then(function (document) {
    if (!document) {
      return document;
    }

    var id = document._id._id;
    delete document._id;

    return col.update({ _id: id }, document, { upsert: true })
    .then(function (mongObject) {
      if (mongObject.result.ok === 1 && mongObject.result.n === 1) {
        return document;
      }
    });
  });
};

// export Mongoat object
module.exports = Mongoat;<|endoftext|>


<commit_before>//
//  Author: Vlad Seryakov vseryakov@gmail.com
//  Nov 2014
//

var util = require('util');
var fs = require('fs');
var path = require('path');
var logger = require(__dirname + '/../lib/logger');
var core = require(__dirname + '/../lib/core');
var lib = require(__dirname + '/../lib/lib');
var aws = require(__dirname + '/../lib/aws');
var msg = require(__dirname + '/../lib/msg');

var client = {
    name: "fcm",
    priority: 10,
    agents: {},
};
module.exports = client;

msg.modules.push(client);

client.check = function(dev)
{
    return dev.service == "fcm" || (dev.service == "gcm" && this.agents.default && this.agents.default.gcm);
}

// Initialize Google Cloud Messaging service to send push notifications to mobile devices
client.init = function(options)
{
    var self = this;
    var config = msg.getConfig(this.name);
    for (var i in config) {
        if (this.agents[config[i]._app]) continue;
        this.agents[config[i]._app] = lib.objClone(config[i], "_sent", 0, "_queue", 0);
        logger.info("init:", "fcm", lib.objDescr(config[i]));
    }
}

// Close GCM connection, flush the queue
client.close = function(callback)
{
    var self = this;
    lib.forEach(Object.keys(this.agents), function(key, next) {
        var agent = self.agents[key];
        delete self.agents[key];
        logger.info('close:', "fcm", key, 'queue:', agent._queue, 'sent:', agent._sent);

        var n = 0;
        function check() {
            if (!agent._queue || ++n > 600) {
                logger.info('close:', "fcm", "done", key);
                next();
            } else {
                setTimeout(check, 50);
            }
        }
        check();
    }, callback);
}

// Send push notification to an Android device, return true if queued.
client.send = function(dev, options, callback)
{
    if (!dev || !dev.id) return typeof callback == "function" && callback(lib.newError("invalid device:" + dev.id));

    var agent = this.agents[dev.app] || this.agents.default;
    if (!agent) return typeof callback == "function" && callback(lib.newError("FCM is not initialized for " + dev.id, 415));

    agent._queue++;

    var msg = { data: {}, notification: {}, priority: options.priority || "high" };
    msg[dev.id.indexOf(",") > -1 ? "registration_ids" : "to"] = dev.id;
    if (options.name) msg.collapse_key = options.name;
    if (options.ttl) msg.time_to_live = lib.toNumber(options.ttl);
    if (options.delay) msg.delay_while_idle = lib.toBool(options.delay);

    if (options.title) msg.notification.title = String(title);
    if (options.msg) msg.notification.body = String(options.msg);
    if (options.badge) msg.notification.badge = lib.toBool(options.badge);
    if (options.sound) msg.notification.sound = typeof options.sound == "string" ? options.sound : "default";
    if (options.vibrate) msg.notification.vibrate = lib.toBool(options.vibrate);
    if (options.icon) msg.notification.icon = String(options.icon);
    if (options.tag) msg.notification.tag = String(options.tag);
    if (options.color) msg.notification.color = String(options.color);
    if (options.clickAction) msg.notification.click_action = String(options.clickAction);
    if (options.titleLocKey) msg.notification.title_loc_key = String(options.titleLocKey);
    if (options.titleLocArgs) msg.notification.title_loc_args = String(options.titleLocArgs);
    if (options.bodyLocKey) msg.notification.body_loc_key = String(options.bodyLocKey);
    if (options.bodyLocArgs) msg.notification.body_loc_args = String(options.bodyLocArgs);

    if (options.id) msg.data.id = String(options.id);
    if (options.url) msg.data.url = String(options.url);
    if (options.type) msg.data.type = String(options.type);

    var opts = {
        method: 'POST',
        headers: { 'Authorization': 'key=' + agent._key },
        postdata: msg,
        retryCount: agent.retryCount || this.retryCount || 3,
        retryTimeout: agent.retryTimeout || this.retryTimeout || 1000,
        retryOnError: client.retryOnError,
    };
    core.httpGet('https://fcm.googleapis.com/fcm/send', opts, function(err, params) {
        if (!err && params.status >= 400) err = lib.newError(params.status + ": " + params.data, params.status);
        if (err) logger.error("send:", "fcm", agent._app, dev, err, msg);
        agent._queue--;
        agent._sent++;
        if (typeof callback == "function") callback(err);
    });
    return true;
}

// Retry on server error, honor Retry-After header if present, use it only on the first error
client.retryOnError = function()
{
    if (this.status < 500) return 0;
    if (!this.retryAfter) {
        this.retryAfter = lib.toNumber(this.headers['retry-after']) * 1000;
        if (this.retryAfter > 0 && this.retryCount > 0) this.retryTimeout = this.retryAfter/2;
    }
    return 1;
}
<commit_msg>fixed FCM parameters<commit_after>//
//  Author: Vlad Seryakov vseryakov@gmail.com
//  Nov 2014
//

var util = require('util');
var fs = require('fs');
var path = require('path');
var logger = require(__dirname + '/../lib/logger');
var core = require(__dirname + '/../lib/core');
var lib = require(__dirname + '/../lib/lib');
var aws = require(__dirname + '/../lib/aws');
var msg = require(__dirname + '/../lib/msg');

var client = {
    name: "fcm",
    priority: 10,
    agents: {},
};
module.exports = client;

msg.modules.push(client);

client.check = function(dev)
{
    return dev.service == "fcm" || (dev.service == "gcm" && this.agents.default && this.agents.default.gcm);
}

// Initialize Google Cloud Messaging service to send push notifications to mobile devices
client.init = function(options)
{
    var self = this;
    var config = msg.getConfig(this.name);
    for (var i in config) {
        if (this.agents[config[i]._app]) continue;
        this.agents[config[i]._app] = lib.objClone(config[i], "_sent", 0, "_queue", 0);
        logger.info("init:", "fcm", lib.objDescr(config[i]));
    }
}

// Close GCM connection, flush the queue
client.close = function(callback)
{
    var self = this;
    lib.forEach(Object.keys(this.agents), function(key, next) {
        var agent = self.agents[key];
        delete self.agents[key];
        logger.info('close:', "fcm", key, 'queue:', agent._queue, 'sent:', agent._sent);

        var n = 0;
        function check() {
            if (!agent._queue || ++n > 600) {
                logger.info('close:', "fcm", "done", key);
                next();
            } else {
                setTimeout(check, 50);
            }
        }
        check();
    }, callback);
}

// Send push notification to an Android device, return true if queued.
client.send = function(dev, options, callback)
{
    if (!dev || !dev.id) return typeof callback == "function" && callback(lib.newError("invalid device:" + dev.id));

    var agent = this.agents[dev.app] || this.agents.default;
    if (!agent) return typeof callback == "function" && callback(lib.newError("FCM is not initialized for " + dev.id, 415));

    agent._queue++;

    var msg = { data: {}, notification: {}, priority: options.priority || "high" };
    msg[dev.id.indexOf(",") > -1 ? "registration_ids" : "to"] = dev.id;
    if (options.name) msg.collapse_key = options.name;
    if (options.ttl) msg.time_to_live = lib.toNumber(options.ttl);
    if (options.delay) msg.delay_while_idle = lib.toBool(options.delay);

    if (options.title) msg.notification.title = String(title);
    if (options.msg) msg.notification.body = String(options.msg);
    if (options.sound) msg.notification.sound = typeof options.sound == "string" ? options.sound : "default";
    if (options.icon) msg.notification.icon = String(options.icon);
    if (options.tag) msg.notification.tag = String(options.tag);
    if (options.color) msg.notification.color = String(options.color);
    if (options.clickAction) msg.notification.click_action = String(options.clickAction);
    if (options.titleLocKey) msg.notification.title_loc_key = String(options.titleLocKey);
    if (options.titleLocArgs) msg.notification.title_loc_args = String(options.titleLocArgs);
    if (options.bodyLocKey) msg.notification.body_loc_key = String(options.bodyLocKey);
    if (options.bodyLocArgs) msg.notification.body_loc_args = String(options.bodyLocArgs);

    if (options.id) msg.data.id = String(options.id);
    if (options.url) msg.data.url = String(options.url);
    if (options.type) msg.data.type = String(options.type);
    if (options.badge) msg.data.badge = lib.toBool(options.badge);
    if (options.vibrate) msg.data.vibrate = lib.toBool(options.vibrate);
    if (options.account_id) msg.data.account_id = options.account_id;
    for (var p in options.payload) msg.data[p] = options.payload[p];

    var opts = {
        method: 'POST',
        headers: { 'Authorization': 'key=' + agent._key },
        postdata: msg,
        retryCount: agent.retryCount || this.retryCount || 3,
        retryTimeout: agent.retryTimeout || this.retryTimeout || 1000,
        retryOnError: client.retryOnError,
    };
    core.httpGet('https://fcm.googleapis.com/fcm/send', opts, function(err, params) {
        if (!err && params.status >= 400) err = lib.newError(params.status + ": " + params.data, params.status);
        if (err) logger.error("send:", "fcm", agent._app, dev, err, msg);
        agent._queue--;
        agent._sent++;
        if (typeof callback == "function") callback(err);
    });
    return true;
}

// Retry on server error, honor Retry-After header if present, use it only on the first error
client.retryOnError = function()
{
    if (this.status < 500) return 0;
    if (!this.retryAfter) {
        this.retryAfter = lib.toNumber(this.headers['retry-after']) * 1000;
        if (this.retryAfter > 0 && this.retryCount > 0) this.retryTimeout = this.retryAfter/2;
    }
    return 1;
}
<|endoftext|>


<commit_before>var path = require('path');

/**
 * Diffing tool instance
 *
 * @type {Differ}
 * @const
 */
var DEFAULT_DIFFER = require('./adapters/looks-same.js');

/**
 * Module for file system interaction
 *
 * @type {FS}
 * @const
 */
var DEFAULT_FS = require('./adapters/fs.js');

/**
 * Module for PNG manipulation
 *
 * @type {PNGProcessor}
 * @const
 */
var DEFAULT_PNGPROCESSOR = require('./adapters/png-crop.js');

/**
 * Root directory of the screenshots
 *
 * @type {String}
 * @const
 * @default
 */
var DEFAULT_ROOT_DIRECTORY = 'visual-tests';

/**
 * File extension for images
 *
 * @type {String}
 * @const
 * @default
 */
var IMAGE_EXTENSION = '.png';

/**
 * Name extension for baseline image
 *
 * @type {String}
 * @const
 * @default
 */
var BASELINE_NAME = '';

/**
 * Name extension for screenshot
 *
 * @type {String}
 * @const
 * @default
 */
var SCREENSHOT_NAME = '.new';

/**
 * Name extension for diff image
 *
 * @type {String}
 * @const
 * @default
 */
var DIFF_NAME = '.diff';

/**
 * @param {Browser} browser - Instance of some browser
 * @param {Object} [options]
 * @param {Differ} [options.differ] - A diffing tool instance
 * @param {FS} [options.fs] - A module to interact with the file system
 * @param {String} [options.rootDirectory='visual-tests'] - The directory
 *     where the screenshots will be saved
 * @constructor
 */
function Mugshot(browser, options) {
  if (browser === undefined) {
    throw new Error('No browser instance was provided');
  }

  this._browser = browser;

  if (options !== undefined &&
      (typeof options !== 'object' || options instanceof Array)) {
    throw new Error('options is not an obejct');
  }

  options = options || {};
  this._options = {};

  this._options.differ = options.differ || DEFAULT_DIFFER;
  this._options.fs = options.fs || DEFAULT_FS;
  this._options.PNGProcessor = options.PNGProcessor || DEFAULT_PNGPROCESSOR;
  this._options.rootDirectory = options.rootDirectory || DEFAULT_ROOT_DIRECTORY;
}

/**
 * @param {Object} captureItem - Details about what will be captured
 * @param {String} [captureItem.selector] - A html or css selector
 * @param {String} captureItem.name - A name for the screenshot without any
 *    extension
 * @param {testCb} callback
 */
Mugshot.prototype.test = function(captureItem, callback) {
  var fs = this._options.fs,
      browser = this._browser,
      options = this._options;

  if (captureItem === undefined) {
    throw new Error('You have not provided any selector');
  }

  if (callback === undefined || typeof callback !== 'function') {
    throw new Error('You have not provided a callback');
  }

  if (typeof captureItem !== 'object' || captureItem instanceof Array) {
    throw new Error('The provided selector is not an object');
  }

  if (captureItem.name === undefined) {
    throw new Error('Your object has no \'name\' property');
  }

  fs.mkdir(this._options.rootDirectory, function(error) {
    if (error && error.code !== 'EEXIST') {
      return callback(error);
    }

    browser.takeScreenshot(function(error, screenshot) {
      if (error) {
        return callback(error);
      }

      _processScreenshot(captureItem, browser, options, screenshot, callback);
    });
  });
};

/**
 * @callback testCb
 * @param error
 * @param {Boolean} result
 * /

/**
 * Writes the screenshot and the diff on disk
 *
 * @param {FS} fs - File system adaptor instance
 * @param {Object} paths - Contains the path of the screenshot and diff on disk
 * @param {String} paths.screenshotPath
 * @param {String} paths.diffPath
 * @param {Object} data - Contains the binary representation of the screenshot
 *    and the diff
 * @param {Buffer} data.screenshot
 * @param {Buffer} data.diff
 * @param {testCb} done - Called when all operations have finished
 */
function _writeScreenshotAndDiff(fs, paths, data, done) {
  fs.writeFile(paths.screenshotPath, data.screenshot, function(error) {
    if (error) {
      return done(error);
    }

    fs.writeFile(paths.diffPath, data.diff, function(error) {
      if (error) {
        return done(error);
      }

      done(null, false);
    });
  });
}

/**
 * Unlinks from disk the screenshot and the diff image from a previous run
 *
 * @param {FS} fs - File system adaptor instance
 * @param {String} screenshotPath - The path of the screenshot on disk
 * @param {String} diffPath - The path of the diff image on disk
 * @param {testCb} done - Called when all operations have finished
 */
function _unlinkScreenshotAndDiff(fs, screenshotPath, diffPath, done) {
  fs.unlink(screenshotPath, function(error) {
    if (error && error.code !== 'ENOENT') {
      return done(error);
    }

    fs.unlink(diffPath, function(error) {
      if (error && error.code !== 'ENOENT') {
        return done(error);
      }

      done(null, true);
    });
  });
}

/**
 * Process the screenshot before testing
 *
 * @param captureItem - Same as in test method
 * @param {Browser} browser - A browser adaptor instance
 * @param {Object} options - Same as in test method
 * @param {Buffer} screenshot - A binary representation of the whole web page
 * @param {testCb} done - Called when all operations have finished
 */
function _processScreenshot(captureItem, browser, options, screenshot, done) {
  var PNGProcessor = options.PNGProcessor;

  if (captureItem.selector === undefined) {
    _test(captureItem.name, options, screenshot, done);
  } else {
    browser.getBoundingClientRect(captureItem.selector, function(error, rect) {
      if (error) {
        return done(error);
      }

      PNGProcessor.crop(screenshot, rect, function(error, croppedImage) {
        if (error) {
          return done(error);
        }

        _test(captureItem.name, options, croppedImage, done);
      });
    });
  }
}

/**
 * Actually does the testing
 *
 * @param {Object} options - Same as in test processScreenshot method
 * @param {Buffer} screenshot - Binary representation of the screenshot
 * @param {testCb} done - Called when all operations have finished
 */
function _test(baseName, options, screenshot, done) {
  options.getPath = composeImagePath(options.rootDirectory, baseName);

  var fs = options.fs,
      baselinePath = options.getPath(BASELINE_NAME);

  fs.exists(baselinePath, function(exists) {
    if (exists) {
      fs.readFile(baselinePath, function(error, baseline) {
        if (error) {
          return done(error);
        }

        _diffImages(options, baseline, screenshot, done);
      });
    } else {
      fs.writeFile(baselinePath, screenshot, function(error) {
        if (error) {
          return done(error);
        }

        done(null, true);
      });
    }
  });
}

/**
 * Compare the images and if there are differences writes the screenshot and the
 * diff on disk
 *
 * @param {Object} options - Same as in _test method
 * @param {Buffer} baseline - The binary representation of the baseline
 * @param {Buffer} screenshot - The binary representation of the screenshot
 * @param {testCb} done - Called when all operations have finished
 */
function _diffImages(options, baseline, screenshot, done) {
  var differ = options.differ,
      screenshotPath = options.getPath(SCREENSHOT_NAME),
      diffPath = options.getPath(DIFF_NAME);

  differ.isEqual(baseline, screenshot, function(error, equal) {
    if (error) {
      return done(error);
    }

    if (equal) {
      _unlinkScreenshotAndDiff(options.fs, screenshotPath, diffPath, done);
    } else {
      differ.createDiff(baseline, screenshot, function(error, diff) {
        if (error) {
          return done(error);
        }

        var paths = {
          screenshotPath: screenshotPath,
          diffPath: diffPath
        };

        var data = {
          screenshot: screenshot,
          diff: diff
        };

        _writeScreenshotAndDiff(options.fs, paths, data, done);
      });
    }
  });
}

/**
* Builds the path of an image on disk
*
* @param {String} rootDirectory - Root directory of the screenshots
* @param {String} baseName - A name for the screenshot without extension
*
* @returns {Function} - Actually returns the path of the image
*/
function composeImagePath(rootDirectory, baseName) {
  /**
  * @param {String} - An extension to give more info about the image
  *
  * @returns {String} The path on the disk
  */
  return function(extensionName) {
    var name = baseName + extensionName + IMAGE_EXTENSION;

    return path.join(rootDirectory, name);
  }
}

module.exports = Mugshot;
<commit_msg>fix LooksSameAdapter instantiation<commit_after>var path = require('path');
var LooksSameAdapter = require('./adapters/looks-same.js');

/**
 * Diffing tool instance
 *
 * @type {Differ}
 * @const
 */
var DEFAULT_DIFFER = new LooksSameAdapter();

/**
 * Module for file system interaction
 *
 * @type {FS}
 * @const
 */
var DEFAULT_FS = require('./adapters/fs.js');

/**
 * Module for PNG manipulation
 *
 * @type {PNGProcessor}
 * @const
 */
var DEFAULT_PNGPROCESSOR = require('./adapters/png-crop.js');

/**
 * Root directory of the screenshots
 *
 * @type {String}
 * @const
 * @default
 */
var DEFAULT_ROOT_DIRECTORY = 'visual-tests';

/**
 * File extension for images
 *
 * @type {String}
 * @const
 * @default
 */
var IMAGE_EXTENSION = '.png';

/**
 * Name extension for baseline image
 *
 * @type {String}
 * @const
 * @default
 */
var BASELINE_NAME = '';

/**
 * Name extension for screenshot
 *
 * @type {String}
 * @const
 * @default
 */
var SCREENSHOT_NAME = '.new';

/**
 * Name extension for diff image
 *
 * @type {String}
 * @const
 * @default
 */
var DIFF_NAME = '.diff';

/**
 * @param {Browser} browser - Instance of some browser
 * @param {Object} [options]
 * @param {Differ} [options.differ] - A diffing tool instance
 * @param {FS} [options.fs] - A module to interact with the file system
 * @param {String} [options.rootDirectory='visual-tests'] - The directory
 *     where the screenshots will be saved
 * @constructor
 */
function Mugshot(browser, options) {
  if (browser === undefined) {
    throw new Error('No browser instance was provided');
  }

  this._browser = browser;

  if (options !== undefined &&
      (typeof options !== 'object' || options instanceof Array)) {
    throw new Error('options is not an obejct');
  }

  options = options || {};
  this._options = {};

  this._options.differ = options.differ || DEFAULT_DIFFER;
  this._options.fs = options.fs || DEFAULT_FS;
  this._options.PNGProcessor = options.PNGProcessor || DEFAULT_PNGPROCESSOR;
  this._options.rootDirectory = options.rootDirectory || DEFAULT_ROOT_DIRECTORY;
}

/**
 * @param {Object} captureItem - Details about what will be captured
 * @param {String} [captureItem.selector] - A html or css selector
 * @param {String} captureItem.name - A name for the screenshot without any
 *    extension
 * @param {testCb} callback
 */
Mugshot.prototype.test = function(captureItem, callback) {
  var fs = this._options.fs,
      browser = this._browser,
      options = this._options;

  if (captureItem === undefined) {
    throw new Error('You have not provided any selector');
  }

  if (callback === undefined || typeof callback !== 'function') {
    throw new Error('You have not provided a callback');
  }

  if (typeof captureItem !== 'object' || captureItem instanceof Array) {
    throw new Error('The provided selector is not an object');
  }

  if (captureItem.name === undefined) {
    throw new Error('Your object has no \'name\' property');
  }

  fs.mkdir(this._options.rootDirectory, function(error) {
    if (error && error.code !== 'EEXIST') {
      return callback(error);
    }

    browser.takeScreenshot(function(error, screenshot) {
      if (error) {
        return callback(error);
      }

      _processScreenshot(captureItem, browser, options, screenshot, callback);
    });
  });
};

/**
 * @callback testCb
 * @param error
 * @param {Boolean} result
 * /

/**
 * Writes the screenshot and the diff on disk
 *
 * @param {FS} fs - File system adaptor instance
 * @param {Object} paths - Contains the path of the screenshot and diff on disk
 * @param {String} paths.screenshotPath
 * @param {String} paths.diffPath
 * @param {Object} data - Contains the binary representation of the screenshot
 *    and the diff
 * @param {Buffer} data.screenshot
 * @param {Buffer} data.diff
 * @param {testCb} done - Called when all operations have finished
 */
function _writeScreenshotAndDiff(fs, paths, data, done) {
  fs.writeFile(paths.screenshotPath, data.screenshot, function(error) {
    if (error) {
      return done(error);
    }

    fs.writeFile(paths.diffPath, data.diff, function(error) {
      if (error) {
        return done(error);
      }

      done(null, false);
    });
  });
}

/**
 * Unlinks from disk the screenshot and the diff image from a previous run
 *
 * @param {FS} fs - File system adaptor instance
 * @param {String} screenshotPath - The path of the screenshot on disk
 * @param {String} diffPath - The path of the diff image on disk
 * @param {testCb} done - Called when all operations have finished
 */
function _unlinkScreenshotAndDiff(fs, screenshotPath, diffPath, done) {
  fs.unlink(screenshotPath, function(error) {
    if (error && error.code !== 'ENOENT') {
      return done(error);
    }

    fs.unlink(diffPath, function(error) {
      if (error && error.code !== 'ENOENT') {
        return done(error);
      }

      done(null, true);
    });
  });
}

/**
 * Process the screenshot before testing
 *
 * @param captureItem - Same as in test method
 * @param {Browser} browser - A browser adaptor instance
 * @param {Object} options - Same as in test method
 * @param {Buffer} screenshot - A binary representation of the whole web page
 * @param {testCb} done - Called when all operations have finished
 */
function _processScreenshot(captureItem, browser, options, screenshot, done) {
  var PNGProcessor = options.PNGProcessor;

  if (captureItem.selector === undefined) {
    _test(captureItem.name, options, screenshot, done);
  } else {
    browser.getBoundingClientRect(captureItem.selector, function(error, rect) {
      if (error) {
        return done(error);
      }

      PNGProcessor.crop(screenshot, rect, function(error, croppedImage) {
        if (error) {
          return done(error);
        }

        _test(captureItem.name, options, croppedImage, done);
      });
    });
  }
}

/**
 * Actually does the testing
 *
 * @param {Object} options - Same as in test processScreenshot method
 * @param {Buffer} screenshot - Binary representation of the screenshot
 * @param {testCb} done - Called when all operations have finished
 */
function _test(baseName, options, screenshot, done) {
  options.getPath = composeImagePath(options.rootDirectory, baseName);

  var fs = options.fs,
      baselinePath = options.getPath(BASELINE_NAME);

  fs.exists(baselinePath, function(exists) {
    if (exists) {
      fs.readFile(baselinePath, function(error, baseline) {
        if (error) {
          return done(error);
        }

        _diffImages(options, baseline, screenshot, done);
      });
    } else {
      fs.writeFile(baselinePath, screenshot, function(error) {
        if (error) {
          return done(error);
        }

        done(null, true);
      });
    }
  });
}

/**
 * Compare the images and if there are differences writes the screenshot and the
 * diff on disk
 *
 * @param {Object} options - Same as in _test method
 * @param {Buffer} baseline - The binary representation of the baseline
 * @param {Buffer} screenshot - The binary representation of the screenshot
 * @param {testCb} done - Called when all operations have finished
 */
function _diffImages(options, baseline, screenshot, done) {
  var differ = options.differ,
      screenshotPath = options.getPath(SCREENSHOT_NAME),
      diffPath = options.getPath(DIFF_NAME);

  differ.isEqual(baseline, screenshot, function(error, equal) {
    if (error) {
      return done(error);
    }

    if (equal) {
      _unlinkScreenshotAndDiff(options.fs, screenshotPath, diffPath, done);
    } else {
      differ.createDiff(baseline, screenshot, function(error, diff) {
        if (error) {
          return done(error);
        }

        var paths = {
          screenshotPath: screenshotPath,
          diffPath: diffPath
        };

        var data = {
          screenshot: screenshot,
          diff: diff
        };

        _writeScreenshotAndDiff(options.fs, paths, data, done);
      });
    }
  });
}

/**
* Builds the path of an image on disk
*
* @param {String} rootDirectory - Root directory of the screenshots
* @param {String} baseName - A name for the screenshot without extension
*
* @returns {Function} - Actually returns the path of the image
*/
function composeImagePath(rootDirectory, baseName) {
  /**
  * @param {String} - An extension to give more info about the image
  *
  * @returns {String} The path on the disk
  */
  return function(extensionName) {
    var name = baseName + extensionName + IMAGE_EXTENSION;

    return path.join(rootDirectory, name);
  }
}

module.exports = Mugshot;
<|endoftext|>


<commit_before>/* A JS library for dealing with n-dimensional arrays.
 * Referenced from numpy.
 * Author : Anubhav Tiwari <atworkstudios@gmail.com>
 */

const core = require('./core');

class ndarray {
    constructor(shape = [], arr = [], dtype = 'uint8') {
        this.array = arr.length === 0 ? core.arrange(shape) : arr;
        this.shape = ((shape.length) > 0) ? shape : (core.calc_shape(this.array));
        this.size = core.calc_size(this.array);
        this.dim = core.find_dim(this.array);
        this.dtype = dtype;
        this.flat = core.form_arr(core.flatten(this.array), this.dtype);
    }

    /* class specific (static) methods */
    /* form a new ndarray for the given array */
    static array(arr) {
        return new ndarray([], arr);
    }

    /* make a new zero ndarray */
    static zeroes(shape) {
        let base_arr = core.fill(shape[shape.length - 1], "linear", 0);
        let arr = shape.length < 2 ? base_arr : [];
        for (let i = shape.length - 2; i >= 0; i--) {
            arr = [];
            for (let j = 0; j < shape[i]; j++) {
                arr.push(base_arr);
            }
            base_arr = arr;
        }
        return new ndarray(shape, arr);
    }

    /* -------------------------------------------------------------------------------------------------------------------------------------------- */

    /* object specific (property) methods */

    /* sum of 2 ndarrays */
    add(v2) {
        if (this.shape.toString() === v2.shape.toString()) {
            let sum = [];
            for (let i = 0; i < v1.flat.length; i++) {
                sum[i] = this.flat[i] + v2.flat[i];
            }
            this.arrange(sum);
        } else {
            return new Error("Unequal Size");
        }
    }

    /* reshapes the ndarray only if for the new shape the number of elements remain same */
    reshape(new_shape) {
        if (core.calc_size(new_shape, 'shape') === this.size) {
            /* reshape */
            const temp_arr = this.flat;
            this.shape = new_shape;
            this.arrange(temp_arr);
        } else {
            return new Error("Resizing error : can't change the size");
        }
    }

    /* changes the shape and size of the ndarray in place */
    resize(new_shape) {
        const temp_arr = this.flat;
        this.shape = new_shape;
        this.size = core.calc_size(new_shape);
        this.arrange(temp_arr);
    }

    arrange(elems_arr) {
        this.array = core.arrange(this.shape, elems_arr);
        this.flatten();
        this.size = core.calc_size(this.array);
        this.shape = core.calc_shape(this.array);
        this.dim = core.find_dim(this.array);
    }

    clip(min_val, max_val) {
        this.arrange(core.clip(this.array, min_val, max_val));
    }

    flatten() {
        this.flat = core.form_arr(core.flatten(this.array), this.dtype);
    }

    transpose() {
        return core.transpose(this.array, this.dtype);
    }

}

module.exports = ndarray;<commit_msg>fixing by testing with jb<commit_after>/* A JS library for dealing with n-dimensional arrays.
 * Referenced from numpy.
 * Author : Anubhav Tiwari <atworkstudios@gmail.com>
 */

const core = require('./core');

class ndarray {
    constructor(shape = [], arr = [], dtype = 'uint8') {
        this.array = arr.length === 0 ? core.arrange(shape) : arr;
        this.shape = ((shape.length) > 0) ? shape : (core.calc_shape(this.array));
        this.size = core.calc_size(this.array);
        this.dim = core.find_dim(this.array);
        this.dtype = dtype;
        this.flat = core.form_arr(core.flatten(this.array), this.dtype);
    }

    /* class specific (static) methods */
    /* form a new ndarray for the given array */
    static array(arr) {
        return new ndarray([], arr);
    }

    /* make a new zero ndarray */
    static zeroes(shape) {
        let base_arr = core.fill(shape[shape.length - 1], "linear", 0);
        let arr = shape.length < 2 ? base_arr : [];
        for (let i = shape.length - 2; i >= 0; i--) {
            arr = [];
            for (let j = 0; j < shape[i]; j++) {
                arr.push(base_arr);
            }
            base_arr = arr;
        }
        return new ndarray(shape, arr);
    }

    /* -------------------------------------------------------------------------------------------------------------------------------------------- */

    /* object specific (property) methods */

    /* sum of 2 ndarrays */
    add(v2) {
        if (this.shape.toString() === v2.shape.toString()) {
            let sum = [];
            for (let i = 0; i < this.flat.length; i++) {
                sum[i] = this.flat[i] + v2.flat[i];
            }
            this.arrange(sum);
        } else {
            return new Error("Unequal Size");
        }
    }

    /* reshapes the ndarray only if for the new shape the number of elements remain same */
    reshape(new_shape) {
        if (core.calc_size(new_shape, 'shape') === this.size) {
            /* reshape */
            const temp_arr = this.flat;
            this.shape = new_shape;
            this.arrange(temp_arr);
        } else {
            return new Error("Resizing error : can't change the size");
        }
    }

    /* changes the shape and size of the ndarray in place */
    resize(new_shape) {
        const temp_arr = this.flat;
        this.shape = new_shape;
        this.size = core.calc_size(new_shape);
        this.arrange(temp_arr);
    }

    arrange(elems_arr) {
        this.array = core.arrange(this.shape, elems_arr);
        this.flatten();
        this.size = core.calc_size(this.array);
        this.shape = core.calc_shape(this.array);
        this.dim = core.find_dim(this.array);
    }

    clip(min_val, max_val) {
        this.arrange(core.clip(this.array, min_val, max_val));
    }

    flatten() {
        this.flat = core.form_arr(core.flatten(this.array), this.dtype);
    }

    transpose() {
        return core.transpose(this.array, this.dtype);
    }

}

module.exports = ndarray;<|endoftext|>


<commit_before>var dns = require('dns')
  , util = require('util')
  , utils = require('./utils')

var exports = module.exports = function(authority) {
  if (authority !== undefined) throw Error('Authority not implemented')

  return {
    a: testType(authority, 'a'),
    aaaa: testType(authority, 'aaaa'),
    cname: testType(authority, 'cname'),
    mx: testType(authority, 'mx'),
    ns: testType(authority, 'ns'),
    ptr: testType(authority, 'ptr'),
    srv: testType(authority, 'srv'),
    txt: testType(authority, 'txt'),
  }
}

var asserts = exports.asserts = {
  address: function(res, address) {
    this.ok(typeof(res) === 'object' &&
      (res.type == 'a' || res.type == 'aaaa') &&
      Array.isArray(res.answer) && res.answer.length > 0 &&
      res.answer.indexOf(address) >= 0,
      'Address "' + address + '" in ' + JSON.stringify(res.answer))
  },
  name: function(res, name) {
    this.ok(typeof(res) === 'object' &&
      (res.type == 'cname' || res.type == 'ns' || res.type == 'ptr') &&
      Array.isArray(res.answer) && res.answer.length > 0 &&
      res.answer.indexOf(name) >= 0, 'Name "' + name + '" in ' + JSON.stringify(res.answer))
  },
}

var testType = function(authority, type) {
  return function() {
    var baseArgs = Array.prototype.slice.call(arguments)
      , baseUri = 'dns:' + (authority !== undefined ? '//' + authority + '/' : '')
      , name = [baseUri + baseArgs[0] + '?type=' + type].join(utils.SEP)

    // add test to module
    return function(test) {
      var args = Array.prototype.slice.call(baseArgs)
      args.unshift(authority)
      args.unshift(type)
      args.unshift(test)
      exports.resolve.apply(this, args)
    }
  }
}

exports.resolve = function(/* test, type, authority, domain, [opts], callback */) {
  var test = arguments[0]
    , type = arguments[1]
    , authority = arguments[2]
    , domain = arguments[3]
    , opts = {}
    , callback = null

  if (arguments.length == 6) {
    opts = arguments[4]
    callback = arguments[5]
  } else {
    callback = arguments[4]
  }

  for (var a in asserts) {
    if (!test.hasOwnProperty(a)) test[a] = asserts[a]
  }

  dns.resolve(domain, type.toUpperCase(), function(err, answer) {
    if (err) {
      test.ok(false, err)
      return test.done()
    }
    callback(test, { answer: answer, type: type })
  })
}
<commit_msg>Convert dns to opts based parameters<commit_after>var dns = require('dns')
  , util = require('util')
  , utils = require('./utils')

var exports = module.exports = function(opts) {
  if (opts === undefined) {
    opts = {}
  } else if (typeof(opts) === 'string') {
    opts = opts = { authority: opts }
  }
  if (opts.authority !== undefined) throw Error('Authority not implemented')

  return {
    a: testType(opts, 'a'),
    aaaa: testType(opts, 'aaaa'),
    cname: testType(opts, 'cname'),
    mx: testType(opts, 'mx'),
    ns: testType(opts, 'ns'),
    ptr: testType(opts, 'ptr'),
    srv: testType(opts, 'srv'),
    txt: testType(opts, 'txt'),
  }
}

var asserts = exports.asserts = {
  address: function(res, address) {
    this.ok(typeof(res) === 'object' &&
      (res.type == 'a' || res.type == 'aaaa') &&
      Array.isArray(res.answer) && res.answer.length > 0 &&
      res.answer.indexOf(address) >= 0,
      'Address "' + address + '" in ' + JSON.stringify(res.answer))
  },
  name: function(res, name) {
    this.ok(typeof(res) === 'object' &&
      (res.type == 'cname' || res.type == 'ns' || res.type == 'ptr') &&
      Array.isArray(res.answer) && res.answer.length > 0 &&
      res.answer.indexOf(name) >= 0, 'Name "' + name + '" in ' + JSON.stringify(res.answer))
  },
}

var testType = function(parentOpts, type) {
  return function(opts, callback) {
    if (typeof(opts) === 'string') opts = { domain: opts }
    opts.type = type
    opts.uri = 'dns:' +
      (opts.authority !== undefined ? '//' + opts.authority + '/' : '') +
      opts.domain + '?type=' + type

    // add test to module
    return function(test) {
      exports.resolve(test, opts, callback)
    }
  }
}

exports.resolve = function(test, opts, callback) {
  for (var a in asserts) {
    if (!test.hasOwnProperty(a)) test[a] = asserts[a]
  }

  dns.resolve(opts.domain, opts.type.toUpperCase(), function(err, answer) {
    if (err) {
      test.ok(false, err)
      return test.done()
    }
    callback(test, { answer: answer, type: opts.type })
  })
}
<|endoftext|>