<commit_before>var chalk = require('chalk');
var childProcess = require('child_process');
var fs = require('fs');
var mkdirp = require('mkdirp');
var parseArgs = require('minimist');
var path = require('path');
var semver = require('semver');
var series = require('run-series');
//var tilde = require('tilde-expansion');
var Wizzard = require('wizzard').Wizzard;

//var merge = require('../lib/commands/merge.js');
var printHelp = require('./help/print-help.js');
var mergeCommands = require('../lib/mergeCmds.js');

//todo improve this with tilde
var potterHome = path.join(process.env.HOME, '.potter');

var commandMap = {
    'install' : install,
    'i': install,
    'remove' : remove,
    'rm': remove,
    'list': list,
    'ls': list,
    'help': halp
};

if (require.main === module) {
    plugin(parseArgs(process.argv.slice(2)), function(err) {
          throw err;
      });
}

function plugin(opts, cb) {
    if(opts._.length === 0) {
        halp();
    } else if(Object.keys(commandMap).indexOf(opts._[0]) !== -1) {
        var cmd = opts._[0];
        opts._ = opts._.slice(1);
        commandMap[cmd](opts, cb);
    }
}

function install(opts, cb) {
    var plugin = opts._[0];
    if (!plugin) cb(new Error(chalk.red('You must provide a plugin to install')));
    var version;
    if(plugin.indexOf('@') && plugin.substr(0,7) !== 'git+ssh') {
        //if only JS had tuples
        version = plugin.split('@');
        plugin = version[0];
        version = (version.length > 1) ? version[1] : null;
    }

    if(plugin.substr(0,7) === 'git+ssh' && plugin.indexOf('#') !== -1) {
        version = plugin.split('#');
        plugin = version[0];
        version = (version.length > 1) ? version[1] : null;
    }

    series([
        //make sure the potter folder exists
        function(cb) {
            fs.exists(potterHome, function(exists) {
                if(exists) {
                    cb(null);
                } else {
                    mkdirp(potterHome, cb);
                }
            });
        },
        //make sure a package.json exists
        function(cb) {
            fs.exists(path.join(potterHome, 'package.json'), function(exists) {
                if(exists) {
                    cb(null);
                } else {
                    var packagejson = '{"dependencies":{}}';
                    fs.writeFile(path.join(potterHome, 'package.json'), packagejson, cb);
                }
            });
        },
        function(cb) {

            //install plugin into ~/.playdoh/node_modules
            //update ~/.playdoh/package.json
            //TODO error handling
            var plugins = require(path.join(potterHome, 'package.json'));
            var deps = plugins.dependencies;
            var found = false;
            //check to see if the plugin has already been installed
            Object.keys(deps).forEach(function(key) {
                var wizz = new Wizzard();
                var upgradeString;
                var depUri;
                var depRef;
                var sDepRef;
                var sVersion;
                var rollback;
                //modules on npm
                if (key === plugin) {
                    found = true;
                    // check if specified version is greater.
                    if(version && semver.gtr(version, deps[key])) {
                        //ask to upgrade if no version
                        upgradeString = 'Do you want to upgrade from ' + deps[key] + ' to ' + version + '?';
                    } else if (version && semver.ltr(version, deps[key])) {
                        //ask to downgrade
                        upgradeString = 'Do you want to downgrade from ' + deps[key] + ' to ' + version + '?';
                    } else {
                        // already installed upgrade?
                        upgradeString = 'Do you want to upgrade from ' + deps[key] + ' to the latest version?';
                    }
                    wizz.addInput(upgradeString, ['y','n']);
                    wizz.on('end', rhb(dealWithIt, null, {name:plugin, version:version, rollback:rollback}, cb));
                    wizz.run();

                } else if(deps[key] === plugin) {
                    found = true;
                    //match exact urls (e.g. git+ssh)
                    console.log(chalk.yellow('This version of ' + key + ' is already installed'));
                    process.exit();
                } else if (deps[key].substr(0,7) === 'git+ssh') {
                    depRef = deps[key].split('#');
                    depUri = depRef[0];
                    depRef = (depRef.length > 1) ? depRef[1] : null;

                    //check if same plugin giturl
                    if(depUri === plugin) {
                        found = true;
                        rollback = key;
                        //now compare refs
                        if((sDepRef = semver.valid(depRef)) &&
                           (sVersion = semver.valid(version))) {
                            if(semver.lt(sDepRef, sVersion)) {
                                //if current version is less than new version ask to upgrade
                                upgradeString = 'Do you want to upgrade from ' + deps[key] + ' to ' + version + '?';

                            } else if(semver.gt(sDepRef, sVersion)) {
                                //if current version is higher than new version ask to downgrade
                                upgradeString = 'Do you want to downgrade from ' + deps[key] + ' to ' + version + '?';

                            } else {
                                //if current version asked to upgrade
                                upgradeString = 'Do you want to upgrade from ' + deps[key] + ' to the latest version?';
                            }
                            wizz.addInput(upgradeString, ['y','n']);
                            wizz.on('end', rhb(dealWithIt, null, {name:plugin, version:version, rollback:rollback}, cb));
                            wizz.run();
                        } else {
                            //at least one of the gitrefs isn't semver
                            //so just ask to upgrade
                            upgradeString = 'Do you want to upgrade from ' + deps[key] + ' to the latest version?';
                            wizz.addInput(upgradeString, ['y','n']);
                            wizz.on('end', rhb(dealWithIt, null, {name:plugin, version:version, rollback:rollback}, cb));
                            wizz.run();
                        }
                    }
                }
            });

            if(!found) {
                installPlugin(plugin, version, null, cb);
            }
        }
    ]);

}

function dealWithIt(input, pkg, cb) {
    if(input[0] === 'y') {
        installPlugin(pkg.name, pkg.version, pkg.rollback, cb);
    } else {
        cb(null);
    }
}

function installPlugin(pkg, version, rollback, cb) {
    var installable = pkg;
    if(version) {
        if(pkg.substr(0,7) === 'git+ssh') {
            installable += '#' + version;
        } else {
            installable += '@' + version;
        }
    }
    var cmd = 'i -S ' + installable;
    console.log('Installing plugin...');
    npm(cmd, potterHome, function validateInstall(err, stdout) {
        //make sure install was success
        //console.log(stderr);
        // console.log(stdout);
        if(err) {
            console.log(chalk.red('NPM install failed!'));
            console.log('Please read the ' + path.join(potterHome, '/npm-debug.log'));
            process.exit();
        }
        console.log('Plugin installed');
        var installed = stdout.match(/^([a-z][-a-z0-9]*)@(\d+\.\d+.\d+ )/m)[1];
        try {
            console.log('Checking for conflicts...');
            var cmds = mergeCommands(path.join(__dirname,'../'), ['lib', 'cli-deprecated.js']);
            mergeCommands(path.join(potterHome,'node_modules'), ['.bin'], cmds);
        /*jshint -W002 */
        } catch (err) {
            console.log(chalk.red('Plugin had conflicts!'));
            console.log('Rolling back...');
            //rollback
            if(rollback) {
                return installPlugin(pkg, rollback, null, cb);
            } else {
                return remove({_:[installed]});
            }
        }

        console.log(chalk.green('Installed Plugin!'));
        process.exit();
    });
}

function npm(cmd, cwd, cb) {
    cmd = 'npm ' + cmd;
    childProcess.exec(cmd, {cwd:cwd}, cb);
}

function remove(opts, cb) {
    var plugin = opts._[0];
    if (!plugin) cb(new Error(chalk.red('You must provide a plugin to remove')));
    console.log(chalk.red('Removing ' + plugin));

    var cmd = 'rm -S ' + plugin;
    npm(cmd, potterHome, function npmRm(err, stdout, stderr) {
        if(err) throw new Error('wat rm');

        //console.log(stdout);
        //console.log(stderr);

        if(stderr && stderr.indexOf('npm WARN uninstall not installed') !== -1) {
            return console.log('Plugin ' + plugin + ' was not installed');
        }
        console.log('Removed plugin ' + plugin);
    });
}

function list() {
    var cmd = 'ls | grep "^[└├]"';
    npm(cmd, potterHome, function npmList(err, stdout) {
        if(err) throw new Error('wat');
        //console.log(stderr);
        var libs = stdout.split('\n');
        libs = libs.map(function(lib) {
            return lib.substr(4);
        }).filter(function(lib) {
            return lib;
        }).forEach(function(lib) {
            var line = chalk.green(' * ') + lib;
            console.log(line);
        });
    });
}

function rhb(fn, scope) {
    //right hand bind
    //call with function, this, arg1, arg2, etc
    var args = Array.prototype.slice.call(arguments).slice(2);
    return function() {
        args = Array.prototype.slice.call(arguments).concat(args);
        fn.apply(scope, args);
    };
}

function halp() {
    return printHelp(path.join(__dirname, 'usage-plugin.md'));
}

plugin.help = halp;

module.exports = plugin;
<commit_msg>get rid of silly errors<commit_after>var chalk = require('chalk');
var childProcess = require('child_process');
var fs = require('fs');
var mkdirp = require('mkdirp');
var parseArgs = require('minimist');
var path = require('path');
var semver = require('semver');
var series = require('run-series');
//var tilde = require('tilde-expansion');
var Wizzard = require('wizzard').Wizzard;

//var merge = require('../lib/commands/merge.js');
var printHelp = require('./help/print-help.js');
var mergeCommands = require('../lib/mergeCmds.js');

//todo improve this with tilde
var potterHome = path.join(process.env.HOME, '.potter');

var commandMap = {
    'install' : install,
    'i': install,
    'remove' : remove,
    'rm': remove,
    'list': list,
    'ls': list,
    'help': halp
};

if (require.main === module) {
    plugin(parseArgs(process.argv.slice(2)), function(err) {
          throw err;
      });
}

function plugin(opts, cb) {
    if(opts._.length === 0) {
        halp();
    } else if(Object.keys(commandMap).indexOf(opts._[0]) !== -1) {
        var cmd = opts._[0];
        opts._ = opts._.slice(1);
        commandMap[cmd](opts, cb);
    }
}

function install(opts, cb) {
    var plugin = opts._[0];
    if (!plugin) cb(new Error(chalk.red('You must provide a plugin to install')));
    var version;
    if(plugin.indexOf('@') && plugin.substr(0,7) !== 'git+ssh') {
        //if only JS had tuples
        version = plugin.split('@');
        plugin = version[0];
        version = (version.length > 1) ? version[1] : null;
    }

    if(plugin.substr(0,7) === 'git+ssh' && plugin.indexOf('#') !== -1) {
        version = plugin.split('#');
        plugin = version[0];
        version = (version.length > 1) ? version[1] : null;
    }

    series([
        //make sure the potter folder exists
        function(cb) {
            fs.exists(potterHome, function(exists) {
                if(exists) {
                    cb(null);
                } else {
                    mkdirp(potterHome, cb);
                }
            });
        },
        //make sure a package.json exists
        function(cb) {
            fs.exists(path.join(potterHome, 'package.json'), function(exists) {
                if(exists) {
                    cb(null);
                } else {
                    var packagejson = '{"dependencies":{}}';
                    fs.writeFile(path.join(potterHome, 'package.json'), packagejson, cb);
                }
            });
        },
        function(cb) {

            //install plugin into ~/.playdoh/node_modules
            //update ~/.playdoh/package.json
            //TODO error handling
            var plugins = require(path.join(potterHome, 'package.json'));
            var deps = plugins.dependencies;
            var found = false;
            //check to see if the plugin has already been installed
            Object.keys(deps).forEach(function(key) {
                var wizz = new Wizzard();
                var upgradeString;
                var depUri;
                var depRef;
                var sDepRef;
                var sVersion;
                var rollback;
                //modules on npm
                if (key === plugin) {
                    found = true;
                    // check if specified version is greater.
                    if(version && semver.gtr(version, deps[key])) {
                        //ask to upgrade if no version
                        upgradeString = 'Do you want to upgrade from ' + deps[key] + ' to ' + version + '?';
                    } else if (version && semver.ltr(version, deps[key])) {
                        //ask to downgrade
                        upgradeString = 'Do you want to downgrade from ' + deps[key] + ' to ' + version + '?';
                    } else {
                        // already installed upgrade?
                        upgradeString = 'Do you want to upgrade from ' + deps[key] + ' to the latest version?';
                    }
                    wizz.addInput(upgradeString, ['y','n']);
                    wizz.on('end', rhb(dealWithIt, null, {name:plugin, version:version, rollback:rollback}, cb));
                    wizz.run();

                } else if(deps[key] === plugin) {
                    found = true;
                    //match exact urls (e.g. git+ssh)
                    console.log(chalk.yellow('This version of ' + key + ' is already installed'));
                    process.exit();
                } else if (deps[key].substr(0,7) === 'git+ssh') {
                    depRef = deps[key].split('#');
                    depUri = depRef[0];
                    depRef = (depRef.length > 1) ? depRef[1] : null;

                    //check if same plugin giturl
                    if(depUri === plugin) {
                        found = true;
                        rollback = key;
                        //now compare refs
                        if((sDepRef = semver.valid(depRef)) &&
                           (sVersion = semver.valid(version))) {
                            if(semver.lt(sDepRef, sVersion)) {
                                //if current version is less than new version ask to upgrade
                                upgradeString = 'Do you want to upgrade from ' + deps[key] + ' to ' + version + '?';

                            } else if(semver.gt(sDepRef, sVersion)) {
                                //if current version is higher than new version ask to downgrade
                                upgradeString = 'Do you want to downgrade from ' + deps[key] + ' to ' + version + '?';

                            } else {
                                //if current version asked to upgrade
                                upgradeString = 'Do you want to upgrade from ' + deps[key] + ' to the latest version?';
                            }
                            wizz.addInput(upgradeString, ['y','n']);
                            wizz.on('end', rhb(dealWithIt, null, {name:plugin, version:version, rollback:rollback}, cb));
                            wizz.run();
                        } else {
                            //at least one of the gitrefs isn't semver
                            //so just ask to upgrade
                            upgradeString = 'Do you want to upgrade from ' + deps[key] + ' to the latest version?';
                            wizz.addInput(upgradeString, ['y','n']);
                            wizz.on('end', rhb(dealWithIt, null, {name:plugin, version:version, rollback:rollback}, cb));
                            wizz.run();
                        }
                    }
                }
            });

            if(!found) {
                installPlugin(plugin, version, null, cb);
            }
        }
    ]);

}

function dealWithIt(input, pkg, cb) {
    if(input[0] === 'y') {
        installPlugin(pkg.name, pkg.version, pkg.rollback, cb);
    } else {
        cb(null);
    }
}

function installPlugin(pkg, version, rollback, cb) {
    var installable = pkg;
    if(version) {
        if(pkg.substr(0,7) === 'git+ssh') {
            installable += '#' + version;
        } else {
            installable += '@' + version;
        }
    }
    var cmd = 'i -S ' + installable;
    console.log('Installing plugin...');
    npm(cmd, potterHome, function validateInstall(err, stdout) {
        //make sure install was success
        //console.log(stderr);
        // console.log(stdout);
        if(err) {
            console.log(chalk.red('NPM install failed!'));
            console.log('Please read the ' + path.join(potterHome, '/npm-debug.log'));
            process.exit();
        }
        console.log('Plugin installed');
        var installed = stdout.match(/^([a-z][-a-z0-9]*)@(\d+\.\d+.\d+ )/m)[1];
        try {
            console.log('Checking for conflicts...');
            var cmds = mergeCommands(path.join(__dirname,'../'), ['lib', 'cli-deprecated.js']);
            mergeCommands(path.join(potterHome,'node_modules'), ['.bin'], cmds);
        /*jshint -W002 */
        } catch (err) {
            console.log(chalk.red('Plugin had conflicts!'));
            console.log('Rolling back...');
            //rollback
            if(rollback) {
                return installPlugin(pkg, rollback, null, cb);
            } else {
                return remove({_:[installed]});
            }
        }

        console.log(chalk.green('Installed Plugin!'));
        process.exit();
    });
}

function npm(cmd, cwd, cb) {
    cmd = 'npm ' + cmd;
    childProcess.exec(cmd, {cwd:cwd}, cb);
}

function remove(opts, cb) {
    var plugin = opts._[0];
    if (!plugin) cb(new Error(chalk.red('You must provide a plugin to remove')));
    console.log(chalk.red('Removing ' + plugin));

    var cmd = 'rm -S ' + plugin;
    npm(cmd, potterHome, function npmRm(err, stdout, stderr) {
        if(err) throw err;

        //console.log(stdout);
        //console.log(stderr);

        if(stderr && stderr.indexOf('npm WARN uninstall not installed') !== -1) {
            return console.log('Plugin ' + plugin + ' was not installed');
        }
        console.log('Removed plugin ' + plugin);
    });
}

function list() {
    var cmd = 'ls | grep "^[└├]"';
    npm(cmd, potterHome, function npmList(err, stdout) {
        if(err) throw err;
        //console.log(stderr);
        var libs = stdout.split('\n');
        libs = libs.map(function(lib) {
            return lib.substr(4);
        }).filter(function(lib) {
            return lib;
        }).forEach(function(lib) {
            var line = chalk.green(' * ') + lib;
            console.log(line);
        });
    });
}

function rhb(fn, scope) {
    //right hand bind
    //call with function, this, arg1, arg2, etc
    var args = Array.prototype.slice.call(arguments).slice(2);
    return function() {
        args = Array.prototype.slice.call(arguments).concat(args);
        fn.apply(scope, args);
    };
}

function halp() {
    return printHelp(path.join(__dirname, 'usage-plugin.md'));
}

plugin.help = halp;

module.exports = plugin;
<|endoftext|>


<commit_before>var paused = 0;

angular.module("gameApp", [])

    .controller("appController", ["$scope", "keyPressHandlerService", function($scope, keyPressHandlerService) {
      window.onload = function() {
        cast.receiver.logger.setLevelValue(0);
        window.castReceiverManager = cast.receiver.CastReceiverManager.getInstance();
        console.log('Starting Receiver Manager');

        // handler for the 'ready' event
        castReceiverManager.onReady = function(event) {
          console.log('Received Ready event: ' + JSON.stringify(event.data));
          window.castReceiverManager.setApplicationState('Application status is ready...');
        };

        // handler for 'senderconnected' event
        castReceiverManager.onSenderConnected = function(event) {
          console.log('Received Sender Connected event: ' + event.data);
          console.log(window.castReceiverManager.getSender(event.data).userAgent);
        };

        // handler for 'senderdisconnected' event
        castReceiverManager.onSenderDisconnected = function(event) {
          console.log('Received Sender Disconnected event: ' + event.data);
          if (window.castReceiverManager.getSenders().length == 0) {
            window.close();
          }
        };

        // handler for 'systemvolumechanged' event
        castReceiverManager.onSystemVolumeChanged = function(event) {
          console.log('Received System Volume Changed event: ' + event.data['level'] + ' ' +
              event.data['muted']);
        };

        // create a CastMessageBus to handle messages for a custom namespace
        window.messageBus =
          window.castReceiverManager.getCastMessageBus(
              'urn:x-cast:com.google.cast.sample.helloworld');

        // handler for the CastMessageBus message event
        window.messageBus.onMessage = function(event) {
          console.log('Message [' + event.senderId + ']: ' + event.data);
          // display the message from the sender
          displayText(event.data);

          if(event.data == 80) {
            console.log("pause!");
            paused = 1;

          }
          keyPressHandlerService.keyPress(event.data);
          keyPressHandlerService.keyRelease(event.data);
          //keyPressHandlerService.keyPress == event.data;

          // inform all senders on the CastMessageBus of the incoming message event
          // sender message listener will be invoked
          window.messageBus.send(event.senderId, event.data);
        }

        // initialize the CastReceiverManager with an application status message
        window.castReceiverManager.start({statusText: 'Application is starting'});
        console.log('Receiver Manager started');
      };

      // utility function to display the text message in the input field
      function displayText(text) {
        console.log(text);
        document.getElementById('message').innerText = text;
        window.castReceiverManager.setApplicationState(text);
      };

      function triggerKeyDown() {
        var e = new KeyboardEvent('keydown', {'key': 'ArrowLeft', 'code': "ArrowLeft", 'keyCode': 38,'which':38});
        document.dispatchEvent(e);
          console.log(e);
      };

/*

        $scope.keydown = function(keyEvent) {
            if (!$scope.instructionsDisplayed) {
                $scope.instructionsDisplayed = true;
                return;
            }
            keyPressHandlerService.keyPress(keyEvent.key);
        };

        $scope.keyup = function(keyEvent) {
            keyPressHandlerService.keyRelease(keyEvent.key);
        };
*/
    }])

    .directive("centipedeGame", ["$interval", "gameService", "renderService", "graphicsEngineService", function($interval, gameService, renderService, graphicsEngineService) {
        return {
            restrict: 'A',
            template: '<canvas id="gameCanvas" width="600" height="640" style="border:1px solid #000000;"></canvas>',

            link: function(scope, element) {
                var intervalPromise;
                var animation = 0;
                var canvas = element.find('canvas')[0].getContext("2d");

                graphicsEngineService.initialise(canvas, 'App/img/graphics.png');
                gameService.initialise();

                function gameLoop() {

                    animation++;

                    if (animation == 4) {
                        animation = 0;
                    }

                   if(paused != 1) {
                      gameService.update(animation);
                      renderService.draw(animation);
                  }

                }

                intervalPromise = $interval(gameLoop, 50);

                scope.$on("$destroy", function() {
                    if (intervalPromise) {
                        $interval.cancel(intervalPromise);
                        intervalPromise = undefined;
                    }
                });
            }
        }
    }]);
<commit_msg>adding pause<commit_after>var paused = 0;

angular.module("gameApp", [])

    .controller("appController", ["$scope", "keyPressHandlerService", function($scope, keyPressHandlerService) {
      window.onload = function() {
        cast.receiver.logger.setLevelValue(0);
        window.castReceiverManager = cast.receiver.CastReceiverManager.getInstance();
        console.log('Starting Receiver Manager');

        // handler for the 'ready' event
        castReceiverManager.onReady = function(event) {
          console.log('Received Ready event: ' + JSON.stringify(event.data));
          window.castReceiverManager.setApplicationState('Application status is ready...');
        };

        // handler for 'senderconnected' event
        castReceiverManager.onSenderConnected = function(event) {
          console.log('Received Sender Connected event: ' + event.data);
          console.log(window.castReceiverManager.getSender(event.data).userAgent);
        };

        // handler for 'senderdisconnected' event
        castReceiverManager.onSenderDisconnected = function(event) {
          console.log('Received Sender Disconnected event: ' + event.data);
          if (window.castReceiverManager.getSenders().length == 0) {
            window.close();
          }
        };

        // handler for 'systemvolumechanged' event
        castReceiverManager.onSystemVolumeChanged = function(event) {
          console.log('Received System Volume Changed event: ' + event.data['level'] + ' ' +
              event.data['muted']);
        };

        // create a CastMessageBus to handle messages for a custom namespace
        window.messageBus =
          window.castReceiverManager.getCastMessageBus(
              'urn:x-cast:com.google.cast.sample.helloworld');

        // handler for the CastMessageBus message event
        window.messageBus.onMessage = function(event) {
          console.log('Message [' + event.senderId + ']: ' + event.data);
          // display the message from the sender
          displayText(event.data);

          if(event.data == 80) {
            if(paused == 1) {
              paused = 0;
              console.log ("play!")
            }
            else {
              console.log("pause!");
              paused = 1;
            }

          }

          keyPressHandlerService.keyPress(event.data);
          keyPressHandlerService.keyRelease(event.data);
          //keyPressHandlerService.keyPress == event.data;

          // inform all senders on the CastMessageBus of the incoming message event
          // sender message listener will be invoked
          window.messageBus.send(event.senderId, event.data);
        }

        // initialize the CastReceiverManager with an application status message
        window.castReceiverManager.start({statusText: 'Application is starting'});
        console.log('Receiver Manager started');
      };

      // utility function to display the text message in the input field
      function displayText(text) {
        console.log(text);
        document.getElementById('message').innerText = text;
        window.castReceiverManager.setApplicationState(text);
      };

      function triggerKeyDown() {
        var e = new KeyboardEvent('keydown', {'key': 'ArrowLeft', 'code': "ArrowLeft", 'keyCode': 38,'which':38});
        document.dispatchEvent(e);
          console.log(e);
      };

/*

        $scope.keydown = function(keyEvent) {
            if (!$scope.instructionsDisplayed) {
                $scope.instructionsDisplayed = true;
                return;
            }
            keyPressHandlerService.keyPress(keyEvent.key);
        };

        $scope.keyup = function(keyEvent) {
            keyPressHandlerService.keyRelease(keyEvent.key);
        };
*/
    }])

    .directive("centipedeGame", ["$interval", "gameService", "renderService", "graphicsEngineService", function($interval, gameService, renderService, graphicsEngineService) {
        return {
            restrict: 'A',
            template: '<canvas id="gameCanvas" width="600" height="640" style="border:1px solid #000000;"></canvas>',

            link: function(scope, element) {
                var intervalPromise;
                var animation = 0;
                var canvas = element.find('canvas')[0].getContext("2d");

                graphicsEngineService.initialise(canvas, 'App/img/graphics.png');
                gameService.initialise();

                function gameLoop() {

                    animation++;

                    if (animation == 4) {
                        animation = 0;
                    }

                   if(paused != 1) {
                      gameService.update(animation);
                      renderService.draw(animation);
                  }

                }

                intervalPromise = $interval(gameLoop, 50);

                scope.$on("$destroy", function() {
                    if (intervalPromise) {
                        $interval.cancel(intervalPromise);
                        intervalPromise = undefined;
                    }
                });
            }
        }
    }]);
<|endoftext|>


<commit_before>var config = require("./config"),
    fs = require("fs"),
    path = require("path"),
    archiver = require('archiver'),
    Stream = require('stream'),
    lazystream = require('lazystream');

// Note that only files and not directories are sent to the function
exports.pack = function(files, callback) {
  var out = fs.createWriteStream(config.bundle_file);
  // Use zlib compression 1 (fastest) to overcome a bug currently in Archiver on Macs
  zip = archiver('zip', {zlib: {level: 1}});
  zip.on('error', function(err) {
    throw err;
  });
  zip.pipe(out);

  for(var i = 0, ln = files.length; i < ln; i++) {
    var file = files[i],
        filename = config.tishadow_src + '/' + file,
        stream;

    // Lazy load streams, to counteract 'too many files' error on Node
    // Lazystream only creates the actual ReadStream when a read command is received
    stream = new lazystream.Readable(function (options) {
      return fs.createReadStream(this.filename);
    });
    stream.filename = filename;

    // Archiver takes care of the async nature of reading streams
    // Starting to read the next stream when the previous stream has closed
    // Thus it is save to append them all here
    zip.append(stream, {name : files[i]});
  }

  zip.finalize(function(err, written) {
    callback(err, written);
  });
};

<commit_msg>archiver call back should be on the writes stream and not finalise - fix for 0.10.0<commit_after>var config = require("./config"),
    fs = require("fs"),
    path = require("path"),
    archiver = require('archiver'),
    lazystream = require('lazystream');

// Note that only files and not directories are sent to the function
exports.pack = function(files, callback) {
  var out = fs.createWriteStream(config.bundle_file);
  out.on("close", callback);
  // Use zlib compression 1 (fastest) to overcome a bug currently in Archiver on Macs
  zip = archiver('zip', {zlib: {level: 1}});
  zip.on('error', function(err) {
    throw err;
  });
  zip.pipe(out);

  for(var i = 0, ln = files.length; i < ln; i++) {
    var file = files[i],
        filename = config.tishadow_src + '/' + file,
        stream;

    // Lazy load streams, to counteract 'too many files' error on Node
    // Lazystream only creates the actual ReadStream when a read command is received
    stream = new lazystream.Readable(function (options) {
      return fs.createReadStream(this.filename);
    });
    stream.filename = filename;

    zip.append(stream, {name : files[i]});
  }

  zip.finalize();
};

<|endoftext|>


<commit_before>;(function($) {
  $(function() {
    $('iframe.templated-page-view').each(function() {
      var $frame = $(this);
      var $doc = $frame.contents();
      var heightFn = function() { $frame.height($doc.find('html').height()); }
      $doc.load(heightFn);
      $doc.ready(heightFn);
    });
  });
})(jQuery);
<commit_msg>Using window's load event to hook our code to fix iframe height<commit_after>;(function($) {
  $(window).load(function() {
    $('iframe.templated-page-view').each(function() {
      var $frame = $(this);
      $frame.height($frame.contents().find('html').height());
    });
  });
})(jQuery);
<|endoftext|>


<commit_before>import 'whatwg-fetch';
import _ from 'underscore';

let helpers = {
  capitalize,
  checkStatus,
  displayPrice,
  displayPricePerUnit,
  findPopupTopValue,
  findTypeId,
  findTypeName,
  parseJSON,
  headers: {
    Accept: 'application/json',
    'Content-Type': 'application/json'
  }
};

function capitalize(string) {
  if (string) {
    return string.charAt(0).toUpperCase() + string.slice(1);
  }
}

function checkStatus(res) {
  if (res.status >= 200 && res.status < 300) {
    return res;
  }

  let error = new Error(res.statusText);
  error.res = res;
  throw error;
}

function displayPrice(price) {
  if (typeof price === 'string') {
    // eslint-disable-next-line no-param-reassign
    price = Number(price);
  }

  if (price % 1 === 0) {
    return `$${price}`;
  }

  return `$${price.toFixed(2)}`;
}

function displayPricePerUnit(price, unit) {
  if (unit) {
    return `${displayPrice(price)} / ${unit}`;
  }

  return `${displayPrice(price)} / `;
}

function findPopupTopValue(element) {
  return element.getBoundingClientRect().bottom + document.body.scrollTop + 8;
}

function findTypeId(types, name) {
  let type = _.findWhere(types, { name });
  return type && type.id;
}

function findTypeName(types, id) {
  let type = _.findWhere(types, { id });
  return type && type.name;
}

function parseJSON(res) {
  return res.json();
}

export default helpers;
<commit_msg>Add vendor helper methods<commit_after>import 'whatwg-fetch';
import _ from 'underscore';

let helpers = {
  capitalize,
  checkStatus,
  displayPrice,
  displayPricePerUnit,
  findPopupTopValue,
  findTypeId,
  findTypeName,
  findVendorId,
  findVendorCompany,
  parseJSON,
  headers: {
    Accept: 'application/json',
    'Content-Type': 'application/json'
  }
};

function capitalize(string) {
  if (string) {
    return string.charAt(0).toUpperCase() + string.slice(1);
  }
}

function checkStatus(res) {
  if (res.status >= 200 && res.status < 300) {
    return res;
  }

  let error = new Error(res.statusText);
  error.res = res;
  throw error;
}

function displayPrice(price) {
  if (typeof price === 'string') {
    // eslint-disable-next-line no-param-reassign
    price = Number(price);
  }

  if (price % 1 === 0) {
    return `$${price}`;
  }

  return `$${price.toFixed(2)}`;
}

function displayPricePerUnit(price, unit) {
  if (unit) {
    return `${displayPrice(price)} / ${unit}`;
  }

  return `${displayPrice(price)} / `;
}

function findPopupTopValue(element) {
  return element.getBoundingClientRect().bottom + document.body.scrollTop + 8;
}

function findTypeId(types, name) {
  let type = _.findWhere(types, { name });
  return type && type.id;
}

function findTypeName(types, id) {
  let type = _.findWhere(types, { id });
  return type && type.name;
}

function findVendorId(vendors, company) {
  let vendor = _.findWhere(vendors, { company });
  return vendor && vendor.id;
}

function findVendorCompany(vendors, id) {
  let vendor = _.findWhere(vendors, { id });
  return vendor && vendor.company;
}

function parseJSON(res) {
  return res.json();
}

export default helpers;
<|endoftext|>


<commit_before>/*
 * This file is part of Report Portal.
 *
 * Report Portal is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Report Portal is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with Report Portal.  If not, see <http://www.gnu.org/licenses/>.
 */
define(function (require, exports, module) {
    'use strict';

    var Util = require('util');
    var $ = require('jquery');
    var Backbone = require('backbone');
    var Epoxy = require('backbone-epoxy');
    var App = require('app');
    var ModalEditDashboard = require('modals/modalEditDashboard');
    var ModalConfirm = require('modals/modalConfirm');
    var ModalAddWidget = require('modals/addWidget/modalAddWidget');
    var modalAddSharedWidget = require('modals/addSharedWidget/modalAddSharedWidget');
    var Localization = require('localization');
    var GadgetCollection = require('dashboard/GadgetCollection');
    var GadgetView = require('dashboard/GadgetView');
    var GadgetModel = require('dashboard/GadgetModel');
    var WidgetModel = require('newWidgets/WidgetModel');
    var WidgetConfig = require('widget/widgetsConfig');
    var SingletonLaunchFilterCollection = require('filters/SingletonLaunchFilterCollection');

    require('gridstackUi');
    require('fullscreen');
    var config = App.getInstance();
    var launchFilterCollection = new SingletonLaunchFilterCollection();

    var DashboardItemView = Epoxy.View.extend({
        className: 'dashboard-item-view',
        template: 'tpl-dashboard-item',

        events: {
            'click [data-js-edit]': 'onClickEdit',
            'click [data-js-remove]': 'onClickRemove',
            'click [data-js-full-screen]': 'onClickFullScreen',
            'click [data-js-close-fullscreen]': 'onClickExitFullScreen',
            'click [data-js-add-widget]': 'onClickAddWidget',
            'click [data-js-add-widget-bootm]': 'onClickWidgetBottom',
            'click [data-js-add-shared-widget]': 'onClickAddSharedWidget',
        },

        bindings: {
            ':el': 'classes: {"not-my": not(isMy)}',
            '[data-js-owner-name]': 'text: owner',
            '[data-js-add-widget]': 'classes: {disabled: not(validateForAddWidget)}, attr: {title: getAddBtnTitle}',
            '[data-js-add-shared-widget]': 'classes: {disabled: not(validateForAddWidget)}, attr: {title: getAddBtnTitle}'
        },

        computeds: {
            validateForAddWidget: {
                deps: ['widgets'],
                get: function(widgets) {
                    widgets = this.model.getWidgets();
                    return widgets.length < config.maxWidgetsOnDashboard;
                }
            },
            getAddBtnTitle: {
                deps: ['widgets'],
                get: function(widgets){
                    widgets = this.model.getWidgets();
                    return widgets.length >= config.maxWidgetsOnDashboard ? Localization.dashboard.maxWidgetsAdded : '';
                }
            }
        },

        initialize: function(options) {
            this.gadgetViews = [];
            this.scrollElement = config.mainScrollElement;
            this.onShowAsync = $.Deferred();
            this.render();
            var self = this;
            if(this.model.get('notLoad')) {
                this.$el.addClass('load');
                this.model.update().done(function() {
                    self.$el.removeClass('load');
                    self.postInit();
                    self.applyBindings();
                })
            } else {
                this.postInit();
            }
        },
        postInit: function() {
            var self = this;
            WidgetConfig.updateInstance().done(function() {
                self.gadgetCollection = new GadgetCollection([], {dashboardModel: self.model});
                self.listenTo(self.gadgetCollection, 'add', self.onAddGadget);
                self.listenTo(self.gadgetCollection, 'remove:view', self.onRemoveGadget);
                self.listenTo(self.gadgetCollection, 'remove', self.checkEmptyDashboard);
                self.activateGridStack();
                self.listenTo(self.model, 'add:widget', self.onAddNewGadget);
                self.listenTo(self.model, 'change:isShared', self.onShareDashboard);
            });

        },
        render: function() {
            this.$el.html(Util.templates(this.template, {}));
        },
        onAddNewGadget: function(model) {
            this.checkEmptyDashboard();
            this.gadgetCollection.add(model);
            this.updateScroll();
        },
        onShareDashboard: function(){
            if(this.model.get('isShared')){
                _.each(this.gadgetViews, function(view){
                    view.model.set('isShared', true);
                }, this);
            }
        },
        activateGridStack: function() {
            var $gridStack = $('[data-js-grid-stack]', this.$el);
            $gridStack.gridstack({
                cellHeight: config.widgetGridCellHeight,
                verticalMargin: config.widgetGridVerticalMargin,
                draggable: {
                    handle: '[data-js-drag-handle]'
                },
                resizable: {
                    handles: 'se, sw'
                },
                disableDrag: !this.model.get('isMy'),
                disableResize: !this.model.get('isMy'),
            });
            this.gridStack = $gridStack.data('gridstack');
            this.createGadgets();
            var self = this;
            $gridStack.on('change', function (e, items) {
                _.each(items, function(item) {
                    var id = item.el.data('id');
                    if(!id) return;
                    var gadgetModel = self.gadgetCollection.get(id);
                    if(!gadgetModel) return;
                    gadgetModel.set({
                        x: item.x,
                        y: item.y,
                        width: item.width,
                        height: item.height,
                    });
                });
                self.gadgetCollection.sort();
                self.updateScroll();
            });
            $gridStack.on('dragstop', function(event, ui) {
                config.trackingDispatcher.trackEventNumber(285);
            });
            $gridStack.on('resizestart', function (event, ui) {
                var view = event.target.backboneView;
                view && view.startResize();
                config.trackingDispatcher.trackEventNumber(289);
            });
            $gridStack.on('resizestop', function (event, ui) {
                var view = event.target.backboneView;
                setTimeout(function(){
                    view && view.stopResize();
                }, 300);
            });

        },
        onClickFullScreen: function(e) {
            e.preventDefault();
            config.trackingDispatcher.trackEventNumber(283);
            $('body').fullscreen({toggleClass: 'fullscreen'});
            this.updateGadgetsTimer();
        },
        onAddGadget: function(gadgetModel) {
            if(gadgetModel.get('isShared')) {
                launchFilterCollection.ready.done(function() {
                    launchFilterCollection.update();
                })
            }
            var view = new GadgetView({model: gadgetModel, dashboardModel: this.model});
            this.gridStack.addWidget.apply(this.gridStack, view.getDataForGridStack());
            this.gadgetViews.push(view);
        },
        onRemoveGadget: function(view) {
            this.gridStack.removeWidget(view.el);
        },
        checkEmptyDashboard: function() {
            if(!this.model.getWidgets().length) {
                this.$el.addClass('not-found');
            } else {
                this.$el.removeClass('not-found');
            }
        },
        createGadgets: function() {
            this.checkEmptyDashboard();
            this.gadgetCollection.add(this.model.getWidgets(), {silent: true, parse: true});
            this.gadgetCollection.forEach(function(model){
                this.onAddGadget(model);
            }, this);
            this.updateScroll();
            var self = this;
            this.$el.on('resize', function(){
                self.scrollerAnimate.resize();
            });
        },
        updateScroll: function() {
            var self = this;
            this.onShowAsync.done(function() {
                self.scrollerAnimate = new ScrollerAnimate(self.gadgetViews);
                self.scrollElement
                    .off('scroll.dashboardPage')
                    .on("scroll.dashboardPage", function (e) {
                        self.onScroll();
                    });
                self.onScroll();
            })
        },
        onShow: function() {
            this.onShowAsync.resolve();
        },
        onScroll: function() {
            var scrollTop = this.scrollElement.scrollTop();
            this.scrollerAnimate.activateScroll(scrollTop);
        },
        onClickEdit: function(e) {
            e.preventDefault();
            e.stopPropagation();
            config.trackingDispatcher.trackEventNumber(282);
            var self = this;
            (new ModalEditDashboard({
                dashboardCollection: this.model.collection,
                dashboardModel: this.model,
                mode: 'edit',
            })).show().done(function(newModel) {
                self.model.set(newModel.toJSON());
            })
        },
        onClickRemove: function(e) {
            e.preventDefault();
            e.stopPropagation();
            config.trackingDispatcher.trackEventNumber(284);
            var self = this;
            var modal = new ModalConfirm({
                headerText: Localization.dialogHeader.dashboardDelete,
                bodyText: Util.replaceTemplate(Localization.dialog.dashboardDelete, this.model.get('name')),
                okButtonDanger: true,
                cancelButtonText: Localization.ui.cancel,
                okButtonText: Localization.ui.delete,
            });
            modal.show()
                .done(function() {
                    var collection = self.model.collection;
                    self.model.collection.remove(self.model);
                    self.destroy();
                    collection.resetActive();
                });
            modal.$el.on('click', function(e){
                var $target = $(e.target),
                    isCancel = $target.is('[data-js-cancel]'),
                    isDelete = $target.is('[data-js-ok]'),
                    isClose = ($target.is('[data-js-close]') || $target.is('[data-js-close] i'));
                if(isClose){
                    config.trackingDispatcher.trackEventNumber(276);
                }
                else if(isCancel){
                    config.trackingDispatcher.trackEventNumber(277);
                }
                else if(isDelete){
                    config.trackingDispatcher.trackEventNumber(278);
                }
            });
        },
        onClickExitFullScreen: function(e) {
            clearTimeout(this.updateTimer);
            e.preventDefault();
            e.stopPropagation();
            $.fullscreen.exit();
        },
        updateGadgetsTimer: function() {
            clearTimeout(this.updateTimer);
            var self = this;
            this.updateTimer = setTimeout(function() {
                _.each(self.gadgetCollection.models, function(gadgetModel) {
                    gadgetModel.trigger('update:timer');
                });
                self.updateGadgetsTimer();
            }, 60000);
        },
        onClickAddWidget: function(e) {
            e.preventDefault();
            e.stopPropagation();
            config.trackingDispatcher.trackEventNumber(280);
            (new ModalAddWidget({model: new GadgetModel(), dashboardModel: this.model})).show();
        },
        onClickWidgetBottom: function(e){
            e.preventDefault();
            e.stopPropagation();
            config.trackingDispatcher.trackEventNumber(345);
            (new ModalAddWidget({model: new GadgetModel(), dashboardModel: this.model})).show();
        },
        onClickAddSharedWidget: function(e) {
            e.preventDefault();
            e.stopPropagation();
            config.trackingDispatcher.trackEventNumber(281);
            (new modalAddSharedWidget({model: new GadgetModel(), dashboardModel: this.model})).show();
        },
        destroy: function () {
            clearTimeout(this.updateTimer);
            $.fullscreen.exit();
            _.each(this.gadgetViews, function(view) {
               view.destroy();
            });
            this.undelegateEvents();
            this.gridStack && this.gridStack.destroy();
            this.$el.off('resize');
            this.scrollElement.off('scroll.dashboardPage');
            this.stopListening();
            this.unbind();
            this.$el.remove();
        },
    });

    function ScrollerAnimate(blocks){
        this.blocks = blocks;
        this.scrollMap = [];
        this.documentHeight = 0;

        this._createScrollMap = function(){
            this.scrollMap = [];
            this.documentHeight = document.documentElement.clientHeight;
            for(var i = 0; i < this.blocks.length; i++){
                this.scrollMap.push({
                    scrollStart: this.blocks[i].el.offsetTop,
                    scrollEnd: this.blocks[i].el.offsetTop + this.blocks[i].el.offsetHeight
                });
            }
        };

        this.activateScroll = function(scrollTop){
            var scrollBottom = scrollTop + this.documentHeight;
            var showBlockIndexs = [];
            for(var i = 0; i < this.scrollMap.length; i++){
                if((this.scrollMap[i].scrollStart <= scrollBottom && scrollTop < this.scrollMap[i].scrollStart)
                    || (this.scrollMap[i].scrollEnd <= scrollBottom && scrollTop < this.scrollMap[i].scrollEnd)
                    || (this.scrollMap[i].scrollEnd > scrollBottom && scrollTop >= this.scrollMap[i].scrollStart)){
                    showBlockIndexs.push(i);
                    if(!this.blocks[i].activate){
                        this.blocks[i].activate = true;
                        this.blocks[i].activateGadget();
                    }
                }
            }
            // return middle block index
            if(showBlockIndexs.length != 2) return showBlockIndexs[parseInt(showBlockIndexs.length/2)];
            var middleScreen = scrollBottom - this.documentHeight/2,
                blockSeparate = this.scrollMap[showBlockIndexs[0]].scrollEnd;
            if(blockSeparate > middleScreen) return showBlockIndexs[0];
            return showBlockIndexs[1];
        };

        this.resize = function(){
            this._createScrollMap();
            this.activateScroll(config.mainScrollElement.scrollTop());
        }

        this._createScrollMap();
    }

    return DashboardItemView;
});
<commit_msg>add auto refresh on all widgets<commit_after>/*
 * This file is part of Report Portal.
 *
 * Report Portal is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Report Portal is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with Report Portal.  If not, see <http://www.gnu.org/licenses/>.
 */
define(function (require, exports, module) {
    'use strict';

    var Util = require('util');
    var $ = require('jquery');
    var Backbone = require('backbone');
    var Epoxy = require('backbone-epoxy');
    var App = require('app');
    var ModalEditDashboard = require('modals/modalEditDashboard');
    var ModalConfirm = require('modals/modalConfirm');
    var ModalAddWidget = require('modals/addWidget/modalAddWidget');
    var modalAddSharedWidget = require('modals/addSharedWidget/modalAddSharedWidget');
    var Localization = require('localization');
    var GadgetCollection = require('dashboard/GadgetCollection');
    var GadgetView = require('dashboard/GadgetView');
    var GadgetModel = require('dashboard/GadgetModel');
    var WidgetModel = require('newWidgets/WidgetModel');
    var WidgetConfig = require('widget/widgetsConfig');
    var SingletonLaunchFilterCollection = require('filters/SingletonLaunchFilterCollection');

    require('gridstackUi');
    require('fullscreen');
    var config = App.getInstance();
    var launchFilterCollection = new SingletonLaunchFilterCollection();

    var TIME_UPDATE = 30000;
    var TIME_UPDATE_FULL_SCREEN = 60000;

    var DashboardItemView = Epoxy.View.extend({
        className: 'dashboard-item-view',
        template: 'tpl-dashboard-item',

        events: {
            'click [data-js-edit]': 'onClickEdit',
            'click [data-js-remove]': 'onClickRemove',
            'click [data-js-full-screen]': 'onClickFullScreen',
            'click [data-js-close-fullscreen]': 'onClickExitFullScreen',
            'click [data-js-add-widget]': 'onClickAddWidget',
            'click [data-js-add-widget-bootm]': 'onClickWidgetBottom',
            'click [data-js-add-shared-widget]': 'onClickAddSharedWidget',
        },

        bindings: {
            ':el': 'classes: {"not-my": not(isMy)}',
            '[data-js-owner-name]': 'text: owner',
            '[data-js-add-widget]': 'classes: {disabled: not(validateForAddWidget)}, attr: {title: getAddBtnTitle}',
            '[data-js-add-shared-widget]': 'classes: {disabled: not(validateForAddWidget)}, attr: {title: getAddBtnTitle}'
        },

        computeds: {
            validateForAddWidget: {
                deps: ['widgets'],
                get: function(widgets) {
                    widgets = this.model.getWidgets();
                    return widgets.length < config.maxWidgetsOnDashboard;
                }
            },
            getAddBtnTitle: {
                deps: ['widgets'],
                get: function(widgets){
                    widgets = this.model.getWidgets();
                    return widgets.length >= config.maxWidgetsOnDashboard ? Localization.dashboard.maxWidgetsAdded : '';
                }
            }
        },

        initialize: function(options) {
            this.gadgetViews = [];
            this.scrollElement = config.mainScrollElement;
            this.onShowAsync = $.Deferred();
            this.render();
            var self = this;
            if(this.model.get('notLoad')) {
                this.$el.addClass('load');
                this.model.update().done(function() {
                    self.$el.removeClass('load');
                    self.postInit();
                    self.applyBindings();
                })
            } else {
                this.postInit();
            }
        },
        postInit: function() {
            var self = this;
            WidgetConfig.updateInstance().done(function() {
                self.gadgetCollection = new GadgetCollection([], {dashboardModel: self.model});
                self.listenTo(self.gadgetCollection, 'add', self.onAddGadget);
                self.listenTo(self.gadgetCollection, 'remove:view', self.onRemoveGadget);
                self.listenTo(self.gadgetCollection, 'remove', self.checkEmptyDashboard);
                self.activateGridStack();
                self.listenTo(self.model, 'add:widget', self.onAddNewGadget);
                self.listenTo(self.model, 'change:isShared', self.onShareDashboard);
                self.updateGadgetsTimer(TIME_UPDATE);
            });

        },
        render: function() {
            this.$el.html(Util.templates(this.template, {}));
        },
        onAddNewGadget: function(model) {
            this.checkEmptyDashboard();
            this.gadgetCollection.add(model);
            this.updateScroll();
        },
        onShareDashboard: function(){
            if(this.model.get('isShared')){
                _.each(this.gadgetViews, function(view){
                    view.model.set('isShared', true);
                }, this);
            }
        },
        activateGridStack: function() {
            var $gridStack = $('[data-js-grid-stack]', this.$el);
            $gridStack.gridstack({
                cellHeight: config.widgetGridCellHeight,
                verticalMargin: config.widgetGridVerticalMargin,
                draggable: {
                    handle: '[data-js-drag-handle]'
                },
                resizable: {
                    handles: 'se, sw'
                },
                disableDrag: !this.model.get('isMy'),
                disableResize: !this.model.get('isMy'),
            });
            this.gridStack = $gridStack.data('gridstack');
            this.createGadgets();
            var self = this;
            $gridStack.on('change', function (e, items) {
                _.each(items, function(item) {
                    var id = item.el.data('id');
                    if(!id) return;
                    var gadgetModel = self.gadgetCollection.get(id);
                    if(!gadgetModel) return;
                    gadgetModel.set({
                        x: item.x,
                        y: item.y,
                        width: item.width,
                        height: item.height,
                    });
                });
                self.gadgetCollection.sort();
                self.updateScroll();
            });
            $gridStack.on('dragstop', function(event, ui) {
                config.trackingDispatcher.trackEventNumber(285);
            });
            $gridStack.on('resizestart', function (event, ui) {
                var view = event.target.backboneView;
                view && view.startResize();
                config.trackingDispatcher.trackEventNumber(289);
            });
            $gridStack.on('resizestop', function (event, ui) {
                var view = event.target.backboneView;
                setTimeout(function(){
                    view && view.stopResize();
                }, 300);
            });

        },
        onClickFullScreen: function(e) {
            e.preventDefault();
            config.trackingDispatcher.trackEventNumber(283);
            $('body').fullscreen({toggleClass: 'fullscreen'});
            this.updateGadgetsTimer(TIME_UPDATE_FULL_SCREEN);
        },
        onAddGadget: function(gadgetModel) {
            if(gadgetModel.get('isShared')) {
                launchFilterCollection.ready.done(function() {
                    launchFilterCollection.update();
                })
            }
            var view = new GadgetView({model: gadgetModel, dashboardModel: this.model});
            this.gridStack.addWidget.apply(this.gridStack, view.getDataForGridStack());
            this.gadgetViews.push(view);
        },
        onRemoveGadget: function(view) {
            this.gridStack.removeWidget(view.el);
        },
        checkEmptyDashboard: function() {
            if(!this.model.getWidgets().length) {
                this.$el.addClass('not-found');
            } else {
                this.$el.removeClass('not-found');
            }
        },
        createGadgets: function() {
            this.checkEmptyDashboard();
            this.gadgetCollection.add(this.model.getWidgets(), {silent: true, parse: true});
            this.gadgetCollection.forEach(function(model){
                this.onAddGadget(model);
            }, this);
            this.updateScroll();
            var self = this;
            this.$el.on('resize', function(){
                self.scrollerAnimate.resize();
            });
        },
        updateScroll: function() {
            var self = this;
            this.onShowAsync.done(function() {
                self.scrollerAnimate = new ScrollerAnimate(self.gadgetViews);
                self.scrollElement
                    .off('scroll.dashboardPage')
                    .on("scroll.dashboardPage", function (e) {
                        self.onScroll();
                    });
                self.onScroll();
            })
        },
        onShow: function() {
            this.onShowAsync.resolve();
        },
        onScroll: function() {
            var scrollTop = this.scrollElement.scrollTop();
            this.scrollerAnimate.activateScroll(scrollTop);
        },
        onClickEdit: function(e) {
            e.preventDefault();
            e.stopPropagation();
            config.trackingDispatcher.trackEventNumber(282);
            var self = this;
            (new ModalEditDashboard({
                dashboardCollection: this.model.collection,
                dashboardModel: this.model,
                mode: 'edit',
            })).show().done(function(newModel) {
                self.model.set(newModel.toJSON());
            })
        },
        onClickRemove: function(e) {
            e.preventDefault();
            e.stopPropagation();
            config.trackingDispatcher.trackEventNumber(284);
            var self = this;
            var modal = new ModalConfirm({
                headerText: Localization.dialogHeader.dashboardDelete,
                bodyText: Util.replaceTemplate(Localization.dialog.dashboardDelete, this.model.get('name')),
                okButtonDanger: true,
                cancelButtonText: Localization.ui.cancel,
                okButtonText: Localization.ui.delete,
            });
            modal.show()
                .done(function() {
                    var collection = self.model.collection;
                    self.model.collection.remove(self.model);
                    self.destroy();
                    collection.resetActive();
                });
            modal.$el.on('click', function(e){
                var $target = $(e.target),
                    isCancel = $target.is('[data-js-cancel]'),
                    isDelete = $target.is('[data-js-ok]'),
                    isClose = ($target.is('[data-js-close]') || $target.is('[data-js-close] i'));
                if(isClose){
                    config.trackingDispatcher.trackEventNumber(276);
                }
                else if(isCancel){
                    config.trackingDispatcher.trackEventNumber(277);
                }
                else if(isDelete){
                    config.trackingDispatcher.trackEventNumber(278);
                }
            });
        },
        onClickExitFullScreen: function(e) {
            this.updateGadgetsTimer(TIME_UPDATE);
            e.preventDefault();
            e.stopPropagation();
            $.fullscreen.exit();
        },
        updateGadgetsTimer: function(time) {
            clearTimeout(this.updateTimer);
            var self = this;
            this.updateTimer = setTimeout(function() {
                _.each(self.gadgetCollection.models, function(gadgetModel) {
                    gadgetModel.trigger('update:timer');
                });
                self.updateGadgetsTimer(time);
            }, time);
        },
        onClickAddWidget: function(e) {
            e.preventDefault();
            e.stopPropagation();
            config.trackingDispatcher.trackEventNumber(280);
            (new ModalAddWidget({model: new GadgetModel(), dashboardModel: this.model})).show();
        },
        onClickWidgetBottom: function(e){
            e.preventDefault();
            e.stopPropagation();
            config.trackingDispatcher.trackEventNumber(345);
            (new ModalAddWidget({model: new GadgetModel(), dashboardModel: this.model})).show();
        },
        onClickAddSharedWidget: function(e) {
            e.preventDefault();
            e.stopPropagation();
            config.trackingDispatcher.trackEventNumber(281);
            (new modalAddSharedWidget({model: new GadgetModel(), dashboardModel: this.model})).show();
        },
        destroy: function () {
            clearTimeout(this.updateTimer);
            $.fullscreen.exit();
            _.each(this.gadgetViews, function(view) {
               view.destroy();
            });
            this.undelegateEvents();
            this.gridStack && this.gridStack.destroy();
            this.$el.off('resize');
            this.scrollElement.off('scroll.dashboardPage');
            this.stopListening();
            this.unbind();
            this.$el.remove();
        },
    });

    function ScrollerAnimate(blocks){
        this.blocks = blocks;
        this.scrollMap = [];
        this.documentHeight = 0;

        this._createScrollMap = function(){
            this.scrollMap = [];
            this.documentHeight = document.documentElement.clientHeight;
            for(var i = 0; i < this.blocks.length; i++){
                this.scrollMap.push({
                    scrollStart: this.blocks[i].el.offsetTop,
                    scrollEnd: this.blocks[i].el.offsetTop + this.blocks[i].el.offsetHeight
                });
            }
        };

        this.activateScroll = function(scrollTop){
            var scrollBottom = scrollTop + this.documentHeight;
            var showBlockIndexs = [];
            for(var i = 0; i < this.scrollMap.length; i++){
                if((this.scrollMap[i].scrollStart <= scrollBottom && scrollTop < this.scrollMap[i].scrollStart)
                    || (this.scrollMap[i].scrollEnd <= scrollBottom && scrollTop < this.scrollMap[i].scrollEnd)
                    || (this.scrollMap[i].scrollEnd > scrollBottom && scrollTop >= this.scrollMap[i].scrollStart)){
                    showBlockIndexs.push(i);
                    if(!this.blocks[i].activate){
                        this.blocks[i].activate = true;
                        this.blocks[i].activateGadget();
                    }
                }
            }
            // return middle block index
            if(showBlockIndexs.length != 2) return showBlockIndexs[parseInt(showBlockIndexs.length/2)];
            var middleScreen = scrollBottom - this.documentHeight/2,
                blockSeparate = this.scrollMap[showBlockIndexs[0]].scrollEnd;
            if(blockSeparate > middleScreen) return showBlockIndexs[0];
            return showBlockIndexs[1];
        };

        this.resize = function(){
            this._createScrollMap();
            this.activateScroll(config.mainScrollElement.scrollTop());
        }

        this._createScrollMap();
    }

    return DashboardItemView;
});
<|endoftext|>


<commit_before>/**
 * Created by IvanP on 13.12.2016.
 */

export default class MediaQuery{
  /**
   * `MediaQuery` helps perform actions when CSS query is matched instead of polling the window width, when it's not so important, just matching the query is important
   * @param {Object} options
   * @param {Object} options.query - The CSS media query to evaluate.
   * @param {Boolean} options.full - If true, the query attribute is assumed to be a complete media query string rather than a single media feature.
   * @param {Function} callback - function to execute when matching is evaluated
   * @param {Object|Function} context - context in which the `callback` function needs to be executed
   * */
  constructor(options,callback,context=this){
    let {query,full=false} = options;
    this.queryMatches = false;
    this.full = full;
    this._mq = null;
    this._callback = callback;
    this._context = context;
    this.query=query;
  }

  _onMatch(mq){
    this.queryMatches = mq.matches;
    return this._callback.call(this._context,mq.matches)
  }

  get query(){
    return this._query;
  }

  set query(val){
    this._query = val;
    this._remove();
    let query = this.query;
    if (!query) {
      return;
    }
    if (!this.full && query[0] !== '(') {
      query = '(' + query + ')';
    }
    this._mq = window.matchMedia(query);
    this.queryMatches = this._mq.matches;
    this._add();
  }

  _add(){
    if (this._mq) {
      this._mq.addListener(this._onMatch.bind(this));
    }
  }

  _remove() {
    if (this._mq) {
      this._mq.removeListener(this._onMatch);
    }
    this._mq = null;
  }
}
<commit_msg>fixed bug<commit_after>/**
 * Created by IvanP on 13.12.2016.
 */

export default class MediaQuery{
  /**
   * `MediaQuery` helps perform actions when CSS query is matched instead of polling the window width, when it's not so important, just matching the query is important
   * @param {Object} options
   * @param {Object} options.query - The CSS media query to evaluate.
   * @param {Boolean} options.full - If true, the query attribute is assumed to be a complete media query string rather than a single media feature.
   * @param {Function} callback - function to execute when matching is evaluated
   * @param {Object|Function} context - context in which the `callback` function needs to be executed
   * */
  constructor(options,callback,context=this){
    let {query,full=false} = options;
    this.queryMatches = false;
    this.full = full;
    this._mq = null;
    this._callback = callback;
    this._context = context;
    this._bound = this._onMatch.bind(this);
    this.query=query;
  }

  _onMatch(mq){
    this.queryMatches = mq.matches;
    return this._callback.call(this._context,mq.matches)
  }

  get query(){
    return this._query;
  }

  set query(val){
    this._query = val;
    this._remove();
    let query = this.query;
    if (!query) {
      return;
    }
    if (!this.full && query[0] !== '(') {
      query = '(' + query + ')';
    }
    this._mq = window.matchMedia(query);
    this.queryMatches = this._mq.matches;
    this._add();
  }

  _add(){
    if (this._mq) {
      this._mq.addListener(this._bound);
    }
  }

  _remove() {
    if (this._mq) {
      this._mq.removeListener(this._bound);
    }
    this._mq = null;
  }
}
<|endoftext|>


<commit_before>
require("../shim-array");
var SortedSet = require("../sorted-set");
var TreeLog = require("../tree-log");
var describeDeque = require("./deque");
var describeCollection = require("./collection");
var describeSet = require("./set");
var Fuzz = require("./fuzz");

describe("SortedSet", function () {

    function newSortedSet(values) {
        return new SortedSet(values);
    }

    newSortedSet.prototype.isSorted = true;

    [SortedSet, newSortedSet].forEach(function (SortedSet) {

        // TODO SortedSet compare and equals argument overrides

        // construction, has, add, get, delete
        describeCollection(SortedSet, [1, 2, 3, 4], true);

        // comparable objects
        function Value(value) {
            this.value = value;
        }
        Value.prototype.compare = function (that) {
            return Object.compare(this.value, that.value);
        }
        var a = new Value(1);
        var b = new Value(2);
        var c = new Value(3);
        var d = new Value(4);
        var values = [a, b, c, d];
        describeCollection(SortedSet, values, true);

        // Happens to qualify as a deque, since the tests keep the content in
        // sorted order.  SortedSet has meaningful pop and shift operations, but
        // push and unshift just add the arguments into their proper sorted
        // positions rather than the ends.
        describeDeque(SortedSet);

        describeSet(SortedSet, "sorted");

    });

    describe("splay", function () {

        function draw(set) {
            var lines = [];
            set.log(TreeLog.ascii, null, lines.push, lines);
            return lines;
        }

        it("should degenerate for sorted values", function () {
            var set = SortedSet([1, 2, 3]);
            expect(draw(set)).toEqual([
                "  .-- 1",
                ".-+ 2",
                "+ 3"
            ]);
        });

        it("should splay middle value", function () {
            var set = SortedSet([1, 2, 3]);
            set.get(2);
            expect(draw(set)).toEqual([
                ".-- 1",
                "+ 2",
                "'-- 3"
            ]);
        });

        it("should splay middle value", function () {
            var set = SortedSet([1, 2, 3]);
            set.get(2);
            set.delete(1);
            expect(draw(set)).toEqual([
                "+ 2",
                "'-- 3"
            ]);
        });

    });

    describe("subtree lengths", function () {

        function draw(set) {
            var lines = [];
            set.log(TreeLog.ascii, function (node, write, writeAbove) {
                write(" " + node.value + " length=" + node.length);
            }, lines.push, lines);
            return lines;
        }

        function expectNodeToHaveCorrectSubtreeLengths(node) {
            if (!node)
                return 0;
            var length = 1;
            length += expectNodeToHaveCorrectSubtreeLengths(node.left);
            length += expectNodeToHaveCorrectSubtreeLengths(node.right);
            expect(node.length).toBe(length);
            return length;
        }

        it("+1", function () {
            var set = SortedSet([1]);
            expect(draw(set)).toEqual([
                "- 1 length=1"
            ]);
            expectNodeToHaveCorrectSubtreeLengths(set.root);
        });

        it("+1, +2", function () {
            var set = SortedSet([1, 2]);
            expect(draw(set)).toEqual([
                ".-- 1 length=1",
                "+ 2 length=2"
            ]);
            expectNodeToHaveCorrectSubtreeLengths(set.root);
        });

        it("+1, +2, 1", function () {
            var set = SortedSet([1, 2]);
            set.get(1);
            expect(draw(set)).toEqual([
                "+ 1 length=2",
                "'-- 2 length=1"
            ]);
            expectNodeToHaveCorrectSubtreeLengths(set.root);
        });

        it("+1, +3, +2", function () {
            var set = SortedSet([1, 3, 2]);
            expect(draw(set)).toEqual([
                ".-- 1 length=1",
                "+ 2 length=3",
                "'-- 3 length=1"
            ]);
            expectNodeToHaveCorrectSubtreeLengths(set.root);
        });

        function makeCase(description, operations, log) {
            it(description + " " + operations, function () {
                var set = SortedSet();
                Fuzz.execute(set, Fuzz.parse(operations), log);
                expectNodeToHaveCorrectSubtreeLengths(set.root);
            });
        }

        makeCase("reduction of case with propagation issue", "+2, +4, +3, +1, 4");

        // 50 fuzz cases
        for (var i = 0; i < 50; i++) {
            (function () {
                var fuzz = Fuzz.make(i * 5, i, Math.max(10, i * 5));
                makeCase("fuzz", Fuzz.stringify(fuzz));
            })();
        }

    });

    describe("splayIndex", function () {
        it("should find the index of every element", function () {
            var numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
            var rand = Fuzz.makeRandom(0);
            numbers.sort(function () {
                return rand() - .5;
            });
            var set = SortedSet(numbers);
            numbers.forEach(function (index) {
                set.splayIndex(index);
                expect(set.root.index).toBe(index);
                expect(set.root.value).toBe(index);
            });
        });
    });

    describe("indexOf", function () {
        // fuzz cases
        for (var seed = 0; seed < 20; seed++) {
            (function (seed) {
                var numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
                var rand = Fuzz.makeRandom(seed);
                numbers.sort(function () {
                    return rand() - .5;
                });
                it("should discern the position of every value in " + numbers.join(", "), function () {
                    var set = SortedSet(numbers);
                    numbers.forEach(function (n, i) {
                        expect(set.indexOf(n)).toBe(n);
                    });
                });
            })(seed);
        }
    });

    describe("observeRangeChange", function () {
        // fuzz cases
        for (var seed = 0; seed < 20; seed++) {
            (function (seed) {
                var numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
                var rand = Fuzz.makeRandom(seed);
                numbers.sort(function () {
                    return rand() - .5;
                });
                it("should bind content changes to an array for " + numbers.join(", "), function () {
                    var mirror = [];
                    var set = SortedSet();
                    set.observeRangeChange(function (plus, minus, index) {
                        mirror.swap(index, minus.length, plus);
                    });
                    set.addEach(numbers);
                    expect(mirror.length).toBe(set.length);
                    mirror.forEach(function (n, i) {
                        expect(n).toBe(i);
                    });
                });
            })(seed);
        }
    });

    describe("log drawings", function () {

        function draw(set) {
            var lines = [];
            set.log({
                intersection: "+",
                through: "-",
                branchUp: "^",
                branchDown: "v",
                fromBelow: ".",
                fromAbove: "'",
                fromBoth: "x",
                strafe: "|"
            }, function (node, write, writeAbove) {
                var line = "" + node.value;
                var length = line.length;
                var rule = Array(length + 1).join("-");
                writeAbove(" +-" + rule + "-+");
                write("-| " + line + " |");
                write(" +-" + rule + "-+");
            }, lines.push, lines);
            return lines;
        }

        it("should draw a simple box", function () {
            var set = SortedSet([1]);
            expect(draw(set)).toEqual([
                "  +---+",
                "--| 1 |",
                "  +---+"
            ]);
        });

        it("should draw a graph of two ascending", function () {
            var set = SortedSet([1, 2]);
            expect(draw(set)).toEqual([
                "    +---+",
                ".---| 1 |",
                "|   +---+",
                "| +---+",
                "^-| 2 |",
                "  +---+"
            ]);
        });

        it("should draw a graph of two descending", function () {
            var set = SortedSet([2, 1]);
            expect(draw(set)).toEqual([
                "  +---+",
                "v-| 1 |",
                "| +---+",
                "|   +---+",
                "'---| 2 |",
                "    +---+"
            ]);
        });

        it("should draw a graph of three", function () {
            var set = SortedSet([3, 1, 2]);
            expect(draw(set)).toEqual([
                "    +---+",
                ".---| 1 |",
                "|   +---+",
                "| +---+",
                "+-| 2 |",
                "| +---+",
                "|   +---+",
                "'---| 3 |",
                "    +---+"
            ]);
        });

        it("should draw a complex graph", function () {
            var set = SortedSet([8, 6, 5, 3, 7, 2, 1, 4]);
            expect(draw(set)).toEqual([
                "      +---+",
                "  .---| 1 |",
                "  |   +---+",
                "  | +---+",
                ".-+-| 2 |",
                "| | +---+",
                "| |   +---+",
                "| '---| 3 |",
                "|     +---+",
                "| +---+",
                "+-| 4 |",
                "| +---+",
                "|   +---+",
                "'-v-| 5 |",
                "  | +---+",
                "  |     +---+",
                "  | .---| 6 |",
                "  | |   +---+",
                "  | | +---+",
                "  '-+-| 7 |",
                "    | +---+",
                "    |   +---+",
                "    '---| 8 |",
                "        +---+"
            ]);
        });

    });

});

<commit_msg>Add tests for SortedSet find* methods<commit_after>
require("../shim-array");
var SortedSet = require("../sorted-set");
var TreeLog = require("../tree-log");
var describeDeque = require("./deque");
var describeCollection = require("./collection");
var describeSet = require("./set");
var Fuzz = require("./fuzz");

describe("SortedSet", function () {

    function newSortedSet(values) {
        return new SortedSet(values);
    }

    newSortedSet.prototype.isSorted = true;

    [SortedSet, newSortedSet].forEach(function (SortedSet) {

        // TODO SortedSet compare and equals argument overrides

        // construction, has, add, get, delete
        describeCollection(SortedSet, [1, 2, 3, 4], true);

        // comparable objects
        function Value(value) {
            this.value = value;
        }
        Value.prototype.compare = function (that) {
            return Object.compare(this.value, that.value);
        }
        var a = new Value(1);
        var b = new Value(2);
        var c = new Value(3);
        var d = new Value(4);
        var values = [a, b, c, d];
        describeCollection(SortedSet, values, true);

        // Happens to qualify as a deque, since the tests keep the content in
        // sorted order.  SortedSet has meaningful pop and shift operations, but
        // push and unshift just add the arguments into their proper sorted
        // positions rather than the ends.
        describeDeque(SortedSet);

        describeSet(SortedSet, "sorted");

    });

    describe("splay", function () {

        function draw(set) {
            var lines = [];
            set.log(TreeLog.ascii, null, lines.push, lines);
            return lines;
        }

        it("should degenerate for sorted values", function () {
            var set = SortedSet([1, 2, 3]);
            expect(draw(set)).toEqual([
                "  .-- 1",
                ".-+ 2",
                "+ 3"
            ]);
        });

        it("should splay middle value", function () {
            var set = SortedSet([1, 2, 3]);
            set.get(2);
            expect(draw(set)).toEqual([
                ".-- 1",
                "+ 2",
                "'-- 3"
            ]);
        });

        it("should splay middle value", function () {
            var set = SortedSet([1, 2, 3]);
            set.get(2);
            set.delete(1);
            expect(draw(set)).toEqual([
                "+ 2",
                "'-- 3"
            ]);
        });

    });

    describe("subtree lengths", function () {

        function draw(set) {
            var lines = [];
            set.log(TreeLog.ascii, function (node, write, writeAbove) {
                write(" " + node.value + " length=" + node.length);
            }, lines.push, lines);
            return lines;
        }

        function expectNodeToHaveCorrectSubtreeLengths(node) {
            if (!node)
                return 0;
            var length = 1;
            length += expectNodeToHaveCorrectSubtreeLengths(node.left);
            length += expectNodeToHaveCorrectSubtreeLengths(node.right);
            expect(node.length).toBe(length);
            return length;
        }

        it("+1", function () {
            var set = SortedSet([1]);
            expect(draw(set)).toEqual([
                "- 1 length=1"
            ]);
            expectNodeToHaveCorrectSubtreeLengths(set.root);
        });

        it("+1, +2", function () {
            var set = SortedSet([1, 2]);
            expect(draw(set)).toEqual([
                ".-- 1 length=1",
                "+ 2 length=2"
            ]);
            expectNodeToHaveCorrectSubtreeLengths(set.root);
        });

        it("+1, +2, 1", function () {
            var set = SortedSet([1, 2]);
            set.get(1);
            expect(draw(set)).toEqual([
                "+ 1 length=2",
                "'-- 2 length=1"
            ]);
            expectNodeToHaveCorrectSubtreeLengths(set.root);
        });

        it("+1, +3, +2", function () {
            var set = SortedSet([1, 3, 2]);
            expect(draw(set)).toEqual([
                ".-- 1 length=1",
                "+ 2 length=3",
                "'-- 3 length=1"
            ]);
            expectNodeToHaveCorrectSubtreeLengths(set.root);
        });

        function makeCase(description, operations, log) {
            it(description + " " + operations, function () {
                var set = SortedSet();
                Fuzz.execute(set, Fuzz.parse(operations), log);
                expectNodeToHaveCorrectSubtreeLengths(set.root);
            });
        }

        makeCase("reduction of case with propagation issue", "+2, +4, +3, +1, 4");

        // 50 fuzz cases
        for (var i = 0; i < 50; i++) {
            (function () {
                var fuzz = Fuzz.make(i * 5, i, Math.max(10, i * 5));
                makeCase("fuzz", Fuzz.stringify(fuzz));
            })();
        }

    });

    describe("splayIndex", function () {
        it("should find the index of every element", function () {
            var numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
            var rand = Fuzz.makeRandom(0);
            numbers.sort(function () {
                return rand() - .5;
            });
            var set = SortedSet(numbers);
            numbers.forEach(function (index) {
                set.splayIndex(index);
                expect(set.root.index).toBe(index);
                expect(set.root.value).toBe(index);
            });
        });
    });

    describe("indexOf", function () {
        // fuzz cases
        for (var seed = 0; seed < 20; seed++) {
            (function (seed) {
                var numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
                var rand = Fuzz.makeRandom(seed);
                numbers.sort(function () {
                    return rand() - .5;
                });
                it("should discern the position of every value in " + numbers.join(", "), function () {
                    var set = SortedSet(numbers);
                    numbers.forEach(function (n, i) {
                        expect(set.indexOf(n)).toBe(n);
                    });
                });
            })(seed);
        }
    });

    describe("find methods", function () {
        var set = new SortedSet([22, 23, 1, 34, 19, 5, 26, 12, 27, 30, 21,
                                 20, 6, 7, 2, 32, 10, 9, 33, 3, 11, 17, 28, 15]);

        describe("find", function() {

            it("should find the node for existing values", function() {
                expect(set.findValue(1).value).toBe(1);
                expect(set.findValue(5).value).toBe(5);
                expect(set.findValue(9).value).toBe(9);
                expect(set.findValue(30).value).toBe(30);
                expect(set.findValue(34).value).toBe(34);
            });

            it("should return undefined for non-existent values", function() {
                expect(set.findValue(4)).toBe(undefined);
                expect(set.findValue(13)).toBe(undefined);
                expect(set.findValue(31)).toBe(undefined);
            });

        });

        describe("findGreatest", function () {

            it("should return the highest value in the set", function() {
                expect(set.findGreatest().value).toBe(34);
            });

        });

        describe("findLeast", function () {

            it("should return the lowest value in the set", function() {
                expect(set.findLeast().value).toBe(1);
            });

        });

        describe("findGreatestLessThanOrEqual", function () {

            it("should return values that exist in the set", function() {
                expect(set.findGreatestLessThanOrEqual(5).value).toBe(5);
                expect(set.findGreatestLessThanOrEqual(7).value).toBe(7);
                expect(set.findGreatestLessThanOrEqual(9).value).toBe(9);
            });

            it("should return the next highest value", function() {
                expect(set.findGreatestLessThanOrEqual(14).value).toBe(12);
                expect(set.findGreatestLessThanOrEqual(24).value).toBe(23);
                expect(set.findGreatestLessThanOrEqual(31).value).toBe(30);
                expect(set.findGreatestLessThanOrEqual(4).value).toBe(3);
                expect(set.findGreatestLessThanOrEqual(29).value).toBe(28);
                expect(set.findGreatestLessThanOrEqual(25).value).toBe(23);
            });

            it("should return undefined for values out of range", function() {
                expect(set.findGreatestLessThanOrEqual(0)).toBe(undefined);
            });

        });

        describe("findGreatestLessThan", function () {

            it("should return next highest for values that exist in the set", function() {
                expect(set.findGreatestLessThan(5).value).toBe(3);
                expect(set.findGreatestLessThan(7).value).toBe(6);
                expect(set.findGreatestLessThan(9).value).toBe(7);
                expect(set.findGreatestLessThan(26).value).toBe(23);
            });

            it("should return the next highest value", function() {
                expect(set.findGreatestLessThan(14).value).toBe(12);
                expect(set.findGreatestLessThan(24).value).toBe(23);
                expect(set.findGreatestLessThan(31).value).toBe(30);
                expect(set.findGreatestLessThan(4).value).toBe(3);
                expect(set.findGreatestLessThan(29).value).toBe(28);
                expect(set.findGreatestLessThan(25).value).toBe(23);
            });

            it("should return undefined for value at bottom of range", function() {
                expect(set.findGreatestLessThan(1)).toBe(undefined);
            });

        });

        describe("findLeastGreaterThanOrEqual", function () {

            it("should return values that exist in the set", function() {
                expect(set.findLeastGreaterThanOrEqual(5).value).toBe(5);
                expect(set.findLeastGreaterThanOrEqual(7).value).toBe(7);
                expect(set.findLeastGreaterThanOrEqual(9).value).toBe(9);
            });

            it("should return the next value", function() {
                expect(set.findLeastGreaterThanOrEqual(13).value).toBe(15);
                expect(set.findLeastGreaterThanOrEqual(24).value).toBe(26);
                expect(set.findLeastGreaterThanOrEqual(31).value).toBe(32);
                expect(set.findLeastGreaterThanOrEqual(4).value).toBe(5);
                expect(set.findLeastGreaterThanOrEqual(29).value).toBe(30);
                expect(set.findLeastGreaterThanOrEqual(25).value).toBe(26);
            });

            it("should return undefined for values out of range", function() {
                expect(set.findLeastGreaterThanOrEqual(36)).toBe(undefined);
            });

        });

        describe("findLeastGreaterThan", function () {

            it("should return next value for values that exist in the set", function() {
                expect(set.findLeastGreaterThan(5).value).toBe(6);
                expect(set.findLeastGreaterThan(7).value).toBe(9);
                expect(set.findLeastGreaterThan(9).value).toBe(10);
                expect(set.findLeastGreaterThan(26).value).toBe(27);
            });

            it("should return the next value", function() {
                expect(set.findLeastGreaterThan(14).value).toBe(15);
                expect(set.findLeastGreaterThan(24).value).toBe(26);
                expect(set.findLeastGreaterThan(31).value).toBe(32);
                expect(set.findLeastGreaterThan(4).value).toBe(5);
                expect(set.findLeastGreaterThan(29).value).toBe(30);
                expect(set.findLeastGreaterThan(25).value).toBe(26);
            });

            it("should return undefined for value at top of range", function() {
                expect(set.findLeastGreaterThan(34)).toBe(undefined);
            });

        });

    });

    describe("observeRangeChange", function () {
        // fuzz cases
        for (var seed = 0; seed < 20; seed++) {
            (function (seed) {
                var numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
                var rand = Fuzz.makeRandom(seed);
                numbers.sort(function () {
                    return rand() - .5;
                });
                it("should bind content changes to an array for " + numbers.join(", "), function () {
                    var mirror = [];
                    var set = SortedSet();
                    set.observeRangeChange(function (plus, minus, index) {
                        mirror.swap(index, minus.length, plus);
                    });
                    set.addEach(numbers);
                    expect(mirror.length).toBe(set.length);
                    mirror.forEach(function (n, i) {
                        expect(n).toBe(i);
                    });
                });
            })(seed);
        }
    });

    describe("log drawings", function () {

        function draw(set) {
            var lines = [];
            set.log({
                intersection: "+",
                through: "-",
                branchUp: "^",
                branchDown: "v",
                fromBelow: ".",
                fromAbove: "'",
                fromBoth: "x",
                strafe: "|"
            }, function (node, write, writeAbove) {
                var line = "" + node.value;
                var length = line.length;
                var rule = Array(length + 1).join("-");
                writeAbove(" +-" + rule + "-+");
                write("-| " + line + " |");
                write(" +-" + rule + "-+");
            }, lines.push, lines);
            return lines;
        }

        it("should draw a simple box", function () {
            var set = SortedSet([1]);
            expect(draw(set)).toEqual([
                "  +---+",
                "--| 1 |",
                "  +---+"
            ]);
        });

        it("should draw a graph of two ascending", function () {
            var set = SortedSet([1, 2]);
            expect(draw(set)).toEqual([
                "    +---+",
                ".---| 1 |",
                "|   +---+",
                "| +---+",
                "^-| 2 |",
                "  +---+"
            ]);
        });

        it("should draw a graph of two descending", function () {
            var set = SortedSet([2, 1]);
            expect(draw(set)).toEqual([
                "  +---+",
                "v-| 1 |",
                "| +---+",
                "|   +---+",
                "'---| 2 |",
                "    +---+"
            ]);
        });

        it("should draw a graph of three", function () {
            var set = SortedSet([3, 1, 2]);
            expect(draw(set)).toEqual([
                "    +---+",
                ".---| 1 |",
                "|   +---+",
                "| +---+",
                "+-| 2 |",
                "| +---+",
                "|   +---+",
                "'---| 3 |",
                "    +---+"
            ]);
        });

        it("should draw a complex graph", function () {
            var set = SortedSet([8, 6, 5, 3, 7, 2, 1, 4]);
            expect(draw(set)).toEqual([
                "      +---+",
                "  .---| 1 |",
                "  |   +---+",
                "  | +---+",
                ".-+-| 2 |",
                "| | +---+",
                "| |   +---+",
                "| '---| 3 |",
                "|     +---+",
                "| +---+",
                "+-| 4 |",
                "| +---+",
                "|   +---+",
                "'-v-| 5 |",
                "  | +---+",
                "  |     +---+",
                "  | .---| 6 |",
                "  | |   +---+",
                "  | | +---+",
                "  '-+-| 7 |",
                "    | +---+",
                "    |   +---+",
                "    '---| 8 |",
                "        +---+"
            ]);
        });

    });

});

<|endoftext|>