<commit_before>var Hipchat = require('node-hipchat'),
    path = require("path"),
    assert = require("assert"),
    fs = require("fs-extra"),
    glob = require("glob"),
    _ = require('lodash'),
    request = require("superagent"),
    async = require("async"),
    tarball = require('tarball-extract')

var HC = new Hipchat(process.env.HIPCHAT);
var hipchat = {
  message: function(color, message) {
    if (process.env.HIPCHAT) {
      var params = {
        room: 165440,
        from: 'Auto Update',
        message: message,
        color: color,
        notify: 0
      };
      HC.postMessage(params, function(data) {});
    } else {
      console.log('No Hipchat API Key');
    }
  }
};

hipchat.message('gray', 'Auto Update Started');
var newVersionCount = 0;
var parse = function (json_file, ignore_missing, ignore_parse_fail) {
    var content;

    try {
        content = fs.readFileSync(json_file, 'utf8');
    } catch (err1) {
        if (!ignore_missing) {
            assert.ok(0, json_file + " doesn't exist!");
        }
        return null;
    }
    try {
        return JSON.parse(content);
    } catch (err2) {
        if (!ignore_parse_fail) {
            //assert.ok(0, json_file + " failed to parse");
        }
        return null;
    }
}

var reEscape = function(s){
    return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
}

/**
 * Check if an npmFileMap object contains any path which are not normalized, and thus could allow access to parent dirs
 * @param pkg
 * @returns {*}
 */
var isValidFileMap = function(pkg){
    var isValidPath = function(p){
        if(p !== null){ //don't allow parent dir access, or tricky paths
            p = p.replace(/\/+/g, '/'); //dont penalize for consequtive path seperators
            return p === path.normalize(p);
        }
        return false
    };

    if(pkg && pkg.npmFileMap){
        return _.every(pkg.npmFileMap, function(fileSpec){
           if(isValidPath(fileSpec.basePath || "/")){
               return _.every(fileSpec.files, isValidPath);
           }
           return false;
        });
    }
    return false
};

var error = function(msg, name){
    var err = new Error(msg);
    err.name = name;
    console.log(msg);
    hipchat.message('red', msg);
    return err;
}
error.PKG_NAME = 'BadPackageName'
error.FILE_PATH = 'BadFilePath'

/**
 * returns a fucntion that takes N args, where each arg is a path that must not outside of libPath.
 * returns true if all paths are within libPath, else false
 */
var isAllowedPathFn = function(libPath){ //is path within the lib dir? if not, they shouldnt be writing/reading there
    libPath = path.normalize(libPath || "/");
    return function(){
        var paths = 1 <= arguments.length ? [].slice.call(arguments, 0) : [];
        var re = new RegExp("^"+reEscape(libPath));
        return _.every(paths, function(p) {
            p = path.normalize(p);
            return p.match(re);
        });
    }
};

var invalidNpmName = function(name){
    return !!~name.indexOf(".."); //doesnt contain
}

/**
 * Attempt to update the npmFileMap from extracted package.json, then using npmFileMap move required files to libPath/../
 * If the npmFileMap tries to modify files outside of libPath, dont let it!
 * @param pkg
 * @param libPath = root folder for extracted lib
 * @returns {Array} = array of security related errors triggered during operation.
 */
var processNewVersion = function(pkg, version){
    //sometimes the tar is extracted to a dir that isnt called 'package' - get that dir via glob
    var extractLibPath = glob.sync(getPackageTempPath(pkg, version)+"/*/")[0];

    if(!extractLibPath){
      //even more rarely, the tar doesnt seem to get extracted at all.. which is probably a bug in that lib.
      console.log(pkg.npmName+"@"+version+" - never got extracted! This problem usually goes away on next run. Couldnt find extract dir here: ", getPackageTempPath(pkg, version));
      return;
    }
    var libPath = getPackagePath(pkg, version)

    var isAllowedPath = isAllowedPathFn(extractLibPath);

    var newPath = path.join(libPath, 'package.json')
    if(false && fs.existsSync(newPath)){ //turn this off for now
        var newPkg = parse(newPath);
        if(isValidFileMap(newPkg)){
            pkg.npmFileMap = newPkg.npmFileMap;
        }
    }
    var npmFileMap = pkg.npmFileMap;
    var errors = [];

    var updated = false;

    _.each(npmFileMap, function(fileSpec) {
        var basePath = fileSpec.basePath || "";

        _.each(fileSpec.files, function(file) {
            var libContentsPath = path.normalize(path.join(extractLibPath, basePath));
            if(!isAllowedPath(libContentsPath)){
                errors.push(error(pkg.npmName+" contains a malicious file path: "+libContentsPath, error.FILE_PATH));
                return
            }
            var files = glob.sync(path.join(libContentsPath, file));
            var copyPath = path.join(libPath, basePath)

            if(files.length == 0){
              //usually old versions have this problem
              console.log(pkg.npmName+"@"+version+" - couldnt find file in npmFileMap. Doesnt exist: ", path.join(libContentsPath, file));
            }

            _.each(files, function(extractFilePath) {
                if(extractFilePath.match(/(dependencies|\.zip\s*$)/i)){
                  return;
                }

                var copyPart = path.relative(libContentsPath, extractFilePath);
                var copyPath = path.join(libPath, copyPart)
                fs.mkdirsSync(path.dirname(copyPath))
                fs.renameSync(extractFilePath, copyPath);
                updated = true
            });
        });
    });
    if(updated){
      newVersionCount++;
    }
    return errors;
}

var getPackageTempPath = function(pkg, version){
    return path.normalize(path.join(__dirname, 'temp', pkg.name, version))
}
var getPackagePath = function(pkg, version){
    return path.normalize(path.join(__dirname, 'ajax', 'libs', pkg.name, version));
}
/**
 * download and extract a tarball for a single npm version, get the files in npmFileMap and delete the rest
 * @param pkg
 * @param tarballUrl
 * @param version
 * @param cb
 * @returns {*}
 */
var updateLibraryVersion = function(pkg, tarballUrl, version, cb) {
    if(invalidNpmName(pkg.name)){
        return cb(error(pkg.npmName+" has a malicious package name:"+ pkg.name, error.PKG_NAME));
    }
    var extractLibPath = getPackageTempPath(pkg, version);
    var libPath = getPackagePath(pkg, version);

    if(!fs.existsSync(libPath)) {
        fs.mkdirsSync(extractLibPath);
        var url = tarballUrl;
        var downloadFile = path.join(extractLibPath, 'dist.tar.gz');
        tarball.extractTarballDownload(url , downloadFile, extractLibPath, {}, function(err, result) {
            if(fs.existsSync(downloadFile)){
                processNewVersion(pkg, version);
                console.log("Do not have version", version, "of ", pkg.npmName);
            } else {
                console.log("error downloading "+ version+ " of "+pkg.npmName+" it didnt exist: ", result, err)
            }
            cb()
        });
    } else {
        cb()
    }
};

/**
 * grab all versions of a lib that has an 'npmFileMap' and 'npmName' in its package.json
 * @param pkg
 * @param tarballUrl
 * @param cb
 */
var updateLibrary = function (pkg, cb) {
    if(!isValidFileMap(pkg)){
        console.log(pkg.npmName+" has a malicious npmFileMap");
        hipchat.message('red', pkg.npmName+" has a malicious npmFileMap: "+ JSON.stringify(pkg.npmFileMap));
        return cb(null);
    }
    console.log('Checking versions for ' + pkg.npmName);
    request.get('http://registry.npmjs.org/' + pkg.npmName, function(result) {
        async.eachSeries(_.pairs(result.body.versions), function(p, cb){
            var data = p[1];
            var version = p[0];
            updateLibraryVersion(pkg, data.dist.tarball, version, cb)
        }, function(err){
	    console.log('Library finished', err);
            var npmVersion = result.body['dist-tags'] && result.body['dist-tags'].latest || 0;
            pkg.version = npmVersion;
            fs.writeFileSync('ajax/libs/' + pkg.name + '/package.json', JSON.stringify(pkg, null, 2), 'utf8');
            cb(null);
        });
    });
}

exports.run = function(){
    fs.removeSync(path.join(__dirname, 'temp'))

    process.on('uncaughtException', function(){
      fs.removeSync(path.join(__dirname, 'temp'))
    })
    console.log('Looking for npm enabled libraries...');

    // load up those files
    var packages = glob.sync("./ajax/libs/*/package.json");
    packages = _(packages).map(function (pkg) {
        var parsedPkg = parse(pkg);
        return (parsedPkg.npmName && parsedPkg.npmFileMap) ? parsedPkg : null;
    }).compact().value();
    hipchat.message('green', 'Found ' + packages.length + ' npm enabled libraries');
    console.log('Found ' + packages.length + ' npm enabled libraries');

    async.eachSeries(packages, updateLibrary, function(err) {
        console.log('Auto Update Completed - ' + newVersionCount + ' versions were updated');
        hipchat.message('green', 'Auto Update Completed - ' + newVersionCount + ' versions were updated');
        fs.removeSync(path.join(__dirname, 'temp'))
    });
}
exports.updateLibrary = updateLibrary;
exports.updateLibraryVersion = updateLibraryVersion;
exports.processNewVersion = processNewVersion;
exports.error = error;
exports.isAllowedPathFn = isAllowedPathFn;
exports.isValidFileMap = isValidFileMap;
exports.invalidNpmName = invalidNpmName;

var args = process.argv.slice(2);
if(args.length > 0 && args[0] == 'run'){
    exports.run()
} else {
    console.log('to start, pass the "run" arg')
}
<commit_msg>retab in auto-update.js<commit_after>var Hipchat = require('node-hipchat'),
    path = require("path"),
    assert = require("assert"),
    fs = require("fs-extra"),
    glob = require("glob"),
    _ = require('lodash'),
    request = require("superagent"),
    async = require("async"),
    tarball = require('tarball-extract')

var HC = new Hipchat(process.env.HIPCHAT);
var hipchat = {
  message: function(color, message) {
    if (process.env.HIPCHAT) {
      var params = {
        room: 165440,
        from: 'Auto Update',
        message: message,
        color: color,
        notify: 0
      };
      HC.postMessage(params, function(data) {});
    } else {
      console.log('No Hipchat API Key');
    }
  }
};

hipchat.message('gray', 'Auto Update Started');
var newVersionCount = 0;
var parse = function (json_file, ignore_missing, ignore_parse_fail) {
    var content;

    try {
        content = fs.readFileSync(json_file, 'utf8');
    } catch (err1) {
        if (!ignore_missing) {
            assert.ok(0, json_file + " doesn't exist!");
        }
        return null;
    }
    try {
        return JSON.parse(content);
    } catch (err2) {
        if (!ignore_parse_fail) {
            //assert.ok(0, json_file + " failed to parse");
        }
        return null;
    }
}

var reEscape = function(s){
    return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
}

/**
 * Check if an npmFileMap object contains any path which are not normalized, and thus could allow access to parent dirs
 * @param pkg
 * @returns {*}
 */
var isValidFileMap = function(pkg){
    var isValidPath = function(p){
        if(p !== null){ //don't allow parent dir access, or tricky paths
            p = p.replace(/\/+/g, '/'); //dont penalize for consequtive path seperators
            return p === path.normalize(p);
        }
        return false
    };

    if(pkg && pkg.npmFileMap){
        return _.every(pkg.npmFileMap, function(fileSpec){
           if(isValidPath(fileSpec.basePath || "/")){
               return _.every(fileSpec.files, isValidPath);
           }
           return false;
        });
    }
    return false
};

var error = function(msg, name){
    var err = new Error(msg);
    err.name = name;
    console.log(msg);
    hipchat.message('red', msg);
    return err;
}
error.PKG_NAME = 'BadPackageName'
error.FILE_PATH = 'BadFilePath'

/**
 * returns a fucntion that takes N args, where each arg is a path that must not outside of libPath.
 * returns true if all paths are within libPath, else false
 */
var isAllowedPathFn = function(libPath){ //is path within the lib dir? if not, they shouldnt be writing/reading there
    libPath = path.normalize(libPath || "/");
    return function(){
        var paths = 1 <= arguments.length ? [].slice.call(arguments, 0) : [];
        var re = new RegExp("^"+reEscape(libPath));
        return _.every(paths, function(p) {
            p = path.normalize(p);
            return p.match(re);
        });
    }
};

var invalidNpmName = function(name){
    return !!~name.indexOf(".."); //doesnt contain
}

/**
 * Attempt to update the npmFileMap from extracted package.json, then using npmFileMap move required files to libPath/../
 * If the npmFileMap tries to modify files outside of libPath, dont let it!
 * @param pkg
 * @param libPath = root folder for extracted lib
 * @returns {Array} = array of security related errors triggered during operation.
 */
var processNewVersion = function(pkg, version){
    //sometimes the tar is extracted to a dir that isnt called 'package' - get that dir via glob
    var extractLibPath = glob.sync(getPackageTempPath(pkg, version)+"/*/")[0];

    if(!extractLibPath){
      //even more rarely, the tar doesnt seem to get extracted at all.. which is probably a bug in that lib.
      console.log(pkg.npmName+"@"+version+" - never got extracted! This problem usually goes away on next run. Couldnt find extract dir here: ", getPackageTempPath(pkg, version));
      return;
    }
    var libPath = getPackagePath(pkg, version)

    var isAllowedPath = isAllowedPathFn(extractLibPath);

    var newPath = path.join(libPath, 'package.json')
    if(false && fs.existsSync(newPath)){ //turn this off for now
        var newPkg = parse(newPath);
        if(isValidFileMap(newPkg)){
            pkg.npmFileMap = newPkg.npmFileMap;
        }
    }
    var npmFileMap = pkg.npmFileMap;
    var errors = [];

    var updated = false;

    _.each(npmFileMap, function(fileSpec) {
        var basePath = fileSpec.basePath || "";

        _.each(fileSpec.files, function(file) {
            var libContentsPath = path.normalize(path.join(extractLibPath, basePath));
            if(!isAllowedPath(libContentsPath)){
                errors.push(error(pkg.npmName+" contains a malicious file path: "+libContentsPath, error.FILE_PATH));
                return
            }
            var files = glob.sync(path.join(libContentsPath, file));
            var copyPath = path.join(libPath, basePath)

            if(files.length == 0){
              //usually old versions have this problem
              console.log(pkg.npmName+"@"+version+" - couldnt find file in npmFileMap. Doesnt exist: ", path.join(libContentsPath, file));
            }

            _.each(files, function(extractFilePath) {
                if(extractFilePath.match(/(dependencies|\.zip\s*$)/i)){
                  return;
                }

                var copyPart = path.relative(libContentsPath, extractFilePath);
                var copyPath = path.join(libPath, copyPart)
                fs.mkdirsSync(path.dirname(copyPath))
                fs.renameSync(extractFilePath, copyPath);
                updated = true
            });
        });
    });
    if(updated){
      newVersionCount++;
    }
    return errors;
}

var getPackageTempPath = function(pkg, version){
    return path.normalize(path.join(__dirname, 'temp', pkg.name, version))
}
var getPackagePath = function(pkg, version){
    return path.normalize(path.join(__dirname, 'ajax', 'libs', pkg.name, version));
}
/**
 * download and extract a tarball for a single npm version, get the files in npmFileMap and delete the rest
 * @param pkg
 * @param tarballUrl
 * @param version
 * @param cb
 * @returns {*}
 */
var updateLibraryVersion = function(pkg, tarballUrl, version, cb) {
    if(invalidNpmName(pkg.name)){
        return cb(error(pkg.npmName+" has a malicious package name:"+ pkg.name, error.PKG_NAME));
    }
    var extractLibPath = getPackageTempPath(pkg, version);
    var libPath = getPackagePath(pkg, version);

    if(!fs.existsSync(libPath)) {
        fs.mkdirsSync(extractLibPath);
        var url = tarballUrl;
        var downloadFile = path.join(extractLibPath, 'dist.tar.gz');
        tarball.extractTarballDownload(url , downloadFile, extractLibPath, {}, function(err, result) {
            if(fs.existsSync(downloadFile)){
                processNewVersion(pkg, version);
                console.log("Do not have version", version, "of ", pkg.npmName);
            } else {
                console.log("error downloading "+ version+ " of "+pkg.npmName+" it didnt exist: ", result, err)
            }
            cb()
        });
    } else {
        cb()
    }
};

/**
 * grab all versions of a lib that has an 'npmFileMap' and 'npmName' in its package.json
 * @param pkg
 * @param tarballUrl
 * @param cb
 */
var updateLibrary = function (pkg, cb) {
    if(!isValidFileMap(pkg)){
        console.log(pkg.npmName+" has a malicious npmFileMap");
        hipchat.message('red', pkg.npmName+" has a malicious npmFileMap: "+ JSON.stringify(pkg.npmFileMap));
        return cb(null);
    }
    console.log('Checking versions for ' + pkg.npmName);
    request.get('http://registry.npmjs.org/' + pkg.npmName, function(result) {
        async.eachSeries(_.pairs(result.body.versions), function(p, cb){
            var data = p[1];
            var version = p[0];
            updateLibraryVersion(pkg, data.dist.tarball, version, cb)
        }, function(err){
        console.log('Library finished', err);
            var npmVersion = result.body['dist-tags'] && result.body['dist-tags'].latest || 0;
            pkg.version = npmVersion;
            fs.writeFileSync('ajax/libs/' + pkg.name + '/package.json', JSON.stringify(pkg, null, 2), 'utf8');
            cb(null);
        });
    });
}

exports.run = function(){
    fs.removeSync(path.join(__dirname, 'temp'))

    process.on('uncaughtException', function(){
      fs.removeSync(path.join(__dirname, 'temp'))
    })
    console.log('Looking for npm enabled libraries...');

    // load up those files
    var packages = glob.sync("./ajax/libs/*/package.json");
    packages = _(packages).map(function (pkg) {
        var parsedPkg = parse(pkg);
        return (parsedPkg.npmName && parsedPkg.npmFileMap) ? parsedPkg : null;
    }).compact().value();
    hipchat.message('green', 'Found ' + packages.length + ' npm enabled libraries');
    console.log('Found ' + packages.length + ' npm enabled libraries');

    async.eachSeries(packages, updateLibrary, function(err) {
        console.log('Auto Update Completed - ' + newVersionCount + ' versions were updated');
        hipchat.message('green', 'Auto Update Completed - ' + newVersionCount + ' versions were updated');
        fs.removeSync(path.join(__dirname, 'temp'))
    });
}
exports.updateLibrary = updateLibrary;
exports.updateLibraryVersion = updateLibraryVersion;
exports.processNewVersion = processNewVersion;
exports.error = error;
exports.isAllowedPathFn = isAllowedPathFn;
exports.isValidFileMap = isValidFileMap;
exports.invalidNpmName = invalidNpmName;

var args = process.argv.slice(2);
if(args.length > 0 && args[0] == 'run'){
    exports.run()
} else {
    console.log('to start, pass the "run" arg')
}
<|endoftext|>


<commit_before>var angular = require('angular');

export default["$timeout", function loadStatusFactory($timeout) {
    // simple UI to track loading status
    return {
        init: function($scope, initialTasks) {
            var service = {};
            var existing = $scope.loadStatus;
            if (existing) {
                angular.extend(service, existing);
                service.allTasks = [].concat(existing.allTasks);

            } else {
                service.allTasks = [];
            }
            $scope.loadStatus = service;

            service.registerTask = function(key, taskOptions) {
                var task = {
                    key: key,
                    title: "Untitled Task",
                    progressCurrent: 0,
                    progressTotal: 1,
                    active: false,
                    message: "",
                    error: null,
                    start: function(message) {
                        $timeout(function() {
                            task.message = message || "";
                            task.active = true;
                            task.error = null;
                            task.progressCurrent = 0;
                        });
                    },
                    finish: function(message) {
                        $timeout(function() {
                            task.message = message || "";
                            task.progressCurrent = task.progressTotal;
                            task.completed = true;
                            task.active = false;
                        });
                    },
                    fail: function(message) {
                        $timeout(function() {
                            task.active = false;
                            task.error = message;
                        });
                    },
                    progress: function(progress, total, message) {
                        $timeout(function() {
                            task.active = true;
                            task.progressCurrent = progress;
                            if (total !== undefined) task.progressTotal = total;
                            if (message !== undefined) task.message = message;
                        });
                    }
                };
                angular.extend(task, taskOptions);
                service[key] = task;
                service.allTasks.push(task);
            };

            service.onUpdate = function(tasksOrKeys, fn) {
                // if no task array specified, include all tasks in the current scope
                tasksOrKeys = tasksOrKeys || service.allTasks;
                var watchedKeys = [];
                for (let i = 0; i < tasksOrKeys.length; i++) {
                    var t = tasksOrKeys[i];
                    if (typeof t == "string") watchedKeys.push(t);
                    else if (t.key) watchedKeys.push(t.key);
                }
                if (watchedKeys.length === 0) return fn({
                    tasks: [],
                    completed: true
                });

                $scope.$watch("[loadStatus." + watchedKeys.join(",loadStatus.") + "]", function(newTasks) {
                    // check all tasks, see if there are any outstanding
                    if (!newTasks) return;

                    var result = {
                        tasks: newTasks
                    };

                    result.currentTask = undefined;
                    for (var i = 0; i < newTasks.length; i++) {
                        var task = newTasks[i];
                        if (task.error) {
                            result.currentTask = task;
                            break;
                        }

                        if (task.active) {
                            result.currentTask = task;
                            break;
                        }
                        if (task.progressCurrent < task.progressTotal && (!result.currentTask || task.progressTotal > result.currentTask.progressTotal)) {
                            result.currentTask = task;
                            break;
                        }
                    }
                    if (!result.currentTask) {
                        // finished
                        result.message = "finished";
                        result.completed = true;
                    } else {
                        result.completed = false;
                        result.title = result.currentTask.title;
                        result.error = result.currentTask.error;
                        result.message = result.currentTask.message || (result.currentTask.progressCurrent + " / " + result.currentTask.progressTotal);
                    }

                    fn(result);

                }, true);

            };

            service.after = function(tasksOrKeys, fn) {
                service.onUpdate(tasksOrKeys, function(taskGroup) {
                    if (taskGroup.completed) return fn();
                });
            };

            if (initialTasks) {
                for (var tk in initialTasks) {
                    service.registerTask(tk, initialTasks[tk]);
                }
            }
            return service;
        }
    };
}];
<commit_msg>set task.completed for restarted tasks<commit_after>var angular = require('angular');

export default["$timeout", function loadStatusFactory($timeout) {
    // simple UI to track loading status
    return {
        init: function($scope, initialTasks) {
            var service = {};
            var existing = $scope.loadStatus;
            if (existing) {
                angular.extend(service, existing);
                service.allTasks = [].concat(existing.allTasks);

            } else {
                service.allTasks = [];
            }
            $scope.loadStatus = service;

            service.registerTask = function(key, taskOptions) {
                var task = {
                    key: key,
                    title: "Untitled Task",
                    progressCurrent: 0,
                    progressTotal: 1,
                    active: false,
                    message: "",
                    error: null,
                    start: function(message) {
                        $timeout(function() {
                            task.message = message || "";
                            task.active = true;
                            task.error = null;
                            task.progressCurrent = 0;
                            task.completed = false;
                        });
                    },
                    finish: function(message) {
                        $timeout(function() {
                            task.message = message || "";
                            task.progressCurrent = task.progressTotal;
                            task.completed = true;
                            task.active = false;
                        });
                    },
                    fail: function(message) {
                        $timeout(function() {
                            task.active = false;
                            task.error = message;
                            task.completed = false;
                        });
                    },
                    progress: function(progress, total, message) {
                        $timeout(function() {
                            task.active = true;
                            task.progressCurrent = progress;
                            if (total !== undefined) task.progressTotal = total;
                            if (message !== undefined) task.message = message;
                        });
                    }
                };
                angular.extend(task, taskOptions);
                service[key] = task;
                service.allTasks.push(task);
            };

            service.onUpdate = function(tasksOrKeys, fn) {
                // if no task array specified, include all tasks in the current scope
                tasksOrKeys = tasksOrKeys || service.allTasks;
                var watchedKeys = [];
                for (let i = 0; i < tasksOrKeys.length; i++) {
                    var t = tasksOrKeys[i];
                    if (typeof t == "string") watchedKeys.push(t);
                    else if (t.key) watchedKeys.push(t.key);
                }
                if (watchedKeys.length === 0) return fn({
                    tasks: [],
                    completed: true
                });

                $scope.$watch("[loadStatus." + watchedKeys.join(",loadStatus.") + "]", function(newTasks) {
                    // check all tasks, see if there are any outstanding
                    if (!newTasks) return;

                    var result = {
                        tasks: newTasks
                    };

                    result.currentTask = undefined;
                    for (var i = 0; i < newTasks.length; i++) {
                        var task = newTasks[i];
                        if (task.error) {
                            result.currentTask = task;
                            break;
                        }

                        if (task.active) {
                            result.currentTask = task;
                            break;
                        }
                        if (task.progressCurrent < task.progressTotal && (!result.currentTask || task.progressTotal > result.currentTask.progressTotal)) {
                            result.currentTask = task;
                            break;
                        }
                    }
                    if (!result.currentTask) {
                        // finished
                        result.message = "finished";
                        result.completed = true;
                    } else {
                        result.completed = false;
                        result.title = result.currentTask.title;
                        result.error = result.currentTask.error;
                        result.message = result.currentTask.message || (result.currentTask.progressCurrent + " / " + result.currentTask.progressTotal);
                    }

                    fn(result);

                }, true);

            };

            service.after = function(tasksOrKeys, fn) {
                service.onUpdate(tasksOrKeys, function(taskGroup) {
                    if (taskGroup.completed) return fn();
                });
            };

            if (initialTasks) {
                for (var tk in initialTasks) {
                    service.registerTask(tk, initialTasks[tk]);
                }
            }
            return service;
        }
    };
}];
<|endoftext|>


<commit_before>// Copyright 2016-2017, University of Colorado Boulder
/**
 * @fileoverview Rule to check that we aren't using native JavaScript constructors.
 * This typically occurs when we forget a require statement for a PhET module that has the same name as a native
 * constructor.
 *
 * Using native JavaScript constructors for types like Image, Text, and Range will almost always result in errors
 * that can be difficult to trace. A type can be defined in a file by loading a module through requireJS or by
 * defining a constructor.
 *
 * This rule works by first traversing down the AST, searching for either variable or function declarations of
 * the types that share a name with a native JavaScript constructor. We then traverse back up the AST searching
 * for nodes that represent instantiation of these types.  An error is thrown when we encounter an instantiation
 * of a type that wasn't declared.
 *
 * @author Jesse Greenberg (PhET Interactive Simulations)
 * @copyright 2016-2017 University of Colorado Boulder
 */

//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------

module.exports = function( context ) {
  'use strict';

  // names of the native JavaScript constructors that clash with PhET type names
  var nativeConstructors = [ 'Image', 'Range', 'Text' ];

  // list of all types that are declared in the file that have the same name as a native JavaScript constructor
  var declaredTypes = [];

  /**
   * Add a type to declared types if the 'declaration' node has a name which is equal to
   * one of the entries in nativeConstructors.  Called when eslint finds VariableDeclarator or FunctionDeclaration
   * nodes as it traverses down the AST.
   *
   * @param {ASTNode} node
   */
  function addDeclaredType( node ) {

    // Example...
    //
    // JavaScript:
    //
    // function Range( min, max ) {...}
    //
    // Corresponding AST:
    //
    // FunctionDeclaration {
    //   type: "FunctionDeclaration",
    //   id: Identifier {
    //     type: "Identifier",
    //     name: "Range"
    //   }
    // }

    if ( node.id && nativeConstructors.indexOf( node.id.name ) !== -1 ) {
      declaredTypes.push( node.id.name );
    }
  }

  return {
    VariableDeclarator: addDeclaredType,
    FunctionDeclaration: addDeclaredType,

    /**
     * When eslint traverses back up the AST, search for a node representing an instantiation of a type.  If found,
     * check to see if the type being instantiated is one of the entries that were added to declaredTypes on
     * the first traversal down the AST.
     *
     * @param  {ASTNode} node
     */
    'NewExpression:exit': function noHTMLConstructor( node ) {

      // Example...
      //
      // JavaScript:
      //
      // var imageNode = new Image( imgsrc );
      //
      // Corresponding AST:
      //
      // exemplar: {
      //   {
      //     "type": "NewExpression",
      //     "callee": {
      //       "type": "Identifier",
      //       "name": "Image"
      //     }
      //   }
      // }

      if ( node.callee && node.callee.name && nativeConstructors.indexOf( node.callee.name ) !== -1 ) {
        if ( declaredTypes.indexOf( node.callee.name ) === -1 ) {
          context.report( {
            node: node,
            loc: node.loc.start,
            message: node.callee.name + ': using native constructor instead of project module, did you forget a requirejs statement?'
          } );
        }
      }
    }
  };
};

module.exports.schema = [
  // JSON Schema for rule options goes here
];<commit_msg>added Event and Node, https://github.com/phetsims/chipper/issues/722<commit_after>// Copyright 2016-2017, University of Colorado Boulder
/**
 * @fileoverview Rule to check that we aren't using native JavaScript constructors.
 * This typically occurs when we forget a require statement for a PhET module that has the same name as a native
 * constructor.
 *
 * Using native JavaScript constructors for types like Image, Text, and Range will almost always result in errors
 * that can be difficult to trace. A type can be defined in a file by loading a module through requireJS or by
 * defining a constructor.
 *
 * This rule works by first traversing down the AST, searching for either variable or function declarations of
 * the types that share a name with a native JavaScript constructor. We then traverse back up the AST searching
 * for nodes that represent instantiation of these types.  An error is thrown when we encounter an instantiation
 * of a type that wasn't declared.
 *
 * @author Jesse Greenberg (PhET Interactive Simulations)
 * @copyright 2016-2017 University of Colorado Boulder
 */

//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------

module.exports = function( context ) {
  'use strict';

  // names of the native JavaScript constructors that clash with PhET type names
  var nativeConstructors = [ 'Image', 'Range', 'Text', 'Node', 'Event' ];

  // list of all types that are declared in the file that have the same name as a native JavaScript constructor
  var declaredTypes = [];

  /**
   * Add a type to declared types if the 'declaration' node has a name which is equal to
   * one of the entries in nativeConstructors.  Called when eslint finds VariableDeclarator or FunctionDeclaration
   * nodes as it traverses down the AST.
   *
   * @param {ASTNode} node
   */
  function addDeclaredType( node ) {

    // Example...
    //
    // JavaScript:
    //
    // function Range( min, max ) {...}
    //
    // Corresponding AST:
    //
    // FunctionDeclaration {
    //   type: "FunctionDeclaration",
    //   id: Identifier {
    //     type: "Identifier",
    //     name: "Range"
    //   }
    // }

    if ( node.id && nativeConstructors.indexOf( node.id.name ) !== -1 ) {
      declaredTypes.push( node.id.name );
    }
  }

  return {
    VariableDeclarator: addDeclaredType,
    FunctionDeclaration: addDeclaredType,

    /**
     * When eslint traverses back up the AST, search for a node representing an instantiation of a type.  If found,
     * check to see if the type being instantiated is one of the entries that were added to declaredTypes on
     * the first traversal down the AST.
     *
     * @param  {ASTNode} node
     */
    'NewExpression:exit': function noHTMLConstructor( node ) {

      // Example...
      //
      // JavaScript:
      //
      // var imageNode = new Image( imgsrc );
      //
      // Corresponding AST:
      //
      // exemplar: {
      //   {
      //     "type": "NewExpression",
      //     "callee": {
      //       "type": "Identifier",
      //       "name": "Image"
      //     }
      //   }
      // }

      if ( node.callee && node.callee.name && nativeConstructors.indexOf( node.callee.name ) !== -1 ) {
        if ( declaredTypes.indexOf( node.callee.name ) === -1 ) {
          context.report( {
            node: node,
            loc: node.loc.start,
            message: node.callee.name + ': using native constructor instead of project module, did you forget a requirejs statement?'
          } );
        }
      }
    }
  };
};

module.exports.schema = [
  // JSON Schema for rule options goes here
];<|endoftext|>


<commit_before>/*!
 * viewport-units-buggyfill v0.3.0
 * @web: https://github.com/rodneyrehm/viewport-units-buggyfill/
 * @author: Rodney Rehm - http://rodneyrehm.de/en/
 */
(function (root, factory) {
  'use strict';
  if (typeof define === 'function' && define.amd) {
    // AMD. Register as an anonymous module.
    define([], factory);
  } else if (typeof exports === 'object') {
    // Node. Does not work with strict CommonJS, but
    // only CommonJS-like enviroments that support module.exports,
    // like Node.
    module.exports = factory();
  } else {
    // Browser globals (root is window)
    root.viewportUnitsBuggyfill = factory();
  }
}(this, function () {
  'use strict';
  /*global document, window, location, XMLHttpRequest, XDomainRequest*/

  var initialized = false;
  var viewportUnitExpression = /([0-9.-]+)(vh|vw|vmin|vmax)/g;
  var forEach = [].forEach;
  var join = [].join;
  var dimensions;
  var declarations;
  var styleNode;

  function initialize(force) {
    if (initialized || (!force && !/ip.+mobile/i.test(window.navigator.userAgent))) {
      // this buggyfill only applies to mobile safari
      return;
    }

    initialized = true;
    styleNode = document.createElement('style');
    styleNode.id = 'patched-viewport';
    document.head.appendChild(styleNode);

    // Issue #6: Cross Origin Stylesheets are not accessible through CSSOM,
    // therefore download and inject them as <style> to circumvent SOP.
    importCrossOriginLinks(function() {
      //window.addEventListener('orientationchange', updateStyles, true);
      // doing a full refresh rather than updateStyles because an orientationchange
      // could activate different stylesheets
      window.addEventListener('orientationchange', refresh, true);
      refresh();
    });
  }

  function updateStyles() {
    styleNode.textContent = getReplacedViewportUnits();
  }

  function refresh() {
    if (!initialized) {
      return;
    }
    findProperties();
    updateStyles();
  }

  function findProperties() {
    declarations = [];
    forEach.call(document.styleSheets, function(sheet) {
      if (sheet.ownerNode.id === 'patched-viewport' || !sheet.cssRules) {
        // skip entire sheet because no rules ara present or it's the target-element of the buggyfill
        return;
      }
      if (sheet.media.mediaText && !window.matchMedia(sheet.media.mediaText).matches) {
        // skip entire sheet because media attribute doesn't match
        return;
      }
      forEach.call(sheet.cssRules, findDeclarations);
    });
    return declarations;
  }

  function findDeclarations(rule) {
    if (rule.type === 7) {
      var value = rule.cssText;
      viewportUnitExpression.lastIndex = 0;
      if (viewportUnitExpression.test(value)) {
        declarations.push([rule, null, value]);
      }
      return;
    }

    if (!rule.style) {
      if (!rule.cssRules) {
        return;
      }

      forEach.call(rule.cssRules, function(_rule) {
        findDeclarations(_rule);
      });

      return;
    }

    forEach.call(rule.style, function(name) {
      var value = rule.style.getPropertyValue(name);
      viewportUnitExpression.lastIndex = 0;
      if (viewportUnitExpression.test(value)) {
        declarations.push([rule, name, value]);
      }
    });
  }

  function getReplacedViewportUnits() {
    dimensions = getViewport();

    var css = [];
    var buffer = [];
    var open;
    var close;

    declarations.forEach(function(item) {
      var _item = overwriteDeclaration.apply(null, item);
      var _open = _item.selector.length ? (_item.selector.join(' {\n') + ' {\n') : '';
      var _close = new Array(_item.selector.length + 1).join('\n}');

      if (!_open || _open !== open) {
        if (buffer.length) {
          css.push(open + buffer.join('\n') + close);
          buffer.length = 0;
        }

        if (_open) {
          open = _open;
          close = _close;
          buffer.push(_item.content);
        } else {
          css.push(_item.content);
          open = null;
          close = null;
        }

        return;
      }

      if (_open && !open) {
        open = _open;
        close = _close;
      }

      buffer.push(_item.content);
    });

    if (buffer.length) {
      css.push(open + buffer.join('\n') + close);
    }

    return css.join('\n\n');
  }

  function overwriteDeclaration(rule, name, value) {
    var _value = value.replace(viewportUnitExpression, replaceValues);
    var _selectors = [];
    if (name) {
      _selectors.push(rule.selectorText);
      _value = name + ': ' + _value + ';';
    }

    var _rule = rule.parentRule;
    while (_rule) {
      _selectors.unshift('@media ' + join.call(_rule.media, ', '));
      _rule = _rule.parentRule;
    }

    return {
      selector: _selectors,
      content: _value
    };
  }

  function replaceValues(match, number, unit) {
    var _base = dimensions[unit];
    var _number = parseFloat(number) / 100;
    return (_number * _base) + 'px';
  }

  function getViewport() {
    var vh = window.innerHeight;
    var vw = window.innerWidth;
    return {
      vh: vh,
      vw: vw,
      vmax: Math.max(vw, vh),
      vmin: Math.min(vw, vh)
    };
  }

  function importCrossOriginLinks(next) {
    var _waiting = 0;
    var decrease = function() {
      _waiting--;
      if (!_waiting) {
        next();
      }
    };

    forEach.call(document.styleSheets, function(sheet) {
      if (!sheet.href || origin(sheet.href) === origin(location.href) ) {
        // skip <style> and <link> from same origin
        return;
      }
      _waiting++;
      convertLinkToStyle(sheet.ownerNode, decrease);
    });

    if (!_waiting) {
      next();
    }
  }

  function origin(url) {
    return url.slice(0, url.indexOf('/', url.indexOf('://') + 3));
  }

  function convertLinkToStyle(link, next) {
    getCors(link.href, function() {
      var style = document.createElement('style');
      style.media = link.media;
      style.textContent = this.responseText;
      link.parentNode.replaceChild(style, link);
      next();
    }, next);
  }

  function getCors(url, success, error) {
    var xhr = new XMLHttpRequest();
    if ('withCredentials' in xhr) {
      // XHR for Chrome/Firefox/Opera/Safari.
      xhr.open('GET', url, true);
    } else if (typeof XDomainRequest !== 'undefined') {
      // XDomainRequest for IE.
      xhr = new XDomainRequest();
      xhr.open('GET', url);
    } else {
      throw new Error('cross-domain XHR not supported');
    }

    xhr.onload = success;
    xhr.onerror = error;
    xhr.send();
    return xhr;
  }

  return {
    version: '0.3.0',
    findProperties: findProperties,
    getCss: getReplacedViewportUnits,
    init: initialize,
    refresh: refresh
  };
}));
<commit_msg>Fix to use more accurate Safari + UIWebView regex.<commit_after>/*!
 * viewport-units-buggyfill v0.3.0
 * @web: https://github.com/rodneyrehm/viewport-units-buggyfill/
 * @author: Rodney Rehm - http://rodneyrehm.de/en/
 */
(function (root, factory) {
  'use strict';
  if (typeof define === 'function' && define.amd) {
    // AMD. Register as an anonymous module.
    define([], factory);
  } else if (typeof exports === 'object') {
    // Node. Does not work with strict CommonJS, but
    // only CommonJS-like enviroments that support module.exports,
    // like Node.
    module.exports = factory();
  } else {
    // Browser globals (root is window)
    root.viewportUnitsBuggyfill = factory();
  }
}(this, function () {
  'use strict';
  /*global document, window, location, XMLHttpRequest, XDomainRequest*/

  var initialized = false;
  var viewportUnitExpression = /([0-9.-]+)(vh|vw|vmin|vmax)/g;
  var forEach = [].forEach;
  var join = [].join;
  var dimensions;
  var declarations;
  var styleNode;
  var is_safari_or_uiwebview = /(iPhone|iPod|iPad).+AppleWebKit/i.test(window.navigator.userAgent);

  function initialize(force) {
    if (initialized || (!force && !is_safari_or_uiwebview)) {
      // this buggyfill only applies to mobile safari
      return;
    }

    initialized = true;
    styleNode = document.createElement('style');
    styleNode.id = 'patched-viewport';
    document.head.appendChild(styleNode);

    // Issue #6: Cross Origin Stylesheets are not accessible through CSSOM,
    // therefore download and inject them as <style> to circumvent SOP.
    importCrossOriginLinks(function() {
      //window.addEventListener('orientationchange', updateStyles, true);
      // doing a full refresh rather than updateStyles because an orientationchange
      // could activate different stylesheets
      window.addEventListener('orientationchange', refresh, true);
      refresh();
    });
  }

  function updateStyles() {
    styleNode.textContent = getReplacedViewportUnits();
  }

  function refresh() {
    if (!initialized) {
      return;
    }
    findProperties();
    updateStyles();
  }

  function findProperties() {
    declarations = [];
    forEach.call(document.styleSheets, function(sheet) {
      if (sheet.ownerNode.id === 'patched-viewport' || !sheet.cssRules) {
        // skip entire sheet because no rules ara present or it's the target-element of the buggyfill
        return;
      }
      if (sheet.media.mediaText && !window.matchMedia(sheet.media.mediaText).matches) {
        // skip entire sheet because media attribute doesn't match
        return;
      }
      forEach.call(sheet.cssRules, findDeclarations);
    });
    return declarations;
  }

  function findDeclarations(rule) {
    if (rule.type === 7) {
      var value = rule.cssText;
      viewportUnitExpression.lastIndex = 0;
      if (viewportUnitExpression.test(value)) {
        declarations.push([rule, null, value]);
      }
      return;
    }

    if (!rule.style) {
      if (!rule.cssRules) {
        return;
      }

      forEach.call(rule.cssRules, function(_rule) {
        findDeclarations(_rule);
      });

      return;
    }

    forEach.call(rule.style, function(name) {
      var value = rule.style.getPropertyValue(name);
      viewportUnitExpression.lastIndex = 0;
      if (viewportUnitExpression.test(value)) {
        declarations.push([rule, name, value]);
      }
    });
  }

  function getReplacedViewportUnits() {
    dimensions = getViewport();

    var css = [];
    var buffer = [];
    var open;
    var close;

    declarations.forEach(function(item) {
      var _item = overwriteDeclaration.apply(null, item);
      var _open = _item.selector.length ? (_item.selector.join(' {\n') + ' {\n') : '';
      var _close = new Array(_item.selector.length + 1).join('\n}');

      if (!_open || _open !== open) {
        if (buffer.length) {
          css.push(open + buffer.join('\n') + close);
          buffer.length = 0;
        }

        if (_open) {
          open = _open;
          close = _close;
          buffer.push(_item.content);
        } else {
          css.push(_item.content);
          open = null;
          close = null;
        }

        return;
      }

      if (_open && !open) {
        open = _open;
        close = _close;
      }

      buffer.push(_item.content);
    });

    if (buffer.length) {
      css.push(open + buffer.join('\n') + close);
    }

    return css.join('\n\n');
  }

  function overwriteDeclaration(rule, name, value) {
    var _value = value.replace(viewportUnitExpression, replaceValues);
    var _selectors = [];
    if (name) {
      _selectors.push(rule.selectorText);
      _value = name + ': ' + _value + ';';
    }

    var _rule = rule.parentRule;
    while (_rule) {
      _selectors.unshift('@media ' + join.call(_rule.media, ', '));
      _rule = _rule.parentRule;
    }

    return {
      selector: _selectors,
      content: _value
    };
  }

  function replaceValues(match, number, unit) {
    var _base = dimensions[unit];
    var _number = parseFloat(number) / 100;
    return (_number * _base) + 'px';
  }

  function getViewport() {
    var vh = window.innerHeight;
    var vw = window.innerWidth;
    return {
      vh: vh,
      vw: vw,
      vmax: Math.max(vw, vh),
      vmin: Math.min(vw, vh)
    };
  }

  function importCrossOriginLinks(next) {
    var _waiting = 0;
    var decrease = function() {
      _waiting--;
      if (!_waiting) {
        next();
      }
    };

    forEach.call(document.styleSheets, function(sheet) {
      if (!sheet.href || origin(sheet.href) === origin(location.href) ) {
        // skip <style> and <link> from same origin
        return;
      }
      _waiting++;
      convertLinkToStyle(sheet.ownerNode, decrease);
    });

    if (!_waiting) {
      next();
    }
  }

  function origin(url) {
    return url.slice(0, url.indexOf('/', url.indexOf('://') + 3));
  }

  function convertLinkToStyle(link, next) {
    getCors(link.href, function() {
      var style = document.createElement('style');
      style.media = link.media;
      style.textContent = this.responseText;
      link.parentNode.replaceChild(style, link);
      next();
    }, next);
  }

  function getCors(url, success, error) {
    var xhr = new XMLHttpRequest();
    if ('withCredentials' in xhr) {
      // XHR for Chrome/Firefox/Opera/Safari.
      xhr.open('GET', url, true);
    } else if (typeof XDomainRequest !== 'undefined') {
      // XDomainRequest for IE.
      xhr = new XDomainRequest();
      xhr.open('GET', url);
    } else {
      throw new Error('cross-domain XHR not supported');
    }

    xhr.onload = success;
    xhr.onerror = error;
    xhr.send();
    return xhr;
  }

  return {
    version: '0.3.0',
    findProperties: findProperties,
    getCss: getReplacedViewportUnits,
    init: initialize,
    refresh: refresh
  };
}));
<|endoftext|>


<commit_before>window.jermaine.util.namespace("window.ide", function (ns) {
    var Button = ns.models.Button;
    var DirectoryView = ns.views.DirectoryView;

    var IDEView = new window.jermaine.View (function () {
        var messageTimer,
            messageTimeout = 5000;

        this.hasA("directoryView").which.validatesWith(function (v) {
            return v instanceof DirectoryView;
        });

        this.respondsTo("toggleEditorAndDirectory", function () {
            var that = this;
            var direction = $("#ide").is(":visible")?"lr":"rl";
            var elementA = $("#ide").is(":visible")?$("#ide"):$("#IDE-directory");
            var elementB = $("#ide").is(":visible")?$("#IDE-directory"):$("#ide");

            $("#IDE-share").hide();
            $("#IDE-attach").hide();

            elementA.flip({
                speed: 200,
                direction:direction,
                color:"#fff",
                onBefore: function () {
                    elementA.hide();
                },
                onEnd: function () {
                    elementB.show();
                    //this is a hack to force Ace to update when the editor
                    //becomes visible again
                    if ($("#ide").is(":visible")) {
                        that.instance().editor().setValue(that.instance().editor().getValue());
                        that.instance().editor().gotoLine(0,0);
                    }

                }
            });
        });

        this.respondsTo("addButtons", function () {
            var that = this;

            //this.instance().buttons().add(new Button("run", "ide/images/icons/run.png", function () {
            this.instance().buttons().add(new Button("run", "icon-play", function () {
                that.instance().messages().add("running program");
                return false;
            }));

            if ($("#ide").hasClass("server")) {
                //this.instance().buttons().add(new Button("save", "ide/images/icons/save.png", function () {
                this.instance().buttons().add(new Button("save", "icon-save", function () {
                    if (that.instance().changedFlag() === false) {
                        that.instance().messages().add("no changes need to be saved");
                    } else {
                        that.instance().project().source(that.instance().editor().getSession().getValue());
                        that.instance().project().save(function (response) {
                            that.instance().messages().add(response);
                            that.instance().changedFlag(false);
                        });
                    }
                }));

                //this.instance().buttons().add(new Button("share", "ide/images/icons/share.png", function () {
                this.instance().buttons().add(new Button("share", "icon-globe", function () {
                    var project = that.instance().project(),
                        code = that.instance().editor().getSession().getValue(),
                        shareValueTemplate = Handlebars.compile($.trim($("#share-content-template").html())),
                        shareTemplate = Handlebars.compile($.trim($("#share-template").html())),
                        url = "http://"+window.location.host +
                              "/"+project.user()+"/" +
                              project.url().match(/sketches\/(.*).json/)[1] +
                              "/embed/";

                    var dims = code.match(/size\s*\(\s*(\d+)\s*,\s*(\d+)/);

                    if (dims !== null && dims.length === 3) {
                        width = dims[1];
                        height = dims[2];
                    } else {
                        width = 200;
                        height = 200;
                    }

                    $("#IDE-share").html(shareTemplate({}));
                    $("#IDE-share #share_link").val(shareValueTemplate({"url":url, "width":width, "height":height}));
                    $("#IDE-share").slideToggle();
                    $("#close_share_dropdown").click(function () {
                        $("#IDE-share_button").trigger("click");
                    });
                }));

                //this.instance().buttons().add(new Button("attach", "ide/images/icons/attach.png", function () {
                this.instance().buttons().add(new Button("attach", "icon-paper-clip", function () {
                    $("#IDE-attach").slideToggle();
                }));
            }

            this.instance().buttons().add(new Button("directory", "icon-home", function () {
                that.toggleEditorAndDirectory();
            }));
        });

        this.respondsTo("setUpAttachButton", function () {
            var that = this;

            var validFile = function(filename)  {
                var validList = ['jpg','jpeg','gif','png','svg'];
                var i;
                if(filename.match(/\.(jpg|jpeg|gif|png|svg)$/))  {
                    return true;
                }  else  {
                    return false;
                }
            };

            attachTemplate = Handlebars.compile($.trim($("#attach-template").html()));
            $("#IDE-attach").html(attachTemplate());
            $("#close_attach_dropdown").click(function () {
                $("#IDE-attach_button").trigger("click");
            });

            $("#attach_submit_button").click(function(evt)  {
                var file = $("input#file_input").val();
                var postURL = that.instance().project().url().match(/(.*).json/)[1]+"/attach/";
                if(file === "")  {
                    alert("please select a file");
                } else if(!validFile(file))  {
                    alert("sorry, we only work with jpg, jpeg, gif, png and svg at this time");
                }  else  {
                    $.ajax({
                        url: postURL,
                        type: "post",
                        dataType: "JSON",
                        data: {
                            "file": file
                        },
                        success: function(res) {
                            //console.log("got an S3 policy!");
                            $("#filename").val(res.filename);
                            $("#policy").val(res.s3PolicyBase64);
                            $("#accessKey").val(res.s3Key);
                            $("#signature").val(res.s3Signature);
                            that.instance().messages().add("file successfully attached");
                            $("#IDE-attach_button").trigger("click");
                            $("#attach_form").submit();
                            that.instance().project().resources().add({"filename":file.replace(/ /g, "_").split("\\").slice(-1)[0]});
                            $("#file_input").val("");
                            //fileAttached("File Attached!!!!!");
                        },
                        error: function(res, status, err) {
                            console.log("S3 policy error: " + err + " (" + status + ")");
                        }
                    });
                }

                return false;
            });
        });

        this.respondsTo("setUpProcessingRunner", function () {
            var p;  //processing object
            var error;  //processing error
            var that = this;

            $("#IDE-run_button").colorbox({
                'title' : this.instance().project().title(),
                'inline' : true,
                'scrolling' : false,
                'href':"#canvas",
                'onLoad' : function()  {
                    var width, height;
                    var code = that.instance().editor().getSession().getValue();
                    var canvas = document.getElementById("processing_canvas");
                    canvas.getContext('2d').clearRect(0, 0, canvas.width, canvas.height);
                    error = null;

                    try  {
                        var dimensions = code.match(/\s+size\((\d+),(\d+)\)/);
                        if (dimensions !== null) {
                            width = parseInt(dimensions[1]);
                            height = parseInt(dimensions[2]);
                        } else {
                            width = 200;
                            height = 200;
                        }
                        $("#processing_canvas").css('width',width);
                        $("#processing_canvas").css('height',height);
                        p = new Processing(canvas, code);
                    }
                    catch(err)  {
                        error = err;
                        Processing.logger.log(err);
                        if(p)  {
                            p.exit();
                        }
                    }
                },

                'onComplete' : function()  {
                    if(error)  {
                        console.log(error);
                        $.colorbox.close();
                    } else  {
                        if (p) {
                            p.exit();
                        }
                        $("#processing_canvas").focus();
                    }
                },
                'onCleanup' : function()  {
                    if(p)  {
                        p.exit();
                    }
                }
            });
        });

        this.initializesWith(function () {
            var that = this;

            this.addButtons();
            this.setUpAttachButton();
        });

        this.watches("messages", function (newMessage) {
            if (messageTimer !== null) {
                clearTimeout(messageTimer);
            }

            $("#IDE-message").css("display", "none");
            $("#IDE-message").text(newMessage);
            $("#IDE-message").fadeIn();

            messageTimer = setTimeout(function()  {
                $("#IDE-message").fadeOut();
            }, messageTimeout);
        });

        this.watches("project", function (newProject) {
            $("#IDE-directory #" + this.instance().project().url().match(/\/(.*)\.json/)[1])
                .addClass("active")
                .removeClass("inactive");
            this.setUpProcessingRunner();
            $("#resource_list").empty();
        });

        this.watches("project.resources", function (newResource) {
            var that = this;

            var resourceTemplate = Handlebars.compile($.trim($("#resource-entry-partial").html())),
                elt = $(resourceTemplate({"filename":newResource.filename}));

            elt.children(".delete_resource_button").click(function () {
                var eltToRemove = $(this).parent();
                var postURL = that.instance().project().url().match(/(.*).json/)[1]+"/"+newResource.filename+"/remove/";
                if (confirm("Are you sure you want to delete " + newResource.filename + " from this sketch?")) {
                    $.post(postURL, {}, function (response) {
                        that.instance().messages().add(response);
                        eltToRemove.fadeOut(function () {
                            eltToRemove.remove();
                        });
                    });
                };
            });
            $("#resource_list").append(elt);
        });

        this.watches("project.title", function (newTitle) {
            $("#IDE-title").text(newTitle);
        });

        this.watches("project.source", function (newSource) {
            this.instance().editor().getSession().setValue(newSource);
            this.instance().changedFlag(false);
        });

        this.watches("buttons", function (newButton) {
            var button = $($.trim(newButton.view().render()));
            //add click function
            button.click(function () {
                newButton.handler()();
            });
            $("#IDE-buttons").append(button);
        });

        this.watches("directory", function (newDirectory) {
            this.directoryView(new DirectoryView(newDirectory, this));
        });
    });

    ns.views.IDEView = IDEView;
});
<commit_msg>fix bug introduced by previous commit<commit_after>window.jermaine.util.namespace("window.ide", function (ns) {
    var Button = ns.models.Button;
    var DirectoryView = ns.views.DirectoryView;

    var IDEView = new window.jermaine.View (function () {
        var messageTimer,
            messageTimeout = 5000;

        this.hasA("directoryView").which.validatesWith(function (v) {
            return v instanceof DirectoryView;
        });

        this.respondsTo("toggleEditorAndDirectory", function () {
            var that = this;
            var direction = $("#ide").is(":visible")?"lr":"rl";
            var elementA = $("#ide").is(":visible")?$("#ide"):$("#IDE-directory");
            var elementB = $("#ide").is(":visible")?$("#IDE-directory"):$("#ide");

            $("#IDE-share").hide();
            $("#IDE-attach").hide();

            elementA.flip({
                speed: 200,
                direction:direction,
                color:"#fff",
                onBefore: function () {
                    elementA.hide();
                },
                onEnd: function () {
                    elementB.show();
                    //this is a hack to force Ace to update when the editor
                    //becomes visible again
                    if ($("#ide").is(":visible")) {
                        that.instance().editor().setValue(that.instance().editor().getValue());
                        that.instance().editor().gotoLine(0,0);
                    }

                }
            });
        });

        this.respondsTo("addButtons", function () {
            var that = this;

            //this.instance().buttons().add(new Button("run", "ide/images/icons/run.png", function () {
            this.instance().buttons().add(new Button("run", "icon-play", function () {
                that.instance().messages().add("running program");
                return false;
            }));

            if ($("#ide").hasClass("server")) {
                //this.instance().buttons().add(new Button("save", "ide/images/icons/save.png", function () {
                this.instance().buttons().add(new Button("save", "icon-save", function () {
                    if (that.instance().changedFlag() === false) {
                        that.instance().messages().add("no changes need to be saved");
                    } else {
                        that.instance().project().source(that.instance().editor().getSession().getValue());
                        that.instance().project().save(function (response) {
                            that.instance().messages().add(response);
                            that.instance().changedFlag(false);
                        });
                    }
                }));

                //this.instance().buttons().add(new Button("share", "ide/images/icons/share.png", function () {
                this.instance().buttons().add(new Button("share", "icon-globe", function () {
                    var project = that.instance().project(),
                        code = that.instance().editor().getSession().getValue(),
                        shareValueTemplate = Handlebars.compile($.trim($("#share-content-template").html())),
                        shareTemplate = Handlebars.compile($.trim($("#share-template").html())),
                        url = "http://"+window.location.host +
                              "/"+project.user()+"/" +
                              project.url().match(/sketches\/(.*).json/)[1] +
                              "/embed/";

                    var dims = code.match(/size\s*\(\s*(\d+)\s*,\s*(\d+)/);

                    if (dims !== null && dims.length === 3) {
                        width = dims[1];
                        height = dims[2];
                    } else {
                        width = 200;
                        height = 200;
                    }

                    $("#IDE-share").html(shareTemplate({}));
                    $("#IDE-share #share_link").val(shareValueTemplate({"url":url, "width":width, "height":height}));
                    $("#IDE-share").slideToggle();
                    $("#close_share_dropdown").click(function () {
                        $("#IDE-share_button").trigger("click");
                    });
                }));

                //this.instance().buttons().add(new Button("attach", "ide/images/icons/attach.png", function () {
                this.instance().buttons().add(new Button("attach", "icon-paper-clip", function () {
                    $("#IDE-attach").slideToggle();
                }));
            }

            this.instance().buttons().add(new Button("directory", "icon-home", function () {
                that.toggleEditorAndDirectory();
            }));
        });

        this.respondsTo("setUpAttachButton", function () {
            var that = this;

            var validFile = function(filename)  {
                var validList = ['jpg','jpeg','gif','png','svg'];
                var i;
                if(filename.match(/\.(jpg|jpeg|gif|png|svg)$/))  {
                    return true;
                }  else  {
                    return false;
                }
            };

            attachTemplate = Handlebars.compile($.trim($("#attach-template").html()));
            $("#IDE-attach").html(attachTemplate());
            $("#close_attach_dropdown").click(function () {
                $("#IDE-attach_button").trigger("click");
            });

            $("#attach_submit_button").click(function(evt)  {
                var file = $("input#file_input").val();
                var postURL = that.instance().project().url().match(/(.*).json/)[1]+"/attach/";
                if(file === "")  {
                    alert("please select a file");
                } else if(!validFile(file))  {
                    alert("sorry, we only work with jpg, jpeg, gif, png and svg at this time");
                }  else  {
                    $.ajax({
                        url: postURL,
                        type: "post",
                        dataType: "JSON",
                        data: {
                            "file": file
                        },
                        success: function(res) {
                            //console.log("got an S3 policy!");
                            $("#filename").val(res.filename);
                            $("#policy").val(res.s3PolicyBase64);
                            $("#accessKey").val(res.s3Key);
                            $("#signature").val(res.s3Signature);
                            that.instance().messages().add("file successfully attached");
                            $("#IDE-attach_button").trigger("click");
                            $("#attach_form").submit();
                            that.instance().project().resources().add({"filename":file.replace(/ /g, "_").split("\\").slice(-1)[0]});
                            $("#file_input").val("");
                            //fileAttached("File Attached!!!!!");
                        },
                        error: function(res, status, err) {
                            console.log("S3 policy error: " + err + " (" + status + ")");
                        }
                    });
                }

                return false;
            });
        });

        this.respondsTo("setUpProcessingRunner", function () {
            var p;  //processing object
            var error;  //processing error
            var that = this;

            $("#IDE-run_button").colorbox({
                'title' : this.instance().project().title(),
                'inline' : true,
                'scrolling' : false,
                'href':"#canvas",
                'onLoad' : function()  {
                    var width, height;
                    var code = that.instance().editor().getSession().getValue();
                    var canvas = document.getElementById("processing_canvas");
                    canvas.getContext('2d').clearRect(0, 0, canvas.width, canvas.height);
                    error = null;

                    try  {
                        var dimensions = code.match(/\s+size\((\d+),(\d+)\)/);
                        if (dimensions !== null) {
                            width = parseInt(dimensions[1]);
                            height = parseInt(dimensions[2]);
                        } else {
                            width = 200;
                            height = 200;
                        }
                        $("#processing_canvas").css('width',width);
                        $("#processing_canvas").css('height',height);
                        p = new Processing(canvas, code);
                    }
                    catch(err)  {
                        error = err;
                        Processing.logger.log(err);
                        if(p)  {
                            p.exit();
                        }
                    }
                },

                'onComplete' : function()  {
                    if(error)  {
                        console.log(error);
                        $.colorbox.close();
                    } else  {
                        $("#processing_canvas").focus();
                    }
                },
                'onCleanup' : function()  {
                    if(p)  {
                        p.exit();
                    }
                }
            });
        });

        this.initializesWith(function () {
            var that = this;

            this.addButtons();
            this.setUpAttachButton();
        });

        this.watches("messages", function (newMessage) {
            if (messageTimer !== null) {
                clearTimeout(messageTimer);
            }

            $("#IDE-message").css("display", "none");
            $("#IDE-message").text(newMessage);
            $("#IDE-message").fadeIn();

            messageTimer = setTimeout(function()  {
                $("#IDE-message").fadeOut();
            }, messageTimeout);
        });

        this.watches("project", function (newProject) {
            $("#IDE-directory #" + this.instance().project().url().match(/\/(.*)\.json/)[1])
                .addClass("active")
                .removeClass("inactive");
            this.setUpProcessingRunner();
            $("#resource_list").empty();
        });

        this.watches("project.resources", function (newResource) {
            var that = this;

            var resourceTemplate = Handlebars.compile($.trim($("#resource-entry-partial").html())),
                elt = $(resourceTemplate({"filename":newResource.filename}));

            elt.children(".delete_resource_button").click(function () {
                var eltToRemove = $(this).parent();
                var postURL = that.instance().project().url().match(/(.*).json/)[1]+"/"+newResource.filename+"/remove/";
                if (confirm("Are you sure you want to delete " + newResource.filename + " from this sketch?")) {
                    $.post(postURL, {}, function (response) {
                        that.instance().messages().add(response);
                        eltToRemove.fadeOut(function () {
                            eltToRemove.remove();
                        });
                    });
                };
            });
            $("#resource_list").append(elt);
        });

        this.watches("project.title", function (newTitle) {
            $("#IDE-title").text(newTitle);
        });

        this.watches("project.source", function (newSource) {
            this.instance().editor().getSession().setValue(newSource);
            this.instance().changedFlag(false);
        });

        this.watches("buttons", function (newButton) {
            var button = $($.trim(newButton.view().render()));
            //add click function
            button.click(function () {
                newButton.handler()();
            });
            $("#IDE-buttons").append(button);
        });

        this.watches("directory", function (newDirectory) {
            this.directoryView(new DirectoryView(newDirectory, this));
        });
    });

    ns.views.IDEView = IDEView;
});
<|endoftext|>


<commit_before>#!/usr/bin/env node

'use strict';

require('../').globalize();

var mNodgine = require('../'),
    mArgs = process.argv.slice(2),
    mFs = require('fs'),
    mPath = require('path');

if (mArgs[0] && mPath.extname(mArgs[0]) === '.json') {
    if (mFs.existsSync(mArgs[0])) {
        mNodgine.loadFromFile(mPath.resolve(process.cwd(), mArgs[0]));
        console.log('Load successful');
    }
    else {
        console.log('Can\'t find ' + mArgs[0]);
    }
}
else {
    console.log('Usage:');
    console.log('    nodgine <filename>');
    console.log('Example:');
    console.log('    nodgine test.json');
}<commit_msg>Removed globalize on every nodgine terminal call<commit_after>#!/usr/bin/env node

'use strict';

var mNodgine = require('../'),
    mArgs = process.argv.slice(2),
    mFs = require('fs'),
    mPath = require('path');

if (mArgs[0] && mPath.extname(mArgs[0]) === '.json') {
    if (mFs.existsSync(mArgs[0])) {
        mNodgine.loadFromFile(mPath.resolve(process.cwd(), mArgs[0]));
        console.log('Load successful');
    }
    else {
        console.log('Can\'t find ' + mArgs[0]);
    }
}
else {
    console.log('Usage:');
    console.log('    nodgine <filename>');
    console.log('Example:');
    console.log('    nodgine test.json');
}<|endoftext|>


<commit_before>#!/usr/bin/env node
const Promise = require('bluebird');
const _ = require('lodash');
const moment = require('moment');
const debug = require('debug')('bin:parserv');
const nconf= require('nconf');

const mongo = require('../lib/mongo');
const parse = require('../lib/parse');
const echoes = require('../lib/echoes');

nconf.argv().env().file({ file: 'config/collector.json' });

const concur = _.isUndefined(nconf.get('concurrency') ) ? 1 : _.parseInt(nconf.get('concurrency') );
const FREQUENCY = 2; // seconds

const backInTime = _.parseInt(nconf.get('minutesago')) ? _.parseInt(nconf.get('minutesago')) : 10;
console.log(`considering the product since ${backInTime} minutes ago, [minutesago] overrides`);

var lastExecution = moment().subtract(backInTime, 'minutes').toISOString();
var lastCycleActive = false;

function getLastActive() {

    return mongo
        .read(nconf.get('schema').supporters, { lastActivity: { $gt: new Date(lastExecution) }})
        .map(function(user) {
            return user.userId;
        });
}

function infiniteLoop() {
    /* this will launch other scheduled tasks too */
    return Promise
        .resolve()
        .delay(FREQUENCY * 1000)
        .then(getLastActive)
        .map(function(userId) {
            if(lastCycleActive)
                debug("Last successful execution was at %s", lastExecution);
            let htmlFilter = { userId: userId, savingTime: { $gt: new Date(lastExecution) }};
            return parse
                .parseHTML(htmlFilter, false);
        }, { concurrency: 1})
        .tap(function(results) {
            lastExecution = moment().toISOString();

            if(_.size(results)) {
                debug("updated lastExection: %s, results: %s",
                    lastExecution, JSON.stringify(results)
                );
                lastCycleActive = true;
                logActivity(results);
            } else {
                lastCycleActive = false;
            }
        })
        .then(infiniteLoop);
};

function logActivity(results) {
    /* results contain an aggregated sum, such as:
       [ {
        "metadata": 8,
        "errors": 0
       } ]                                         */
    echoes.echo({
        id: Math.round((new Date()).getTime() / 1000),
        success: _.first(results).metadata,
        errors: _.first(results).errors,
        completedAt: new Date()
    });
};

infiniteLoop();
<commit_msg>forgotten index about ELK echoes<commit_after>#!/usr/bin/env node
const Promise = require('bluebird');
const _ = require('lodash');
const moment = require('moment');
const debug = require('debug')('bin:parserv');
const nconf= require('nconf');

const mongo = require('../lib/mongo');
const parse = require('../lib/parse');
const echoes = require('../lib/echoes');

nconf.argv().env().file({ file: 'config/collector.json' });

const concur = _.isUndefined(nconf.get('concurrency') ) ? 1 : _.parseInt(nconf.get('concurrency') );
const FREQUENCY = 2; // seconds

const backInTime = _.parseInt(nconf.get('minutesago')) ? _.parseInt(nconf.get('minutesago')) : 10;
console.log(`considering the product since ${backInTime} minutes ago, [minutesago] overrides`);

var lastExecution = moment().subtract(backInTime, 'minutes').toISOString();
var lastCycleActive = false;

function getLastActive() {

    return mongo
        .read(nconf.get('schema').supporters, { lastActivity: { $gt: new Date(lastExecution) }})
        .map(function(user) {
            return user.userId;
        });
}

function infiniteLoop() {
    /* this will launch other scheduled tasks too */
    return Promise
        .resolve()
        .delay(FREQUENCY * 1000)
        .then(getLastActive)
        .map(function(userId) {
            if(lastCycleActive)
                debug("Last successful execution was at %s", lastExecution);
            let htmlFilter = { userId: userId, savingTime: { $gt: new Date(lastExecution) }};
            return parse
                .parseHTML(htmlFilter, false);
        }, { concurrency: 1})
        .tap(function(results) {
            lastExecution = moment().toISOString();

            if(_.size(results)) {
                debug("updated lastExection: %s, results: %s",
                    lastExecution, JSON.stringify(results)
                );
                lastCycleActive = true;
                logActivity(results);
            } else {
                lastCycleActive = false;
            }
        })
        .then(infiniteLoop);
};

function logActivity(results) {
    /* results contain an aggregated sum, such as:
       [ {
        "metadata": 8,
        "errors": 0
       } ]                                         */
    echoes.echo({
        index: "parserv",
        id: Math.round((new Date()).getTime() / 1000),
        success: _.first(results).metadata,
        errors: _.first(results).errors,
        completedAt: new Date()
    });
};

infiniteLoop();
<|endoftext|>


<commit_before>/**
 * Copyright (c) 2019 The xterm.js authors. All rights reserved.
 * @license MIT
 */

const cp = require('child_process');
const fs = require('fs');
const path = require('path');

// Setup auth
fs.writeFileSync(`${process.env['HOME']}/.npmrc`, `//registry.npmjs.org/:_authToken=${process.env['NPM_AUTH_TOKEN']}`);

const isDryRun = process.argv.indexOf('--dry') !== -1;
if (isDryRun) {
  console.log('Publish dry run');
}

const publishablePackages = [
  path.resolve(__dirname, '..'),
  path.resolve(__dirname, '../addons/xterm-addon-attach'),
  path.resolve(__dirname, '../addons/xterm-addon-fit'),
  path.resolve(__dirname, '../addons/xterm-addon-search'),
  path.resolve(__dirname, '../addons/xterm-addon-web-links')
];

publishablePackages.forEach(p => checkAndPublishPackage(p));

function checkAndPublishPackage(packageDir) {
  const packageJson = require(path.join(packageDir, 'package.json'));
  console.group('Checking package ' + packageJson.name);

  // Determine if this is a stable or beta release
  const publishedVersions = getPublishedVersions(packageJson);
  const isStableRelease = publishedVersions.indexOf(packageJson.version) === -1;

  // Get the next version
  let nextVersion = isStableRelease ? packageJson.version : getNextBetaVersion(packageJson);
  console.log(`Publishing version: ${nextVersion}`);

  // Set the version in package.json
  const packageJsonFile = path.join(packageDir, 'package.json');
  packageJson.version = nextVersion;
  if (isDryRun) {
    console.log(`Set version of ${packageJsonFile} to ${nextVersion}`);
  } else {
    fs.writeFileSync(packageJsonFile, JSON.stringify(packageJson, null, 2));
  }

  // Publish
  const args = ['publish'];
  if (!isStableRelease) {
    args.push('--tag', 'beta');
  }
  if (isDryRun) {
    console.log(`Spawn: npm ${args.join(' ')}`);
  } else {
    const result = cp.spawn('npm', args, { stdio: 'inherit' });
    result.on('exit', code => process.exit(code));
  }

  console.groupEnd();
}

function getNextBetaVersion(packageJson) {
  if (!/^[0-9]+\.[0-9]+\.[0-9]+$/.exec(packageJson.version)) {
    console.error('The package.json version must be of the form x.y.z');
    process.exit(1);
  }
  const tag = 'beta';
  const stableVersion = packageJson.version.split('.');
  const nextStableVersion = `${stableVersion[0]}.${parseInt(stableVersion[1]) + 1}.0`;
  const publishedVersions = getPublishedVersions(packageJson, nextStableVersion, tag);
  if (publishedVersions.length === 0) {
    return `${nextStableVersion}-${tag}1`;
  }
  const latestPublishedVersion = publishedVersions.sort((a, b) => {
    const aVersion = parseInt(a.substr(a.search(/[0-9]+$/)));
    const bVersion = parseInt(b.substr(b.search(/[0-9]+$/)));
    return aVersion > bVersion ? -1 : 1;
  })[0];
  const latestTagVersion = parseInt(latestPublishedVersion.substr(latestPublishedVersion.search(/[0-9]+$/)), 10);
  return `${nextStableVersion}-${tag}${latestTagVersion + 1}`;
}

function getPublishedVersions(packageJson, version, tag) {
  const versionsProcess = cp.spawnSync('npm', ['view', packageJson.name, 'versions', '--json']);
  const versionsJson = JSON.parse(versionsProcess.stdout);
  if (tag) {
    return versionsJson.filter(v => !v.search(new RegExp(`${version}-${tag}[0-9]+`)));
  }
  return versionsJson;
}
<commit_msg>Publish addons and xterm based on whether files changed<commit_after>/**
 * Copyright (c) 2019 The xterm.js authors. All rights reserved.
 * @license MIT
 */

const cp = require('child_process');
const fs = require('fs');
const path = require('path');

// Setup auth
fs.writeFileSync(`${process.env['HOME']}/.npmrc`, `//registry.npmjs.org/:_authToken=${process.env['NPM_AUTH_TOKEN']}`);

const isDryRun = process.argv.indexOf('--dry') !== -1;
if (isDryRun) {
  console.log('Publish dry run');
}

const addonPackageDirs = [
  path.resolve(__dirname, '../addons/xterm-addon-attach'),
  path.resolve(__dirname, '../addons/xterm-addon-fit'),
  path.resolve(__dirname, '../addons/xterm-addon-search'),
  path.resolve(__dirname, '../addons/xterm-addon-web-links')
];

const changedFiles = getChangedFilesInCommit('HEAD');

// Publish xterm if any files were changed outside of the addons directory
if (changedFiles.some(e => e.search(/^addons\//) === -1)) {
  checkAndPublishPackage(path.resolve(__dirname, '..'));
}

// Publish addons if any files were changed inside of the addon
addonPackageDirs.forEach(p => {
  const addon = path.basename(p);
  if (changedFiles.some(e => e.indexOf(addon) !== -1)) {
    checkAndPublishPackage(p);
  }
});

function checkAndPublishPackage(packageDir) {
  const packageJson = require(path.join(packageDir, 'package.json'));

  // Determine if this is a stable or beta release
  const publishedVersions = getPublishedVersions(packageJson);
  const isStableRelease = publishedVersions.indexOf(packageJson.version) === -1;

  // Get the next version
  let nextVersion = isStableRelease ? packageJson.version : getNextBetaVersion(packageJson);
  console.log(`Publishing version: ${nextVersion}`);

  // Set the version in package.json
  const packageJsonFile = path.join(packageDir, 'package.json');
  packageJson.version = nextVersion;
  if (isDryRun) {
    console.log(`Set version of ${packageJsonFile} to ${nextVersion}`);
  } else {
    fs.writeFileSync(packageJsonFile, JSON.stringify(packageJson, null, 2));
  }

  // Publish
  const args = ['publish'];
  if (!isStableRelease) {
    args.push('--tag', 'beta');
  }
  if (isDryRun) {
    console.log(`Spawn: npm ${args.join(' ')}`);
  } else {
    const result = cp.spawn('npm', args, { stdio: 'inherit' });
    result.on('exit', code => process.exit(code));
  }

  console.groupEnd();
}

function getNextBetaVersion(packageJson) {
  if (!/^[0-9]+\.[0-9]+\.[0-9]+$/.exec(packageJson.version)) {
    console.error('The package.json version must be of the form x.y.z');
    process.exit(1);
  }
  const tag = 'beta';
  const stableVersion = packageJson.version.split('.');
  const nextStableVersion = `${stableVersion[0]}.${parseInt(stableVersion[1]) + 1}.0`;
  const publishedVersions = getPublishedVersions(packageJson, nextStableVersion, tag);
  if (publishedVersions.length === 0) {
    return `${nextStableVersion}-${tag}1`;
  }
  const latestPublishedVersion = publishedVersions.sort((a, b) => {
    const aVersion = parseInt(a.substr(a.search(/[0-9]+$/)));
    const bVersion = parseInt(b.substr(b.search(/[0-9]+$/)));
    return aVersion > bVersion ? -1 : 1;
  })[0];
  const latestTagVersion = parseInt(latestPublishedVersion.substr(latestPublishedVersion.search(/[0-9]+$/)), 10);
  return `${nextStableVersion}-${tag}${latestTagVersion + 1}`;
}

function getPublishedVersions(packageJson, version, tag) {
  const versionsProcess = cp.spawnSync('npm', ['view', packageJson.name, 'versions', '--json']);
  const versionsJson = JSON.parse(versionsProcess.stdout);
  if (tag) {
    return versionsJson.filter(v => !v.search(new RegExp(`${version}-${tag}[0-9]+`)));
  }
  return versionsJson;
}

function getChangedFilesInCommit(commit) {
  const args = ['log', '-m', '-1', '--name-only', `--pretty=format:`, commit];
  const result = cp.spawnSync('git', args);
  const output = result.stdout.toString();
  const changedFiles = output.split('\n').filter(e => e.length > 0);
  return changedFiles;
}
<|endoftext|>


<commit_before>#!/usr/bin/env node
'use strict';

process.env.NODE_ENV = 'production';

const serverImpl = require('../lib/server-impl.js');

const argv = require('yargs')
    .usage('$0 [options]')
    .env(true)
    .option('port', {
        alias: 'p',
        describe: 'The HTTP port you want to start unleash on',
        demand: false,
        default: 4242,
        type: 'number',
    })
    .option('host', {
        alias: 'l',
        describe: 'The HTTP address the server will accept connections on.',
        demand: false,
        type: 'string',
    })
    .option('databaseUrl', {
        alias: 'd',
        describe:
            'The full databaseUrl to connect to, including username and password',
        demand: true,
        type: 'string',
    }).argv;

serverImpl
    .start(argv)
    .then(instance => {
        console.log(
            `Unleash started on http://${instance.server.address().address}:${
                instance.server.address().port
            }`
        );
    })
    .catch(console.err);
<commit_msg>refactor<commit_after>#!/usr/bin/env node
'use strict';

process.env.NODE_ENV = 'production';

const serverImpl = require('../lib/server-impl.js');

const argv = require('yargs')
    .usage('$0 [options]')
    .env(true)
    .option('port', {
        alias: 'p',
        describe: 'The HTTP port you want to start unleash on',
        demand: false,
        default: 4242,
        type: 'number',
    })
    .option('host', {
        alias: 'l',
        describe: 'The HTTP address the server will accept connections on.',
        demand: false,
        type: 'string',
    })
    .option('databaseUrl', {
        alias: 'd',
        describe:
            'The full databaseUrl to connect to, including username and password',
        demand: true,
        type: 'string',
    }).argv;

serverImpl
    .start(argv)
    .then(instance => {
        const address = instance.server.address();
        console.log(
            `Unleash started on http://${address.address}:${address.port}`
        );
    })
    .catch(console.err);
<|endoftext|>


<commit_before>import React from 'react';
import Document, {
  Html,
  Head,
  Main,
  NextScript,
} from 'next/document';

class MyDocument extends Document {
  render() {
    return (