<commit_before>var gulp = require('gulp');
var filter = require('gulp-filter');
var cleancss = require('gulp-clean-css');
var rename = require('gulp-rename');
var uglify = require('gulp-uglify');
var replace = require('gulp-replace');
var octophant = require('octophant');
var readline = require('readline');
var { green, bold } = require('kleur');
var exec = require('child_process').execSync;
var plumber = require('gulp-plumber');
var sourcemaps = require('gulp-sourcemaps');
var rollup = require('rollup');

var ROLLUP_CONFIG = require('../../rollup.config.js');
var CONFIG = require('../config.js');
var CURRENT_VERSION = require('../../package.json').version;
var NEXT_VERSION;

gulp.task('deploy', gulp.series('deploy:prompt', 'deploy:version', 'deploy:dist', 'deploy:plugins', 'deploy:settings', 'deploy:commit', 'deploy:templates'));

gulp.task('deploy:prep', gulp.series('deploy:prompt', 'deploy:version', 'deploy:dist', 'deploy:plugins', 'deploy:settings'));
gulp.task('deploy:dist', gulp.series('sass:foundation', 'javascript:foundation', 'deploy:dist:files', 'deploy:dist:bundles'));
gulp.task('deploy:plugins', gulp.series('deploy:plugins:sources', 'deploy:plugins:sourcemaps'));

gulp.task('deploy:prompt', function(cb) {
  var rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout
  });

  rl.question(
    green('?') + ' ' + bold('What version are we moving to? (Current version is ' + CURRENT_VERSION + ') '),
    (version) => {
      NEXT_VERSION = version
        ? version
        : CURRENT_VERSION;
      rl.close();
      cb();
    }
  );
});

// Bumps the version number in any file that has one
gulp.task('deploy:version', function() {
  return gulp.src(CONFIG.VERSIONED_FILES, { base: process.cwd() })
  .pipe(replace(CURRENT_VERSION, NEXT_VERSION))
  .pipe(gulp.dest('.'));
});

// Generates compiled CSS and JS files and sourcemaps and puts them in the dist/ folder
gulp.task('deploy:dist:files', function() {
  var cssFilter = filter(['**/*.css'], { restore: true });
  var jsFilter  = filter(['**/*.js'], { restore: true });
  var cssSourcemapFilter = filter(['**/*.css.map'], { restore: true });
  var jsSourcemapFilter = filter(['**/*.js.map'], { restore: true });
  var tsFilter  = filter(['**/*.ts'], { restore: true });

  return gulp.src(CONFIG.DIST_FILES)
    .pipe(plumber())

    // --- Source maps ---
    // * Copy sourcemaps to the dist folder
    // This is done first to avoid collision with minified-sourcemaps.
    .pipe(cssSourcemapFilter)
      .pipe(gulp.dest('./dist/css'))
      .pipe(cssSourcemapFilter.restore)
    .pipe(jsSourcemapFilter)
      .pipe(gulp.dest('./dist/js'))
      .pipe(jsSourcemapFilter.restore)

    // --- Source files ---
    // * Copy source files to dist folder
    // * Create minified files
    // * Create minified-sourcemaps based on standard sourcemaps.
    //   Sourcemaps are initialized before the ".min" renaming to be able retrieve
    //   original sourcemaps from source names.
    .pipe(cssFilter)
      .pipe(gulp.dest('./dist/css'))
      .pipe(sourcemaps.init({ loadMaps: true }))
      .pipe(rename({ suffix: '.min' }))
      .pipe(cleancss({ compatibility: "ie11" }))
      .pipe(sourcemaps.write('.'))
      .pipe(gulp.dest('./dist/css'))
      .pipe(cssFilter.restore)

    .pipe(jsFilter)
      .pipe(gulp.dest('./dist/js'))
      .pipe(sourcemaps.init({ loadMaps: true }))
      .pipe(rename({ suffix: '.min' }))
      .pipe(uglify())
      .pipe(sourcemaps.write('.'))
      .pipe(gulp.dest('./dist/js'))
      .pipe(jsFilter.restore)

    // --- TypeScript files ---
    // * Copy typescript files to the dist folder
    .pipe(tsFilter)
      .pipe(gulp.dest('./dist/js'))
      .pipe(tsFilter.restore);
});

//
// Generates JS bundles and puts them in the dist/ folder.
//
// In addition to the UMD bundle coming from the build task, the following
// formats are generated: CJS, ESM, ES6.
// See "rollup.config.js" for more information.
//
gulp.task('deploy:dist:bundles', gulp.series(
  // Create a subtask for each Rollup config
  ...ROLLUP_CONFIG.map((config) => function () {

    // Run rollup with the Rollup config
    return rollup.rollup(config)
      .then(bundle => bundle.write(config.output));
  })
));

// Copies standalone JavaScript plugins to dist/ folder
gulp.task('deploy:plugins:sources', function () {
  return gulp.src('_build/assets/js/plugins/*.js')
    .pipe(gulp.dest('dist/js/plugins'))
    .pipe(sourcemaps.init({ loadMaps: true }))
    .pipe(rename({ suffix: '.min' }))
    .pipe(uglify())
    .pipe(sourcemaps.write('.'))
    .pipe(gulp.dest('dist/js/plugins'));
});

// Copies standalone JavaScript plugins sourcemaps to dist/ folder
gulp.task('deploy:plugins:sourcemaps', function () {
  return gulp.src('_build/assets/js/plugins/*.js.map')
    .pipe(gulp.dest('dist/js/plugins'));
});

// Generates a settings file
gulp.task('deploy:settings', function(done) {
  var options = {
    title: 'Foundation for Sites Settings',
    output: './scss/settings/_settings.scss',
    groups: {
      'grid': 'The Grid',
      'off-canvas': 'Off-canvas',
      'typography-base': 'Base Typography'
    },
    sort: [
      'global',
      'breakpoints',
      'grid',
      'typography-base',
      'typography-helpers'
    ],
    imports: ['util/util'],
    _foundationShim: true
  }

  octophant('./scss', options, done);
});

// Writes a commit with the changes to the version numbers
gulp.task('deploy:commit', function() {
  exec('git commit -am "Bump to version "' + NEXT_VERSION);
  exec('git tag v' + NEXT_VERSION);
  exec('git push origin develop --follow-tags');
});

// This part of the deploy process hasn't been tested! It should be done manually for now
gulp.task('deploy:templates', function(done) {
  // exec('git clone https://github.com/foundation/foundation-sites-template');
  // exec('cp scss/settings/_settings.scss foundation-sites-template/scss/_settings.scss');
  // exec('cd foundation-sites-template');
  // exec('git commit -am "Update settings file to match Foundation "' + NEXT_VERSION);
  // exec('git push origin master');
  // exec('cd ..');
  // exec('rm -rf foundation-sites-template');
  //
  // exec('git clone https://github.com/foundation/foundation-zurb-template');
  // exec('cp scss/settings/_settings.scss foundation-zurb-template/src/assets/scss/_settings.scss');
  // exec('cd foundation-zurb-template');
  // exec('git commit -am "Update settings file to match Foundation "' + NEXT_VERSION);
  // exec('git push origin master');
  // exec('cd ..');
  // exec('rm -rf foundation-zurb-template');
  done();
});

// The Customizer runs this function to generate files it needs
gulp.task('deploy:custom', gulp.series('sass:foundation', 'javascript:foundation', gulp.parallel(
  function () {
    return gulp.src('./_build/assets/css/foundation.css')
      .pipe(cleancss({ compatibility: 'ie9' }))
      .pipe(rename('foundation.min.css'))
      .pipe(gulp.dest('./_build/assets/css'));
  },
  function () {
    return gulp.src('_build/assets/js/foundation.js')
      .pipe(uglify())
      .pipe(rename('foundation.min.js'))
      .pipe(gulp.dest('./_build/assets/js'));
  }
)));
<commit_msg>build: cleanup dist before deploy<commit_after>var gulp = require('gulp');
var rimraf = require('rimraf');
var filter = require('gulp-filter');
var cleancss = require('gulp-clean-css');
var rename = require('gulp-rename');
var uglify = require('gulp-uglify');
var replace = require('gulp-replace');
var octophant = require('octophant');
var readline = require('readline');
var { green, bold } = require('kleur');
var exec = require('child_process').execSync;
var plumber = require('gulp-plumber');
var sourcemaps = require('gulp-sourcemaps');
var rollup = require('rollup');

var ROLLUP_CONFIG = require('../../rollup.config.js');
var CONFIG = require('../config.js');
var CURRENT_VERSION = require('../../package.json').version;
var NEXT_VERSION;

gulp.task('deploy', gulp.series('deploy:prompt', 'deploy:version', 'deploy:dist', 'deploy:plugins', 'deploy:settings', 'deploy:commit', 'deploy:templates'));

gulp.task('deploy:prep', gulp.series('deploy:prompt', 'deploy:version', 'deploy:dist', 'deploy:plugins', 'deploy:settings'));
gulp.task('deploy:dist', gulp.series('sass:foundation', 'javascript:foundation', 'deploy:dist:clean', 'deploy:dist:files', 'deploy:dist:bundles'));
gulp.task('deploy:plugins', gulp.series('deploy:plugins:sources', 'deploy:plugins:sourcemaps'));

gulp.task('deploy:prompt', function(cb) {
  var rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout
  });

  rl.question(
    green('?') + ' ' + bold('What version are we moving to? (Current version is ' + CURRENT_VERSION + ') '),
    (version) => {
      NEXT_VERSION = version
        ? version
        : CURRENT_VERSION;
      rl.close();
      cb();
    }
  );
});

// Bumps the version number in any file that has one
gulp.task('deploy:version', function() {
  return gulp.src(CONFIG.VERSIONED_FILES, { base: process.cwd() })
  .pipe(replace(CURRENT_VERSION, NEXT_VERSION))
  .pipe(gulp.dest('.'));
});

// Erases the dist folder
gulp.task('deploy:dist:clean', function(done) {
  rimraf('dist/**', done);
});

// Generates compiled CSS and JS files and sourcemaps and puts them in the dist/ folder
gulp.task('deploy:dist:files', function() {
  var cssFilter = filter(['**/*.css'], { restore: true });
  var jsFilter  = filter(['**/*.js'], { restore: true });
  var cssSourcemapFilter = filter(['**/*.css.map'], { restore: true });
  var jsSourcemapFilter = filter(['**/*.js.map'], { restore: true });
  var tsFilter  = filter(['**/*.ts'], { restore: true });

  return gulp.src(CONFIG.DIST_FILES)
    .pipe(plumber())

    // --- Source maps ---
    // * Copy sourcemaps to the dist folder
    // This is done first to avoid collision with minified-sourcemaps.
    .pipe(cssSourcemapFilter)
      .pipe(gulp.dest('./dist/css'))
      .pipe(cssSourcemapFilter.restore)
    .pipe(jsSourcemapFilter)
      .pipe(gulp.dest('./dist/js'))
      .pipe(jsSourcemapFilter.restore)

    // --- Source files ---
    // * Copy source files to dist folder
    // * Create minified files
    // * Create minified-sourcemaps based on standard sourcemaps.
    //   Sourcemaps are initialized before the ".min" renaming to be able retrieve
    //   original sourcemaps from source names.
    .pipe(cssFilter)
      .pipe(gulp.dest('./dist/css'))
      .pipe(sourcemaps.init({ loadMaps: true }))
      .pipe(rename({ suffix: '.min' }))
      .pipe(cleancss({ compatibility: "ie11" }))
      .pipe(sourcemaps.write('.'))
      .pipe(gulp.dest('./dist/css'))
      .pipe(cssFilter.restore)

    .pipe(jsFilter)
      .pipe(gulp.dest('./dist/js'))
      .pipe(sourcemaps.init({ loadMaps: true }))
      .pipe(rename({ suffix: '.min' }))
      .pipe(uglify())
      .pipe(sourcemaps.write('.'))
      .pipe(gulp.dest('./dist/js'))
      .pipe(jsFilter.restore)

    // --- TypeScript files ---
    // * Copy typescript files to the dist folder
    .pipe(tsFilter)
      .pipe(gulp.dest('./dist/js'))
      .pipe(tsFilter.restore);
});

//
// Generates JS bundles and puts them in the dist/ folder.
//
// In addition to the UMD bundle coming from the build task, the following
// formats are generated: CJS, ESM, ES6.
// See "rollup.config.js" for more information.
//
gulp.task('deploy:dist:bundles', gulp.series(
  // Create a subtask for each Rollup config
  ...ROLLUP_CONFIG.map((config) => function () {

    // Run rollup with the Rollup config
    return rollup.rollup(config)
      .then(bundle => bundle.write(config.output));
  })
));

// Copies standalone JavaScript plugins to dist/ folder
gulp.task('deploy:plugins:sources', function () {
  return gulp.src('_build/assets/js/plugins/*.js')
    .pipe(gulp.dest('dist/js/plugins'))
    .pipe(sourcemaps.init({ loadMaps: true }))
    .pipe(rename({ suffix: '.min' }))
    .pipe(uglify())
    .pipe(sourcemaps.write('.'))
    .pipe(gulp.dest('dist/js/plugins'));
});

// Copies standalone JavaScript plugins sourcemaps to dist/ folder
gulp.task('deploy:plugins:sourcemaps', function () {
  return gulp.src('_build/assets/js/plugins/*.js.map')
    .pipe(gulp.dest('dist/js/plugins'));
});

// Generates a settings file
gulp.task('deploy:settings', function(done) {
  var options = {
    title: 'Foundation for Sites Settings',
    output: './scss/settings/_settings.scss',
    groups: {
      'grid': 'The Grid',
      'off-canvas': 'Off-canvas',
      'typography-base': 'Base Typography'
    },
    sort: [
      'global',
      'breakpoints',
      'grid',
      'typography-base',
      'typography-helpers'
    ],
    imports: ['util/util'],
    _foundationShim: true
  }

  octophant('./scss', options, done);
});

// Writes a commit with the changes to the version numbers
gulp.task('deploy:commit', function() {
  exec('git commit -am "Bump to version "' + NEXT_VERSION);
  exec('git tag v' + NEXT_VERSION);
  exec('git push origin develop --follow-tags');
});

// This part of the deploy process hasn't been tested! It should be done manually for now
gulp.task('deploy:templates', function(done) {
  // exec('git clone https://github.com/foundation/foundation-sites-template');
  // exec('cp scss/settings/_settings.scss foundation-sites-template/scss/_settings.scss');
  // exec('cd foundation-sites-template');
  // exec('git commit -am "Update settings file to match Foundation "' + NEXT_VERSION);
  // exec('git push origin master');
  // exec('cd ..');
  // exec('rm -rf foundation-sites-template');
  //
  // exec('git clone https://github.com/foundation/foundation-zurb-template');
  // exec('cp scss/settings/_settings.scss foundation-zurb-template/src/assets/scss/_settings.scss');
  // exec('cd foundation-zurb-template');
  // exec('git commit -am "Update settings file to match Foundation "' + NEXT_VERSION);
  // exec('git push origin master');
  // exec('cd ..');
  // exec('rm -rf foundation-zurb-template');
  done();
});

// The Customizer runs this function to generate files it needs
gulp.task('deploy:custom', gulp.series('sass:foundation', 'javascript:foundation', gulp.parallel(
  function () {
    return gulp.src('./_build/assets/css/foundation.css')
      .pipe(cleancss({ compatibility: 'ie9' }))
      .pipe(rename('foundation.min.css'))
      .pipe(gulp.dest('./_build/assets/css'));
  },
  function () {
    return gulp.src('_build/assets/js/foundation.js')
      .pipe(uglify())
      .pipe(rename('foundation.min.js'))
      .pipe(gulp.dest('./_build/assets/js'));
  }
)));
<|endoftext|>


<commit_before>function runTest()
{
    FBTest.sysout("issue5504.START");

    FBTest.openNewTab(basePath + "html/5504/issue5504.html", function(win)
    {
        FBTest.openFirebug();
        var panel = FBTest.selectPanel("html");

        // Get the selected element and execute "New Attribute" action on it.
        var nodeBox = getSelectedNodeBox();
        FBTest.executeContextMenuCommand(nodeBox, "htmlNewAttribute", function()
        {
            var editor = panel.panelNode.getElementsByClassName("textEditorInner").item(0);
            FBTest.compare("", editor.value, "The default value must be an empty string");
            FBTest.testDone("issue5504.DONE");
        });
    });
}

// xxxHonza: use the one from FBTest (should be in FBTest 1.10b5)
function getSelectedNodeBox()
{
    var panel = FBTest.getPanel("html");
    return panel.panelNode.querySelector(".nodeBox.selected");
}
<commit_msg>Fix FBTest, the inline editor can be opened async on Mac<commit_after>function runTest()
{
    FBTest.sysout("issue5504.START");

    FBTest.openNewTab(basePath + "html/5504/issue5504.html", function(win)
    {
        FBTest.openFirebug();
        var panel = FBTest.selectPanel("html");

        // Get the selected element and execute "New Attribute" action on it.
        var nodeBox = getSelectedNodeBox();
        FBTest.executeContextMenuCommand(nodeBox, "htmlNewAttribute", function()
        {
            // Wait till the inline editor is available.
            var config = {tagName: "input", classes: "textEditorInner"};
            FBTest.waitForDisplayedElement("html", config, function(editor)
            {
                FBTest.compare("", editor.value, "The default value must be an empty string");
                FBTest.testDone("issue5504.DONE");
            });
        });
    });
}

// xxxHonza: use the one from FBTest (should be in FBTest 1.10b5)
function getSelectedNodeBox()
{
    var panel = FBTest.getPanel("html");
    return panel.panelNode.querySelector(".nodeBox.selected");
}
<|endoftext|>


<commit_before>'use strict';

/**
 * This class forms the builder pattern for updating an item.
 *
 * @author Sam Verschueren	  <sam.verschueren@gmail.com>
 * @since  19 Jul. 2015
 */

// module dependencies
var Promise = require('pinkie-promise');
var pify = require('pify');
var objectAssign = require('object-assign');

// utility
var queryUtil = require('../utils/query');
var updateUtil = require('../utils/update');

/**
 * Creates a new update item object that can then be used to built the entire
 * request.
 *
 * @param {string}		    table           The name of the table that should be queried.
 * @param {DOC.DynamoDB}    dynamodb        The dynamodb object that should be used to query to database.
 */
function UpdateItem(table, dynamodb) {
	this._dynamodb = dynamodb;
	this._params = {
		TableName: table,
		ReturnValues: 'ALL_NEW'
	};
}

/**
 * This method will initialize the request with the index query and the data query that has been provided.
 *
 * @param  {object}	        query           The query of the index of the item to update.
 * @param  {object}	        data            The update data object.
 * @return {DeleteItem}                     The delete item object.
 */
UpdateItem.prototype._initialize = function (query, data) {
	// Set the query as key
	this._params.Key = query;

	// Parse the update query
	var parsedUpdate = updateUtil.parse(data);

	// Append the attributes to the correct properties
	this._params.UpdateExpression = parsedUpdate.UpdateExpression;
	this._params.ExpressionAttributeNames = objectAssign({}, this._params.ExpressionAttributeNames, parsedUpdate.ExpressionAttributeNames);
	this._params.ExpressionAttributeValues = objectAssign({}, this._params.ExpressionAttributeValues, parsedUpdate.ExpressionAttributeValues);

	// Return the object so that it can be chained
	return this;
};

/**
 * This will create a conditional update item object where the condition should be satisfied in order for the item to be
 * updated. This should be used if you want to update a record but not insert one if the index does not exist.
 *
 * @param  {object}	    condition           A condition that must be satisfied in order for a conditional UpdateItem to succeed.
 * @return {DeleteItem}	                    The query object.
 */
UpdateItem.prototype._where = function (condition) {
	// Parse the query
	var parsedQuery = queryUtil.parse(condition);

	// Add the parsed query attributes to the correct properties of the params object
	this._params.ConditionExpression = parsedQuery.ConditionExpression;
	this._params.ExpressionAttributeNames = objectAssign({}, this._params.ExpressionAttributeNames, parsedQuery.ExpressionAttributeNames);
	this._params.ExpressionAttributeValues = objectAssign({}, this._params.ExpressionAttributeValues, parsedQuery.ExpressionAttributeValues);

	// Return the object for chaining purposes
	return this;
};

/**
 * This method will execute the update item request that was built up.
 *
 * @return {Promise}                        The promise object that resolves or rejects the promise if something went wrong.
 */
UpdateItem.prototype.exec = function () {
	var dynamodb = this._dynamodb;
	var params = this._params;

	return pify(dynamodb.update.bind(dynamodb), Promise)(params)
		.then(function (data) {
			// Return the attributes
			return data.Attributes;
		});
};

// Export the module
module.exports = UpdateItem;
<commit_msg>Resolve #19 - Insert object only consisting of key<commit_after>'use strict';

/**
 * This class forms the builder pattern for updating an item.
 *
 * @author Sam Verschueren	  <sam.verschueren@gmail.com>
 * @since  19 Jul. 2015
 */

// module dependencies
var Promise = require('pinkie-promise');
var pify = require('pify');
var objectAssign = require('object-assign');

// utility
var queryUtil = require('../utils/query');
var updateUtil = require('../utils/update');

/**
 * Creates a new update item object that can then be used to built the entire
 * request.
 *
 * @param {string}		    table           The name of the table that should be queried.
 * @param {DOC.DynamoDB}    dynamodb        The dynamodb object that should be used to query to database.
 */
function UpdateItem(table, dynamodb) {
	this._dynamodb = dynamodb;
	this._params = {
		TableName: table,
		ReturnValues: 'ALL_NEW'
	};
}

/**
 * This method will initialize the request with the index query and the data query that has been provided.
 *
 * @param  {object}	        query           The query of the index of the item to update.
 * @param  {object}	        data            The update data object.
 * @return {DeleteItem}                     The delete item object.
 */
UpdateItem.prototype._initialize = function (query, data) {
	// Set the query as key
	this._params.Key = query;

	// Parse the update query
	var parsedUpdate = updateUtil.parse(data);

	// Append the attributes to the correct properties
	this._params.UpdateExpression = parsedUpdate.UpdateExpression;
	this._params.ExpressionAttributeNames = objectAssign({}, this._params.ExpressionAttributeNames, parsedUpdate.ExpressionAttributeNames);
	this._params.ExpressionAttributeValues = objectAssign({}, this._params.ExpressionAttributeValues, parsedUpdate.ExpressionAttributeValues);

	// Return the object so that it can be chained
	return this;
};

/**
 * This will create a conditional update item object where the condition should be satisfied in order for the item to be
 * updated. This should be used if you want to update a record but not insert one if the index does not exist.
 *
 * @param  {object}	    condition           A condition that must be satisfied in order for a conditional UpdateItem to succeed.
 * @return {DeleteItem}	                    The query object.
 */
UpdateItem.prototype._where = function (condition) {
	// Parse the query
	var parsedQuery = queryUtil.parse(condition);

	// Add the parsed query attributes to the correct properties of the params object
	this._params.ConditionExpression = parsedQuery.ConditionExpression;
	this._params.ExpressionAttributeNames = objectAssign({}, this._params.ExpressionAttributeNames, parsedQuery.ExpressionAttributeNames);
	this._params.ExpressionAttributeValues = objectAssign({}, this._params.ExpressionAttributeValues, parsedQuery.ExpressionAttributeValues);

	// Return the object for chaining purposes
	return this;
};

/**
 * This method will execute the update item request that was built up.
 *
 * @return {Promise}                        The promise object that resolves or rejects the promise if something went wrong.
 */
UpdateItem.prototype.exec = function () {
	var dynamodb = this._dynamodb;
	var params = this._params;

	if (params.UpdateExpression === '') {
		delete params.ExpressionAttributeNames;
		delete params.ExpressionAttributeValues;
		delete params.UpdateExpression;
	}

	return pify(dynamodb.update.bind(dynamodb), Promise)(params)
		.then(function (data) {
			// Return the attributes
			return data.Attributes;
		});
};

// Export the module
module.exports = UpdateItem;
<|endoftext|>


<commit_before>(function() {

    function isArrayAnswerEmpty(answers) {
        for(var i=0; i<answers.length; i++) {
            if(answers[i]) { return false; }
        }
        return true;
    }

    function testMultiple(valid, answers) {
        var mistakes = [];
        for(var i=0; i<answers.length; i++) {
            if(valid.indexOf(answers[i]) === -1) {
                mistakes.push(answers[i]);
            }
        }
        return mistakes.length == 0 && valid.length == answers.length ? true : mistakes;
    }

    function testStrict(valid, answers) {
        var mistakes = [];
        for(var i=0; i<answers.length; i++) {
            if(valid[i] !== answers[i]) {
                mistakes.push(answers[i]);
            }
        }
        return mistakes.length == 0 && valid.length == answers.length ? true : mistakes;
    }

    window.Quiz.grader.handler = function(grader_data, answer, versions, score_settings) {
        var res = {
            score: 0,
            mistakes: [],
            messages: []
        };
        var isValid;
        var nb_valid = 0;
        var nb_mistakes = 0;
        for (var i = 0; i < grader_data.length; i++) {
            var grader = grader_data[i];
            if(versions && i in versions) {
                grader = grader[versions[i]];
            }
            if (typeof grader === "function") {
                if(!answer[i]) { continue; }
                var fres = grader(answer[i]);
                if (typeof fres === "object") {
                    var score =
                        "score" in fres ? parseFloat(fres.score) || 0 : 0;
                    isValid = score > 0;
                    if ("message" in fres && fres.message) {
                        res.messages[i] = fres.message;
                    }
                    nb_valid += score;
                    nb_mistakes += score > 0 ? 0 : 1;
                } else {
                    isValid = !!fres;
                    nb_valid += isValid ? 1 : 0;
                    nb_mistakes += isValid ? 0 : 1;
                }
                res.mistakes.push(isValid ? null : answer[i]);
            } else if (Array.isArray(grader)) {
                if(isArrayAnswerEmpty(answer[i])) { continue; }
                var test = testMultiple(grader, answer[i]);
                isValid = test === true;
                res.mistakes.push(isValid ? [] : test);
                nb_valid += isValid ? 1 : 0;
                nb_mistakes += isValid ? 0 : 1;
            } else if (typeof grader == 'object') {
                if(Array.isArray(grader.value)) {
                    if(isArrayAnswerEmpty(answer[i])) {
                        continue;
                    }
                    if(grader.strict) {
                        var test = testStrict(grader.value, answer[i]);
                    } else {
                        var test = testMultiple(grader.value, answer[i]);
                    }
                    isValid = test === true;
                    var mistakes = isValid ? [] : test;
                    res.mistakes.push(mistakes);
                    if(grader.messages && mistakes.length) {
                        res.messages[i] = [];
                        for(var j=0; j<mistakes.length; j++) {
                            if(grader.messages[mistakes[j]]) {
                                res.messages[i][mistakes[j]] = grader.messages[mistakes[j]];
                            }
                        }
                    }

                } else {
                    if(typeof answer[i] == 'undefined') { continue; }
                    isValid = grader == answer[i] ? 1 : 0;
                    res.mistakes.push(isValid ? null : answer[i]);
                    if(grader.messages && !isValid && grader.messages[answer[i]]) {
                        res.messages[i] = grader.messages[answer[i]];
                    }
                }
                nb_valid += isValid ? 1 : 0;
                nb_mistakes += isValid ? 0 : 1;
            } else {
                if(!answer[i]) { continue; }
                isValid = grader == answer[i] ? 1 : 0;
                res.mistakes.push(isValid ? null : answer[i]);
                nb_valid += isValid ? 1 : 0;
                nb_mistakes += isValid ? 0 : 1;
            }
        }
        var nb_total = grader_data.length;
        if(score_settings) {
            res.score = (nb_valid * score_settings.maxScore
                       + nb_mistakes * score_settings.minScore
                       + (nb_total - nb_valid - nb_mistakes) * score_settings.noScore) / grader_data.length;
        } else {
            res.score = nb_valid / nb_total;
        }
        res.score = +res.score.toFixed(2);
        return res;
    };

})();
<commit_msg>quiz: round score<commit_after>(function() {

    function isArrayAnswerEmpty(answers) {
        for(var i=0; i<answers.length; i++) {
            if(answers[i]) { return false; }
        }
        return true;
    }

    function testMultiple(valid, answers) {
        var mistakes = [];
        for(var i=0; i<answers.length; i++) {
            if(valid.indexOf(answers[i]) === -1) {
                mistakes.push(answers[i]);
            }
        }
        return mistakes.length == 0 && valid.length == answers.length ? true : mistakes;
    }

    function testStrict(valid, answers) {
        var mistakes = [];
        for(var i=0; i<answers.length; i++) {
            if(valid[i] !== answers[i]) {
                mistakes.push(answers[i]);
            }
        }
        return mistakes.length == 0 && valid.length == answers.length ? true : mistakes;
    }

    window.Quiz.grader.handler = function(grader_data, answer, versions, score_settings) {
        var res = {
            score: 0,
            mistakes: [],
            messages: []
        };
        var isValid;
        var nb_valid = 0;
        var nb_mistakes = 0;
        for (var i = 0; i < grader_data.length; i++) {
            var grader = grader_data[i];
            if(versions && i in versions) {
                grader = grader[versions[i]];
            }
            if (typeof grader === "function") {
                if(!answer[i]) { continue; }
                var fres = grader(answer[i]);
                if (typeof fres === "object") {
                    var score =
                        "score" in fres ? parseFloat(fres.score) || 0 : 0;
                    isValid = score > 0;
                    if ("message" in fres && fres.message) {
                        res.messages[i] = fres.message;
                    }
                    nb_valid += score;
                    nb_mistakes += score > 0 ? 0 : 1;
                } else {
                    isValid = !!fres;
                    nb_valid += isValid ? 1 : 0;
                    nb_mistakes += isValid ? 0 : 1;
                }
                res.mistakes.push(isValid ? null : answer[i]);
            } else if (Array.isArray(grader)) {
                if(isArrayAnswerEmpty(answer[i])) { continue; }
                var test = testMultiple(grader, answer[i]);
                isValid = test === true;
                res.mistakes.push(isValid ? [] : test);
                nb_valid += isValid ? 1 : 0;
                nb_mistakes += isValid ? 0 : 1;
            } else if (typeof grader == 'object') {
                if(Array.isArray(grader.value)) {
                    if(isArrayAnswerEmpty(answer[i])) {
                        continue;
                    }
                    if(grader.strict) {
                        var test = testStrict(grader.value, answer[i]);
                    } else {
                        var test = testMultiple(grader.value, answer[i]);
                    }
                    isValid = test === true;
                    var mistakes = isValid ? [] : test;
                    res.mistakes.push(mistakes);
                    if(grader.messages && mistakes.length) {
                        res.messages[i] = [];
                        for(var j=0; j<mistakes.length; j++) {
                            if(grader.messages[mistakes[j]]) {
                                res.messages[i][mistakes[j]] = grader.messages[mistakes[j]];
                            }
                        }
                    }

                } else {
                    if(typeof answer[i] == 'undefined') { continue; }
                    isValid = grader == answer[i] ? 1 : 0;
                    res.mistakes.push(isValid ? null : answer[i]);
                    if(grader.messages && !isValid && grader.messages[answer[i]]) {
                        res.messages[i] = grader.messages[answer[i]];
                    }
                }
                nb_valid += isValid ? 1 : 0;
                nb_mistakes += isValid ? 0 : 1;
            } else {
                if(!answer[i]) { continue; }
                isValid = grader == answer[i] ? 1 : 0;
                res.mistakes.push(isValid ? null : answer[i]);
                nb_valid += isValid ? 1 : 0;
                nb_mistakes += isValid ? 0 : 1;
            }
        }
        var nb_total = grader_data.length;
        if(score_settings) {
            res.score = (nb_valid * score_settings.maxScore
                       + nb_mistakes * score_settings.minScore
                       + (nb_total - nb_valid - nb_mistakes) * score_settings.noScore) / grader_data.length;
        } else {
            res.score = nb_valid / nb_total;
        }
        res.score = Math.floor(res.score);
        return res;
    };

})();
<|endoftext|>


<commit_before>'use strict';

/**
 * @module models
 */

var shortid = require('shortid');

/**
 * Defines class EntityModel.
 *
 * The EntityModel provides basic CRUD (**C**read **R**ead **U**pdate **D**elete) operations on entities.

 * All entities models must extend EntityModel. EntityModel must not be used directly. Use one of its sub class
 * instead.
 *
 * Each entity as it's own associated Model (sub class of EntityModel).
 *
 * @example
 *
 *     // Example for implementing a new EntityModel named "CustomModel"
 *
 *     // CustomModel.js
 *
 *     var util = require('util');
 *     var api = require('@openveo/api');
 *     var CustomProvider = process.require('CustomProvider.js');
 *
 *     function CustomModel() {
 *
 *       // Initialize the entity model with a dedicated provider
 *       api.EntityModel.prototype.init.call(this, new CustomProvider(api.applicationStorage.getDatabase()));
 *
 *     }
 *
 *     // CustomModel must extends EntityModel
 *     module.exports = CustomModel;
 *     util.inherits(CustomModel, api.EntityModel);
 *
 * @example
 *
 *     // Example for how to use CustomModel defined in previous example
 *
 *     var api = require('@openveo/api');
 *
 *     var CustomModel = process.require('CustomModel.js');
 *     var model = new CustomModel();
 *
 * @class EntityModel
 * @constructor
 */
function EntityModel() {
}

module.exports = EntityModel;

/**
 * Initializes an EntityModel with a provider.
 *
 * @method init
 * @protected
 * @param {EntityProvider} provider The entity provider
 */
EntityModel.prototype.init = function(provider) {
  this.provider = provider;

  if (!this.provider)
    throw new Error('An EntityModel needs a provider');
};

/**
 * Gets a single entity by its id.
 *
 * @method getOne
 * @async
 * @param {String} id The entity id
 * @param {Function} callback The function to call when it's done
 *   - **Error** The error if an error occurred, null otherwise
 *   - **Object** The entity
 */
EntityModel.prototype.getOne = function(id, callback) {
  this.provider.getOne(id, callback);
};

/**
 * Gets all entities.
 *
 * @method get
 * @async
 * @param {Function} callback The function to call when it's done
 *   - **Error** The error if an error occurred, null otherwise
 *   - **Array** The list of entities
 */
EntityModel.prototype.get = function(callback) {
  this.provider.get(callback);
};

/**
 * Gets a list of filtered entities
 *
 * @method getByFilter
 * @async
 * @param {Object} filter A MongoDB filter
 * @param {Function} callback The function to call when it's done
 *   - **Error** The error if an error occurred, null otherwise
 *   - **Object** The entity
 */
EntityModel.prototype.getByFilter = function(filter, callback) {
  this.provider.getByFilter(filter, callback);
};

/**
 * Gets an ordered list of entities by page.
 *
 * @method getPaginatedFilteredEntities
 * @async
 * @param {Object} [filter] MongoDB filter
 * @param {Number} [limit] The maximum number of expected entities
 * @param {Number} [page] The expected page
 * @param {Object} [sort] A sort object
 * @param {Boolean} [populate] true to automatically populate results with additional information
 * @param {Function} callback The function to call when it's done
 *   - **Error** The error if an error occurred, null otherwise
 *   - **Array** The list of entities
 *   - **Object** Pagination information
 */
EntityModel.prototype.getPaginatedFilteredEntities = function(filter, count, page, sort, populate, callback) {
  // TODO change filter format to not directly do a DB call
  this.provider.getPaginatedFilteredEntities(filter, count, page, sort, callback);
};

/**
 * Adds a new entity.
 *
 * @method add
 * @async
 * @param {Object} data Entity data to store into the collection, its structure depends on the type of entity
 * @param {Function} callback The function to call when it's done
 *   - **Error** The error if an error occurred, null otherwise
 *   - **Object** The added entity
 */
EntityModel.prototype.add = function(data, callback) {
  data.id = shortid.generate();
  this.provider.add(data, function(error, insertCount, documents) {
    if (callback)
      callback(error, documents[0]);
  });
};

/**
 * Updates an entity.
 *
 * @method update
 * @async
 * @param {String} id The id of the entity to update
 * @param {Object} data Entity data, its structure depends on the type of entity
 * @param {Function} callback The function to call when it's done
 *   - **Error** The error if an error occurred, null otherwise
 *   - **Number** The number of updated items
 */
EntityModel.prototype.update = function(id, data, callback) {
  this.provider.update(id, data, callback);
};

/**
 * Removes one or several entities.
 *
 * @method remove
 * @async
 * @param {String|Array} ids Id(s) of the document(s) to remove from the collection
 * @param {Function} callback The function to call when it's done
 *   - **Error** The error if an error occurred, null otherwise
 *   - **Number** The number of deleted entities
 */
EntityModel.prototype.remove = function(ids, callback) {
  this.provider.remove(ids, callback);
};
<commit_msg>Correct returned values of EntityModel.add method<commit_after>'use strict';

/**
 * @module models
 */

var shortid = require('shortid');

/**
 * Defines class EntityModel.
 *
 * The EntityModel provides basic CRUD (**C**read **R**ead **U**pdate **D**elete) operations on entities.

 * All entities models must extend EntityModel. EntityModel must not be used directly. Use one of its sub class
 * instead.
 *
 * Each entity as it's own associated Model (sub class of EntityModel).
 *
 * @example
 *
 *     // Example for implementing a new EntityModel named "CustomModel"
 *
 *     // CustomModel.js
 *
 *     var util = require('util');
 *     var api = require('@openveo/api');
 *     var CustomProvider = process.require('CustomProvider.js');
 *
 *     function CustomModel() {
 *
 *       // Initialize the entity model with a dedicated provider
 *       api.EntityModel.prototype.init.call(this, new CustomProvider(api.applicationStorage.getDatabase()));
 *
 *     }
 *
 *     // CustomModel must extends EntityModel
 *     module.exports = CustomModel;
 *     util.inherits(CustomModel, api.EntityModel);
 *
 * @example
 *
 *     // Example for how to use CustomModel defined in previous example
 *
 *     var api = require('@openveo/api');
 *
 *     var CustomModel = process.require('CustomModel.js');
 *     var model = new CustomModel();
 *
 * @class EntityModel
 * @constructor
 */
function EntityModel() {
}

module.exports = EntityModel;

/**
 * Initializes an EntityModel with a provider.
 *
 * @method init
 * @protected
 * @param {EntityProvider} provider The entity provider
 */
EntityModel.prototype.init = function(provider) {
  this.provider = provider;

  if (!this.provider)
    throw new Error('An EntityModel needs a provider');
};

/**
 * Gets a single entity by its id.
 *
 * @method getOne
 * @async
 * @param {String} id The entity id
 * @param {Function} callback The function to call when it's done
 *   - **Error** The error if an error occurred, null otherwise
 *   - **Object** The entity
 */
EntityModel.prototype.getOne = function(id, callback) {
  this.provider.getOne(id, callback);
};

/**
 * Gets all entities.
 *
 * @method get
 * @async
 * @param {Function} callback The function to call when it's done
 *   - **Error** The error if an error occurred, null otherwise
 *   - **Array** The list of entities
 */
EntityModel.prototype.get = function(callback) {
  this.provider.get(callback);
};

/**
 * Gets a list of filtered entities
 *
 * @method getByFilter
 * @async
 * @param {Object} filter A MongoDB filter
 * @param {Function} callback The function to call when it's done
 *   - **Error** The error if an error occurred, null otherwise
 *   - **Object** The entity
 */
EntityModel.prototype.getByFilter = function(filter, callback) {
  this.provider.getByFilter(filter, callback);
};

/**
 * Gets an ordered list of entities by page.
 *
 * @method getPaginatedFilteredEntities
 * @async
 * @param {Object} [filter] MongoDB filter
 * @param {Number} [limit] The maximum number of expected entities
 * @param {Number} [page] The expected page
 * @param {Object} [sort] A sort object
 * @param {Boolean} [populate] true to automatically populate results with additional information
 * @param {Function} callback The function to call when it's done
 *   - **Error** The error if an error occurred, null otherwise
 *   - **Array** The list of entities
 *   - **Object** Pagination information
 */
EntityModel.prototype.getPaginatedFilteredEntities = function(filter, count, page, sort, populate, callback) {
  // TODO change filter format to not directly do a DB call
  this.provider.getPaginatedFilteredEntities(filter, count, page, sort, callback);
};

/**
 * Adds a new entity.
 *
 * @method add
 * @async
 * @param {Object} data Entity data to store into the collection, its structure depends on the type of entity
 * @param {Function} callback The function to call when it's done
 *   - **Error** The error if an error occurred, null otherwise
 *   - **Number** The total amount of items inserted
 *   - **Object** The added entity
 */
EntityModel.prototype.add = function(data, callback) {
  data.id = shortid.generate();
  this.provider.add(data, function(error, insertCount, documents) {
    if (callback)
      callback(error, insertCount, documents[0]);
  });
};

/**
 * Updates an entity.
 *
 * @method update
 * @async
 * @param {String} id The id of the entity to update
 * @param {Object} data Entity data, its structure depends on the type of entity
 * @param {Function} callback The function to call when it's done
 *   - **Error** The error if an error occurred, null otherwise
 *   - **Number** The number of updated items
 */
EntityModel.prototype.update = function(id, data, callback) {
  this.provider.update(id, data, callback);
};

/**
 * Removes one or several entities.
 *
 * @method remove
 * @async
 * @param {String|Array} ids Id(s) of the document(s) to remove from the collection
 * @param {Function} callback The function to call when it's done
 *   - **Error** The error if an error occurred, null otherwise
 *   - **Number** The number of deleted entities
 */
EntityModel.prototype.remove = function(ids, callback) {
  this.provider.remove(ids, callback);
};
<|endoftext|>


<commit_before>/* jshint node: true */
'use strict';

var debug = require('cog/logger')('rtc-signaller');
var extend = require('cog/extend');
var roles = ['a', 'b'];

/**
  #### announce

  ```
  /announce|{"id": "...", ... }
  ```

  When an announce message is received by the signaller, the attached
  object data is decoded and the signaller emits an `announce` message.

  ##### Events Triggered in response to `/announce`

  There are two different types of `peer:` events that can be triggered
  in on peer B to calling the `announce` method on peer A.

  - `peer:announce`

    The `peer:announce` event is triggered when a new peer has been
    discovered.  The data for the new peer (as an JS object) is provided
    as the first argument of the event handler.

  - `peer:update`

    If a peer "reannounces" then a `peer:update` event will be triggered
    rather than a `peer:announce` event.

**/
module.exports = function(signaller) {

  function copyData(target, source) {
    if (target && source) {
      for (var key in source) {
        target[key] = source[key];
      }
    }

    return target;
  }

  return function(args, messageType, srcData, srcState, isDM) {
    var data = args[0];
    var peer;

    debug('announce handler invoked, received data: ', data);

    // if we have valid data then process
    if (data && data.id && data.id !== signaller.id) {
      // check to see if this is a known peer
      peer = signaller.peers.get(data.id);

      // if the peer is existing, then update the data
      if (peer) {
        debug('signaller: ' + signaller.id + ' received update, data: ', data);

        // update the data
        copyData(peer.data, data);

        // trigger the peer update event
        return signaller.emit('peer:update', data, srcData);
      }

      // create a new peer
      peer = {
        id: data.id,

        // initialise the local role index
        roleIdx: [data.id, signaller.id].sort().indexOf(data.id),

        // initialise the peer data
        data: {}
      };

      // initialise the peer data
      copyData(peer.data, data);

      // set the peer data
      signaller.peers.set(data.id, peer);

      // if this is an initial announce message (no vector clock attached)
      // then send a announce reply
      if (signaller.autoreply && (! isDM)) {
        signaller
          .to(data.id)
          .send('/announce', signaller.attributes);
      }

      // emit a new peer announce event
      return signaller.emit('peer:announce', data, peer);
    }
  };
};<commit_msg>Added peer:screen event for filtering out peers prior to announce/update<commit_after>/* jshint node: true */
'use strict';

var debug = require('cog/logger')('rtc-signaller');
var extend = require('cog/extend');
var roles = ['a', 'b'];

/**
  #### announce

  ```
  /announce|{"id": "...", ... }
  ```

  When an announce message is received by the signaller, the attached
  object data is decoded and the signaller emits an `announce` message.

  ##### Events Triggered in response to `/announce`

  There are three different types of `peer:` events that can be triggered
  in on peer B to calling the `announce` method on peer A.

  - `peer:screen`

    The `peer:screen` event is triggered prior to the `peer:announce` or
    `peer:update` events being fired and provides an application the
    opportunity to reject a peer.  The handler for this event is passed
    a JS object that contains a `data` attribute for the announce data, and an
    `allow` flag that controls whether the peer is to be accepted.

    Due to the way event emitters behave in node, the last handler invoked
    is the authority on whether the peer is accepted or not (so make sure to
    check the previous state of the allow flag):

    ```js
    // only accept connections from Bob
    signaller.on('peer:screen', function(evt) {
      evt.allow = evt.allow && (evt.data.name === 'Bob');
    });
    ```

  - `peer:announce`

    The `peer:announce` event is triggered when a new peer has been
    discovered.  The data for the new peer (as an JS object) is provided
    as the first argument of the event handler.

  - `peer:update`

    If a peer "reannounces" then a `peer:update` event will be triggered
    rather than a `peer:announce` event.

**/
module.exports = function(signaller) {

  function copyData(target, source) {
    if (target && source) {
      for (var key in source) {
        target[key] = source[key];
      }
    }

    return target;
  }

  function dataAllowed(data) {
    var evt = {
      data: data,
      allow: true
    };

    signaller.emit('peer:screen', evt);

    return evt.allow;
  }

  return function(args, messageType, srcData, srcState, isDM) {
    var data = args[0];
    var peer;

    debug('announce handler invoked, received data: ', data);

    // if we have valid data then process
    if (data && data.id && data.id !== signaller.id) {
      if (! dataAllowed(data)) {
        return;
      }
      // check to see if this is a known peer
      peer = signaller.peers.get(data.id);

      // if the peer is existing, then update the data
      if (peer) {
        debug('signaller: ' + signaller.id + ' received update, data: ', data);

        // update the data
        copyData(peer.data, data);

        // trigger the peer update event
        return signaller.emit('peer:update', data, srcData);
      }

      // create a new peer
      peer = {
        id: data.id,

        // initialise the local role index
        roleIdx: [data.id, signaller.id].sort().indexOf(data.id),

        // initialise the peer data
        data: {}
      };

      // initialise the peer data
      copyData(peer.data, data);

      // set the peer data
      signaller.peers.set(data.id, peer);

      // if this is an initial announce message (no vector clock attached)
      // then send a announce reply
      if (signaller.autoreply && (! isDM)) {
        signaller
          .to(data.id)
          .send('/announce', signaller.attributes);
      }

      // emit a new peer announce event
      return signaller.emit('peer:announce', data, peer);
    }
  };
};<|endoftext|>


<commit_before>/* global describe, it, xit */
/* jslint node: true, esnext: true */

"use strict";

const chai = require('chai'),
  assert = chai.assert,
  expect = chai.expect,
  should = chai.should(),
  MockReceiveInterceptor = require('../index').MockReceiveInterceptor;

describe('Message Handler', function () {

  it('Create', function (done) {
    const exampleValidationFunction = function (request, oldRequest) {
      assert.ok(request);
      done();
    };

    const mock = new MockReceiveInterceptor(exampleValidationFunction);
    mock.receive({
      "some": "thing"
    });

  });
});
<commit_msg>fix(dependencies): kronos-interceptor@2.1.0<commit_after>/* global describe, it, xit */
/* jslint node: true, esnext: true */

"use strict";

const chai = require('chai'),
  assert = chai.assert,
  expect = chai.expect,
  should = chai.should(),
  MockReceiveInterceptor = require('../index').MockReceiveInterceptor;

describe('Message Handler', () => {
  it('Create', function (done) {
    const exampleValidationFunction = (request, oldRequest) => {
      assert.ok(request);
      done();
    };

    const mock = new MockReceiveInterceptor(exampleValidationFunction);
    mock.receive({
      "some": "thing"
    });
  });
});
<|endoftext|>


<commit_before>
/*
Copyright (c) 2011, Chris Umbel

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

var tokenizer = require('./whitespace_tokenizer');

var numbers = {
    "one": 1,
    "two": 2,
    "three": 3,
    "four": 4,
    "five": 5,
    "six": 6,
    "seven": 7,
    "eight": 8,
    "nine": 9,
    "ten": 10,
    "eleven": 11,
    "twelve": 12,
    "thirteen": 13,
    "fourteen": 14,
    "fifteen": 15,
    "sixteen": 16,
    "eighteen": 18,
    "nineteen": 19,
    "twenty": 20,
    "twenty-one": 21,
    "twenty-two": 22,
    "twenty-three": 23
};

function parse(str) {
    tokens = tokenizer.tokenize(str.toLowerCase());

    var now = this.providedNow ? this.providedNow : new Date();
    var result = new Date(0, 0, 0, 0, 0, 0, 0);
    var hourModifier = 0;

    for(var i = 0; i < tokens.length; i++) {
        switch(tokens[i]) {
            case 'today':
                result.setFullYear(now.getFullYear());
                result.setMonth(now.getMonth());
                result.setDate(now.getDate());
                break;
            case 'noon':
                result.setHours(12);
                break;
            case 'midnight':
                result.setHours(0);
                break;
            case 'passed':
                if(i > 0) {
                    if(tokens[i - 1] == 'half')
                        result.setMinutes(30);
                    else if(tokens[i - 1] == 'quarter')
                        result.setMinutes(15);
                    else if(numbers[tokens[i - 1]])
                        result.setMinutes(numbers[tokens[i - 1]]);

                    if(numbers[tokens[i + 1]]) {
                        result.setHours(numbers[tokens[++i]]);
                    }
                }

                break;
            case 'till':
            case 'to':
                if(i < tokens.length) {
                    if(tokens[i - 1] == 'quarter') {
                        result.setMinutes(45);
                        hourModifier = -1;
                    } else if(numbers[tokens[i - 1]]) {
                        result.setMinutes(60 - numbers[tokens[i - 1]]);
                        hourModifier = -1;
                    }

                    if(numbers[tokens[i + 1]]) {
                        result.setHours(numbers[tokens[++i]]);
                    }
                }

                break;
         }
    }

    result.setHours(result.getHours() + hourModifier);

    return result;
}

var Chronology = function(providedNow) {
    this.parse = parse;
    this.providedNow = providedNow;
};

module.exports = Chronology;<commit_msg>added more number words<commit_after>
/*
Copyright (c) 2011, Chris Umbel

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

var tokenizer = require('./whitespace_tokenizer');

var numbers = {
    "one": 1,
    "two": 2,
    "three": 3,
    "four": 4,
    "five": 5,
    "six": 6,
    "seven": 7,
    "eight": 8,
    "nine": 9,
    "ten": 10,
    "eleven": 11,
    "twelve": 12,
    "thirteen": 13,
    "fourteen": 14,
    "fifteen": 15,
    "sixteen": 16,
    "eighteen": 18,
    "nineteen": 19,
    "twenty": 20,
    "twenty-one": 21,
    "twenty-two": 22,
    "twenty-three": 23,
    "twenty-four": 24,
    "twenty-five": 25,
    "twenty-six": 26,
    "twenty-seven": 27,
    "twenty-eight": 28,
    "twenty-nine": 29
};

function parse(str) {
    tokens = tokenizer.tokenize(str.toLowerCase());

    var now = this.providedNow ? this.providedNow : new Date();
    var result = new Date(0, 0, 0, 0, 0, 0, 0);
    var hourModifier = 0;

    for(var i = 0; i < tokens.length; i++) {
        switch(tokens[i]) {
            case 'today':
                result.setFullYear(now.getFullYear());
                result.setMonth(now.getMonth());
                result.setDate(now.getDate());
                break;
            case 'noon':
                result.setHours(12);
                break;
            case 'midnight':
                result.setHours(0);
                break;
            case 'passed':
                if(i > 0) {
                    if(tokens[i - 1] == 'half')
                        result.setMinutes(30);
                    else if(tokens[i - 1] == 'quarter')
                        result.setMinutes(15);
                    else if(numbers[tokens[i - 1]])
                        result.setMinutes(numbers[tokens[i - 1]]);

                    if(numbers[tokens[i + 1]]) {
                        result.setHours(numbers[tokens[++i]]);
                    }
                }

                break;
            case 'till':
            case 'to':
                if(i < tokens.length) {
                    if(tokens[i - 1] == 'quarter') {
                        result.setMinutes(45);
                        hourModifier = -1;
                    } else if(numbers[tokens[i - 1]]) {
                        result.setMinutes(60 - numbers[tokens[i - 1]]);
                        hourModifier = -1;
                    }

                    if(numbers[tokens[i + 1]]) {
                        result.setHours(numbers[tokens[++i]]);
                    }
                }

                break;
         }
    }

    result.setHours(result.getHours() + hourModifier);

    return result;
}

var Chronology = function(providedNow) {
    this.parse = parse;
    this.providedNow = providedNow;
};

module.exports = Chronology;<|endoftext|>


<commit_before>import panoPreview from './pano-preview';

describe('panoPreview service', () => {
  it('should return an object filled with data if response is ok', () => {
    fetch.mockResponseOnce(JSON.stringify({
      pano_id: 'pano_id',
      heading: 'heading',
      url: 'url'
    }));
    panoPreview({ latitude: 123, longitude: 321 }).then((res) => {
      expect(res).toEqual({
        id: 'pano_id',
        heading: 'heading',
        url: 'url'
      });
    });
    expect(fetch).toHaveBeenCalledWith('https://acc.api.data.amsterdam.nl/panorama/thumbnail/?lat=undefined&lon=321&width=438&radius=180');
  });

  it('should return an empty object when status is 404', () => {
    fetch.mockResponseOnce('{}', { status: 404 });
    panoPreview({ latitude: 123, longitude: 321 }).then((res) => {
      expect(res).toEqual({});
    });
  });

  it('should throw an error is response != ok and status != 404', async () => {
    fetch.mockResponseOnce('{}', { status: 503 });
    // const result =
    expect(panoPreview({
      latitude: 123,
      longitude: 321
    })).rejects.toEqual(new Error('Error requesting a panoramic view'));
  });
});
<commit_msg>test updated to reflect proper url<commit_after>import panoPreview from './pano-preview';

describe('panoPreview service', () => {
  it('should return an object filled with data if response is ok', () => {
    fetch.mockResponseOnce(JSON.stringify({
      pano_id: 'pano_id',
      heading: 'heading',
      url: 'url'
    }));
    panoPreview({ latitude: 123, longitude: 321 }).then((res) => {
      expect(res).toEqual({
        id: 'pano_id',
        heading: 'heading',
        url: 'url'
      });
    });
    expect(fetch).toHaveBeenCalledWith('https://acc.api.data.amsterdam.nl/panorama/thumbnail/?lat=123&lon=321&width=438&radius=180');
  });

  it('should return an empty object when status is 404', () => {
    fetch.mockResponseOnce('{}', { status: 404 });
    panoPreview({ latitude: 123, longitude: 321 }).then((res) => {
      expect(res).toEqual({});
    });
  });

  it('should throw an error is response != ok and status != 404', async () => {
    fetch.mockResponseOnce('{}', { status: 503 });
    // const result =
    expect(panoPreview({
      latitude: 123,
      longitude: 321
    })).rejects.toEqual(new Error('Error requesting a panoramic view'));
  });
});
<|endoftext|>


<commit_before>import { Kettlepaw, Zeboot } from 'CONTRIBUTORS';
import { change, date } from 'common/changelog';

export default [
  change(date(2020, 12, 18), 'Fixed compiler errors affecing FrenziedRegen and AntiFillerSpam', Kettlepaw),
  change(date(2020, 10, 18), 'Converted legacy listeners to new event filters', Zeboot),
];
<commit_msg>Correct a typo in the new changelog entry<commit_after>import { Kettlepaw, Zeboot } from 'CONTRIBUTORS';
import { change, date } from 'common/changelog';

export default [
  change(date(2020, 12, 18), 'Fixed compiler errors affecting FrenziedRegen and AntiFillerSpam', Kettlepaw),
  change(date(2020, 10, 18), 'Converted legacy listeners to new event filters', Zeboot),
];
<|endoftext|>


<commit_before>/**
 * Twig extensions
 * @type {*}
 */

let twig = require('twig'),
  fs = require('fs');

module.exports = function () {
  /**
   * Function for include svg on page
   *
   * @usage svg('path/from/root/dir)
   *
   * @param path - path from project root dir
   *
   * TODO: location independence
   *
   * @returns {String} - svg code
   *
   */
  twig.extendFunction('svg', function (path) {
    return fs.readFileSync(__dirname + '/..' + path, 'utf-8');
  });

  /**
   * Function for getting full named event-type
   *
   * @usage {{ event.tag | event-type }}
   *
   * @param eventTag - 'fatal', 'warnings', 'notice' or 'javascript' type of error
   *
   * @returns {String} - full named event-type
   *
   */
  twig.extendFilter('event-type', function (eventTag) {
    switch (eventTag) {
      case 'fatal':
        return 'Fatal Error';
        break;
      case 'warnings':
        return 'Warning';
        break;
      case 'notice':
        return 'Notice';
        break;
      case 'javascript':
        return 'JavaScript Error';
        break;
    }
  });
}();
<commit_msg>remove line<commit_after>/**
 * Twig extensions
 * @type {*}
 */

let twig = require('twig'),
  fs = require('fs');

module.exports = function () {
  /**
   * Function for include svg on page
   *
   * @usage svg('path/from/root/dir)
   *
   * @param path - path from project root dir
   *
   * TODO: location independence
   *
   * @returns {String} - svg code
   *
   */
  twig.extendFunction('svg', function (path) {
    return fs.readFileSync(__dirname + '/..' + path, 'utf-8');
  });

  /**
   * Function for getting full named event-type
   *
   * @usage {{ event.tag | event-type }}
   *
   * @param eventTag - 'fatal', 'warnings', 'notice' or 'javascript' type of error
   *
   * @returns {String} - full named event-type
   */
  twig.extendFilter('event-type', function (eventTag) {
    switch (eventTag) {
      case 'fatal':
        return 'Fatal Error';
        break;
      case 'warnings':
        return 'Warning';
        break;
      case 'notice':
        return 'Notice';
        break;
      case 'javascript':
        return 'JavaScript Error';
        break;
    }
  });
}();
<|endoftext|>


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

function StateStore(store) {
  this._store = store;
}

StateStore.prototype.store = function(req, meta, cb) {
  var state = {
    name: 'login/oauth2',
    authorizationURL: meta.authorizationURL,
    tokenURL: meta.tokenURL,
    clientID: meta.clientID
  };

  // NOTE: Will be (correctly) overridden by the underlying state store with
  //       the handle of the current request state, if any.
  state.prev = (req.query && req.query.state) || (req.body && req.body.state);

  this._store.save(req, state, function(err, h) {
    if (err) { return cb(err); }
    return cb(null, h);
  });
}

StateStore.prototype.verify = function(req, h, meta, cb) {
  function loaded(err, state) {
    if (err) { return cb(err); }
    if (!state) { return cb(null, false); }

    if (state.name !== 'login/oauth2') {
      // TODO: This should be 403 forbidden, with an error code for logging
      return cb(new Error('State out of sync, expected login/oauth2, got: ' + state.name));
    }

    // TODO: Destroy the state

    if (state.authorizationURL !== meta.authorizationURL) {
      return cb(null, false);
    }
    if (state.tokenURL !== meta.tokenURL) {
      return cb(null, false);
    }
    if (state.clientID !== meta.clientID) {
      return cb(null, false);
    }
    return cb(null, true, state);
  }

  if (req.state && req.state.name == 'login/oauth2') {
    loaded(null, clone(req.state));
  } else {
    this._store.load(req, h, loaded);
  }
}

module.exports = StateStore;
<commit_msg>Cleaner OAuth 2.0 state store.<commit_after>function StateStore(store) {
  this._store = store;
}

StateStore.prototype.store = function(req, meta, cb) {
  var state = {
    name: 'login/oauth2',
    authorizationURL: meta.authorizationURL,
    clientID: meta.clientID
  };
  var ps = (req.query && req.query.state) || (req.body && req.body.state);
  if (ps) { state.prev = ps; }

  this._store.save(req, state, function(err, h) {
    if (err) { return cb(err); }
    return cb(null, h);
  });
}

StateStore.prototype.verify = function(req, h, meta, cb) {
  function loaded(err, state) {
    if (err) { return cb(err); }
    if (!state) { return cb(null, false); }

    // TODO: Destroy the state??

    if (state.name !== 'login/oauth2') {
      return cb(null, false);
    }
    if (state.authorizationURL !== meta.authorizationURL) {
      return cb(null, false);
    }
    if (state.clientID !== meta.clientID) {
      return cb(null, false);
    }
    return cb(null, true, state);
  }

  if (req.state) {
    loaded(null, req.state);
  } else {
    this._store.load(req, h, loaded);
  }
}

module.exports = StateStore;
<|endoftext|>


<commit_before>(function (exports) {

  'use strict';

  function comparator(a, b) {
    return a - b;
  }

  /**
   * The heapsort algorithm. It's complexity is O(nlog n).
   *
   * @public
   */
  var heapSort = (function () {

    /**
     * Finds the correct place of given element in given max heap.
     *
     * @private
     * @param {array} array Array
     * @param {number} index Index of the element which palce in
     *                       the max heap should be found.
     */
    function heapify(array, index, heapSize, cmp) {
      var left = 2 * index + 1,
          right = 2 * index + 2,
          largest = index;

      if (left < heapSize && cmp(array[left], array[index]) > 0) {
        largest = left;
      }

      if (right < heapSize && cmp(array[right], array[largest]) > 0) {
        largest = right;
      }

      if (largest !== index) {
        var temp = array[index];
        array[index] = array[largest];
        array[largest] = temp;
        heapify(array, largest, heapSize, cmp);
      }
    }
<commit_msg>Update heapsort.js : Added use strict<commit_after>(function (exports) {

  'use strict';

  function comparator(a, b) {
    return a - b;
  }

  /**
   * The heapsort algorithm. It's complexity is O(nlog n).
   *
   * @public
   */
  var heapSort = (function () {

    /**
     * Finds the correct place of given element in given max heap.
     *
     * @private
     * @param {array} array Array
     * @param {number} index Index of the element which palce in
     *                       the max heap should be found.
     */
    function heapify(array, index, heapSize, cmp) {
      var left = 2 * index + 1,
          right = 2 * index + 2,
          largest = index;

      if (left < heapSize && cmp(array[left], array[index]) > 0) {
        largest = left;
      }

      if (right < heapSize && cmp(array[right], array[largest]) > 0) {
        largest = right;
      }

      if (largest !== index) {
        var temp = array[index];
        array[index] = array[largest];
        array[largest] = temp;
        heapify(array, largest, heapSize, cmp);
      }
    }

    /**
     * Builds max heap from given array.
     *
     * @private
     * @param {array} array Array which should be turned into max heap
     * @returns {array} array Array turned into max heap
     */
    function buildMaxHeap(array, cmp) {
      for (var i = Math.floor(array.length / 2); i >= 0; i -= 1) {
        heapify(array, i, array.length, cmp);
      }
      return array;
    }

    /**
     * Heapsort. Turns the input array into max heap and after that sorts it.
     *
     * @public
     * @param {array} array Input array
     * @returns {array} array Sorted array
     */
    return function (array, cmp) {
      cmp = cmp || comparator;
      var size = array.length,
          temp;
      buildMaxHeap(array, cmp);
      for (var i = array.length - 1; i > 0; i -= 1) {
        temp = array[0];
        array[0] = array[i];
        array[i] = temp;
        size -= 1;
        heapify(array, 0, size, cmp);
      }
      return array;
    };
  }());

  exports.heapSort = heapSort;

}(typeof exports === 'undefined' ? window : exports));
<|endoftext|>


<commit_before>import {
  curry,
  difference,
  intersection
} from 'lodash';
import {
  demoteManagers,
  diffLabels,
  findNodeId,
  initSwarm,
  joinNodes,
  promoteNodes,
  updateLabels
} from './swarm';
import chalk from 'chalk';
import { checkVersion } from './utils';
import debug from 'debug';
import {
  each
} from 'async';
import { map } from 'bluebird';
import nodemiral from 'nodemiral';

const log = debug('mup:module:docker');

function uniqueSessions(api) {
  const sessions = api.getSessions(['app', 'mongo', 'proxy']);

  return sessions.reduce(
    (prev, curr) => {
      if (prev.map(session => session._host).indexOf(curr._host) === -1) {
        prev.push(curr);
      }

      return prev;
    }, []
  );
}

export function setup(api) {
  log('exec => mup docker setup');
  const config = api.getConfig();
  const swarmEnabled = config.swarm;
  const servers = Object.keys(config.servers);

  const list = nodemiral.taskList('Setup Docker');

  list.executeScript('Setup Docker', {
    script: api.resolvePath(__dirname, 'assets/docker-setup.sh')
  });

  const sessions = swarmEnabled ?
    api.getSessionsForServers(servers) :
    uniqueSessions(api);

  if (sessions.length === 0) {
    // There are no servers, so we can skip running the list
    return;
  }

  return api
    .runTaskList(list, sessions, {
      verbose: api.verbose
    })
    .then(() => setupSwarm(api));
}

export async function setupSwarm(api) {
  const config = api.getConfig();
  const swarmConfig = config.swarm;

  if (!swarmConfig) {
    return;
  }

  let serverInfo = await api.getServerInfo();
  const {
    currentManagers,
    desiredManagers
  } = await api.swarmInfo();

  log('currentManagers', currentManagers);
  log('wantedManagers', desiredManagers);

  const managersToAdd = difference(desiredManagers, currentManagers);
  const managersToRemove = difference(currentManagers, desiredManagers);

  // These managers are safe to run tasks on that require a manager
  // This array is modified as managers are added and removed to have
  const managersToKeep = intersection(currentManagers, desiredManagers);

  log('managers to add', managersToAdd);
  log('managers to remove', managersToRemove);
  log('managers keeping', managersToKeep);

  if (currentManagers.length === 0) {
    log('Creating swarm cluster');
    const host = config.servers[managersToAdd[0]].host;

    await initSwarm(managersToAdd[0], host, api);

    managersToKeep.push(managersToAdd.shift());
    log('finished creating cluster');
    api.serverInfoStale();
  } else if (managersToKeep.length === 0) {
    // We can run tasks on the managers being removed until
    // the new managers are added
    managersToKeep.push(managersToRemove[0]);
  }

  // refresh server info after updating managers
  serverInfo = await api.getServerInfo();

  const {
    nodes: currentNodes,
    currentLabels,
    desiredLabels
  } = await api.swarmInfo();
  const wantedNodes = Object.keys(config.servers);
  const nodesToAdd = difference(wantedNodes, currentNodes);

  log('current nodes', currentNodes);
  log('adding nodes', nodesToAdd);

  if (nodesToAdd.length > 0) {
    const token = Object.keys(serverInfo)
      .reduce((result, item) => result || serverInfo[item].swarmToken, null);
    const managerIP = config.servers[desiredManagers[0]].host;

    await joinNodes(nodesToAdd, token, managerIP, api);
    api.serverInfoStale();
  }

  const {
    nodeIDs
  } = await api.swarmInfo();
  const curriedFindNodeId = curry(findNodeId)(nodeIDs);

  log('remaining managers to add', managersToAdd);
  if (managersToAdd.length > 0) {
    const managerIDs = managersToAdd
      .map(curriedFindNodeId);

    await promoteNodes(managersToKeep[0], managerIDs, api);

    if (managersToKeep[0] === managersToRemove[0]) {
      // There were no managers being kept, so we were only able
      // to use the managers that will be removed. We can now use
      // the newly promoted managers.
      managersToKeep[0] = managersToAdd[0];
    }
  }

  if (managersToRemove.length > 0) {
    await demoteManagers(
      managersToKeep[0],
      managersToRemove.map(curriedFindNodeId),
      api
    );
    api.serverInfoStale();
  }

  // Update tags
  let { toRemove, toAdd } = diffLabels(currentLabels, desiredLabels);

  log('current labels', currentLabels);
  log('desired labels', desiredLabels);
  log('adding labels', toAdd);
  log('removing labels', toRemove);

  if (toRemove.length > 0 || toAdd.length > 0) {
    toRemove = toRemove.map(data => {
      data.node = curriedFindNodeId(data.server);

      if (!data.node) {
        console.error(`Unable to remove "${data.label}" label for server "${data.server}": Server doesn't have a node id.`);
      }

      return data;
    });

    toAdd = toAdd.map(data => {
      data.node = curriedFindNodeId(data.server);

      if (!data.node) {
        console.log(`Unable to update "${data.label}" label for server "${data.server}": Server doesn't have a node id.`);
      }

      return data;
    });

    await updateLabels(api, managersToKeep[0], toAdd, toRemove);
  }
}

export function restart(api) {
  const list = nodemiral.taskList('Restart Docker Daemon');

  list.executeScript('Restart Docker', {
    script: api.resolvePath(__dirname, 'assets/docker-restart.sh')
  });

  const sessions = uniqueSessions(api);

  return api.runTaskList(list, sessions, {
    verbose: api.verbose
  });
}

export function removeSwarm(api) {
  const list = nodemiral.taskList('Destroy Swarm Cluster');
  const servers = Object.keys(api.getConfig().servers);
  const sessions = api.getSessionsForServers(servers);

  list.executeScript('Leave Swarm Cluster', {
    script: api.resolvePath(__dirname, 'assets/swarm-leave.sh')
  });

  return api.runTaskList(list, sessions, {
    verbose: api.verbose
  });
}

export function ps(api) {
  const args = api.getArgs();

  args.shift();
  each(uniqueSessions(api), (session, cb) => {
    session.execute(`sudo docker ${args.join(' ')} 2>&1`, (err, code, logs) => {
      console.log(chalk.magenta(`[${session._host}]`) + chalk.blue(` docker ${args.join(' ')}`));
      console.log(logs.stdout);
      cb();
    });
  });
}

export async function status(api) {
  const config = api.getConfig();

  if (!config.servers) {
    return;
  }

  const results = await map(
    Object.values(config.servers),
    server => api.runSSHCommand(server, 'sudo docker version --format "{{.Server.Version}}"'),
    { concurrency: 2 }
  );

  const lines = [];
  let overallColor = chalk.green;

  results.forEach(result => {
    let dockerStatus = 'Running';
    let color = 'green';

    if (result.code === 1) {
      dockerStatus = 'Stopped';
      color = 'red';
      overallColor = chalk.red;
    } else if (result.code === 127) {
      dockerStatus = 'Not installed';
      color = 'red';
      overallColor = chalk.red;
    }

    const version = result.output.trim().length > 1 ? result.output.trim() : '';
    let versionColor = chalk.green;

    if (!checkVersion(version)) {
      overallColor = chalk.red;
      versionColor = chalk.red;
    }

    lines.push(` - ${result.host}: ${versionColor(version)} ${chalk[color](dockerStatus)}`);
  });

  console.log(overallColor('\n=> Docker Status'));
  console.log(lines.join('\n'));

  if (!config.swarm) {
    return;
  }

  const { currentManagers, nodes } = await api.swarmInfo();
  const list = [];

  currentManagers.forEach(manager => {
    list.push(` - ${manager} (Manager)`);
  });

  difference(nodes, currentManagers).forEach(node => {
    list.push(` - ${node || 'Unknown server'}`);
  });

  if (currentManagers.length === 0) {
    console.log('No swarm managers');

    return;
  }

  // TODO: show swarm health:
  // https://docs.docker.com/engine/swarm/admin_guide/#monitor-swarm-health

  console.log(`Swarm Nodes: ${nodes.length}`);
  console.log(list.join('\n'));
}
<commit_msg>Fix docker ps Since sessions are now closed after the last promised is resolved, commands and hooks using sessions need to return a promise.<commit_after>import {
  curry,
  difference,
  intersection
} from 'lodash';
import {
  demoteManagers,
  diffLabels,
  findNodeId,
  initSwarm,
  joinNodes,
  promoteNodes,
  updateLabels
} from './swarm';
import chalk from 'chalk';
import { checkVersion } from './utils';
import debug from 'debug';
import { map } from 'bluebird';
import nodemiral from 'nodemiral';

const log = debug('mup:module:docker');

function uniqueSessions(api) {
  const {servers, swarm} = api.getConfig().servers;
  const sessions = api.getSessions(['app', 'mongo', 'proxy']);

  if (swarm) {
    return api.getSessionsForServers(Object.keys(servers));
  }

  return sessions.reduce(
    (prev, curr) => {
      if (prev.map(session => session._host).indexOf(curr._host) === -1) {
        prev.push(curr);
      }

      return prev;
    }, []
  );
}

export function setup(api) {
  log('exec => mup docker setup');
  const config = api.getConfig();
  const swarmEnabled = config.swarm;
  const servers = Object.keys(config.servers);

  const list = nodemiral.taskList('Setup Docker');

  list.executeScript('Setup Docker', {
    script: api.resolvePath(__dirname, 'assets/docker-setup.sh')
  });

  const sessions = swarmEnabled ?
    api.getSessionsForServers(servers) :
    uniqueSessions(api);

  if (sessions.length === 0) {
    // There are no servers, so we can skip running the list
    return;
  }

  return api
    .runTaskList(list, sessions, {
      verbose: api.verbose
    })
    .then(() => setupSwarm(api));
}

export async function setupSwarm(api) {
  const config = api.getConfig();
  const swarmConfig = config.swarm;

  if (!swarmConfig) {
    return;
  }

  let serverInfo = await api.getServerInfo();
  const {
    currentManagers,
    desiredManagers
  } = await api.swarmInfo();

  log('currentManagers', currentManagers);
  log('wantedManagers', desiredManagers);

  const managersToAdd = difference(desiredManagers, currentManagers);
  const managersToRemove = difference(currentManagers, desiredManagers);

  // These managers are safe to run tasks on that require a manager
  // This array is modified as managers are added and removed
  const managersToKeep = intersection(currentManagers, desiredManagers);

  log('managers to add', managersToAdd);
  log('managers to remove', managersToRemove);
  log('managers keeping', managersToKeep);

  if (currentManagers.length === 0) {
    log('Creating swarm cluster');
    const host = config.servers[managersToAdd[0]].host;

    await initSwarm(managersToAdd[0], host, api);

    managersToKeep.push(managersToAdd.shift());
    log('finished creating cluster');
    api.serverInfoStale();
  } else if (managersToKeep.length === 0) {
    // We can run tasks on the managers being removed until
    // the new managers are added
    managersToKeep.push(managersToRemove[0]);
  }

  // refresh server info after updating managers
  serverInfo = await api.getServerInfo();

  const {
    nodes: currentNodes,
    currentLabels,
    desiredLabels
  } = await api.swarmInfo();
  const wantedNodes = Object.keys(config.servers);
  const nodesToAdd = difference(wantedNodes, currentNodes);

  log('current nodes', currentNodes);
  log('adding nodes', nodesToAdd);

  if (nodesToAdd.length > 0) {
    const token = Object.keys(serverInfo)
      .reduce((result, item) => result || serverInfo[item].swarmToken, null);
    const managerIP = config.servers[desiredManagers[0]].host;

    await joinNodes(nodesToAdd, token, managerIP, api);
    api.serverInfoStale();
  }

  const {
    nodeIDs
  } = await api.swarmInfo();
  const curriedFindNodeId = curry(findNodeId)(nodeIDs);

  log('remaining managers to add', managersToAdd);
  if (managersToAdd.length > 0) {
    const managerIDs = managersToAdd
      .map(curriedFindNodeId);

    await promoteNodes(managersToKeep[0], managerIDs, api);

    if (managersToKeep[0] === managersToRemove[0]) {
      // There were no managers being kept, so we were only able
      // to use the managers that will be removed. We can now use
      // the newly promoted managers.
      managersToKeep[0] = managersToAdd[0];
    }
  }

  if (managersToRemove.length > 0) {
    await demoteManagers(
      managersToKeep[0],
      managersToRemove.map(curriedFindNodeId),
      api
    );
    api.serverInfoStale();
  }

  // Update tags
  let { toRemove, toAdd } = diffLabels(currentLabels, desiredLabels);

  log('current labels', currentLabels);
  log('desired labels', desiredLabels);
  log('adding labels', toAdd);
  log('removing labels', toRemove);

  if (toRemove.length > 0 || toAdd.length > 0) {
    toRemove = toRemove.map(data => {
      data.node = curriedFindNodeId(data.server);

      if (!data.node) {
        console.error(`Unable to remove "${data.label}" label for server "${data.server}": Server doesn't have a node id.`);
      }

      return data;
    });

    toAdd = toAdd.map(data => {
      data.node = curriedFindNodeId(data.server);

      if (!data.node) {
        console.log(`Unable to update "${data.label}" label for server "${data.server}": Server doesn't have a node id.`);
      }

      return data;
    });

    await updateLabels(api, managersToKeep[0], toAdd, toRemove);
  }
}

export function restart(api) {
  const list = nodemiral.taskList('Restart Docker Daemon');

  list.executeScript('Restart Docker', {
    script: api.resolvePath(__dirname, 'assets/docker-restart.sh')
  });

  const sessions = uniqueSessions(api);

  return api.runTaskList(list, sessions, {
    verbose: api.verbose
  });
}

export function removeSwarm(api) {
  const list = nodemiral.taskList('Destroy Swarm Cluster');
  const servers = Object.keys(api.getConfig().servers);
  const sessions = api.getSessionsForServers(servers);

  list.executeScript('Leave Swarm Cluster', {
    script: api.resolvePath(__dirname, 'assets/swarm-leave.sh')
  });

  return api.runTaskList(list, sessions, {
    verbose: api.verbose
  });
}

export async function ps(api) {
  const args = api.getArgs();

  args.shift();
  const sessions = uniqueSessions(api);

  for (const session of sessions) {
    await api.runSSHCommand(session, `sudo docker ${args.join(' ')} 2>&1`).then(({output, host}) => {
      console.log(chalk.magenta(`[${host}]`) + chalk.blue(` docker ${args.join(' ')}`));
      console.log(output);
    });
  }
}

export async function status(api) {
  const config = api.getConfig();

  if (!config.servers) {
    return;
  }

  const results = await map(
    Object.values(config.servers),
    server => api.runSSHCommand(server, 'sudo docker version --format "{{.Server.Version}}"'),
    { concurrency: 2 }
  );

  const lines = [];
  let overallColor = chalk.green;

  results.forEach(result => {
    let dockerStatus = 'Running';
    let color = 'green';

    if (result.code === 1) {
      dockerStatus = 'Stopped';
      color = 'red';
      overallColor = chalk.red;
    } else if (result.code === 127) {
      dockerStatus = 'Not installed';
      color = 'red';
      overallColor = chalk.red;
    }

    const version = result.output.trim().length > 1 ? result.output.trim() : '';
    let versionColor = chalk.green;

    if (!checkVersion(version)) {
      overallColor = chalk.red;
      versionColor = chalk.red;
    }

    lines.push(` - ${result.host}: ${versionColor(version)} ${chalk[color](dockerStatus)}`);
  });

  console.log(overallColor('\n=> Docker Status'));
  console.log(lines.join('\n'));

  if (!config.swarm) {
    return;
  }

  const { currentManagers, nodes } = await api.swarmInfo();
  const list = [];

  currentManagers.forEach(manager => {
    list.push(` - ${manager} (Manager)`);
  });

  difference(nodes, currentManagers).forEach(node => {
    list.push(` - ${node || 'Unknown server'}`);
  });

  if (currentManagers.length === 0) {
    console.log('No swarm managers');

    return;
  }

  // TODO: show swarm health:
  // https://docs.docker.com/engine/swarm/admin_guide/#monitor-swarm-health

  console.log(`Swarm Nodes: ${nodes.length}`);
  console.log(list.join('\n'));
}
<|endoftext|>


<commit_before>"use strict";

let Repository = require("./repository");
let _ = require("underscore");

module.exports = function processRepositories (repositoryName, githubAuth, logbook, logger, githubRepositoryApi, npmApi, PullRequest) {
    let repository = new Repository(githubRepositoryApi, npmApi);

    return npmApi.load()
    .then(() => repository.createPackages())
    .then(packages => {
        return Promise.all(packages.map(p => {
            logger.info("Processing %s:%s", repositoryName, p.path);
            return p.createDependencies()
            .then(dependencies => {
                return Promise.all(dependencies.map(d => {
                    let lastCheckedVersion = logbook.get(repositoryName, d.name);
                    return d.checkForNewerVersion(lastCheckedVersion, logger);
                }));
            })
            .then(dependencies => {
                let outdatedDependencies = _.where(dependencies, {outdated: true});
                let promiseChain = Promise.resolve();
                let prs = [];
                let aborted = false;

                outdatedDependencies.forEach(dependency => {
                    promiseChain = promiseChain.then(() => {
                        if (aborted) { return; }
                        let pr = new PullRequest(githubRepositoryApi, dependency);
                        return pr.open(logger, logbook)
                        .then(pr => {
                            logbook.set(githubRepositoryApi.repositoryName, dependency.name, dependency.suggestedVersion);
                            prs.push(pr);
                        }, err => {
                            if (err.code === 403 && err.message.indexOf("abuse detection")) {
                                aborted = true;
                                logger.warning("  Github's abuse detection still stopping requests from succeeding. Aborting opening further PRs");
                            }
                            throw err;
                        });
                    });
                });

                return promiseChain.then(() => prs);
            });
        }));
    })
    .then(_.flatten);
};<commit_msg>Process mutliple repositories in serial<commit_after>"use strict";

let Repository = require("./repository");
let _ = require("underscore");

module.exports = function processRepositories (repositoryName, githubAuth, logbook, logger, githubRepositoryApi, npmApi, PullRequest) {
    let repository = new Repository(githubRepositoryApi, npmApi);

    return npmApi.load()
    .then(() => repository.createPackages())
    .then(packages => {
        let packagePromiseChain = Promise.resolve();
        let prs = [];

        packages.forEach(p => {
            packagePromiseChain = packagePromiseChain.then(() => {
                logger.info("Processing %s:%s", repositoryName, p.path);
                return p.createDependencies()
            })
            .then(dependencies => {
                return Promise.all(dependencies.map(d => {
                    let lastCheckedVersion = logbook.get(repositoryName, d.name);
                    return d.checkForNewerVersion(lastCheckedVersion, logger);
                }));
            })
            .then(dependencies => {
                let outdatedDependencies = _.where(dependencies, {outdated: true});
                let promiseChain = Promise.resolve();
                let aborted = false;

                outdatedDependencies.forEach(dependency => {
                    promiseChain = promiseChain.then(() => {
                        if (aborted) { return; }
                        let pr = new PullRequest(githubRepositoryApi, dependency);
                        return pr.open(logger, logbook)
                        .then(pr => {
                            logbook.set(githubRepositoryApi.repositoryName, dependency.name, dependency.suggestedVersion);
                            prs.push(pr);
                        }, err => {
                            if (err.code === 403 && err.message.indexOf("abuse detection")) {
                                aborted = true;
                                logger.warning("  Github's abuse detection still stopping requests from succeeding. Aborting opening further PRs");
                            }
                            throw err;
                        });
                    });
                });
                return promiseChain;
            });
        });
        return packagePromiseChain.then(() => prs);
    })
    .then(_.flatten);
};<|endoftext|>


<commit_before>var xd = Math.pow(2, 39),
    yd = Math.pow(2, 25),
    mp2_14 = Math.pow(2, 14),
    mp2_28 = Math.pow(2, 28);

// Combine the scores for each match across multiple grids and zoom levels,
// returning an object of `zxy` => feature mappings
//
// @param {Array} grids
// @param {Array} feats
// @param {Array} types
// @param {Array} zooms
// @param {Array} indexes
// @returns {Object} mapping
module.exports = function coalesceZooms(grids, feats, types, zooms, indexes) {
    var coalesced = {},
        grid,
        feat,
        h,
        z, x, y,
        pxy, p, s;

    // Coalesce relevs into higher zooms, e.g.
    // z5 inherits relev of overlapping tiles at z4.
    // @TODO assumes sources are in zoom ascending order.
    for (h = 0; h < grids.length; h++) {
        grid = grids[h];
        feat = feats[h];
        z = indexes[types[h]]._carmen.zoom;
        for (i = 0; i < grid.length; i++) {
            f = feat[grid[i] % yd];

            if (!f) continue;
            x = Math.floor(grid[i]/xd);
            y = Math.floor(grid[i]%xd/yd);
            zxy = (z * mp2_28) + (x * mp2_14) + y;

            // @TODO this is an optimization that  assumes multiple
            // DBs do not use the same zoom level.
            if (!coalesced[zxy]) coalesced[zxy] = [f];

            for (a = 0; zooms[a] < z; a++) {
                p = zooms[a];
                s = 1 << (z-p);
                pxy = (p * mp2_28) + (Math.floor(x/s) * mp2_14) + Math.floor(y/s);

                if (coalesced[pxy]) {
                    coalesced[zxy].push.apply(coalesced[zxy], coalesced[pxy]);
                }
            }
        }
    }

    return coalesced;
};
<commit_msg>Alphabet var soup<commit_after>var xd = Math.pow(2, 39),
    yd = Math.pow(2, 25),
    mp2_14 = Math.pow(2, 14),
    mp2_28 = Math.pow(2, 28);

// Combine the scores for each match across multiple grids and zoom levels,
// returning an object of `zxy` => feature mappings
//
// @param {Array} grids
// @param {Array} feats
// @param {Array} types
// @param {Array} zooms
// @param {Array} indexes
// @returns {Object} mapping
module.exports = function coalesceZooms(grids, feats, types, zooms, indexes) {
    var coalesced = {},
        grid,
        feat,
        i, h, f, a,
        z, x, y,
        zxy, pxy, p, s;

    // Coalesce relevs into higher zooms, e.g.
    // z5 inherits relev of overlapping tiles at z4.
    // @TODO assumes sources are in zoom ascending order.
    for (h = 0; h < grids.length; h++) {
        grid = grids[h];
        feat = feats[h];
        z = indexes[types[h]]._carmen.zoom;
        for (i = 0; i < grid.length; i++) {
            f = feat[grid[i] % yd];

            if (!f) continue;
            x = Math.floor(grid[i]/xd);
            y = Math.floor(grid[i]%xd/yd);
            zxy = (z * mp2_28) + (x * mp2_14) + y;

            // @TODO this is an optimization that  assumes multiple
            // DBs do not use the same zoom level.
            if (!coalesced[zxy]) coalesced[zxy] = [f];

            for (a = 0; zooms[a] < z; a++) {
                p = zooms[a];
                s = 1 << (z-p);
                pxy = (p * mp2_28) + (Math.floor(x/s) * mp2_14) + Math.floor(y/s);

                if (coalesced[pxy]) {
                    coalesced[zxy].push.apply(coalesced[zxy], coalesced[pxy]);
                }
            }
        }
    }

    return coalesced;
};
<|endoftext|>


<commit_before>import { Styler } from './styler';

let _instances = {};

class raster {
  parseAST(ast) {
    if(ast.update) {

    } else {
      this.build(ast);
    }
  }
  setupAnimation(ast){
    console.log('animation', ast);
  }
  build(ast) {
    let instance = this.createComponent(ast);
    if(instance) {
      document.body.appendChild(instance);
      this.buildChidren(ast, instance);
    }
  }
  buildChidren(component, parent) {
    component.children.forEach(element => {
      let instance = this.createComponent(element);
      parent.appendChild(instance);

      if(element.children) {
        this.buildChidren(element, instance);
      }
    });
  }
  createComponent(component) {
    let tag = component.instance.tag();
    let instance = document.createElement(tag);
    instance.id = component.guid;
    _instances[instance.id] = instance;

    let styles = component.instance.attributes.style;
    if(styles) {
      Styler.styleElement(instance, styles)
    }

    return instance;
  }
}

const Raster = new raster();

export { Raster };<commit_msg>more working dom rendering<commit_after>import { Styler } from './styler';

let _instances = {};

class raster {
  parseAST(ast) {
    if(ast.update) {

    } else {
      this.build(ast);
    }
  }
  setupAnimation(ast){
    console.log('setup animation', ast);
  }
  build(ast) {
    let instance = this.createComponent(ast);
    if(instance) {
      document.body.appendChild(instance);
      SyrEvents.emit({
        type:'componentDidMount',
        guid: ast.guid
      })
      this.buildChidren(ast, instance);
    }
  }
  buildChidren(component, parent) {
    component.children.forEach(element => {
      let instance = this.createComponent(element);
      parent.appendChild(instance);

      if(element.children) {
        this.buildChidren(element, instance);
      }
    });
  }
  createComponent(component) {
    let tag = component.instance.tag();
    let instance = document.createElement(tag);
    instance.id = component.guid;
    _instances[instance.id] = instance;

    let styles = component.instance.attributes.style;
    if(styles) {
      Styler.styleElement(instance, styles)
    }

    if(component.elementName === 'Button' || component.elementName === 'Text') {
      instance.innerText = component.instance.value;
    }

    if(component.elementName === 'Image') {
      console.log(component);
      let source = component.instance.attributes.source;
      instance.src = '/images/' + source.uri + '.png';
      console.log(source);
    }

    return instance;
  }
}

const Raster = new raster();

export { Raster };<|endoftext|>