<commit_before>	/*-----Function definition-------*/
	var activePage = document.URL.split("/").pop(); /*get page name*/
	var activePageHighlight=function(){  // add top and bottom border on the active page name
		$("#navbar-"+activePage).addClass("navbar-item");
	};
	var deactivePageHighlight=function(){  // add top and bottom border on the active page name
		$("#navbar-"+activePage).removeClass("navbar-item");
	};
	var addScrollOnChart=function(){
		$("#balance-slimscroll").niceScroll();
	};

	$('.navbar .dropdown').hover(function() {
		$(this).find('.dropdown-menu').first().stop(true, true).delay(250).slideDown();
	}, function() {
		$(this).find('.dropdown-menu').first().stop(true, true).delay(100).slideUp()
	});

	/*--------CHARTS--------*/

	var graphColor=function(graphData){
		var chartColor=[];
		for(var i=0; i<graphData.length;i++){
			if(graphData[i]>=0){
				chartColor.push("rgba(168,189,68,0.5)");
			}else{
				chartColor.push("rgba(249,126,118,0.5)");
			}
		};
		return chartColor
	}

	var members_chart=[];
	for (var i = 0; i < balances.length; i++) {
		members_chart[i]='';
	}

	var colorFill=graphColor(balances);
	var data = {
		labels : members_chart,
		datasets : [
		{
			fillColor : colorFill,
			strokeColor : "rgba(220,220,220,1)",
			data : balances
		}
		]
	}

	var loadChart=function(){

		var graphColor=function(graphData){
			var chartColor=[];
			for(var i=0; i<graphData.length;i++){
				if(graphData[i]>=0){
					chartColor.push("rgba(168,189,68,0.5)");
				}else{
					chartColor.push("rgba(249,126,118,0.5)");
				}
			};
			return chartColor
		}

		var members_chart=[];
		for (var i = 0; i < balances.length; i++) {
			members_chart[i]='';

		}

		var colorFill=graphColor(balances);
		var data = {
			labels : members_chart,
			datasets : [
			{
				fillColor : colorFill,
				strokeColor : "rgba(220,220,220,1)",
				data : balances
			}
			]
		}

		var ctx = document.getElementById("balanceChart").getContext("2d");
		new Chart(ctx).Bar(data,{
			scaleOverlay : false,
			scaleShowLabels : false
		});
	}

	/* HEADER ACTIONS */

	$(document).ready(function() {

		/* --- Group members picture toggle --- */
		$("#toggle-button").click(function(){
			$("#second-row-big").slideToggle();
			if($(this).text() === 'hide members'){
				$(this).text('show members');
			}else{
				$(this).text('hide members');
			}
		});

		/* --- Group members show profile in modal --- */
		$("a[data-target=memberProfileModal]").on("click", function(e){
			e.preventDefault();
			$.get('modal/profile/'+$(this).data('id'), function(response){
				$("#memberProfileModal").html(response).modal('show');
			});
		});
	});

	window.onresize =function() {
		$('#timeline').height(Math.max($('#balance-expense-container').height(),$('#timeline-expense-container').height())-100+'px');
	}

	/* settingsStart, expenseStart, listsStart define the funciton that needs to be
	/* called on page load and in response for ajax request

	/*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!SETTINGS START!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/

	/*-------Settings Start----*/
	var settingsStart = function(){

		deactivePageHighlight();
		activePage = document.URL.split("/").pop(); /*get page name*/
		activePageHighlight();

		addScrollOnChart();
		loadChart();

		$('#action-bar-first-child').hover(
			function()
			{
				$('.group-edit').addClass('group-edit-hover');
			},
			function(){
				$('.group-edit').removeClass('group-edit-hover');
			}
			);

		/*--------CHARTS & TIMLINE SIZE--------*/
		if (activePage!=="lists"){
			var members_nb= balances.length;
		};
		var navbarHeight=$("#navbar-row").height();

	}

	/*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! EXPENSE START !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
	/*-------expenseStart-----*/
	var expenseStart = function(){

		deactivePageHighlight();
		activePage = document.URL.split("/").pop(); /*get page name*/
		activePageHighlight();

		addScrollOnChart();
		loadChart();

		/*--------CHARTS & TIMLINE SIZE--------*/
		if (activePage!=="lists"){
			var members_nb= balances.length;
		};
		var navbarHeight=$("#navbar-row").height();

		$('#timeline').height(Math.max($('#balance-expense-container').height(),$('#timeline-expense-container').height())-65+'px');

		/*-------TOOLTIPS--------*/
		$(function () {
			$("[rel='tooltip']").tooltip({placement: 'top'});
		});

		/*-------Pinpoint buttons on timeline (date)--------*/

		$('.pinpoint-button').hover(function () {
			this.src = 'http://twinkler.co/img/Frame/tmln-btn-hover.png';
		}, function () {
			this.src = 'http://twinkler.co/img/Frame/tmln-btn.png';
		});

		var today=new Date();
		var dd=today.getDate();
		var mm=today.getMonth()+1;

		if(dd<10){dd='0'+dd};
		if(mm<10){mm='0'+mm};

		$('#today-pinpoint').attr('title', dd +"/"+mm);

	    // --> expense modal scroll
	    $(function(){
	    	$('#expense-slimscroll').slimScroll({
	    		height: Math.min('450',$(window).height()-120)+'px'
	    	});
	    });

	    // ---> Expense filter
	    $("#show-all-button").on("click", function(){
	    	$(".expense-block").fadeIn();
	    	$("#only-mine-button").removeClass("active");
	    	$(this).addClass("active");
	    });
	    $("#only-mine-button").on("click", function(){
	    	$(".expense-block").filter(".nottagged").fadeOut();
	    	$("#show-all-button").removeClass("active");
	    	$(this).addClass("active");
	    });

	    $('.edit-button').on('click', function(e){
	    	e.preventDefault();
	    	var expenseId = $(this).data('id');
	    	var editBox = $('#expense-edit-'+expenseId);
	    	if(editBox.hasClass('shown')){
	    		editBox.fadeOut();
	    		editBox.removeClass('shown');
	    	} else {
	    		$.get('expenses/edit/'+expenseId, function(response){
	    			editBox.html(response).hide().fadeIn();
	    			editBox.addClass('shown');
	    		});
	    	}
	    })

	}

	/*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! TIMELINE START !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/

	var timelineStart = function(){

		deactivePageHighlight();
		activePage = document.URL.split("/").pop(); /*get page name*/
		activePageHighlight();

		var input = $("#send-box").find('input');

		function refreshMessages() {
			rowCount=$('#chat-table tr').length
			if(activePage=="timeline"){
				$.get('messages', function(response){
					$('#message-list').html(response);
				// rappeler les fonctions de mise en forme
				if(rowCount!=$('#chat-table tr').length){
					$("#message-list").animate({ scrollTop: 100000 }, "slow");
				}
			});
			}
		}
		window.setInterval(refreshMessages, 10000);

		$(document).keypress(function(e) {
			if(e.which == 13) {
				var message = $("#send-box").find('input').val();
				$.get('ajax/message/new?new_message='+message, function(response){
					$('#message-list').html(response);
					input.val('');
					input.focus();
					// rappeler les fonctions de mise en forme

					var rowCount=$('#chat-table tr').length

					if(rowCount < 7){
						$('#message-list').slimScroll({
							height: (rowCount+1)*61,
						});
						$('#chat-container').height(40+(rowCount)*61+'px');
						$('#chat-container .slimScrollDiv').height((rowCount)*61+'px');
						$('#message-list').height((rowCount)*61+'px');

					}

					$("#message-list").animate({ scrollTop: 100000 }, "slow");
				});
			}
		});

		$("#more-expenses").on('click', 'a', function(e){
			e.preventDefault();
			$.get('ajax/expenses', function(response){
				$('#content-container').html(response);
				window.history.pushState("", "", 'expenses');
				// rappeler les fonctions de mise en forme
				addScrollOnChart();
				$('#expense-slimscroll').slimScroll({
					height: Math.min('450',$(window).height()-120)+'px'
				});
				expenseStart();
			});
		});

		$('#message-list').slimScroll({
			height: Math.min('280',$('#message-list').height())+'px',
			start: 'bottom'
		});

	}

	/*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! LOAD FUNCTION ON START !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/

	/* actually call the function when page is loaded for the first time */
	$(document).ready(function() {

		jQuery(function($) {
			function fixDiv() {

				var oritop=55;
				if($("#toggle-button").text() === 'hide members'){
					oritop=55;
				}else{
					oritop=0;
				}

				var $cache = $('#navbar-row');
				var $cacheItem = $('#navbar-expenses');
				if ($(window).scrollTop() > oritop && ($(document).height()-32>$(window).height())) {
					$("#navbar-"+activePage).css({'border-top-left-radius':'0px','border-top-right-radius':'0px'});
					$cache.addClass("navbar-scroll");
					$cache.css({'position': 'fixed', 'top': '40px','z-index':'9999999999'});
					$( "#toggle-button" ).hide();
				}
				else{
					$cache.css({'position': 'relative', 'top': 'auto','z-index':'0'});
					$cache.removeClass("navbar-scroll");
					$("#navbar-"+activePage).css({'border-top-left-radius':'4px','border-top-right-radius':'4px'});
					$( "#toggle-button" ).show();
				}
			}
			$(window).scroll(fixDiv);
			fixDiv();
		});

		if (activePage==="expenses"){
			expenseStart();
		}else if(activePage==="timeline"){
			timelineStart();
		}
	});

	/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/

	/* --- AJAX FOR SELECTION MENU --- */
	$(document).ready(function() {

	// ---> ajax for going to expenses
	$("#navbar-expenses").on('click', 'a', function(e){
		e.preventDefault();
		$.get('ajax/expenses', function(response){
			$('#content-container').html(response);
			window.history.pushState("", "", 'expenses');
				// rappeler les fonctions de mise en forme
				addScrollOnChart();
				$('#expense-slimscroll').slimScroll({
					height: Math.min('450',$(window).height()-120)+'px'
				});
				expenseStart();
			});
	});

	// ---> ajax for going to timeline
	$("#navbar-timeline").on('click', 'a', function(e){
		e.preventDefault();
		$.get('ajax/timeline', function(response){
			$('#content-container').html(response);
			window.history.pushState("", "", 'timeline');
				// rappeler les fonctions de mise en forme
				// rappel de listapp.js

				deactivePageHighlight();
				activePage = document.URL.split("/").pop(); /*get page name*/
				activePageHighlight();

				timelineStart();
			});
	});

});

<commit_msg>chat height fixed<commit_after>	/*-----Function definition-------*/
	var activePage = document.URL.split("/").pop(); /*get page name*/
	var activePageHighlight=function(){  // add top and bottom border on the active page name
		$("#navbar-"+activePage).addClass("navbar-item");
	};
	var deactivePageHighlight=function(){  // add top and bottom border on the active page name
		$("#navbar-"+activePage).removeClass("navbar-item");
	};
	var addScrollOnChart=function(){
		$("#balance-slimscroll").niceScroll();
	};

	$('.navbar .dropdown').hover(function() {
		$(this).find('.dropdown-menu').first().stop(true, true).delay(250).slideDown();
	}, function() {
		$(this).find('.dropdown-menu').first().stop(true, true).delay(100).slideUp()
	});

	/*--------CHARTS--------*/

	var graphColor=function(graphData){
		var chartColor=[];
		for(var i=0; i<graphData.length;i++){
			if(graphData[i]>=0){
				chartColor.push("rgba(168,189,68,0.5)");
			}else{
				chartColor.push("rgba(249,126,118,0.5)");
			}
		};
		return chartColor
	}

	var members_chart=[];
	for (var i = 0; i < balances.length; i++) {
		members_chart[i]='';
	}

	var colorFill=graphColor(balances);
	var data = {
		labels : members_chart,
		datasets : [
		{
			fillColor : colorFill,
			strokeColor : "rgba(220,220,220,1)",
			data : balances
		}
		]
	}

	var loadChart=function(){

		var graphColor=function(graphData){
			var chartColor=[];
			for(var i=0; i<graphData.length;i++){
				if(graphData[i]>=0){
					chartColor.push("rgba(168,189,68,0.5)");
				}else{
					chartColor.push("rgba(249,126,118,0.5)");
				}
			};
			return chartColor
		}

		var members_chart=[];
		for (var i = 0; i < balances.length; i++) {
			members_chart[i]='';

		}

		var colorFill=graphColor(balances);
		var data = {
			labels : members_chart,
			datasets : [
			{
				fillColor : colorFill,
				strokeColor : "rgba(220,220,220,1)",
				data : balances
			}
			]
		}

		var ctx = document.getElementById("balanceChart").getContext("2d");
		new Chart(ctx).Bar(data,{
			scaleOverlay : false,
			scaleShowLabels : false
		});
	}

	/* HEADER ACTIONS */

	$(document).ready(function() {

		/* --- Group members picture toggle --- */
		$("#toggle-button").click(function(){
			$("#second-row-big").slideToggle();
			if($(this).text() === 'hide members'){
				$(this).text('show members');
			}else{
				$(this).text('hide members');
			}
		});

		/* --- Group members show profile in modal --- */
		$("a[data-target=memberProfileModal]").on("click", function(e){
			e.preventDefault();
			$.get('modal/profile/'+$(this).data('id'), function(response){
				$("#memberProfileModal").html(response).modal('show');
			});
		});
	});

	window.onresize =function() {
		$('#timeline').height(Math.max($('#balance-expense-container').height(),$('#timeline-expense-container').height())-100+'px');
	}

	/* settingsStart, expenseStart, listsStart define the funciton that needs to be
	/* called on page load and in response for ajax request

	/*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!SETTINGS START!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/

	/*-------Settings Start----*/
	var settingsStart = function(){

		deactivePageHighlight();
		activePage = document.URL.split("/").pop(); /*get page name*/
		activePageHighlight();

		addScrollOnChart();
		loadChart();

		$('#action-bar-first-child').hover(
			function()
			{
				$('.group-edit').addClass('group-edit-hover');
			},
			function(){
				$('.group-edit').removeClass('group-edit-hover');
			}
			);

		/*--------CHARTS & TIMLINE SIZE--------*/
		if (activePage!=="lists"){
			var members_nb= balances.length;
		};
		var navbarHeight=$("#navbar-row").height();

	}

	/*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! EXPENSE START !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
	/*-------expenseStart-----*/
	var expenseStart = function(){

		deactivePageHighlight();
		activePage = document.URL.split("/").pop(); /*get page name*/
		activePageHighlight();

		addScrollOnChart();
		loadChart();

		/*--------CHARTS & TIMLINE SIZE--------*/
		if (activePage!=="lists"){
			var members_nb= balances.length;
		};
		var navbarHeight=$("#navbar-row").height();

		$('#timeline').height(Math.max($('#balance-expense-container').height(),$('#timeline-expense-container').height())-65+'px');

		/*-------TOOLTIPS--------*/
		$(function () {
			$("[rel='tooltip']").tooltip({placement: 'top'});
		});

		/*-------Pinpoint buttons on timeline (date)--------*/

		$('.pinpoint-button').hover(function () {
			this.src = 'http://twinkler.co/img/Frame/tmln-btn-hover.png';
		}, function () {
			this.src = 'http://twinkler.co/img/Frame/tmln-btn.png';
		});

		var today=new Date();
		var dd=today.getDate();
		var mm=today.getMonth()+1;

		if(dd<10){dd='0'+dd};
		if(mm<10){mm='0'+mm};

		$('#today-pinpoint').attr('title', dd +"/"+mm);

	    // --> expense modal scroll
	    $(function(){
	    	$('#expense-slimscroll').slimScroll({
	    		height: Math.min('450',$(window).height()-120)+'px'
	    	});
	    });

	    // ---> Expense filter
	    $("#show-all-button").on("click", function(){
	    	$(".expense-block").fadeIn();
	    	$("#only-mine-button").removeClass("active");
	    	$(this).addClass("active");
	    });
	    $("#only-mine-button").on("click", function(){
	    	$(".expense-block").filter(".nottagged").fadeOut();
	    	$("#show-all-button").removeClass("active");
	    	$(this).addClass("active");
	    });

	    $('.edit-button').on('click', function(e){
	    	e.preventDefault();
	    	var expenseId = $(this).data('id');
	    	var editBox = $('#expense-edit-'+expenseId);
	    	if(editBox.hasClass('shown')){
	    		editBox.fadeOut();
	    		editBox.removeClass('shown');
	    	} else {
	    		$.get('expenses/edit/'+expenseId, function(response){
	    			editBox.html(response).hide().fadeIn();
	    			editBox.addClass('shown');
	    		});
	    	}
	    })

	}

	/*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! TIMELINE START !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/

	var timelineStart = function(){

		deactivePageHighlight();
		activePage = document.URL.split("/").pop(); /*get page name*/
		activePageHighlight();

		var input = $("#send-box").find('input');

		function refreshMessages() {
			rowCount=$('#chat-table tr').length
			if(activePage=="timeline"){
				$.get('messages', function(response){
					$('#message-list').html(response);
				// rappeler les fonctions de mise en forme
				if(rowCount!=$('#chat-table tr').length){
					$("#message-list").animate({ scrollTop: 100000 }, "slow");
				}
			});
			}
		}
		window.setInterval(refreshMessages, 10000);

		$(document).keypress(function(e) {
			if(e.which == 13) {
				var message = $("#send-box").find('input').val();
				$.get('ajax/message/new?new_message='+message, function(response){
					$('#message-list').html(response);
					input.val('');
					input.focus();
					// rappeler les fonctions de mise en forme

					var rowCount=$('#chat-table tr').length

					if(rowCount < 7){
						$('#message-list').slimScroll({
							height: (rowCount+1)*($('#chat-table tr').height()+2),
						});
						$('#chat-container').height(40+(rowCount)*($('#chat-table tr').height()+2)+'px');
						$('#chat-container .slimScrollDiv').height((rowCount)*($('#chat-table tr').height()+2)+'px');
						$('#message-list').height((rowCount)*($('#chat-table tr').height()+2)+'px');

					}

					$("#message-list").animate({ scrollTop: 100000 }, "slow");
				});
			}
		});

		$("#more-expenses").on('click', 'a', function(e){
			e.preventDefault();
			$.get('ajax/expenses', function(response){
				$('#content-container').html(response);
				window.history.pushState("", "", 'expenses');
				// rappeler les fonctions de mise en forme
				addScrollOnChart();
				$('#expense-slimscroll').slimScroll({
					height: Math.min('450',$(window).height()-120)+'px'
				});
				expenseStart();
			});
		});

		$('#message-list').slimScroll({
			height: Math.min('280',$('#message-list').height())+'px',
			start: 'bottom'
		});

	}

	/*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! LOAD FUNCTION ON START !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/

	/* actually call the function when page is loaded for the first time */
	$(document).ready(function() {

		jQuery(function($) {
			function fixDiv() {

				var oritop=55;
				if($("#toggle-button").text() === 'hide members'){
					oritop=55;
				}else{
					oritop=0;
				}

				var $cache = $('#navbar-row');
				var $cacheItem = $('#navbar-expenses');
				if ($(window).scrollTop() > oritop && ($(document).height()-32>$(window).height())) {
					$("#navbar-"+activePage).css({'border-top-left-radius':'0px','border-top-right-radius':'0px'});
					$cache.addClass("navbar-scroll");
					$cache.css({'position': 'fixed', 'top': '40px','z-index':'9999999999'});
					$( "#toggle-button" ).hide();
				}
				else{
					$cache.css({'position': 'relative', 'top': 'auto','z-index':'0'});
					$cache.removeClass("navbar-scroll");
					$("#navbar-"+activePage).css({'border-top-left-radius':'4px','border-top-right-radius':'4px'});
					$( "#toggle-button" ).show();
				}
			}
			$(window).scroll(fixDiv);
			fixDiv();
		});

		if (activePage==="expenses"){
			expenseStart();
		}else if(activePage==="timeline"){
			timelineStart();
		}
	});

	/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/

	/* --- AJAX FOR SELECTION MENU --- */
	$(document).ready(function() {

	// ---> ajax for going to expenses
	$("#navbar-expenses").on('click', 'a', function(e){
		e.preventDefault();
		$.get('ajax/expenses', function(response){
			$('#content-container').html(response);
			window.history.pushState("", "", 'expenses');
				// rappeler les fonctions de mise en forme
				addScrollOnChart();
				$('#expense-slimscroll').slimScroll({
					height: Math.min('450',$(window).height()-120)+'px'
				});
				expenseStart();
			});
	});

	// ---> ajax for going to timeline
	$("#navbar-timeline").on('click', 'a', function(e){
		e.preventDefault();
		$.get('ajax/timeline', function(response){
			$('#content-container').html(response);
			window.history.pushState("", "", 'timeline');
				// rappeler les fonctions de mise en forme
				// rappel de listapp.js

				deactivePageHighlight();
				activePage = document.URL.split("/").pop(); /*get page name*/
				activePageHighlight();

				timelineStart();
			});
	});

});

<|endoftext|>


<commit_before>'use strict';

var JID = require('node-xmpp-core').JID,
    url = require('url'),
    querystring = require('querystring');

function getJID(req) {
    console.log(JSON.stringify(req.user));
    return new JID(req.user.jid);
}

function exportJSON(model) {
    if (model instanceof Array) {
        var exportVal = [];
        model.forEach(function (item) {
            exportVal.push(exportJSON(item));
        });
        return exportVal;
    } else if (model && typeof (model.exportJSON) === 'function') {
        return model.exportJSON();
    } else {
        return model.toJSON();
    }
}

function serverPath(req) {

    var path = req.url;
    var requrl = url.resolve(req.protocol + '://' + req.get('host'), path);
    return requrl.replace(/\/$/, "");
}

function findOwner(members, ownerJid) {

    if (members) {
        var owner = null;
        members.forEach(function (member) {
            if (member.roomMember.affiliation === 'owner') {
                if (member.jid) {
                    owner = new JID(member.jid).getLocal(true).toString();
                }
            }
        });
        return owner;
    } else if (ownerJid){
        return ownerJid.getLocal(true).toString();
    } else {
        return null;
    }
}

function roomToJSON(ownerJid, room, meetingsPath) {
    var jsonroom = room.toJSON();

    jsonroom.owner = findOwner(jsonroom.members, ownerJid);
    delete jsonroom.members;

    jsonroom.url = url.resolve(meetingsPath, querystring.escape(jsonroom.owner) + '/' + querystring.escape(jsonroom.name));
    return jsonroom;
}

function roomsToJSON(ownerJid, rooms, meetingsPath) {
    // add owner and url to json output
    var results = [];

    // add owner to outout
    rooms.forEach(function (room) {
        results.push(roomToJSON(ownerJid, room, meetingsPath));
    });

    return results;
}

module.exports = {
    getJID: getJID,
    exportJSON: exportJSON,
    serverPath: serverPath,
    roomToJSON: roomToJSON,
    roomsToJSON: roomsToJSON
};<commit_msg>fix original url recovery<commit_after>'use strict';

var JID = require('node-xmpp-core').JID,
    url = require('url'),
    querystring = require('querystring');

function getJID(req) {
    console.log(JSON.stringify(req.user));
    return new JID(req.user.jid);
}

function exportJSON(model) {
    if (model instanceof Array) {
        var exportVal = [];
        model.forEach(function (item) {
            exportVal.push(exportJSON(item));
        });
        return exportVal;
    } else if (model && typeof (model.exportJSON) === 'function') {
        return model.exportJSON();
    } else {
        return model.toJSON();
    }
}

function serverPath(req) {

    var path = req.originalUrl;
    var requrl = url.resolve(req.protocol + '://' + req.get('host'), path);
    return requrl.replace(/\/$/, "");
}

function findOwner(members, ownerJid) {

    if (members) {
        var owner = null;
        members.forEach(function (member) {
            if (member.roomMember.affiliation === 'owner') {
                if (member.jid) {
                    owner = new JID(member.jid).getLocal(true).toString();
                }
            }
        });
        return owner;
    } else if (ownerJid){
        return ownerJid.getLocal(true).toString();
    } else {
        return null;
    }
}

function roomToJSON(ownerJid, room, meetingsPath) {
    var jsonroom = room.toJSON();

    jsonroom.owner = findOwner(jsonroom.members, ownerJid);
    delete jsonroom.members;

    jsonroom.url = url.resolve(meetingsPath, querystring.escape(jsonroom.owner) + '/' + querystring.escape(jsonroom.name));
    return jsonroom;
}

function roomsToJSON(ownerJid, rooms, meetingsPath) {
    // add owner and url to json output
    var results = [];

    // add owner to outout
    rooms.forEach(function (room) {
        results.push(roomToJSON(ownerJid, room, meetingsPath));
    });

    return results;
}

module.exports = {
    getJID: getJID,
    exportJSON: exportJSON,
    serverPath: serverPath,
    roomToJSON: roomToJSON,
    roomsToJSON: roomsToJSON
};<|endoftext|>


<commit_before>'use strict'
/*

* relation definition
** extensional
*** defined by data
** intensional
*** defined by computation
*** potentially infinite modes
*** decidable modes may be precomputed
*** any mode may be memoized

* relation properties
** decidable
*** finite number of answers
*** may require tabling/memoization to terminate when calculating fixed points
** semi-deterministic
*** 0 or 1 answer

* negation
** allowed for any decidable goal

* constraints
** should be idempotent, unlike CHR
** lattice-based (a bit ad-hoc at the moment)
*** types (possibly other predicates?)
*** intervals
*** finite domains
*** (in)equalities
*** computations (e.g. arithmetic: a + b = c)
*** negated versions of the above

* stratification and analyses?

* higher level sugar
** multi-site definitions/assignments
*** definitions may be distributed across several source locations
** monotonic/merging assignment
*** merge operations must be commutative, associative, idempotent (CRDTs)
*** generalizes relation definition?
** perturbance-based assignment
*** optionally deferred
*** optionally pinned
**** pinned values are not changeable by future perturbances until unpinned
** conditionals
*** optionally multi-arm
*** optionally event/signal-based
** arithmetic (in)equalities
*** could be generalized to other structures/computations
**** e.g. (append a b) == (append c d)
** aggregation
** higher-order functional orchestration and communication

* terms
** atoms
*** boolean, exact, inexact (later), symbol
*** text is pseudo-atomic?
** compounds
*** tuple
**** unordered (record)
**** ordered (array)
*** set
**** monomorphic vs. polymorphic sets
****   boolean (ideal: two bits)
****   number  (ideal: intervals)
****   text    (ideal: some kind of trie/index?)
****   symbol  (ideal: also intervals?)
****   tuple ordered
****   tuple unordered
****   set (nested, so mono vs. poly again)
****   polymorphic
*** extensional relations are sets of unordered tuples

*/

function range(start, end) {
  var xs = []; xs.length = end - start;
  for (var ix = 0; ix + start < end; ++ix) {
    xs[ix] = ix + start;
  }
  return xs;
}

function bisect(xs, key, start, end) {
  while (start < end) {
    var mid = start + ((end - start) >> 1);
    var found = xs[mid];
    if      (key < found) { end = mid; }
    else if (key > found) { start = mid + 1; }
    else                  { return mid; }
  }
  return start;
}

function array_insert(xs, ix, val) {
  var rhs = xs.length;
  var ys = []; ys.length = rhs + 1;
  for (; ix < rhs; --rhs) { ys[rhs] = xs[rhs - 1]; }
  ys[ix] = val;
  while (--ix >= 0) { ys[ix] = xs[ix]; }
  return ys;
}
function array_replace(xs, ix, val) {
  var ys = xs.slice();
  ys[ix] = val;
  return ys;
}
function array_remove(xs, ix) {
  var len = xs.length - 1;
  var ys = []; ys.length = len;
  for (var j = 0; j < ix; ++j) { ys[j] = xs[j]; }
  for (; j < len; ++j) { ys[j] = xs[j + 1]; }
  return ys;
}
function array_insert_remove_right(xs, start, end, ix, val) {
  var lhs = start, rhs = end - 1;
  var ys = []; ys.length = end - start;
  var j = 0;
  for (; lhs < ix; ++j, ++lhs) { ys[j] = xs[lhs]; }
  ys[j] = val;
  for (++j; lhs < rhs; ++j, ++lhs) { ys[j] = xs[lhs]; }
  return ys;
}
function array_insert_remove_left(xs, start, end, ix, val) {
  var lhs = start, rhs = end - 1;
  var ys = []; ys.length = end - start;
  var j = 0;
  for (; ++lhs < ix; ++j) { ys[j] = xs[lhs]; }
  ys[j] = val;
  for (++j; lhs <= rhs; ++j, ++lhs) { ys[j] = xs[lhs]; }
  return ys;
}

var BTREE_BLOCK_SIZE_FULL = 8;
var BTREE_BLOCK_SIZE_HALF = BTREE_BLOCK_SIZE_FULL/2;
function btree_branch(keys, values, children) {
  return {'keys': keys, 'values': values, 'children': children};
}
function btree_leaf(keys, values) { return btree_branch(keys, values, null); }
function btree_step(path, bt, index) { path.push({'index': index, 'tree': bt}); }
var btree_empty = btree_leaf([], []);

function btree_get(bt, key) {
  while (true) {
    var keys = bt.keys;
    var klen = keys.length;
    var ix = bisect(keys, key, 0, klen);
    if (ix < klen && keys[ix] === key) { return bt.values[ix]; }
    var children = bt.children;
    if (!children) { return undefined; }
    bt = bt.children[ix];
  }
}

function btree_path_update(path, bt) {
  for (var ip = path.length - 1; ip >= 0; --ip) {
    var pseg = path[ip];
    var ix = pseg.index;
    var old = pseg.tree;
    var children = old.children.slice();
    children[ix] = bt;
    bt = btree_branch(old.keys, old.values, children);
  }
  return bt;
}

function btree_put(bt, key, value) {
  var original = bt;
  var path = [];
  while (true) {
    var keys = bt.keys;
    var klen = keys.length;
    var ix = bisect(keys, key, 0, klen);
    var children = bt.children;
    if (ix < klen && keys[ix] === key) {
      values = bt.values;
      if (values[ix] === value) { return original; }
      bt = btree_branch(keys, array_replace(values, ix, value), children);
      return btree_path_update(path, bt);
    }
    btree_step(path, bt, ix);
    if (!children) { return btree_path_insert(path, key, value, null, null); }
    bt = children[ix];
  }
}

function btree_path_insert(path, key, value, left, right) {
  for (var ip = path.length - 1; ip >= 0; --ip) {
    var pseg = path[ip];
    var ix = pseg.index;
    var old = pseg.tree;
    var keys = old.keys;
    var values = old.values;
    var children = old.children;
    var klen = keys.length;
    if (klen < BTREE_BLOCK_SIZE_FULL) {
      keys = array_insert(keys, ix, key);
      values = array_insert(values, ix, value);
      if (children) {
        children = array_insert(children, ix, left);
        children[ix + 1] = right;
      }
      path.length = ip;
      return btree_path_update(path, btree_branch(keys, values, children));
    } else {
      var kl, kr, vl, vr, chl = null, chr = null;
      if (ix < BTREE_BLOCK_SIZE_HALF) {
        kr = keys.slice(BTREE_BLOCK_SIZE_HALF, BTREE_BLOCK_SIZE_FULL);
        kl = array_insert_remove_right(keys, 0, BTREE_BLOCK_SIZE_HALF, ix, key);
        key = keys[BTREE_BLOCK_SIZE_HALF - 1];
        vr = values.slice(BTREE_BLOCK_SIZE_HALF, BTREE_BLOCK_SIZE_FULL);
        vl = array_insert_remove_right(values, 0, BTREE_BLOCK_SIZE_HALF, ix, value);
        value = keys[BTREE_BLOCK_SIZE_HALF - 1];
        if (children) {
          chr = children.slice(BTREE_BLOCK_SIZE_HALF, BTREE_BLOCK_SIZE_FULL + 1);
          chl = array_insert_remove_right(children, 0, BTREE_BLOCK_SIZE_HALF + 1, ix, left);
          chl[ix + 1] = right;
        }
      } else if (ix > BTREE_BLOCK_SIZE_HALF) {
        kl = keys.slice(0, BTREE_BLOCK_SIZE_HALF);
        kr = array_insert_remove_left(keys, BTREE_BLOCK_SIZE_HALF, BTREE_BLOCK_SIZE_FULL, ix, key);
        key = keys[BTREE_BLOCK_SIZE_HALF];
        vl = values.slice(0, BTREE_BLOCK_SIZE_HALF);
        vr = array_insert_remove_left(values, BTREE_BLOCK_SIZE_HALF, BTREE_BLOCK_SIZE_FULL, ix, value);
        value = keys[BTREE_BLOCK_SIZE_HALF];
        if (children) {
          chl = children.slice(0, BTREE_BLOCK_SIZE_HALF + 1);
          chr = array_insert_remove_left(children, BTREE_BLOCK_SIZE_HALF, BTREE_BLOCK_SIZE_FULL + 1, ix, left);
          chr[ix - BTREE_BLOCK_SIZE_HALF] = right;
        }
      } else {
        kl = keys.slice(0, BTREE_BLOCK_SIZE_HALF);
        kr = keys.slice(BTREE_BLOCK_SIZE_HALF, BTREE_BLOCK_SIZE_FULL);
        vl = values.slice(0, BTREE_BLOCK_SIZE_HALF);
        vr = values.slice(BTREE_BLOCK_SIZE_HALF, BTREE_BLOCK_SIZE_FULL);
        if (children) {
          chl = children.slice(0, BTREE_BLOCK_SIZE_HALF + 1);
          chr = children.slice(BTREE_BLOCK_SIZE_HALF, BTREE_BLOCK_SIZE_FULL + 1);
          chl[BTREE_BLOCK_SIZE_HALF] = left;
          chr[0] = right;
        }
      }
      left = btree_branch(kl, vl, chl);
      right = btree_branch(kr, vr, chr);
    }
  }
  return btree_branch([key], [value], [left, right]);
}

function btree_remove(bt, key) {
}

//function btree_join(bt0, bt1) {
//}
//function btree_meet(bt0, bt1) {
//}
//function btree_to_list(bt) {
//}

function btree_from_list(xs) {
  var bt = btree_empty;
  for (var ix = 0, len = xs.length; ix < len; ++ix) {
    key = xs[ix];
    bt = btree_put(bt, key, key);
  }
  return bt;
}

function sorted(xs) {
  var ys = xs.slice();
  ys.sort();
  return ys;
}
function sorted_by(cmp, xs) {
  var ys = xs.slice();
  ys.sort(cmp);
  return ys;
}
function compare_asc(n0, n1) { return n0 - n1; }
function compare_desc(n0, n1) { return n1 - n0; }

var string_interner = {'': true}; // ensure hash table mode
delete string_interner[''];
function string_interned(str) {
  string_interner[str] = true;
  var interned = Object.keys(symbols_interned)[0];
  delete string_interner[interned];
  return interned;
}

function is_boolean(term) { return typeof term === 'boolean'; }
function is_number(term)  { return typeof term === 'number'; }
function is_text(term)    { return typeof term === 'string'; }
function is_tuple(term)   { return typeof term === 'object'; }

function tagged(tag, payload) { return [tag, payload]; }
function tagged_tag(tg)       { return tg[0]; }
function tagged_payload(tg)   { return tg[1]; }

var tag_count = 0;
var boolean_tag = tag_count++;
var number_tag = tag_count++;
var text_tag = tag_count++;
var symbol_tag = tag_count++;
var set_tag = tag_count++;
var tuple_ordered_tag = tag_count++;
var tuple_unordered_tag = tag_count++;

var symbol_table = {};
var symbol_name = [];
function symbol_new(name) {
  var index = symbol_name.length;
  symbol_name.push(name);
  return tagged(symbol_tag, index);
}
function symbol(name) {
  name = string_interned(name);
  var sym = symbol_table[name];
  if (sym === undefined) {
    sym = symbol_new(name);
    symbol_table[str] = sym;
  }
  return sym;
}

function tuple_from_obj(obj) {
  var tuple = {};
  for (var name in obj) {
    tuple[symbol(name)[1]] = obj[name];
  }
  return tuple;
}
function tuple_insert(tup, key, value) {
  var tnew = {};
  for (var k in tup) {
    tnew[k] = tup[k];
  }
  // TODO: check for existing key and unify
  tnew[key] = value;
  return tnew;
}
function tuple_remove(tup, key) {
  var tnew = {};
  for (var k in tup) {
    if (k !== key) tnew[k] = tup[k];
  }
  return tnew;
}
function tuple_meet(t0, t1) {
  var tnew = {};
  for (var k in t0) {
    tnew[k] = t0[k];
  }
  for (var k in t1) {
    // TODO: check for existing key and unify
    tnew[k] = t1[k];
  }
  return tnew;
}

function is_symbol(term) { return tagged_tag(term) === symbol_tag; }
function is_set(term)    { return tagged_tag(term) === set_tag; }

var set_boolean_empty = 0;
function set_boolean_has(set, bool) { return (set & (1 << bool)) > 0; }
function set_boolean_add(set, bool) { return set | (1 << bool); }
function set_boolean_join(s0, s1)   { return s0 | s1; }
function set_boolean_meet(s0, s1)   { return s0 & s1; }

// https://www.npmjs.com/package/v8-natives
// node --allow-natives-syntax
// %HasFastProperties(obj)
// %GetOptimizationStatus(fn)
// %OptimizeFunctionOnNextCall(fn)
<commit_msg>Define array merge and extend<commit_after>'use strict'
/*

* relation definition
** extensional
*** defined by data
** intensional
*** defined by computation
*** potentially infinite modes
*** decidable modes may be precomputed
*** any mode may be memoized

* relation properties
** decidable
*** finite number of answers
*** may require tabling/memoization to terminate when calculating fixed points
** semi-deterministic
*** 0 or 1 answer

* negation
** allowed for any decidable goal

* constraints
** should be idempotent, unlike CHR
** lattice-based (a bit ad-hoc at the moment)
*** types (possibly other predicates?)
*** intervals
*** finite domains
*** (in)equalities
*** computations (e.g. arithmetic: a + b = c)
*** negated versions of the above

* stratification and analyses?

* higher level sugar
** multi-site definitions/assignments
*** definitions may be distributed across several source locations
** monotonic/merging assignment
*** merge operations must be commutative, associative, idempotent (CRDTs)
*** generalizes relation definition?
** perturbance-based assignment
*** optionally deferred
*** optionally pinned
**** pinned values are not changeable by future perturbances until unpinned
** conditionals
*** optionally multi-arm
*** optionally event/signal-based
** arithmetic (in)equalities
*** could be generalized to other structures/computations
**** e.g. (append a b) == (append c d)
** aggregation
** higher-order functional orchestration and communication

* terms
** atoms
*** boolean, exact, inexact (later), symbol
*** text is pseudo-atomic?
** compounds
*** tuple
**** unordered (record)
**** ordered (array)
*** set
**** monomorphic vs. polymorphic sets
****   boolean (ideal: two bits)
****   number  (ideal: intervals)
****   text    (ideal: some kind of trie/index?)
****   symbol  (ideal: also intervals?)
****   tuple ordered
****   tuple unordered
****   set (nested, so mono vs. poly again)
****   polymorphic
*** extensional relations are sets of unordered tuples

*/

function range(start, end) {
  var xs = []; xs.length = end - start;
  for (var ix = 0; ix + start < end; ++ix) {
    xs[ix] = ix + start;
  }
  return xs;
}

function bisect(xs, key, start, end) {
  while (start < end) {
    var mid = start + ((end - start) >> 1);
    var found = xs[mid];
    if      (key < found) { end = mid; }
    else if (key > found) { start = mid + 1; }
    else                  { return mid; }
  }
  return start;
}

function array_insert(xs, ix, val) {
  var rhs = xs.length;
  var ys = []; ys.length = rhs + 1;
  for (; ix < rhs; --rhs) { ys[rhs] = xs[rhs - 1]; }
  ys[ix] = val;
  while (--ix >= 0) { ys[ix] = xs[ix]; }
  return ys;
}
function array_replace(xs, ix, val) {
  var ys = xs.slice();
  ys[ix] = val;
  return ys;
}
function array_remove(xs, ix) {
  var len = xs.length - 1;
  var ys = []; ys.length = len;
  for (var j = 0; j < ix; ++j) { ys[j] = xs[j]; }
  for (; j < len; ++j) { ys[j] = xs[j + 1]; }
  return ys;
}
function array_insert_remove_right(xs, start, end, ix, val) {
  var lhs = start, rhs = end - 1;
  var ys = []; ys.length = end - start;
  var j = 0;
  for (; lhs < ix; ++j, ++lhs) { ys[j] = xs[lhs]; }
  ys[j] = val;
  for (++j; lhs < rhs; ++j, ++lhs) { ys[j] = xs[lhs]; }
  return ys;
}
function array_insert_remove_left(xs, start, end, ix, val) {
  var lhs = start, rhs = end - 1;
  var ys = []; ys.length = end - start;
  var j = 0;
  for (; ++lhs < ix; ++j) { ys[j] = xs[lhs]; }
  ys[j] = val;
  for (++j; lhs <= rhs; ++j, ++lhs) { ys[j] = xs[lhs]; }
  return ys;
}
function array_merge(xs, ys) { return xs.concat(ys); }
function array_merge_mid(xs, mid, ys) { return xs.concat([mid]).concat(ys); }
function array_extend(xs, ys) {
  var ix = xs.length;
  var len = ix + ys.length;
  xs.length = len;
  for (var j = 0; ix < len; ++ix, ++j) { xs[ix] = ys[j]; }
}

var BTREE_BLOCK_SIZE_FULL = 8;
var BTREE_BLOCK_SIZE_HALF = BTREE_BLOCK_SIZE_FULL/2;
function btree_branch(keys, values, children) {
  return {'keys': keys, 'values': values, 'children': children};
}
function btree_leaf(keys, values) { return btree_branch(keys, values, null); }
function btree_step(path, bt, index) { path.push({'index': index, 'tree': bt}); }
var btree_empty = btree_leaf([], []);

function btree_get(bt, key) {
  while (true) {
    var keys = bt.keys;
    var klen = keys.length;
    var ix = bisect(keys, key, 0, klen);
    if (ix < klen && keys[ix] === key) { return bt.values[ix]; }
    var children = bt.children;
    if (!children) { return undefined; }
    bt = bt.children[ix];
  }
}

function btree_path_update(path, bt) {
  for (var ip = path.length - 1; ip >= 0; --ip) {
    var pseg = path[ip];
    var ix = pseg.index;
    var old = pseg.tree;
    var children = old.children.slice();
    children[ix] = bt;
    bt = btree_branch(old.keys, old.values, children);
  }
  return bt;
}

function btree_put(bt, key, value) {
  var original = bt;
  var path = [];
  while (true) {
    var keys = bt.keys;
    var klen = keys.length;
    var ix = bisect(keys, key, 0, klen);
    var children = bt.children;
    if (ix < klen && keys[ix] === key) {
      values = bt.values;
      if (values[ix] === value) { return original; }
      bt = btree_branch(keys, array_replace(values, ix, value), children);
      return btree_path_update(path, bt);
    }
    btree_step(path, bt, ix);
    if (!children) { return btree_path_insert(path, key, value, null, null); }
    bt = children[ix];
  }
}

function btree_path_insert(path, key, value, left, right) {
  for (var ip = path.length - 1; ip >= 0; --ip) {
    var pseg = path[ip];
    var ix = pseg.index;
    var old = pseg.tree;
    var keys = old.keys;
    var values = old.values;
    var children = old.children;
    var klen = keys.length;
    if (klen < BTREE_BLOCK_SIZE_FULL) {
      keys = array_insert(keys, ix, key);
      values = array_insert(values, ix, value);
      if (children) {
        children = array_insert(children, ix, left);
        children[ix + 1] = right;
      }
      path.length = ip;
      return btree_path_update(path, btree_branch(keys, values, children));
    } else {
      var kl, kr, vl, vr, chl = null, chr = null;
      if (ix < BTREE_BLOCK_SIZE_HALF) {
        kr = keys.slice(BTREE_BLOCK_SIZE_HALF, BTREE_BLOCK_SIZE_FULL);
        kl = array_insert_remove_right(keys, 0, BTREE_BLOCK_SIZE_HALF, ix, key);
        key = keys[BTREE_BLOCK_SIZE_HALF - 1];
        vr = values.slice(BTREE_BLOCK_SIZE_HALF, BTREE_BLOCK_SIZE_FULL);
        vl = array_insert_remove_right(values, 0, BTREE_BLOCK_SIZE_HALF, ix, value);
        value = keys[BTREE_BLOCK_SIZE_HALF - 1];
        if (children) {
          chr = children.slice(BTREE_BLOCK_SIZE_HALF, BTREE_BLOCK_SIZE_FULL + 1);
          chl = array_insert_remove_right(children, 0, BTREE_BLOCK_SIZE_HALF + 1, ix, left);
          chl[ix + 1] = right;
        }
      } else if (ix > BTREE_BLOCK_SIZE_HALF) {
        kl = keys.slice(0, BTREE_BLOCK_SIZE_HALF);
        kr = array_insert_remove_left(keys, BTREE_BLOCK_SIZE_HALF, BTREE_BLOCK_SIZE_FULL, ix, key);
        key = keys[BTREE_BLOCK_SIZE_HALF];
        vl = values.slice(0, BTREE_BLOCK_SIZE_HALF);
        vr = array_insert_remove_left(values, BTREE_BLOCK_SIZE_HALF, BTREE_BLOCK_SIZE_FULL, ix, value);
        value = keys[BTREE_BLOCK_SIZE_HALF];
        if (children) {
          chl = children.slice(0, BTREE_BLOCK_SIZE_HALF + 1);
          chr = array_insert_remove_left(children, BTREE_BLOCK_SIZE_HALF, BTREE_BLOCK_SIZE_FULL + 1, ix, left);
          chr[ix - BTREE_BLOCK_SIZE_HALF] = right;
        }
      } else {
        kl = keys.slice(0, BTREE_BLOCK_SIZE_HALF);
        kr = keys.slice(BTREE_BLOCK_SIZE_HALF, BTREE_BLOCK_SIZE_FULL);
        vl = values.slice(0, BTREE_BLOCK_SIZE_HALF);
        vr = values.slice(BTREE_BLOCK_SIZE_HALF, BTREE_BLOCK_SIZE_FULL);
        if (children) {
          chl = children.slice(0, BTREE_BLOCK_SIZE_HALF + 1);
          chr = children.slice(BTREE_BLOCK_SIZE_HALF, BTREE_BLOCK_SIZE_FULL + 1);
          chl[BTREE_BLOCK_SIZE_HALF] = left;
          chr[0] = right;
        }
      }
      left = btree_branch(kl, vl, chl);
      right = btree_branch(kr, vr, chr);
    }
  }
  return btree_branch([key], [value], [left, right]);
}

function btree_remove(bt, key) {
}

//function btree_join(bt0, bt1) {
//}
//function btree_meet(bt0, bt1) {
//}
//function btree_to_list(bt) {
//}

function btree_from_list(xs) {
  var bt = btree_empty;
  for (var ix = 0, len = xs.length; ix < len; ++ix) {
    key = xs[ix];
    bt = btree_put(bt, key, key);
  }
  return bt;
}

function sorted(xs) {
  var ys = xs.slice();
  ys.sort();
  return ys;
}
function sorted_by(cmp, xs) {
  var ys = xs.slice();
  ys.sort(cmp);
  return ys;
}
function compare_asc(n0, n1) { return n0 - n1; }
function compare_desc(n0, n1) { return n1 - n0; }

var string_interner = {'': true}; // ensure hash table mode
delete string_interner[''];
function string_interned(str) {
  string_interner[str] = true;
  var interned = Object.keys(symbols_interned)[0];
  delete string_interner[interned];
  return interned;
}

function is_boolean(term) { return typeof term === 'boolean'; }
function is_number(term)  { return typeof term === 'number'; }
function is_text(term)    { return typeof term === 'string'; }
function is_tuple(term)   { return typeof term === 'object'; }

function tagged(tag, payload) { return [tag, payload]; }
function tagged_tag(tg)       { return tg[0]; }
function tagged_payload(tg)   { return tg[1]; }

var tag_count = 0;
var boolean_tag = tag_count++;
var number_tag = tag_count++;
var text_tag = tag_count++;
var symbol_tag = tag_count++;
var set_tag = tag_count++;
var tuple_ordered_tag = tag_count++;
var tuple_unordered_tag = tag_count++;

var symbol_table = {};
var symbol_name = [];
function symbol_new(name) {
  var index = symbol_name.length;
  symbol_name.push(name);
  return tagged(symbol_tag, index);
}
function symbol(name) {
  name = string_interned(name);
  var sym = symbol_table[name];
  if (sym === undefined) {
    sym = symbol_new(name);
    symbol_table[str] = sym;
  }
  return sym;
}

function tuple_from_obj(obj) {
  var tuple = {};
  for (var name in obj) {
    tuple[symbol(name)[1]] = obj[name];
  }
  return tuple;
}
function tuple_insert(tup, key, value) {
  var tnew = {};
  for (var k in tup) {
    tnew[k] = tup[k];
  }
  // TODO: check for existing key and unify
  tnew[key] = value;
  return tnew;
}
function tuple_remove(tup, key) {
  var tnew = {};
  for (var k in tup) {
    if (k !== key) tnew[k] = tup[k];
  }
  return tnew;
}
function tuple_meet(t0, t1) {
  var tnew = {};
  for (var k in t0) {
    tnew[k] = t0[k];
  }
  for (var k in t1) {
    // TODO: check for existing key and unify
    tnew[k] = t1[k];
  }
  return tnew;
}

function is_symbol(term) { return tagged_tag(term) === symbol_tag; }
function is_set(term)    { return tagged_tag(term) === set_tag; }

var set_boolean_empty = 0;
function set_boolean_has(set, bool) { return (set & (1 << bool)) > 0; }
function set_boolean_add(set, bool) { return set | (1 << bool); }
function set_boolean_join(s0, s1)   { return s0 | s1; }
function set_boolean_meet(s0, s1)   { return s0 & s1; }

// https://www.npmjs.com/package/v8-natives
// node --allow-natives-syntax
// %HasFastProperties(obj)
// %GetOptimizationStatus(fn)
// %OptimizeFunctionOnNextCall(fn)
<|endoftext|>


<commit_before>const path = require('path')
const webpack = require('webpack')
const UglifyJsPlugin = require('uglifyjs-webpack-plugin')

const packageJson = require('./package.json')
const env = process.env.NODE_ENV || 'development'
const version = packageJson.version
const link = packageJson.homepage

let plugins = [
  new webpack.DefinePlugin({ VERSION: JSON.stringify(version) })
]

const devTool = (env === 'test')
  ? 'inline-source-map'
  : 'source-map'

if (env === 'production') {
  plugins = plugins.concat([
    new webpack.BannerPlugin({
      banner: `/*!\n * Mappersmith ${version}\n * ${link}\n */`,
      raw: true,
      entryOnly: true
    })
  ])
}

module.exports = {
  mode: env === 'production' ? 'production' : 'development',
  context: __dirname,
  resolve: {
    modules: [
      path.join(__dirname, '/node_modules'),
      __dirname
    ]
  },
  entry: './src/index.js',
  output: {
    path: path.resolve(__dirname, 'dist/'),
    filename: 'mappersmith.js',
    sourceMapFilename: 'mappersmith.map',
    library: 'mappersmith',
    libraryTarget: 'umd'
  },
  target: 'web',
  node: {
    process: false
  },
  optimization: {
    minimizer: [
      new UglifyJsPlugin({
        sourceMap: true,
        uglifyOptions: {
          compress: { warnings: false }
        }
      })
    ]
  },
  plugins: plugins,
  devtool: devTool,
  module: {
    rules: [
      { test: /\.js$/, exclude: /node_modules/, use: 'babel-loader' }
    ]
  }
}
<commit_msg>Fix npm run build<commit_after>const path = require('path')
const webpack = require('webpack')
const UglifyJsPlugin = require('uglifyjs-webpack-plugin')

const packageJson = require('./package.json')
const env = process.env.NODE_ENV || 'development'
const version = packageJson.version
const link = packageJson.homepage

let plugins = [
  new webpack.DefinePlugin({ VERSION: JSON.stringify(version) })
]

const devTool = (env === 'test')
  ? 'inline-source-map'
  : 'source-map'

if (env === 'production') {
  plugins = plugins.concat([
    new webpack.BannerPlugin({
      banner: `/*!\n * Mappersmith ${version}\n * ${link}\n */`,
      raw: true,
      entryOnly: true
    })
  ])
}

module.exports = {
  mode: env === 'production' ? 'production' : 'development',
  context: __dirname,
  resolve: {
    modules: [
      path.join(__dirname, '/node_modules'),
      __dirname
    ]
  },
  entry: './src/index.js',
  output: {
    path: path.resolve(__dirname, 'dist/'),
    filename: 'mappersmith.js',
    sourceMapFilename: 'mappersmith.map',
    library: 'mappersmith',
    libraryTarget: 'umd'
  },
  target: 'web',
  node: {
    process: false
  },
  optimization: {
    minimizer: [
      new UglifyJsPlugin({
        sourceMap: true,
        uglifyOptions: {
          warnings: false
        }
      })
    ]
  },
  plugins: plugins,
  devtool: devTool,
  module: {
    rules: [
      { test: /\.js$/, exclude: /node_modules/, use: 'babel-loader' }
    ]
  }
}
<|endoftext|>


<commit_before>var seriesStyles = [
  // See: https://www.nig.ac.jp/color/gen/#color
  {strokeStyle: 'rgb(230, 159, 0)', fillStyle: 'rgba(230, 159, 0, 0.3)', lineWidth: 2},
  {strokeStyle: 'rgb(86, 180, 233)', fillStyle: 'rgba(86, 180, 233, 0.3)', lineWidth: 2},
  {strokeStyle: 'rgb(0, 158, 115)', fillStyle: 'rgba(0, 158, 115, 0.3)', lineWidth: 2}
];

var series = null;
var reconnectIntervalID = null;
var messageElement = document.getElementById('message');
var smoothie = new SmoothieChart();
smoothie.streamTo(document.getElementById('graph'), 1000);

var wsProtocol = (location.protocol === 'https:') ? 'wss://' : 'ws://';
var wsUri = wsProtocol + location.host + '/ws';
console.log(wsUri);

showMessage('Connnecting...');
connect();

function connect() {
  var websocket = new WebSocket(wsUri);
  websocket.onmessage = function(evt) {
    var metrics = JSON.parse(evt.data);
    //console.log(metrics);
    if (series === null || series.length != metrics.metrics.length) {
      resetSeries(metrics.metrics.length);
    }

    var t = new Date();
    t.setTime(metrics.time);
    var message = t.toLocaleString();

    metrics.metrics.forEach(function(metric, i) {
      series[i].append(metrics.time, metric.value);
      message += '\n' + metric.label + ': ' + metric.value;
    });

    showMessage(message);
  };
  websocket.onerror = function(evt) {
    //showMessage('Failed to connect');
  };
  websocket.onopen = function(evt) {
    showMessage('Sucessfully connected.');
    if (reconnectIntervalID !== null) {
      clearInterval(reconnectIntervalID);
      reconnectIntervalID = null;
    }
  };
  websocket.onclose = function(evt) {
    var sleep = 5;
    showMessage('Connection closed. Try reconnecting every ' + sleep + ' seconds.');

    if (reconnectIntervalID === null) {
      reconnectIntervalID = setInterval(function() {
        connect();
      }, sleep * 1000);
    }
  };
}

function resetSeries(numSeries) {
  if (series !== null) {
    series.forEach(function(s) {
      smoothie.removeTimeSeries(s);
    });
  }

  series = [];
  for (var i = 0; i < numSeries; i++) {
    var s = new TimeSeries();
    series.push(s);
    smoothie.addTimeSeries(s, seriesStyles[i]);
  }
}

function showMessage(text) {
  messageElement.innerHTML = '';
  text.split(/\n/).forEach(function(line) {
    messageElement.appendChild(document.createTextNode(line));
    messageElement.appendChild(document.createElement('br'));
  });
}
<commit_msg>Use setTimeout instead of setInterval to simplify codes<commit_after>var seriesStyles = [
  // See: https://www.nig.ac.jp/color/gen/#color
  {strokeStyle: 'rgb(230, 159, 0)', fillStyle: 'rgba(230, 159, 0, 0.3)', lineWidth: 2},
  {strokeStyle: 'rgb(86, 180, 233)', fillStyle: 'rgba(86, 180, 233, 0.3)', lineWidth: 2},
  {strokeStyle: 'rgb(0, 158, 115)', fillStyle: 'rgba(0, 158, 115, 0.3)', lineWidth: 2}
];

var series = null;
var messageElement = document.getElementById('message');
var smoothie = new SmoothieChart();
smoothie.streamTo(document.getElementById('graph'), 1000);

var wsProtocol = (location.protocol === 'https:') ? 'wss://' : 'ws://';
var wsUri = wsProtocol + location.host + '/ws';
console.log(wsUri);

showMessage('Connnecting...');
connect();

function connect() {
  var websocket = new WebSocket(wsUri);
  websocket.onmessage = function(evt) {
    var metrics = JSON.parse(evt.data);
    //console.log(metrics);
    if (series === null || series.length != metrics.metrics.length) {
      resetSeries(metrics.metrics.length);
    }

    var t = new Date();
    t.setTime(metrics.time);
    var message = t.toLocaleString();

    metrics.metrics.forEach(function(metric, i) {
      series[i].append(metrics.time, metric.value);
      message += '\n' + metric.label + ': ' + metric.value;
    });

    showMessage(message);
  };
  websocket.onerror = function(evt) {
    //showMessage('Failed to connect');
  };
  websocket.onopen = function(evt) {
    showMessage('Sucessfully connected.');
  };
  websocket.onclose = function(evt) {
    var sleep = 5;
    showMessage('Connection closed. Try reconnecting every ' + sleep + ' seconds.');

    setTimeout(function() {
      connect();
    }, sleep * 1000);
  };
}

function resetSeries(numSeries) {
  if (series !== null) {
    series.forEach(function(s) {
      smoothie.removeTimeSeries(s);
    });
  }

  series = [];
  for (var i = 0; i < numSeries; i++) {
    var s = new TimeSeries();
    series.push(s);
    smoothie.addTimeSeries(s, seriesStyles[i]);
  }
}

function showMessage(text) {
  messageElement.innerHTML = '';
  text.split(/\n/).forEach(function(line) {
    messageElement.appendChild(document.createTextNode(line));
    messageElement.appendChild(document.createElement('br'));
  });
}
<|endoftext|>


<commit_before>// karma config info: http://karma-runner.github.io/0.12/config/configuration-file.html
var webpack           = require('webpack');
const webpackConfig = require('./webpack.config')('test');

module.exports = () => {
  const testConfig = {

    // If browser does not capture in given timeout [ms], kill it
    captureTimeout: 60000,

    // How long will Karma wait for a message from a browser before disconnecting from it (in ms)
    browserNoActivityTimeout: 60000,

    // enable / disable colors in the output (reporters and logs)
    colors: true,

    // web server port
    port: 9876,

    files: [
      './specs_support/mocks/*.js',
      './specs_support/spec_helper.js',
      // Use webpack to build each test individually. If changed here, change in preprocessors
      // './js/**/*.spec.js'
      './webpack.tests.js',          // More performant but tests cannot be run individually
    ],

    // Transpile tests with the karma-webpack plugin
    preprocessors: {
      // Use webpack to build each test individually. If changed here, match the change in files
      // './js/**/*.spec.js': ['webpack', 'sourcemap']
      './webpack.tests.js': ['webpack', 'sourcemap', 'coverage'],      // More performant but tests cannot be run individually
      // './js/**/*.js*': 'coverage',
    },

    // Run the tests using any of the following browsers
    // - Chrome         npm install --save-dev karma-chrome-launcher
    // - ChromeCanary
    // - Firefox        npm install --save-dev karma-firefox-launcher
    // - Opera          npm install --save-dev karma-opera-launcher
    // - Safari         npm install --save-dev karma-safari-launcher  (only Mac)
    // - PhantomJS      npm install --save-dev karma-phantomjs-launcher
    // - IE             npm install karma-ie-launcher (only Windows)
    browsers: ['Chrome'],

    // Exit the test runner as well when the test suite returns.
    singleRun: false,

    // enable / disable watching file and executing tests whenever any file changes
    autoWatch: true,

    // Use jasmine as the test framework
    frameworks: ['jasmine-ajax', 'jasmine'],

    // possible values: 'dots', 'progress', 'junit', 'growl', 'coverage', 'spec'
    reporters: ['dots', 'coverage'],

    // karma-webpack configuration. Load and transpile js and jsx files.
    // Use istanbul-transformer post loader to generate code coverage report.
    webpack: {
      devtool: 'eval',
      plugins: webpackConfig.plugins,
      module: webpackConfig.module,
      resolve: webpackConfig.resolve,
    },

    // Reduce the noise to the console
    webpackMiddleware: {
      noInfo: true,
      stats: {
        colors: true,
      },
    },

    coverageReporter: {
      type: 'lcovonly',
      dir: '../coverage/',
      file: 'coverage.info',
    },
  };
  return testConfig;
};
<commit_msg>Format for aslant<commit_after>// karma config info: http://karma-runner.github.io/0.12/config/configuration-file.html
const webpack       = require('webpack');
const webpackConfig = require('./webpack.config')('test');

module.exports = () => {
  const testConfig = {

    // If browser does not capture in given timeout [ms], kill it
    captureTimeout: 60000,

    // How long will Karma wait for a message from a browser before disconnecting from it (in ms)
    browserNoActivityTimeout: 60000,

    // enable / disable colors in the output (reporters and logs)
    colors: true,

    // web server port
    port: 9876,

    files: [
      './specs_support/mocks/*.js',
      './specs_support/spec_helper.js',
      // Use webpack to build each test individually. If changed here, change in preprocessors
      // './js/**/*.spec.js'
      './webpack.tests.js',          // More performant but tests cannot be run individually
    ],

    // Transpile tests with the karma-webpack plugin
    preprocessors: {
      // Use webpack to build each test individually. If changed here, match the change in files
      // './js/**/*.spec.js': ['webpack', 'sourcemap']
      './webpack.tests.js': ['webpack', 'sourcemap', 'coverage'],      // More performant but tests cannot be run individually
      // './js/**/*.js*': 'coverage',
    },

    // Run the tests using any of the following browsers
    // - Chrome         npm install --save-dev karma-chrome-launcher
    // - ChromeCanary
    // - Firefox        npm install --save-dev karma-firefox-launcher
    // - Opera          npm install --save-dev karma-opera-launcher
    // - Safari         npm install --save-dev karma-safari-launcher  (only Mac)
    // - PhantomJS      npm install --save-dev karma-phantomjs-launcher
    // - IE             npm install karma-ie-launcher (only Windows)
    browsers: ['Chrome'],

    // Exit the test runner as well when the test suite returns.
    singleRun: false,

    // enable / disable watching file and executing tests whenever any file changes
    autoWatch: true,

    // Use jasmine as the test framework
    frameworks: ['jasmine-ajax', 'jasmine'],

    // possible values: 'dots', 'progress', 'junit', 'growl', 'coverage', 'spec'
    reporters: ['dots', 'coverage'],

    // karma-webpack configuration. Load and transpile js and jsx files.
    // Use istanbul-transformer post loader to generate code coverage report.
    webpack: {
      devtool : 'eval',
      plugins : webpackConfig.plugins,
      module  : webpackConfig.module,
      resolve : webpackConfig.resolve,
    },

    // Reduce the noise to the console
    webpackMiddleware: {
      noInfo : true,
      stats  : {
        colors: true,
      },
    },

    coverageReporter: {
      type : 'lcovonly',
      dir  : '../coverage/',
      file : 'coverage.info',
    },
  };
  return testConfig;
};
<|endoftext|>


<commit_before>(function (global, factory) {
  typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('d3-interpolate')) :
  typeof define === 'function' && define.amd ? define(['exports', 'd3-interpolate'], factory) :
  (factory((global.d3 = global.d3 || {}),global.d3));
}(this, (function (exports,d3Interpolate) { 'use strict';

/**
 * List of params for each command type in a path `d` attribute
 */
var typeMap = {
  M: ['x', 'y'],
  L: ['x', 'y'],
  H: ['x'],
  V: ['y'],
  C: ['x1', 'y1', 'x2', 'y2', 'x', 'y'],
  S: ['x2', 'y2', 'x', 'y'],
  Q: ['x1', 'y1', 'x', 'y'],
  T: ['x', 'y'],
  A: ['rx', 'ry', 'xAxisRotation', 'largeArcFlag', 'sweepFlag', 'x', 'y']
};

/**
 * Convert to object representation of the command from a string
 *
 * @param {String} commandString Token string from the `d` attribute (e.g., L0,0)
 * @return {Object} An object representing this command.
 */
function commandObject(commandString) {
  // convert all spaces to commas
  commandString = commandString.trim().replace(/ /g, ',');

  var type = commandString[0];
  var args = commandString.substring(1).split(',');
  return typeMap[type.toUpperCase()].reduce(function (obj, param, i) {
    // parse X as float since we need it to do distance checks for extending points
    obj[param] = param === 'x' ? parseFloat(args[i]) : args[i];
    return obj;
  }, { type: type });
}

/**
 * Converts a command object to a string to be used in a `d` attribute
 * @param {Object} command A command object
 * @return {String} The string for the `d` attribute
 */
function commandToString(command) {
  var type = command.type;

  var params = typeMap[type.toUpperCase()];
  return '' + type + params.map(function (p) {
    return command[p];
  }).join(',');
}

/**
 * Converts command A to have the same type as command B.
 *
 * e.g., L0,5 -> C0,5,0,5,0,5
 *
 * Uses these rules:
 * x1 <- x
 * x2 <- x
 * y1 <- y
 * y2 <- y
 * rx <- 0
 * ry <- 0
 * xAxisRotation <- read from B
 * largeArcFlag <- read from B
 * sweepflag <- read from B
 *
 * @param {Object} aCommand Command object from path `d` attribute
 * @param {Object} bCommand Command object from path `d` attribute to match against
 * @return {Object} aCommand converted to type of bCommand
 */
function convertToSameType(aCommand, bCommand) {
  var conversionMap = {
    x1: 'x',
    y1: 'y',
    x2: 'x',
    y2: 'y'
  };

  var readFromBKeys = ['xAxisRotation', 'largeArcFlag', 'sweepFlag'];

  // convert (but ignore M types)
  if (aCommand.type !== bCommand.type && bCommand.type.toUpperCase() !== 'M') {
    (function () {
      var aConverted = {};
      Object.keys(bCommand).forEach(function (bKey) {
        var bValue = bCommand[bKey];
        // first read from the A command
        var aValue = aCommand[bKey];

        // if it is one of these values, read from B no matter what
        if (aValue === undefined) {
          if (readFromBKeys.includes(bKey)) {
            aValue = bValue;
          } else {
            // if it wasn't in the A command, see if an equivalent was
            if (aValue === undefined && conversionMap[bKey]) {
              aValue = aCommand[conversionMap[bKey]];
            }

            // if it doesn't have a converted value, use 0
            if (aValue === undefined) {
              aValue = 0;
            }
          }
        }

        aConverted[bKey] = aValue;
      });

      // update the type to match B
      aConverted.type = bCommand.type;
      aCommand = aConverted;
    })();
  }

  return aCommand;
}

/**
 * Extends an array of commands to the length of the second array
 * inserting points at the spot that is closest by X value. Ensures
 * all the points of commandsToExtend are in the extended array and that
 * only numPointsToExtend points are added.
 *
 * @param {Object[]} commandsToExtend The commands array to extend
 * @param {Object[]} referenceCommands The commands array to match
 * @return {Object[]} The extended commands1 array
 */
function extend(commandsToExtend, referenceCommands, numPointsToExtend) {
  // map each command in B to a command in A by counting how many times ideally
  // a command in A was in the initial path
  var counts = referenceCommands.reduce(function (counts, refCommand) {
    var minDistance = Math.abs(commandsToExtend[0].x - refCommand.x);
    var minCommand = 0;
    // find the closest point by X position in A
    for (var j = 1; j < commandsToExtend.length; j++) {
      var distance = Math.abs(commandsToExtend[j].x - refCommand.x);
      if (distance < minDistance) {
        minDistance = distance;
        minCommand = j;
        // since we assume sorted by X, once we find a value farther, we can return the min.
      } else {
        break;
      }
    }

    counts[minCommand] = (counts[minCommand] || 0) + 1;
    return counts;
  }, {});

  // now extend the array adding in at the appropriate place as needed
  var extended = [];
  var numExtended = 0;
  for (var i = 0; i < commandsToExtend.length; i++) {
    // add in the initial point for this A command
    extended.push(commandsToExtend[i]);

    for (var j = 1; j < counts[i] && numExtended < numPointsToExtend; j++) {
      var commandToAdd = Object.assign({}, commandsToExtend[i]);
      // don't allow multiple Ms
      if (commandToAdd.type === 'M') {
        commandToAdd.type = 'L';
      } else {
        // try to set control points to x and y
        if (commandToAdd.x1 !== undefined) {
          commandToAdd.x1 = commandToAdd.x;
          commandToAdd.y1 = commandToAdd.y;
        }

        if (commandToAdd.x2 !== undefined) {
          commandToAdd.x2 = commandToAdd.x;
          commandToAdd.y2 = commandToAdd.y;
        }
      }
      extended.push(commandToAdd);
      numExtended += 1;
    }
  }

  return extended;
}

/**
 * Interpolate from A to B by extending A and B during interpolation to have
 * the same number of points. This allows for a smooth transition when they
 * have a different number of points.
 *
 * Ignores the `Z` character in paths unless both A and B end with it.
 *
 * @param {String} a The `d` attribute for a path
 * @param {String} b The `d` attribute for a path
 */
function interpolatePath(a, b) {
  // remove Z, remove spaces after letters as seen in IE
  var aNormalized = a == null ? '' : a.replace(/[Z]/gi, '').replace(/([MLCSTQAHV])\W*/gi, '$1');
  var bNormalized = b == null ? '' : b.replace(/[Z]/gi, '').replace(/([MLCSTQAHV])\W*/gi, '$1');
  var aPoints = aNormalized === '' ? [] : aNormalized.split(/(?=[MLCSTQAHV])/gi);
  var bPoints = bNormalized === '' ? [] : bNormalized.split(/(?=[MLCSTQAHV])/gi);

  // if both are empty, interpolation is always the empty string.
  if (!aPoints.length && !bPoints.length) {
    return function nullInterpolator() {
      return '';
    };
  }

  // if A is empty, treat it as if it used to contain just the first point
  // of B. This makes it so the line extends out of from that first point.
  if (!aPoints.length) {
    aPoints.push(bPoints[0]);

    // otherwise if B is empty, treat it as if it contains the first point
    // of A. This makes it so the line retracts into the first point.
  } else if (!bPoints.length) {
    bPoints.push(aPoints[0]);
  }

  // convert to command objects so we can match types
  var aCommands = aPoints.map(commandObject);
  var bCommands = bPoints.map(commandObject);

  // extend to match equal size
  var numPointsToExtend = Math.abs(bPoints.length - aPoints.length);

  if (numPointsToExtend !== 0) {
    // B has more points than A, so add points to A before interpolating
    if (bCommands.length > aCommands.length) {
      aCommands = extend(aCommands, bCommands, numPointsToExtend);

      // else if A has more points than B, add more points to B
    } else if (bCommands.length < aCommands.length) {
      bCommands = extend(bCommands, aCommands, numPointsToExtend);
    }
  }

  // commands have same length now.
  // convert A to the same type of B
  aCommands = aCommands.map(function (aCommand, i) {
    return convertToSameType(aCommand, bCommands[i]);
  });

  var aProcessed = aCommands.map(commandToString).join('');
  var bProcessed = bCommands.map(commandToString).join('');

  // if both A and B end with Z add it back in
  if ((a == null || a[a.length - 1] === 'Z') && (b == null || b[b.length - 1] === 'Z')) {
    aProcessed += 'Z';
    bProcessed += 'Z';
  }

  var stringInterpolator = d3Interpolate.interpolateString(aProcessed, bProcessed);

  return function pathInterpolator(t) {
    // at 1 return the final value without the extensions used during interpolation
    if (t === 1) {
      return b == null ? '' : b;
    }

    return stringInterpolator(t);
  };
}

exports.interpolatePath = interpolatePath;

Object.defineProperty(exports, '__esModule', { value: true });

})));<commit_msg>Update example build<commit_after>(function (global, factory) {
  typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('d3-interpolate')) :
  typeof define === 'function' && define.amd ? define(['exports', 'd3-interpolate'], factory) :
  (factory((global.d3 = global.d3 || {}),global.d3));
}(this, (function (exports,d3Interpolate) { 'use strict';

/**
 * List of params for each command type in a path `d` attribute
 */
var typeMap = {
  M: ['x', 'y'],
  L: ['x', 'y'],
  H: ['x'],
  V: ['y'],
  C: ['x1', 'y1', 'x2', 'y2', 'x', 'y'],
  S: ['x2', 'y2', 'x', 'y'],
  Q: ['x1', 'y1', 'x', 'y'],
  T: ['x', 'y'],
  A: ['rx', 'ry', 'xAxisRotation', 'largeArcFlag', 'sweepFlag', 'x', 'y']
};

/**
 * Convert to object representation of the command from a string
 *
 * @param {String} commandString Token string from the `d` attribute (e.g., L0,0)
 * @return {Object} An object representing this command.
 */
function commandObject(commandString) {
  // convert all spaces to commas
  commandString = commandString.trim().replace(/ /g, ',');

  var type = commandString[0];
  var args = commandString.substring(1).split(',');
  return typeMap[type.toUpperCase()].reduce(function (obj, param, i) {
    // parse X as float since we need it to do distance checks for extending points
    obj[param] = param === 'x' ? parseFloat(args[i]) : args[i];
    return obj;
  }, { type: type });
}

/**
 * Converts a command object to a string to be used in a `d` attribute
 * @param {Object} command A command object
 * @return {String} The string for the `d` attribute
 */
function commandToString(command) {
  var type = command.type;

  var params = typeMap[type.toUpperCase()];
  return '' + type + params.map(function (p) {
    return command[p];
  }).join(',');
}

/**
 * Converts command A to have the same type as command B.
 *
 * e.g., L0,5 -> C0,5,0,5,0,5
 *
 * Uses these rules:
 * x1 <- x
 * x2 <- x
 * y1 <- y
 * y2 <- y
 * rx <- 0
 * ry <- 0
 * xAxisRotation <- read from B
 * largeArcFlag <- read from B
 * sweepflag <- read from B
 *
 * @param {Object} aCommand Command object from path `d` attribute
 * @param {Object} bCommand Command object from path `d` attribute to match against
 * @return {Object} aCommand converted to type of bCommand
 */
function convertToSameType(aCommand, bCommand) {
  var conversionMap = {
    x1: 'x',
    y1: 'y',
    x2: 'x',
    y2: 'y'
  };

  var readFromBKeys = ['xAxisRotation', 'largeArcFlag', 'sweepFlag'];

  // convert (but ignore M types)
  if (aCommand.type !== bCommand.type && bCommand.type.toUpperCase() !== 'M') {
    (function () {
      var aConverted = {};
      Object.keys(bCommand).forEach(function (bKey) {
        var bValue = bCommand[bKey];
        // first read from the A command
        var aValue = aCommand[bKey];

        // if it is one of these values, read from B no matter what
        if (aValue === undefined) {
          if (readFromBKeys.includes(bKey)) {
            aValue = bValue;
          } else {
            // if it wasn't in the A command, see if an equivalent was
            if (aValue === undefined && conversionMap[bKey]) {
              aValue = aCommand[conversionMap[bKey]];
            }

            // if it doesn't have a converted value, use 0
            if (aValue === undefined) {
              aValue = 0;
            }
          }
        }

        aConverted[bKey] = aValue;
      });

      // update the type to match B
      aConverted.type = bCommand.type;
      aCommand = aConverted;
    })();
  }

  return aCommand;
}

/**
 * Extends an array of commands to the length of the second array
 * inserting points at the spot that is closest by X value. Ensures
 * all the points of commandsToExtend are in the extended array and that
 * only numPointsToExtend points are added.
 *
 * @param {Object[]} commandsToExtend The commands array to extend
 * @param {Object[]} referenceCommands The commands array to match
 * @return {Object[]} The extended commands1 array
 */
function extend(commandsToExtend, referenceCommands, numPointsToExtend) {
  // map each command in B to a command in A by counting how many times ideally
  // a command in A was in the initial path (see https://github.com/pbeshai/d3-interpolate-path/issues/8)
  var initialCommandIndex = commandsToExtend.length > 1 && commandsToExtend[0].type === 'M' ? 1 : 0;

  var counts = referenceCommands.reduce(function (counts, refCommand, i) {
    // skip first M
    if (i === 0 && refCommand.type === 'M') {
      counts[0] = 1;
      return counts;
    }

    var minDistance = Math.abs(commandsToExtend[initialCommandIndex].x - refCommand.x);
    var minCommand = initialCommandIndex;

    // find the closest point by X position in A
    for (var j = initialCommandIndex + 1; j < commandsToExtend.length; j++) {
      var distance = Math.abs(commandsToExtend[j].x - refCommand.x);
      if (distance < minDistance) {
        minDistance = distance;
        minCommand = j;
        // since we assume sorted by X, once we find a value farther, we can return the min.
      } else {
        break;
      }
    }

    counts[minCommand] = (counts[minCommand] || 0) + 1;
    return counts;
  }, {});

  // now extend the array adding in at the appropriate place as needed
  var extended = [];
  var numExtended = 0;
  for (var i = 0; i < commandsToExtend.length; i++) {
    // add in the initial point for this A command
    extended.push(commandsToExtend[i]);

    for (var j = 1; j < counts[i] && numExtended < numPointsToExtend; j++) {
      var commandToAdd = Object.assign({}, commandsToExtend[i]);
      // don't allow multiple Ms
      if (commandToAdd.type === 'M') {
        commandToAdd.type = 'L';
      } else {
        // try to set control points to x and y
        if (commandToAdd.x1 !== undefined) {
          commandToAdd.x1 = commandToAdd.x;
          commandToAdd.y1 = commandToAdd.y;
        }

        if (commandToAdd.x2 !== undefined) {
          commandToAdd.x2 = commandToAdd.x;
          commandToAdd.y2 = commandToAdd.y;
        }
      }
      extended.push(commandToAdd);
      numExtended += 1;
    }
  }

  return extended;
}

/**
 * Interpolate from A to B by extending A and B during interpolation to have
 * the same number of points. This allows for a smooth transition when they
 * have a different number of points.
 *
 * Ignores the `Z` character in paths unless both A and B end with it.
 *
 * @param {String} a The `d` attribute for a path
 * @param {String} b The `d` attribute for a path
 */
function interpolatePath(a, b) {
  // remove Z, remove spaces after letters as seen in IE
  var aNormalized = a == null ? '' : a.replace(/[Z]/gi, '').replace(/([MLCSTQAHV])\W*/gi, '$1');
  var bNormalized = b == null ? '' : b.replace(/[Z]/gi, '').replace(/([MLCSTQAHV])\W*/gi, '$1');
  var aPoints = aNormalized === '' ? [] : aNormalized.split(/(?=[MLCSTQAHV])/gi);
  var bPoints = bNormalized === '' ? [] : bNormalized.split(/(?=[MLCSTQAHV])/gi);

  // if both are empty, interpolation is always the empty string.
  if (!aPoints.length && !bPoints.length) {
    return function nullInterpolator() {
      return '';
    };
  }

  // if A is empty, treat it as if it used to contain just the first point
  // of B. This makes it so the line extends out of from that first point.
  if (!aPoints.length) {
    aPoints.push(bPoints[0]);

    // otherwise if B is empty, treat it as if it contains the first point
    // of A. This makes it so the line retracts into the first point.
  } else if (!bPoints.length) {
    bPoints.push(aPoints[0]);
  }

  // convert to command objects so we can match types
  var aCommands = aPoints.map(commandObject);
  var bCommands = bPoints.map(commandObject);

  // extend to match equal size
  var numPointsToExtend = Math.abs(bPoints.length - aPoints.length);

  if (numPointsToExtend !== 0) {
    // B has more points than A, so add points to A before interpolating
    if (bCommands.length > aCommands.length) {
      aCommands = extend(aCommands, bCommands, numPointsToExtend);

      // else if A has more points than B, add more points to B
    } else if (bCommands.length < aCommands.length) {
      bCommands = extend(bCommands, aCommands, numPointsToExtend);
    }
  }

  // commands have same length now.
  // convert A to the same type of B
  aCommands = aCommands.map(function (aCommand, i) {
    return convertToSameType(aCommand, bCommands[i]);
  });

  var aProcessed = aCommands.map(commandToString).join('');
  var bProcessed = bCommands.map(commandToString).join('');

  // if both A and B end with Z add it back in
  if ((a == null || a[a.length - 1] === 'Z') && (b == null || b[b.length - 1] === 'Z')) {
    aProcessed += 'Z';
    bProcessed += 'Z';
  }

  var stringInterpolator = d3Interpolate.interpolateString(aProcessed, bProcessed);

  return function pathInterpolator(t) {
    // at 1 return the final value without the extensions used during interpolation
    if (t === 1) {
      return b == null ? '' : b;
    }

    return stringInterpolator(t);
  };
}

exports.interpolatePath = interpolatePath;

Object.defineProperty(exports, '__esModule', { value: true });

})));<|endoftext|>