<commit_before>var rewire = require('rewire'),
    moment = require('moment'),
    chai = require('chai'),
    sinon = require('sinon'),
    sinonChai = require('sinon-chai'),
    expect = chai.expect,
    metrics = rewire('../../lib/metrics');

chai.use(sinonChai);

describe('Metrics', function() {
    describe('.add()', function() {
        context('when newrelic license key is set', function() {
            var event = 'run',
                callback, newCallback, revertFakeLicenseKey, revertNewRelic;

            beforeEach(function() {
                useFakeLicenseKey();
                callback = sinon.stub();
            });

            afterEach(function() {
                revertFakeLicenseKey();
            });

            it('returns a different callback than the original one', function() {
                newCallback = metrics.add(event, callback);

                expect(newCallback).not.to.equal(callback);
            });

            it('returns a callback encapsulating the original one', function() {
                var data = 'test';

                newCallback = metrics.add(event, callback);

                // We must first verify that we are not getting the original one.
                if (newCallback !== callback)
                    newCallback(data);

                expect(callback).to.have.been.calledWith(data);
            });

            it('creates a newrelic web transaction with event specified', function() {
                fakeNewRelic = { createWebTransaction: sinon.stub() };

                useFakeNewRelic();

                newCallback = metrics.add(event, callback);

                expect(fakeNewRelic.createWebTransaction).to.have.been
                    .calledWith(event);

                revertNewRelic();
            });

            it('ends newrelic web transaction after callback', function() {
                fakeNewRelic = { createWebTransaction: function(event, callback) {
                    callback();
                }, endTransaction: sinon.stub() };

                useFakeNewRelic();

                newCallback = metrics.add(event, callback);

                expect(fakeNewRelic.endTransaction).to.have.been
                    .calledAfter(callback);

                revertNewRelic();
            });

            // Hopefully, newrelics module doesn't fail with
            // a fake license key, this is very convenient to have
            // this test working in multiple environments.
            function useFakeLicenseKey() {
                var envVar = 'process.env.NEW_RELIC_LICENSE_KEY';

                revertFakeLicenseKey = metrics.__set__(envVar, '42');
            }

            function useFakeNewRelic() {
                revertNewRelic = metrics.__set__('getNewRelic', function() {
                    return fakeNewRelic;
                });
            }
        });

        context('without newrelic license key', function() {
            var event = 'test',
                callback, newCallback;

            beforeEach(function() {
                callback = function() {};
                newCallback = metrics.add(event, callback);
            });

            it('returns the original callback', function() {
                expect(newCallback).to.equal(callback);
            });
        });
    });
});
<commit_msg>remove useless beforeEach<commit_after>var rewire = require('rewire'),
    moment = require('moment'),
    chai = require('chai'),
    sinon = require('sinon'),
    sinonChai = require('sinon-chai'),
    expect = chai.expect,
    metrics = rewire('../../lib/metrics');

chai.use(sinonChai);

describe('Metrics', function() {
    describe('.add()', function() {
        context('when newrelic license key is set', function() {
            var event = 'run',
                callback, newCallback, revertFakeLicenseKey, revertNewRelic;

            beforeEach(function() {
                useFakeLicenseKey();
                callback = sinon.stub();
            });

            afterEach(function() {
                revertFakeLicenseKey();
            });

            it('returns a different callback than the original one', function() {
                newCallback = metrics.add(event, callback);

                expect(newCallback).not.to.equal(callback);
            });

            it('returns a callback encapsulating the original one', function() {
                var data = 'test';

                newCallback = metrics.add(event, callback);

                // We must first verify that we are not getting the original one.
                if (newCallback !== callback)
                    newCallback(data);

                expect(callback).to.have.been.calledWith(data);
            });

            it('creates a newrelic web transaction with event specified', function() {
                fakeNewRelic = { createWebTransaction: sinon.stub() };

                useFakeNewRelic();

                newCallback = metrics.add(event, callback);

                expect(fakeNewRelic.createWebTransaction).to.have.been
                    .calledWith(event);

                revertNewRelic();
            });

            it('ends newrelic web transaction after callback', function() {
                fakeNewRelic = { createWebTransaction: function(event, callback) {
                    callback();
                }, endTransaction: sinon.stub() };

                useFakeNewRelic();

                newCallback = metrics.add(event, callback);

                expect(fakeNewRelic.endTransaction).to.have.been
                    .calledAfter(callback);

                revertNewRelic();
            });

            // Hopefully, newrelics module doesn't fail with
            // a fake license key, this is very convenient to have
            // this test working in multiple environments.
            function useFakeLicenseKey() {
                var envVar = 'process.env.NEW_RELIC_LICENSE_KEY';

                revertFakeLicenseKey = metrics.__set__(envVar, '42');
            }

            function useFakeNewRelic() {
                revertNewRelic = metrics.__set__('getNewRelic', function() {
                    return fakeNewRelic;
                });
            }
        });

        context('without newrelic license key', function() {
            var event       = 'test',
                callback    = function() {};
                newCallback = metrics.add(event, callback);

            it('returns the original callback', function() {
                expect(newCallback).to.equal(callback);
            });
        });
    });
});
<|endoftext|>


<commit_before>$(function () {
	var cnv = $('canvas'), img = $('#img'), svg = $('svg');
	var w = svg.width(), h = svg.height();
	cnv.attr({width: w, height: h});
	var ctx = cnv[0].getContext('2d');
	ctx.fillStyle ='#fff';
	ctx.fillRect(0, 0, w, h);
	ctx.drawImage(img[0], 0, 0, w, h);
	let url = cnv[0].toDataURL('image/png');
	$('#export').attr('href', 'command:uiflow.saveImage?' +encodeURIComponent(JSON.stringify(url)));
});
<commit_msg>refactor index.js<commit_after>$(() => {
	let cnv = $('canvas'), img = $('#img'), svg = $('svg');
	let w = svg.width(), h = svg.height();
	cnv.attr({width: w, height: h});
	let ctx = cnv[0].getContext('2d');
	ctx.fillStyle ='#fff';
	ctx.fillRect(0, 0, w, h);
	ctx.drawImage(img[0], 0, 0, w, h);
	let url = cnv[0].toDataURL('image/png');
	$('#export').attr('href', 'command:uiflow.saveImage?' +encodeURIComponent(JSON.stringify(url)));
});
<|endoftext|>


<commit_before>var players = [];
var guardians = [];
var frogStatus = 0;
var kingStrength = 100; //can use this to extrapolate enemy strength.
var queenStrength = 100;
var jackStrength = 50;
var hardStrength = 250;  //what consititutes a  'hard' game.
var democracyStrength = 0;
var queenUncrowned = false;  //if she loses her ring, she doesn't get stronger with further prototypes
var reckoningStarted = false; //can't god tier if you are definitely on skaia.
var ectoBiologyStarted = false;
var doomedTimeline = false;
var scratched = false;
var debugMode = false;
var introScene;
var currentSceneNum = 0;
var spriteWidth = 400;
var spriteHeight = 300;
var canvasWidth = 1000;
var canvasHeight = 300;
var repeatTime = 500;
var version2 = true;
var timeTillReckoning = getRandomInt(10,30);
//have EVERYTHING be a scene, don't put any story in v2.0's controller
//every scene can update the narration, or the canvas.
//should there be only one canvas?  Can have player sprites be written to a virtual canvas first, then copied to main one.
//main canvas is either Leader + PesterChumWindow + 1 or more Players (in chat or group chat with leader)
//or Leader + 1 or more Players  (leader doing bullshit side quests with someone)
window.onload = function() {
	debug("after 3.0, definitely add a new html page where you can create characters and then run a sim with them. ")
	debug("if i wanter rending to be more complex than just wait a second, make an object that keeps track of all parts of a rendering and only writes it to the canas when all are loaded");
	debug("why are quirk replacements sometimes all caps?seems to happen with unchanged capitilization. doesn't happen in replacement, definitely.")
	debug("sprite for Yx corpse smooch combo")
	debug("more varied romantic rejection convos");
	debug("speech bubble for converstion theme? jack/mayor/a player aspect?");
	debug("rainbow godtier be rendered behind regular godtier on revival. lets godtier outfit be seen. makes it look like an aura without having to do edge detection")
   init();

	if(!debugMode){
		randomizeEntryOrder();
	}
	//debugRoyalRumble();
	//authorMessage();
	makeGuardians(); //after entry order established

	intro();
	//debugRelationshipDrama();
	//debugTriggerLevel();
	//debugGrimDark();
	//debugJackScheme();
	//debugLevelTheHellUp();
	//debugGodTierLevelTheHellUp();
	//debugCorpseLevelTheHellUp();
	//debugGodTierRevive();
	//debugCorpseSmooch();

	//make a new intro scene that has characters talk about their lands with their best friends/worst enemies.
	//refacor other scenario controller to use special scenes (not part of scene controller) rather than
	//have messy internal methods.
	//all other scenes are handled through the scene controller like normal, which will check if var version2 = true;
	//and if so will call "render" rather than "content"
	debug("consider keeping track of async tasks in array. if too many at a time, put new async tasks in second array, only activate and add to first array when it is empty enough");

	debug("relationship text. reckoning");
	//tick();  dont tick here, tick after intro
}

function renderScratchButton(){
	//alert("scratch [possible]");
	//can't scratch if it was a a total party wipe. just a regular doomed timeline.
	var living = findLivingPlayers(players);
	if(living.length > 0){
		var timePlayer = findAspectPlayer(players, "Time");
		if(!scratched){
			alert(living.length  + " living players and the " + timePlayer.land + " makes a scratch available!");
			var html = '<button type="button" onclick="scratchConfirm()">Would You Like To Scratch Session?</button>';
			$("#story").append(html);
		}else{
			$("#story").append("
This session is already scratched. No further scratches available.");
		}
	}
}

function scratchConfirm(){
	var scratchConfirmed = confirm("This session is doomed. Scratching this session will erase it. A new session will be generated, but you will no longer be able to view this session. Is this okay?");
	if(scratchConfirmed){
		scratch();
	}
}

//TODO if i wanted to, I could have mixed sessions like in canon.
//not erasing the players, after all.
//or could have an afterlife where they meet guardian players???
function scratch(){
	timeTillReckoning = getRandomInt(10,30);
	frogStatus = 0;
	kingStrength = 100; //can use this to extrapolate enemy strength.
	queenStrength = 100;
	jackStrength = 50;
	hardStrength = 250;  //what consititutes a  'hard' game.
	democracyStrength = 0;
	queenUncrowned = false;  //if she loses her ring, she doesn't get stronger with further prototypes
	reckoningStarted = false; //can't god tier if you are definitely on skaia.
	//ectobiology not reset. if performed in previous session, it's done.
	//if not, it's not. like how the alpha session trolls didn't perform ectobiology, so Karkat did.
  doomedTimeline = false;
	scratched = true;
	var scratch = "The session has been scratched. The " + getPlayersTitlesBasic(players) + " will now be the beloved guardians.";
  scratch += " Their former guardians, the " + getPlayersTitlesBasic(guardians) + " will now be the players.";
	scratch += " The new players will be given stat boosts to give them a better chance than the previous generation."
	scratch += " What will happen?"
	var tmp = players;
	players = guardians;
	guardians = tmp;
	$("#story").html(scratch);
	window.scrollTo(0, 0);

	var guardianDiv = newScene();
	var guardianID = (guardianDiv.attr("id")) + "_guardians" ;
	var ch = canvasHeight;
	if(guardians.length > 6){
		ch = canvasHeight*1.5; //a little bigger than two rows, cause time clones
	}
	var canvasHTML = "
<canvas id='canvas" + guardianID+"' width='" +canvasWidth + "' height="+ch + "'>  </canvas>";

	guardianDiv.append(canvasHTML);
	var canvasDiv = document.getElementById("canvas"+ guardianID);
	poseAsATeam(canvasDiv, guardians, 2000); //everybody, even corpses, pose as a team.

	var playerDiv = newScene();
	var playerID = (playerDiv.attr("id")) + "_players" ;
	var ch = canvasHeight;
	if(players.length > 6){
		ch = canvasHeight*1.5; //a little bigger than two rows, cause time clones
	}
	var canvasHTML = "
<canvas id='canvas" + playerID+"' width='" +canvasWidth + "' height="+ch + "'>  </canvas>";

	playerDiv.append(canvasHTML);
	var canvasDiv = document.getElementById("canvas"+ playerID);
	poseAsATeam(canvasDiv, players, 2000); //everybody, even corpses, pose as a team.

	intro();

}

function tick(){
	if(timeTillReckoning > 0 && !doomedTimeline){
		setTimeout(function(){
			timeTillReckoning += -1;
			processScenes2(players);
			tick();
		},repeatTime); //or availablePlayers.length * *1000?
	}else{

		reckoning();
	}
}

function reckoning(){
	var s = new Reckoning();
	s.trigger(players)
	s.renderContent(newScene());
	if(!doomedTimeline){
		reckoningTick();
	}
}

function reckoningTick(){
	if(timeTillReckoning > -10){
		setTimeout(function(){
			timeTillReckoning += -1;
			processReckoning2(players)
			reckoningTick();
		},repeatTime);
	}else{
		var s = new Aftermath();
		s.trigger(players)
		s.renderContent(newScene());
	}

}

//scenes call this
function chatLine(start, player, line){
  if(player.grimDark == true){
    return start + line.trim()+"\n"; //no whimsy for grim dark players
  }else{
    return start + player.quirk.translate(line).trim()+"\n";
  }
}

function newScene(){
	currentSceneNum ++;
	var div = "

";
	$("#story").append(div);
	return $("#scene"+currentSceneNum);
}

function authorMessage(){
	makeAuthorAvatar();
	introScene = new AuthorMessage();
	introScene.trigger(players, players[0])
	introScene.renderContent(newScene(),0); //new scenes take care of displaying on their own.
}

function callNextIntroWithDelay(player_index){
	if(player_index >= players.length){
    tick();//NOW start ticking
		return;
	}
	setTimeout(function(){
		var s = new Intro();
		var p = players[player_index];
		var playersInMedium = players.slice(0, player_index+1); //anybody past me isn't in the medium, yet.
		s.trigger(playersInMedium, p)
		s.renderContent(newScene(),player_index); //new scenes take care of displaying on their own.
		processScenes2(playersInMedium);
		player_index += 1;
		callNextIntroWithDelay(player_index)
	},  repeatTime);  //want all players to be done with their setTimeOuts players.length*1000+2000
}

function intro(){
  //delay is needed here because this is when images are first loaded.
	callNextIntroWithDelay(0);
  /* //
	introScene = new Intro();

	for(var i = 0; i<players.length; i++){
		var playersInMedium = players.slice(0, i+1); //anybody past me isn't in the medium, yet.
		var p = players[i];
		introScene.trigger(players, p)
		//$("#story").append(introScene.content());
		introScene.renderContent(newScene(),i); //new scenes take care of displaying on their own.
		processScenes2(playersInMedium);
	}*/

}

function randomizeEntryOrder(){
	players = shuffle(players);
	players[0].leader = true;
}

function makeAuthorAvatar(){
	players[0].grimDark = false;
	players[0].aspect = "Mind"
	players[0].class_name = "Maid"
	players[0].hair = 13;
	players[0].hairColor = "#291200";
	players[0].quirk.punctuation = 3;
	players[0].quirk.capitalization = 5;
	players[0].quirk.favoriteNumber = 3;
	players[0].chatHandle = "jadedResearcher"
	players[0].isTroll = false
	players[0].bloodColor = "#ff0000"
	players[0].mylevels = ["INSTEAD","a CORPSE JUST RENDERS HERE","STILL CAN LEVEL UP.","OH, AND CORPSES.","SAME LEVELS","BUT STILL HAVE","IMAGE","THEY GET A DIFFERENT","BEFORE MAXING OUT","IF THEY GODTIER","AND GO UP THE LADDER","LEVELS NOW","16 PREDETERMINED","HAVE","PLAYERS","I FINISHED ECHELADDERS."];
}

function decideHemoCaste(player){
	if(player.aspect != "Blood"){  //sorry karkat
		player.bloodColor = getRandomElementFromArray(bloodColors);
	}
}

function decideLusus(player){
	if(player.bloodColor == "#610061" || player.bloodColor == "#99004d" || players.bloodColor == "#631db4" ){
		player.lusus = getRandomElementFromArray(seaLususTypes);
	}else{
		player.lusus = getRandomElementFromArray(landlususTypes);
	}
}

function decideTroll(player){
	if(Math.random() > 0.55 ){
		player.isTroll = true;
		player.triggerLevel ++;//trolls are less stable
		decideHemoCaste(player);
		decideLusus(player);
		player.kernel_sprite = player.lusus;
	}
}
//species, hair and blood color is the same, horns and favorite number. aspect.  Thats it.
//when scratch, get rid of story dif. make blank. scratch has to be button press.
function makeGuardians(){
	//console.log("Making guardians")
	available_classes = classes.slice(0);
	available_aspects = nonrequired_aspects.slice(0); //required_aspects
	available_aspects = available_aspects.concat(required_aspects.slice(0));
	for(var i = 0; i<players.length; i++){
		  var player = players[i];
			//console.log("guardian for " + player.titleBasic());
			var guardian = randomPlayerWithoutRemoving();
			guardian.isTroll = player.isTroll;
			if(guardian.isTroll){
				guardian.quirk = randomTrollSim(guardian)
			}else{
				guardian.quirk = randomHumanSim(guardian);
			}
			guardian.quirk.favoriteNumber = player.quirk.favoriteNumber;
			guardian.bloodColor = player.bloodColor;
			guardian.lusus = player.lusus;
			guardian.hairColor = player.hairColor;
			guardian.aspect = player.aspect;
			guardian.leftHorn = player.leftHorn;
			guardian.rightHorn = player.rightHorn;
			guardian.level_index = 5; //scratched kids start more leveled up
			guardian.power = 50;
			guardian.leader = player.leader;
			guardian.reinit();//redo levels and land based on real aspect
			guardians.push(guardian);
	}

	for(var j = 0; j<guardians.length; j++){
		var g = guardians[j];
		g.generateRelationships(guardians);
	}
}

function init(){
	available_classes = classes.slice(0); //re-init available classes.
	available_aspects = nonrequired_aspects.slice(0);
	var numPlayers = getRandomInt(2,12);
	players.push(randomSpacePlayer());
	players.push(randomTimePlayer());

	for(var i = 2; i<numPlayers; i++){
		players.push(randomPlayer());
	}

	for(var j = 0; j<players.length; j++){
		var p = players[j];
		decideTroll(p);
		p.generateRelationships(players);
		if(p.isTroll){
			p.quirk = randomTrollSim(p)
		}else{
			p.quirk = randomHumanSim(p);
		}
	}

}
<commit_msg>more relationship stuff<commit_after>var players = [];
var guardians = [];
var frogStatus = 0;
var kingStrength = 100; //can use this to extrapolate enemy strength.
var queenStrength = 100;
var jackStrength = 50;
var hardStrength = 250;  //what consititutes a  'hard' game.
var democracyStrength = 0;
var queenUncrowned = false;  //if she loses her ring, she doesn't get stronger with further prototypes
var reckoningStarted = false; //can't god tier if you are definitely on skaia.
var ectoBiologyStarted = false;
var doomedTimeline = false;
var scratched = false;
var debugMode = false;
var introScene;
var currentSceneNum = 0;
var spriteWidth = 400;
var spriteHeight = 300;
var canvasWidth = 1000;
var canvasHeight = 300;
var repeatTime = 500;
var version2 = true;
var timeTillReckoning = getRandomInt(10,30);
//have EVERYTHING be a scene, don't put any story in v2.0's controller
//every scene can update the narration, or the canvas.
//should there be only one canvas?  Can have player sprites be written to a virtual canvas first, then copied to main one.
//main canvas is either Leader + PesterChumWindow + 1 or more Players (in chat or group chat with leader)
//or Leader + 1 or more Players  (leader doing bullshit side quests with someone)
window.onload = function() {
	debug("after 3.0, definitely add a new html page where you can create characters and then run a sim with them. ")
	debug("if i wanter rending to be more complex than just wait a second, make an object that keeps track of all parts of a rendering and only writes it to the canas when all are loaded");
	debug("have guardians have at least one interest in common with player");
	debug("why are quirk replacements sometimes all caps?seems to happen with unchanged capitilization. doesn't happen in replacement, definitely.")
	debug("sprite for Yx corpse smooch combo")
	debug("more varied romantic rejection convos. sometimes stop using quirk (like feferi did rejecting eridan)");
	debug("speech bubble for converstion theme? jack/mayor/a player aspect?");
	debug("rainbow godtier be rendered behind regular godtier on revival. lets godtier outfit be seen. makes it look like an aura without having to do edge detection")
   init();

	if(!debugMode){
		randomizeEntryOrder();
	}
	//debugRoyalRumble();
	//authorMessage();
	makeGuardians(); //after entry order established

	intro();
	//debugRelationshipDrama();
	//debugTriggerLevel();
	//debugGrimDark();
	//debugJackScheme();
	//debugLevelTheHellUp();
	//debugGodTierLevelTheHellUp();
	//debugCorpseLevelTheHellUp();
	//debugGodTierRevive();
	//debugCorpseSmooch();

	//make a new intro scene that has characters talk about their lands with their best friends/worst enemies.
	//refacor other scenario controller to use special scenes (not part of scene controller) rather than
	//have messy internal methods.
	//all other scenes are handled through the scene controller like normal, which will check if var version2 = true;
	//and if so will call "render" rather than "content"
	debug("consider keeping track of async tasks in array. if too many at a time, put new async tasks in second array, only activate and add to first array when it is empty enough");

	debug("relationship text. reckoning");
	//tick();  dont tick here, tick after intro
}

function renderScratchButton(){
	//alert("scratch [possible]");
	//can't scratch if it was a a total party wipe. just a regular doomed timeline.
	var living = findLivingPlayers(players);
	if(living.length > 0){
		var timePlayer = findAspectPlayer(players, "Time");
		if(!scratched){
			alert(living.length  + " living players and the " + timePlayer.land + " makes a scratch available!");
			var html = '<button type="button" onclick="scratchConfirm()">Would You Like To Scratch Session?</button>';
			$("#story").append(html);
		}else{
			$("#story").append("
This session is already scratched. No further scratches available.");
		}
	}
}

function scratchConfirm(){
	var scratchConfirmed = confirm("This session is doomed. Scratching this session will erase it. A new session will be generated, but you will no longer be able to view this session. Is this okay?");
	if(scratchConfirmed){
		scratch();
	}
}

//TODO if i wanted to, I could have mixed sessions like in canon.
//not erasing the players, after all.
//or could have an afterlife where they meet guardian players???
function scratch(){
	timeTillReckoning = getRandomInt(10,30);
	frogStatus = 0;
	kingStrength = 100; //can use this to extrapolate enemy strength.
	queenStrength = 100;
	jackStrength = 50;
	hardStrength = 250;  //what consititutes a  'hard' game.
	democracyStrength = 0;
	queenUncrowned = false;  //if she loses her ring, she doesn't get stronger with further prototypes
	reckoningStarted = false; //can't god tier if you are definitely on skaia.
	//ectobiology not reset. if performed in previous session, it's done.
	//if not, it's not. like how the alpha session trolls didn't perform ectobiology, so Karkat did.
  doomedTimeline = false;
	scratched = true;
	var scratch = "The session has been scratched. The " + getPlayersTitlesBasic(players) + " will now be the beloved guardians.";
  scratch += " Their former guardians, the " + getPlayersTitlesBasic(guardians) + " will now be the players.";
	scratch += " The new players will be given stat boosts to give them a better chance than the previous generation."
	scratch += " What will happen?"
	var tmp = players;
	players = guardians;
	guardians = tmp;
	$("#story").html(scratch);
	window.scrollTo(0, 0);

	var guardianDiv = newScene();
	var guardianID = (guardianDiv.attr("id")) + "_guardians" ;
	var ch = canvasHeight;
	if(guardians.length > 6){
		ch = canvasHeight*1.5; //a little bigger than two rows, cause time clones
	}
	var canvasHTML = "
<canvas id='canvas" + guardianID+"' width='" +canvasWidth + "' height="+ch + "'>  </canvas>";

	guardianDiv.append(canvasHTML);
	var canvasDiv = document.getElementById("canvas"+ guardianID);
	poseAsATeam(canvasDiv, guardians, 2000); //everybody, even corpses, pose as a team.

	var playerDiv = newScene();
	var playerID = (playerDiv.attr("id")) + "_players" ;
	var ch = canvasHeight;
	if(players.length > 6){
		ch = canvasHeight*1.5; //a little bigger than two rows, cause time clones
	}
	var canvasHTML = "
<canvas id='canvas" + playerID+"' width='" +canvasWidth + "' height="+ch + "'>  </canvas>";

	playerDiv.append(canvasHTML);
	var canvasDiv = document.getElementById("canvas"+ playerID);
	poseAsATeam(canvasDiv, players, 2000); //everybody, even corpses, pose as a team.

	intro();

}

function tick(){
	if(timeTillReckoning > 0 && !doomedTimeline){
		setTimeout(function(){
			timeTillReckoning += -1;
			processScenes2(players);
			tick();
		},repeatTime); //or availablePlayers.length * *1000?
	}else{

		reckoning();
	}
}

function reckoning(){
	var s = new Reckoning();
	s.trigger(players)
	s.renderContent(newScene());
	if(!doomedTimeline){
		reckoningTick();
	}
}

function reckoningTick(){
	if(timeTillReckoning > -10){
		setTimeout(function(){
			timeTillReckoning += -1;
			processReckoning2(players)
			reckoningTick();
		},repeatTime);
	}else{
		var s = new Aftermath();
		s.trigger(players)
		s.renderContent(newScene());
	}

}

//scenes call this
function chatLine(start, player, line){
  if(player.grimDark == true){
    return start + line.trim()+"\n"; //no whimsy for grim dark players
  }else{
    return start + player.quirk.translate(line).trim()+"\n";
  }
}

function newScene(){
	currentSceneNum ++;
	var div = "

";
	$("#story").append(div);
	return $("#scene"+currentSceneNum);
}

function authorMessage(){
	makeAuthorAvatar();
	introScene = new AuthorMessage();
	introScene.trigger(players, players[0])
	introScene.renderContent(newScene(),0); //new scenes take care of displaying on their own.
}

function callNextIntroWithDelay(player_index){
	if(player_index >= players.length){
    tick();//NOW start ticking
		return;
	}
	setTimeout(function(){
		var s = new Intro();
		var p = players[player_index];
		var playersInMedium = players.slice(0, player_index+1); //anybody past me isn't in the medium, yet.
		s.trigger(playersInMedium, p)
		s.renderContent(newScene(),player_index); //new scenes take care of displaying on their own.
		processScenes2(playersInMedium);
		player_index += 1;
		callNextIntroWithDelay(player_index)
	},  repeatTime);  //want all players to be done with their setTimeOuts players.length*1000+2000
}

function intro(){
  //delay is needed here because this is when images are first loaded.
	callNextIntroWithDelay(0);
  /* //
	introScene = new Intro();

	for(var i = 0; i<players.length; i++){
		var playersInMedium = players.slice(0, i+1); //anybody past me isn't in the medium, yet.
		var p = players[i];
		introScene.trigger(players, p)
		//$("#story").append(introScene.content());
		introScene.renderContent(newScene(),i); //new scenes take care of displaying on their own.
		processScenes2(playersInMedium);
	}*/

}

function randomizeEntryOrder(){
	players = shuffle(players);
	players[0].leader = true;
}

function makeAuthorAvatar(){
	players[0].grimDark = false;
	players[0].aspect = "Mind"
	players[0].class_name = "Maid"
	players[0].hair = 13;
	players[0].hairColor = "#291200";
	players[0].quirk.punctuation = 3;
	players[0].quirk.capitalization = 5;
	players[0].quirk.favoriteNumber = 3;
	players[0].chatHandle = "jadedResearcher"
	players[0].isTroll = false
	players[0].bloodColor = "#ff0000"
	players[0].mylevels = ["INSTEAD","a CORPSE JUST RENDERS HERE","STILL CAN LEVEL UP.","OH, AND CORPSES.","SAME LEVELS","BUT STILL HAVE","IMAGE","THEY GET A DIFFERENT","BEFORE MAXING OUT","IF THEY GODTIER","AND GO UP THE LADDER","LEVELS NOW","16 PREDETERMINED","HAVE","PLAYERS","I FINISHED ECHELADDERS."];
}

function decideHemoCaste(player){
	if(player.aspect != "Blood"){  //sorry karkat
		player.bloodColor = getRandomElementFromArray(bloodColors);
	}
}

function decideLusus(player){
	if(player.bloodColor == "#610061" || player.bloodColor == "#99004d" || players.bloodColor == "#631db4" ){
		player.lusus = getRandomElementFromArray(seaLususTypes);
	}else{
		player.lusus = getRandomElementFromArray(landlususTypes);
	}
}

function decideTroll(player){
	if(Math.random() > 0.55 ){
		player.isTroll = true;
		player.triggerLevel ++;//trolls are less stable
		decideHemoCaste(player);
		decideLusus(player);
		player.kernel_sprite = player.lusus;
	}
}
//species, hair and blood color is the same, horns and favorite number. aspect.  Thats it.
//when scratch, get rid of story dif. make blank. scratch has to be button press.
function makeGuardians(){
	//console.log("Making guardians")
	available_classes = classes.slice(0);
	available_aspects = nonrequired_aspects.slice(0); //required_aspects
	available_aspects = available_aspects.concat(required_aspects.slice(0));
	for(var i = 0; i<players.length; i++){
		  var player = players[i];
			//console.log("guardian for " + player.titleBasic());
			var guardian = randomPlayerWithoutRemoving();
			guardian.isTroll = player.isTroll;
			if(guardian.isTroll){
				guardian.quirk = randomTrollSim(guardian)
			}else{
				guardian.quirk = randomHumanSim(guardian);
			}
			guardian.quirk.favoriteNumber = player.quirk.favoriteNumber;
			guardian.bloodColor = player.bloodColor;
			guardian.lusus = player.lusus;
			guardian.hairColor = player.hairColor;
			guardian.aspect = player.aspect;
			guardian.leftHorn = player.leftHorn;
			guardian.rightHorn = player.rightHorn;
			guardian.level_index = 5; //scratched kids start more leveled up
			guardian.power = 50;
			guardian.leader = player.leader;
			guardian.reinit();//redo levels and land based on real aspect
			guardians.push(guardian);
	}

	for(var j = 0; j<guardians.length; j++){
		var g = guardians[j];
		g.generateRelationships(guardians);
	}
}

function init(){
	available_classes = classes.slice(0); //re-init available classes.
	available_aspects = nonrequired_aspects.slice(0);
	var numPlayers = getRandomInt(2,12);
	players.push(randomSpacePlayer());
	players.push(randomTimePlayer());

	for(var i = 2; i<numPlayers; i++){
		players.push(randomPlayer());
	}

	for(var j = 0; j<players.length; j++){
		var p = players[j];
		decideTroll(p);
		p.generateRelationships(players);
		if(p.isTroll){
			p.quirk = randomTrollSim(p)
		}else{
			p.quirk = randomHumanSim(p);
		}
	}

}
<|endoftext|>


<commit_before>import Mixin from '@ember/object/mixin';

export default Mixin.create({

  _createInternalModel(name, parent, opts={}) {
    opts.database = this;
    return this.get('store')._createInternalModel(name, parent, opts);
  },

  _createInternalModels(name, parent, source, opts={}) {
    opts.props = opts.props || {};
    opts.props.database = this;
    return this.get('store')._createInternalModels(name, parent, source, opts);
  },

  model(name, opts) {
    return this._createInternalModel(name, null, opts).model(true);
  },

  models(name, source, opts) {
    return this._createInternalModels(name, null, source, opts).model(true);
  }

});
<commit_msg>add _ref param for internal model<commit_after>import Mixin from '@ember/object/mixin';

export default Mixin.create({

  _createInternalModel(name, parent, opts={}, _ref) {
    opts.database = this;
    return this.get('store')._createInternalModel(name, parent, opts, _ref);
  },

  _createInternalModels(name, parent, source, opts={}) {
    opts.props = opts.props || {};
    opts.props.database = this;
    return this.get('store')._createInternalModels(name, parent, source, opts);
  },

  model(name, opts) {
    return this._createInternalModel(name, null, opts).model(true);
  },

  models(name, source, opts) {
    return this._createInternalModels(name, null, source, opts).model(true);
  }

});
<|endoftext|>


<commit_before>var index = {
    init: function() {
        $(document).ready(function() {
            if (!$('#shortener form')) return;

            // focus URL field or error
            var err = $('#shortener .errorlist:first');
            if (err) {
                err.prev().find('input').focus().select();
            } else {
                $('#id_url').focus();
            }
        });
    }
}
<commit_msg>fixing focus-on-load for front page (issue 1)<commit_after>var index = {
    init: function() {
        $(document).ready(function() {
            if (!$('#shortener form').length) return;

            // focus URL field or error
            var err = $('#shortener .errorlist:first');
            if (err.length) {
                err.prev().find('input').focus().select();
            } else {
                $('#id_url').focus();
            }
        });
    }
}
<|endoftext|>


<commit_before>context('Smoke Test', () => {
  before(function () {
    cy.visit('/?endTime=2018-01-01T12:00:00.000Z')
  })

  context('Loading screen and initialization of app', () => {
    it('Makes sure splash screen renders and disappears', () => {
      cy.waitForSplashscreen()
    })

    it('Makes sure data loading icon renders and disappears', () => {
      cy.waitForSpinner()
    })

    it('verifies the logo', () => {
      cy.get('[data-test=cc-logo]')
        .should('exist')
        .and('be.visible')
    })

    it('verifies the start and end data', () => {
      cy.get('.rc-slider-mark')
        .should('contain', '01/01/1980')
        .and('contain', '1990')
        .and('contain', '2000')
        .and('contain', '2010')
        .and('contain', '01/01/2018')
    })
  })

  context('Cross section interactions', () => {
    it('ensures user can enter and exit cross-section mode', () => {
      cy.get('[data-test=draw-cross-section]').click()
      cy.get('[data-test=open-3d-view]').should('be.visible')
      cy.get('[data-test=cancel-drawing]').should('be.visible')

      cy.drag('.map', [ { x: 700, y: 500 }, { x: 800, y: 500 } ])
      cy.contains('.leaflet-marker-icon', 'P1')
      cy.contains('.leaflet-marker-icon', 'P2')

      cy.get('[data-test=open-3d-view]').click()

      cy.get('.cross-section-3d').should('be.visible')
      cy.get('[data-test=exit-3d-view]').should('be.visible')

      cy.get('[data-test=exit-3d-view]').click()
      cy.get('.cross-section-3d').should('not.exist')

      cy.get('[data-test=cancel-drawing]').click()
      cy.get('.leaflet-marker-icon').should('not.exist')
    })
  })

  context('Earthquakes slider', () => {
    it('ensures user can show earthquakes', () => {
      cy.wait(1000)
      // text will be similar to "Displaying 0 of 80000 earthquakes"
      cy.get('.stats').then(statText => {
        const num1 = parseInt(statText.text().split(' ')[1])
        const num2 = parseInt(statText.text().split(' ')[3])
        expect(num1).to.eq(0)
        expect(num2 > 10000).to.eq(true)
      })
      cy.contains(' earthquakes')
      cy.get('.earthquake-playback .slider-big .rc-slider-rail').click()
      // total number of earthquakes may vary, it's in the 20-30k range
      cy.contains('Displaying ')
      cy.get('.stats').then(statText => {
        const num1 = parseInt(statText.text().split(' ')[1])
        const num2 = parseInt(statText.text().split(' ')[3])
        expect(num1 > 0).to.eq(true)
        expect(num2 > 10000).to.eq(true)
        expect(num2 > num1).to.eq(true)
      })
      cy.contains(' earthquakes')
    })
  })

  context('Magnitude slider', () => {
    it('ensures user can limit earthquakes magnitude', () => {
      cy.contains('Magnitudes from 0.0 to 10.0')
      cy.get('.mag-slider .rc-slider-rail').click(60, 2, { force: true })
      cy.contains('Magnitudes from 3.5 to 10.0')
    })
  })

  context('Data type menu', () => {
    it('ensures user can display various data on the map', () => {
      cy.get('[data-test=data-type]').click()
      cy.get('.map-layer-content')
        .should('contain', 'Plate Boundaries')
        .and('contain', 'Plate Names')
        .and('contain', 'Continent and Ocean Names')
        .and('contain', 'Volcanoes')
        .and('contain', 'Earthquakes')
        .and('contain', 'Plate Movement')

      cy.get('.map-layer-content .close-icon').click()
      cy.get('.map-layer-content').should('not.exist')
    })
  })

  context('Map type', () => {
    it('ensures user can change map type', () => {
      cy.window().then(win => {
        const scale = win.devicePixelRatio > 1 ? `@${win.devicePixelRatio}x` : ''

        cy.get('[data-test=map-type]').click()
        cy.get('.map-layer-content')
          .should('contain', 'Relief')
          .and('contain', 'Street (ArcGIS)')
          .and('contain', 'Satellite')
        cy.get('input[value=street]').click()
        cy.get(`.leaflet-tile-pane img[src="https://services.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer/tile/2/1/1"]`).should('exist')
        cy.get('input[value=relief]').click()
        cy.get('.leaflet-tile-pane img[src="https://tiles.arcgis.com/tiles/C8EMgrsFcRFL6LrL/arcgis/rest/services/ETOPO1_Global_Relief_Model_Color_Shaded_Relief/MapServer/tile/2/1/1"]').should('exist')
        cy.get('input[value=satellite]').click()
        cy.get('.leaflet-tile-pane img[src="https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/2/1/1"]').should('exist')

        cy.get('.map-layer-content .close-icon').click()
        cy.get('.map-layer-content').should('not.exist')
      })
    })
  })

  context('Key button', () => {
    it('ensures user can open the key', () => {
      cy.get('[data-test=key]').click()
      cy.get('.map-key-content')
        .should('contain', 'Magnitude')
        .and('contain', 'Depth')
        .and('contain', '3')
        .and('contain', '5')
        .and('contain', '9')
        .and('contain', '0-30 km')
        .and('contain', '300-500 km')
        .and('contain', '> 500 km')
        .and('not.contain', 'Volcano - time since last eruption')

      cy.get('[data-test=data-type]').click()
      cy.get('[title="Show Historical Volcanoes"]').click()

      cy.get('.map-key-content')
        .should('contain', 'Volcano - time since last eruption')
        .and('contain', 'Up to 100 years')
        .and('contain', '400-1600 years')
        .and('contain', '> 6400 years')
    })
  })

  context('About button', () => {
    it('ensures user can see the about box', () => {
      cy.get('[data-test=about]').click()
      cy.get('.about-modal-content')
        .should('contain', 'About: Seismic Explorer')
        .and('contain', 'Geologists collect earthquake data every day. What are the patterns of earthquake magnitude, depth, location, and frequency? What are the patterns of earthquakes along plate boundaries?')

      cy.get('[data-test=close-modal]').click()
      cy.get('.about-modal-content').should('not.exist')
    })
  })

  context('Share button', () => {
    it('ensures user can see the share box', () => {
      cy.get('[data-test=share]').click()
      cy.get('.share-modal-content')
        .should('contain', 'Share: Seismic Explorer')
        .and('contain', 'Paste this link in email or IM.')
        .and('contain', 'Paste HTML to embed in website or blog.')

      cy.get('[data-test=close-modal]').click()
      cy.get('.about-modal-content').should('not.exist')
    })
  })

  context('Reload button', () => {
    it('ensures user can reload the app', () => {
      cy.get('[data-test=reload]').click()
      cy.waitForSplashscreen()
    })
  })
})
<commit_msg>Fix lint errors<commit_after>context('Smoke Test', () => {
  before(function () {
    cy.visit('/?endTime=2018-01-01T12:00:00.000Z')
  })

  context('Loading screen and initialization of app', () => {
    it('Makes sure splash screen renders and disappears', () => {
      cy.waitForSplashscreen()
    })

    it('Makes sure data loading icon renders and disappears', () => {
      cy.waitForSpinner()
    })

    it('verifies the logo', () => {
      cy.get('[data-test=cc-logo]')
        .should('exist')
        .and('be.visible')
    })

    it('verifies the start and end data', () => {
      cy.get('.rc-slider-mark')
        .should('contain', '01/01/1980')
        .and('contain', '1990')
        .and('contain', '2000')
        .and('contain', '2010')
        .and('contain', '01/01/2018')
    })
  })

  context('Cross section interactions', () => {
    it('ensures user can enter and exit cross-section mode', () => {
      cy.get('[data-test=draw-cross-section]').click()
      cy.get('[data-test=open-3d-view]').should('be.visible')
      cy.get('[data-test=cancel-drawing]').should('be.visible')

      cy.drag('.map', [ { x: 700, y: 500 }, { x: 800, y: 500 } ])
      cy.contains('.leaflet-marker-icon', 'P1')
      cy.contains('.leaflet-marker-icon', 'P2')

      cy.get('[data-test=open-3d-view]').click()

      cy.get('.cross-section-3d').should('be.visible')
      cy.get('[data-test=exit-3d-view]').should('be.visible')

      cy.get('[data-test=exit-3d-view]').click()
      cy.get('.cross-section-3d').should('not.exist')

      cy.get('[data-test=cancel-drawing]').click()
      cy.get('.leaflet-marker-icon').should('not.exist')
    })
  })

  context('Earthquakes slider', () => {
    it('ensures user can show earthquakes', () => {
      cy.wait(1000)
      // text will be similar to "Displaying 0 of 80000 earthquakes"
      cy.get('.stats').then(statText => {
        const num1 = parseInt(statText.text().split(' ')[1])
        const num2 = parseInt(statText.text().split(' ')[3])
        expect(num1).to.eq(0)
        expect(num2 > 10000).to.eq(true)
      })
      cy.contains(' earthquakes')
      cy.get('.earthquake-playback .slider-big .rc-slider-rail').click()
      // total number of earthquakes may vary, it's in the 20-30k range
      cy.contains('Displaying ')
      cy.get('.stats').then(statText => {
        const num1 = parseInt(statText.text().split(' ')[1])
        const num2 = parseInt(statText.text().split(' ')[3])
        expect(num1 > 0).to.eq(true)
        expect(num2 > 10000).to.eq(true)
        expect(num2 > num1).to.eq(true)
      })
      cy.contains(' earthquakes')
    })
  })

  context('Magnitude slider', () => {
    it('ensures user can limit earthquakes magnitude', () => {
      cy.contains('Magnitudes from 0.0 to 10.0')
      cy.get('.mag-slider .rc-slider-rail').click(60, 2, { force: true })
      cy.contains('Magnitudes from 3.5 to 10.0')
    })
  })

  context('Data type menu', () => {
    it('ensures user can display various data on the map', () => {
      cy.get('[data-test=data-type]').click()
      cy.get('.map-layer-content')
        .should('contain', 'Plate Boundaries')
        .and('contain', 'Plate Names')
        .and('contain', 'Continent and Ocean Names')
        .and('contain', 'Volcanoes')
        .and('contain', 'Earthquakes')
        .and('contain', 'Plate Movement')

      cy.get('.map-layer-content .close-icon').click()
      cy.get('.map-layer-content').should('not.exist')
    })
  })

  context('Map type', () => {
    it('ensures user can change map type', () => {
      cy.window().then(win => {
        cy.get('[data-test=map-type]').click()
        cy.get('.map-layer-content')
          .should('contain', 'Relief')
          .and('contain', 'Street (ArcGIS)')
          .and('contain', 'Satellite')
        cy.get('input[value=street]').click()
        cy.get(`.leaflet-tile-pane img[src="https://services.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer/tile/2/1/1"]`).should('exist')
        cy.get('input[value=relief]').click()
        cy.get('.leaflet-tile-pane img[src="https://tiles.arcgis.com/tiles/C8EMgrsFcRFL6LrL/arcgis/rest/services/ETOPO1_Global_Relief_Model_Color_Shaded_Relief/MapServer/tile/2/1/1"]').should('exist')
        cy.get('input[value=satellite]').click()
        cy.get('.leaflet-tile-pane img[src="https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/2/1/1"]').should('exist')

        cy.get('.map-layer-content .close-icon').click()
        cy.get('.map-layer-content').should('not.exist')
      })
    })
  })

  context('Key button', () => {
    it('ensures user can open the key', () => {
      cy.get('[data-test=key]').click()
      cy.get('.map-key-content')
        .should('contain', 'Magnitude')
        .and('contain', 'Depth')
        .and('contain', '3')
        .and('contain', '5')
        .and('contain', '9')
        .and('contain', '0-30 km')
        .and('contain', '300-500 km')
        .and('contain', '> 500 km')
        .and('not.contain', 'Volcano - time since last eruption')

      cy.get('[data-test=data-type]').click()
      cy.get('[title="Show Historical Volcanoes"]').click()

      cy.get('.map-key-content')
        .should('contain', 'Volcano - time since last eruption')
        .and('contain', 'Up to 100 years')
        .and('contain', '400-1600 years')
        .and('contain', '> 6400 years')
    })
  })

  context('About button', () => {
    it('ensures user can see the about box', () => {
      cy.get('[data-test=about]').click()
      cy.get('.about-modal-content')
        .should('contain', 'About: Seismic Explorer')
        .and('contain', 'Geologists collect earthquake data every day. What are the patterns of earthquake magnitude, depth, location, and frequency? What are the patterns of earthquakes along plate boundaries?')

      cy.get('[data-test=close-modal]').click()
      cy.get('.about-modal-content').should('not.exist')
    })
  })

  context('Share button', () => {
    it('ensures user can see the share box', () => {
      cy.get('[data-test=share]').click()
      cy.get('.share-modal-content')
        .should('contain', 'Share: Seismic Explorer')
        .and('contain', 'Paste this link in email or IM.')
        .and('contain', 'Paste HTML to embed in website or blog.')

      cy.get('[data-test=close-modal]').click()
      cy.get('.about-modal-content').should('not.exist')
    })
  })

  context('Reload button', () => {
    it('ensures user can reload the app', () => {
      cy.get('[data-test=reload]').click()
      cy.waitForSplashscreen()
    })
  })
})
<|endoftext|>


<commit_before>/**
 * test case for /lib/support/logger module
 */
var vows = require('vows'), assert = require('assert');
var logger = require('../../../../lib/support/logger');

var logMessage1 = '[2013-11-18 10:37:14.588] [INFO] [Zenith] -  Starting Zenith ESB ..... ';
var logMessage2 = '[2013-11-18 10:38:45.425] [DEBUG] [ServiceView] - Start of View method';
var logMessage3 = '[2013-11-18 10:39:56.392] [ERROR] [WSEndPoint] - problem with request: connect ECONNREFUSED';

vows.decribe ('Zenith log message type INFO').addBatch({
	'Logger' : {
		topic:function(){
			return logger.trace;
		},
		'we get INFO': function(topic){
			assert.equal(topic,'INFO');
		}
	}
}
		).run();

vows.decribe ('Zenith log message type DEBUG').addBatch({
	'Logger' : {
		topic:function(){
			return logger.debug;
		},
		'we get INFO': function(topic){
			assert.equal(topic,'DEBUG');
		}
	}
}
		).run();

vows.decribe ('Zenith log message type ERROR').addBatch({
	'Logger' : {
		topic:function(){
			return logger.trace;
		},
		'we get INFO': function(topic){
			assert.equal(topic,'ERROR');
		}
	}
}
		).run();<commit_msg>test cse to test log level<commit_after>/**
 * test case for /lib/support/logger module
 */
var vows = require('vows'), assert = require('assert');
var logger = require('../configuration/log_config');

var logMessage1 = '[2013-11-18 10:37:14.588] [INFO] [Zenith] -  Starting Zenith ESB ..... ';
var logMessage2 = '[2013-11-18 10:38:45.425] [DEBUG] [ServiceView] - Start of View method';
var logMessage3 = '[2013-11-18 10:39:56.392] [ERROR] [WSEndPoint] - problem with request: connect ECONNREFUSED';

vows.describe('Zenith message type').addBatch({
	'Http Server configuration' : {
		topic : function() {
			return logger.logLevel;
		},

		'we get DEBUG' : function(topic) {
			assert.equal(topic,'DEBUG');
		}
	}
}).run();<|endoftext|>


<commit_before>import Ember from "ember";

export default Ember.Service.extend(Ember.Evented, {
	PN: null,
	pnState: {},

	setup: function() {
		let config = this.container.lookupFactory("config.environment");

		if (window.PUBNUB === void 0) {
			throw new Ember.Error("ember-cli-pubnub: PubNub JS SDK not found");
		}

		if (config.pubnub === void 0){
			throw new Ember.Error("ember-cli-pubnub: no configuration in config.environment");
		}

		let pn = window.PUBNUB.init(config.pubnub);

		// ************************************************* Ember.A Ember.Object ??
		this.get("pnstate")["_channels"] = [];
		this.get("pnstate")["_presence"] = {};
		this.get("pnstate")["_presData"] = {};

		return this.set("PN", pn);

	}.on("init"),

	listChannels: function() {
		return this.get("pnState")["_channels"].slice(0);
	},

	listPresence: function(channel) {
		let _ref;
		return (_ref = this.get("pnState")["_presence"][channel]) != null ? _ref.slice(0) : void 0;
	},

	presenceData: function(channel) {
		return this.get("pnState")["_presData"][channel] || {};
	},

	msgEvent: function(channel) {
		return `pn-message:${channel}`;
	},

	prsEvent: function(channel) {
		return `pn-presence:${channel}`;
	},

	publish: function(args) {
		return this.get("PN")["publish"].apply(this.get("PN"), args);
	},

	state: function(args) {
		return this.get("PN")["state"](args);
	},

	auth: function(){
		return this.get("PN")["auth"].apply(this.get("PN"), arguments);
	},

	audit: function(){
		return this.get("PN")["audit"].apply(this.get("PN"), arguments);
	},

	grant: function(){
		return this.get("PN")["grant"].apply(this.get("PN"), arguments);
	},

	whereNow: function(args) {
		return this.get("PN")["where_now"](args);
	},

	hereNow: function(args) {
		args          = this._installHandlers(args);
		args.state    = true;
		args.callback = args.presence;
		delete args.presence;
		delete args.message;
		return this.get("PN")["here_now"](args);
	},

	history: function(args) {
		args.callback = this._fireMessages(args.channel);
		return this.get("PN")["history"](args);
	},

	subscribe: function(args) {
		let _base, _name, pnState = this.get("pnState");

		args = this._installHandlers(args);

		if (pnState["_channels"].indexOf(args.channel) < 0) {
			pnState["_channels"].push(args.channel);
		}

		(_base = pnState["_presence"])[_name = args.channel] || (_base[_name] = []);

		return this.get("PN")["subscribe"].apply(this.get("PN"), args);
	},

	unsubscribe: function(args) {
		let cpos, pnState = this.get("pnState");

		cpos = pnState["_channels"].indexOf(args.channel);

		if (cpos !== -1) {
			pnState["_channels"].splice(cpos, 1);
		}

		pnState["_presence"][args.channel] = null;
		this.off(this.msgEvent(args.channel));
		this.off(this.prsEvent(args.channel));

		return this.get("PN")["unsubscribe"](args);
	},

	_fireMessages: function(channel) {
		let PN   = this.get("PN");
		let self = this;

		return function(payload) {
			return PN.each(payload[0], function(message) {
				return self.trigger(self.msgEvent(channel), {
					message: message,
					channel: channel
				});
			});
		};
	}

	_installHandlers: function(args) {
		let self      = this;
		let PN        = this.get("PN");
		let pnState   = this.get("pnState");
		let _message  = args.message;
		let _presence = args.presence;

		args.message = function() {
			self.trigger(self.msgEvent(args.channel), {
				channel:args.channel,
				message: arguments[0],
				env    : arguments[1]
			});

			if (_message) {
				return _message(arguments);
			}
		};

		args.presence = function() {
			let channel = args.channel;
			let event   = arguments[0];

			if (event.uuids) {
				PN.each(event.uuids, function(uuid) {
					let _base1, _base2, cpos;
					let state = uuid.state || null;

					uuid = uuid.uuid | uuid;

					(_base1 = pnState["_presence"])[channel] || (_base1[channel] = []);

					if (pnState["_presence"][channel].indexOf(uuid) < 0) {
						pnState["_presence"][channel].push(uuid);
					}

					(_base2 = pnState["_presData"])[channel] || (_base2[channel] = []);

					if (state) {
						return pnState["_presData"][channel][uuid] = state;
					}
				});
			}
			else {
				if (event.uuid && event.action) {
					(_base1 = pnState["_presence"])[channel] || (_base1[channel] = []);
					(_base2 = pnState["_presData"])[channel] || (_base2[channel] = {});

					if (event.action === "leave") {
						cpos = pnState["_presence"][channel].indexOf(event.uuid);

						if (cpos !== -1) {
							pnState["_presence"][channel].splice(cpos, 1);
						}
						delete pnState["_presData"][channel][event.uuid];
					}
					else {
						if (pnState["_presence"][channel].indexOf(event.uuid) < 0) {
							pnState["_presence"][channel].push(event.uuid);
						}
						if (event.data) {
							pnState["_presData"][channel][event.uuid] = event.data;
						}
					}
				}
			}

			return self.trigger(self.prsEvent(args.channel), {
				event  : event,
				channel: channel,
				message: arguments[1]
			});
		};
		return args;
	}
});
<commit_msg>linting<commit_after>/*jshint -W030 */
import Ember from "ember";

export default Ember.Service.extend(Ember.Evented, {
	PN: null,
	pnState: {},

	setup: function() {
		let config = this.container.lookupFactory("config.environment");

		if (window.PUBNUB === void 0) {
			throw new Ember.Error("ember-cli-pubnub: PubNub JS SDK not found");
		}

		if (config.pubnub === void 0){
			throw new Ember.Error("ember-cli-pubnub: no configuration in config.environment");
		}

		let pn = window.PUBNUB.init(config.pubnub);

		// ************************************************* Ember.A Ember.Object ??
		this.get("pnstate")["_channels"] = [];
		this.get("pnstate")["_presence"] = {};
		this.get("pnstate")["_presData"] = {};

		return this.set("PN", pn);

	}.on("init"),

	listChannels: function() {
		return this.get("pnState")["_channels"].slice(0);
	},

	listPresence: function(channel) {
		let _ref;
		return (_ref = this.get("pnState")["_presence"][channel]) != null ? _ref.slice(0) : void 0;
	},

	presenceData: function(channel) {
		return this.get("pnState")["_presData"][channel] || {};
	},

	msgEvent: function(channel) {
		return `pn-message:${channel}`;
	},

	prsEvent: function(channel) {
		return `pn-presence:${channel}`;
	},

	publish: function(args) {
		return this.get("PN")["publish"].apply(this.get("PN"), args);
	},

	state: function(args) {
		return this.get("PN")["state"](args);
	},

	auth: function(){
		return this.get("PN")["auth"].apply(this.get("PN"), arguments);
	},

	audit: function(){
		return this.get("PN")["audit"].apply(this.get("PN"), arguments);
	},

	grant: function(){
		return this.get("PN")["grant"].apply(this.get("PN"), arguments);
	},

	whereNow: function(args) {
		return this.get("PN")["where_now"](args);
	},

	hereNow: function(args) {
		args          = this._installHandlers(args);
		args.state    = true;
		args.callback = args.presence;
		delete args.presence;
		delete args.message;
		return this.get("PN")["here_now"](args);
	},

	history: function(args) {
		args.callback = this._fireMessages(args.channel);
		return this.get("PN")["history"](args);
	},

	subscribe: function(args) {
		let _base, _name, pnState = this.get("pnState");

		args = this._installHandlers(args);

		if (pnState["_channels"].indexOf(args.channel) < 0) {
			pnState["_channels"].push(args.channel);
		}

		(_base = pnState["_presence"])[_name = args.channel] || (_base[_name] = []);

		return this.get("PN")["subscribe"].apply(this.get("PN"), args);
	},

	unsubscribe: function(args) {
		let cpos, pnState = this.get("pnState");

		cpos = pnState["_channels"].indexOf(args.channel);

		if (cpos !== -1) {
			pnState["_channels"].splice(cpos, 1);
		}

		pnState["_presence"][args.channel] = null;
		this.off(this.msgEvent(args.channel));
		this.off(this.prsEvent(args.channel));

		return this.get("PN")["unsubscribe"](args);
	},

	_fireMessages: function(channel) {
		let PN   = this.get("PN");
		let self = this;

		return function(payload) {
			return PN.each(payload[0], function(message) {
				return self.trigger(self.msgEvent(channel), {
					message: message,
					channel: channel
				});
			});
		};
	},

	_installHandlers: function(args) {
		let self      = this;
		let PN        = this.get("PN");
		let pnState   = this.get("pnState");
		let _message  = args.message;
		let _presence = args.presence;

		args.message = function() {
			self.trigger(self.msgEvent(args.channel), {
				channel:args.channel,
				message: arguments[0],
				env    : arguments[1]
			});

			if (_message) {
				return _message(arguments);
			}
		};

		args.presence = function() {
			let _base1, _base2, cpos;
			let channel = args.channel;
			let event   = arguments[0];

			if (event.uuids) {
				PN.each(event.uuids, function(uuid) {
					let state = uuid.state || null;

					uuid = uuid.uuid | uuid;

					(_base1 = pnState["_presence"])[channel] || (_base1[channel] = []);

					if (pnState["_presence"][channel].indexOf(uuid) < 0) {
						pnState["_presence"][channel].push(uuid);
					}

					(_base2 = pnState["_presData"])[channel] || (_base2[channel] = []);

					if (state) {
						return pnState["_presData"][channel][uuid] = state;
					}
				});
			}
			else {
				if (event.uuid && event.action) {
					(_base1 = pnState["_presence"])[channel] || (_base1[channel] = []);
					(_base2 = pnState["_presData"])[channel] || (_base2[channel] = {});

					if (event.action === "leave") {
						cpos = pnState["_presence"][channel].indexOf(event.uuid);

						if (cpos !== -1) {
							pnState["_presence"][channel].splice(cpos, 1);
						}
						delete pnState["_presData"][channel][event.uuid];
					}
					else {
						if (pnState["_presence"][channel].indexOf(event.uuid) < 0) {
							pnState["_presence"][channel].push(event.uuid);
						}
						if (event.data) {
							pnState["_presData"][channel][event.uuid] = event.data;
						}
					}
				}
			}

			return self.trigger(self.prsEvent(args.channel), {
				event  : event,
				channel: channel,
				message: arguments[1]
			});
		};
		return args;
	}
});
<|endoftext|>


<commit_before>/*
 * logger-test.js: Tests for instances of the winston Logger
 *
 * (C) 2010 Charlie Robbins
 * MIT LICENSE
 *
 */

var path = require('path'),
    vows = require('vows'),
    assert = require('assert'),
    util = require('util'),
    winston = require('../lib/winston'),
    helpers = require('./helpers'),
    transport = require('./transports/transport');

vows.describe('winton/logger').addBatch({
  "An instance of winston.Logger": {
    topic: new (winston.Logger)({ transports: [new (winston.transports.Console)({ level: 'info' })] }),
    "should have the correct methods / properties defined": function (logger) {
      helpers.assertLogger(logger);
    },
    "the add() with an unsupported transport": {
      "should throw an error": function () {
        assert.throws(function () { logger.add('unsupported') }, Error);
      }
    }
  }
}).addBatch({
  "An instance of winston.Logger": {
    topic: new (winston.Logger)({ transports: [new (winston.transports.Console)({ level: 'info' })] }),
    "the log() method": {
      "when listening for the 'logging' event": {
        topic: function (logger) {
          logger.once('logging', this.callback);
          logger.log('info', 'test message');
        },
        "should emit the 'log' event with the appropriate transport": function (transport, ign) {
          helpers.assertConsole(transport);
        }
      },
      "when listening for the 'logged' event": {
        topic: function (logger) {
          logger.once('logged', this.callback);
          logger.log('info', 'test message');
        },
        "should emit the 'logged' event": function (level, msg, meta) {
          assert.equal(level, 'info');
          assert.equal(msg, 'test message');
        }
      },
    }
  }
}).addBatch({
  "An instance of winston.Logger with no transports": {
    topic: new (winston.Logger)({ emitErrs: true }),
    "the log() method should throw an error": function (logger) {
      assert.throws(function () { logger.log('anything') }, Error);
    },
    "the extend() method called on an empty object": {
      topic: function (logger) {
        var empty = {};
        logger.extend(empty);
        return empty;
      },
      "should define the appropriate methods": function (extended) {
        ['log', 'profile', 'startTimer'].concat(Object.keys(winston.config.npm.levels)).forEach(function (method) {
          assert.isFunction(extended[method]);
        });
      }
    },
    "the add() method with a supported transport": {
      topic: function (logger) {
        return logger.add(winston.transports.Console);
      },
      "should add the console Transport onto transports": function (logger) {
        assert.equal(helpers.size(logger.transports), 1);
        helpers.assertConsole(logger.transports.console);
      },
      "should throw an error when the same Transport is added": function (logger) {
        assert.throws(function () { logger.add(winston.transports.Console) }, Error);
      },
      "the profile() method": {
        "when passed a callback": {
          topic: function (logger) {
            var cb = this.callback;
            logger.profile('test1');
            setTimeout(function () {
              logger.profile('test1', function (err, level, msg, meta) {
                cb(err, level, msg, meta, logger);
              });
            }, 50);
          },
          "should respond with the appropriate profile message": function (err, level, msg, meta, logger) {
            assert.isNull(err);
            assert.equal(level, 'info');
            assert.match(meta.duration, /(\d+)ms/);
            assert.isTrue(typeof logger.profilers['test'] === 'undefined');
          },
          "when passed some metadata": {
            topic: function () {
              var logger = arguments[arguments.length - 1];
              var that = this;
              logger.profile('test3');
              logger.once('logging', that.callback.bind(null, null));
              setTimeout(function () {
                logger.profile('test3', {
                  some: 'data'
                });
              }, 50);
            },
            "should respond with the right metadata": function (err, transport, level, msg, meta) {
              assert.equal(msg, 'test3');
              assert.isNull(err);
              assert.equal(level, 'info');
              assert.match(meta.duration, /(\d+)ms/);
              assert.equal(meta.some, 'data');
            },
            "when not passed a callback": {
              topic: function (logger) {
                var logger = arguments[arguments.length - 1];
                var that = this;
                logger.profile('test2');
                logger.once('logging', that.callback.bind(null, null));
                setTimeout(function () {
                  logger.profile('test2');
                }, 50);
              },
              "should respond with the appropriate profile message": function (err, transport, level, msg, meta) {
                assert.isNull(err);
                assert.equal(msg, 'test2');
                assert.equal(level, 'info');
                assert.match(meta.duration, /(\d+)ms/);
              }
            }
          }
        }
      },
      "the startTimer() method": {
        "when passed a callback": {
          topic: function (logger) {
            var that = this;
            var timer = logger.startTimer()
            setTimeout(function () {
              timer.done('test', function (err, level, msg, meta) {
                that.callback(err, level, msg, meta, logger);
              });
            }, 1000);
          },
          "should respond with the appropriate message": function (err, level, msg, meta, logger) {
            assert.isNull(err);
            assert.equal(level, 'info');
            assert.match(meta.duration, /(\d+)ms/);
          }
        },
        "when not passed a callback": {
          topic: function (logger) {
            var that = this;
            var timer = logger.startTimer()
            logger.once('logging', that.callback.bind(null, null));
            setTimeout(function () {
              timer.done();
            }, 1000);
          },
          "should respond with the appropriate message": function (err, transport, level, msg, meta) {
            assert.isNull(err);
            assert.equal(level, 'info');
            assert.match(meta.duration, /(\d+)ms/);

            var duration = parseInt(meta.duration);
            assert.isNumber(duration);
            assert.isTrue(duration > 900 && duration < 1100);
          }
        }
      },
      "and adding an additional transport": {
        topic: function (logger) {
          return logger.add(winston.transports.File, {
            filename: path.join(__dirname, 'fixtures', 'logs', 'testfile2.log')
          });
        },
        "should be able to add multiple transports": function (logger) {
          assert.equal(helpers.size(logger.transports), 2);
          helpers.assertConsole(logger.transports.console);
          helpers.assertFile(logger.transports.file);
        }
      }
    }
  }
}).addBatch({
  "The winston logger": {
    topic: new (winston.Logger)({
      transports: [
        new (winston.transports.Console)(),
        new (winston.transports.File)({ filename: path.join(__dirname, 'fixtures', 'logs', 'filelog.log' )})
      ]
    }),
    "should return have two transports": function (logger) {
      assert.equal(helpers.size(logger.transports), 2);
    },
    "the remove() with an unadded transport": {
      "should throw an Error": function (logger) {
        assert.throws(function () { logger.remove(winston.transports.Webhook) }, Error);
      }
    },
    "the remove() method with an added transport": {
      topic: function (logger) {
         return logger.remove(winston.transports.Console);
      },
      "should remove the Console transport from transports": function (logger) {
        assert.equal(helpers.size(logger.transports), 1);
        helpers.assertFile(logger.transports.file);
      },
      "and removing an additional transport": {
        topic: function (logger) {
           return logger.remove(winston.transports.File);
        },
        "should remove File transport from transports": function (logger) {
          assert.equal(helpers.size(logger.transports), 0);
        }
      }
    }
  }
}).addBatch({
  "The winston logger": {
    topic: new (winston.Logger)({
      transports: [
        new (winston.transports.Console)(),
        new (winston.transports.File)({ filename: path.join(__dirname, 'fixtures', 'logs', 'filelog.log' )})
      ]
    }),
    "the clear() method": {
      "should remove all transports": function (logger) {
        logger.clear();
        assert.equal(helpers.size(logger.transports), 0);
      }
    }
  }
}).addBatch({
  "The winston logger": {
    topic: new (winston.Logger)({
      exceptionHandlers: [
        new (winston.transports.Console)(),
        new (winston.transports.File)({ filename: path.join(__dirname, 'fixtures', 'logs', 'filelog.log' )})
      ]
    }),
    "the unhandleExceptions() method": {
      "should remove all transports": function (logger) {
        assert.equal(helpers.size(logger.exceptionHandlers), 2);
        logger.unhandleExceptions();
        assert.equal(helpers.size(logger.exceptionHandlers), 0);
      }
    }
  }
}).addBatch({
  "The winston logger": {
    topic: new (winston.Logger)({
      transports: [
        new (winston.transports.Console)()
      ]
    }),
    "the log() method": {
      "when passed a string placeholder": {
        topic: function (logger) {
          logger.once('logging', this.callback);
          logger.log('info', 'test message %s', 'my string');
        },
        "should interpolate": function (transport, level, msg, meta) {
          assert.strictEqual(msg, 'test message my string');
        },
      },
      "when passed a number placeholder": {
        topic: function (logger) {
          logger.once('logging', this.callback);
          logger.log('info', 'test message %d', 123);
        },
        "should interpolate": function (transport, level, msg, meta) {
          assert.strictEqual(msg, 'test message 123');
        },
      },
      "when passed a json placholder and an empty object": {
        topic: function (logger) {
          logger.once('logging', this.callback);
          logger.log('info', 'test message %j', {number: 123}, {});
        },
        "should interpolate": function (transport, level, msg, meta) {
          assert.strictEqual(msg, 'test message {"number":123}');
        },
      },
      "when passed a escaped percent sign": {
        topic: function (logger) {
          logger.once('logging', this.callback);
          logger.log('info', 'test message %%', {number: 123});
        },
        "should not interpolate": function (transport, level, msg, meta) {
          assert.strictEqual(msg, util.format('test message %%'));
          assert.deepEqual(meta, {number: 123});
        },
      },
      "when passed interpolation strings and a meta object": {
        topic: function (logger) {
          logger.once('logging', this.callback);
          logger.log('info', 'test message %s, %s', 'first', 'second' ,{number: 123});
        },
        "should interpolate and have a meta object": function (transport, level, msg, meta) {
          assert.strictEqual(msg, 'test message first, second');
          assert.deepEqual(meta, {number: 123});
        },
      },
      "when passed multiple strings and a meta object": {
        topic: function (logger) {
          logger.once('logging', this.callback);
          logger.log('info', 'test message', 'first', 'second' , {number: 123});
        },
        "should join and have a meta object": function (transport, level, msg, meta) {
          assert.strictEqual(msg, 'test message first second');
          assert.deepEqual(meta, {number: 123});
        },
      },
      "when passed interpolations strings, meta object and a callback": {
        topic: function (logger) {
          var that = this;
          logger.log('info', 'test message %s, %s', 'first', 'second' , {number: 123}, function(transport, level, msg, meta){
            that.callback(transport, level, msg, meta)
          });
        },
        "should interpolate and have a meta object": function (transport, level, msg, meta) {
          assert.strictEqual(msg, 'test message first, second');
          assert.deepEqual(meta, {number: 123});
        },
      },
      "when passed multiple strings, a meta object and a callback": {
        topic: function (logger) {
          var that = this;
          logger.log('info', 'test message', 'first', 'second' , {number: 123}, function(transport, level, msg, meta){
            that.callback(transport, level, msg, meta)
          });
        },
        "should join and have a meta object": function (transport, level, msg, meta) {
          assert.strictEqual(msg, 'test message first second');
          assert.deepEqual(meta, {number: 123});
        },
      }
    }
  }
}).export(module);
<commit_msg>fix tests for profile fix<commit_after>/*
 * logger-test.js: Tests for instances of the winston Logger
 *
 * (C) 2010 Charlie Robbins
 * MIT LICENSE
 *
 */

var path = require('path'),
    vows = require('vows'),
    assert = require('assert'),
    util = require('util'),
    winston = require('../lib/winston'),
    helpers = require('./helpers'),
    transport = require('./transports/transport');

vows.describe('winton/logger').addBatch({
  "An instance of winston.Logger": {
    topic: new (winston.Logger)({ transports: [new (winston.transports.Console)({ level: 'info' })] }),
    "should have the correct methods / properties defined": function (logger) {
      helpers.assertLogger(logger);
    },
    "the add() with an unsupported transport": {
      "should throw an error": function () {
        assert.throws(function () { logger.add('unsupported') }, Error);
      }
    }
  }
}).addBatch({
  "An instance of winston.Logger": {
    topic: new (winston.Logger)({ transports: [new (winston.transports.Console)({ level: 'info' })] }),
    "the log() method": {
      "when listening for the 'logging' event": {
        topic: function (logger) {
          logger.once('logging', this.callback);
          logger.log('info', 'test message');
        },
        "should emit the 'log' event with the appropriate transport": function (transport, ign) {
          helpers.assertConsole(transport);
        }
      },
      "when listening for the 'logged' event": {
        topic: function (logger) {
          logger.once('logged', this.callback);
          logger.log('info', 'test message');
        },
        "should emit the 'logged' event": function (level, msg, meta) {
          assert.equal(level, 'info');
          assert.equal(msg, 'test message');
        }
      },
    }
  }
}).addBatch({
  "An instance of winston.Logger with no transports": {
    topic: new (winston.Logger)({ emitErrs: true }),
    "the log() method should throw an error": function (logger) {
      assert.throws(function () { logger.log('anything') }, Error);
    },
    "the extend() method called on an empty object": {
      topic: function (logger) {
        var empty = {};
        logger.extend(empty);
        return empty;
      },
      "should define the appropriate methods": function (extended) {
        ['log', 'profile', 'startTimer'].concat(Object.keys(winston.config.npm.levels)).forEach(function (method) {
          assert.isFunction(extended[method]);
        });
      }
    },
    "the add() method with a supported transport": {
      topic: function (logger) {
        return logger.add(winston.transports.Console);
      },
      "should add the console Transport onto transports": function (logger) {
        assert.equal(helpers.size(logger.transports), 1);
        helpers.assertConsole(logger.transports.console);
      },
      "should throw an error when the same Transport is added": function (logger) {
        assert.throws(function () { logger.add(winston.transports.Console) }, Error);
      },
      "the profile() method": {
        "when passed a callback": {
          topic: function (logger) {
            var cb = this.callback;
            logger.profile('test1');
            setTimeout(function () {
              logger.profile('test1', function (err, level, msg, meta) {
                cb(err, level, msg, meta, logger);
              });
            }, 50);
          },
          "should respond with the appropriate profile message": function (err, level, msg, meta, logger) {
            assert.isNull(err);
            assert.equal(level, 'info');
            assert.match(meta.duration, /(\d+)ms/);
            assert.isTrue(typeof logger.profilers['test'] === 'undefined');
          },
          "when passed some metadata": {
            topic: function () {
              var logger = arguments[arguments.length - 1];
              var cb = this.callback.bind(null, null);
              logger.profile('test3');
              setTimeout(function () {
                logger.once('logging', cb);
                logger.profile('test3', {
                  some: 'data'
                });
              }, 50);
            },
            "should respond with the right metadata": function (err, transport, level, msg, meta) {
              assert.equal(msg, 'test3');
              assert.isNull(err);
              assert.equal(level, 'info');
              assert.match(meta.duration, /(\d+)ms/);
              assert.equal(meta.some, 'data');
            },
            "when not passed a callback": {
              topic: function () {
                var logger = arguments[arguments.length - 1];
                var cb = this.callback.bind(null, null);
                logger.profile('test2');
                setTimeout(function () {
                  logger.once('logging', cb);
                  logger.profile('test2');
                }, 50);
              },
              "should respond with the appropriate profile message": function (err, transport, level, msg, meta) {
                assert.isNull(err);
                assert.equal(msg, 'test2');
                assert.equal(level, 'info');
                assert.match(meta.duration, /(\d+)ms/);
              }
            }
          }
        }
      },
      "the startTimer() method": {
        "when passed a callback": {
          topic: function (logger) {
            var that = this;
            var timer = logger.startTimer()
            setTimeout(function () {
              timer.done('test', function (err, level, msg, meta) {
                that.callback(err, level, msg, meta, logger);
              });
            }, 1000);
          },
          "should respond with the appropriate message": function (err, level, msg, meta, logger) {
            assert.isNull(err);
            assert.equal(level, 'info');
            assert.match(meta.duration, /(\d+)ms/);
          }
        },
        "when not passed a callback": {
          topic: function (logger) {
            var that = this;
            var timer = logger.startTimer()
            logger.once('logging', that.callback.bind(null, null));
            setTimeout(function () {
              timer.done();
            }, 1000);
          },
          "should respond with the appropriate message": function (err, transport, level, msg, meta) {
            assert.isNull(err);
            assert.equal(level, 'info');
            assert.match(meta.duration, /(\d+)ms/);

            var duration = parseInt(meta.duration);
            assert.isNumber(duration);
            assert.isTrue(duration >= 50 && duration < 100);
          }
        }
      },
      "and adding an additional transport": {
        topic: function (logger) {
          return logger.add(winston.transports.File, {
            filename: path.join(__dirname, 'fixtures', 'logs', 'testfile2.log')
          });
        },
        "should be able to add multiple transports": function (logger) {
          assert.equal(helpers.size(logger.transports), 2);
          helpers.assertConsole(logger.transports.console);
          helpers.assertFile(logger.transports.file);
        }
      }
    }
  }
}).addBatch({
  "The winston logger": {
    topic: new (winston.Logger)({
      transports: [
        new (winston.transports.Console)(),
        new (winston.transports.File)({ filename: path.join(__dirname, 'fixtures', 'logs', 'filelog.log' )})
      ]
    }),
    "should return have two transports": function (logger) {
      assert.equal(helpers.size(logger.transports), 2);
    },
    "the remove() with an unadded transport": {
      "should throw an Error": function (logger) {
        assert.throws(function () { logger.remove(winston.transports.Webhook) }, Error);
      }
    },
    "the remove() method with an added transport": {
      topic: function (logger) {
         return logger.remove(winston.transports.Console);
      },
      "should remove the Console transport from transports": function (logger) {
        assert.equal(helpers.size(logger.transports), 1);
        helpers.assertFile(logger.transports.file);
      },
      "and removing an additional transport": {
        topic: function (logger) {
           return logger.remove(winston.transports.File);
        },
        "should remove File transport from transports": function (logger) {
          assert.equal(helpers.size(logger.transports), 0);
        }
      }
    }
  }
}).addBatch({
  "The winston logger": {
    topic: new (winston.Logger)({
      transports: [
        new (winston.transports.Console)(),
        new (winston.transports.File)({ filename: path.join(__dirname, 'fixtures', 'logs', 'filelog.log' )})
      ]
    }),
    "the clear() method": {
      "should remove all transports": function (logger) {
        logger.clear();
        assert.equal(helpers.size(logger.transports), 0);
      }
    }
  }
}).addBatch({
  "The winston logger": {
    topic: new (winston.Logger)({
      exceptionHandlers: [
        new (winston.transports.Console)(),
        new (winston.transports.File)({ filename: path.join(__dirname, 'fixtures', 'logs', 'filelog.log' )})
      ]
    }),
    "the unhandleExceptions() method": {
      "should remove all transports": function (logger) {
        assert.equal(helpers.size(logger.exceptionHandlers), 2);
        logger.unhandleExceptions();
        assert.equal(helpers.size(logger.exceptionHandlers), 0);
      }
    }
  }
}).addBatch({
  "The winston logger": {
    topic: new (winston.Logger)({
      transports: [
        new (winston.transports.Console)()
      ]
    }),
    "the log() method": {
      "when passed a string placeholder": {
        topic: function (logger) {
          logger.once('logging', this.callback);
          logger.log('info', 'test message %s', 'my string');
        },
        "should interpolate": function (transport, level, msg, meta) {
          assert.strictEqual(msg, 'test message my string');
        },
      },
      "when passed a number placeholder": {
        topic: function (logger) {
          logger.once('logging', this.callback);
          logger.log('info', 'test message %d', 123);
        },
        "should interpolate": function (transport, level, msg, meta) {
          assert.strictEqual(msg, 'test message 123');
        },
      },
      "when passed a json placholder and an empty object": {
        topic: function (logger) {
          logger.once('logging', this.callback);
          logger.log('info', 'test message %j', {number: 123}, {});
        },
        "should interpolate": function (transport, level, msg, meta) {
          assert.strictEqual(msg, 'test message {"number":123}');
        },
      },
      "when passed a escaped percent sign": {
        topic: function (logger) {
          logger.once('logging', this.callback);
          logger.log('info', 'test message %%', {number: 123});
        },
        "should not interpolate": function (transport, level, msg, meta) {
          assert.strictEqual(msg, util.format('test message %%'));
          assert.deepEqual(meta, {number: 123});
        },
      },
      "when passed interpolation strings and a meta object": {
        topic: function (logger) {
          logger.once('logging', this.callback);
          logger.log('info', 'test message %s, %s', 'first', 'second' ,{number: 123});
        },
        "should interpolate and have a meta object": function (transport, level, msg, meta) {
          assert.strictEqual(msg, 'test message first, second');
          assert.deepEqual(meta, {number: 123});
        },
      },
      "when passed multiple strings and a meta object": {
        topic: function (logger) {
          logger.once('logging', this.callback);
          logger.log('info', 'test message', 'first', 'second' , {number: 123});
        },
        "should join and have a meta object": function (transport, level, msg, meta) {
          assert.strictEqual(msg, 'test message first second');
          assert.deepEqual(meta, {number: 123});
        },
      },
      "when passed interpolations strings, meta object and a callback": {
        topic: function (logger) {
          var that = this;
          logger.log('info', 'test message %s, %s', 'first', 'second' , {number: 123}, function(transport, level, msg, meta){
            that.callback(transport, level, msg, meta)
          });
        },
        "should interpolate and have a meta object": function (transport, level, msg, meta) {
          assert.strictEqual(msg, 'test message first, second');
          assert.deepEqual(meta, {number: 123});
        },
      },
      "when passed multiple strings, a meta object and a callback": {
        topic: function (logger) {
          var that = this;
          logger.log('info', 'test message', 'first', 'second' , {number: 123}, function(transport, level, msg, meta){
            that.callback(transport, level, msg, meta)
          });
        },
        "should join and have a meta object": function (transport, level, msg, meta) {
          assert.strictEqual(msg, 'test message first second');
          assert.deepEqual(meta, {number: 123});
        },
      }
    }
  }
}).export(module);
<|endoftext|>


<commit_before><commit_msg>JSDoc updates and rearrangement<commit_after><|endoftext|>