<commit_before>window.SvJs = function ($, selector) {
    $('

').addClass('svjs').appendTo($(selector));

    function clear() {
        $('table', selector).empty();
    }

    // Displays annotations with sequence. Annotations should be an array of
    // objects, each with base_first, base_last, and display_name attributes.
    //
    function setSequenceWithAnnotations(sequence, annotations, start_bp, rowlen) {
        if (start_bp < 1) { alert('start_bp should be one or greater'); }

        function add_annotations(row, bpi, pre, annotation_list, tr_html, tr_list) {
            if (annotation_list.length > 0) {
                if (annotation_list[bpi]) {
                    _.map(annotation_list[bpi], function(a) {
                        var tr = $(tr_html);
                        // empty td for bp number
                        tr.append('	');
                        if (bpi > 0) { tr.append('	'); }
                        var td = $('	');
                        var c = '>';
                        if (a.strand < 0) { c = '<'; }
                        var a = $('

')
                                  .addClass('sequence-annotation-'+a.__sequence_annotation_id)
                                  .data('sequence-annotation-id', a.__sequence_annotation_id)
                                  .append(pre+c+a.display_name);
                        td.append(a);
                        tr.append(td);
                        if (bpi < row.length-1) {
                            tr.append('	');
                        }
                        // empty td for bp number
                        tr.append('	');
                        tr_list.push(tr);
                    });
                }
            }
        }

        function annotationToggle(ev) {
            var el = $(ev.target);
            if (el.hasClass('sequence-annotation-selected')) {
                $('tr.sequence-annotation td div').show();
                $('tr.sequence-annotation').show();
                $('tr.sequence-annotation td div.sequence-annotation-selected')
                  .removeClass('sequence-annotation-selected');
            }
            else {
                $('tr.sequence-annotation td div').hide();
                $('tr.sequence-annotation').hide();

                var id = el.data('sequence-annotation-id');
                $('tr.sequence-annotation td div.sequence-annotation-'+id)
                  .addClass('sequence-annotation-selected')
                  .show()
                  .parents('tr')
                  .show();
            }
        }

        rowlen = typeof rowlen !== 'undefined' ? rowlen : 80;
        clear();
        var rsplit = new RegExp('(.{1,'+rowlen+'})', 'g');
        var rows = sequence.match(rsplit);

        var ai = 0;
        _.map(annotations, function(a) { a.__sequence_annotation_id = ai; ai++; });

        var row_start = start_bp;
        _.map(rows, function(row) {
            var row_end = row_start+row.length-1;
            var row_annotations = _.select(annotations, function(a) {
                return (row_start <= a.base_first && a.base_first <= row_end) ||
                       (row_start <= a.base_last && a.base_last <= row_end);
            });

            var start_annotations = [];
            var end_annotations = [];

            _.map(row_annotations, function(a) {
                if (row_start <= a.base_first && a.base_first <= row_end) {
                    var i = a.base_first-row_start;
                    if (start_annotations[i] === undefined) { start_annotations[i] = []; }
                    start_annotations[i].push(a);
                }
                if (row_start <= a.base_last && a.base_last <= row_end) {
                    var i = a.base_last-row_start;
                    if (end_annotations[i] === undefined) { end_annotations[i] = []; }
                    end_annotations[i].push(a);
                }
            });

            var tr_mid = $('

');
            var pos = $('	').append(row_start);
            tr_mid.append(pos);
            var tr_top = [];
            var tr_bot = [];

            if (row_annotations.length === 0) {
                var td = $('	').append(row);
                tr_mid.append(td);
            }
            else {
                var tr_top_html = '

';
                var tr_bot_html = '

';

                var i = 0;
                _.map(row.split(''), function(bp) {
                    var td = $('	');
                    tr_mid.append(td);
                    td.append(bp);

                    add_annotations(row, i, '[', start_annotations, tr_top_html, tr_top);
                    add_annotations(row, i, ']', end_annotations, tr_bot_html, tr_bot);
                    i += 1;
                });
            }

            if (row_end < start_bp+sequence.length-1) {
                var pos = $('	').append(row_end);
                tr_mid.append(pos);
            }

            if (tr_top.length > 0) { tr_top[0].addClass('sequence-annotation-start-first'); }
            _.map(tr_top, function(tr) { $('table', selector).append(tr); });
            $('table', selector).append(tr_mid);
            if (tr_bot.length > 0) { tr_bot[tr_bot.length-1].addClass('sequence-annotation-end-last'); }
            _.map(tr_bot, function(tr) { $('table', selector).append(tr); });

            row_start += row.length;
        });

        $('tr.sequence-annotation td div').on('click', annotationToggle);
    }

    return {
        clear: clear,
        setSequenceWithAnnotations: setSequenceWithAnnotations
    }
};
<commit_msg>Add btn to toggle bps<commit_after>window.SvJs = function ($, selector) {
    var container = $('

');
    $(selector).append(container);

    var show_hide_bps = $('Toggle bps').on('click', function() {
        $('table td.sequence-pos', container).toggle();
    });
    container.append($('

').append(show_hide_bps));

    $('

').addClass('svjs').appendTo(container);

    function clear() {
        $('table', selector).empty();
    }

    // Displays annotations with sequence. Annotations should be an array of
    // objects, each with base_first, base_last, and display_name attributes.
    //
    function setSequenceWithAnnotations(sequence, annotations, start_bp, rowlen) {
        if (start_bp < 1) { alert('start_bp should be one or greater'); }

        function add_annotations(row, bpi, pre, annotation_list, tr_html, tr_list) {
            if (annotation_list.length > 0) {
                if (annotation_list[bpi]) {
                    _.map(annotation_list[bpi], function(a) {
                        var tr = $(tr_html);
                        // empty td for bp number
                        tr.append('	');
                        if (bpi > 0) { tr.append('	'); }
                        var td = $('	');
                        var c = '>';
                        if (a.strand < 0) { c = '<'; }
                        var a = $('

')
                                  .addClass('sequence-annotation-'+a.__sequence_annotation_id)
                                  .data('sequence-annotation-id', a.__sequence_annotation_id)
                                  .append(pre+c+a.display_name);
                        td.append(a);
                        tr.append(td);
                        if (bpi < row.length-1) {
                            tr.append('	');
                        }
                        // empty td for bp number
                        tr.append('	');
                        tr_list.push(tr);
                    });
                }
            }
        }

        function annotationToggle(ev) {
            var el = $(ev.target);
            if (el.hasClass('sequence-annotation-selected')) {
                $('tr.sequence-annotation td div').show();
                $('tr.sequence-annotation').show();
                $('tr.sequence-annotation td div.sequence-annotation-selected')
                  .removeClass('sequence-annotation-selected');
            }
            else {
                $('tr.sequence-annotation td div').hide();
                $('tr.sequence-annotation').hide();

                var id = el.data('sequence-annotation-id');
                $('tr.sequence-annotation td div.sequence-annotation-'+id)
                  .addClass('sequence-annotation-selected')
                  .show()
                  .parents('tr')
                  .show();
            }
        }

        rowlen = typeof rowlen !== 'undefined' ? rowlen : 80;
        clear();
        var rsplit = new RegExp('(.{1,'+rowlen+'})', 'g');
        var rows = sequence.match(rsplit);

        var ai = 0;
        _.map(annotations, function(a) { a.__sequence_annotation_id = ai; ai++; });

        var row_start = start_bp;
        _.map(rows, function(row) {
            var row_end = row_start+row.length-1;
            var row_annotations = _.select(annotations, function(a) {
                return (row_start <= a.base_first && a.base_first <= row_end) ||
                       (row_start <= a.base_last && a.base_last <= row_end);
            });

            var start_annotations = [];
            var end_annotations = [];

            _.map(row_annotations, function(a) {
                if (row_start <= a.base_first && a.base_first <= row_end) {
                    var i = a.base_first-row_start;
                    if (start_annotations[i] === undefined) { start_annotations[i] = []; }
                    start_annotations[i].push(a);
                }
                if (row_start <= a.base_last && a.base_last <= row_end) {
                    var i = a.base_last-row_start;
                    if (end_annotations[i] === undefined) { end_annotations[i] = []; }
                    end_annotations[i].push(a);
                }
            });

            var tr_mid = $('

');
            var pos = $('	').append(row_start);
            tr_mid.append(pos);
            var tr_top = [];
            var tr_bot = [];

            if (row_annotations.length === 0) {
                var td = $('	').append(row);
                tr_mid.append(td);
            }
            else {
                var tr_top_html = '

';
                var tr_bot_html = '

';

                var i = 0;
                _.map(row.split(''), function(bp) {
                    var td = $('	');
                    tr_mid.append(td);
                    td.append(bp);

                    add_annotations(row, i, '[', start_annotations, tr_top_html, tr_top);
                    add_annotations(row, i, ']', end_annotations, tr_bot_html, tr_bot);
                    i += 1;
                });
            }

            if (row_end < start_bp+sequence.length-1) {
                var pos = $('	').append(row_end);
                tr_mid.append(pos);
            }

            if (tr_top.length > 0) { tr_top[0].addClass('sequence-annotation-start-first'); }
            _.map(tr_top, function(tr) { $('table', selector).append(tr); });
            $('table', selector).append(tr_mid);
            if (tr_bot.length > 0) { tr_bot[tr_bot.length-1].addClass('sequence-annotation-end-last'); }
            _.map(tr_bot, function(tr) { $('table', selector).append(tr); });

            row_start += row.length;
        });

        $('tr.sequence-annotation td div').on('click', annotationToggle);
    }

    return {
        clear: clear,
        setSequenceWithAnnotations: setSequenceWithAnnotations
    }
};
<|endoftext|>


<commit_before>/* Sway (c) 2016 Benson Pan. MIT @license: en.wikipedia.org/wiki/MIT_License */

/* Note: Sway relies on JQuery and Velocity.js; a copy can be found on VelocityJS.org */
var callCount = 0;

var sway = function(animation)
{
	var velocity_param;

	// var fns = ['opacity', 'width', 'height', 'paddingTop', 'paddingRight', 'paddingBottom', 'paddingLeft', 'top', 'right', 'bottom', 'left', 'marginTop', 'marginRight', 'marginBottom', 'marginLeft', 'borderTopWidth', 'borderRightWidth', 'borderBottomWidth', 'borderLeftWidth', 'borderRadius', 'outerWidth', 'fontSize', 'lineHeight', 'letterSpacing', 'wordSpacing', 'color', 'colorRed', 'colorGreen', 'colorBlue', 'colorAlpha', 'backgroundColor', 'backgroundColorRed', 'backgroundColorBlue', 'backgroundColorGreen', 'backgroundColorAlpha', 'borderColor', 'borderColorRed', 'borderColorGreen', 'borderColorBlue', 'borderColorAlpha', 'outlineColor', 'outlineColorRed', 'outlineColorGreen', 'outlineColorBlue', 'outlineColorAlpha', 'textShadowX', 'textShadowY', 'textShadowBlur', 'boxShadowX', 'boxShadowY', 'boxShadowBlur', 'boxShadowSpread', 'translateX', 'translateY', 'translateZ', 'scale', 'scaleX', 'scaleY', 'rotateX', 'rotateY', 'rotateZ', 'skewX', 'skewY'];

	for (var key in animation)
	{
		velocity_param = key;
	}

	$('.sway').each(function(i, obj)
	{
		if (callCount == i)
		{
			var message = $(this).text();
			notCalled = 0;
			$(this).html(''); // clear the html

			while (message != '')
			{
				var indexSpace1 = message.indexOf(' ');
				if (indexSpace1 != -1)
				{
					if (message.indexOf('
') == 0)
					{
						$(this).append('
');
						message = message.substring(indexSpace1 + 1);
					}

					else
					{
						$(this).append('
' + message.substring(0, indexSpace1) + '
 ');
						message = message.substring(indexSpace1 + 1);
					}

				}
				else
				{
					$(this).append('
' + message + '
');
					message = '';
				}
			}
			$('.inner-sway' + callCount).each(function(i, obj)
			{
				var temp = {};
				var ending = {};
				temp[velocity_param] = parseInt(animation[velocity_param]) * -1;

				if ("scale".indexOf(velocity_param) != -1)
				{
					ending[velocity_param] = 1;
				}
				else if ("fontSizeopacity".indexOf(velocity_param) != -1)
				{
					ending[velocity_param] = $(this).css(velocity_param);
					temp[velocity_param] = $(this).css(velocity_param) / 2;
				}
				else if ("color".indexOf(velocity_param) != -1)
				{
					temp = animation;
					ending[velocity_param] = rgb2hex($(this).css(velocity_param));
				}
				else
				{
					ending[velocity_param] = $(this).css(velocity_param);
				}
				// FOLLOWING ARE NOT SUPPORTED:
				if ("heightwidth".indexOf(velocity_param) == -1)
				{
					$(this).hover(function()
					{
						if ($('.velocity-animating'))
							$(this).stop();
						$(this).velocity(animation, {duration:100, easing: 'easeOutBounce'});
						$(this).velocity(temp, {duration:200, easing: 'easeOutBounce'});
						$(this).velocity(ending, {duration:250, easing: 'easeOutBounce'});
					},
					function()
					{
					});
				}

			});
			$('.inner-sway' + callCount).css({'display':'inline-block'});
		}

		if (notCalled && i == $('.sway').length - 1)
			console.log("Sway: Function was called more than number of available .sway divs")
	});
	callCount++;
}

function rgb2hex(rgb) {
    if (/^#[0-9A-F]{6}$/i.test(rgb)) return rgb;

    rgb = rgb.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/);
    function hex(x) {
        return ("0" + parseInt(x).toString(16)).slice(-2);
    }
    return "#" + hex(rgb[1]) + hex(rgb[2]) + hex(rgb[3]);
}
<commit_msg>Update sway.js<commit_after>/* Sway (c) 2016 Benson Pan. MIT @license: en.wikipedia.org/wiki/MIT_License */

/* Note: Sway relies on JQuery and Velocity.js; a copy can be found on VelocityJS.org */

(function ( $ ) {
	var callCount = 0;
	$.fn.sway = function(animation)
	{
		function rgb2hex(rgb) {
			if (/^#[0-9A-F]{6}$/i.test(rgb)) return rgb;

			rgb = rgb.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/);
			function hex(x) {
				return ("0" + parseInt(x).toString(16)).slice(-2);
			}
			return "#" + hex(rgb[1]) + hex(rgb[2]) + hex(rgb[3]);
		}

		var velocity_param;
		var message;

		for (var key in animation)
		{
			velocity_param = key;
		}

		this.each(function(i, obj)
		{
			message = $(this).text();
			$(this).html('');
			callCount++;

			while (message != '')
			{
				var indexSpace1 = message.indexOf(' ');
				if (indexSpace1 != -1)
				{
					if (message.indexOf('
') == 0)
					{
						$(this).append('
');
						message = message.substring(indexSpace1 + 1);
					}

					else
					{
						$(this).append('
' + message.substring(0, indexSpace1) + '
 ');
						message = message.substring(indexSpace1 + 1);
					}

				}
				else
				{
					$(this).append('
' + message + '
');
					message = '';
				}
			}

			$('.inner-sway' + callCount).each(function(i, obj)
			{
				var temp = {};
				var ending = {};
				temp[velocity_param] = parseInt(animation[velocity_param]) * -1;

				if ("scale".indexOf(velocity_param) != -1)
				{
					ending[velocity_param] = 1;
				}
				else if ("fontSizeopacity".indexOf(velocity_param) != -1)
				{
					ending[velocity_param] = $(this).css(velocity_param);
					temp[velocity_param] = $(this).css(velocity_param) / 2;
				}
				else if ("color".indexOf(velocity_param) != -1)
				{
					temp = animation;
					ending[velocity_param] = rgb2hex($(this).css(velocity_param));
				}
				else
				{
					ending[velocity_param] = $(this).css(velocity_param);
				}
				// FOLLOWING ARE NOT SUPPORTED:
				if ("heightwidth".indexOf(velocity_param) == -1)
				{
					$(this).hover(function()
					{
						if ($('.velocity-animating'))
							$(this).stop();
						$(this).velocity(animation, {duration:100, easing: 'easeOutBounce'});
						$(this).velocity(temp, {duration:200, easing: 'easeOutBounce'});
						$(this).velocity(ending, {duration:250, easing: 'easeOutBounce'});
					},
					function()
					{
					});
				}

			});
			$('.inner-sway' + callCount).css({'display':'inline-block'});

		});
	}
}(jQuery));
<|endoftext|>


<commit_before>// avoids stack overflow for long lists
exports.forEach = function (array, func, callback) {
	step(0);
	function step(i) {
		if (i >= array.length)
			return callback(null);
		func(array[i], function (err) {
			if (err)
				return callback(err);
			setTimeout(step.bind(null, i + 1), 0);
		});
	}
};

exports.map = function (array, func, callback) {
	var results = [];
	step(0);
	function step(i) {
		if (i >= array.length)
			return callback(null, results);
		func(array[i], function (err, res) {
			if (err)
				return callback(err);
			results.push(res);
			setTimeout(step.bind(null, i + 1), 0);
		});
	}
};
<commit_msg>Use process.nextTick in tail helpers<commit_after>// avoids stack overflow for long lists
exports.forEach = function (array, func, callback) {
	step(0);
	function step(i) {
		if (i >= array.length)
			return callback(null);
		func(array[i], function (err) {
			if (err)
				return callback(err);
			process.nextTick(step.bind(null, i + 1));
		});
	}
};

exports.map = function (array, func, callback) {
	var results = [];
	step(0);
	function step(i) {
		if (i >= array.length)
			return callback(null, results);
		func(array[i], function (err, res) {
			if (err)
				return callback(err);
			results.push(res);
			process.nextTick(step.bind(null, i + 1));
		});
	}
};
<|endoftext|>


<commit_before>'use strict';

var spawn = require('cross-spawn'),
    fs = require('fs-extra'),
    path = require('path'),
    glob = require('glob'),
    config = require('./config'),
    utils = require('./utils'),
    logger = require('./logger');

var webpack = require('webpack');

module.exports = {

    /**
     * init a new project with mock and test module (default is not initilized)
     * @param  {[Object]} args {test: false, mock: false}
     */
    init: function(args) {
        var mock = !!args.mock;
        var test = !!args.test;

        var initMods = () => {
            var folders = ['js'];
            var cpfiles = ['pack.default.js', 'index.html', 'index.js', 'js/main.js'];
            if (mock) {
                folders.push('mock');
                cpfiles.push('mock/mock.js');

                logger.info(' Add mock module. ');
            }
            if (test) {
                Array.prototype.push.apply(folders, ['test', 'test/mocha', 'test/phantom']);
                Array.prototype.push.apply(cpfiles, ['test/karma.conf.js', 'test/mocha/index.test.js', 'test/phantom/index.test.js']);

                logger.info(' Add test module. ');
            }

            folders.forEach((folder) => {
                try {
                    fs.statSync(folder);
                } catch ( err ) {
                    if (err) {
                        fs.mkdirSync(folder);
                    }
                }
            })

            cpfiles.forEach((file) => {
                fs.stat(file, (err, stats) => {
                    if (err) {
                        var origin = path.join(__dirname, 'default', file);
                        var dest = path.join(process.cwd(), file);
                        fs.createReadStream(origin).pipe(fs.createWriteStream(dest));
                    }
                })
            })

            logger.info(' init successfully. ');
        }

        var packageJson = path.join(process.cwd(), 'package.json');
        fs.stat(packageJson, (err) => {
            if (err) {
                spawn('npm', ['init'], {
                    stdio: 'inherit'
                }).on('close', (code) => {
                    logger.info('Add key kil in package.json for system configuration. ');

                    var pack = require(packageJson);
                    pack.kil = require('./default/package.default.js');
                    fs.writeFile('package.json', JSON.stringify(pack), function(err) {
                        if (err) {
                            logger.error(err);
                            process.exit(1);
                        }
                    });

                    initMods();
                });
            } else {
                initMods();
            }
        })
    },

    /**
     * load webpack config and start webpack dev server
     * @return {[type]} [description]
     */
    dev: function(args) {
        var pack_config = utils.loadWebpackCfg('dev', args);

        var compiler = webpack(pack_config);
        var WebpackDevServer = require('webpack-dev-server');
        var serverCfg = {
            hot: true,
            watchOptions: {
                poll: 1000
            },
            stats: {
                colors: true
            }
        }

        if (pack_config.devServer && pack_config.devServer.proxy) {
            serverCfg.proxy = pack_config.devServer.proxy;
        }

        logger.debug('webpack dev server start with config: ');
        logger.debug(serverCfg);

        new WebpackDevServer(compiler, serverCfg).listen(config.getPort(), 'localhost', (err) => {
            if (err) {
                logger.error(err);
                process.exit(1);
            }

            logger.info('----------------------------------');
            logger.info(`Server listening at localhost:${config.getPort()}`);
            logger.info('----------------------------------');
        });
    },

    /**
     * do unit tests with mocha and endless tests with phantom
     * @param  {[Object]} args: {phantom: false, mocha: false}
     * @return {[type]}
     */
    test: function(args) {
        var mocha = !!args.mocha;
        var phantom = !!args.phantom;
        var server = !!args.server;

        var testPath = path.join(process.cwd(), 'test');
        fs.stat(testPath, (err) => {
            if (err) {
                logger.error(`can't find ${testPath}, have you ever ` + 'init test module'.to.bold.red.color + ' ? ');
                logger.error('try to use ' + 'kil init -t'.to.bold.red.color + ' to fix this issue. ');

                process.exit(1);
            }

            if (mocha) {
                var karmaBin = path.join(__dirname, 'node_modules/karma/bin/karma');
                var karmaConfPath = path.join(process.cwd(), 'test/karma.conf.js');

                var bins;
                if (server) {
                    bins = ['start', karmaConfPath, '--detached'];
                } else {
                    bins = ['start', karmaConfPath, '--detached', '--single-run'];
                }

                spawn(karmaBin, bins, {
                    stdio: 'inherit'
                }).on('close', (code) => {
                    logger.info(`mocha test finished with code : ${code}`);
                });
            }

            if (phantom) {
                var phantomBin = path.join(__dirname, 'node_modules/phantomjs/bin/phantomjs');
                var phantomEntry = path.join(process.cwd(), 'test/phantom/index.test.js');
                spawn(phantomBin, [phantomEntry], {
                    stdio: 'inherit',
                    cwd: __dirname
                }).on('close', (code) => {
                    logger.info(`phontom test finished with code : ${code}`);
                });
            }
        })
    },

    /**
     * use webpack and build bundle
     * @return {[type]} [description]
     */
    build: function(args) {
        var pack_config = utils.loadWebpackCfg('release', args);

        logger.info('start build project... ');

        var compiler = webpack(pack_config);
        compiler.run((err, stats) => {
            if (err) {
                logger.error(err);
            }
            var jsonStats = stats.toJson();
            if (jsonStats.errors.length > 0) {
                logger.error(jsonStats.errors);
            }
            if (jsonStats.warnings.length > 0) {
                logger.warn(jsonStats.warnings);
            }

            var conf = config.getConfig();
            if (conf.copy && conf.copy.length > 0) {
                conf.copy.forEach((key) => {
                    let files = glob.sync(key);
                    files.forEach((file) => {
                        fs.copySync(file, `dist/${file}`);
                    })
                })
            }

            logger.info('build successfully. ');
        });
    },

    /**
     * use webpack and build bundle
     * @return {[type]} [description]
     */
    release: function() {
        // var conf = config.loadPackageConfig(),
        //     pack_config = utils.loadWebpackCfg('release');

        // logger.info('building project...');

        // var compiler = webpack(pack_config);
        // compiler.run((err, stats) => {
        //     if (err) {
        //         console.error(err);
        //     }
        //     var jsonStats = stats.toJson();
        //     if (jsonStats.errors.length > 0) {
        //         return console.error(jsonStats.errors);
        //     }
        //     if (jsonStats.warnings.length > 0) {
        //         console.error(jsonStats.warnings);
        //     }

        //     logger.info('bundle built, copy files to dist folder');

        //     //TODO lib be cdn liked
        //     const copyList = ['img', 'images'];
        //     copyList.forEach((file) => {
        //         fs.stat(file, (err, stats) => {
        //             if (!err) {
        //                 spawn('cp', ['-r', file, `dist/${file}`], {
        //                     stdio: 'inherit'
        //                 }).on('close', function(code) {})
        //             }
        //         })
        //     });

        //     logger.info('build successfully.');

        //     //TODO zip
        // });
    }
}
<commit_msg>support img in css when dev<commit_after>'use strict';

var spawn = require('cross-spawn'),
    fs = require('fs-extra'),
    path = require('path'),
    glob = require('glob'),
    config = require('./config'),
    utils = require('./utils'),
    logger = require('./logger');

var webpack = require('webpack');

module.exports = {

    /**
     * init a new project with mock and test module (default is not initilized)
     * @param  {[Object]} args {test: false, mock: false}
     */
    init: function(args) {
        var mock = !!args.mock;
        var test = !!args.test;

        var initMods = () => {
            var folders = ['js'];
            var cpfiles = ['pack.default.js', 'index.html', 'index.js', 'js/main.js'];
            if (mock) {
                folders.push('mock');
                cpfiles.push('mock/mock.js');

                logger.info(' Add mock module. ');
            }
            if (test) {
                Array.prototype.push.apply(folders, ['test', 'test/mocha', 'test/phantom']);
                Array.prototype.push.apply(cpfiles, ['test/karma.conf.js', 'test/mocha/index.test.js', 'test/phantom/index.test.js']);

                logger.info(' Add test module. ');
            }

            folders.forEach((folder) => {
                try {
                    fs.statSync(folder);
                } catch ( err ) {
                    if (err) {
                        fs.mkdirSync(folder);
                    }
                }
            })

            cpfiles.forEach((file) => {
                fs.stat(file, (err, stats) => {
                    if (err) {
                        var origin = path.join(__dirname, 'default', file);
                        var dest = path.join(process.cwd(), file);
                        fs.createReadStream(origin).pipe(fs.createWriteStream(dest));
                    }
                })
            })

            logger.info(' init successfully. ');
        }

        var packageJson = path.join(process.cwd(), 'package.json');
        fs.stat(packageJson, (err) => {
            if (err) {
                spawn('npm', ['init'], {
                    stdio: 'inherit'
                }).on('close', (code) => {
                    logger.info('Add key kil in package.json for system configuration. ');

                    var pack = require(packageJson);
                    pack.kil = require('./default/package.default.js');
                    fs.writeFile('package.json', JSON.stringify(pack), function(err) {
                        if (err) {
                            logger.error(err);
                            process.exit(1);
                        }
                    });

                    initMods();
                });
            } else {
                initMods();
            }
        })
    },

    /**
     * load webpack config and start webpack dev server
     * @return {[type]} [description]
     */
    dev: function(args) {
        var pack_config = utils.loadWebpackCfg('dev', args);
        pack_config.output.publicPath = `http://localhost:${config.getPort()}/`;

        var compiler = webpack(pack_config);
        var WebpackDevServer = require('webpack-dev-server');
        var serverCfg = {
            hot: true,
            watchOptions: {
                poll: 1000
            },
            stats: {
                colors: true
            }
        }

        if (pack_config.devServer && pack_config.devServer.proxy) {
            serverCfg.proxy = pack_config.devServer.proxy;
        }

        logger.debug('webpack dev server start with config: ');
        logger.debug(serverCfg);

        new WebpackDevServer(compiler, serverCfg).listen(config.getPort(), 'localhost', (err) => {
            if (err) {
                logger.error(err);
                process.exit(1);
            }

            logger.info('----------------------------------');
            logger.info(`Server listening at localhost:${config.getPort()}`);
            logger.info('----------------------------------');
        });
    },

    /**
     * do unit tests with mocha and endless tests with phantom
     * @param  {[Object]} args: {phantom: false, mocha: false}
     * @return {[type]}
     */
    test: function(args) {
        var mocha = !!args.mocha;
        var phantom = !!args.phantom;
        var server = !!args.server;

        var testPath = path.join(process.cwd(), 'test');
        fs.stat(testPath, (err) => {
            if (err) {
                logger.error(`can't find ${testPath}, have you ever ` + 'init test module'.to.bold.red.color + ' ? ');
                logger.error('try to use ' + 'kil init -t'.to.bold.red.color + ' to fix this issue. ');

                process.exit(1);
            }

            if (mocha) {
                var karmaBin = path.join(__dirname, 'node_modules/karma/bin/karma');
                var karmaConfPath = path.join(process.cwd(), 'test/karma.conf.js');

                var bins;
                if (server) {
                    bins = ['start', karmaConfPath, '--detached'];
                } else {
                    bins = ['start', karmaConfPath, '--detached', '--single-run'];
                }

                spawn(karmaBin, bins, {
                    stdio: 'inherit'
                }).on('close', (code) => {
                    logger.info(`mocha test finished with code : ${code}`);
                });
            }

            if (phantom) {
                var phantomBin = path.join(__dirname, 'node_modules/phantomjs/bin/phantomjs');
                var phantomEntry = path.join(process.cwd(), 'test/phantom/index.test.js');
                spawn(phantomBin, [phantomEntry], {
                    stdio: 'inherit',
                    cwd: __dirname
                }).on('close', (code) => {
                    logger.info(`phontom test finished with code : ${code}`);
                });
            }
        })
    },

    /**
     * use webpack and build bundle
     * @return {[type]} [description]
     */
    build: function(args) {
        var pack_config = utils.loadWebpackCfg('release', args);

        logger.info('start build project... ');

        var compiler = webpack(pack_config);
        compiler.run((err, stats) => {
            if (err) {
                logger.error(err);
            }
            var jsonStats = stats.toJson();
            if (jsonStats.errors.length > 0) {
                logger.error(jsonStats.errors);
            }
            if (jsonStats.warnings.length > 0) {
                logger.warn(jsonStats.warnings);
            }

            var conf = config.getConfig();
            if (conf.copy && conf.copy.length > 0) {
                conf.copy.forEach((key) => {
                    let files = glob.sync(key);
                    files.forEach((file) => {
                        fs.copySync(file, `dist/${file}`);
                    })
                })
            }

            logger.info('build successfully. ');
        });
    },

    /**
     * use webpack and build bundle
     * @return {[type]} [description]
     */
    release: function() {
        // var conf = config.loadPackageConfig(),
        //     pack_config = utils.loadWebpackCfg('release');

        // logger.info('building project...');

        // var compiler = webpack(pack_config);
        // compiler.run((err, stats) => {
        //     if (err) {
        //         console.error(err);
        //     }
        //     var jsonStats = stats.toJson();
        //     if (jsonStats.errors.length > 0) {
        //         return console.error(jsonStats.errors);
        //     }
        //     if (jsonStats.warnings.length > 0) {
        //         console.error(jsonStats.warnings);
        //     }

        //     logger.info('bundle built, copy files to dist folder');

        //     //TODO lib be cdn liked
        //     const copyList = ['img', 'images'];
        //     copyList.forEach((file) => {
        //         fs.stat(file, (err, stats) => {
        //             if (!err) {
        //                 spawn('cp', ['-r', file, `dist/${file}`], {
        //                     stdio: 'inherit'
        //                 }).on('close', function(code) {})
        //             }
        //         })
        //     });

        //     logger.info('build successfully.');

        //     //TODO zip
        // });
    }
}
<|endoftext|>


<commit_before>var promise	= require( "promise" );
var async	= require( "async" );

var checkpointer = function( checkpointArgs ){

	var checkpoint = function( scope ){
		var promise = new Promise( function( resolve, reject ){
			console.log( "Would look through scope.." );
			return resolve( null );
		} );
		return promise;
	};
};

var myCheckpointer = new checkpointer( { "foo": "bar" } );

console.log( JSON.stringify( checkpointer ) );

var testFunc = function( argA, argB, cb ){

	var t = argA + argB;

	myCheckpointer.checkpoint( this ).then( function( ){
		cb( t % argA );
	} );
};

testFunc( 5, 1, function( res ){
	console.log( "I have res of " + res );
} );
<commit_msg>Got basic instance going.<commit_after>var util	= require( "util" );
var Promise	= require( "promise" );
var async	= require( "async" );

function Checkpointer( checkpointArgs ){

	this.checkpoint = function( scope ){
		var promise = new Promise( function( resolve, reject ){
			console.log( "Would look through scope.." );
			return resolve( null );
		} );
		return promise;
	};
};

var myCheckpointer = new Checkpointer( { "foo": "bar" } );

console.log( util.inspect( myCheckpointer ) );

var testFunc = function( argA, argB, cb ){

	var t = argA + argB;

	myCheckpointer.checkpoint( this ).then( function( ){
		cb( t % argA );
	} );
};

testFunc( 5, 1, function( res ){
	console.log( "I have res of " + res );
} );
<|endoftext|>


<commit_before>var util = require('util')

// Setup
// set env GEOIP2WS_USERID and GEOIP2WS_LICENSE (Travis CI)
// or user cli arguments: npm test --app_userid=1234 --app_license=abc123
var geo = require('./')(
  process.env.npm_config_app_userid || process.env.geoip2ws_userid || null,
  process.env.npm_config_app_license || process.env.geoip2ws_license || null,
  process.env.npm_config_app_service || process.env.geoip2ws_service || 'city'
)

// handle exits
var errors = 0
process.on( 'exit', function() {
	if( errors == 0 ) {
		console.log('\n\033[1mDONE, no errors.\033[0m\n')
		process.exit(0)
	} else {
		console.log('\n\033[1mFAIL, '+ errors +' error'+ (errors > 1 ? 's' : '') +' occurred!\033[0m\n')
		process.exit(1)
	}
})

// prevent errors from killing the process
process.on( 'uncaughtException', function( err ) {} )

// Queue to prevent flooding
var queue = []
var next = 0

function doNext() {
	next++
	if( queue[next] ) {
		queue[next]()
	}
}

// doTest( passErr, 'methods', [
//   ['feeds', typeof feeds === 'object']
// ])
function doTest( err, label, tests ) {
	if( err instanceof Error ) {
		console.error( label +': \033[1m\033[31mERROR\033[0m\n' )
		console.error( util.inspect(err, false, 10, true) )
		console.log()
		console.error( err.stack )
		console.log()
		errors++
	} else {
		var testErrors = []
		tests.forEach( function( test ) {
			if( test[1] !== true ) {
				testErrors.push(test[0])
				errors++
			}
		})

		if( testErrors.length == 0 ) {
			console.log( label +': \033[1mok\033[0m' )
		} else {
			console.error( label +': \033[1m\033[31mfailed\033[0m ('+ testErrors.join(', ') +')' )
		}
	}

	doNext()
}

// METHOD
queue.push( function() { doTest( null, 'module', [
  ['function type', typeof geo === 'function']
])})

// Test error
queue.push( function() {
  geo('', function(err, data) {
    doTest( null, 'error', [
      ['err instanceof Error', err instanceof Error]
    ])
  })
})

// Test success
queue.push( function() {
  geo('74.125.206.100', function(err, data) {
    doTest( err, 'lookup', [
      ['city name', !err && data && typeof data.city.names.en === 'string']
    ])
  })
})

// Start the tests
queue[0]()
<commit_msg>Tests: fixed env variables<commit_after>var util = require('util')

// Setup
// set env GEOIP2WS_USERID and GEOIP2WS_LICENSE (Travis CI)
// or user cli arguments: npm test --app_userid=1234 --app_license=abc123
var geo = require('./')(
  process.env.npm_config_app_userid || process.env.GEOIP2WS_USERID || null,
  process.env.npm_config_app_license || process.env.GEOIP2WS_LICENSE || null,
  process.env.npm_config_app_service || process.env.GEOIP2WS_SERVICE || 'city'
)

// handle exits
var errors = 0
process.on( 'exit', function() {
	if( errors == 0 ) {
		console.log('\n\033[1mDONE, no errors.\033[0m\n')
		process.exit(0)
	} else {
		console.log('\n\033[1mFAIL, '+ errors +' error'+ (errors > 1 ? 's' : '') +' occurred!\033[0m\n')
		process.exit(1)
	}
})

// prevent errors from killing the process
process.on( 'uncaughtException', function( err ) {} )

// Queue to prevent flooding
var queue = []
var next = 0

function doNext() {
	next++
	if( queue[next] ) {
		queue[next]()
	}
}

// doTest( passErr, 'methods', [
//   ['feeds', typeof feeds === 'object']
// ])
function doTest( err, label, tests ) {
	if( err instanceof Error ) {
		console.error( label +': \033[1m\033[31mERROR\033[0m\n' )
		console.error( util.inspect(err, false, 10, true) )
		console.log()
		console.error( err.stack )
		console.log()
		errors++
	} else {
		var testErrors = []
		tests.forEach( function( test ) {
			if( test[1] !== true ) {
				testErrors.push(test[0])
				errors++
			}
		})

		if( testErrors.length == 0 ) {
			console.log( label +': \033[1mok\033[0m' )
		} else {
			console.error( label +': \033[1m\033[31mfailed\033[0m ('+ testErrors.join(', ') +')' )
		}
	}

	doNext()
}

// METHOD
queue.push( function() { doTest( null, 'module', [
  ['function type', typeof geo === 'function']
])})

// Test error
queue.push( function() {
  geo('', function(err, data) {
    doTest( null, 'error', [
      ['err instanceof Error', err instanceof Error]
    ])
  })
})

// Test success
queue.push( function() {
  geo('74.125.206.100', function(err, data) {
    doTest( err, 'lookup', [
      ['city name', !err && data && typeof data.city.names.en === 'string']
    ])
  })
})

// Start the tests
queue[0]()
<|endoftext|>


<commit_before>const test = require('ava');
const random = require('./helpers/random');
const all = require('./products');

test('all()', t => {
  t.true(all.length > 0);
});

test('random()', t => {
  t.truthy(random(all));
  t.not(random(all), random(all));
});
<commit_msg>🤖(break): 2017-7-23 23:48:21<commit_after>const test = require('ava');
const random = require('./helpers/random');
const all = require('./products');

test('all()', t => {
  t.true(all.length < 0);
});

test('random()', t => {
  t.truthy(random(all));
  t.not(random(all), random(all));
});
<|endoftext|>


<commit_before>const test = require('ava');
const random = require('./helpers/random');
const all = require('./products');

test('all()', t => {
  t.true(all.length < 0);
});

test('random()', t => {
  t.truthy(random(all));
  t.not(random(all), random(all));
});
<commit_msg>🤖(fix): 2017-7-20 11:47:33<commit_after>const test = require('ava');
const random = require('./helpers/random');
const all = require('./products');

test('all()', t => {
  t.true(all.length > 0);
});

test('random()', t => {
  t.truthy(random(all));
  t.not(random(all), random(all));
});
<|endoftext|>


<commit_before>import test from 'ava';
import Now from './src/time.js';
import {Maths, Animation, Interpolation} from './src/inter.js';

let animation = new Animation();
let obj = {x: 0, y: 0};
let inter = new Interpolation(obj);
inter.interpolate({x: 50, y: 50}, 1000);

function testEaseInBounds(t, eased) {
  t.true(eased>=0.0 && eased<=1.0);
}

function testEasingFn(t, fn) {
  t.plan(10);
  for (let i=0; i<1.0; i+=.101) {
    testEaseInBounds(t, fn(i));
  }
}

function testSymmetricEasingFn(t, fn) {
  t.plan(70);
  for (let i=0; i<1.0; i+=.101) {
    for (let k = 0.5; k<=3.5; k+=0.5) {
      testEaseInBounds(t, fn(-1*(0.9-i*2), k));
    }
  }
}

test('Add interpolation to animation', function(t) {
  t.plan(2);
  t.is(animation.interpolations.length, 0);
  animation.add(inter);
  t.is(animation.interpolations.length, 1);
});
test('Added interpolations are not active', function(t) {
  t.plan(1);
  t.is(animation.active_interpolations.length, 0);
});
test('Remove interpolation from animation', function(t) {
  t.plan(1);
  animation.remove(inter);
  t.is(animation.interpolations.length, 0);
});
test('Interpolations become active when played', function(t) {
  t.plan(2);
  animation.play(inter);
  t.is(animation.interpolations.length, 1);
  t.is(animation.active_interpolations.length, 1);
});
test('Interpolations are removed from animations when complete', function(t) {
  t.plan(2);
  animation.update(Now()+1001);
  t.is(animation.interpolations.length, 0);
  t.is(animation.active_interpolations.length, 0);
});
test('Looping interpolations are not removed from animations when complete', function(t) {
  t.plan(4)

  inter = new Interpolation(obj);
  inter.interpolate({x: 50, y: 50}, 1000);
  inter.loop = -1;

  animation.play(inter);
  animation.update(Now()+1001);
  t.is(animation.interpolations.length, 1);
  t.is(animation.active_interpolations.length, 1);
  animation.remove(inter);
  t.is(animation.interpolations.length, 0);
  t.is(animation.active_interpolations.length, 0);
});
test('Interpolations may have multiple keyframes', function(t) {
  t.plan(2);

  inter = new Interpolation(obj);
  inter.interpolate({}, 1);
  t.is(inter.keyframes.length, 1);
  inter.interpolate({}, 1);
  t.is(inter.keyframes.length, 2);
});
test('Interpolation.update() returns true when not out of keyframes', function(t) {
  t.plan(1);
  t.is(inter.update(Now()+10), true);
});
test('Interpolation.update() on non-looping interpolations returns false if out of keyframes', function(t) {
  t.plan(1);
  t.is(inter.update(Now()+10), false);
});
test('Interpolation.update() on looping interpolations returns true if out of keyframes', function(t) {
  t.plan(1);
  inter = new Interpolation(obj);
  inter.interpolate({}, 1);
  inter.interpolate({}, 1);
  inter.loop = -1;
  t.is(inter.update(Now()+10), true);
});
test('Maths.isPowerOfTwo', function(t) {
  t.plan(7);
  t.true(Maths.isPowerOfTwo(0));
  t.true(Maths.isPowerOfTwo(0.5));
  t.true(Maths.isPowerOfTwo(1));
  t.true(Maths.isPowerOfTwo(1.2));
  t.false(Maths.isPowerOfTwo(3));
  t.false(Maths.isPowerOfTwo(5));
  t.true(Maths.isPowerOfTwo(8));
});
test('Maths.nextPowerOfTwo', function(t) {
  t.plan(7);
  t.is(Maths.nextPowerOfTwo(0), 0);
  t.is(Maths.nextPowerOfTwo(0.5), 0);
  t.is(Maths.nextPowerOfTwo(1), 1);
  t.is(Maths.nextPowerOfTwo(1.2), 1);
  t.is(Maths.nextPowerOfTwo(3), 4);
  t.is(Maths.nextPowerOfTwo(5), 8);
  t.is(Maths.nextPowerOfTwo(8), 8);
});
test('Maths.closestPowerOfTwo', function(t) {
  t.plan(7);
  t.is(Maths.closestPowerOfTwo(0), 0);
  t.is(Maths.closestPowerOfTwo(0.5), 0);
  t.is(Maths.closestPowerOfTwo(1), 1);
  t.is(Maths.closestPowerOfTwo(1.2), 1);
  t.is(Maths.closestPowerOfTwo(3), 4);
  t.is(Maths.closestPowerOfTwo(5), 4);
  t.is(Maths.closestPowerOfTwo(8), 8);
});
test('Maths.clip', function(t) {
  t.plan(3);
  t.is(Maths.clip(5.5, 5.1, 5.9), 5.5);
  t.is(Maths.clip(5.5, 5.6, 5.9), 5.6);
  t.is(Maths.clip(5.5, 5.1, 5.4), 5.4);
});
test('Maths.clip01', function(t) {
  t.plan(3);
  t.is(Maths.clip01(-0.5), 0.0);
  t.is(Maths.clip01(0.5), 0.5);
  t.is(Maths.clip01(1.5), 1.0);
});
test('Maths.lerp', function(t) {
  t.plan(3);
  t.is(Maths.lerp(0, 100, 0), 0);
  t.is(Maths.lerp(0, 100, 0.5), 50);
  t.is(Maths.lerp(0, 100, 1), 100);
});
test('Maths.lerpWithPrecision', function(t) {
  t.plan(2);
  t.is(Maths.lerp(-42.0e30, 42.0, 1.0), 0);
  t.is(Maths.lerpWithPrecision(-42.0e30, 42.0, 1.0), 42.0);
});
test('Maths.lerpAngle', function(t) {
  t.plan(8);
  t.is(Maths.lerpAngle(0, 90, 0), 0);
  t.is(Maths.lerpAngle(0, 90, 0.2), 18);
  t.is(Maths.lerpAngle(0, 90, 0.4), 36);
  t.is(Maths.lerpAngle(0, 90, 0.8), 72);
  t.is(Maths.lerpAngle(0, 90, 1.0), 90);
  t.is(Maths.lerpAngle(100, 90, 0.8), -8);
  t.is(Maths.lerpAngle(30, 862, 0.5), 56);
  t.is(Maths.lerpAngle(30, 862, 1.0), 112);
});
test('Maths.NoEasing', function(t) {
  t.plan(10);
  for (let i=0; i<1.0; i+=.101) {
    let eased = Maths.NoEasing(i);
    t.is(eased, i);
  }
});
test('Maths.QuadraticIn', function(t) {
  testEasingFn(t, Maths.QuadraticIn);
});
test('Maths.QuadraticOut', function(t) {
  testEasingFn(t, Maths.QuadraticOut);
});
test('Maths.QuadraticInOut', function(t) {
  testEasingFn(t, Maths.QuadraticInOut);
});
test('Maths.CubicIn', function(t) {
  testEasingFn(t, Maths.CubicIn);
});
test('Maths.CubicOut', function(t) {
  testEasingFn(t, Maths.CubicOut);
});
test('Maths.CubicInOut', function(t) {
  testEasingFn(t, Maths.CubicInOut);
});
test('Maths.QuarticIn', function(t) {
  testEasingFn(t, Maths.QuarticIn);
});
test('Maths.QuarticOut', function(t) {
  testEasingFn(t, Maths.QuarticOut);
});
test('Maths.QuarticInOut', function(t) {
  testEasingFn(t, Maths.QuarticInOut);
});
test('Maths.QuinticIn', function(t) {
  testEasingFn(t, Maths.QuinticIn);
});
test('Maths.QuinticOut', function(t) {
  testEasingFn(t, Maths.QuinticOut);
});
test('Maths.QuinticInOut', function(t) {
  testEasingFn(t, Maths.QuinticInOut);
});
test('Maths.Impulse', function(t) {
  t.plan(7);
  t.is(Maths.Impulse(0.0, 2), 0);
  t.is(Maths.Impulse(0.5, 2), 1);
  t.is(parseFloat(Maths.Impulse(1.0, 2).toFixed(2)), 0.74);
  t.is(Maths.Impulse(0.0, 24), 0);
  t.is(parseFloat(Maths.Impulse(0.1, 24).toFixed(2)), 0.59);
  t.is(parseFloat(Maths.Impulse(0.5, 24).toFixed(4)), 0.0002);
  t.is(parseFloat(Maths.Impulse(1.0, 24).toFixed(2)), 0);
});
test('Maths.CubicPulse', function(t) {
  t.plan(9);
  t.is(Maths.CubicPulse(0.0, 0.0, 0.5), 1);
  t.is(Maths.CubicPulse(0.5, 0.0, 0.5), 0);
  t.is(Maths.CubicPulse(1.0, 0.0, 0.5), 0);
  t.is(Maths.CubicPulse(0.0, 0.5, 0.5), 0);
  t.is(Maths.CubicPulse(0.5, 0.5, 0.5), 1);
  t.is(Maths.CubicPulse(1.0, 0.5, 0.5), 0);
  t.is(Maths.CubicPulse(0.0, 1.0, 0.5), 0);
  t.is(Maths.CubicPulse(0.5, 1.0, 0.5), 0);
  t.is(Maths.CubicPulse(1.0, 1.0, 0.5), 1);
});
test('Maths.PowerCurve', function(t) {
  t.plan(6);
  t.is(Maths.PowerCurve(0.0, 2.0, 1.0), 0);
  t.is(parseFloat(Maths.PowerCurve(0.2, 2.0, 1.0).toFixed(3)), 0.216);
  t.is(parseFloat(Maths.PowerCurve(0.4, 2.0, 1.0).toFixed(3)), 0.648);
  t.is(Maths.PowerCurve(0.6, 2.0, 1.0), 0.972);
  t.is(Maths.PowerCurve(0.8, 2.0, 1.0), 0.864);
  t.is(Maths.PowerCurve(1.0, 2.0, 1.0), 0);
});

test('Maths.SymmetricPowerCurveA', function(t) {
  testSymmetricEasingFn(t, Maths.SymmetricPowerCurveA);
});
test('Maths.SymmetricPowerCurveB', function(t) {
  testSymmetricEasingFn(t, Maths.SymmetricPowerCurveB);
});
test('Maths.SymmetricPowerCurveC', function(t) {
  testSymmetricEasingFn(t, Maths.SymmetricPowerCurveC);
});
test('Maths.SymmetricPowerCurveD', function(t) {
  testSymmetricEasingFn(t, Maths.SymmetricPowerCurveD);
});
test('Maths.SymmetricPowerCurveE', function(t) {
  testSymmetricEasingFn(t, Maths.SymmetricPowerCurveE);
});
<commit_msg>Code review updates from #5<commit_after>import test from 'ava';
import Now from './src/time.js';
import {Maths, Animation, Interpolation} from './src/inter.js';

let animation = new Animation();
let obj = {x: 0, y: 0};
let inter = new Interpolation(obj);
inter.interpolate({x: 50, y: 50}, 1000);

function testEaseInBounds(t, eased) {
  t.true(eased>=0.0 && eased<=1.0);
}

function testEasingFn(t, fn) {
  t.plan(10);
  for (let i=0; i<1.0; i+=.101) {
    testEaseInBounds(t, fn(i));
  }
}

function testSymmetricEasingFn(t, fn) {
  t.plan(70);
  for (let i=0; i<1.0; i+=.101) {
    for (let k = 0.5; k<=3.5; k+=0.5) {
      testEaseInBounds(t, fn(-1*(0.9-i*2), k));
    }
  }
}

test('Add interpolation to animation', function(t) {
  t.plan(2);
  t.is(animation.interpolations.length, 0);
  animation.add(inter);
  t.is(animation.interpolations.length, 1);
});
test('Added interpolations are not active', function(t) {
  t.plan(1);
  t.is(animation.active_interpolations.length, 0);
});
test('Remove interpolation from animation', function(t) {
  t.plan(1);
  animation.remove(inter);
  t.is(animation.interpolations.length, 0);
});
test('Interpolations become active when played', function(t) {
  t.plan(2);
  animation.play(inter);
  t.is(animation.interpolations.length, 1);
  t.is(animation.active_interpolations.length, 1);
});
test('Interpolations are removed from animations when complete', function(t) {
  t.plan(2);
  animation.update(Now()+1001);
  t.is(animation.interpolations.length, 0);
  t.is(animation.active_interpolations.length, 0);
});
test('Looping interpolations are not removed from animations when complete', function(t) {
  t.plan(4)

  inter = new Interpolation(obj);
  inter.interpolate({x: 50, y: 50}, 1000);
  inter.loop = -1;

  animation.play(inter);
  animation.update(Now()+1001);
  t.is(animation.interpolations.length, 1);
  t.is(animation.active_interpolations.length, 1);
  animation.remove(inter);
  t.is(animation.interpolations.length, 0);
  t.is(animation.active_interpolations.length, 0);
});
test('Interpolations may have multiple keyframes', function(t) {
  t.plan(2);

  inter = new Interpolation(obj);
  inter.interpolate({}, 1);
  t.is(inter.keyframes.length, 1);
  inter.interpolate({}, 1);
  t.is(inter.keyframes.length, 2);
});
test('Interpolation.update() returns true when not out of keyframes', function(t) {
  t.plan(1);
  t.is(inter.update(Now()+10), true);
});
test('Interpolation.update() on non-looping interpolations returns false if out of keyframes', function(t) {
  t.plan(1);
  t.is(inter.update(Now()+10), false);
});
test('Interpolation.update() on looping interpolations returns true if out of keyframes', function(t) {
  t.plan(1);
  inter = new Interpolation(obj);
  inter.interpolate({}, 1);
  inter.loop = -1;
  t.is(inter.update(Now()+10), true);
});
test('Maths.isPowerOfTwo', function(t) {
  t.plan(7);
  t.true(Maths.isPowerOfTwo(0));
  t.true(Maths.isPowerOfTwo(0.5));
  t.true(Maths.isPowerOfTwo(1));
  t.true(Maths.isPowerOfTwo(1.2));
  t.false(Maths.isPowerOfTwo(3));
  t.false(Maths.isPowerOfTwo(5));
  t.true(Maths.isPowerOfTwo(8));
});
test('Maths.nextPowerOfTwo', function(t) {
  t.plan(7);
  t.is(Maths.nextPowerOfTwo(0), 0);
  t.is(Maths.nextPowerOfTwo(0.5), 0);
  t.is(Maths.nextPowerOfTwo(1), 1);
  t.is(Maths.nextPowerOfTwo(1.2), 1);
  t.is(Maths.nextPowerOfTwo(3), 4);
  t.is(Maths.nextPowerOfTwo(5), 8);
  t.is(Maths.nextPowerOfTwo(8), 8);
});
test('Maths.closestPowerOfTwo', function(t) {
  t.plan(7);
  t.is(Maths.closestPowerOfTwo(0), 0);
  t.is(Maths.closestPowerOfTwo(0.5), 0);
  t.is(Maths.closestPowerOfTwo(1), 1);
  t.is(Maths.closestPowerOfTwo(1.2), 1);
  t.is(Maths.closestPowerOfTwo(3), 4);
  t.is(Maths.closestPowerOfTwo(5), 4);
  t.is(Maths.closestPowerOfTwo(8), 8);
});
test('Maths.clip', function(t) {
  t.plan(3);
  t.is(Maths.clip(5.5, 5.1, 5.9), 5.5);
  t.is(Maths.clip(5.5, 5.6, 5.9), 5.6);
  t.is(Maths.clip(5.5, 5.1, 5.4), 5.4);
});
test('Maths.clip01', function(t) {
  t.plan(3);
  t.is(Maths.clip01(-0.5), 0.0);
  t.is(Maths.clip01(0.5), 0.5);
  t.is(Maths.clip01(1.5), 1.0);
});
test('Maths.lerp', function(t) {
  t.plan(3);
  t.is(Maths.lerp(0, 100, 0), 0);
  t.is(Maths.lerp(0, 100, 0.5), 50);
  t.is(Maths.lerp(0, 100, 1), 100);
});
test('Maths.lerpWithPrecision', function(t) {
  t.plan(2);
  t.is(Maths.lerp(-42.0e30, 42.0, 1.0), 0);
  t.is(Maths.lerpWithPrecision(-42.0e30, 42.0, 1.0), 42.0);
});
test('Maths.lerpAngle', function(t) {
  t.plan(8);
  t.is(Maths.lerpAngle(0, 90, 0), 0);
  t.is(Maths.lerpAngle(0, 90, 0.2), 18);
  t.is(Maths.lerpAngle(0, 90, 0.4), 36);
  t.is(Maths.lerpAngle(0, 90, 0.8), 72);
  t.is(Maths.lerpAngle(0, 90, 1.0), 90);
  t.is(Maths.lerpAngle(100, 90, 0.8), -8);
  t.is(Maths.lerpAngle(30, 862, 0.5), 56);
  t.is(Maths.lerpAngle(30, 862, 1.0), 112);
});
test('Maths.NoEasing', function(t) {
  t.plan(10);
  for (let i=0; i<1.0; i+=.101) {
    let eased = Maths.NoEasing(i);
    t.is(eased, i);
  }
});
test('Maths.QuadraticIn', function(t) {
  testEasingFn(t, Maths.QuadraticIn);
});
test('Maths.QuadraticOut', function(t) {
  testEasingFn(t, Maths.QuadraticOut);
});
test('Maths.QuadraticInOut', function(t) {
  testEasingFn(t, Maths.QuadraticInOut);
});
test('Maths.CubicIn', function(t) {
  testEasingFn(t, Maths.CubicIn);
});
test('Maths.CubicOut', function(t) {
  testEasingFn(t, Maths.CubicOut);
});
test('Maths.CubicInOut', function(t) {
  testEasingFn(t, Maths.CubicInOut);
});
test('Maths.QuarticIn', function(t) {
  testEasingFn(t, Maths.QuarticIn);
});
test('Maths.QuarticOut', function(t) {
  testEasingFn(t, Maths.QuarticOut);
});
test('Maths.QuarticInOut', function(t) {
  testEasingFn(t, Maths.QuarticInOut);
});
test('Maths.QuinticIn', function(t) {
  testEasingFn(t, Maths.QuinticIn);
});
test('Maths.QuinticOut', function(t) {
  testEasingFn(t, Maths.QuinticOut);
});
test('Maths.QuinticInOut', function(t) {
  testEasingFn(t, Maths.QuinticInOut);
});
test('Maths.Impulse', function(t) {
  t.plan(7);
  t.is(Maths.Impulse(0.0, 2), 0);
  t.is(Maths.Impulse(0.5, 2), 1);
  t.is(parseFloat(Maths.Impulse(1.0, 2).toFixed(2)), 0.74);
  t.is(Maths.Impulse(0.0, 24), 0);
  t.is(parseFloat(Maths.Impulse(0.1, 24).toFixed(2)), 0.59);
  t.is(parseFloat(Maths.Impulse(0.5, 24).toFixed(4)), 0.0002);
  t.is(parseFloat(Maths.Impulse(1.0, 24).toFixed(2)), 0);
});
test('Maths.CubicPulse', function(t) {
  t.plan(9);
  t.is(Maths.CubicPulse(0.0, 0.0, 0.5), 1);
  t.is(Maths.CubicPulse(0.5, 0.0, 0.5), 0);
  t.is(Maths.CubicPulse(1.0, 0.0, 0.5), 0);
  t.is(Maths.CubicPulse(0.0, 0.5, 0.5), 0);
  t.is(Maths.CubicPulse(0.5, 0.5, 0.5), 1);
  t.is(Maths.CubicPulse(1.0, 0.5, 0.5), 0);
  t.is(Maths.CubicPulse(0.0, 1.0, 0.5), 0);
  t.is(Maths.CubicPulse(0.5, 1.0, 0.5), 0);
  t.is(Maths.CubicPulse(1.0, 1.0, 0.5), 1);
});
test('Maths.PowerCurve', function(t) {
  t.plan(6);
  t.is(Maths.PowerCurve(0.0, 2.0, 1.0), 0);
  t.is(parseFloat(Maths.PowerCurve(0.2, 2.0, 1.0).toFixed(3)), 0.216);
  t.is(parseFloat(Maths.PowerCurve(0.4, 2.0, 1.0).toFixed(3)), 0.648);
  t.is(Maths.PowerCurve(0.6, 2.0, 1.0), 0.972);
  t.is(Maths.PowerCurve(0.8, 2.0, 1.0), 0.864);
  t.is(Maths.PowerCurve(1.0, 2.0, 1.0), 0);
});

test('Maths.SymmetricPowerCurveA', function(t) {
  testSymmetricEasingFn(t, Maths.SymmetricPowerCurveA);
});
test('Maths.SymmetricPowerCurveB', function(t) {
  testSymmetricEasingFn(t, Maths.SymmetricPowerCurveB);
});
test('Maths.SymmetricPowerCurveC', function(t) {
  testSymmetricEasingFn(t, Maths.SymmetricPowerCurveC);
});
test('Maths.SymmetricPowerCurveD', function(t) {
  testSymmetricEasingFn(t, Maths.SymmetricPowerCurveD);
});
test('Maths.SymmetricPowerCurveE', function(t) {
  testSymmetricEasingFn(t, Maths.SymmetricPowerCurveE);
});
<|endoftext|>


<commit_before>const test = require('ava');
const random = require('./helpers/random');
const all = require('./products');

test('all()', t => {
  t.true(all.length < 0);
});

test('random()', t => {
  t.truthy(random(all));
  t.not(random(all), random(all));
});
<commit_msg>🤖(fix): 2017-6-13 20:41:36<commit_after>const test = require('ava');
const random = require('./helpers/random');
const all = require('./products');

test('all()', t => {
  t.true(all.length > 0);
});

test('random()', t => {
  t.truthy(random(all));
  t.not(random(all), random(all));
});
<|endoftext|>


<commit_before>// Unit tests for reactive-function.
var assert = require("assert");

// If using from the NPM package, this line would be
// var ReactiveFunction = require("reactive-function");
var ReactiveFunction = require("./index.js");

var ReactiveProperty = require("reactive-property");

var outputGraph = require("graph-diagrams")({

  // If true, writes graph files to ../graph-diagrams for visualization.
  outputGraphs: true,
  project: "reactive-function"
});

function output(name){
  outputGraph(ReactiveFunction.serializeGraph(), name);
}

describe("ReactiveFunction", function() {

  it("Should depend on two reactive properties.", function () {

    var firstName = ReactiveProperty("Jane");
    var lastName = ReactiveProperty("Smith");

    var fullName = ReactiveProperty();

    var reactiveFunction = ReactiveFunction({
      inputs: [firstName, lastName],
      output: fullName,
      callback: function (first, last){
        return first + " " + last;
      }
    });

    ReactiveFunction.digest();
    assert.equal(fullName(), "Jane Smith");

    firstName("John");
    ReactiveFunction.digest();
    assert.equal(fullName(), "John Smith");

    lastName("Lennon");
    ReactiveFunction.digest();
    assert.equal(fullName(), "John Lennon");

    // For serialization.
    firstName.propertyName = "firstName";
    lastName.propertyName = "lastName";
    fullName.propertyName = "fullName";
    output("full-name");

    reactiveFunction.destroy();
  });

  it("Should depend on any number of reactive properties.", function () {
    var a = ReactiveProperty(5);
    var b = ReactiveProperty(10);
    var c = ReactiveProperty(15);

    var d = ReactiveProperty();
    var e = ReactiveProperty();

    var rf1 = ReactiveFunction({
      inputs: [a],
      output: d,
      callback: function (a){
        return a * 2;
      }
    });

    var rf2 = ReactiveFunction({
      inputs: [a, b, c],
      output: e,
      callback: function (a, b, c){
        return a + b + c;
      }
    });

    ReactiveFunction.digest();

    assert.equal(d(), 10);
    assert.equal(e(), 30);

    // For serialization.
    a.propertyName = "a";
    b.propertyName = "b";
    c.propertyName = "c";
    d.propertyName = "d";
    e.propertyName = "e";
    output("any-number");

    rf1.destroy();
    rf2.destroy();
  });

  it("Should depend on a reactive function output.", function () {

    var a = ReactiveProperty(5);
    var b = ReactiveProperty();
    var c = ReactiveProperty();

    var rf1 = ReactiveFunction({
      inputs: [a],
      output: b,
      callback: function (a){
        return a * 2;
      }
    });

    var rf2 = ReactiveFunction({
      inputs: [b],
      output: c,
      callback: function (b){
        return b / 2;
      }
    });

    ReactiveFunction.digest();
    assert.equal(c(), 5);

    // For serialization.
    a.propertyName = "a";
    b.propertyName = "b";
    c.propertyName = "c";
    output("abc");

    rf1.destroy();
    rf2.destroy();
  });

  it("Should depend on a property and a reactive function output.", function () {

    var a = ReactiveProperty(5);
    var b = ReactiveProperty(10);

    var c = ReactiveProperty();
    var d = ReactiveProperty();

    var rf1 = ReactiveFunction({
      inputs: [a],
      output: c,
      callback: function (a){
        return a * 2;
      }
    });

    var rf2 = ReactiveFunction({
      inputs: [b, c],
      output: d,
      callback: function (b, c){
        return b + c;
      }
    });

    ReactiveFunction.digest();
    assert.equal(d(), 20);

    // For serialization.
    a.propertyName = "a";
    b.propertyName = "b";
    c.propertyName = "c";
    d.propertyName = "d";
    output("abcd");

    rf1.destroy();
    rf2.destroy();
  });

  it("Should handle tricky case.", function () {

    // This is the case where model-js failed (https://github.com/curran/model),
    // which cropped up as flashes of inconstistent states in Chiasm visualizations.
    // For example, it happens when you change the X column in this example
    // "Magic Heat Map" http://bl.ocks.org/curran/a54fc3a6578efcdc19f4
    // This flaw in model-js is the main inspiration for making this library and using topological sort.
    //
    //      a
    //     / \
    //    b   |
    //    |   d
    //    c   |
    //     \ /
    //      e
    //
    var a = ReactiveProperty(5);
    var b = ReactiveProperty();
    var c = ReactiveProperty();
    var d = ReactiveProperty();
    var e = ReactiveProperty();

    var rfs = [
      ReactiveFunction({ inputs: [a],    output: b, callback: function (a){    return a * 2; } }),
      ReactiveFunction({ inputs: [b],    output: c, callback: function (b){    return b + 5; } }),
      ReactiveFunction({ inputs: [a],    output: d, callback: function (a){    return a * 3; } }),
      ReactiveFunction({ inputs: [c, d], output: e, callback: function (c, d){ return c + d; } })
    ];

    ReactiveFunction.digest();
    assert.equal(e(), ((a() * 2) + 5) + (a() * 3));

    a(10);
    ReactiveFunction.digest();
    assert.equal(e(), ((a() * 2) + 5) + (a() * 3));

    // For serialization.
    a.propertyName = "a";
    b.propertyName = "b";
    c.propertyName = "c";
    d.propertyName = "d";
    e.propertyName = "e";
    output("tricky-case");

    rfs.forEach(function (reactiveFunction){
      reactiveFunction.destroy();
    });
  });

  it("Should clear changed nodes on digest.", function () {
    var numInvocations = 0;
    var a = ReactiveProperty(5);
    var b = ReactiveProperty();

    var reactiveFunction = ReactiveFunction({
      inputs: [a],
      output: b,
      callback: function (a){
        numInvocations++;
        return a * 2;
      }
    });

    ReactiveFunction.digest();
    ReactiveFunction.digest();
    assert.equal(numInvocations, 1);

    reactiveFunction.destroy();
  });

  it("Should automatically digest on next tick.", function (done) {
    var a = ReactiveProperty(5);
    var b = ReactiveProperty(10);
    var c = ReactiveProperty();

    var reactiveFunction = ReactiveFunction({
      inputs: [a, b],
      output: c,
      callback: function (a, b){
        return a + b;
      }
    });

    ReactiveFunction.nextFrame(function (){
      assert.equal(c(), 15);
      reactiveFunction.destroy();
      done();
    }, 0);

  });

  it("Should remove listeners on destroy.", function (done){
    var a = ReactiveProperty(5);
    var b = ReactiveProperty(10);
    var c = ReactiveProperty();

    var rf = ReactiveFunction({
      inputs: [a, b],
      output: c,
      callback: function (a, b){
        return a + b;
      }
    });

    // Wait until after the first auto-digest.
    ReactiveFunction.nextFrame(function (){

      rf.destroy();

      // Without the call to destroy(), this would trigger a digest.
      a(20);

      // Give time for an auto-digest to occur.
      ReactiveFunction.nextFrame(function (){

        // Confirm that a digest did not occur.
        assert.equal(c(), 15);

        done();
      }, 0);
    }, 0);
  });

  it("Should remove edges on destroy.", function (){
    var a = ReactiveProperty(5);
    var b = ReactiveProperty(10);
    var c = ReactiveProperty();

    var rf = ReactiveFunction({
      inputs: [a, b],
      output: c,
      callback: function (a, b){
        return a + b;
      }
    });

    ReactiveFunction.digest();

    assert.equal(c(), 15);

    rf.destroy();

    a(20);

    ReactiveFunction.digest();
    assert.equal(c(), 15);
  });

  it("Should not invoke if an input is undefined.", function (){
    var numInvocations = 0;
    var a = ReactiveProperty();
    var b = ReactiveProperty(10);
    var c = ReactiveProperty();

    var reactiveFunction = ReactiveFunction({
      inputs: [a, b],
      output: c,
      callback: function (a, b){
        numInvocations++;
        return a + b;
      }
    });

    ReactiveFunction.digest();
    assert.equal(numInvocations, 0);

    reactiveFunction.destroy();
  });

  it("Should invoke if an input is null.", function (){
    var numInvocations = 0;
    var a = ReactiveProperty(null);
    var b = ReactiveProperty(10);
    var c = ReactiveProperty();

    var reactiveFunction = ReactiveFunction({
      inputs: [a, b],
      output: c,
      callback: function (a, b){
        numInvocations++;
        return a + b;
      }
    });

    ReactiveFunction.digest();
    assert.equal(numInvocations, 1);

    reactiveFunction.destroy();
  });

  it("Should invoke if a single input is null.", function (){
    var numInvocations = 0;
    var a = ReactiveProperty(null);

    var reactiveFunction = ReactiveFunction({
      inputs: [a],
      callback: function (a, b){
        numInvocations++;
      }
    });

    ReactiveFunction.digest();
    assert.equal(numInvocations, 1);

    reactiveFunction.destroy();
  });

  it("Should be able to implement unidirectional data binding.", function (){

    var a = ReactiveProperty(5);
    var b = ReactiveProperty(10);

    var reactiveFunction = ReactiveFunction({
      inputs: [a],
      output: b,
      callback: function (a){
        return a;
      }
    });

    ReactiveFunction.digest();

    assert.equal(b(), 5);

    // For serialization.
    a.propertyName = "a";
    b.propertyName = "b";
    output("ab");

    reactiveFunction.destroy();
  });

  it("Should be able to implement bidirectional data binding.", function (){

    var a = ReactiveProperty(5);
    var b = ReactiveProperty(10);

    function identity(x){ return x; }

    var rf1 = ReactiveFunction({ inputs: [a], output: b, callback: identity });
    var rf2 = ReactiveFunction({ inputs: [b], output: a, callback: identity });

    ReactiveFunction.digest();

    // The most recently added edge takes precedence.
    assert.equal(b(), 10);

    a(50);
    ReactiveFunction.digest();
    assert.equal(b(), 50);

    b(100);
    ReactiveFunction.digest();
    assert.equal(a(), 100);

    // For serialization.
    a.propertyName = "a";
    b.propertyName = "b";
    output("data-binding");

    rf1.destroy();
    rf2.destroy();
  });

  it("Should compute Ohm's Law.", function (){

    // These symbols are used in the definition of Ohm's law.
    // See https://en.wikipedia.org/wiki/Ohm%27s_law
    var I = ReactiveProperty();
    var V = ReactiveProperty();
    var R = ReactiveProperty();

    var rfs = [

      // I = V / R
      ReactiveFunction({
        inputs: [V, R],
        output: I,
        callback: function (v, r){ return v / r; }
      }),

      // V = I * R
      ReactiveFunction({
        inputs: [I, R],
        output: V,
        callback: function (i, r){ return i * r; }
      }),

      // R = V / I
      ReactiveFunction({
        inputs: [V, I],
        output: R,
        callback: function (v, i){ return v / i; }
      })
    ];

    V(9)
    I(2)
    ReactiveFunction.digest();
    assert.equal(R(), 4.5);

    R(6)
    I(2)
    ReactiveFunction.digest();
    assert.equal(V(), 12);

    V(9);
    R(18);
    ReactiveFunction.digest();
    assert.equal(I(), 0.5);

    V(9)
    I(2)
    ReactiveFunction.digest();
    assert.equal(R(), 4.5);

    // For serialization.
    V.propertyName = "V";
    I.propertyName = "I";
    R.propertyName = "R";
    output("ohms-law");

    rfs.forEach(function (reactiveFunction){
      reactiveFunction.destroy();
    });
  });

  it("Should remove the 'evaluate' function from the output on destroy.", function (){
    var a = ReactiveProperty(5);
    var b = ReactiveProperty(10);
    var c = ReactiveProperty();

    var rf = ReactiveFunction({
      inputs: [a, b],
      output: c,
      callback: function (a, b){
        return a + b;
      }
    });

    assert.equal(typeof c.evaluate, "function");

    rf.destroy();
    assert.equal(typeof c.evaluate, "undefined");
  });

  it("Should work without any output specified.", function (){
    var a = ReactiveProperty(5);
    var b = ReactiveProperty(10);
    var sideEffect = 0;

    var rf = ReactiveFunction({
      inputs: [a, b],
      callback: function (a, b){
        sideEffect++;
      }
    });

    ReactiveFunction.digest();
    assert(sideEffect);

    rf.destroy();
  });

  it("Should work asynchronously.", function (done){
    var a = ReactiveProperty(5);
    var b = ReactiveProperty(10);
    var c = ReactiveProperty();

    var rf = ReactiveFunction({
      inputs: [a, b],
      callback: function (a, b) {
        setTimeout(function(){
          c(a + b);
        }, 10);
      }
    });

    c.on(function(value){
      assert.equal(value, 15);
      rf.destroy();
      done();
    });
  });

  it("Should serialize the data flow graph.", function (){

    var firstName = ReactiveProperty("Jane");
    var lastName = ReactiveProperty("Smith");
    var fullName = ReactiveProperty();

    // For serialization.
    firstName.propertyName = "firstName";
    lastName.propertyName = "lastName";
    fullName.propertyName = "fullName";

    var rf = ReactiveFunction({
      inputs: [firstName, lastName],
      output: fullName,
      callback: function (first, last){
        return first + " " + last;
      }
    });

    var serialized = ReactiveFunction.serializeGraph();

    //console.log(JSON.stringify(serialized, null, 2));

    assert.equal(serialized.nodes.length, 3);
    assert.equal(serialized.links.length, 2);

    assert.equal(serialized.nodes[0].id, "fullName");
    assert.equal(serialized.nodes[1].id, "firstName");
    assert.equal(serialized.nodes[2].id, "lastName");

    assert.equal(serialized.links[0].source, "firstName");
    assert.equal(serialized.links[0].target, "fullName");
    assert.equal(serialized.links[1].source, "lastName");
    assert.equal(serialized.links[1].target, "fullName");

    rf.destroy();
  });

  it("Should serialize the data flow graph, falling back to property ids.", function (){

    var firstName = ReactiveProperty("Jane");
    var lastName = ReactiveProperty("Smith");
    var fullName = ReactiveProperty();

    ReactiveFunction({
      inputs: [firstName, lastName],
      output: fullName,
      callback: function (first, last){
        return first + " " + last;
      }
    });

    var serialized = ReactiveFunction.serializeGraph();

    assert.equal(serialized.nodes.length, 3);
    assert.equal(serialized.links.length, 2);

    // These tests may easily break if earlier tests are modified.
    // Fix by copying values from:
    //console.log(JSON.stringify(serialized, null, 2));

    assert.equal(serialized.nodes[0].id, "59");
    assert.equal(serialized.nodes[1].id, "60");
    assert.equal(serialized.nodes[2].id, "61");

    assert.equal(serialized.links[0].source, "60");
    assert.equal(serialized.links[0].target, "59");
    assert.equal(serialized.links[1].source, "61");
    assert.equal(serialized.links[1].target, "59");

  });
});
<commit_msg>Add test for serialize without any output specified (empty string as name)<commit_after>// Unit tests for reactive-function.
var assert = require("assert");

// If using from the NPM package, this line would be
// var ReactiveFunction = require("reactive-function");
var ReactiveFunction = require("./index.js");

var ReactiveProperty = require("reactive-property");

var outputGraph = require("graph-diagrams")({

  // If true, writes graph files to ../graph-diagrams for visualization.
  outputGraphs: true,
  project: "reactive-function"
});

function output(name){
  outputGraph(ReactiveFunction.serializeGraph(), name);
}

describe("ReactiveFunction", function() {

  it("Should depend on two reactive properties.", function () {

    var firstName = ReactiveProperty("Jane");
    var lastName = ReactiveProperty("Smith");

    var fullName = ReactiveProperty();

    var reactiveFunction = ReactiveFunction({
      inputs: [firstName, lastName],
      output: fullName,
      callback: function (first, last){
        return first + " " + last;
      }
    });

    ReactiveFunction.digest();
    assert.equal(fullName(), "Jane Smith");

    firstName("John");
    ReactiveFunction.digest();
    assert.equal(fullName(), "John Smith");

    lastName("Lennon");
    ReactiveFunction.digest();
    assert.equal(fullName(), "John Lennon");

    // For serialization.
    firstName.propertyName = "firstName";
    lastName.propertyName = "lastName";
    fullName.propertyName = "fullName";
    output("full-name");

    reactiveFunction.destroy();
  });

  it("Should depend on any number of reactive properties.", function () {
    var a = ReactiveProperty(5);
    var b = ReactiveProperty(10);
    var c = ReactiveProperty(15);

    var d = ReactiveProperty();
    var e = ReactiveProperty();

    var rf1 = ReactiveFunction({
      inputs: [a],
      output: d,
      callback: function (a){
        return a * 2;
      }
    });

    var rf2 = ReactiveFunction({
      inputs: [a, b, c],
      output: e,
      callback: function (a, b, c){
        return a + b + c;
      }
    });

    ReactiveFunction.digest();

    assert.equal(d(), 10);
    assert.equal(e(), 30);

    // For serialization.
    a.propertyName = "a";
    b.propertyName = "b";
    c.propertyName = "c";
    d.propertyName = "d";
    e.propertyName = "e";
    output("any-number");

    rf1.destroy();
    rf2.destroy();
  });

  it("Should depend on a reactive function output.", function () {

    var a = ReactiveProperty(5);
    var b = ReactiveProperty();
    var c = ReactiveProperty();

    var rf1 = ReactiveFunction({
      inputs: [a],
      output: b,
      callback: function (a){
        return a * 2;
      }
    });

    var rf2 = ReactiveFunction({
      inputs: [b],
      output: c,
      callback: function (b){
        return b / 2;
      }
    });

    ReactiveFunction.digest();
    assert.equal(c(), 5);

    // For serialization.
    a.propertyName = "a";
    b.propertyName = "b";
    c.propertyName = "c";
    output("abc");

    rf1.destroy();
    rf2.destroy();
  });

  it("Should depend on a property and a reactive function output.", function () {

    var a = ReactiveProperty(5);
    var b = ReactiveProperty(10);

    var c = ReactiveProperty();
    var d = ReactiveProperty();

    var rf1 = ReactiveFunction({
      inputs: [a],
      output: c,
      callback: function (a){
        return a * 2;
      }
    });

    var rf2 = ReactiveFunction({
      inputs: [b, c],
      output: d,
      callback: function (b, c){
        return b + c;
      }
    });

    ReactiveFunction.digest();
    assert.equal(d(), 20);

    // For serialization.
    a.propertyName = "a";
    b.propertyName = "b";
    c.propertyName = "c";
    d.propertyName = "d";
    output("abcd");

    rf1.destroy();
    rf2.destroy();
  });

  it("Should handle tricky case.", function () {

    // This is the case where model-js failed (https://github.com/curran/model),
    // which cropped up as flashes of inconstistent states in Chiasm visualizations.
    // For example, it happens when you change the X column in this example
    // "Magic Heat Map" http://bl.ocks.org/curran/a54fc3a6578efcdc19f4
    // This flaw in model-js is the main inspiration for making this library and using topological sort.
    //
    //      a
    //     / \
    //    b   |
    //    |   d
    //    c   |
    //     \ /
    //      e
    //
    var a = ReactiveProperty(5);
    var b = ReactiveProperty();
    var c = ReactiveProperty();
    var d = ReactiveProperty();
    var e = ReactiveProperty();

    var rfs = [
      ReactiveFunction({ inputs: [a],    output: b, callback: function (a){    return a * 2; } }),
      ReactiveFunction({ inputs: [b],    output: c, callback: function (b){    return b + 5; } }),
      ReactiveFunction({ inputs: [a],    output: d, callback: function (a){    return a * 3; } }),
      ReactiveFunction({ inputs: [c, d], output: e, callback: function (c, d){ return c + d; } })
    ];

    ReactiveFunction.digest();
    assert.equal(e(), ((a() * 2) + 5) + (a() * 3));

    a(10);
    ReactiveFunction.digest();
    assert.equal(e(), ((a() * 2) + 5) + (a() * 3));

    // For serialization.
    a.propertyName = "a";
    b.propertyName = "b";
    c.propertyName = "c";
    d.propertyName = "d";
    e.propertyName = "e";
    output("tricky-case");

    rfs.forEach(function (reactiveFunction){
      reactiveFunction.destroy();
    });
  });

  it("Should clear changed nodes on digest.", function () {
    var numInvocations = 0;
    var a = ReactiveProperty(5);
    var b = ReactiveProperty();

    var reactiveFunction = ReactiveFunction({
      inputs: [a],
      output: b,
      callback: function (a){
        numInvocations++;
        return a * 2;
      }
    });

    ReactiveFunction.digest();
    ReactiveFunction.digest();
    assert.equal(numInvocations, 1);

    reactiveFunction.destroy();
  });

  it("Should automatically digest on next tick.", function (done) {
    var a = ReactiveProperty(5);
    var b = ReactiveProperty(10);
    var c = ReactiveProperty();

    var reactiveFunction = ReactiveFunction({
      inputs: [a, b],
      output: c,
      callback: function (a, b){
        return a + b;
      }
    });

    ReactiveFunction.nextFrame(function (){
      assert.equal(c(), 15);
      reactiveFunction.destroy();
      done();
    }, 0);

  });

  it("Should remove listeners on destroy.", function (done){
    var a = ReactiveProperty(5);
    var b = ReactiveProperty(10);
    var c = ReactiveProperty();

    var rf = ReactiveFunction({
      inputs: [a, b],
      output: c,
      callback: function (a, b){
        return a + b;
      }
    });

    // Wait until after the first auto-digest.
    ReactiveFunction.nextFrame(function (){

      rf.destroy();

      // Without the call to destroy(), this would trigger a digest.
      a(20);

      // Give time for an auto-digest to occur.
      ReactiveFunction.nextFrame(function (){

        // Confirm that a digest did not occur.
        assert.equal(c(), 15);

        done();
      }, 0);
    }, 0);
  });

  it("Should remove edges on destroy.", function (){
    var a = ReactiveProperty(5);
    var b = ReactiveProperty(10);
    var c = ReactiveProperty();

    var rf = ReactiveFunction({
      inputs: [a, b],
      output: c,
      callback: function (a, b){
        return a + b;
      }
    });

    ReactiveFunction.digest();

    assert.equal(c(), 15);

    rf.destroy();

    a(20);

    ReactiveFunction.digest();
    assert.equal(c(), 15);
  });

  it("Should not invoke if an input is undefined.", function (){
    var numInvocations = 0;
    var a = ReactiveProperty();
    var b = ReactiveProperty(10);
    var c = ReactiveProperty();

    var reactiveFunction = ReactiveFunction({
      inputs: [a, b],
      output: c,
      callback: function (a, b){
        numInvocations++;
        return a + b;
      }
    });

    ReactiveFunction.digest();
    assert.equal(numInvocations, 0);

    reactiveFunction.destroy();
  });

  it("Should invoke if an input is null.", function (){
    var numInvocations = 0;
    var a = ReactiveProperty(null);
    var b = ReactiveProperty(10);
    var c = ReactiveProperty();

    var reactiveFunction = ReactiveFunction({
      inputs: [a, b],
      output: c,
      callback: function (a, b){
        numInvocations++;
        return a + b;
      }
    });

    ReactiveFunction.digest();
    assert.equal(numInvocations, 1);

    reactiveFunction.destroy();
  });

  it("Should invoke if a single input is null.", function (){
    var numInvocations = 0;
    var a = ReactiveProperty(null);

    var reactiveFunction = ReactiveFunction({
      inputs: [a],
      callback: function (a, b){
        numInvocations++;
      }
    });

    ReactiveFunction.digest();
    assert.equal(numInvocations, 1);

    reactiveFunction.destroy();
  });

  it("Should be able to implement unidirectional data binding.", function (){

    var a = ReactiveProperty(5);
    var b = ReactiveProperty(10);

    var reactiveFunction = ReactiveFunction({
      inputs: [a],
      output: b,
      callback: function (a){
        return a;
      }
    });

    ReactiveFunction.digest();

    assert.equal(b(), 5);

    // For serialization.
    a.propertyName = "a";
    b.propertyName = "b";
    output("ab");

    reactiveFunction.destroy();
  });

  it("Should be able to implement bidirectional data binding.", function (){

    var a = ReactiveProperty(5);
    var b = ReactiveProperty(10);

    function identity(x){ return x; }

    var rf1 = ReactiveFunction({ inputs: [a], output: b, callback: identity });
    var rf2 = ReactiveFunction({ inputs: [b], output: a, callback: identity });

    ReactiveFunction.digest();

    // The most recently added edge takes precedence.
    assert.equal(b(), 10);

    a(50);
    ReactiveFunction.digest();
    assert.equal(b(), 50);

    b(100);
    ReactiveFunction.digest();
    assert.equal(a(), 100);

    // For serialization.
    a.propertyName = "a";
    b.propertyName = "b";
    output("data-binding");

    rf1.destroy();
    rf2.destroy();
  });

  it("Should compute Ohm's Law.", function (){

    // These symbols are used in the definition of Ohm's law.
    // See https://en.wikipedia.org/wiki/Ohm%27s_law
    var I = ReactiveProperty();
    var V = ReactiveProperty();
    var R = ReactiveProperty();

    var rfs = [

      // I = V / R
      ReactiveFunction({
        inputs: [V, R],
        output: I,
        callback: function (v, r){ return v / r; }
      }),

      // V = I * R
      ReactiveFunction({
        inputs: [I, R],
        output: V,
        callback: function (i, r){ return i * r; }
      }),

      // R = V / I
      ReactiveFunction({
        inputs: [V, I],
        output: R,
        callback: function (v, i){ return v / i; }
      })
    ];

    V(9)
    I(2)
    ReactiveFunction.digest();
    assert.equal(R(), 4.5);

    R(6)
    I(2)
    ReactiveFunction.digest();
    assert.equal(V(), 12);

    V(9);
    R(18);
    ReactiveFunction.digest();
    assert.equal(I(), 0.5);

    V(9)
    I(2)
    ReactiveFunction.digest();
    assert.equal(R(), 4.5);

    // For serialization.
    V.propertyName = "V";
    I.propertyName = "I";
    R.propertyName = "R";
    output("ohms-law");

    rfs.forEach(function (reactiveFunction){
      reactiveFunction.destroy();
    });
  });

  it("Should remove the 'evaluate' function from the output on destroy.", function (){
    var a = ReactiveProperty(5);
    var b = ReactiveProperty(10);
    var c = ReactiveProperty();

    var rf = ReactiveFunction({
      inputs: [a, b],
      output: c,
      callback: function (a, b){
        return a + b;
      }
    });

    assert.equal(typeof c.evaluate, "function");

    rf.destroy();
    assert.equal(typeof c.evaluate, "undefined");
  });

  it("Should work without any output specified.", function (){
    var a = ReactiveProperty(5);
    var b = ReactiveProperty(10);
    var sideEffect = 0;

    var rf = ReactiveFunction({
      inputs: [a, b],
      callback: function (a, b){
        sideEffect++;
      }
    });

    ReactiveFunction.digest();
    assert(sideEffect);

    rf.destroy();
  });

  it("Should work asynchronously.", function (done){
    var a = ReactiveProperty(5);
    var b = ReactiveProperty(10);
    var c = ReactiveProperty();

    var rf = ReactiveFunction({
      inputs: [a, b],
      callback: function (a, b) {
        setTimeout(function(){
          c(a + b);
        }, 10);
      }
    });

    c.on(function(value){
      assert.equal(value, 15);
      rf.destroy();
      done();
    });
  });

  it("Should serialize the data flow graph.", function (){

    var firstName = ReactiveProperty("Jane");
    var lastName = ReactiveProperty("Smith");
    var fullName = ReactiveProperty();

    // For serialization.
    firstName.propertyName = "firstName";
    lastName.propertyName = "lastName";
    fullName.propertyName = "fullName";

    var rf = ReactiveFunction({
      inputs: [firstName, lastName],
      output: fullName,
      callback: function (first, last){
        return first + " " + last;
      }
    });

    var serialized = ReactiveFunction.serializeGraph();

    //console.log(JSON.stringify(serialized, null, 2));

    assert.equal(serialized.nodes.length, 3);
    assert.equal(serialized.links.length, 2);

    assert.equal(serialized.nodes[0].id, "fullName");
    assert.equal(serialized.nodes[1].id, "firstName");
    assert.equal(serialized.nodes[2].id, "lastName");

    assert.equal(serialized.links[0].source, "firstName");
    assert.equal(serialized.links[0].target, "fullName");
    assert.equal(serialized.links[1].source, "lastName");
    assert.equal(serialized.links[1].target, "fullName");

    rf.destroy();
  });

  it("Should serialize the data flow graph, falling back to property ids.", function (){

    var firstName = ReactiveProperty("Jane");
    var lastName = ReactiveProperty("Smith");
    var fullName = ReactiveProperty();
    var rf = ReactiveFunction({
      inputs: [firstName, lastName],
      output: fullName,
      callback: function (first, last){
        return first + " " + last;
      }
    });

    var serialized = ReactiveFunction.serializeGraph();

    assert.equal(serialized.nodes.length, 3);
    assert.equal(serialized.links.length, 2);

    // These tests may easily break if earlier tests are modified.
    // Fix by copying values from:
    //console.log(JSON.stringify(serialized, null, 2));

    assert.equal(serialized.nodes[0].id, "59");
    assert.equal(serialized.nodes[1].id, "60");
    assert.equal(serialized.nodes[2].id, "61");

    assert.equal(serialized.links[0].source, "60");
    assert.equal(serialized.links[0].target, "59");
    assert.equal(serialized.links[1].source, "61");
    assert.equal(serialized.links[1].target, "59");

    rf.destroy();
  });

  it("Should serialize without any output specified (empty string as name).", function (){
    var a = ReactiveProperty(5);
    var b = ReactiveProperty(10);
    var sideEffect = 0;

    var rf = ReactiveFunction({
      inputs: [a, b],
      callback: function (a, b){
        sideEffect++;
      }
    });

    // For serialization.
    a.propertyName = "a";
    b.propertyName = "b";
    var serialized = ReactiveFunction.serializeGraph();

    assert.equal(serialized.nodes.length, 3);
    assert.equal(serialized.links.length, 2);

    //console.log(JSON.stringify(serialized, null, 2));

    assert.equal(serialized.nodes[0].id, "62");
    assert.equal(serialized.nodes[1].id, "a");
    assert.equal(serialized.nodes[2].id, "b");

    assert.equal(serialized.links[0].source, "a");
    assert.equal(serialized.links[0].target, "62");
    assert.equal(serialized.links[1].source, "b");
    assert.equal(serialized.links[1].target, "62");

    rf.destroy();
  });
});
<|endoftext|>


<commit_before>'use strict';

/**
 * Dependencies.
 */

var iterate,
    assert;

iterate = require('./');
assert = require('assert');

/**
 * Tests.
 */

describe('iterate()', function () {
    it('should be a `function`', function () {
        assert(typeof iterate === 'function');
    });

    it('should throw when no `values` are given', function () {
        assert.throws(function () {
            iterate();
        }, /\|this\| not be undefined/);
    });

    it('should throw when an object without `length` is given', function () {
        assert.throws(function () {
            iterate({});
        }, /\|this\| has a `length`/);
    });

    it('should throw when no `callback` is given', function () {
        assert.throws(function () {
            iterate([]);
        }, /must be a function/);
    });

    it('should iterate over an array with `value`, `index`, and `values`',
        function () {
            var list,
                n;

            list = [0, 1, 2];

            n = 0;

            iterate(list, function (value, index, values) {
                assert(value === n);
                assert(index === n);
                assert(values === list);

                n++;
            });

            assert(n === 3);
        }
    );

    it('should invoke `callback` with `undefined` as context', function () {
        var n;

        n = 0;

        iterate([1, 2, 3], function () {
            assert(this === undefined);

            n++;
        });

        assert(n === 3);
    });

    it('should invoke `callback` with the given `context`', function () {
        var scope,
            n;

        scope = this;

        n = 0;

        iterate([1, 2, 3], function () {
            assert(this === scope);

            n++;
        }, scope);

        assert(n === 3);
    });

    it('should change the next position when `callback` returns a number',
        function () {
            var n;

            n = 0;

            iterate([0, 1, 2], function (value, index) {
                n++;

                assert(value === index);

                /**
                 * Stay on position `0` ten times.
                 */

                if (n <= 10) {
                    return 0;
                }
            });

            assert(n === 13);
        }
    );

    it('should ignore missing values', function () {
        var list,
            magicNumber,
            n;

        magicNumber = 10;

        list = Array(magicNumber);

        list.push(magicNumber + 1);

        iterate(list, function (value, index) {
            assert(value === magicNumber + 1);

            assert(index === magicNumber);

            n = index;
        });

        assert(n === magicNumber);
    });

    it('should NOT fail when a negative index is returned', function () {
        var results,
            n;

        n = 0;

        results = ['a', 'b', 'a', 'b', 'c', 'd'];

        iterate(['a', 'b', 'c', 'd'], function (value) {
            assert(value === results[n]);

            n++;

            if (n === 2) {
                return -1;
            }
        });

        assert(n === results.length);
    });
});
<commit_msg>Fix incorrect executive rights on `test.js`<commit_after>'use strict';

/**
 * Dependencies.
 */

var iterate,
    assert;

iterate = require('./');
assert = require('assert');

/**
 * Tests.
 */

describe('iterate()', function () {
    it('should be a `function`', function () {
        assert(typeof iterate === 'function');
    });

    it('should throw when no `values` are given', function () {
        assert.throws(function () {
            iterate();
        }, /\|this\| not be undefined/);
    });

    it('should throw when an object without `length` is given', function () {
        assert.throws(function () {
            iterate({});
        }, /\|this\| has a `length`/);
    });

    it('should throw when no `callback` is given', function () {
        assert.throws(function () {
            iterate([]);
        }, /must be a function/);
    });

    it('should iterate over an array with `value`, `index`, and `values`',
        function () {
            var list,
                n;

            list = [0, 1, 2];

            n = 0;

            iterate(list, function (value, index, values) {
                assert(value === n);
                assert(index === n);
                assert(values === list);

                n++;
            });

            assert(n === 3);
        }
    );

    it('should invoke `callback` with `undefined` as context', function () {
        var n;

        n = 0;

        iterate([1, 2, 3], function () {
            assert(this === undefined);

            n++;
        });

        assert(n === 3);
    });

    it('should invoke `callback` with the given `context`', function () {
        var scope,
            n;

        scope = this;

        n = 0;

        iterate([1, 2, 3], function () {
            assert(this === scope);

            n++;
        }, scope);

        assert(n === 3);
    });

    it('should change the next position when `callback` returns a number',
        function () {
            var n;

            n = 0;

            iterate([0, 1, 2], function (value, index) {
                n++;

                assert(value === index);

                /**
                 * Stay on position `0` ten times.
                 */

                if (n <= 10) {
                    return 0;
                }
            });

            assert(n === 13);
        }
    );

    it('should ignore missing values', function () {
        var list,
            magicNumber,
            n;

        magicNumber = 10;

        list = Array(magicNumber);

        list.push(magicNumber + 1);

        iterate(list, function (value, index) {
            assert(value === magicNumber + 1);

            assert(index === magicNumber);

            n = index;
        });

        assert(n === magicNumber);
    });

    it('should NOT fail when a negative index is returned', function () {
        var results,
            n;

        n = 0;

        results = ['a', 'b', 'a', 'b', 'c', 'd'];

        iterate(['a', 'b', 'c', 'd'], function (value) {
            assert(value === results[n]);

            n++;

            if (n === 2) {
                return -1;
            }
        });

        assert(n === results.length);
    });
});
<|endoftext|>


<commit_before>const test = require('ava');
const random = require('./helpers/random');
const all = require('./products');

test('all()', t => {
  t.true(all.length < 0);
});

test('random()', t => {
  t.truthy(random(all));
  t.not(random(all), random(all));
});
<commit_msg>🤖(fix): 2017-12-4 02:38:04<commit_after>const test = require('ava');
const random = require('./helpers/random');
const all = require('./products');

test('all()', t => {
  t.true(all.length > 0);
});

test('random()', t => {
  t.truthy(random(all));
  t.not(random(all), random(all));
});
<|endoftext|>