<commit_before>
/**
 *
 * TODO:
 * - use arguments in function to let user pass multiple variables as for
 * original console log
 * - let user set color with argument color:color_name
 * - let user change environment with environment:environment_mode
 * - let user choose default color on initialization
 * - let user set environment on initialization
 * - silence console logs on production mode
 *
 * @returns {undefined}
 */

(function() {

    'use strict';

    var utilities = {};

    utilities.version = '0.0.4';

    var errorLogger;

    utilities.logFontColor = 'default';

    utilities.logBackgroundColor = 'default';

    utilities.logSpecial = false;

    utilities.logVerbose = true;

    /**
     *
     * html log
     * create a div an insert the messages in div
     * can be usefull on mobile if no other console is available
     *
     * @param {type} logObjects
     * @param {type} logObjectsLength
     * @param {type} logFontColor
     * @param {type} logBackgroundColor
     * @returns {undefined}
     */
    utilities.htmlLog = function (logObjects, logObjectsLength, logFontColor, logBackgroundColor) {

        // TODO: fix: seems that if logging starts before "domload" some
        // messages get lost

        if (document.getElementById('log') === null) {

            var logDiv = document.createElement('div');

            logDiv.id = 'log';

            logDiv.style.cssText = 'position: absolute; overflow: scroll; left: 0; bottom: 0; padding: 0; margin: 0; border: 0; z-index: 999999; width: 100%; height: 20%; background-color: #fff;';

            document.body.appendChild(logDiv);

        }

        for (var i = 0; i < logObjectsLength; i++) {

            var logSpan = document.createElement('span');

            logSpan.style.cssText = 'color: #' + logFontColor + '; background-color: #' + logBackgroundColor + ';';

            var spanContent = document.createTextNode(logObjects[i]);

            logSpan.appendChild(spanContent);

            document.getElementById('log').appendChild(logSpan);

            var brElement = document.createElement('br');

            document.getElementById('log').appendChild(brElement);

        }

    };

    /**
     *
     * file log
     * nodejs logging to file
     *
     * @param {type} logObjects
     * @param {type} logObjectsLength
     * @param {type} logFontColor
     * @returns {undefined}
     */
    utilities.fileLog = function fileLogFunction(logObjects, logObjectsLength, logFontColor) {

		try {

			var winston = require('winston');

			for (var i = 0; i < logObjectsLength; i++) {

				switch(logFontColor) {
					case 'red':
						winston.error(logObjects[i]);
						break;
					case 'yellow':
						winston.warn(logObjects[i]);
						break;
					default:
						winston.info(logObjects[i]);
				}

			}

		} catch(e) {

			// winston is not installed

		}

    };

    /**
     *
     * log messages
     *
     * @returns {Boolean}
     */
    utilities.log = function logFunction() {

        // is console defined, some older IEs don't have a console
        if (typeof(console) === 'undefined') {

            return false;

        }

        // extract options and get objects to log
        var logArguments = handleLogArguments(arguments);

        var logObjects = logArguments.objects;
        var logFontColor = logArguments.fontColor;
        var logBackgroundColor = logArguments.backgroundColor;

        var logObjectsLength = logObjects.length;

        // nodejs or browser mode
        if (typeof(window) === 'undefined') {

            if (typeof(utilities.logVerbose) !== 'undefined'
            && utilities.logVerbose === true) {

                // get background and fontColor codes
                var color = getServerColors(logFontColor, logBackgroundColor);

                // log each object
                for (var i = 0; i < logObjectsLength; i++) {

                    if (typeof(logObjects[i]) === 'string') {

                        console.log(color.background + color.font + logObjects[i] + color.reset);

                    } else {

                        console.log(logObjects[i]);

                    }

                };

            }

            // log to file if logSpecial is enabled or if the fontColor is red
            if ((typeof(utilities.logSpecial) !== 'undefined'
            && utilities.logSpecial === true) || logFontColor === 'red') {

                this.fileLog(logObjects, logObjectsLength, logFontColor);

            }

        } else {

            // get background and fontColor codes
            var color = getClientColors(logFontColor, logBackgroundColor);

            if (typeof(utilities.logVerbose) !== 'undefined'
            && utilities.logVerbose === true) {

                // log each object
                for (var i = 0; i < logObjectsLength; i++) {

                    if (typeof(logObjects[i]) === 'string') {

                        console.log('%c' + logObjects[i], 'background: #' + color.background + '; color: #' + color.font);

                    } else {

                        console.log(logObjects[i]);

                    }

                };

            }

            // log to html if logSpecial is enabled
            if (typeof(utilities.logSpecial) !== 'undefined'
            && utilities.logSpecial === true) {

                this.htmlLog(logObjects, logObjectsLength, color.font, color.background);

            }

        }

    };

    /**
     *
     * get the client side (browser) colors
     *
     * @param {type} logFontColor
     * @param {type} logBackgroundColor
     * @returns {_L16.getClientColors.Anonym$2}
     */
    var getClientColors = function getClientColorsFunction(logFontColor, logBackgroundColor) {

        var colors = {};

        colors.red = 'FF0000';
        colors.green = '00FF00';
        colors.yellow = 'FFFF00';
        colors.blue = '0000FF';
        colors.magenta = 'FF00FF';
        colors.cyan = '00FFFF';
        colors.white = 'FFFFFF';
        colors.black = '000000';

        var fontColor;
        var backgroundColor;

        // font color
        if (typeof(logFontColor) === 'undefined'
        || logFontColor === 'default') {

            fontColor = colors['black'];

        } else {

            if (typeof(colors[logFontColor]) !== 'undefined') {

                fontColor = colors[logFontColor];

            } else {

                throw 'unknown fontColor in utilities console log';

            }

        }

        // background color
        if (typeof(logBackgroundColor) === 'undefined'
        || logBackgroundColor === 'default') {

            backgroundColor = colors['white'];

        } else {

            if (typeof(colors[logBackgroundColor]) !== 'undefined') {

                backgroundColor = colors[logBackgroundColor];

            } else {

                throw 'unknown fontColor in utilities console log';

            }

        }

        return { font: fontColor, background: backgroundColor };

    };

    /**
     *
     * get the colors for the backend (server) console
     *
     * @param {type} logFontColor
     * @param {type} logBackgroundColor
     * @returns {_L16.getServerColors.Anonym$2}
     */
    var getServerColors = function getServerColorsFunction(logFontColor, logBackgroundColor) {

        var backgroundColors = {};

        backgroundColors.black = '\u001b[40m';
        backgroundColors.red = '\u001b[41m';
        backgroundColors.green = '\u001b[42m';
        backgroundColors.yellow = '\u001b[43m';
        backgroundColors.blue = '\u001b[44m';
        backgroundColors.magenta = '\u001b[45m';
        backgroundColors.cyan = '\u001b[46m';
        backgroundColors.white = '\u001b[47m';

        var foregroundColors = {};

        foregroundColors.black = '\u001b[30m';
        foregroundColors.red = '\u001b[31m';
        foregroundColors.green = '\u001b[32m';
        foregroundColors.yellow = '\u001b[33m';
        foregroundColors.blue = '\u001b[34m';
        foregroundColors.magenta = '\u001b[35m';
        foregroundColors.cyan = '\u001b[36m';
        foregroundColors.white = '\u001b[37m';

        var fontColor;
        var backgroundColor;

        // font color
        if (typeof(logFontColor) === 'undefined'
        || logFontColor === 'default') {

            fontColor = foregroundColors['white'];

        } else {

            if (typeof(foregroundColors[logFontColor]) !== 'undefined') {

                fontColor = foregroundColors[logFontColor];

            } else {

                throw 'unknown font color in utilities console log';

            }

        }

        // background color
        if (typeof(logBackgroundColor) === 'undefined'
        || logBackgroundColor === 'default') {

            backgroundColor = backgroundColors['black'];

        } else {

            if (typeof(backgroundColors[logBackgroundColor]) !== 'undefined') {

                backgroundColor = backgroundColors[logBackgroundColor];

            } else {

                throw 'unknown background color in utilities console log';

            }

        }

        return { font: fontColor, background: backgroundColor, reset: '\u001b[0m' };

    };

    /**
     *
     * handle log arguments
     * extract the color infos from the arguments to log
     *
     * @param {type} logArguments
     * @returns {_L16.handleLogArguments.Anonym$2}
     */
    var handleLogArguments = function handleLogArgumentsFunction(logArguments) {

        var logObjects = [];

        var logFontColor = utilities.logFontColor;
        var logBackgroundColor = utilities.logBackgroundColor;

        var argumentsLength = logArguments.length;

        var i;

        for (i = 0; i < argumentsLength; i++) {

            var argument = logArguments[i];

            if (typeof(argument) === 'string') {

                if (argument.substr(0, 10) === 'fontColor:') {

                    logFontColor = argument.substr(10, argument.length);

                } else if (argument.substr(0, 16) === 'backgroundColor:') {

                    logBackgroundColor = argument.substr(16, argument.length);

                } else {

                    logObjects.push(argument);

                }

            } else {

                logObjects.push(argument);

            }

        }

        return { objects: logObjects, fontColor: logFontColor, backgroundColor: logBackgroundColor };

    };

    /**
     *
     * returns the timestamp of right now for browser that dont support
     * es5 Date.now
     *
     * @returns {Number}
     */
    utilities.getTimestamp = function getTimestampFunction() {

        return new Date().getTime();

    };

    /**
     *
     * extracts html elements (and their content) from strings
     *
     * @param {type} text
     * @param {type} removeTextBetweenTags
     * @returns {unresolved}
     */
    utilities.removeElements = function removeElementsFunction(text, removeTextBetweenTags) {

        if (removeTextBetweenTags !== undefined && removeTextBetweenTags === false) {

            // replace single tags
            text = text.replace(/<[^>]*>?/g, '');

        } else {

            // replace all tags and whats inside
            text = text.replace(/<[^>]*>[^>]*<\/[^>]*>?/g, '');

            // replace single tags
            text = text.replace(/<[^>]*>?/g, '');

        }

        return text;

    };

    /**
     *
     * returns a universally unique identifier
     *
     * @returns {unresolved}
     */
    utilities.generateUUID = function generateUUIDFunction() {

        // http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript

        // http://www.ietf.org/rfc/rfc4122.txt
        var s = [];
        var hexDigits = "0123456789abcdef";
        var i;

        for (i = 0; i < 36; i++) {
            s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
        }

        s[14] = "4";  // bits 12-15 of the time_hi_and_version field to 0010
        s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1);  // bits 6-7 of the clock_seq_hi_and_reserved to 01
        s[8] = s[13] = s[18] = s[23] = "-";

        var uuid = s.join("");

        return uuid;

    };

    /**
     *
     * filters a string
     * removes everything that is a not an alpha or numeric character, plus
     * the characters if any got specified as second argument
     *
     * @param {type} inputString
     * @param {type} specialCharacters
     * @returns {Boolean}
     */
    utilities.filterAlphaNumericPlus = function filterAlphaNumericFunctionPlus(inputString, specialCharacters) {

        if (typeof(inputString) === 'string' && inputString.length > 0) {

            var outputString;

            if (specialCharacters !== undefined) {

                var regex = RegExp('[^a-z0-9' + specialCharacters + ']', 'gi');

                outputString = inputString.replace(regex, '');

            } else {

                outputString = inputString.replace(/[^a-z0-9]/gi, '');

            }

            return outputString;

        }

        return false;

    };

    /**
     *
     * decode uri
     *
     * @param {type} uri
     * @returns {unresolved}
     */
    utilities.decodeUri = function decodeUriFunction(uri) {

        var additionToSpace = '/\+/g';  // replace addition symbol with a space

        return decodeURIComponent(uri.replace(additionToSpace, ' '));

    };

    /**
     *
     * encode uri
     *
     * @param {type} uri
     * @returns {unresolved}
     */
    utilities.encodeUri = function (uri) {

        return encodeURIComponent(uri);

    };

    /**
     *
     *
     *
     * @param {type} array
     * @param {type} removeMe
     * @returns {undefined}
     */
    utilities.arrayRemove = function arrayRemove(array, removeMe) {

        var index = array.indexOf(removeMe);

        if (index > -1) {

            array.splice(index, 1);

        }

    };

    /**
     *
     * capitalise first letter of a string
     *
     * @param {type} string
     * @returns {unresolved}
     */
    utilities.capitaliseFirstLetter = function capitaliseFirstLetterFunction(string) {

        return string.charAt(0).toUpperCase() + string.slice(1);

    };

    /**
     *
     * get url parameters
     *
     * @param {type} query
     * @returns {_L16.utilities@call;decodeUri|Boolean}
     */
    utilities.getUrlParameters = function getUrlParametersFunction(query) {

        if (query === undefined) {

            if (window !== undefined) {

                query  = window.location.search.substring(1);

            } else {

                throw 'you must provide a query to parse';

            }

        }

        var search = /([^&=]+)=?([^&]*)/g;
        var urlParams = {};
        var parameters = search.exec(query);
        var i;

        for (i=0; i<= parameters.length; i++) {

            var parameter = parameters[i];

            urlParams[decode(parameter[1])] = this.decodeUri(parameter[2]);

        }

        return urlParams;

    };

    /**
     *
     * does a string contain another string
     *
     * @param {type} string
     * @param {type} contains
     * @returns {Boolean}
     */
    utilities.stringContains = function stringContainsFunction(string, contains) {

        if (typeof string !== 'string') {

            throw 'input is not a string';

        }

        if (string.indexOf(contains) > -1) {

            return true;

        } else {

            return false;

        }

    };

    /**
     *
     * get the index of a substring in a string with optional nth time it occurs
     *
     * @param {type} string
     * @param {type} substring
     * @param {type} nthTime
     * @returns {unresolved}
     */
    utilities.getSubstringIndex = function getSubstringIndexFunction(string, substring, nthTime) {

        var times = 0;
        var index = null;

        if (nthTime === 0) {

            nthTime = 1;

        }

        while (times < nthTime && index !== -1) {

            index = string.indexOf(substring, index+1);
            times++;

        }

        return index;

    };

    // this module can be used in the browser as well as in nodejs
    if (typeof(module) === 'object' && typeof(module.exports) === 'object') {
        module.exports = utilities;
    } else if (typeof(define) === 'function' && define.amd) {
        define('chrisweb.utilities', [], function() {
            return utilities;
        });
    }

})();
<commit_msg>added isServer and isClient methods<commit_after>
/**
 *
 * TODO:
 * - use arguments in function to let user pass multiple variables as for
 * original console log
 * - let user set color with argument color:color_name
 * - let user change environment with environment:environment_mode
 * - let user choose default color on initialization
 * - let user set environment on initialization
 * - silence console logs on production mode
 *
 * @returns {undefined}
 */

(function() {

    'use strict';

    var utilities = {};

    utilities.version = '0.0.4';

    var errorLogger;

    utilities.logFontColor = 'default';

    utilities.logBackgroundColor = 'default';

    utilities.logSpecial = false;

    utilities.logVerbose = true;

    /**
     *
     * html log
     * create a div an insert the messages in div
     * can be usefull on mobile if no other console is available
     *
     * @param {type} logObjects
     * @param {type} logObjectsLength
     * @param {type} logFontColor
     * @param {type} logBackgroundColor
     * @returns {undefined}
     */
    utilities.htmlLog = function (logObjects, logObjectsLength, logFontColor, logBackgroundColor) {

        // TODO: fix: seems that if logging starts before "domload" some
        // messages get lost

        if (document.getElementById('log') === null) {

            var logDiv = document.createElement('div');

            logDiv.id = 'log';

            logDiv.style.cssText = 'position: absolute; overflow: scroll; left: 0; bottom: 0; padding: 0; margin: 0; border: 0; z-index: 999999; width: 100%; height: 20%; background-color: #fff;';

            document.body.appendChild(logDiv);

        }

        for (var i = 0; i < logObjectsLength; i++) {

            var logSpan = document.createElement('span');

            logSpan.style.cssText = 'color: #' + logFontColor + '; background-color: #' + logBackgroundColor + ';';

            var spanContent = document.createTextNode(logObjects[i]);

            logSpan.appendChild(spanContent);

            document.getElementById('log').appendChild(logSpan);

            var brElement = document.createElement('br');

            document.getElementById('log').appendChild(brElement);

        }

    };

    /**
     *
     * file log
     * nodejs logging to file
     *
     * @param {type} logObjects
     * @param {type} logObjectsLength
     * @param {type} logFontColor
     * @returns {undefined}
     */
    utilities.fileLog = function fileLogFunction(logObjects, logObjectsLength, logFontColor) {

		try {

			var winston = require('winston');

			for (var i = 0; i < logObjectsLength; i++) {

				switch(logFontColor) {
					case 'red':
						winston.error(logObjects[i]);
						break;
					case 'yellow':
						winston.warn(logObjects[i]);
						break;
					default:
						winston.info(logObjects[i]);
				}

			}

		} catch(e) {

			// winston is not installed

		}

    };

    /**
     *
     * log messages
     *
     * @returns {Boolean}
     */
    utilities.log = function logFunction() {

        // is console defined, some older IEs don't have a console
        if (typeof(console) === 'undefined') {

            return false;

        }

        // extract options and get objects to log
        var logArguments = handleLogArguments(arguments);

        var logObjects = logArguments.objects;
        var logFontColor = logArguments.fontColor;
        var logBackgroundColor = logArguments.backgroundColor;

        var logObjectsLength = logObjects.length;

        // nodejs or browser mode
        if (typeof(window) === 'undefined') {

            if (typeof(utilities.logVerbose) !== 'undefined'
            && utilities.logVerbose === true) {

                // get background and fontColor codes
                var color = getServerColors(logFontColor, logBackgroundColor);

                // log each object
                for (var i = 0; i < logObjectsLength; i++) {

                    if (typeof(logObjects[i]) === 'string') {

                        console.log(color.background + color.font + logObjects[i] + color.reset);

                    } else {

                        console.log(logObjects[i]);

                    }

                };

            }

            // log to file if logSpecial is enabled or if the fontColor is red
            if ((typeof(utilities.logSpecial) !== 'undefined'
            && utilities.logSpecial === true) || logFontColor === 'red') {

                this.fileLog(logObjects, logObjectsLength, logFontColor);

            }

        } else {

            // get background and fontColor codes
            var color = getClientColors(logFontColor, logBackgroundColor);

            if (typeof(utilities.logVerbose) !== 'undefined'
            && utilities.logVerbose === true) {

                // log each object
                for (var i = 0; i < logObjectsLength; i++) {

                    if (typeof(logObjects[i]) === 'string') {

                        console.log('%c' + logObjects[i], 'background: #' + color.background + '; color: #' + color.font);

                    } else {

                        console.log(logObjects[i]);

                    }

                };

            }

            // log to html if logSpecial is enabled
            if (typeof(utilities.logSpecial) !== 'undefined'
            && utilities.logSpecial === true) {

                this.htmlLog(logObjects, logObjectsLength, color.font, color.background);

            }

        }

    };

    /**
     *
     * get the client side (browser) colors
     *
     * @param {type} logFontColor
     * @param {type} logBackgroundColor
     * @returns {_L16.getClientColors.Anonym$2}
     */
    var getClientColors = function getClientColorsFunction(logFontColor, logBackgroundColor) {

        var colors = {};

        colors.red = 'FF0000';
        colors.green = '00FF00';
        colors.yellow = 'FFFF00';
        colors.blue = '0000FF';
        colors.magenta = 'FF00FF';
        colors.cyan = '00FFFF';
        colors.white = 'FFFFFF';
        colors.black = '000000';

        var fontColor;
        var backgroundColor;

        // font color
        if (typeof(logFontColor) === 'undefined'
        || logFontColor === 'default') {

            fontColor = colors['black'];

        } else {

            if (typeof(colors[logFontColor]) !== 'undefined') {

                fontColor = colors[logFontColor];

            } else {

                throw 'unknown fontColor in utilities console log';

            }

        }

        // background color
        if (typeof(logBackgroundColor) === 'undefined'
        || logBackgroundColor === 'default') {

            backgroundColor = colors['white'];

        } else {

            if (typeof(colors[logBackgroundColor]) !== 'undefined') {

                backgroundColor = colors[logBackgroundColor];

            } else {

                throw 'unknown fontColor in utilities console log';

            }

        }

        return { font: fontColor, background: backgroundColor };

    };

    /**
     *
     * get the colors for the backend (server) console
     *
     * @param {type} logFontColor
     * @param {type} logBackgroundColor
     * @returns {_L16.getServerColors.Anonym$2}
     */
    var getServerColors = function getServerColorsFunction(logFontColor, logBackgroundColor) {

        var backgroundColors = {};

        backgroundColors.black = '\u001b[40m';
        backgroundColors.red = '\u001b[41m';
        backgroundColors.green = '\u001b[42m';
        backgroundColors.yellow = '\u001b[43m';
        backgroundColors.blue = '\u001b[44m';
        backgroundColors.magenta = '\u001b[45m';
        backgroundColors.cyan = '\u001b[46m';
        backgroundColors.white = '\u001b[47m';

        var foregroundColors = {};

        foregroundColors.black = '\u001b[30m';
        foregroundColors.red = '\u001b[31m';
        foregroundColors.green = '\u001b[32m';
        foregroundColors.yellow = '\u001b[33m';
        foregroundColors.blue = '\u001b[34m';
        foregroundColors.magenta = '\u001b[35m';
        foregroundColors.cyan = '\u001b[36m';
        foregroundColors.white = '\u001b[37m';

        var fontColor;
        var backgroundColor;

        // font color
        if (typeof(logFontColor) === 'undefined'
        || logFontColor === 'default') {

            fontColor = foregroundColors['white'];

        } else {

            if (typeof(foregroundColors[logFontColor]) !== 'undefined') {

                fontColor = foregroundColors[logFontColor];

            } else {

                throw 'unknown font color in utilities console log';

            }

        }

        // background color
        if (typeof(logBackgroundColor) === 'undefined'
        || logBackgroundColor === 'default') {

            backgroundColor = backgroundColors['black'];

        } else {

            if (typeof(backgroundColors[logBackgroundColor]) !== 'undefined') {

                backgroundColor = backgroundColors[logBackgroundColor];

            } else {

                throw 'unknown background color in utilities console log';

            }

        }

        return { font: fontColor, background: backgroundColor, reset: '\u001b[0m' };

    };

    /**
     *
     * handle log arguments
     * extract the color infos from the arguments to log
     *
     * @param {type} logArguments
     * @returns {_L16.handleLogArguments.Anonym$2}
     */
    var handleLogArguments = function handleLogArgumentsFunction(logArguments) {

        var logObjects = [];

        var logFontColor = utilities.logFontColor;
        var logBackgroundColor = utilities.logBackgroundColor;

        var argumentsLength = logArguments.length;

        var i;

        for (i = 0; i < argumentsLength; i++) {

            var argument = logArguments[i];

            if (typeof(argument) === 'string') {

                if (argument.substr(0, 10) === 'fontColor:') {

                    logFontColor = argument.substr(10, argument.length);

                } else if (argument.substr(0, 16) === 'backgroundColor:') {

                    logBackgroundColor = argument.substr(16, argument.length);

                } else {

                    logObjects.push(argument);

                }

            } else {

                logObjects.push(argument);

            }

        }

        return { objects: logObjects, fontColor: logFontColor, backgroundColor: logBackgroundColor };

    };

    /**
     *
     * returns the timestamp of right now for browser that dont support
     * es5 Date.now
     *
     * @returns {Number}
     */
    utilities.getTimestamp = function getTimestampFunction() {

        return new Date().getTime();

    };

    /**
     *
     * extracts html elements (and their content) from strings
     *
     * @param {type} text
     * @param {type} removeTextBetweenTags
     * @returns {unresolved}
     */
    utilities.removeElements = function removeElementsFunction(text, removeTextBetweenTags) {

        if (removeTextBetweenTags !== undefined && removeTextBetweenTags === false) {

            // replace single tags
            text = text.replace(/<[^>]*>?/g, '');

        } else {

            // replace all tags and whats inside
            text = text.replace(/<[^>]*>[^>]*<\/[^>]*>?/g, '');

            // replace single tags
            text = text.replace(/<[^>]*>?/g, '');

        }

        return text;

    };

    /**
     *
     * returns a universally unique identifier
     *
     * @returns {unresolved}
     */
    utilities.generateUUID = function generateUUIDFunction() {

        // http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript

        // http://www.ietf.org/rfc/rfc4122.txt
        var s = [];
        var hexDigits = "0123456789abcdef";
        var i;

        for (i = 0; i < 36; i++) {
            s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
        }

        s[14] = "4";  // bits 12-15 of the time_hi_and_version field to 0010
        s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1);  // bits 6-7 of the clock_seq_hi_and_reserved to 01
        s[8] = s[13] = s[18] = s[23] = "-";

        var uuid = s.join("");

        return uuid;

    };

    /**
     *
     * filters a string
     * removes everything that is a not an alpha or numeric character, plus
     * the characters if any got specified as second argument
     *
     * @param {type} inputString
     * @param {type} specialCharacters
     * @returns {Boolean}
     */
    utilities.filterAlphaNumericPlus = function filterAlphaNumericFunctionPlus(inputString, specialCharacters) {

        if (typeof(inputString) === 'string' && inputString.length > 0) {

            var outputString;

            if (specialCharacters !== undefined) {

                var regex = RegExp('[^a-z0-9' + specialCharacters + ']', 'gi');

                outputString = inputString.replace(regex, '');

            } else {

                outputString = inputString.replace(/[^a-z0-9]/gi, '');

            }

            return outputString;

        }

        return false;

    };

    /**
     *
     * decode uri
     *
     * @param {type} uri
     * @returns {unresolved}
     */
    utilities.decodeUri = function decodeUriFunction(uri) {

        var additionToSpace = '/\+/g';  // replace addition symbol with a space

        return decodeURIComponent(uri.replace(additionToSpace, ' '));

    };

    /**
     *
     * encode uri
     *
     * @param {type} uri
     * @returns {unresolved}
     */
    utilities.encodeUri = function (uri) {

        return encodeURIComponent(uri);

    };

    /**
     *
     *
     *
     * @param {type} array
     * @param {type} removeMe
     * @returns {undefined}
     */
    utilities.arrayRemove = function arrayRemove(array, removeMe) {

        var index = array.indexOf(removeMe);

        if (index > -1) {

            array.splice(index, 1);

        }

    };

    /**
     *
     * capitalise first letter of a string
     *
     * @param {type} string
     * @returns {unresolved}
     */
    utilities.capitaliseFirstLetter = function capitaliseFirstLetterFunction(string) {

        return string.charAt(0).toUpperCase() + string.slice(1);

    };

    /**
     *
     * get url parameters
     *
     * @param {type} query
     * @returns {_L16.utilities@call;decodeUri|Boolean}
     */
    utilities.getUrlParameters = function getUrlParametersFunction(query) {

        if (query === undefined) {

            if (window !== undefined) {

                query  = window.location.search.substring(1);

            } else {

                throw 'you must provide a query to parse';

            }

        }

        var search = /([^&=]+)=?([^&]*)/g;
        var urlParams = {};
        var parameters = search.exec(query);
        var i;

        for (i=0; i<= parameters.length; i++) {

            var parameter = parameters[i];

            urlParams[decode(parameter[1])] = this.decodeUri(parameter[2]);

        }

        return urlParams;

    };

    /**
     *
     * does a string contain another string
     *
     * @param {type} string
     * @param {type} contains
     * @returns {Boolean}
     */
    utilities.stringContains = function stringContainsFunction(string, contains) {

        if (typeof string !== 'string') {

            throw 'input is not a string';

        }

        if (string.indexOf(contains) > -1) {

            return true;

        } else {

            return false;

        }

    };

    /**
     *
     * get the index of a substring in a string with optional nth time it occurs
     *
     * @param {type} string
     * @param {type} substring
     * @param {type} nthTime
     * @returns {unresolved}
     */
    utilities.getSubstringIndex = function getSubstringIndexFunction(string, substring, nthTime) {

        var times = 0;
        var index = null;

        if (nthTime === 0) {

            nthTime = 1;

        }

        while (times < nthTime && index !== -1) {

            index = string.indexOf(substring, index+1);
            times++;

        }

        return index;

    };

    utilities.isServer = function isServerFunction() {
    	if (typeof(module) === 'object' && typeof(module.exports) === 'object') {
    		return true;
    	} else {
    		return false;
    	}
    };

    utilities.isClient = function isClientFunction() {
    	return !this.isServer();
    };

    // this module can be used in the browser as well as in nodejs
    if (typeof(module) === 'object' && typeof(module.exports) === 'object') {
        module.exports = utilities;
    } else if (typeof(define) === 'function' && define.amd) {
        define('chrisweb.utilities', [], function() {
            return utilities;
        });
    }

})();
<|endoftext|>


<commit_before>angular.module('genesis.services', ['pubnub.angular.service'])
.factory('User', function ($http, $window) {

  var username = $window.localStorage.getItem('com.genesis').username;
  var getUserData = function () {
    return $http({
      method: 'GET',
      url: '/api/users',
      data: {
        username: username
      }
    }).then(function (res) {
      console.log('username is '+username);
      return res.data;
    })
  };

  return {
    getUserData: getUserData
  };

})
.factory('Keys', function($http, Pubnub) {

  // Wrap videochat controller in promise, ensure access to keys
  return $http.get('/keys').then(function(keys) {
      console.log('here are the keys on client:');
      console.log(keys);
      var pub_sub = keys.data;
      return pub_sub;
  });

})
.factory('Video', function(Pubnub) {

  // PubNub Video Functionality
  var video_out  = document.getElementById("vid-box");
  var embed_code = document.getElementById("embed-code");
  var here_now   = document.getElementById('here-now');
  var streamName;

  // public broadcasting CHANGE HARDCODE streamname to param
  var stream = function(keys) {
    streamName = 'auction-channel' || Math.floor(Math.random()*100)+''; // Random stream if not provided
    var phone = window.phone = PHONE({
        number        : streamName, // listen on username else random
        publish_key: keys[0], // Your Pub Key
        subscribe_key: keys[1], // Your Sub Key
        oneway        : true, // One-Way streaming enabled
        broadcast     : true,  // True since you are the broadcaster
        ssl : (('https:' == document.location.protocol) ? true : false)

    });
    var ctrl = window.ctrl = CONTROLLER(phone);
    ctrl.ready(function(){
      // form.streamname.style.background="#55ff5b";
      // ctrl.stream_submit.hidden="true";
      console.log(streamName);
      ctrl.addLocalStream(video_out);
      ctrl.stream();  // Begin streaming video
    });
    ctrl.streamPresence(function(m){ here_now.innerHTML=m.occupancy; });
    return false;  // So form does not submit
  };

  // watching CHANGE HARDCODE num to param
  var watch = function(keys){
    var num = 'auction-channel';  // Stream to join
    var phone = window.phone = PHONE({
        number        : "Viewer" + Math.floor(Math.random()*100), // Random name
        publish_key: keys[0],
        subscribe_key: keys[1], // Your Sub Key
        oneway        : true,  // One way streaming enabled
        ssl : (('https:' == document.location.protocol) ? true : false)

    });
    var ctrl = window.ctrl = CONTROLLER(phone, true);
    ctrl.ready(function(){
      console.log(num);
      ctrl.isStreaming(num, function(isOn){
        if (isOn) ctrl.joinStream(num);
        else alert("User is not streaming!");
      });
    });
    ctrl.receive(function(session){
        session.connected(function(session){ video_out.appendChild(session.video); });
    });
    ctrl.streamPresence(function(m){ here_now.innerHTML=m.occupancy; });
    return false;  // Prevent form from submitting
  };

  return {
    stream: stream,
    watch: watch
  };

});
<commit_msg>Fixed backend setting for watching streams<commit_after>angular.module('genesis.services', ['pubnub.angular.service'])
.factory('User', function ($http, $window) {

  var username = $window.localStorage.getItem('com.genesis').username;
  var getUserData = function () {
    return $http({
      method: 'GET',
      url: '/api/users',
      data: {
        username: username
      }
    }).then(function (res) {
      console.log('username is '+username);
      return res.data;
    })
  };

  return {
    getUserData: getUserData
  };

})
.factory('Keys', function($http, Pubnub) {

  // Wrap videochat controller in promise, ensure access to keys
  return $http.get('/keys').then(function(keys) {
      console.log('here are the keys on client:');
      console.log(keys);
      var pub_sub = keys.data;
      return pub_sub;
  });

})
.factory('Video', function(Pubnub) {

  // PubNub Video Functionality
  var video_out  = document.getElementById("vid-box");
  var embed_code = document.getElementById("embed-code");
  var here_now   = document.getElementById('here-now');
  var streamName;

  // public broadcasting CHANGE HARDCODE streamname to param
  var stream = function(keys) {
    streamName = 'auction-name' || Math.floor(Math.random()*100)+''; // Random stream if not provided
    var phone = window.phone = PHONE({
        number        : streamName, // listen on username else random
        publish_key: keys[0], // Your Pub Key
        subscribe_key: keys[1], // Your Sub Key
        oneway        : true, // One-Way streaming enabled
        broadcast     : true,  // True since you are the broadcaster
        ssl : (('https:' == document.location.protocol) ? true : false)

    });
    var ctrl = window.ctrl = CONTROLLER(phone);
    ctrl.ready(function(){
      // form.streamname.style.background="#55ff5b";
      // ctrl.stream_submit.hidden="true";
      console.log(streamName);
      ctrl.addLocalStream(video_out);
      ctrl.stream();  // Begin streaming video
    });
    ctrl.streamPresence(function(m){ here_now.innerHTML=m.occupancy; });
    return false;  // So form does not submit
  };

  // watching CHANGE HARDCODE num to param
  var watch = function(keys){
    var num = 'auction-name';  // Stream to join
    var phone = window.phone = PHONE({
        number        : "Viewer" + Math.floor(Math.random()*100), // Random name
        publish_key: keys[0],
        subscribe_key: keys[1], // Your Sub Key
        oneway        : true,  // One way streaming enabled
        ssl : (('https:' == document.location.protocol) ? true : false)

    });
    var ctrl = window.ctrl = CONTROLLER(phone, true);
    ctrl.ready(function(){
      console.log(num);
      ctrl.isStreaming(num, function(isOn){
        if (isOn) ctrl.joinStream(num);
        else alert("User is not streaming!");
      });
    });
    ctrl.receive(function(session){
        session.connected(function(session){ video_out.appendChild(session.video); });
    });
    ctrl.streamPresence(function(m){ here_now.innerHTML=m.occupancy; });
    return false;  // Prevent form from submitting
  };

  return {
    stream: stream,
    watch: watch
  };

});
<|endoftext|>


<commit_before>'use strict';

var http = require('http');

var assert = require('assertive');

var fetch = require('../lib/fetch');

describe('fetch', function() {
  var server;

  before('start echo server', function(done) {
    server = http.createServer(function(req, res) {
      res.writeHead(200, {
        'Content-Type': 'application/json',
      });
      res.end(JSON.stringify({
        method: req.method,
        url: req.url,
        headers: req.headers,
      }));
    });
    server.on('error', done);
    server.listen(3000, function() { done(); });
  });

  after('close echo server', function(done) {
    server.close(done);
  });

  it('can fetch stuff', function() {
    var headers = { 'x-Fancy': 'stuff' };
    headers['X-Fancy'] = 'other stuff';
    return fetch('http://localhost:3000/foo', { headers: headers })
      .json()
      .then(function(echo) {
        assert.equal('GET', echo.method);
        assert.equal('/foo', echo.url);
        assert.equal('overriding headers works thanks to key ordering',
          'other stuff', echo.headers['x-fancy']);
      });
  });
});
<commit_msg>Add test for empty body<commit_after>'use strict';

var http = require('http');

var assert = require('assertive');

var fetch = require('../lib/fetch');

describe('fetch', function() {
  var server;

  before('start echo server', function(done) {
    server = http.createServer(function(req, res) {
      var chunks = [];
      req.on('data', function(chunk) {
        chunks.push(chunk);
      });
      req.on('end', function() {
        res.writeHead(200, {
          'Content-Type': 'application/json',
        });
        res.end(JSON.stringify({
          method: req.method,
          url: req.url,
          headers: req.headers,
          body: Buffer.concat(chunks).toString()
        }));
      });
    });
    server.on('error', done);
    server.listen(3000, function() { done(); });
  });

  after('close echo server', function(done) {
    server.close(done);
  });

  it('can fetch stuff', function() {
    var headers = { 'x-Fancy': 'stuff' };
    headers['X-Fancy'] = 'other stuff';
    return fetch('http://localhost:3000/foo', { headers: headers })
      .json()
      .then(function(echo) {
        assert.equal('GET', echo.method);
        assert.equal('/foo', echo.url);
        assert.equal('', echo.body);
        assert.equal('overriding headers works thanks to key ordering',
          'other stuff', echo.headers['x-fancy']);
      });
  });
});
<|endoftext|>


<commit_before>import controller from './app.controller';

export default function routes($urlRouterProvider, $httpProvider, $stateProvider) {
    $httpProvider.interceptors.push('interceptor');

    $stateProvider
        .state('default', {
            controller: controller.UID,
            controllerAs:'$ctrl',
            params: {
                chromosome: {squash: true, value: null},
                end: {squash: true, value: null},
                referenceId: {squash: true, value: null},
                start: {squash: true, value: null},

                bookmark: null,
                layout: null,
                rewrite:null,
                screenshot: null,
                toolbar: null,
                tracks: null,
                filterByGenome: null,
                collapsedTrackHeaders: null,
                miew: null,
                heatmap: null,
                pathway: null,
                embedded: null,
                controls: null,
                auth: null
            },
            resolve: {
                $stateParams: '$stateParams'
            },
            reloadOnSearch: false,
            template: require('./app.tpl.html'),
            url: '/:referenceId/:chromosome/:start/:end?rewrite&bookmark&screenshot&toolbar&layout&tracks&filterByGenome&collapsedTrackHeaders&miew&heatmap&embedded&controls&pathway?auth'
        });

}
<commit_msg>JS API enhancements: loadRegisteredTracks, load nested projects, token management (#833), route fix<commit_after>import controller from './app.controller';

export default function routes($urlRouterProvider, $httpProvider, $stateProvider) {
    $httpProvider.interceptors.push('interceptor');

    $stateProvider
        .state('default', {
            controller: controller.UID,
            controllerAs:'$ctrl',
            params: {
                chromosome: {squash: true, value: null},
                end: {squash: true, value: null},
                referenceId: {squash: true, value: null},
                start: {squash: true, value: null},

                bookmark: null,
                layout: null,
                rewrite:null,
                screenshot: null,
                toolbar: null,
                tracks: null,
                filterByGenome: null,
                collapsedTrackHeaders: null,
                miew: null,
                heatmap: null,
                pathway: null,
                embedded: null,
                controls: null,
                auth: null
            },
            resolve: {
                $stateParams: '$stateParams'
            },
            reloadOnSearch: false,
            template: require('./app.tpl.html'),
            url: '/:referenceId/:chromosome/:start/:end?rewrite&bookmark&screenshot&toolbar&layout&tracks&filterByGenome&collapsedTrackHeaders&miew&heatmap&embedded&controls&pathway&auth'
        });

}
<|endoftext|>


<commit_before>var pull = require('../')

require('tape')('group', function (t) {
  pull.count()
  .pipe(pull.take(20))
  .pipe(pull.group(7))
  .pipe(pull.group(3))
  .pipe(function (read) {
    return function (end, cb) {
      read(null, function (end, data) {
        if(!end) t.deepEqual(data, [
          [0, 1,2,3,4,5,6],
          [7,8,9,10,11,12,13],
          [14, 15,16,17,18,19]
        ])
       process.nextTick(cb.bind(null, end, data))
      })
    }
  })
  .pipe(pull.drain(function () {
    t.end()
  }))
})
<commit_msg>logging it tests<commit_after>var pull = require('../')

require('tape')('group', function (t) {
  pull.count()
  .pipe(pull.take(20))
  .pipe(pull.group(7))
  .pipe(pull.group(3))
  .pipe(function (read) {
    return function (end, cb) {
      read(null, function (end, data) {
        if(!end) {
          t.deepEqual(data, [
            [0, 1,2,3,4,5,6],
            [7,8,9,10,11,12,13],
            [14, 15,16,17,18,19]
          ])
          console.log(data)
        }
       process.nextTick(cb.bind(null, end, data))
      })
    }
  })
  .pipe(pull.drain(function () {
    t.end()
  }))
})
<|endoftext|>


<commit_before>let mongoose = require('mongoose')
let House = require('../api/models/houseModel')

let chai = require('chai')
let chaiHttp = require('chai-http')
let server = require('../server')
let should = chai.should()

chai.use(chaiHttp)

// Parent block
describe('Houses', () => {
  /*
   * Test the /GET route
   */
  describe('/GET api/v1/houses', () => {
    it('should GET all houses', (done) => {
      chai.request(server)
        .get('/api/v1/houses')
        .end((err, res) => {
          res.should.have.status(200)
          res.body.should.be.a('array')
          done()
        })
    })
  })

  describe('/POST api/v1/houses', () => {
    it('should not POST a house without Authorization', (done) => {
      let house = {
        short_description: "Up on the mountain",
        long_description: "Nothing like a house not by the sea, but up high on mountain Kerkis.",
        price: 200
      }
      chai.request(server)
        .post('/api/v1/houses')
        .send(house)
        .end((err, res) => {
          res.should.have.status(401)
          done()
        })
    })
    // it('it should POST a house', (done) => {
    //   let house = {
    //     short_description: "Up on the mountain",
    //     long_description: "Nothing like a house not by the sea, but up high on mountain Kerkis.",
    //     price: 200
    //   }
    //   chai.request(server)
    //     .post('/api/v1/houses')
    //     .send(house)
    //     .end((err, res) => {
    //       res.should.have.status(200)
    //       res.body.should.be.a('object')
    //       res.body.house.should.have.property('short_description')
    //       res.body.house.should.have.property('long_description')
    //       res.body.house.should.have.property('price')
    //       res.body.house.should.have.property('created_at')
    //       done()
    //     })
    // })
  })

})
<commit_msg>Add test for showing a single House by houseId.<commit_after>let mongoose = require('mongoose')
let House = require('../api/models/houseModel')

let chai = require('chai')
let chaiHttp = require('chai-http')
let server = require('../server')
let should = chai.should()

chai.use(chaiHttp)

// Parent block
describe('Houses', () => {

  describe('/GET api/v1/houses', () => {
    it('should GET all houses', (done) => {
      chai.request(server)
        .get('/api/v1/houses')
        .end((err, res) => {
          res.should.have.status(200)
          res.body.should.be.a('array')
          done()
        })
    })
  })

  describe('/GET api/v1/houses/:houseId', () => {
    it('should GET a house', (done) => {
      chai.request(server)
        .get('/api/v1/houses/594fdbf2579f162b199576eb')
        .end((err, res) => {
          res.should.have.status(200)
          res.body.should.be.a('object')
          res.body.should.have.property('short_description')
          res.body.should.have.property('long_description')
          res.body.should.have.property('price')
          res.body.should.have.property('owner')
          done()
        })
    })
  })

  describe('/POST api/v1/houses', () => {
    it('should not POST a house without Authorization', (done) => {
      let house = {
        short_description: "Up on the mountain",
        long_description: "Nothing like a house not by the sea, but up high on mountain Kerkis.",
        price: 200
      }
      chai.request(server)
        .post('/api/v1/houses')
        .send(house)
        .end((err, res) => {
          res.should.have.status(401)
          done()
        })
    })
    // it('it should POST a house', (done) => {
    //   let house = {
    //     short_description: "Up on the mountain",
    //     long_description: "Nothing like a house not by the sea, but up high on mountain Kerkis.",
    //     price: 200
    //   }
    //   chai.request(server)
    //     .post('/api/v1/houses')
    //     .send(house)
    //     .end((err, res) => {
    //       res.should.have.status(200)
    //       res.body.should.be.a('object')
    //       res.body.house.should.have.property('short_description')
    //       res.body.house.should.have.property('long_description')
    //       res.body.house.should.have.property('price')
    //       res.body.house.should.have.property('created_at')
    //       done()
    //     })
    // })
  })

})
<|endoftext|>


<commit_before>klimaChallenge.controller('PhysicsCtrl', function($scope, $timeout) {

   var numberProjects = 15;
   var ballRadius = Math.pow(window.innerWidth, 1/2) * Math.pow(1/numberProjects, 1/10) + 30;

   Physics(function (world) {
      // world bounds to the window
      var viewportBounds = Physics.aabb(0, 0, window.innerWidth, window.innerHeight),
      edgeBounce,
      renderer;

      // create a renderer
      renderer = Physics.renderer('canvas', {
          el: 'physics-spring', // The DOM element to append the stage to
          meta: false // Turns debug info on/off
      });

      // add the renderer
      world.add(renderer);
      // render on each step
      world.on('step', function () {
         world.render();
      });

      // constrain objects to these bounds
      edgeBounce = Physics.behavior('edge-collision-detection', {
         aabb: viewportBounds,
         restitution: 0.4
      });

      // resize canvas on canvas resize
      window.addEventListener('resize', function () {
         viewportBounds = Physics.aabb(0, 0, renderer.width, renderer.height);
         edgeBounce.setAABB(viewportBounds);
      }, true);

      // At init the canvas won't load the correct window height, so refresh aufter 0.7s
      $timeout(function() {
         window.dispatchEvent(new Event('resize'));
      }, 700);

       // create some bodies
      for (var i = 0; i < numberProjects; i++) {
         var thisRadius = ballRadius * (Math.random() * 1.05 + 0.95);

         var icon = Physics.body('rectangle', {
            x: 0,
            y: 0,
            width: thisRadius*2-30,
            height: thisRadius*2-30
         });
         icon.view = new Image();
         icon.view.src = 'img/icons/bike.png';

         var project = Physics.body('circle', {
            x: renderer.width * 0.5,
            y: -i*1000,
            vx: 0.3,
            radius: thisRadius,
            styles: {
               fillStyle: '#8bc34a'
            }
         });

         /*
         project.view = new Image();
         project.view.src = 'img/icons/ball.png';
         project.view.width = thisRadius*2;
         project.view.height = thisRadius*2;
         */

         world.add(project);
      }

      // add behaviors to the world
      world.add([
         Physics.behavior('interactive', { el: renderer.container }),
         Physics.behavior('constant-acceleration', {acc: { x : 0, y: 0.0005 }}),
         Physics.behavior('body-impulse-response'),
         Physics.behavior('body-collision-detection'),
         Physics.behavior('sweep-prune'),
         edgeBounce
      ]);

      // Tick all bodies on page change to awake them
      $scope.$on('$locationChangeSuccess', function(event) {
         var bodies = world.getBodies();

         $timeout(function() {
            angular.forEach(bodies, function(body) {
               body.applyForce({x: 0, y: .2});
            });
         }, 500);
      });

      // subscribe to ticker to advance the simulation
      Physics.util.ticker.on(function(time) {
         world.step( time );
      });
   });

   $scope.getBallAreaHeight = function() {
      var areaHeight = Math.pow(ballRadius*2, 2) * numberProjects/window.innerWidth * 2.1 + 220;

      // Ball area shall be at least 400px high
      if (areaHeight < 400)
         return 400;
      return areaHeight;
   }
});
<commit_msg>Objekte hüpfen nicht mehr beim Seitenwechsel<commit_after>klimaChallenge.controller('PhysicsCtrl', function($scope, $timeout) {

   var numberProjects = 15;
   var ballRadius = Math.pow(window.innerWidth, 1/2) * Math.pow(1/numberProjects, 1/10) + 30;

   Physics(function (world) {
      // world bounds to the window
      var viewportBounds = Physics.aabb(0, 0, window.innerWidth, window.innerHeight),
      edgeBounce,
      renderer;

      // create a renderer
      renderer = Physics.renderer('canvas', {
          el: 'physics-spring', // The DOM element to append the stage to
          meta: false // Turns debug info on/off
      });

      // add the renderer
      world.add(renderer);
      // render on each step
      world.on('step', function () {
         world.render();
      });

      // constrain objects to these bounds
      edgeBounce = Physics.behavior('edge-collision-detection', {
         aabb: viewportBounds,
         restitution: 0.4
      });

      // resize canvas on canvas resize
      window.addEventListener('resize', function () {
         viewportBounds = Physics.aabb(0, 0, renderer.width, renderer.height);
         edgeBounce.setAABB(viewportBounds);
      }, true);

      // At init the canvas won't load the correct window height, so refresh aufter 0.7s
      $timeout(function() {
         window.dispatchEvent(new Event('resize'));
      }, 700);

       // create some bodies
      for (var i = 0; i < numberProjects; i++) {
         var thisRadius = ballRadius * (Math.random() * 1.05 + 0.95);

         var icon = Physics.body('rectangle', {
            x: 0,
            y: 0,
            width: thisRadius*2-30,
            height: thisRadius*2-30
         });
         icon.view = new Image();
         icon.view.src = 'img/icons/bike.png';

         var project = Physics.body('circle', {
            x: renderer.width * 0.5,
            y: -i*1000,
            vx: 0.3,
            radius: thisRadius,
            styles: {
               fillStyle: '#8bc34a'
            }
         });

         /*
         project.view = new Image();
         project.view.src = 'img/icons/ball.png';
         project.view.width = thisRadius*2;
         project.view.height = thisRadius*2;
         */

         world.add(project);
      }

      // add behaviors to the world
      world.add([
         Physics.behavior('interactive', { el: renderer.container }),
         Physics.behavior('constant-acceleration', {acc: { x : 0, y: 0.0005 }}),
         Physics.behavior('body-impulse-response'),
         Physics.behavior('body-collision-detection'),
         Physics.behavior('sweep-prune'),
         edgeBounce
      ]);

      // Tick all bodies on page change to awake them
      $scope.$on('$locationChangeSuccess', function(event) {
         var bodies = world.getBodies();
         angular.forEach(bodies, function(body) {
            body.sleep(false);
         });
      });

      // subscribe to ticker to advance the simulation
      Physics.util.ticker.on(function(time) {
         world.step( time );
      });
   });

   $scope.getBallAreaHeight = function() {
      var areaHeight = Math.pow(ballRadius*2, 2) * numberProjects/window.innerWidth * 2.1 + 220;

      // Ball area shall be at least 400px high
      if (areaHeight < 400)
         return 400;
      return areaHeight;
   }
});
<|endoftext|>


<commit_before>//Handles monitoring changes from the input text fields and applying them to the appropriate controller
//Also handles import and export events when the buttons are pressed

var EntityController=require('./EntityController');
var Grid=require('./Grid');
var Optimizer=require('./Optimizer');
var Calculate=require('./Calculate');

var InputController=function(){

	$('#optimizer_var_input').change(function() {
	    var variance = parseInt($(this).val());
	    if (!isNaN(variance) && variance!==0) { //to make sure the input is valid (is an integer and non-zero)
	      	Optimizer.variation=variance;
	    }
	});

	$('#desired_ratio_input').change(function() {
	    var ratio = parseInt($(this).val());
	    if (!isNaN(ratio) && ratio >1) { //to make sure the input is valid (is an integer and greater than 1)
	       EntityController.desired_ratio=ratio;
	       Calculate();
	    }
	});

	$('#member_width').change(function() {
	    var width = parseInt($(this).val());
	    if (!isNaN(width) && width >1) { //to make sure the input is valid (is an integer and greater than 1)
	       EntityController.member_width=width;
	       Calculate();
	    }
	});

	//Monitors for changes in the grid spacing input field and re-creates the grid if a change is detected
	$('#grid-size-input').change(function() {
	    var new_grid_size = parseInt($('#grid-size-input').val());
	    if (!isNaN(new_grid_size) && new_grid_size > Grid.min_grid_size) { //makes sure the new grid size is an integer and greater than the minimum grid size
	        Grid.grid_size = new_grid_size;
	        Grid.createGrid(); //recreates the grid with the new specified grid size
	    }
	});

	$('#exportBtn').click(function() {
		jsonStr = JSON.stringify(EntityController.export()); //export the entity controller as a string
		$('#export-cont').val(jsonStr); //paste the string in the export field
		$('#uniqueHash').val(EntityController.exportHash(jsonStr)); //hash the output and paste it in the hash input field
		return false;
	});

	$('#importBtn').click(function() {
		jsonStr = $('#export-cont').val(); //stores the value of the import text field
		if (jsonStr.length > 0) { //makes sure its not empty
			if (jsonStr.charAt(1) == 'A') { //if the input is a hash
				EntityController.importHash(jsonStr);
			} else { //if the input is not hashed
				jsonObj = JSON.parse(jsonStr);
				EntityController.import(jsonObj);
			}
		}
		return false;
	});

	//selects all of the text on click of the export and hash input fields
	$('#export-cont').click(function () {
		this.select();
	});
	$('#uniqueHash').click(function() {
		this.select();
	});
};

module.exports=InputController;<commit_msg>Fixed width adjustments<commit_after>//Handles monitoring changes from the input text fields and applying them to the appropriate controller
//Also handles import and export events when the buttons are pressed

var EntityController=require('./EntityController');
var Grid=require('./Grid');
var Optimizer=require('./Optimizer');
var Calculate=require('./Calculate');

var InputController=function(){

	$('#optimizer_var_input').change(function() {
	    var variance = parseInt($(this).val());
	    if (!isNaN(variance) && variance!==0) { //to make sure the input is valid (is an integer and non-zero)
	      	Optimizer.variation=variance;
	    }
	});

	$('#desired_ratio_input').change(function() {
	    var ratio = parseInt($(this).val());
	    if (!isNaN(ratio) && ratio >1) { //to make sure the input is valid (is an integer and greater than 1)
	       EntityController.desired_ratio=ratio;
	       Calculate();
	    }
	});

	$('#member_width').change(function() {
	    var width = parseInt($(this).val());
	    if (!isNaN(width)) { //to make sure the input is valid (is an integer and greater than 1)
	       EntityController.member_width=width;
	       Calculate();
	    }
	});

	//Monitors for changes in the grid spacing input field and re-creates the grid if a change is detected
	$('#grid-size-input').change(function() {
	    var new_grid_size = parseInt($('#grid-size-input').val());
	    if (!isNaN(new_grid_size) && new_grid_size > Grid.min_grid_size) { //makes sure the new grid size is an integer and greater than the minimum grid size
	        Grid.grid_size = new_grid_size;
	        Grid.createGrid(); //recreates the grid with the new specified grid size
	    }
	});

	$('#exportBtn').click(function() {
		jsonStr = JSON.stringify(EntityController.export()); //export the entity controller as a string
		$('#export-cont').val(jsonStr); //paste the string in the export field
		$('#uniqueHash').val(EntityController.exportHash(jsonStr)); //hash the output and paste it in the hash input field
		return false;
	});

	$('#importBtn').click(function() {
		jsonStr = $('#export-cont').val(); //stores the value of the import text field
		if (jsonStr.length > 0) { //makes sure its not empty
			if (jsonStr.charAt(1) == 'A') { //if the input is a hash
				EntityController.importHash(jsonStr);
			} else { //if the input is not hashed
				jsonObj = JSON.parse(jsonStr);
				EntityController.import(jsonObj);
			}
		}
		return false;
	});

	//selects all of the text on click of the export and hash input fields
	$('#export-cont').click(function () {
		this.select();
	});
	$('#uniqueHash').click(function() {
		this.select();
	});
};

module.exports=InputController;<|endoftext|>


<commit_before>const fs = require('fs');
const R = require('ramda');
const assert = require('assert');
const reporter = require('../lib/reporter');

const defaultMsg = fs.readFileSync('./lib/templates/noItems.md');
const testReporter = R.pipe(R.flip, R.curry)(reporter.reporter)(true);

describe('jshint-md-reporter', function () {

  describe('No Errors', function () {

    it('returns default message on undefined', function () {
      var result = testReporter(undefined);
      assert.equal(result, defaultMsg);
    });

    it('returns default message on null', function () {
      var result = testReporter(null);
      assert.equal(result, defaultMsg);
    });

    it('returns default message on empty string', function () {
      var result = testReporter('');
      assert.equal(result, defaultMsg);
    });

    it('returns default message on empty array', function () {
      var result = testReporter([]);
      assert.equal(result, defaultMsg);
    });

    it('returns default message on empty object', function () {
      var result = testReporter({});
      assert.equal(result, defaultMsg);
    });

  });

});
<commit_msg>Fix unit tests<commit_after>const fs = require('fs');
const R = require('ramda');
const assert = require('assert');
const reporter = require('../lib/reporter');

const removeNewLines = R.replace(/^\s+|\s+$/g, '');
const defaultMsg = removeNewLines(fs.readFileSync('./lib/templates/noItems.md').toString());
const testReporter = R.pipe(R.flip, R.curry)(reporter.reporter)(true);

describe('jshint-md-reporter', function () {

  describe('No Errors', function () {

    it('returns default message on undefined', function () {
      const result = testReporter(undefined);
      assert.equal(result, defaultMsg);
    });

    it('returns default message on null', function () {
      const result = testReporter(null);
      assert.equal(result, defaultMsg);
    });

    it('returns default message on empty string', function () {
      const result = testReporter('');
      assert.equal(result, defaultMsg);
    });

    it('returns default message on empty array', function () {
      const result = testReporter([]);
      assert.equal(result, defaultMsg);
    });

    it('returns default message on empty object', function () {
      const result = testReporter({});
      assert.equal(result, defaultMsg);
    });

  });

});
<|endoftext|>


<commit_before>var test = require('tape');
var sync = require('../ampersand-sync');
var Model = require('ampersand-model');

function getStub(data) {
    return {
        url: '/library',
        trigger: function () {
            // capture args for comparison
            this.args = arguments;
        },
        toJSON: function () {
            return data || {};
        }
    };
}

test('should allow models to overwrite ajax configs at the model level', function (t) {
    t.plan(3);
    var Me = Model.extend({
        url: '/hi',
        ajaxConfig: {
            useXDR: true,
            xhrFields: {
                withCredentials: true
            }
        }
    });
    var m = new Me();
    m.on('request', function (model, xhr, options, ajaxSettings) {
        t.equal(ajaxSettings.type, 'GET');
        t.equal(ajaxSettings.xhrFields.withCredentials, true);
        t.equal(ajaxSettings.useXDR, true);
        t.end();
    });
    var xhr = sync('read', m);
});

test('read', function (t) {
    var xhr = sync('read', getStub());
    t.equal(xhr.ajaxSettings.url, '/library');
    t.equal(xhr.ajaxSettings.type, 'GET');
    t.ok(!xhr.ajaxSettings.json);
    t.ok(!xhr.ajaxSettings.data);
    var xhr2 = sync('read', getStub(), {url: '/library/books'});
    t.equal(xhr2.ajaxSettings.url, '/library/books', 'passed url should overwrite model url');
    t.end();
});

test('passing data', function (t) {
    // on reads it should be part of the URL
    var xhr = sync('read', getStub(), {data: {a: 'a', one: 1}});
    t.equal(xhr.ajaxSettings.url, '/library?a=a&one=1', 'data passed to reads should be made into a query string');
    var otherStub = getStub();
    otherStub.url = '/library?something=hi';
    var xhr2 = sync('read', otherStub, {data: {a: 'a', one: 1}});
    t.equal(xhr2.ajaxSettings.url, '/library?something=hi&a=a&one=1', 'data passed to reads should be made into a query string');
    var xhr3 = sync('read', getStub(), {url: '/library/books', data: {a: 'a', one: 1}});
    t.equal(xhr3.ajaxSettings.url, '/library/books?a=a&one=1', 'data passed to reads should added to query string for passed url');
    t.end();
});

test('create', function (t) {
    var xhr = sync('create', getStub({
        title: 'The Tempest',
        author: 'Bill Shakespeare',
        length: 123
    }));
    t.equal(xhr.ajaxSettings.url, '/library');
    t.equal(xhr.ajaxSettings.type, 'POST');
    t.equal(xhr.ajaxSettings.headers['Content-Type'], 'application/json');
    var data = xhr.ajaxSettings.json;
    t.equal(data.title, 'The Tempest');
    t.equal(data.author, 'Bill Shakespeare');
    t.equal(data.length, 123);
    t.end();
});

test('update', function (t) {
    var xhr = sync('update', getStub({
        id: '1-the-tempest',
        author: 'William Shakespeare'
    }));
    t.equal(xhr.ajaxSettings.url, '/library');
    t.equal(xhr.ajaxSettings.type, 'PUT');
    t.equal(xhr.ajaxSettings.headers['Content-Type'], 'application/json');
    var data = xhr.ajaxSettings.json;
    t.equal(data.id, '1-the-tempest');
    t.equal(data.author, 'William Shakespeare');
    t.end();
});

test('update with emulateHTTP and emulateJSON', function (t) {
    var xhr = sync('update', getStub({
            id: '2-the-tempest',
            author: 'Tim Shakespeare',
            length: 123
        }),
        {
            emulateHTTP: true,
            emulateJSON: true
        }
    );
    t.equal(xhr.ajaxSettings.url, '/library');
    t.equal(xhr.ajaxSettings.type, 'POST');
    t.equal(xhr.ajaxSettings.body, 'model%5Bid%5D=2-the-tempest&model%5Bauthor%5D=Tim%20Shakespeare&model%5Blength%5D=123&_method=PUT');
    t.equal(xhr.ajaxSettings.headers['Content-Type'], 'application/x-www-form-urlencoded');
    t.end();
});

test('update with just emulateHTTP', function (t) {
    var xhr = sync('update', getStub({
            id: '2-the-tempest',
            author: 'Tim Shakespeare',
            length: 123
        }),
        {
            emulateHTTP: true
        }
    );
    t.equal(xhr.ajaxSettings.url, '/library');
    t.equal(xhr.ajaxSettings.type, 'POST');
    t.equal(xhr.ajaxSettings.headers['Content-Type'], 'application/json');
    var data = xhr.ajaxSettings.json;
    t.equal(data.id, '2-the-tempest');
    t.equal(data.author, 'Tim Shakespeare');
    t.equal(data.length, 123);
    t.end();
});

test('update with just emulateJSON', function (t) {
    var xhr = sync('update', getStub({
            id: '2-the-tempest',
            author: 'Tim Shakespeare',
            length: 123
        }),
        {
            emulateJSON: true
        }
    );
    t.equal(xhr.ajaxSettings.url, '/library');
    t.equal(xhr.ajaxSettings.type, 'PUT');
    t.equal(xhr.ajaxSettings.headers['Content-Type'], 'application/x-www-form-urlencoded');
    t.equal(xhr.ajaxSettings.body, 'model%5Bid%5D=2-the-tempest&model%5Bauthor%5D=Tim%20Shakespeare&model%5Blength%5D=123');
    t.end();
});

test('delete', function (t) {
    var xhr = sync('delete', getStub({
        author: 'Tim Shakespeare',
        length: 123
    }));
    t.equal(xhr.ajaxSettings.url, '/library');
    t.equal(xhr.ajaxSettings.type, 'DELETE');
    t.notOk(xhr.ajaxSettings.data);
    t.end();
});

test('destroy with emulateHTTP', function (t) {
    var xhr = sync('delete', getStub({
            author: 'Tim Shakespeare',
            length: 123
        }),
        {
            emulateHTTP: true,
            emulateJSON: true
        }
    );
    t.equal(xhr.ajaxSettings.url, '/library');
    t.equal(xhr.ajaxSettings.type, 'POST');
    t.equal(xhr.ajaxSettings.body, '_method=DELETE');
    t.end();
});

test('urlError', function (t) {
    t.throws(function () {
        var xhr = sync('read', {});
    }, Error);
    t.end();
});

test('Call provided error callback on error.', function (t) {
    t.plan(1);
    var xhr = sync('read', getStub(), {
        error: function () {
            t.pass();
            t.end();
        }
    });
    xhr.ajaxSettings.error();
});

test('Call provided error callback is bad JSON error.', function (t) {
    t.plan(3);

    var xhr = sync('read', getStub(), {
        error: function (resp, type, error) {
            t.deepEqual(resp, {}, 'should be passed through response');
            t.equal(type, 'error', 'is string \'error\' as per jquery');
            t.equal(error, 'Unable to parse JSON string', 'should be json parse message');
            t.end();
        },
        xhrImplementation: function (ajaxSettings, callback) {
            callback(null, {}, '{"bad": "json');
            return {};
        }
    });
});

test('Call user provided beforeSend function.', function (t) {
    t.plan(1);
    var xhr = sync('delete', getStub(), {
        beforeSend: function (_xhr) {
            t.pass();
        },
        emulateHTTP: true
    });
    t.end();
});

test('Call user provided beforeSend function from model\'s ajaxConfig when no custom xhrFields are passed', function (t) {
    t.plan(1);

    var Me = Model.extend({
        url: '/hi',
        ajaxConfig: {
            beforeSend: function (xhr) {
                t.pass();
            }
        }
    });

    var m = new Me();
    var xhr = sync('create', m);

    t.end();
});
<commit_msg>Tidy up “read with data” tests to make it a bit more readable.<commit_after>var test = require('tape');
var sync = require('../ampersand-sync');
var Model = require('ampersand-model');

function getStub(data) {
    return {
        url: '/library',
        trigger: function () {
            // capture args for comparison
            this.args = arguments;
        },
        toJSON: function () {
            return data || {};
        }
    };
}

test('should allow models to overwrite ajax configs at the model level', function (t) {
    t.plan(3);
    var Me = Model.extend({
        url: '/hi',
        ajaxConfig: {
            useXDR: true,
            xhrFields: {
                withCredentials: true
            }
        }
    });
    var m = new Me();
    m.on('request', function (model, xhr, options, ajaxSettings) {
        t.equal(ajaxSettings.type, 'GET');
        t.equal(ajaxSettings.xhrFields.withCredentials, true);
        t.equal(ajaxSettings.useXDR, true);
        t.end();
    });
    var xhr = sync('read', m);
});

test('read', function (t) {
    var xhr = sync('read', getStub());
    t.equal(xhr.ajaxSettings.url, '/library');
    t.equal(xhr.ajaxSettings.type, 'GET');
    t.ok(!xhr.ajaxSettings.json);
    t.ok(!xhr.ajaxSettings.data);
    var xhr2 = sync('read', getStub(), {url: '/library/books'});
    t.equal(xhr2.ajaxSettings.url, '/library/books', 'passed url should overwrite model url');
    t.end();
});

test('passing data', function (t) {
    // on reads it should be part of the URL
    var xhr = sync('read', getStub(), {data: {a: 'a', one: 1}});
    t.equal(xhr.ajaxSettings.url, '/library?a=a&one=1', 'data passed to reads should be made into a query string');

    var modelStub = getStub();
    modelStub.url = '/library?something=hi';
    var xhr2 = sync('read', modelStub, {data: {a: 'a', one: 1}});
    t.equal(xhr2.ajaxSettings.url, '/library?something=hi&a=a&one=1', 'data passed to reads should be appended to an existing query string in the url');

    var xhr3 = sync('read', getStub(), {url: '/library/books', data: {a: 'a', one: 1}});
    t.equal(xhr3.ajaxSettings.url, '/library/books?a=a&one=1', 'data passed to reads should be added as a query string to overwritten url');
    t.end();
});

test('create', function (t) {
    var xhr = sync('create', getStub({
        title: 'The Tempest',
        author: 'Bill Shakespeare',
        length: 123
    }));
    t.equal(xhr.ajaxSettings.url, '/library');
    t.equal(xhr.ajaxSettings.type, 'POST');
    t.equal(xhr.ajaxSettings.headers['Content-Type'], 'application/json');
    var data = xhr.ajaxSettings.json;
    t.equal(data.title, 'The Tempest');
    t.equal(data.author, 'Bill Shakespeare');
    t.equal(data.length, 123);
    t.end();
});

test('update', function (t) {
    var xhr = sync('update', getStub({
        id: '1-the-tempest',
        author: 'William Shakespeare'
    }));
    t.equal(xhr.ajaxSettings.url, '/library');
    t.equal(xhr.ajaxSettings.type, 'PUT');
    t.equal(xhr.ajaxSettings.headers['Content-Type'], 'application/json');
    var data = xhr.ajaxSettings.json;
    t.equal(data.id, '1-the-tempest');
    t.equal(data.author, 'William Shakespeare');
    t.end();
});

test('update with emulateHTTP and emulateJSON', function (t) {
    var xhr = sync('update', getStub({
            id: '2-the-tempest',
            author: 'Tim Shakespeare',
            length: 123
        }),
        {
            emulateHTTP: true,
            emulateJSON: true
        }
    );
    t.equal(xhr.ajaxSettings.url, '/library');
    t.equal(xhr.ajaxSettings.type, 'POST');
    t.equal(xhr.ajaxSettings.body, 'model%5Bid%5D=2-the-tempest&model%5Bauthor%5D=Tim%20Shakespeare&model%5Blength%5D=123&_method=PUT');
    t.equal(xhr.ajaxSettings.headers['Content-Type'], 'application/x-www-form-urlencoded');
    t.end();
});

test('update with just emulateHTTP', function (t) {
    var xhr = sync('update', getStub({
            id: '2-the-tempest',
            author: 'Tim Shakespeare',
            length: 123
        }),
        {
            emulateHTTP: true
        }
    );
    t.equal(xhr.ajaxSettings.url, '/library');
    t.equal(xhr.ajaxSettings.type, 'POST');
    t.equal(xhr.ajaxSettings.headers['Content-Type'], 'application/json');
    var data = xhr.ajaxSettings.json;
    t.equal(data.id, '2-the-tempest');
    t.equal(data.author, 'Tim Shakespeare');
    t.equal(data.length, 123);
    t.end();
});

test('update with just emulateJSON', function (t) {
    var xhr = sync('update', getStub({
            id: '2-the-tempest',
            author: 'Tim Shakespeare',
            length: 123
        }),
        {
            emulateJSON: true
        }
    );
    t.equal(xhr.ajaxSettings.url, '/library');
    t.equal(xhr.ajaxSettings.type, 'PUT');
    t.equal(xhr.ajaxSettings.headers['Content-Type'], 'application/x-www-form-urlencoded');
    t.equal(xhr.ajaxSettings.body, 'model%5Bid%5D=2-the-tempest&model%5Bauthor%5D=Tim%20Shakespeare&model%5Blength%5D=123');
    t.end();
});

test('delete', function (t) {
    var xhr = sync('delete', getStub({
        author: 'Tim Shakespeare',
        length: 123
    }));
    t.equal(xhr.ajaxSettings.url, '/library');
    t.equal(xhr.ajaxSettings.type, 'DELETE');
    t.notOk(xhr.ajaxSettings.data);
    t.end();
});

test('destroy with emulateHTTP', function (t) {
    var xhr = sync('delete', getStub({
            author: 'Tim Shakespeare',
            length: 123
        }),
        {
            emulateHTTP: true,
            emulateJSON: true
        }
    );
    t.equal(xhr.ajaxSettings.url, '/library');
    t.equal(xhr.ajaxSettings.type, 'POST');
    t.equal(xhr.ajaxSettings.body, '_method=DELETE');
    t.end();
});

test('urlError', function (t) {
    t.throws(function () {
        var xhr = sync('read', {});
    }, Error);
    t.end();
});

test('Call provided error callback on error.', function (t) {
    t.plan(1);
    var xhr = sync('read', getStub(), {
        error: function () {
            t.pass();
            t.end();
        }
    });
    xhr.ajaxSettings.error();
});

test('Call provided error callback is bad JSON error.', function (t) {
    t.plan(3);

    var xhr = sync('read', getStub(), {
        error: function (resp, type, error) {
            t.deepEqual(resp, {}, 'should be passed through response');
            t.equal(type, 'error', 'is string \'error\' as per jquery');
            t.equal(error, 'Unable to parse JSON string', 'should be json parse message');
            t.end();
        },
        xhrImplementation: function (ajaxSettings, callback) {
            callback(null, {}, '{"bad": "json');
            return {};
        }
    });
});

test('Call user provided beforeSend function.', function (t) {
    t.plan(1);
    var xhr = sync('delete', getStub(), {
        beforeSend: function (_xhr) {
            t.pass();
        },
        emulateHTTP: true
    });
    t.end();
});

test('Call user provided beforeSend function from model\'s ajaxConfig when no custom xhrFields are passed', function (t) {
    t.plan(1);

    var Me = Model.extend({
        url: '/hi',
        ajaxConfig: {
            beforeSend: function (xhr) {
                t.pass();
            }
        }
    });

    var m = new Me();
    var xhr = sync('create', m);

    t.end();
});
<|endoftext|>


<commit_before>'use strict';

/* global Connector */

Connector.playerSelector = 'body';

Connector.artistSelector = '.now_playing .artist';

Connector.trackSelector = '.now_playing .title';

Connector.albumSelector = '.now_playing .album';

Connector.trackArtSelector = '.now_playing .art_container';

Connector.isPlaying = () => $('#r4_audio_player').hasClass('playing');
<commit_msg>Rainwave: get artists correctly<commit_after>'use strict';

/* global Connector, Util */

Connector.playerSelector = 'body';

Connector.getArtist = () => {
	let artists = $('.now_playing .artist a').toArray();
	return Util.joinArtists(artists);
};

Connector.trackSelector = '.now_playing .title';

Connector.albumSelector = '.now_playing .album';

Connector.trackArtSelector = '.now_playing .art_container';

Connector.isPlaying = () => $('#r4_audio_player').hasClass('playing');
<|endoftext|>


<commit_before>/* global suite: false, test: false */
var assert = require('assert');
var request = require('supertest');

var app = require('../');
var appConfig = app.get('config');

suite('OPTIONS /', function () {
  test('return CORS headers', function (done) {
    request(app)
      .options('/')
      .expect('Access-Control-Allow-Origin', '*')
      .expect('Access-Control-Allow-Headers', 'X-Requested-With')
      .expect('Access-Control-Allow-Methods', 'GET')
      .expect('Access-Control-Max-Age', '86400')
      .expect(200, done);
  });
});

suite('GET /shorten', function () {
  test('checks for valid URL format', function (done) {
    request(app)
      .get('/shorten/http%3A%2F%2F')
      .expect(400, done);
  });

  test('checks for valid protocol', function (done) {
    request(app)
      .get('/shorten/ftp%3A%2F%2Fwww.test.de%2Ffoo%2Fbar%2Fbaz')
      .expect(403, done);
  });

  test('refuses to shorten too short URLs', function (done) {
    request(app)
      .get('/shorten/http%3A%2F%2Ffoo.bar')
      .expect(403, done);
  });

  test('refuses request hashes when forbidden', function (done) {
    var requestHash = 'test';
    appConfig.hash.allowRequest = false;
    request(app)
      .get('/shorten/http%3A%2F%2Fa-very-long-domain.name%2Fwith%2Fan%2Feven' +
        '%2Flonger%2Fpath%2Fand%2Fa%2Frequest%2Fhash?hash=' + requestHash)
      .expect(403)
      .end(function (err, res) {
        appConfig.hash.allowRequest = true;
        if (err) {
          return done(err);
        } else {
          return done();
        }
      });
  });

  test('refuses bad request hashes', function (done) {
    var requestHash = 'this%20is%20a%20malformed%20hash';
    request(app)
      .get('/shorten/http%3A%2F%2Fa-very-long-domain.name%2Fwith%2Fan%2Feven' +
        '%2Flonger%2Fpath%2Fand%2Fa%2Frequest%2Fhash?hash=' + requestHash)
      .expect(400, done);
  });

  test('refuses forbidden request hashes', function (done) {
    var requestHash = 'shorten';
    request(app)
      .get('/shorten/http%3A%2F%2Fa-very-long-domain.name%2Fwith%2Fan%2Feven' +
        '%2Flonger%2Fpath%2Fand%2Fa%2Frequest%2Fhash?hash=' + requestHash)
      .expect(400, done);
  });

  test('refuses URL with hostname on blacklist', function (done) {
    appConfig.urlLimit.hostnameBlacklist = ['a-bad-host.name'];
    request(app)
      .get('/shorten/http%3A%2F%2Fa-bad-host.name%2Fwith%2Fan%2Feven' +
        '%2Flonger%2Fpath')
      .expect(403)
      .end(function (err, res) {
        appConfig.urlLimit.hostnameBlacklist = [];
        if (err) {
          return done(err);
        } else {
          return done();
        }
      });
  });

  test('refuses URL with hostname not on whitelist', function (done) {
    appConfig.urlLimit.hostnameWhitelist = ['a-known-good-host.name'];
    request(app)
      .get('/shorten/http%3A%2F%2Fanother-bad-host.name%2Fwith%2Fan%2Feven' +
        '%2Flonger%2Fpath')
      .expect(403)
      .end(function (err, res) {
        appConfig.urlLimit.hostnameWhitelist = [];
        if (err) {
          return done(err);
        } else {
          return done();
        }
      });
  });

  test('performs shortening', function (done) {
    request(app)
      .get('/shorten/http%3A%2F%2Fa-very-long-domain.name%2Fwith%2Fan%2Feven' +
        '%2Flonger%2Fpath')
      .expect(200)
      .expect('Content-Type', /json/)
      .end(function (err, res) {
        if (err) {
          return done(err);
        } else {
          assert(appConfig.hash._regex.test(res.body.hash));
          assert.strictEqual(res.body.longUrl,
            'http://a-very-long-domain.name/with/an/even/longer/path');
          assert.strictEqual(res.body.url, appConfig.hash.urlPrefix +
            res.body.hash);
          return done();
        }
      });
  });

  test('performs normalization during shortening', function (done) {
    request(app)
      .get('/shorten/http%3A%2F%2Fa-very-long-domain.name%2Fwith%2Fan%2Feven' +
        '%2Flonger%2Fpath')
      .expect(200)
      .expect('Content-Type', /json/)
      .end(function (err, res) {
        if (err) {
          return done(err);
        } else {
          var hashCanonicalUrl = res.body.hash;
          request(app)
            .get('/shorten/http%3A%2F%2Fa-very-long-domain.name%3A80' +
                '%2Fwith%2Fan%2Feven%2Flonger%2Fpath%23')
            .expect(200)
            .expect('Content-Type', /json/)
            .end(function (err, res) {
              if (err) {
                return done(err);
              } else {
                assert.strictEqual(hashCanonicalUrl, res.body.hash);
                request(app)
                  .get('/shorten/http%3A%2F%2Fa-very-long-domain.name' +
                      '%2Fwith%2Fan%2Feven%2Flonger%2Fpath%3F')
                  .expect(200)
                  .expect('Content-Type', /json/)
                  .end(function (err, res) {
                    if (err) {
                      return done(err);
                    } else {
                      assert.strictEqual(hashCanonicalUrl, res.body.hash);
                      return done();
                    }
                  });
              }
            });
        }
      });
  });

  test('accepts request hashes when allowed', function (done) {
    var requestHash = 'test';
    request(app)
      .get('/shorten/http%3A%2F%2Fa-very-long-domain.name%2Fwith%2Fan%2Feven' +
        '%2Flonger%2Fpath%2Fand%2Fa%2Frequest%2Fhash?hash=' + requestHash)
      .expect('Content-Type', /json/)
      .end(function (err, res) {
        if (err) {
          return done(err);
        } else {
          assert.strictEqual(requestHash, res.body.hash);
          return done();
        }
      });
  });

  test('returns text/plain (on demand)', function (done) {
    request(app)
      .get('/shorten/http%3A%2F%2Fa-very-long-domain.name%2Fwith%2Fan%2Feven' +
        '%2Flonger%2Fpath?format=txt')
      .expect('Content-Type', /text\/plain/)
      .expect(new RegExp('^' + appConfig.hash.urlPrefix))
      .expect(200, done);
  });

  test('returns qrcode (on demand)', function (done) {
    request(app)
      .get('/shorten/http%3A%2F%2Fa-very-long-domain.name%2Fwith%2Fan%2Feven' +
        '%2Flonger%2Fpath?format=qrcode')
      .expect('Content-Type', /image\/png/)
      .expect('Content-Length', /[0-9]{3,4}/)
      .expect(200, done);
  });
});

suite('GET|HEAD /[hash]', function () {
  var hash;

  test('GET returns 404 for unknown hash', function (done) {
    request(app)
      .get('/unkno')
      .expect(404, done);
  });

  test('GET returns permanent redirect for known hash', function (done) {
    request(app)
      .get('/shorten/http%3A%2F%2Fa-very-long-domain.name%2Fwith%2Fan%2Feven' +
        '%2Flonger%2Fpath%3F')
      .expect(200)
      .expect('Content-Type', /json/)
      .end(function (err, res) {
        if (err) {
          return done(err);
        } else {
          hash = res.body.hash;
          request(app)
            .get('/' + hash)
            .expect('Location', 'http://a-very-long-domain.name/with/an/even' +
                '/longer/path')
            .expect(301, done);
        }
      });
  });

  test('HEAD returns 404 for unknown hash', function (done) {
    request(app)
      .head('/unkno')
      .expect(404, done);
  });

  test('HEAD returns permanent redirect for known hash', function (done) {
    request(app)
      .head('/' + hash)
      .expect('Location', 'http://a-very-long-domain.name/with/an/even' +
          '/longer/path')
      .expect(301, done);
  });
});

suite('GET /stats', function () {
  var hash;

  test('returns 404 for unknown hash', function (done) {
    request(app)
      .get('/stats/unkno')
      .expect(404, done);
  });

  test('returns stats for known hash', function (done) {
    request(app)
      .get('/shorten/http%3A%2F%2Fa-very-long-domain.name%2Fwith%2Fan%2Feven' +
        '%2Flonger%2Fpath%3F')
      .expect(200)
      .expect('Content-Type', /json/)
      .end(function (err, res) {
        if (err) {
          return done(err);
        } else {
          hash = res.body.hash;
          request(app)
            .get('/stats/' + hash)
            .expect('Content-Type', /json/)
            .expect(200, done);
        }
      });
  });

  test('returns clicks in text/plain (on demand)', function (done) {
    request(app)
      .get('/stats/' + hash + '?format=txt')
      .expect('Content-Type', /text\/plain/)
      .expect(/\d+/)
      .expect(200, done);
  });

  test('returns actually incremented clicks', function (done) {
    this.slow(4075);
    this.timeout(5000);
    request(app)
      .get('/stats/' + hash + '?format=txt')
      .expect('Content-Type', /text\/plain/)
      .expect(200)
      .end(function (err, res) {
        if (err) {
          return done(err);
        } else {
          var clicks = parseInt(res.text, 10);
          setTimeout(function () {
            request(app)
              .get('/' + hash)
              .expect(301)
              .end(function (err, res) {
                request(app)
                  .get('/stats/' + hash + '?format=txt')
                  .expect(200)
                  .expect('' + (clicks + 1), done);
              });
          }, 4000);
        }
      });
  });
});
<commit_msg>Skip click counter incrementation test<commit_after>/* global suite: false, test: false */
var assert = require('assert');
var request = require('supertest');

var app = require('../');
var appConfig = app.get('config');

suite('OPTIONS /', function () {
  test('return CORS headers', function (done) {
    request(app)
      .options('/')
      .expect('Access-Control-Allow-Origin', '*')
      .expect('Access-Control-Allow-Headers', 'X-Requested-With')
      .expect('Access-Control-Allow-Methods', 'GET')
      .expect('Access-Control-Max-Age', '86400')
      .expect(200, done);
  });
});

suite('GET /shorten', function () {
  test('checks for valid URL format', function (done) {
    request(app)
      .get('/shorten/http%3A%2F%2F')
      .expect(400, done);
  });

  test('checks for valid protocol', function (done) {
    request(app)
      .get('/shorten/ftp%3A%2F%2Fwww.test.de%2Ffoo%2Fbar%2Fbaz')
      .expect(403, done);
  });

  test('refuses to shorten too short URLs', function (done) {
    request(app)
      .get('/shorten/http%3A%2F%2Ffoo.bar')
      .expect(403, done);
  });

  test('refuses request hashes when forbidden', function (done) {
    var requestHash = 'test';
    appConfig.hash.allowRequest = false;
    request(app)
      .get('/shorten/http%3A%2F%2Fa-very-long-domain.name%2Fwith%2Fan%2Feven' +
        '%2Flonger%2Fpath%2Fand%2Fa%2Frequest%2Fhash?hash=' + requestHash)
      .expect(403)
      .end(function (err, res) {
        appConfig.hash.allowRequest = true;
        if (err) {
          return done(err);
        } else {
          return done();
        }
      });
  });

  test('refuses bad request hashes', function (done) {
    var requestHash = 'this%20is%20a%20malformed%20hash';
    request(app)
      .get('/shorten/http%3A%2F%2Fa-very-long-domain.name%2Fwith%2Fan%2Feven' +
        '%2Flonger%2Fpath%2Fand%2Fa%2Frequest%2Fhash?hash=' + requestHash)
      .expect(400, done);
  });

  test('refuses forbidden request hashes', function (done) {
    var requestHash = 'shorten';
    request(app)
      .get('/shorten/http%3A%2F%2Fa-very-long-domain.name%2Fwith%2Fan%2Feven' +
        '%2Flonger%2Fpath%2Fand%2Fa%2Frequest%2Fhash?hash=' + requestHash)
      .expect(400, done);
  });

  test('refuses URL with hostname on blacklist', function (done) {
    appConfig.urlLimit.hostnameBlacklist = ['a-bad-host.name'];
    request(app)
      .get('/shorten/http%3A%2F%2Fa-bad-host.name%2Fwith%2Fan%2Feven' +
        '%2Flonger%2Fpath')
      .expect(403)
      .end(function (err, res) {
        appConfig.urlLimit.hostnameBlacklist = [];
        if (err) {
          return done(err);
        } else {
          return done();
        }
      });
  });

  test('refuses URL with hostname not on whitelist', function (done) {
    appConfig.urlLimit.hostnameWhitelist = ['a-known-good-host.name'];
    request(app)
      .get('/shorten/http%3A%2F%2Fanother-bad-host.name%2Fwith%2Fan%2Feven' +
        '%2Flonger%2Fpath')
      .expect(403)
      .end(function (err, res) {
        appConfig.urlLimit.hostnameWhitelist = [];
        if (err) {
          return done(err);
        } else {
          return done();
        }
      });
  });

  test('performs shortening', function (done) {
    request(app)
      .get('/shorten/http%3A%2F%2Fa-very-long-domain.name%2Fwith%2Fan%2Feven' +
        '%2Flonger%2Fpath')
      .expect(200)
      .expect('Content-Type', /json/)
      .end(function (err, res) {
        if (err) {
          return done(err);
        } else {
          assert(appConfig.hash._regex.test(res.body.hash));
          assert.strictEqual(res.body.longUrl,
            'http://a-very-long-domain.name/with/an/even/longer/path');
          assert.strictEqual(res.body.url, appConfig.hash.urlPrefix +
            res.body.hash);
          return done();
        }
      });
  });

  test('performs normalization during shortening', function (done) {
    request(app)
      .get('/shorten/http%3A%2F%2Fa-very-long-domain.name%2Fwith%2Fan%2Feven' +
        '%2Flonger%2Fpath')
      .expect(200)
      .expect('Content-Type', /json/)
      .end(function (err, res) {
        if (err) {
          return done(err);
        } else {
          var hashCanonicalUrl = res.body.hash;
          request(app)
            .get('/shorten/http%3A%2F%2Fa-very-long-domain.name%3A80' +
                '%2Fwith%2Fan%2Feven%2Flonger%2Fpath%23')
            .expect(200)
            .expect('Content-Type', /json/)
            .end(function (err, res) {
              if (err) {
                return done(err);
              } else {
                assert.strictEqual(hashCanonicalUrl, res.body.hash);
                request(app)
                  .get('/shorten/http%3A%2F%2Fa-very-long-domain.name' +
                      '%2Fwith%2Fan%2Feven%2Flonger%2Fpath%3F')
                  .expect(200)
                  .expect('Content-Type', /json/)
                  .end(function (err, res) {
                    if (err) {
                      return done(err);
                    } else {
                      assert.strictEqual(hashCanonicalUrl, res.body.hash);
                      return done();
                    }
                  });
              }
            });
        }
      });
  });

  test('accepts request hashes when allowed', function (done) {
    var requestHash = 'test';
    request(app)
      .get('/shorten/http%3A%2F%2Fa-very-long-domain.name%2Fwith%2Fan%2Feven' +
        '%2Flonger%2Fpath%2Fand%2Fa%2Frequest%2Fhash?hash=' + requestHash)
      .expect('Content-Type', /json/)
      .end(function (err, res) {
        if (err) {
          return done(err);
        } else {
          assert.strictEqual(requestHash, res.body.hash);
          return done();
        }
      });
  });

  test('returns text/plain (on demand)', function (done) {
    request(app)
      .get('/shorten/http%3A%2F%2Fa-very-long-domain.name%2Fwith%2Fan%2Feven' +
        '%2Flonger%2Fpath?format=txt')
      .expect('Content-Type', /text\/plain/)
      .expect(new RegExp('^' + appConfig.hash.urlPrefix))
      .expect(200, done);
  });

  test('returns qrcode (on demand)', function (done) {
    request(app)
      .get('/shorten/http%3A%2F%2Fa-very-long-domain.name%2Fwith%2Fan%2Feven' +
        '%2Flonger%2Fpath?format=qrcode')
      .expect('Content-Type', /image\/png/)
      .expect('Content-Length', /[0-9]{3,4}/)
      .expect(200, done);
  });
});

suite('GET|HEAD /[hash]', function () {
  var hash;

  test('GET returns 404 for unknown hash', function (done) {
    request(app)
      .get('/unkno')
      .expect(404, done);
  });

  test('GET returns permanent redirect for known hash', function (done) {
    request(app)
      .get('/shorten/http%3A%2F%2Fa-very-long-domain.name%2Fwith%2Fan%2Feven' +
        '%2Flonger%2Fpath%3F')
      .expect(200)
      .expect('Content-Type', /json/)
      .end(function (err, res) {
        if (err) {
          return done(err);
        } else {
          hash = res.body.hash;
          request(app)
            .get('/' + hash)
            .expect('Location', 'http://a-very-long-domain.name/with/an/even' +
                '/longer/path')
            .expect(301, done);
        }
      });
  });

  test('HEAD returns 404 for unknown hash', function (done) {
    request(app)
      .head('/unkno')
      .expect(404, done);
  });

  test('HEAD returns permanent redirect for known hash', function (done) {
    request(app)
      .head('/' + hash)
      .expect('Location', 'http://a-very-long-domain.name/with/an/even' +
          '/longer/path')
      .expect(301, done);
  });
});

suite('GET /stats', function () {
  var hash;

  test('returns 404 for unknown hash', function (done) {
    request(app)
      .get('/stats/unkno')
      .expect(404, done);
  });

  test('returns stats for known hash', function (done) {
    request(app)
      .get('/shorten/http%3A%2F%2Fa-very-long-domain.name%2Fwith%2Fan%2Feven' +
        '%2Flonger%2Fpath%3F')
      .expect(200)
      .expect('Content-Type', /json/)
      .end(function (err, res) {
        if (err) {
          return done(err);
        } else {
          hash = res.body.hash;
          request(app)
            .get('/stats/' + hash)
            .expect('Content-Type', /json/)
            .expect(200, done);
        }
      });
  });

  test('returns clicks in text/plain (on demand)', function (done) {
    request(app)
      .get('/stats/' + hash + '?format=txt')
      .expect('Content-Type', /text\/plain/)
      .expect(/\d+/)
      .expect(200, done);
  });

  test.skip('returns actually incremented clicks', function (done) {
    this.slow(4075);
    this.timeout(5000);
    request(app)
      .get('/stats/' + hash + '?format=txt')
      .expect('Content-Type', /text\/plain/)
      .expect(200)
      .end(function (err, res) {
        if (err) {
          return done(err);
        } else {
          var clicks = parseInt(res.text, 10);
          setTimeout(function () {
            request(app)
              .get('/' + hash)
              .expect(301)
              .end(function (err, res) {
                request(app)
                  .get('/stats/' + hash + '?format=txt')
                  .expect(200)
                  .expect('' + (clicks + 1), done);
              });
          }, 4000);
        }
      });
  });
});
<|endoftext|>