<commit_before>function openInNewTab(url)
{
    window.open(url, '_blank');
    window.focus();
}

function showDetails(uid) {
    var Element = document.getElementById('table' + uid);
    if (Element.classList.contains('tCompact')) {
        Element.classList.remove('tCompact');
        Element.childNodes[0].childNodes[2].classList.remove('hideRow');
        Element.childNodes[0].childNodes[3].classList.remove('hideRow');
        Element.childNodes[0].childNodes[5].classList.remove('hideRow');
    }
    else {
        Element.classList.add('tCompact');
        addClass(Element.childNodes[0].childNodes[2], 'hideRow');
        addClass(Element.childNodes[0].childNodes[3], 'hideRow');
        addClass(Element.childNodes[0].childNodes[5], 'hideRow');
    }
}

function submitForm() {
    var FormElement = document.getElementById('searchForm');
    FormElement.submit();
}

function checkForEnter (event) {
    var keyCode = ('which' in event) ? event.which : event.keyCode;

    if (keyCode == '13') {
        sendMsg('userSelect', 'sendMessage')
    }
    return true;
}

function newAJAX()
{
    var AJAX = null;
    if (window.XMLHttpRequest)
    {
        AJAX=new XMLHttpRequest();
    } else {
        AJAX=new ActiveXObject("Microsoft.XMLHTTP");
    }
    return AJAX;
}

function sendStatus(Id, Uid)
{
    var AJAX = newAJAX();
    if (AJAX == null)
    {
        alert("Initialisation of AJAX failed.");
        return false;
    }
    var Data = document.getElementById(Id).value;
    var url= '/eTodo/eWeb:sendStatus?status=' + Data + '&uid=' + Uid;
    AJAX.open("GET", url, true);
    AJAX.send(null);
}

function sendMsg(ToId, MsgId)
{
    var AJAX = newAJAX();
    if (AJAX == null) {
        alert("Initialisation of AJAX failed.");
        return false;
    }
    var Msg = encodeURIComponent(document.getElementById(MsgId).value);
    document.getElementById(MsgId).value = '';
    var To  = encodeURIComponent(document.getElementById(ToId).value);
    var url = '/eTodo/eWeb:sendMsg?to=' + To + '&msg=' + Msg;
    AJAX.open("GET", url, true);
    AJAX.send(null);
}

function checkForMessage()
{
    var AJAX = newAJAX();
    if (AJAX == null)
    {
        alert("Initialisation of AJAX failed.");
        return false;
    }

    AJAX.onreadystatechange = function() {
        if (AJAX.readyState == 4 || AJAX.readyState == "complete") {
            handleResult(AJAX.responseText, AJAX.status);
        }
    };
    var url= '/eTodo/eWeb:checkForMessage';
    AJAX.open("GET", url, true);
    AJAX.send(null);
}

function handleResult(responseText, status)
{
    if (status == 200 && responseText != "noMessages") {
        document.getElementById('messageField').innerHTML = responseText;
        notifyUser();
    }
    setTimeout('checkForMessage()', 0);
}

function checkStatus() {
    var AJAX = newAJAX();
    if (AJAX == null) {
        alert("Initialisation of AJAX failed.");
        return false;
    }

    AJAX.onreadystatechange = function () {
        if (AJAX.readyState == 4 || AJAX.readyState == "complete") {
            handleStatusResult(AJAX.responseText, AJAX.status);
        }
    };
    var url = '/eTodo/eWeb:checkStatus';
    AJAX.open("GET", url, true);
    AJAX.send(null);
    setTimeout('checkStatus()', 1000);
}

function handleStatusResult(responseText, status)
{
    if (status == 200) {
        var obj = JSON.parse(responseText);
        var seconds = parseInt(obj.timer);

        document.getElementById('timerField').innerHTML = toHoursMinSec(seconds);
        document.getElementById('timerStatus').innerHTML = obj.status;
        document.getElementById('timerStatusMsg').innerHTML = obj.statusMsg;

        var element = document.getElementById('theBody');

        if (seconds == 0) {
            element.classList.remove('timerBusy');
            addClass(element, 'timerAvailable');
        }
        else {
            element.classList.remove('timerAvailable');
            addClass(element, 'timerBusy');
        }

        if (obj.status == 'Available') {
            element.classList.remove('statusAway');
            element.classList.remove('statusBusy');
            addClass(element, 'statusAvailable');
        }
        else if (obj.status == 'Away') {
            element.classList.remove('statusAvailable');
            element.classList.remove('statusBusy');
            addClass(element, 'statusAway');
        }
        else
        {
            element.classList.remove('statusAvailable');
            element.classList.remove('statusAway');
            addClass(element, 'statusBusy');
        }
    }
}

function addClass(element, elementClass) {
    if (element.classList.contains(elementClass) == false) {
        element.classList.add(elementClass);
    }
}

function toHoursMinSec(seconds) {
    var hour = parseInt(seconds / 3600);
    var min  = parseInt(seconds / 60 - hour * 60);
    var sec  = seconds % 60;

    sec = sec < 10 ? ("0" + sec) : sec;

    if (hour == 0) {
        return min + ":" + sec;
    }
    else {
        min = min < 10 ? ("0" + min) : min;
        return hour + ":" + min + ":" + sec;
    }
}

function notifyUser() {
    var Element = document.getElementById('messageField');
    var msgType = Element.childNodes[0].getAttribute('class');
    if ((msgType == 'msgReceived') || (msgType == 'msgAlarm')) {
        if ('Notification' in window) {
            var msgRec =
                Element.
                    childNodes[0].
                    childNodes[0].
                    childNodes[0].
                    childNodes[2].textContent;

            var msgText =
                Element.
                    childNodes[0].
                    childNodes[0].
                    childNodes[1].
                    childNodes[2].textContent;

            var title = (msgType == 'msgReceived') ?
            'eTodo: ' + msgRec.split(' to ')[0]:'eTodo: alarm';

            var icon = (osType() == "Windows") ?
                '/priv/Icons/etodoBig.png':'/priv/Icons/eTodo.png';

            var options = {
                body: msgText,
                tag: 'preset',
                icon: icon
            }
        }
        Notification.requestPermission(function() {
            var notification = new Notification(title, options);
        });

        window.navigator = window.navigator || {};
        if (navigator.vibrate != undefined) {
            // Vibrate mobile device
            navigator.vibrate(1000);
        }
    }
}

function osType() {
    // This script sets OSName variable as follows:
    // "Windows"    for all versions of Windows
    // "MacOS"      for all versions of Macintosh OS
    // "Linux"      for all versions of Linux
    // "UNIX"       for all other UNIX flavors
    // "Unknown OS" indicates failure to detect the OS

    var OSName="Unknown OS";
    if (navigator.appVersion.indexOf("Win")!=-1) OSName="Windows";
    if (navigator.appVersion.indexOf("Mac")!=-1) OSName="MacOS";
    if (navigator.appVersion.indexOf("X11")!=-1) OSName="UNIX";
    if (navigator.appVersion.indexOf("Linux")!=-1) OSName="Linux";

    return OSName;
}
<commit_msg>Updated a little to newer notification API<commit_after>function openInNewTab(url)
{
    window.open(url, '_blank');
    window.focus();
}

function showDetails(uid) {
    var Element = document.getElementById('table' + uid);
    if (Element.classList.contains('tCompact')) {
        Element.classList.remove('tCompact');
        Element.childNodes[0].childNodes[2].classList.remove('hideRow');
        Element.childNodes[0].childNodes[3].classList.remove('hideRow');
        Element.childNodes[0].childNodes[5].classList.remove('hideRow');
    }
    else {
        Element.classList.add('tCompact');
        addClass(Element.childNodes[0].childNodes[2], 'hideRow');
        addClass(Element.childNodes[0].childNodes[3], 'hideRow');
        addClass(Element.childNodes[0].childNodes[5], 'hideRow');
    }
}

function submitForm() {
    var FormElement = document.getElementById('searchForm');
    FormElement.submit();
}

function checkForEnter (event) {
    var keyCode = ('which' in event) ? event.which : event.keyCode;

    if (keyCode == '13') {
        sendMsg('userSelect', 'sendMessage')
    }
    return true;
}

function newAJAX()
{
    var AJAX = null;
    if (window.XMLHttpRequest)
    {
        AJAX=new XMLHttpRequest();
    } else {
        AJAX=new ActiveXObject("Microsoft.XMLHTTP");
    }
    return AJAX;
}

function sendStatus(Id, Uid)
{
    var AJAX = newAJAX();
    if (AJAX == null)
    {
        alert("Initialisation of AJAX failed.");
        return false;
    }
    var Data = document.getElementById(Id).value;
    var url= '/eTodo/eWeb:sendStatus?status=' + Data + '&uid=' + Uid;
    AJAX.open("GET", url, true);
    AJAX.send(null);
}

function sendMsg(ToId, MsgId)
{
    var AJAX = newAJAX();
    if (AJAX == null) {
        alert("Initialisation of AJAX failed.");
        return false;
    }
    var Msg = encodeURIComponent(document.getElementById(MsgId).value);
    document.getElementById(MsgId).value = '';
    var To  = encodeURIComponent(document.getElementById(ToId).value);
    var url = '/eTodo/eWeb:sendMsg?to=' + To + '&msg=' + Msg;
    AJAX.open("GET", url, true);
    AJAX.send(null);
}

function checkForMessage()
{
    var AJAX = newAJAX();
    if (AJAX == null)
    {
        alert("Initialisation of AJAX failed.");
        return false;
    }

    AJAX.onreadystatechange = function() {
        if (AJAX.readyState == 4 || AJAX.readyState == "complete") {
            handleResult(AJAX.responseText, AJAX.status);
        }
    };
    var url= '/eTodo/eWeb:checkForMessage';
    AJAX.open("GET", url, true);
    AJAX.send(null);
}

function handleResult(responseText, status)
{
    if (status == 200 && responseText != "noMessages") {
        document.getElementById('messageField').innerHTML = responseText;
        notifyUser();
    }
    setTimeout('checkForMessage()', 0);
}

function checkStatus() {
    var AJAX = newAJAX();
    if (AJAX == null) {
        alert("Initialisation of AJAX failed.");
        return false;
    }

    AJAX.onreadystatechange = function () {
        if (AJAX.readyState == 4 || AJAX.readyState == "complete") {
            handleStatusResult(AJAX.responseText, AJAX.status);
        }
    };
    var url = '/eTodo/eWeb:checkStatus';
    AJAX.open("GET", url, true);
    AJAX.send(null);
    setTimeout('checkStatus()', 1000);
}

function handleStatusResult(responseText, status)
{
    if (status == 200) {
        var obj = JSON.parse(responseText);
        var seconds = parseInt(obj.timer);

        document.getElementById('timerField').innerHTML = toHoursMinSec(seconds);
        document.getElementById('timerStatus').innerHTML = obj.status;
        document.getElementById('timerStatusMsg').innerHTML = obj.statusMsg;

        var element = document.getElementById('theBody');

        if (seconds == 0) {
            element.classList.remove('timerBusy');
            addClass(element, 'timerAvailable');
        }
        else {
            element.classList.remove('timerAvailable');
            addClass(element, 'timerBusy');
        }

        if (obj.status == 'Available') {
            element.classList.remove('statusAway');
            element.classList.remove('statusBusy');
            addClass(element, 'statusAvailable');
        }
        else if (obj.status == 'Away') {
            element.classList.remove('statusAvailable');
            element.classList.remove('statusBusy');
            addClass(element, 'statusAway');
        }
        else
        {
            element.classList.remove('statusAvailable');
            element.classList.remove('statusAway');
            addClass(element, 'statusBusy');
        }
    }
}

function addClass(element, elementClass) {
    if (element.classList.contains(elementClass) == false) {
        element.classList.add(elementClass);
    }
}

function toHoursMinSec(seconds) {
    var hour = parseInt(seconds / 3600);
    var min  = parseInt(seconds / 60 - hour * 60);
    var sec  = seconds % 60;

    sec = sec < 10 ? ("0" + sec) : sec;

    if (hour == 0) {
        return min + ":" + sec;
    }
    else {
        min = min < 10 ? ("0" + min) : min;
        return hour + ":" + min + ":" + sec;
    }
}

function notifyUser() {
    var Element = document.getElementById('messageField');
    var msgType = Element.childNodes[0].getAttribute('class');
    if ((msgType == 'msgReceived') || (msgType == 'msgAlarm')) {
        if ('Notification' in window) {
            var msgRec =
                Element.
                    childNodes[0].
                    childNodes[0].
                    childNodes[0].
                    childNodes[2].textContent;

            var msgText =
                Element.
                    childNodes[0].
                    childNodes[0].
                    childNodes[1].
                    childNodes[2].textContent;

            var title = (msgType == 'msgReceived') ?
            'eTodo: ' + msgRec.split(' to ')[0]:'eTodo: alarm';

            var icon = (osType() == "Windows") ?
                '/priv/Icons/etodoBig.png':'/priv/Icons/etodoBig.png';

            var options = {
                body: msgText,
                tag: 'preset',
                icon: icon
            }
        }
        if (Notification.permission != "granted") {
            Notification.requestPermission(function() {
		        var notification = new Notification(title, options);
	        });
        }
        else {
            if (Notification.permission == "granted") {
                var notification = new Notification(title, options);
            }
        }

        window.navigator = window.navigator || {};
        if (navigator.vibrate != undefined) {
            // Vibrate mobile device
            navigator.vibrate(1000);
        }
    }
}

function osType() {
    // This script sets OSName variable as follows:
    // "Windows"    for all versions of Windows
    // "MacOS"      for all versions of Macintosh OS
    // "Linux"      for all versions of Linux
    // "UNIX"       for all other UNIX flavors
    // "Unknown OS" indicates failure to detect the OS

    var OSName="Unknown OS";
    if (navigator.appVersion.indexOf("Win")!=-1) OSName="Windows";
    if (navigator.appVersion.indexOf("Mac")!=-1) OSName="MacOS";
    if (navigator.appVersion.indexOf("X11")!=-1) OSName="UNIX";
    if (navigator.appVersion.indexOf("Linux")!=-1) OSName="Linux";

    return OSName;
}
<|endoftext|>


<commit_before>"use strict";
module.directive('resumableDrop', [
	'pageService', function (page) {
		var link = function($scope, $el, $attrs) {
			var r = new page.resumable.makeResumable({
				target: $attrs.uploadTarget,
				method: 'octet',
				maxFiles: 1,
				testChunks: false,
				chunkRetryInterval: 5000,
				permanentErrors: [400,403,404,415,500,501]
			});

			r.assignDrop($el);

			r.on('fileAdded', function(file){
						page.$http.post($attrs.prepTarget+
							'?volume='+$scope.volumeEditMaterialsForm.volume.id+
							';filename='+file.fileName+
							';size='+file.size).then(function(res){
									file.uniqueIdentifier = res.data;
								}
							);
					}
			);

			r.on('complete', function(){
				//call to api/asset with remaining fields
				}
			);

			$scope.resumableObj = r;
		};

		return {
			restrict: 'A',
			scope: true,
			templateUrl: 'resumableDrop.html',
			replace: false,
			link: link
		};
	}
]);

<commit_msg>assets added properly, but too much is done in directive as opposed to service<commit_after>"use strict";
module.directive('resumableDrop', [
	'pageService', function (page) {
		var link = function($scope, $el, $attrs) {
			var r = new page.resumable.makeResumable({
				target: $attrs.uploadTarget,
				method: 'octet',
				maxFiles: 1,
				testChunks: false,
				chunkRetryInterval: 5000,
				permanentErrors: [400,403,404,415,500,501]
			});

			r.assignDrop($el);

			r.on('fileAdded', function(file){
						page.$http.post($attrs.prepTarget+
							'?volume='+$scope.volumeEditMaterialsForm.volume.id+
							';filename='+file.fileName+
							';size='+file.size).then(function(res){
									file.uniqueIdentifier = res.data;
									$scope.token = res.data;
								}
							);
					}
			);

			r.on('complete', function(){
				//call to api/asset with remaining fields
				var data = {};
				data.name = $scope.asset.name;
				data.classification = page.constants.data.classification.indexOf($scope.asset.classification);  //TODO: improve this!
				data.container = $scope.volumeEditMaterialsForm.slot.container.id;
				data.upload = $scope.token;

				page.$http.post('/api/asset?volume='+$scope.volumeEditMaterialsForm.volume.id,data);
			});

			$scope.resumableObj = r;
		};

		return {
			restrict: 'A',
			scope: true,
			templateUrl: 'resumableDrop.html',
			replace: false,
			link: link
		};
	}
]);

<|endoftext|>


<commit_before>module.exports = function (app, utils, urls, url, Users, Slices, script_dir) {
    function makeTarfile(sliceName) {
	return sliceName;
    }

    function makeExpiryDate() {
	var expiration = new Date() // gets doday
        var two_weeks = 1000 * 3600 * 24 * 7 * 2; // ms/sec * secs/hour * hours/day * days/week * 2 weeks
        expiration.setTime(expiration.getTime() + two_weeks)
        return expiration;
    }

    // invoke a remote command.  If the command exits with 0, invoke callBack, which should
    // be a function foo(req, res, callBackArgStruct, results), where results are the data
    // that came back from command.  On error invoke errorCallBack, which takes (req, res, error)

    var invokeCommand = function(req, res, cmdName, argList, callBack, callBackArgStruct, errorCallback) {
        var spawn = require('child_process').spawn;
        var cmd = spawn(script_dir + '/' + cmdName, argList);
        var error = "";
        var result = "";
        var data_received = false;
        cmd.stdout.on('data', function (data) {
            // console.log('stdout: ' + data);
            result = JSON.parse(data);
            data_received = true;
        });
        // when data is received on stderr, we have a problem and log it.  Should do something more
        // intelligent on exit...
        cmd.stderr.on('data', function (data) {
            console.log('Error in ' + cmdName +': ' + data);
            error = error + data;
        });
        // when the command finishes, either handle the error or do the callback
        cmd.on('close', function (code) {
            console.log('child process exited with code ' + code);
            if(code > 0) {
                errorCallback(req, res, "Error in subprocess " + cmdName + " " + argList + ": " + error)
            } else {
                callBack(req, res, callBackArgStruct, result)
            }
        });
    }

    var deleteSliceFromDBOnError = function(req, res, errorMessage) {
       Slices.remove({user:req.session.user}, function(err, result) {
        if(err) {
            utils.handleError(req, res, "Double Error, requires administrator attention: " + errorMessage + " : " + err)
        } else {
            utils.handleError(req, res, errorMessage)
        }
       })
    }
    var redirectToUser = function(req, res) {
        res.redirect('/user')
    }

    // get the next slice number.  used only for debugging
    app.get('/slice/next', function (req, res) {
        res.end('Next slice number is ' + next_slice)
    })

    app.get('/slice/get', function (req, res) {
        Slices.nextCount(function(err, nextSliceNum) {
            if (err) {
                var message  = "Error in getting the next Slice Number: " + err
                console.log(message);
                utils.render_error_page(req, res,  message);
            } else {
                var sliceName = utils.makeSliceName(nextSliceNum)
                var tarFile = makeTarfile(sliceName)
                Slices.create({user:req.session.user,
                              tarfile:makeTarfile(sliceName),
                              expires:makeExpiryDate()
                              },
                              function(err, slice) {
                                if (err) {
                                    var message  = "Error in creating the Slice: " + sliceName + ": " + err;
                                    console.log(message)
                                    utils.render_error_page(req, res, message)
                                } else {
                                    console.log("Slice " + sliceName + " entered for user " + req.session.user)
                                    invokeCommand(req, res, 'createSlice.sh', [sliceName, tarFile, 'foo'], redirectToUser, {}, deleteSliceFromDBOnError) // need to fix the imagename
                                }
                              });
            }
        });
    });

    // free a slicelet.  Just deletes the slicelet from the db
    app.get('/slice/free', function (req, res) {
        console.log(req.url);
        Slices.find({user:req.session.user}, function(err, slices) {
            if(err) {
                utils.handleError("Error in finding slice for user " + req.session.user + ": " + err)
            } else if (slices.length == 0) {
                utils.handleError("No slices found for user " + req.session.user)
            } else {
                var sliceName = utils.makeSliceName(slices[0].sliceNum)
                var tarfile = slices[0].tarfile;
                Slices.remove({user:req.session.user}, function(err) {
                    if(err) {
                        utils.handleError("Error removing slice for user " + req.session.user + " from the database: " + err)
                    } else {
                        invokeCommand(req, res, 'deleteSlice.sh', [sliceName, tarFile], redirectToUser, {}, utils.handleError)
                    }
                })
            }
        })
    });
    //
    // Renew a slicelet.  Just calls makeExpiryDate to set the session expiration two weeks into the
    // future, updates the slice record, then renders the dashboard.
    app.get('/slice/renew', function (req, res) {
        Slices.findOne({user:req.session.user}, function(err, doc) {
            if (err) {
                var message = "Error renewing slice for user " + req.session.user + ": " + err
                console.log(message)
                utils.render_error_page(req, res, message)
            } else {
                doc.expires = makeExpiryDate();
                doc.save(function(err, slice, numberAffected) {
                    if (err ) {
                        var message = "Error renewing slice for user " + req.session.user + ": " + err
                        console.log(message)
                        utils.render_error_page(req, res, message)
                    } else {
                        console.log("Slice for user " + req.session.user + " renewed ")
                        res.redirect('/user')
                    }
                });
            }
        });
    });

    // Callback for download.  Fortunately, this is simple, as node.js provides a
    // download primitive.  We need to error-check this better.  In particular, we
    // need to check that the file actually exists!
    app.get('/slice/download', function (req, res) {
        if (req.session.filename == null) {
            var error_message = "No filename set on call to /download ";
            utils.render_error_page(req, res, error_message, "");
        } else {
            console.log(req.session.filename);
            res.download(req.session.filename);
        }
    });
}<commit_msg>fixed typo<commit_after>module.exports = function (app, utils, urls, url, Users, Slices, script_dir) {
    function makeTarfile(sliceName) {
	return sliceName;
    }

    function makeExpiryDate() {
	var expiration = new Date() // gets doday
        var two_weeks = 1000 * 3600 * 24 * 7 * 2; // ms/sec * secs/hour * hours/day * days/week * 2 weeks
        expiration.setTime(expiration.getTime() + two_weeks)
        return expiration;
    }

    // invoke a remote command.  If the command exits with 0, invoke callBack, which should
    // be a function foo(req, res, callBackArgStruct, results), where results are the data
    // that came back from command.  On error invoke errorCallBack, which takes (req, res, error)

    var invokeCommand = function(req, res, cmdName, argList, callBack, callBackArgStruct, errorCallback) {
        var spawn = require('child_process').spawn;
        var cmd = spawn(script_dir + '/' + cmdName, argList);
        var error = "";
        var result = "";
        var data_received = false;
        cmd.stdout.on('data', function (data) {
            // console.log('stdout: ' + data);
            result = JSON.parse(data);
            data_received = true;
        });
        // when data is received on stderr, we have a problem and log it.  Should do something more
        // intelligent on exit...
        cmd.stderr.on('data', function (data) {
            console.log('Error in ' + cmdName +': ' + data);
            error = error + data;
        });
        // when the command finishes, either handle the error or do the callback
        cmd.on('close', function (code) {
            console.log('child process exited with code ' + code);
            if(code > 0) {
                errorCallback(req, res, "Error in subprocess " + cmdName + " " + argList + ": " + error)
            } else {
                callBack(req, res, callBackArgStruct, result)
            }
        });
    }

    var deleteSliceFromDBOnError = function(req, res, errorMessage) {
       Slices.remove({user:req.session.user}, function(err, result) {
        if(err) {
            utils.handleError(req, res, "Double Error, requires administrator attention: " + errorMessage + " : " + err)
        } else {
            utils.handleError(req, res, errorMessage)
        }
       })
    }
    var redirectToUser = function(req, res) {
        res.redirect('/user')
    }

    // get the next slice number.  used only for debugging
    app.get('/slice/next', function (req, res) {
        res.end('Next slice number is ' + next_slice)
    })

    app.get('/slice/get', function (req, res) {
        Slices.nextCount(function(err, nextSliceNum) {
            if (err) {
                var message  = "Error in getting the next Slice Number: " + err
                console.log(message);
                utils.render_error_page(req, res,  message);
            } else {
                var sliceName = utils.makeSliceName(nextSliceNum)
                var tarFile = makeTarfile(sliceName)
                Slices.create({user:req.session.user,
                              tarfile:makeTarfile(sliceName),
                              expires:makeExpiryDate()
                              },
                              function(err, slice) {
                                if (err) {
                                    var message  = "Error in creating the Slice: " + sliceName + ": " + err;
                                    console.log(message)
                                    utils.render_error_page(req, res, message)
                                } else {
                                    console.log("Slice " + sliceName + " entered for user " + req.session.user)
                                    invokeCommand(req, res, 'createSlice.sh', [sliceName, tarFile, 'foo'], redirectToUser, {}, deleteSliceFromDBOnError) // need to fix the imagename
                                }
                              });
            }
        });
    });

    // free a slicelet.  Just deletes the slicelet from the db
    app.get('/slice/free', function (req, res) {
        console.log(req.url);
        Slices.find({user:req.session.user}, function(err, slices) {
            if(err) {
                utils.handleError("Error in finding slice for user " + req.session.user + ": " + err)
            } else if (slices.length == 0) {
                utils.handleError("No slices found for user " + req.session.user)
            } else {
                var sliceName = utils.makeSliceName(slices[0].sliceNum)
                var tarfile = slices[0].tarfile;
                Slices.remove({user:req.session.user}, function(err) {
                    if(err) {
                        utils.handleError("Error removing slice for user " + req.session.user + " from the database: " + err)
                    } else {
                        invokeCommand(req, res, 'deleteSlice.sh', [sliceName, tarfile], redirectToUser, {}, utils.handleError)
                    }
                })
            }
        })
    });
    //
    // Renew a slicelet.  Just calls makeExpiryDate to set the session expiration two weeks into the
    // future, updates the slice record, then renders the dashboard.
    app.get('/slice/renew', function (req, res) {
        Slices.findOne({user:req.session.user}, function(err, doc) {
            if (err) {
                var message = "Error renewing slice for user " + req.session.user + ": " + err
                console.log(message)
                utils.render_error_page(req, res, message)
            } else {
                doc.expires = makeExpiryDate();
                doc.save(function(err, slice, numberAffected) {
                    if (err ) {
                        var message = "Error renewing slice for user " + req.session.user + ": " + err
                        console.log(message)
                        utils.render_error_page(req, res, message)
                    } else {
                        console.log("Slice for user " + req.session.user + " renewed ")
                        res.redirect('/user')
                    }
                });
            }
        });
    });

    // Callback for download.  Fortunately, this is simple, as node.js provides a
    // download primitive.  We need to error-check this better.  In particular, we
    // need to check that the file actually exists!
    app.get('/slice/download', function (req, res) {
        if (req.session.filename == null) {
            var error_message = "No filename set on call to /download ";
            utils.render_error_page(req, res, error_message, "");
        } else {
            console.log(req.session.filename);
            res.download(req.session.filename);
        }
    });
}<|endoftext|>


<commit_before>'use strict';

var Node2NeoError = require('node2neo-schema').error;

/**
 * Generic find for your model
 * Conditions and callback are mandatory but fields and options are not
 *
 * Examples:
 * User.find({first:'Rory'}, function(err, nodes){})
 *
 * Options can include: limit, skip, using (to specify an index) or orderBy
 * limit: options = {limit: 10}
 * skip: options = {skip: 7}
 * using: options = {using: ['first, last']}  // can be a single value string or an array
 * orderBy: options = {orderBy: [{field: 'first', desc:true, nulls:true}]}
 * orderBy must be an array of objects - even if there is only one onject
 * each object in orderBy must contain a field element, desc and nulls are optional and default to false
 * User.find({first:'Rory'}, '', {limit: 5, skip:3, orderBy: [{first: 'last', desc:true, nulls: true}]}, function(){})
 *
 *
 * @param  {Object}   conditions  Object of fields and value
 * @param  {Object}   options     Object of options
 * @param  {Function} callback
 * @return {Node or Array}        If you specify a limit of 1 a single node is returned, otherwise an array of nodes
 */
module.exports.find = function(conditions, options, callback){
  var self = this;

  if ('function' == typeof conditions) {
    callback = conditions;
    return callback(new Node2NeoError('Invalid find. You must provide some conditions in your query'));
  } else if ('function' === typeof options) {
    callback = options;
    options = {};
  }

  // build query
  var query = 'MATCH (n:' + this.label + ')';
  var params = {};
  // if there are conditions add in the where clauses
  if(conditions){
    // if we are querying for an id we have to start our search differently
    if(conditions.hasOwnProperty('_id')){
      // query = 'START n='+this.objectType+'('+conditions['_id']+')';
      query = 'START n=node('+ conditions._id + ')';
      // remove the condition so it doesn't get checked again
      conditions = null;
    }
    // loop through all conditions and add a WHERE clause
    var firstWhere = true;
    for(var key in conditions){
      if(firstWhere) {
        query += ' WHERE n.' + key + ' = {' + key + '}';
        firstWhere = false;
      }
      else query += ' AND n.' + key + ' = {' + key + '}';

      // set the
      params[key] = self.schema._types[key] === 'number' ? parseInt(conditions[key], 10) : conditions[key];
    }
  }

  query += ' RETURN id(n), n';

  for(var option in options){
    // many options can be array of values orderBy, using
    switch(option) {
    case 'limit':
      // expected format options = { limit: 1 }
      query += ' LIMIT ' + options[option];
      break;
    case 'orderBy':
      //expected format options = {orderBy: [{ field: 'name', nulls: true}, {field: 'gender', desc: true}] }
      // nulls and desc are optional
      var lenO = options[option].length;
      for(var k=0; k<lenO; k++){
        if(options[option][k].field){
          query += ' ORDER BY n.' + options[option][k].field;
          // if(options[option][k].nulls) query += '?';
          if(options[option][k].desc) query += ' DESC';
          query += ', ';
        }
      }
      // clean up comma at end
      if(query.substr(-2,2) === ', ') query = query.substr(0, query.length - 2);
      break;
    case 'skip':
      // expected format options = { skip: 1 }
      query += ' SKIP ' + options[option];
      break;
    case 'using':
      //expected format options = {using: ['name', 'gender'] }
      if(typeof options[option] === 'array'){
        var lenO = options[option].length;
        for(var l=0; l<lenO; l++){
          query += ' USING INDEX n:'+ this.modelName + '(' + options[option][l] + ')';
        }
      }
      else query += ' USING INDEX n:'+ this.modelName + '(' + options[option] + ')';
      break;
    }
  }

  // convert the statement into the correct format
  var statement = {
    statement : query,
    parameters: params
  };

  self.db.beginTransaction({statements: [statement]}, {commit:true}, function(err, results){
    if(err) return callback(err);
    else {
      if(results.errors.length > 0){
        return callback(results.errors);
      }
      else {
        var result = self.parseResults(results, options);
        return callback(null, result);
        // return callback(null, results);
      }
    }
  });
};

/**
 * Returns a single node which matches the conditions.
 * If multiple nodes match the first node will be returned
 * Conditions and callback are mandatory but options are not
 *
 * Examples:
 * User.findOne({first:'Rory'}, function(err, nodes){})
 *
 * Options can include: skip, using (to specify an index) or orderBy
 * skip: options = {skip: 7}
 * using: options = {using: ['first, last']}  // can be a single value string or an array
 * orderBy: options = {orderBy: [{field: 'first', desc:true, nulls:true}]}
 * orderBy must be an array of objects - even if there is only one onject
 * each object in orderBy must contain a field element, desc and nulls are optional and default to false
 * User.findOne({first:'Rory'}, {skip:3, orderBy: [{first: 'last', desc:true, nulls: true}]}, function(){})
 *
 *
 * @param  {Object}   conditions  Object of fields and value
 * @param  {Object}   options     Object of options
 * @param  {Function} callback
 * @return {Node/Relationship}    Node/Relationship
 */
 module.exports.findOne = function(conditions, options, callback){
  if ('function' === typeof options) {
    callback = options;
    options = {};
  } else if ('function' === typeof conditions) {
    callback = conditions;
    return callback(new Node2NeoError('Invalid findOne. You must provide some conditions in your query.'));
  }

  // only want to return one item
  options.limit = 1;
  var self = this;

  // pass to find
  // return this.find(conditions, options, function(err, results){
  //   if(err) return callback(err);
  //   else {
  //     if(results.errors.length > 0){
  //       return callback(results.errors);
  //     }
  //     else {
  //       var result = self.parseResults(results, options);

  //       return callback(null, result);
  //     }
  //   }
  // });
  return this.find(conditions, options, callback);
};

/**
 * Returns a single node which matches the id.
 * If multiple nodes match the first node will be returned
 * Id and callback are mandatory but options are not
 *
 * Examples:
 * User.findById(20189, function(err, nodes){})
 *
 * Options:
 * fields: string of space delimited fields to be returned
 *
 * User.findById(20189, {fields: 'firstname lastname'}, function(){})
 *
 *
 * @param  {Number}   id          Id requested
 * @param  {Object}   options     Object of options
 * @param  {Function} callback
 * @return {Object}               Id and node
 */
 module.exports.findById = function(id, options, callback) {
  if(typeof id ==='function'){
    callback = id;
    return callback(new Node2NeoError('Invalid findById: You need to include an id'));
  }
  if(typeof options === 'function'){
    callback = options;
    options = {};
  }

  // only want to return one item
  options.limit = 1;

  // var self = this;
  //
  // return this.findOne({ _id: id }, options, function(err, results){
  //   if(err) return callback(err);
  //   else {
  //     if(results.errors.length > 0){
  //       return callback(results.errors);
  //     }
  //     else {
  //       var result = self.parseResults(results, options);

  //       return callback(null, result);
  //     }
  //   }
  // });
  return this.find({ _id: parseInt(id,10) }, options, callback);
};

/**
 * Find a node by id and perform an update
 * @param  {number}   id       The id of the node to be returned
 * @param  {Object}   updates  The updates to be performed on the node
 * @param  {Object}   options  Optional. Transaction
 * @param  {Function} callback
 * @return {Object}            Id and node
 */
module.exports.findByIdAndUpdate = function(id, updates, options, callback){
  if ('function' === typeof options) {
    callback = options;
    options = {};
  } else if ('function' === typeof updates) {
    callback = conditions;
    return callback(new Node2NeoError('Invalid Update. You must provide some updates.'));
  }

  var self = this;
  this.findById(id, function(err, node){
    if(err) return callback(err);
    self.update(node, updates, options, function(err, result){
      return callback(err, result);
    });
  });
};

/**
 * Find a node by conditions and perform an update
 * @param  {number}   id       The id of the node to be returned
 * @param  {Object}   updates  The updates to be performed on the node
 * @param  {Object}   options  Optional. Skip, Limit, OrderBy, Transaction
 * @param  {Function} callback
 * @return {Object}            Id and node
 */

module.exports.findOneAndUpdate = function(conditions, updates, options, callback){
  if ('function' === typeof options) {
    callback = options;
    options = {};
  } else if ('function' === typeof updates) {
    callback = conditions;
    return callback(new Node2NeoError('Invalid Update. You must provide some updates.'));
  }

  var self = this;
  this.findOne(conditions, options, function(err, node){
    if(err) return callback(err);
    self.update(node, updates, options, function(err, result){
      return callback(err, result);
    });
  });
};

/**
 * Get relationships from a node
 *
 * conditions contains:
 *   types: single relationship type or array of types to be returned
 *   direction: 'to' or 'from'. Leave blank for both
 *   label: the single label to return
 *   nodeConditions: key:value query conditions to match data on the related nodes
 *   relConditions: key:value query conditions to match data on the relationship
 *
 *
 * @param  {Number} id         The id of the node whose relationships you are searching
 * @param  {Object} conditions Object containing query options for matching the relationships
 * @param  {Object} options    Limit, orderBy, skip and Using options. Optional.
 * @param  {Function} callback
 * @return {Array}             {rels: Array of relationships, nodes: Array of nodes}.
 * @api    public
 */
module.exports.getRelationships = function(id, conditions, options, callback){
  if(typeof options === 'function'){
    callback = options;
    options = {};
  }
  if(typeof conditions === 'function'){
    callback = conditions;
    conditions = {};
  }
  if(typeof id === 'function'){
    callback = id;
    return callback(new Node2NeoError('Invalid getRelationships request. You must provide the id of the node to request its relationships.'));
  }

  // Assume no types
  var types = '';
  if(conditions.types){
    if (conditions.types instanceof Array) {
      conditions.types.forEach(function(element){
        types += ':' + element + '| ';
      });
      // clear the last |
      types = types.substr(0, types.length-2);
    }
    else{
      types = ':' + conditions.types;
    }
  }

  var params = {
    id: parseInt(id, 10)
  };

  var query = 'START n=node({id}) MATCH (n)';
  if(conditions.direction && conditions.direction === 'in') query += '<';
  query += '-[r' + types + ']-';
  if(conditions.direction && conditions.direction === 'out') query += '>';

  if(conditions.label) query += '(o:' + conditions.label +')';
  else query += '(o)';

  var firstWhere = true;
  if(conditions.nodeConditions){
    // loop through all conditions and add a WHERE clause
    for(var key in conditions.nodeConditions){
      if(firstWhere) {
        query += ' WHERE o.' + key + ' = {' + key + '}';
        firstWhere = false;
      }
      else query += ' AND o.' + key + ' = {' + key + '}';
      params[key] = conditions.nodeConditions[key];
    }
  }
  if(conditions.relConditions){
    // loop through all conditions and add a WHERE clause
    for(var key in conditions.relConditions){
      if(firstWhere) {
        query += ' WHERE r.' + key + ' = {' + relKey + '}';
        firstWhere = false;
      }
      else query += ' AND r.' + key + ' = {' + relKey + '}';
      params[relKey] = conditions.relConditions[key];
    }
  }
  query += ' RETURN id(r), id(startnode(r)), r, type(r), id(o), o, labels(o)';

  //if there are options add in the options
  if(options){
    for(var option in options){
      // many options can be array of values orderBy, using
      switch(option) {
      case 'limit':
        // expected format options = { limit: 1 }
        query += ' LIMIT ' + options[option];
        break;
      case 'orderBy':
        //expected format options = {orderBy: [{ field: 'name', nulls: true}, {field: 'gender', desc: true}] }
        // nulls and desc are optional
        for(var k=0, lenO = options[option].length; k < lenO; k++){
          if(options[option][k].field){
            query += ' ORDER BY r.' + options[option][k].field;
            // if(options[option][k].nulls) query += '?';
            if(options[option][k].desc) query += ' DESC';
            query += ', ';
          }
        }
        // clean up comma at end
        if(query.substr(-2,2) === ', ') query = query.substr(0, query.length - 2);
        break;
      case 'skip':
        // expected format options = { skip: 1 }
        query += ' SKIP ' + options[option];
        break;
      case 'using':
        //expected format options = {using: ['name', 'gender'] }
        if(typeof options[option] === 'array'){
          for(var l=0, lenO = options[option].length; l<lenO; l++){
            query += ' USING INDEX r:'+ this.modelName + '(' + options[option][l] + ')';
          }
        }
        else query += ' USING INDEX r:'+ this.modelName + '(' + options[option] + ')';
        break;
      }
    }
  }

  var statement = {
    statement: query,
    parameters: params
  };

  var self = this;

  this.db.beginTransaction({statements:[statement]}, {commit:true}, function(err, results){
    if(err) return callback(err);
    else {
      if(results.errors.length > 0){
        return callback(results.errors);
      }
      else {
        return callback(null, parseRelationships(id, results));
      }
    }
  });
};

var parseRelationships = function(id, results){
  var result = {
    nodes: [],
    rels: []
  };

  results.results[0].data.forEach(function(element, index){
    var relId = results.results[0].data[index].row[0];
    var relStart = results.results[0].data[index].row[1];
    var rel = results.results[0].data[index].row[2];
    var type = results.results[0].data[index].row[3];
    var otherId = results.results[0].data[index].row[4];
    var otherNode = results.results[0].data[index].row[5];
    otherNode._nodeType = results.results[0].data[index].row[6][0];

    var direction = relStart === id ? 'from': 'to';

    otherNode._id = otherId;

    result.rels.push({
      _id: relId,
      type: type,
      direction: direction,
      data: rel
    });
    result.nodes.push(otherNode);
  });
  return result;
};
<commit_msg>Renamed 'in' => 'to' and 'out' => 'from'<commit_after>'use strict';

var Node2NeoError = require('node2neo-schema').error;

/**
 * Generic find for your model
 * Conditions and callback are mandatory but fields and options are not
 *
 * Examples:
 * User.find({first:'Rory'}, function(err, nodes){})
 *
 * Options can include: limit, skip, using (to specify an index) or orderBy
 * limit: options = {limit: 10}
 * skip: options = {skip: 7}
 * using: options = {using: ['first, last']}  // can be a single value string or an array
 * orderBy: options = {orderBy: [{field: 'first', desc:true, nulls:true}]}
 * orderBy must be an array of objects - even if there is only one onject
 * each object in orderBy must contain a field element, desc and nulls are optional and default to false
 * User.find({first:'Rory'}, '', {limit: 5, skip:3, orderBy: [{first: 'last', desc:true, nulls: true}]}, function(){})
 *
 *
 * @param  {Object}   conditions  Object of fields and value
 * @param  {Object}   options     Object of options
 * @param  {Function} callback
 * @return {Node or Array}        If you specify a limit of 1 a single node is returned, otherwise an array of nodes
 */
module.exports.find = function(conditions, options, callback){
  var self = this;

  if ('function' == typeof conditions) {
    callback = conditions;
    return callback(new Node2NeoError('Invalid find. You must provide some conditions in your query'));
  } else if ('function' === typeof options) {
    callback = options;
    options = {};
  }

  // build query
  var query = 'MATCH (n:' + this.label + ')';
  var params = {};
  // if there are conditions add in the where clauses
  if(conditions){
    // if we are querying for an id we have to start our search differently
    if(conditions.hasOwnProperty('_id')){
      // query = 'START n='+this.objectType+'('+conditions['_id']+')';
      query = 'START n=node('+ conditions._id + ')';
      // remove the condition so it doesn't get checked again
      conditions = null;
    }
    // loop through all conditions and add a WHERE clause
    var firstWhere = true;
    for(var key in conditions){
      if(firstWhere) {
        query += ' WHERE n.' + key + ' = {' + key + '}';
        firstWhere = false;
      }
      else query += ' AND n.' + key + ' = {' + key + '}';

      // set the
      params[key] = self.schema._types[key] === 'number' ? parseInt(conditions[key], 10) : conditions[key];
    }
  }

  query += ' RETURN id(n), n';

  for(var option in options){
    // many options can be array of values orderBy, using
    switch(option) {
    case 'limit':
      // expected format options = { limit: 1 }
      query += ' LIMIT ' + options[option];
      break;
    case 'orderBy':
      //expected format options = {orderBy: [{ field: 'name', nulls: true}, {field: 'gender', desc: true}] }
      // nulls and desc are optional
      var lenO = options[option].length;
      for(var k=0; k<lenO; k++){
        if(options[option][k].field){
          query += ' ORDER BY n.' + options[option][k].field;
          // if(options[option][k].nulls) query += '?';
          if(options[option][k].desc) query += ' DESC';
          query += ', ';
        }
      }
      // clean up comma at end
      if(query.substr(-2,2) === ', ') query = query.substr(0, query.length - 2);
      break;
    case 'skip':
      // expected format options = { skip: 1 }
      query += ' SKIP ' + options[option];
      break;
    case 'using':
      //expected format options = {using: ['name', 'gender'] }
      if(typeof options[option] === 'array'){
        var lenO = options[option].length;
        for(var l=0; l<lenO; l++){
          query += ' USING INDEX n:'+ this.modelName + '(' + options[option][l] + ')';
        }
      }
      else query += ' USING INDEX n:'+ this.modelName + '(' + options[option] + ')';
      break;
    }
  }

  // convert the statement into the correct format
  var statement = {
    statement : query,
    parameters: params
  };

  self.db.beginTransaction({statements: [statement]}, {commit:true}, function(err, results){
    if(err) return callback(err);
    else {
      if(results.errors.length > 0){
        return callback(results.errors);
      }
      else {
        var result = self.parseResults(results, options);
        return callback(null, result);
        // return callback(null, results);
      }
    }
  });
};

/**
 * Returns a single node which matches the conditions.
 * If multiple nodes match the first node will be returned
 * Conditions and callback are mandatory but options are not
 *
 * Examples:
 * User.findOne({first:'Rory'}, function(err, nodes){})
 *
 * Options can include: skip, using (to specify an index) or orderBy
 * skip: options = {skip: 7}
 * using: options = {using: ['first, last']}  // can be a single value string or an array
 * orderBy: options = {orderBy: [{field: 'first', desc:true, nulls:true}]}
 * orderBy must be an array of objects - even if there is only one onject
 * each object in orderBy must contain a field element, desc and nulls are optional and default to false
 * User.findOne({first:'Rory'}, {skip:3, orderBy: [{first: 'last', desc:true, nulls: true}]}, function(){})
 *
 *
 * @param  {Object}   conditions  Object of fields and value
 * @param  {Object}   options     Object of options
 * @param  {Function} callback
 * @return {Node/Relationship}    Node/Relationship
 */
 module.exports.findOne = function(conditions, options, callback){
  if ('function' === typeof options) {
    callback = options;
    options = {};
  } else if ('function' === typeof conditions) {
    callback = conditions;
    return callback(new Node2NeoError('Invalid findOne. You must provide some conditions in your query.'));
  }

  // only want to return one item
  options.limit = 1;
  var self = this;

  // pass to find
  // return this.find(conditions, options, function(err, results){
  //   if(err) return callback(err);
  //   else {
  //     if(results.errors.length > 0){
  //       return callback(results.errors);
  //     }
  //     else {
  //       var result = self.parseResults(results, options);

  //       return callback(null, result);
  //     }
  //   }
  // });
  return this.find(conditions, options, callback);
};

/**
 * Returns a single node which matches the id.
 * If multiple nodes match the first node will be returned
 * Id and callback are mandatory but options are not
 *
 * Examples:
 * User.findById(20189, function(err, nodes){})
 *
 * Options:
 * fields: string of space delimited fields to be returned
 *
 * User.findById(20189, {fields: 'firstname lastname'}, function(){})
 *
 *
 * @param  {Number}   id          Id requested
 * @param  {Object}   options     Object of options
 * @param  {Function} callback
 * @return {Object}               Id and node
 */
 module.exports.findById = function(id, options, callback) {
  if(typeof id ==='function'){
    callback = id;
    return callback(new Node2NeoError('Invalid findById: You need to include an id'));
  }
  if(typeof options === 'function'){
    callback = options;
    options = {};
  }

  // only want to return one item
  options.limit = 1;

  // var self = this;
  //
  // return this.findOne({ _id: id }, options, function(err, results){
  //   if(err) return callback(err);
  //   else {
  //     if(results.errors.length > 0){
  //       return callback(results.errors);
  //     }
  //     else {
  //       var result = self.parseResults(results, options);

  //       return callback(null, result);
  //     }
  //   }
  // });
  return this.find({ _id: parseInt(id,10) }, options, callback);
};

/**
 * Find a node by id and perform an update
 * @param  {number}   id       The id of the node to be returned
 * @param  {Object}   updates  The updates to be performed on the node
 * @param  {Object}   options  Optional. Transaction
 * @param  {Function} callback
 * @return {Object}            Id and node
 */
module.exports.findByIdAndUpdate = function(id, updates, options, callback){
  if ('function' === typeof options) {
    callback = options;
    options = {};
  } else if ('function' === typeof updates) {
    callback = conditions;
    return callback(new Node2NeoError('Invalid Update. You must provide some updates.'));
  }

  var self = this;
  this.findById(id, function(err, node){
    if(err) return callback(err);
    self.update(node, updates, options, function(err, result){
      return callback(err, result);
    });
  });
};

/**
 * Find a node by conditions and perform an update
 * @param  {number}   id       The id of the node to be returned
 * @param  {Object}   updates  The updates to be performed on the node
 * @param  {Object}   options  Optional. Skip, Limit, OrderBy, Transaction
 * @param  {Function} callback
 * @return {Object}            Id and node
 */

module.exports.findOneAndUpdate = function(conditions, updates, options, callback){
  if ('function' === typeof options) {
    callback = options;
    options = {};
  } else if ('function' === typeof updates) {
    callback = conditions;
    return callback(new Node2NeoError('Invalid Update. You must provide some updates.'));
  }

  var self = this;
  this.findOne(conditions, options, function(err, node){
    if(err) return callback(err);
    self.update(node, updates, options, function(err, result){
      return callback(err, result);
    });
  });
};

/**
 * Get relationships from a node
 *
 * conditions contains:
 *   types: single relationship type or array of types to be returned
 *   direction: 'to' or 'from'. Leave blank for both
 *   label: the single label to return
 *   nodeConditions: key:value query conditions to match data on the related nodes
 *   relConditions: key:value query conditions to match data on the relationship
 *
 *
 * @param  {Number} id         The id of the node whose relationships you are searching
 * @param  {Object} conditions Object containing query options for matching the relationships
 * @param  {Object} options    Limit, orderBy, skip and Using options. Optional.
 * @param  {Function} callback
 * @return {Array}             {rels: Array of relationships, nodes: Array of nodes}.
 * @api    public
 */
module.exports.getRelationships = function(id, conditions, options, callback){
  if(typeof options === 'function'){
    callback = options;
    options = {};
  }
  if(typeof conditions === 'function'){
    callback = conditions;
    conditions = {};
  }
  if(typeof id === 'function'){
    callback = id;
    return callback(new Node2NeoError('Invalid getRelationships request. You must provide the id of the node to request its relationships.'));
  }

  // Assume no types
  var types = '';
  if(conditions.types){
    if (conditions.types instanceof Array) {
      conditions.types.forEach(function(element){
        types += ':' + element + '| ';
      });
      // clear the last |
      types = types.substr(0, types.length-2);
    }
    else{
      types = ':' + conditions.types;
    }
  }

  var params = {
    id: parseInt(id, 10)
  };

  var query = 'START n=node({id}) MATCH (n)';
  if(conditions.direction && conditions.direction === 'to') query += '<';
  query += '-[r' + types + ']-';
  if(conditions.direction && conditions.direction === 'from') query += '>';

  if(conditions.label) query += '(o:' + conditions.label +')';
  else query += '(o)';

  var firstWhere = true;
  if(conditions.nodeConditions){
    // loop through all conditions and add a WHERE clause
    for(var key in conditions.nodeConditions){
      if(firstWhere) {
        query += ' WHERE o.' + key + ' = {' + key + '}';
        firstWhere = false;
      }
      else query += ' AND o.' + key + ' = {' + key + '}';
      params[key] = conditions.nodeConditions[key];
    }
  }
  if(conditions.relConditions){
    // loop through all conditions and add a WHERE clause
    for(var key in conditions.relConditions){
      if(firstWhere) {
        query += ' WHERE r.' + key + ' = {' + relKey + '}';
        firstWhere = false;
      }
      else query += ' AND r.' + key + ' = {' + relKey + '}';
      params[relKey] = conditions.relConditions[key];
    }
  }
  query += ' RETURN id(r), id(startnode(r)), r, type(r), id(o), o, labels(o)';

  //if there are options add in the options
  if(options){
    for(var option in options){
      // many options can be array of values orderBy, using
      switch(option) {
      case 'limit':
        // expected format options = { limit: 1 }
        query += ' LIMIT ' + options[option];
        break;
      case 'orderBy':
        //expected format options = {orderBy: [{ field: 'name', nulls: true}, {field: 'gender', desc: true}] }
        // nulls and desc are optional
        for(var k=0, lenO = options[option].length; k < lenO; k++){
          if(options[option][k].field){
            query += ' ORDER BY r.' + options[option][k].field;
            // if(options[option][k].nulls) query += '?';
            if(options[option][k].desc) query += ' DESC';
            query += ', ';
          }
        }
        // clean up comma at end
        if(query.substr(-2,2) === ', ') query = query.substr(0, query.length - 2);
        break;
      case 'skip':
        // expected format options = { skip: 1 }
        query += ' SKIP ' + options[option];
        break;
      case 'using':
        //expected format options = {using: ['name', 'gender'] }
        if(typeof options[option] === 'array'){
          for(var l=0, lenO = options[option].length; l<lenO; l++){
            query += ' USING INDEX r:'+ this.modelName + '(' + options[option][l] + ')';
          }
        }
        else query += ' USING INDEX r:'+ this.modelName + '(' + options[option] + ')';
        break;
      }
    }
  }

  var statement = {
    statement: query,
    parameters: params
  };

  var self = this;

  this.db.beginTransaction({statements:[statement]}, {commit:true}, function(err, results){
    if(err) return callback(err);
    else {
      if(results.errors.length > 0){
        return callback(results.errors);
      }
      else {
        return callback(null, parseRelationships(id, results));
      }
    }
  });
};

var parseRelationships = function(id, results){
  var result = {
    nodes: [],
    rels: []
  };

  results.results[0].data.forEach(function(element, index){
    var relId = results.results[0].data[index].row[0];
    var relStart = results.results[0].data[index].row[1];
    var rel = results.results[0].data[index].row[2];
    var type = results.results[0].data[index].row[3];
    var otherId = results.results[0].data[index].row[4];
    var otherNode = results.results[0].data[index].row[5];
    otherNode._nodeType = results.results[0].data[index].row[6][0];

    var direction = relStart === id ? 'from': 'to';

    otherNode._id = otherId;

    result.rels.push({
      _id: relId,
      type: type,
      direction: direction,
      data: rel
    });
    result.nodes.push(otherNode);
  });
  return result;
};
<|endoftext|>


<commit_before>require('ember-handlebars/ext');

var EmberHandlebars = Ember.Handlebars,
    getPath = EmberHandlebars.getPath,
    get = Ember.get,
    a_slice = Array.prototype.slice;

var ActionHelper = EmberHandlebars.ActionHelper = {
  registeredActions: {}
};

ActionHelper.registerAction = function(actionName, options) {
  var actionId = (++Ember.$.uuid).toString();

  ActionHelper.registeredActions[actionId] = {
    eventName: options.eventName,
    handler: function(event) {
      var modifier = event.shiftKey || event.metaKey || event.altKey || event.ctrlKey,
          secondaryClick = event.which > 1, // IE9 may return undefined
          nonStandard = modifier || secondaryClick;

      if (options.link && nonStandard) {
        // Allow the browser to handle special link clicks normally
        return;
      }

      event.preventDefault();

      event.view = options.view;

      if (options.hasOwnProperty('context')) {
        event.context = options.context;
      }

      if (options.hasOwnProperty('contexts')) {
        event.contexts = options.contexts;
      }

      var target = options.target;

      // Check for StateManager (or compatible object)
      if (target.isState && typeof target.send === 'function') {
        return target.send(actionName, event);
      } else {
        Ember.assert(Ember.String.fmt('Target %@ does not have action %@', [target, actionName]), target[actionName]);
        return target[actionName].call(target, event);
      }
    }
  };

  options.view.on('willRerender', function() {
    delete ActionHelper.registeredActions[actionId];
  });

  return actionId;
};

/**
  The `{{action}}` helper registers an HTML element within a template for
  DOM event handling and forwards that interaction to the Application's router,
  the template's `Ember.View` instance, or supplied `target` option (see 'Specifiying a Target').

  User interaction with that element will invoke the supplied action name on
  the appropriate target.

  Given the following Handlebars template on the page

  And application code

      AView = Ember.View.extend({
        templateName; 'a-template',
        anActionName: function(event){}
      });

      aView = AView.create();
      aView.appendTo('body');

  Will results in the following rendered HTML

          click me

  Clicking "click me" will trigger the `anActionName` method of the `aView`
  object with a  `jQuery.Event` object as its argument. The `jQuery.Event`
  object will be extended to include a `view` property that is set to the
  original view interacted with (in this case the `aView` object).

  ### Event Propagation

  Events triggered through the action helper will automatically have
  `.preventDefault()` called on them. You do not need to do so in your event
  handlers. To stop propagation of the event, simply return `false` from your
  handler.

  If you need the default handler to trigger you should either register your
  own event handler, or use event methods on your view class. See Ember.View
  'Responding to Browser Events' for more information.

  ### Specifying DOM event type

  By default the `{{action}}` helper registers for DOM `click` events. You can
  supply an `on` option to the helper to specify a different DOM event name:

  See Ember.View 'Responding to Browser Events' for a list of
  acceptable DOM event names.

  Because `{{action}}` depends on Ember's event dispatch system it will only
  function if an `Ember.EventDispatcher` instance is available. An
  `Ember.EventDispatcher` instance will be created when a new
  `Ember.Application` is created. Having an instance of `Ember.Application`
  will satisfy this requirement.

  ### Specifying a Target
  There are several possible target objects for `{{action}}` helpers:

  In a typical `Ember.Router`-backed Application where views are managed
  through use of the `{{outlet}}` helper, actions will be forwarded to the
  current state of the Applications's Router. See Ember.Router 'Responding
  to User-initiated Events' for more information.

  If you manaully set the `target` property on the controller of a template's
  `Ember.View` instance, the specifed `controller.target` will become the target
  for any actions. Likely custom values for a controller's `target` are the
  controller itself or a StateManager other than the Application's Router.

  If the templates's view lacks a controller property the view itself is the target.

  Finally, a `target` option can be provided to the helper to change which object
  will receive the method call. This option must be a string representing a
  path to an object:

  Clicking "click me" in the rendered HTML of the above template will trigger
  the  `anActionName` method of the object at `MyApplication.someObject`.
  The first argument to this method will be a `jQuery.Event` extended to
  include a `view` property that is set to the original view interacted with.

  A path relative to the template's `Ember.View` instance can also be used as
  a target:

  Clicking "click me" in the rendered HTML of the above template will trigger
  the `anActionName` method of the view's parent view.

  The `{{action}}` helper is `Ember.StateManager` aware. If the target of the
  action is an `Ember.StateManager` instance `{{action}}` will use the `send`
  functionality of StateManagers. The documentation for `Ember.StateManager`
  has additional information about this use.

  If an action's target does not implement a method that matches the supplied
  action name an error will be thrown.

  With the following application code

      AView = Ember.View.extend({
        templateName; 'a-template',
        // note: no method 'aMethodNameThatIsMissing'
        anActionName: function(event){}
      });

      aView = AView.create();
      aView.appendTo('body');

  Will throw `Uncaught TypeError: Cannot call method 'call' of undefined` when
  "click me" is clicked.

  ### Specifying a context

  By default the `{{action}}` helper passes the current Handlebars context
  along in the `jQuery.Event` object. You may specify an alternate object to
  pass as the context by providing a property path:

  @name Handlebars.helpers.action
  @param {String} actionName
  @param {Object...} contexts
  @param {Hash} options
*/
EmberHandlebars.registerHelper('action', function(actionName) {
  var options = arguments[arguments.length - 1],
      contexts = a_slice.call(arguments, 1, -1);

  var hash = options.hash,
      view = options.data.view,
      target, controller, link;

  // create a hash to pass along to registerAction
  var action = {
    eventName: hash.on || "click"
  };

  action.view = view = get(view, 'concreteView');

  if (hash.target) {
    target = getPath(this, hash.target, options);
  } else if (controller = options.data.keywords.controller) {
    target = get(controller, 'target');
  }

  action.target = target = target || view;

  if (contexts.length) {
    action.contexts = contexts = Ember.EnumerableUtils.map(contexts, function(context) {
      return getPath(this, context, options);
    }, this);
    action.context = contexts[0];
  }

  var output = [], url;

  if (hash.href && target.urlForEvent) {
    url = target.urlForEvent.apply(target, [actionName].concat(contexts));
    output.push('href="' + url + '"');
    action.link = true;
  }

  var actionId = ActionHelper.registerAction(actionName, action);
  output.push('data-ember-action="' + actionId + '"');

  return new EmberHandlebars.SafeString(output.join(" "));
});
<commit_msg>Fix issue #1356: a small typo in doc<commit_after>require('ember-handlebars/ext');

var EmberHandlebars = Ember.Handlebars,
    getPath = EmberHandlebars.getPath,
    get = Ember.get,
    a_slice = Array.prototype.slice;

var ActionHelper = EmberHandlebars.ActionHelper = {
  registeredActions: {}
};

ActionHelper.registerAction = function(actionName, options) {
  var actionId = (++Ember.$.uuid).toString();

  ActionHelper.registeredActions[actionId] = {
    eventName: options.eventName,
    handler: function(event) {
      var modifier = event.shiftKey || event.metaKey || event.altKey || event.ctrlKey,
          secondaryClick = event.which > 1, // IE9 may return undefined
          nonStandard = modifier || secondaryClick;

      if (options.link && nonStandard) {
        // Allow the browser to handle special link clicks normally
        return;
      }

      event.preventDefault();

      event.view = options.view;

      if (options.hasOwnProperty('context')) {
        event.context = options.context;
      }

      if (options.hasOwnProperty('contexts')) {
        event.contexts = options.contexts;
      }

      var target = options.target;

      // Check for StateManager (or compatible object)
      if (target.isState && typeof target.send === 'function') {
        return target.send(actionName, event);
      } else {
        Ember.assert(Ember.String.fmt('Target %@ does not have action %@', [target, actionName]), target[actionName]);
        return target[actionName].call(target, event);
      }
    }
  };

  options.view.on('willRerender', function() {
    delete ActionHelper.registeredActions[actionId];
  });

  return actionId;
};

/**
  The `{{action}}` helper registers an HTML element within a template for
  DOM event handling and forwards that interaction to the Application's router,
  the template's `Ember.View` instance, or supplied `target` option (see 'Specifying a Target').

  User interaction with that element will invoke the supplied action name on
  the appropriate target.

  Given the following Handlebars template on the page

  And application code

      AView = Ember.View.extend({
        templateName; 'a-template',
        anActionName: function(event){}
      });

      aView = AView.create();
      aView.appendTo('body');

  Will results in the following rendered HTML

          click me

  Clicking "click me" will trigger the `anActionName` method of the `aView`
  object with a  `jQuery.Event` object as its argument. The `jQuery.Event`
  object will be extended to include a `view` property that is set to the
  original view interacted with (in this case the `aView` object).

  ### Event Propagation

  Events triggered through the action helper will automatically have
  `.preventDefault()` called on them. You do not need to do so in your event
  handlers. To stop propagation of the event, simply return `false` from your
  handler.

  If you need the default handler to trigger you should either register your
  own event handler, or use event methods on your view class. See Ember.View
  'Responding to Browser Events' for more information.

  ### Specifying DOM event type

  By default the `{{action}}` helper registers for DOM `click` events. You can
  supply an `on` option to the helper to specify a different DOM event name:

  See Ember.View 'Responding to Browser Events' for a list of
  acceptable DOM event names.

  Because `{{action}}` depends on Ember's event dispatch system it will only
  function if an `Ember.EventDispatcher` instance is available. An
  `Ember.EventDispatcher` instance will be created when a new
  `Ember.Application` is created. Having an instance of `Ember.Application`
  will satisfy this requirement.

  ### Specifying a Target
  There are several possible target objects for `{{action}}` helpers:

  In a typical `Ember.Router`-backed Application where views are managed
  through use of the `{{outlet}}` helper, actions will be forwarded to the
  current state of the Applications's Router. See Ember.Router 'Responding
  to User-initiated Events' for more information.

  If you manaully set the `target` property on the controller of a template's
  `Ember.View` instance, the specifed `controller.target` will become the target
  for any actions. Likely custom values for a controller's `target` are the
  controller itself or a StateManager other than the Application's Router.

  If the templates's view lacks a controller property the view itself is the target.

  Finally, a `target` option can be provided to the helper to change which object
  will receive the method call. This option must be a string representing a
  path to an object:

  Clicking "click me" in the rendered HTML of the above template will trigger
  the  `anActionName` method of the object at `MyApplication.someObject`.
  The first argument to this method will be a `jQuery.Event` extended to
  include a `view` property that is set to the original view interacted with.

  A path relative to the template's `Ember.View` instance can also be used as
  a target:

  Clicking "click me" in the rendered HTML of the above template will trigger
  the `anActionName` method of the view's parent view.

  The `{{action}}` helper is `Ember.StateManager` aware. If the target of the
  action is an `Ember.StateManager` instance `{{action}}` will use the `send`
  functionality of StateManagers. The documentation for `Ember.StateManager`
  has additional information about this use.

  If an action's target does not implement a method that matches the supplied
  action name an error will be thrown.

  With the following application code

      AView = Ember.View.extend({
        templateName; 'a-template',
        // note: no method 'aMethodNameThatIsMissing'
        anActionName: function(event){}
      });

      aView = AView.create();
      aView.appendTo('body');

  Will throw `Uncaught TypeError: Cannot call method 'call' of undefined` when
  "click me" is clicked.

  ### Specifying a context

  By default the `{{action}}` helper passes the current Handlebars context
  along in the `jQuery.Event` object. You may specify an alternate object to
  pass as the context by providing a property path:

  @name Handlebars.helpers.action
  @param {String} actionName
  @param {Object...} contexts
  @param {Hash} options
*/
EmberHandlebars.registerHelper('action', function(actionName) {
  var options = arguments[arguments.length - 1],
      contexts = a_slice.call(arguments, 1, -1);

  var hash = options.hash,
      view = options.data.view,
      target, controller, link;

  // create a hash to pass along to registerAction
  var action = {
    eventName: hash.on || "click"
  };

  action.view = view = get(view, 'concreteView');

  if (hash.target) {
    target = getPath(this, hash.target, options);
  } else if (controller = options.data.keywords.controller) {
    target = get(controller, 'target');
  }

  action.target = target = target || view;

  if (contexts.length) {
    action.contexts = contexts = Ember.EnumerableUtils.map(contexts, function(context) {
      return getPath(this, context, options);
    }, this);
    action.context = contexts[0];
  }

  var output = [], url;

  if (hash.href && target.urlForEvent) {
    url = target.urlForEvent.apply(target, [actionName].concat(contexts));
    output.push('href="' + url + '"');
    action.link = true;
  }

  var actionId = ActionHelper.registerAction(actionName, action);
  output.push('data-ember-action="' + actionId + '"');

  return new EmberHandlebars.SafeString(output.join(" "));
});
<|endoftext|>


<commit_before>'use strict';

var gulp   = require('gulp');
var plugins = require('gulp-load-plugins')();

var paths = {
  lint: ['./gulpfile.js', './lib/**/*.js'],
  watch: ['./gulpfile.js', './lib/**', './test/**/*.js', '!test/{temp,temp/**}'],
  tests: ['./test/**/*.js', '!test/{temp,temp/**}']<% if (istanbulModule) { %>,
  source: ['./lib/*.js']<% } %>
};
var watching = false;

function onError(err) {
  console.log(err.toString());
  if (watching) {
    this.emit('end');
  } else {
    // if you want to be really specific
    process.exit(1);
  }
}

gulp.task('lint', function () {
  return gulp.src(paths.lint)
    .pipe(plugins.jshint('.jshintrc'))<% if (jscsModule) { %>
    .pipe(plugins.jscs())<% } %>
    .pipe(plugins.jshint.reporter('jshint-stylish'));
});<% if (istanbulModule) { %>

gulp.task('istanbul', function (cb) {
  gulp.src(paths.source)
    .pipe(plugins.istanbul()) // Covering files
    .on('finish', function () {
      gulp.src(paths.tests)
        .pipe(plugins.mocha().on('error', onError))
        .pipe(plugins.istanbul.writeReports()) // Creating the reports after tests runned
        .on('finish', function() {
          process.chdir(__dirname);
          cb();
        });
    });
});<% } else { %>

gulp.task('mocha', function () {
  gulp.src(paths.tests, {cwd: __dirname})
    .pipe(mocha({ reporter: 'list' }).on('error', onError));
});<% } %><% if (releaseModule) { %>

gulp.task('bump', ['test'], function () {
  var bumpType = process.env.BUMP || 'patch'; // major.minor.patch

  return gulp.src(['./package.json'])
    .pipe(plugins.bump({ type: bumpType }))
    .pipe(gulp.dest('./'));
});<% } %>

gulp.task('watch', function () {
  watching = true;
  gulp.run('test');
  gulp.watch(paths.watch, ['test']);
});

gulp.task('default', ['test']);
gulp.task('test', ['lint', <% if (istanbulModule) { %>'istanbul'<% } else { %>'mocha'<% } %>]);
<% if (releaseModule) { %>gulp.task('release', ['bump']);<% } %>
<commit_msg>add jshint comment to supress warning<commit_after>'use strict';

var gulp   = require('gulp');
var plugins = require('gulp-load-plugins')();

var paths = {
  lint: ['./gulpfile.js', './lib/**/*.js'],
  watch: ['./gulpfile.js', './lib/**', './test/**/*.js', '!test/{temp,temp/**}'],
  tests: ['./test/**/*.js', '!test/{temp,temp/**}']<% if (istanbulModule) { %>,
  source: ['./lib/*.js']<% } %>
};
var watching = false;

function onError(err) {
  console.log(err.toString());
  if (watching) {
    /*jshint validthis:true */
    this.emit('end');
  } else {
    // if you want to be really specific
    process.exit(1);
  }
}

gulp.task('lint', function () {
  return gulp.src(paths.lint)
    .pipe(plugins.jshint('.jshintrc'))<% if (jscsModule) { %>
    .pipe(plugins.jscs())<% } %>
    .pipe(plugins.jshint.reporter('jshint-stylish'));
});<% if (istanbulModule) { %>

gulp.task('istanbul', function (cb) {
  gulp.src(paths.source)
    .pipe(plugins.istanbul()) // Covering files
    .on('finish', function () {
      gulp.src(paths.tests)
        .pipe(plugins.mocha().on('error', onError))
        .pipe(plugins.istanbul.writeReports()) // Creating the reports after tests runned
        .on('finish', function() {
          process.chdir(__dirname);
          cb();
        });
    });
});<% } else { %>

gulp.task('mocha', function () {
  gulp.src(paths.tests, {cwd: __dirname})
    .pipe(mocha({ reporter: 'list' }).on('error', onError));
});<% } %><% if (releaseModule) { %>

gulp.task('bump', ['test'], function () {
  var bumpType = process.env.BUMP || 'patch'; // major.minor.patch

  return gulp.src(['./package.json'])
    .pipe(plugins.bump({ type: bumpType }))
    .pipe(gulp.dest('./'));
});<% } %>

gulp.task('watch', function () {
  watching = true;
  gulp.run('test');
  gulp.watch(paths.watch, ['test']);
});

gulp.task('default', ['test']);
gulp.task('test', ['lint', <% if (istanbulModule) { %>'istanbul'<% } else { %>'mocha'<% } %>]);
<% if (releaseModule) { %>gulp.task('release', ['bump']);<% } %>
<|endoftext|>


<commit_before>describe("channels", function() {
  var xhr = new XMLHttpRequest();
  xhr.open("get", "freedom.js", false);
  xhr.overrideMimeType("text/javascript; charset=utf-8");
  xhr.send(null);
  var freedom_src = xhr.responseText;

  var freedom;
  beforeEach(function() {
    var global = {
      console: {
        log: function() {}
      }
    };

    // Setup resource loading for the test environment, which uses file:// urls.
    fdom.resources = new Resource();
    fdom.resources.addResolver(function(manifest, url, deferred) {
      if (url.indexOf('relative://') === 0) {
        var dirname = manifest.substr(0, manifest.lastIndexOf('/'));
        deferred.resolve(dirname + '/' + url.substr(11));
        return true;
      }
      return false;
    });
    fdom.resources.addResolver(function(manifest, url, deferred) {
      if (manifest.indexOf('file://') === 0) {
        manifest = 'http' + manifest.substr(4);
        fdom.resources.resolve(manifest, url).done(function(addr) {
          addr = 'file' + addr.substr(4);
          deferred.resolve(addr);
        });
        return true;
      }
      return false;
    });
    fdom.resources.addRetriever('file', fdom.resources.xhrRetriever);

    var path = window.location.href,
        dir_idx = path.lastIndexOf('/'),
        dir = path.substr(0, dir_idx) + '/';
    freedom = setup(global, undefined, {
      manifest: "relative://spec/helper/channel.json",
      portType: 'Frame',
      inject: dir + "node_modules/es5-shim/es5-shim.js",
      src: freedom_src
    });
  });

  afterEach(function() {
    var frames = document.getElementsByTagName('iframe');
    for (var i = 0; i < frames.length; i++) {
      frames[i].parentNode.removeChild(frames[i]);
    }
  });

  it("Manages Channels Between Modules", function() {
    var cb = jasmine.createSpy('cb');
    var called = false;
    runs(function() {
      freedom.once('message', function(msg) {
        // created.
        expect(msg).toEqual('creating custom channel 0');
        freedom.on('message', cb);
        freedom.on('message', function() {
          called = true;
        });
        freedom.emit('message', 0);
      });
      freedom.emit('create');
    });

    waitsFor(function() {
      return called;
    }, "Freedom should return success", 4000);

    runs(function() {
      expect(cb).toHaveBeenCalledWith('sending message to 0');
    });
  });

  it("Manages Channels With providers", function() {
    var cb = jasmine.createSpy('cb');
    var called = false;
    runs(function() {
      freedom.once('message', function(msg) {
        // created.
        freedom.on('message', cb);
        freedom.on('message', function() {
          called = true;
        });
        freedom.emit('message', 0);
      });
      freedom.emit('peer');
    });

    waitsFor(function() {
      return called;
    }, "Freedom should return success", 4000);

    runs(function() {
      expect(cb).toHaveBeenCalledWith('sending message to 0');
    });
  });
});
<commit_msg>make name better<commit_after>describe("Core Provider", function() {
  var xhr = new XMLHttpRequest();
  xhr.open("get", "freedom.js", false);
  xhr.overrideMimeType("text/javascript; charset=utf-8");
  xhr.send(null);
  var freedom_src = xhr.responseText;

  var freedom;
  beforeEach(function() {
    var global = {
      console: {
        log: function() {}
      }
    };

    // Setup resource loading for the test environment, which uses file:// urls.
    fdom.resources = new Resource();
    fdom.resources.addResolver(function(manifest, url, deferred) {
      if (url.indexOf('relative://') === 0) {
        var dirname = manifest.substr(0, manifest.lastIndexOf('/'));
        deferred.resolve(dirname + '/' + url.substr(11));
        return true;
      }
      return false;
    });
    fdom.resources.addResolver(function(manifest, url, deferred) {
      if (manifest.indexOf('file://') === 0) {
        manifest = 'http' + manifest.substr(4);
        fdom.resources.resolve(manifest, url).done(function(addr) {
          addr = 'file' + addr.substr(4);
          deferred.resolve(addr);
        });
        return true;
      }
      return false;
    });
    fdom.resources.addRetriever('file', fdom.resources.xhrRetriever);

    var path = window.location.href,
        dir_idx = path.lastIndexOf('/'),
        dir = path.substr(0, dir_idx) + '/';
    freedom = setup(global, undefined, {
      manifest: "relative://spec/helper/channel.json",
      portType: 'Frame',
      inject: dir + "node_modules/es5-shim/es5-shim.js",
      src: freedom_src
    });
  });

  afterEach(function() {
    var frames = document.getElementsByTagName('iframe');
    for (var i = 0; i < frames.length; i++) {
      frames[i].parentNode.removeChild(frames[i]);
    }
  });

  it("Manages Channels Between Modules", function() {
    var cb = jasmine.createSpy('cb');
    var called = false;
    runs(function() {
      freedom.once('message', function(msg) {
        // created.
        expect(msg).toEqual('creating custom channel 0');
        freedom.on('message', cb);
        freedom.on('message', function() {
          called = true;
        });
        freedom.emit('message', 0);
      });
      freedom.emit('create');
    });

    waitsFor(function() {
      return called;
    }, "Freedom should return success", 4000);

    runs(function() {
      expect(cb).toHaveBeenCalledWith('sending message to 0');
    });
  });

  it("Manages Channels With providers", function() {
    var cb = jasmine.createSpy('cb');
    var called = false;
    runs(function() {
      freedom.once('message', function(msg) {
        // created.
        freedom.on('message', cb);
        freedom.on('message', function() {
          called = true;
        });
        freedom.emit('message', 0);
      });
      freedom.emit('peer');
    });

    waitsFor(function() {
      return called;
    }, "Freedom should return success", 4000);

    runs(function() {
      expect(cb).toHaveBeenCalledWith('sending message to 0');
    });
  });
});
<|endoftext|>


<commit_before>//Base class
var flotChartDisplay = (function(protected) {

    //chart private variables
    protected = protected || {};
    protected.jsonData = null,
        protected.graph = null,
        protected.previousPoint = null,
        protected.data = null,
        protected.tooltipId = null,
        protected.options = null;

    protected.getOptions = function() {
        return {};
    };

    protected.prepData = function(jsonData) {
        return jsonData;
    };

    protected.showTooltip = function(id, x, y, contents) {
        var div = $('
' + contents + '
');
        div.css( {
            position: 'absolute',
            display: 'none',
            top: y + 5,
            left: x + 5,
            border: '1px solid #fdd',
            padding: '2px',
            'background-color': '#fee',
            opacity: 0.80
        }).appendTo("body").fadeIn(200);
    };

    protected.tooltipContent = function(item) {
        return "This is a tooltip."
    };

    protected.hideTooltip = function(id) {
        $('#'+id).remove();
    };

    protected.selected = function (event, ranges) {
        var opt = $.extend(true, {}, protected.options, {
            xaxis: { min: ranges.xaxis.from, max: ranges.xaxis.to },
            yaxis: { min: ranges.yaxis.from, max: ranges.yaxis.to }
        });
        $.plot(protected.graph,protected.data, opt);
    };

    protected.unselected = function () {
        $.plot(protected.graph,protected.data, protected.options);
    };

    protected.hover = function (event, pos, item) {
        if (item) {
            var index = item.seriesIndex.toFixed(0) + item.dataIndex.toFixed(0);

            if (protected.previousPoint != index) {
                protected.hideTooltip(protected.tooltipId);
                protected.showTooltip(protected.tooltipId, item.pageX, item.pageY, protected.tooltipContent(item));
            }
        }
        else {
            protected.hideTooltip(protected.tooltipId);
            protected.previousPoint = null;
        }
    };

    protected.monthName = function(i) {
        return Date.parse(i+"/01/2012").toString('MMM');
    }

    protected.dayOfWeekName = function(i) {
        return Date.today().moveToDayOfWeek(i-1).toString('dddd');
    }

    protected.unbindEvents = function() {
        protected.graph.unbind("plothover");
        protected.graph.unbind("plotselected");
        protected.graph.unbind("plotunselected");
    }

    protected.showGraph = function(data) {
        protected.jsonData = data;
        protected.graph = $("#graph");
        protected.tooltipId = 'tooltip';
        protected.options = protected.getOptions();
        protected.data = protected.prepData(protected.jsonData);
        var plot = $.plot(protected.graph, protected.data, protected.options);
        protected.unbindEvents();
        protected.graph.bind("plothover", protected.hover);
        protected.graph.bind("plotselected", protected.selected);
        protected.graph.bind("plotunselected",protected.unselected);
    }

    return {
        show:protected.showGraph
    }

});<commit_msg>Attempted to fix tooltip weirdness.<commit_after>//Base class
var flotChartDisplay = (function(protected) {

    //chart private variables
    protected = protected || {};
    protected.jsonData = null,
        protected.graph = null,
        protected.previousPoint = null,
        protected.data = null,
        protected.tooltipId = null,
        protected.options = null,
        protected.hovercount = 0,
        protected.hoveroff = 5;

    protected.getOptions = function() {
        return {};
    };

    protected.prepData = function(jsonData) {
        return jsonData;
    };

    protected.showTooltip = function(x, y, contents) {
        var div = $('
' + contents + '
');
        div.css( {
            position: 'absolute',
            display: 'none',
            top: y + 5,
            left: x + 5,
            border: '1px solid #fdd',
            padding: '2px',
            'background-color': '#fee',
            opacity: 0.80
        }).appendTo("body").fadeIn(200);
    };

    protected.tooltipContent = function(item) {
        return "This is a tooltip."
    };

    protected.hideTooltip = function() {
        protected.hovercount = 0;
        $('#'+protected.tooltipId).remove();
    };

    protected.selected = function (event, ranges) {
        var opt = $.extend(true, {}, protected.options, {
            xaxis: { min: ranges.xaxis.from, max: ranges.xaxis.to },
            yaxis: { min: ranges.yaxis.from, max: ranges.yaxis.to }
        });
        $.plot(protected.graph,protected.data, opt);
    };

    protected.unselected = function () {
        $.plot(protected.graph,protected.data, protected.options);
    };

    protected.hover = function (event, pos, item) {

        if (item) {
            var index = item.seriesIndex.toFixed(0) + item.dataIndex.toFixed(0);

            if (protected.previousPoint != index) {
                protected.hideTooltip();
                protected.showTooltip(item.pageX, item.pageY, protected.tooltipContent(item));
            }
        }
        else {
            protected.hovercount += 1;
            if (protected.hovercount > protected.hoveroff) {
                protected.hideTooltip();
                protected.previousPoint = null;
            }
        }
    };

    protected.monthName = function(i) {
        return Date.parse(i+"/01/2012").toString('MMM');
    }

    protected.dayOfWeekName = function(i) {
        return Date.today().moveToDayOfWeek(i-1).toString('dddd');
    }

    protected.unbindEvents = function() {
        protected.graph.unbind("plothover");
        protected.graph.unbind("plotselected");
        protected.graph.unbind("plotunselected");
    }

    protected.showGraph = function(data) {
        protected.jsonData = data;
        protected.graph = $("#graph");
        protected.tooltipId = 'tooltip';
        protected.options = protected.getOptions();
        protected.data = protected.prepData(protected.jsonData);
        var plot = $.plot(protected.graph, protected.data, protected.options);
        protected.unbindEvents();
        protected.graph.bind("plothover", protected.hover);
        protected.graph.bind("plotselected", protected.selected);
        protected.graph.bind("plotunselected",protected.unselected);
        protected.hideTooltip();
    }

    return {
        show:protected.showGraph,
        hideTooltip: protected.hideTooltip
    }

});<|endoftext|>