<commit_before>var _ = require('lodash')
var Promise = require('bluebird')

var helpers = '../client/helpers'
var hasDepartment = require('../client/helpers/hasDepartment')
var partialTitle = require('../client/helpers/partialTitle')
var coursesAtLevel = require('../client/helpers/courseLevels').coursesAtLevel
var coursesAtOrAboveLevel = require('../client/helpers/courseLevels').coursesAtOrAboveLevel
var checkCoursesForDeptNum = require('../client/helpers/getCourses').checkCoursesForDeptNum

function interdisciplinaryApproachesToAsia(courses) {
	// Asian Studies 275: Interdisciplinary Approaches to Asia (.25 credit)
	console.log('checkCoursesForDeptNum', checkCoursesForDeptNum('ASIAN 275', courses))
	return checkCoursesForDeptNum('ASIAN 275', courses)
}

function lowerLevelLanguageCourses(course) {
	// If all of these match, it is a lower-level language course, and will be
	// rejected by the `reject` method.
	return (
		(
			hasDepartment('ASIAN', course) ||
			hasDepartment('CHINA', course) ||
			hasDepartment('JAPAN', course)
		) &&
		(partialTitle('Beginner', course) || partialTitle('Intermediate', course)) &&
		(course.level < 300)
	)
}

function electives(courses) {
	// Six electives, with stipulations:
	// 1. At least two at level II or level III, taken on campus;
	// 2. No more than two at level I;
	// 3. No more than four elective courses about any one country;
	// 4. No level I or level II language courses may count.

	var asianStudiesCourses = _.chain(courses)
		.filter(hasDepartment('ASIAN'))
		.reject(lowerLevelLanguageCourses)
		.value()

	var levelsTwoOrThree = _.chain(asianStudiesCourses)
		.filter(coursesAtOrAboveLevel(200)).size().value() >= 2

	var onlyTwoAtLevelOne = _.chain(asianStudiesCourses)
		.filter(coursesAtLevel(100)).size().value() <= 2

	var notTooSpecialized = _.any([
		_.chain(asianStudiesCourses).filter(partialTitle('China')).size().value() <= 4,
		_.chain(asianStudiesCourses).filter(partialTitle('Japan')).size().value() <= 4,
	])

	// Req. #4 was embedded at the beginning, when we reject any lower-level
	// languages. That way, we can't count them.
	return _.all([levelsTwoOrThree, onlyTwoAtLevelOne, notTooSpecialized])
}

function seniorSeminar(courses) {
	// Senior Seminar: Asian Studies 397: Human Rights/Asian Context or Asian
	// Studies 399: Asian Studies Seminar
	return (checkCoursesForDeptNum('ASIAN 397', courses) || checkCoursesForDeptNum('ASIAN 399', courses))
}

function language(courses) {
	// Two courses in Chinese or Japanese above 112 or its equivalent
	// "'JAPAN' IN depts AND level >= 200 AND (('Intermediate' OR 'Advanced') AND 'Japanese') IN title"
	// "'CHIN' IN depts AND level >= 200 AND (('Intermediate' OR 'Advanced') AND 'Chinese') IN title"
	var subsetOfCourses = _.chain(courses)
		.filter(coursesAtOrAboveLevel(200))
		.filter(function(course) {return partialTitle('Intermediate', course) || partialTitle('Advanced', course)})
		.value()

	var japaneseLanguage = _.chain(subsetOfCourses)
		.filter(hasDepartment('JAPAN'))
		.filter(partialTitle('Japanese'))
		.size().value() >= 2

	var chineseLanguage = _.chain(subsetOfCourses)
		.filter(hasDepartment('CHIN'))
		.filter(partialTitle('Chinese'))
		.size().value() >= 2

	return (japaneseLanguage || chineseLanguage)
}

function checkAsianStudiesMajor(student) {
	// shuck off cortex for a while
	console.log('checkAsianStudiesMajor', student)

	var asianStudiesMajorRequirements = Promise.props({
		interdisciplinaryApproachesToAsia: interdisciplinaryApproachesToAsia(student.courses),
		electives: electives(student.courses),
		seniorSeminar: seniorSeminar(student.courses),
		language: language(student.courses)
	})

	return Promise.props({result: asianStudiesMajorRequirements.then(_.all), details: asianStudiesMajorRequirements})
}

module.exports = checkAsianStudiesMajor
<commit_msg>Use more promises in demo_major<commit_after>var _ = require('lodash')
var Promise = require('bluebird')

var helpers = '../client/helpers'
var hasDepartment = require('../client/helpers/hasDepartment')
var partialTitle = require('../client/helpers/partialTitle')
var coursesAtLevel = require('../client/helpers/courseLevels').coursesAtLevel
var coursesAtOrAboveLevel = require('../client/helpers/courseLevels').coursesAtOrAboveLevel
var checkCoursesForDeptNum = require('../client/helpers/getCourses').checkCoursesForDeptNum

function interdisciplinaryApproachesToAsia(courses) {
	// Asian Studies 275: Interdisciplinary Approaches to Asia (.25 credit)
	return Promise.resolve(checkCoursesForDeptNum('ASIAN 275', courses))
}

function lowerLevelLanguageCourses(course) {
	// If all of these match, it is a lower-level language course, and will be
	// rejected by the `reject` method.
	return Promise.resolve(
		(
			hasDepartment('ASIAN', course) ||
			hasDepartment('CHINA', course) ||
			hasDepartment('JAPAN', course)
		) &&
		(partialTitle('Beginner', course) || partialTitle('Intermediate', course)) &&
		(course.level < 300)
	)
}

function electives(courses) {
	// Six electives, with stipulations:
	// 1. At least two at level II or level III, taken on campus;
	// 2. No more than two at level I;
	// 3. No more than four elective courses about any one country;
	// 4. No level I or level II language courses may count.

	var asianStudiesCourses = _.chain(courses)
		.filter(hasDepartment('ASIAN'))
		.reject(lowerLevelLanguageCourses)
		.value()

	var levelsTwoOrThree = _.chain(asianStudiesCourses)
		.filter(coursesAtOrAboveLevel(200)).size().value() >= 2

	var onlyTwoAtLevelOne = _.chain(asianStudiesCourses)
		.filter(coursesAtLevel(100)).size().value() <= 2

	var notTooSpecialized = _.any([
		_.chain(asianStudiesCourses).filter(partialTitle('China')).size().value() <= 4,
		_.chain(asianStudiesCourses).filter(partialTitle('Japan')).size().value() <= 4,
	])

	// Req. #4 was embedded at the beginning, when we reject any lower-level
	// languages. That way, we can't count them.
	return Promise.resolve(_.all([levelsTwoOrThree, onlyTwoAtLevelOne, notTooSpecialized]))
}

function seniorSeminar(courses) {
	// Senior Seminar: One of:
	// - Asian Studies 397: Human Rights/Asian Context, or
	// - Asian Studies 399: Asian Studies Seminar
	var humanRights = checkCoursesForDeptNum('ASIAN 397', courses)
	var otherSeminar = checkCoursesForDeptNum('ASIAN 399', courses)
	return Promise.all([humanRights, otherSeminar]).then(function(seminars) {
		var hasTakenSeminar = _.any(seminars)
		console.log('hasTakenSeminar', hasTakenSeminar, seminars)
		return hasTakenSeminar
	})
}

function language(courses) {
	// Two courses in Chinese or Japanese above 112 or its equivalent
	// "'JAPAN' IN depts AND level >= 200 AND (('Intermediate' OR 'Advanced') AND 'Japanese') IN title"
	// "'CHIN' IN depts AND level >= 200 AND (('Intermediate' OR 'Advanced') AND 'Chinese') IN title"
	var subsetOfCourses = _.chain(courses)
		.filter(coursesAtOrAboveLevel(200))
		.filter(function(course) {
			return partialTitle('Intermediate', course) || partialTitle('Advanced', course)
		})
		.value()

	var japaneseLanguage = _.chain(subsetOfCourses)
		.filter(hasDepartment('JAPAN'))
		.filter(partialTitle('Japanese'))
		.size().value() >= 2

	var chineseLanguage = _.chain(subsetOfCourses)
		.filter(hasDepartment('CHIN'))
		.filter(partialTitle('Chinese'))
		.size().value() >= 2

	return Promise.resolve(japaneseLanguage || chineseLanguage)
}

function checkAsianStudiesMajor(student) {
	// shuck off cortex for a while
	console.log('checkAsianStudiesMajor', student)

	var asianStudiesMajorRequirements = Promise.props({
		interdisciplinaryApproachesToAsia: interdisciplinaryApproachesToAsia(student.courses),
		electives: electives(student.courses),
		seniorSeminar: seniorSeminar(student.courses),
		language: language(student.courses)
	})

	return Promise.props({
		result: asianStudiesMajorRequirements.then(_.all),
		details: asianStudiesMajorRequirements
	})
}

module.exports = checkAsianStudiesMajor
<|endoftext|>


<commit_before>'use strict';
/*jshint freeze:false */

var cfg = require('./config');
var callsite = require('callsite');
var path = require('path');
var postRunCleanup = require('./postRunCleanup');

// if someone tries to call 'require("approvals")...' without calling ".mocha(...) or
// they won't get a helpful error. So we put this in there - just in case"
if (typeof beforeEach === "function") {
  beforeEach(function () {
    this.verify = function () {
      throw new Error("You must call either .mocha()");
    };
  });
}

// keep track of approved files we run into with tests
var listOfApprovedFiles = [];
process.on("approvalFileApproved", function (fileName) {
  if (listOfApprovedFiles.indexOf(fileName) === -1) {
    listOfApprovedFiles.push(fileName);
  }
});

process.on('exit', function () {
  var options = cfg.currentConfig();
  postRunCleanup(options, listOfApprovedFiles);
});

exports.configure = function (overrideOptions) {
  cfg.configure(overrideOptions);
  return exports;
};

exports.mocha = function (optionalBaseDir) {

  // if not providing a base dir, fallback to the current calling code's directory
  if (!optionalBaseDir) {
    optionalBaseDir = path.dirname(callsite()[1].getFileName());
  }

  var Namer = require("./Providers/Mocha/MochaNamer.js");
  var baseVerifier = require("./Providers/BeforeEachVerifierBase.js");

  baseVerifier(Namer, "require('Approvals').mocha();", optionalBaseDir);

  return exports;
};

exports.jasmine = function () {
  throw new Error("Aww shucks.\n\nApprovals support of Jasmine has been completely yanked out (don't shoot). \n\n Jasmine has grown quite complicated (behind our back) and we haven't had enough time to figure out a solid integration pattern... for now it's support has been removed.\n\n Check out the docs for manual usage of approval tests to work around the missing Jasmine integration (it should be a straightforward change for you, really).\n\n We'll consider bringing it back if we can get someone with interest in submitting a pull request that can bring it back...")
};

// Only export the MultiReporter due to performance - and you can
// pass any reporter into the multireporter using string or oject syntax (per the docs)
exports.reporters = {
  MultiReporter: require('./Reporting/Reporters/multiReporter')
}

exports.scrubbers = require('./Scrubbers');

exports.verifyAndScrub = function (dirName, testName, data, scrubber, optionsOverride) {

  scrubber = scrubber || exports.scrubbers.noScrubber;

  // backwards compatible option
  if (Array.isArray(optionsOverride)) {
    optionsOverride = {
      reporters: optionsOverride
    };
    var stringReporters = JSON.stringify(optionsOverride.reporters);
    console.error("For the last arg of the approvals.verify(...) function, if you passed in an array of reporters, something like [\"opendiff\",\"nodediff\"], this has been deprecated and replaced by passing in a config object. Please re-evaluate if you can remove this parameter alltogether and use individual user configs in ~/.approvalConfig, if not then replace this: " + stringReporters + " with this { reporters: " + stringReporters + "}.");
  }

  var newOptions = cfg.configure(optionsOverride);
  var ManualNamer = require('./ManualNamer');
  var StringWriter = require("./StringWriter");
  var BinaryWriter = require('./Writers/BinaryWriter');
  var FileApprover = require("./FileApprover");
  var ReporterFactory = require("./Reporting/ReporterFactory");

  var namer = new ManualNamer(dirName, testName);
  var reporterFactory = function () {
    return [ReporterFactory.loadReporter(newOptions.reporters)];
  };

  var writer;
  if (data instanceof Buffer) {
    writer = new BinaryWriter(newOptions, data);
  } else {
    data = scrubber(data);

    writer = new StringWriter(newOptions, data);
  }
  FileApprover.verify(namer, writer, reporterFactory, newOptions);
};

exports.verify = function (dirName, testName, data, optionsOverride) {
  return exports.verifyAndScrub(dirName, testName, data, null, optionsOverride);
};

exports.verifyAsJSON = function (dirName, testName, data, optionsOverride) {
  exports.verifyAsJSONAndScrub(dirName, testName, data, null, optionsOverride);
};

exports.verifyAsJSONAndScrub = function (dirName, testName, data, scrubber, optionsOverride) {
  exports.verifyAndScrub(dirName, testName, JSON.stringify(data, null, '  '), scrubber, optionsOverride);
};
<commit_msg>refactor Approvals.js to use revealing module pattern<commit_after>'use strict';
/*jshint freeze:false */

var cfg = require('./config');
var callsite = require('callsite');
var path = require('path');
var postRunCleanup = require('./postRunCleanup');

// if someone tries to call 'require("approvals")...' without calling ".mocha(...) or
// they won't get a helpful error. So we put this in there - just in case"
if (typeof beforeEach === "function") {
  beforeEach(function () {
    this.verify = function () {
      throw new Error("You must call either .mocha()");
    };
  });
}

// keep track of approved files we run into with tests
var listOfApprovedFiles = [];
process.on("approvalFileApproved", function (fileName) {
  if (listOfApprovedFiles.indexOf(fileName) === -1) {
    listOfApprovedFiles.push(fileName);
  }
});

process.on('exit', function () {
  var options = cfg.currentConfig();
  postRunCleanup(options, listOfApprovedFiles);
});

/**
 * Allows you to provide overrides to the default configuration.
 * @param {*} overrideOptions
 */
var configure = function (overrideOptions) {
  cfg.configure(overrideOptions);
  return module.exports;
};

var getConfig = function(overrideOptions) {
  return cfg.getConfig(overrideOptions);
}

var scrubbers = require('./Scrubbers');

/**
 * Configure approvals to hook into Mocha tests.
 * @param {*} optionalBaseDir - An optional folder to save approval files to.
 */
var mochaExport = function (optionalBaseDir) {

  // if not providing a base dir, fallback to the current calling code's directory
  if (!optionalBaseDir) {
    optionalBaseDir = path.dirname(callsite()[1].getFileName());
  }

  var Namer = require("./Providers/Mocha/MochaNamer.js");
  var baseVerifier = require("./Providers/BeforeEachVerifierBase.js");

  baseVerifier(Namer, "require('Approvals').mocha();", optionalBaseDir);

  return module.exports;
};

var jasmineExport = function () {
  throw new Error("Aww shucks.\n\nApprovals support of Jasmine has been completely yanked out (don't shoot). \n\n Jasmine has grown quite complicated (behind our back) and we haven't had enough time to figure out a solid integration pattern... for now it's support has been removed.\n\n Check out the docs for manual usage of approval tests to work around the missing Jasmine integration (it should be a straightforward change for you, really).\n\n We'll consider bringing it back if we can get someone with interest in submitting a pull request that can bring it back...")
};

// Only export the MultiReporter due to performance - and you can
// pass any reporter into the multireporter using string or oject syntax (per the docs)
var reportersExport = {
  MultiReporter: require('./Reporting/Reporters/multiReporter')
}

var verifyAndScrub = function (dirName, testName, data, scrubber, optionsOverride) {

  scrubber = scrubber || scrubbers.noScrubber;

  // backwards compatible option
  if (Array.isArray(optionsOverride)) {
    optionsOverride = {
      reporters: optionsOverride
    };
    var stringReporters = JSON.stringify(optionsOverride.reporters);
    console.error("For the last arg of the approvals.verify(...) function, if you passed in an array of reporters, something like [\"opendiff\",\"nodediff\"], this has been deprecated and replaced by passing in a config object. Please re-evaluate if you can remove this parameter alltogether and use individual user configs in ~/.approvalConfig, if not then replace this: " + stringReporters + " with this { reporters: " + stringReporters + "}.");
  }

  var newOptions = cfg.configure(optionsOverride);
  var ManualNamer = require('./ManualNamer');
  var StringWriter = require("./StringWriter");
  var BinaryWriter = require('./Writers/BinaryWriter');
  var FileApprover = require("./FileApprover");
  var ReporterFactory = require("./Reporting/ReporterFactory");

  var namer = new ManualNamer(dirName, testName);
  var reporterFactory = function () {
    return [ReporterFactory.loadReporter(newOptions.reporters)];
  };

  var writer;
  if (data instanceof Buffer) {
    writer = new BinaryWriter(newOptions, data);
  } else {
    data = scrubber(data);

    writer = new StringWriter(newOptions, data);
  }
  FileApprover.verify(namer, writer, reporterFactory, newOptions);
};

var verify = function (dirName, testName, data, optionsOverride) {
  return verifyAndScrub(dirName, testName, data, null, optionsOverride);
};

var verifyAsJSON = function (dirName, testName, data, optionsOverride) {
  return verifyAsJSONAndScrub(dirName, testName, data, null, optionsOverride);
};

var verifyAsJSONAndScrub = function (dirName, testName, data, scrubber, optionsOverride) {
  return verifyAndScrub(dirName, testName, JSON.stringify(data, null, '  '), scrubber, optionsOverride);
};

module.exports = {
  configure: configure,
  getConfig: getConfig,

  verify: verify,
  verifyAndScrub: verifyAndScrub,

  verifyAsJSON: verifyAsJSON,
  verifyAsJSONAndScrub: verifyAsJSONAndScrub,

  mocha: mochaExport,
  jasmine: jasmineExport,

  reporters: reportersExport,
  scrubbers: scrubbers

}
<|endoftext|>


<commit_before>function FamodulusClient(servers, brief) {
    'use strict';
    this.servers = servers;
    this.brief = typeof brief === 'undefined' ? true : brief;
}

FamodulusClient.prototype._request = function (query, callback) {
    'use strict';
    query.brief = this.brief;
    var req = new XMLHttpRequest();
    req.addEventListener('load', function () {
        var res = JSON.parse(this.responseText);
        if (res.modexps.length === 1) {
            callback(res.modexps[0]);
        } else {
            callback(res.modexps);
        }
    });

    req.open('POST', this.servers[0]);
    req.setRequestHeader('Content-type', 'application/json');
    req.send(JSON.stringify(query));
};

FamodulusClient.prototype.modexp = function (base, exponent, modulus, callback) {
    'use strict';
    this._request({modexps: [{b: base, e: exponent, m: modulus}]}, callback);
};

FamodulusClient.prototype.modexps = function () {
    'use strict';
    var modexps = arguments[0];
    var defaultBase;
    var defaultExponent;
    var defaultModulus;
    var callback;

    if (arguments.length === 2) {
        defaultBase = undefined;
        defaultExponent = undefined;
        defaultModulus = undefined;
        callback = arguments[1];
    } else if (arguments.length === 5) {
        defaultBase = arguments[1];
        defaultExponent = arguments[2];
        defaultModulus = arguments[3];
        callback = arguments[4];
    } else {
        throw 'Invalid arguments!';
    }

    var queryModexps = [];
    for (var i = 0; i < modexps.length; i++) {
        queryModexps.push({b: modexps[i][0], e: modexps[i][1], m: modexps[i][2]});
    }
    this._request({b: defaultBase, e: defaultExponent, m: defaultModulus, modexps: queryModexps}, callback);
};

FamodulusClient.prototype.decExponent = function (uStr, aStr, pStr, callback) {
    'use strict';
    this.decsExponent([[uStr, aStr, pStr]], function (result) {
        callback({r: result[0].r});
    });
};

FamodulusClient.prototype.decsExponent = function () {
    'use strict';
    var self = this;
    var BI = require('BigInt');

    var modexps = arguments[0];
    var defaultBase;
    var defaultExponent;
    var defaultModulus;
    var callback;

    // @todo test
    if (arguments.length === 2) {
        defaultBase = undefined;
        defaultExponent = undefined;
        defaultModulus = undefined;
        callback = arguments[1];
    } else if (arguments.length === 5) {
        defaultBase = arguments[1];
        defaultExponent = arguments[2];
        defaultModulus = arguments[3];
        callback = arguments[4];
    } else {
        throw 'Invalid arguments!';
    }

    // @todo errorhandling!
    var queryModexps = [];
    for (var i = 0; i < modexps.length; i++) {
        queryModexps.push([typeof modexps[i][0] === 'undefined' ? defaultBase : modexps[i][0],
            typeof modexps[i][1] === 'undefined' ? defaultExponent : modexps[i][1],
            typeof modexps[i][2] === 'undefined' ? defaultModulus : modexps[i][2]]);
    }

    var zero = BI.str2bigInt('0', 16, 0);
    var one = BI.str2bigInt('1', 16, 0);

    var ps = [];
    var modexpsB = [];
    var modexpsC = [];
    for (var i = 0; i < queryModexps.length; i++) {
        var a = BI.str2bigInt(queryModexps[i][1], 16, 0);
        var p = BI.str2bigInt(queryModexps[i][2], 16, 0);
        var q = BI.sub(p, one);                         // q = p-1

        var qbits = BI.bitSize(q) < 8 ? 8 : BI.bitSize(q);
        var b = BI.randBigInt(qbits, 1);
        while (BI.greater(b, q) || BI.equals(b, q) || BI.equals(b, zero)) {
            b = BI.randBigInt(qbits);
        }

        var c = BI.mod(BI.sub(BI.add(a, q), b), q);      // c = (a+q)-b mod q

        ps.push(p);
        modexpsB.push([queryModexps[i][0], BI.bigInt2str(b, 16), queryModexps[i][2]]);
        modexpsC.push([queryModexps[i][0], BI.bigInt2str(c, 16), queryModexps[i][2]]);
    }

    function resultCB(bres, cres, callback) {
        var results = [];
        if (typeof bres.r !== 'undefined') {
            results.push({r: BI.bigInt2str(BI.multMod(BI.str2bigInt(bres.r, 16, 0), BI.str2bigInt(cres.r, 16, 0), ps[0]), 16)});
        } else {
            for (var i = 0; i < bres.length; i++) {
                results.push({r: BI.bigInt2str(BI.multMod(BI.str2bigInt(bres[i].r, 16, 0), BI.str2bigInt(cres[i].r, 16, 0), ps[i]), 16)});
            }
        }
        callback(results);
    }

    // @todo randomize servers, checkability
    var resultB, resultC;
    self.modexps(modexpsB, function (result) {
        resultB = result;
        if (typeof resultC !== 'undefined') {
            resultCB(resultB, resultC, callback);
            resultC = undefined;
        }
    });
    self.modexps(modexpsC, function (result) {
        resultC = result;
        if (typeof resultB !== 'undefined') {
            resultCB(resultB, resultC, callback);
            resultB = undefined;
        }
    });
};

if (typeof module !== 'undefined' && module.hasOwnProperty('exports')) {
    module.exports = FamodulusClient;
}<commit_msg>cleaned up DEC2-algorithm, added param for checkability without implementation<commit_after>function FamodulusClient(servers, brief) {
    'use strict';
    this.servers = servers;
    this.brief = typeof brief === 'undefined' ? true : brief;
}

FamodulusClient.prototype._request = function (query, callback) {
    'use strict';
    query.brief = this.brief;
    var req = new XMLHttpRequest();
    req.addEventListener('load', function () {
        var res = JSON.parse(this.responseText);
        if (res.modexps.length === 1) {
            callback(res.modexps[0]);
        } else {
            callback(res.modexps);
        }
    });

    req.open('POST', this.servers[0]);
    req.setRequestHeader('Content-type', 'application/json');
    req.send(JSON.stringify(query));
};

FamodulusClient.prototype._rand = function (bound) {
    'use strict';
    var BI = require('BigInt');
    var ZERO = BI.str2bigInt('0', 16, 0);

    var bits = BI.bitSize(bound) < 8 ? 8 : BI.bitSize(bound);
    var rand = BI.randBigInt(bits, 1);
    while (BI.greater(rand, bound) || BI.equals(rand, bound) || BI.equals(rand, ZERO)) {
        rand = BI.randBigInt(bits);
    }
    return rand;
};

FamodulusClient.prototype.modexp = function (base, exponent, modulus, callback) {
    'use strict';
    this._request({modexps: [{b: base, e: exponent, m: modulus}]}, callback);
};

FamodulusClient.prototype.modexps = function () {
    'use strict';
    var defaultBase;
    var defaultExponent;
    var defaultModulus;
    var callback;

    if (arguments.length === 2) {
        defaultBase = undefined;
        defaultExponent = undefined;
        defaultModulus = undefined;
        callback = arguments[1];
    } else if (arguments.length === 5) {
        defaultBase = arguments[1];
        defaultExponent = arguments[2];
        defaultModulus = arguments[3];
        callback = arguments[4];
    } else {
        throw 'Invalid arguments!';
    }

    var modexps = [];
    for (var i = 0; i < arguments[0].length; i++) {
        modexps.push({b: arguments[0][i][0], e: arguments[0][i][1], m: arguments[0][i][2]});
    }
    this._request({b: defaultBase, e: defaultExponent, m: defaultModulus, modexps: modexps}, callback);
};

FamodulusClient.prototype.decExponent = function (u, a, p, checked, callback) {
    'use strict';
    this.decsExponent([[u, a, p]], checked, function (result) {
        callback({r: result[0].r});
    });
};

FamodulusClient.prototype.decsExponent = function () {
    'use strict';
    var BI = require('BigInt');
    var ONE = BI.str2bigInt('1', 16, 0);

    var defaultBase;
    var defaultExponent;
    var defaultModulus;
    var checked;
    var callback;

    // @todo test
    if (arguments.length === 3) {
        checked = arguments[1];
        callback = arguments[2];
    } else if (arguments.length === 6) {
        defaultBase = arguments[1];
        defaultExponent = arguments[2];
        defaultModulus = arguments[3];
        checked = arguments[4];
        callback = arguments[5];
    } else {
        throw 'Invalid arguments!';
    }

    // @todo errorhandling!
    var modexps = [];
    for (var i = 0; i < arguments[0].length; i++) {
        modexps.push([typeof arguments[0][i][0] === 'undefined' ? defaultBase : arguments[0][i][0],
            typeof arguments[0][i][1] === 'undefined' ? defaultExponent : arguments[0][i][1],
            typeof arguments[0][i][2] === 'undefined' ? defaultModulus : arguments[0][i][2]]);
    }

    //////////////// Start of algorithm ///////////////
    var moduli = [];
    var modexpsB = [];
    var modexpsC = [];

    for (var i = 0; i < modexps.length; i++) {
        var a = BI.str2bigInt(modexps[i][1], 16, 0);
        var p = BI.str2bigInt(modexps[i][2], 16, 0);
        var q = BI.sub(p, ONE);                             // q = p-1
        var b = this._rand(q);
        var c = BI.mod(BI.sub(BI.add(a, q), b), q);         // c = (a+q)-b mod q

        moduli.push(p);
        modexpsB.push([modexps[i][0], BI.bigInt2str(b, 16), modexps[i][2]]);
        modexpsC.push([modexps[i][0], BI.bigInt2str(c, 16), modexps[i][2]]);
    }

    // calculate u^b*u^c mod p for all results with corresponding modulus
    function resultCallback(resB, resC, callback) {
        var results = [];
        if (typeof resB.r !== 'undefined') {                // single result
            results.push({r: BI.bigInt2str(BI.multMod(BI.str2bigInt(resB.r, 16, 0), BI.str2bigInt(resC.r, 16, 0), moduli[0]), 16)});
        } else {                                            // multiple results
            for (var i = 0; i < resB.length; i++) {
                results.push({r: BI.bigInt2str(BI.multMod(BI.str2bigInt(resB[i].r, 16, 0), BI.str2bigInt(resC[i].r, 16, 0), moduli[i]), 16)});
            }
        }
        callback(results);
    }

    // @todo randomize servers, checkability
    var resultB, resultC;
    this.modexps(modexpsB, function (result) {
        resultB = result;
        if (typeof resultC !== 'undefined') {
            resultCallback(resultB, resultC, callback);
            resultC = undefined;
        }
    });
    this.modexps(modexpsC, function (result) {
        resultC = result;
        if (typeof resultB !== 'undefined') {
            resultCallback(resultB, resultC, callback);
            resultB = undefined;
        }
    });
};

if (typeof module !== 'undefined' && module.hasOwnProperty('exports')) {
    module.exports = FamodulusClient;
}<|endoftext|>


<commit_before>'use strict';

const fs = require('fs');

require.extensions['.md'] = function (module, filename) {
  let initBlock = [];
  let examples = [];
  let definitions = {};

  const content = fs.readFileSync(filename, 'utf8').split("\n");

  let i = 0;

  while (i < content.length) {

    if (content[i] === '<!-- init-block') {
      ++i;
      while (i < content.length && content[i] !== '-->') {
        initBlock.push(content[i]);
        ++i;
      }
    } else if ((content[i] === '```js' || content[i] === '```javascript') &&
        (i === 0 || content[i - 1] !== '<!-- skip-test -->')) {

      const defined = content[i - 1].match(/<!-- define ([a-z-]+) -->/);

      const usingDefinition = content[i - 1].match(/<!-- use ([a-z-]+) -->/);

      ++i;
      let example = [];

      if (usingDefinition) {
        example = definitions[usingDefinition[1]].slice(0);
      }

      while (i < content.length && content[i] !== '```') {
        example.push(content[i]);
        ++i;
      }

      if (defined) {
        definitions[defined[1]] = example;
      }
      examples.push(example.join("\n"));
    }
    ++i;
  }

  var test = `
    ${initBlock.join("\n")}

    describe('Markdown file: ${filename}', function () {
      ${examples.map((example, index) => {
        let preview = example.replace(/'/g, "\\'");
        preview = preview.substr(0, preview.indexOf("\n")) || preview;

        return `it('should run API example #${index + 1}: ${preview}', function () {
          ${example}
        });`;
      }).join("\n")}
    });`;

  return module._compile(test, filename);
};
<commit_msg>Marked compiled tests as strict mode to avoid errors in Node v4 or v5<commit_after>'use strict';

const fs = require('fs');

require.extensions['.md'] = function (module, filename) {
  let initBlock = [];
  let examples = [];
  let definitions = {};

  const content = fs.readFileSync(filename, 'utf8').split("\n");

  let i = 0;

  while (i < content.length) {

    if (content[i] === '<!-- init-block') {
      ++i;
      while (i < content.length && content[i] !== '-->') {
        initBlock.push(content[i]);
        ++i;
      }
    } else if ((content[i] === '```js' || content[i] === '```javascript') &&
        (i === 0 || content[i - 1] !== '<!-- skip-test -->')) {

      const defined = content[i - 1].match(/<!-- define ([a-z-]+) -->/);

      const usingDefinition = content[i - 1].match(/<!-- use ([a-z-]+) -->/);

      ++i;
      let example = [];

      if (usingDefinition) {
        example = definitions[usingDefinition[1]].slice(0);
      }

      while (i < content.length && content[i] !== '```') {
        example.push(content[i]);
        ++i;
      }

      if (defined) {
        definitions[defined[1]] = example;
      }
      examples.push(example.join("\n"));
    }
    ++i;
  }

  var test = `
    'use strict';

    ${initBlock.join("\n")}

    describe('Markdown file: ${filename}', function () {
      ${examples.map((example, index) => {
        let preview = example.replace(/'/g, "\\'");
        preview = preview.substr(0, preview.indexOf("\n")) || preview;

        return `it('should run API example #${index + 1}: ${preview}', function () {
          ${example}
        });`;
      }).join("\n")}
    });`;

  return module._compile(test, filename);
};
<|endoftext|>


<commit_before>/**
 * A component representing a motor.
 * Props:
 *   id: a unique id string
 *   value: the speed, from 0 to 100.
 *   disconnected: Boolean indicator if this motor is disconnected
 */

import React from 'react';
import {Label} from 'react-bootstrap';
import NameEdit from './NameEdit';

var Motor = React.createClass({
  propTypes: {
    name: React.PropTypes.string,
    value: React.PropTypes.number
  },
  render() {
    return (

<NameEdit name={this.props.name} id={this.props.id} /> Motor

        {
          this.props.disconnected
          ? Disconnected
          : Math.round(this.props.value * 100) / 100
        }

    );
  }
});

export default Motor;
<commit_msg>Motor Displays Positive Sign<commit_after>/**
 * A component representing a motor.
 * Props:
 *   id: a unique id string
 *   value: the speed, from -100 to 100.
 *   disconnected: Boolean indicator if this motor is disconnected
 */

import React from 'react';
import {Label} from 'react-bootstrap';
import NameEdit from './NameEdit';

var _roundMotor = function(num) {
  if (num > 0) {
    return "+" + (Math.round(num * 100) / 100);
  } else return (Math.round(num * 100) / 100);
};

var Motor = React.createClass({
  propTypes: {
    name: React.PropTypes.string,
    value: React.PropTypes.number
  },
  render() {
    return (

<NameEdit name={this.props.name} id={this.props.id} /> Motor

        {
          this.props.disconnected
          ? Disconnected
          : (this.props.value > 0) ? "+" + (Math.round(this.props.value * 100) / 100):(Math.round(this.props.value * 100) / 100)
        }

    );
  }
});

export default Motor;
<|endoftext|>


<commit_before>const path = require('path')
const fs = require('fs-extra')

const Request = require('./Request')

const debug = require('debug')('Nexus:FileStore')

/**
 * Default options
 * @type {Object}
 */
const DEFAULT_OPTIONS = {
  checkRootExistence: true,
  ensureRoot: false,
  maxDepth: 0
}

/**
 * Class representing a local file store.
 */
class FileStore {
  /**
   * Supported read modes
   * @type {Array}
   */
  static get MODES_READ () { return [ 'r' ] }
  /**
   * Supported write modes
   * @type {Array}
   */
  static get MODES_WRITE () { return [ 'w', 'a' ] }

  /**
   * Read mode (r) (default)
   * @type {String}
   */
  static get MODE_READ () { return 'r' }
  /**
   * Append mode (a)
   * @type {String}
   */
  static get MODE_APPEND () { return 'a' }
  /**
   * Write mode
   * @type {String}
   */
  static get MODE_WRITE () { return 'w' }

  /**
   * Creates a new FileStore.
   * @param {String} [root=null] The absolute root path
   * @param {Object} [options={}] Options
   * @param {Boolean} [options.checkRootExistence=true] Check to make sure the root path is valid
   * @param {Boolean} [options.ensureRoot=false] Create the root path if it does not exist
   * @param {Number} [options.maxDepth=0] If set to a value higher than zero, limits the resource depth
   */
  constructor (root = null, options = {}) {
    this._options = Object.assign({}, DEFAULT_OPTIONS, options)
    if (root === null) {
      throw new TypeError('root can not be null')
    } else if (!path.isAbsolute(root)) {
      throw new TypeError('root must be an absolute path')
    } else if (this._options.checkRootExistence && !fs.existsSync(root)) {
      if (!this._options.ensureRoot) throw new Error('root does not exist')
      fs.ensureDirSync(root)
    }
    this._root = root
  }

  /**
   * Creates a new read stream to the provided resource.
   * @param {String} resource The path to the resource
   * @param {String} [mode=FileStore.MODE_READ] Mode to open resource in
   * @param {Object} [options] Stream options
   * @param {Number} [options.start=0] Start reading at this byte index
   * @param {Number} [options.end] Stop reading at this byte index
   * @return {Promise} Resolves with a readable stream to the resource
   */
  createReadStream (resource, mode = FileStore.MODE_READ, options = {}) {
    debug(`createReadStream ('${resource}', '${mode}')`)
    return new Promise((resolve, reject) => {
      if (!isNaN(this._options.maxDepth) && this._options.maxDepth > 0 && (resource.split('/').length - 1) > this._options.maxDepth) {
        return reject(new Request.Error(`Maximum Resource Depth (${this._options.maxDepth}) Exceeded`, Request.Error.BAD_REQUEST))
      }
      const resourcePath = this._getResourcePath(resource)
      if (FileStore.MODES_READ.indexOf(mode) === -1) {
        return reject(new Request.Error(`Unsupported Read Mode (${mode})`))
      }
      fs.stat(resourcePath, (err, stats) => {
        if (err) return reject(err)
        options = Object.assign({ start: 0 }, options, { flags: mode })
        if ((!isNaN(options.start) && options.start > stats.size) || (!isNaN(options.end) && options.end > stats.size)) {
          return reject(new Request.Error('Range Not Satisfiable', Request.Error.RANGE_NOT_SATISFIABLE))
        }
        resolve({ stream: fs.createReadStream(resourcePath, options), stats: stats })
      })
    })
  }

  /**
   * Creates a new write stream to the provided resource.
   * @param {String} resource The path to the resourc
   * @param {String} [mode=FileStore.MODE_WRITE] Mode to open the resource in
   * @param {Object} [options] Stream options
   * @param {Number} [options.start=0] Start writing at this byte index
   * @return {Promise} Resolves with a writable stream to the resource
   */
  createWriteStream (resource, mode = FileStore.MODE_WRITE, options = {}) {
    debug(`createWriteStream ('${resource}', '${mode}')`)
    return new Promise((resolve, reject) => {
      if (this._options.maxDepth > 0 && (resource.split('/').length - 1) > this._options.maxDepth) {
        return reject(new Request.Error(`Maximum Resource Depth (${this._options.maxDepth}) Exceeded`, Request.Error.BAD_REQUEST))
      }
      const resourcePath = this._getResourcePath(resource)
      if (FileStore.MODES_WRITE.indexOf(mode) === -1) {
        return reject(new Request.Error(`Unsupported Write Mode (${mode})`))
      }
      fs.ensureFile(resourcePath, err => {
        if (err) return reject(err)
        options = Object.assign({ start: 0 }, options, { flags: mode })
        resolve(fs.createWriteStream(resourcePath, options))
      })
    })
  }

  /**
   * Converts the resource path to an absolute file system path.
   * @param {String} resource The resource path
   * @return {String} An absolute path to the resource
   */
  _getResourcePath (resource) {
    let resourcePath = path.resolve(this._root, `.${resource}`)
    // With no extension add a period, so the file system will see it as a file
    if (path.extname(resourcePath) === '') resourcePath += '.'
    return resourcePath
  }
}

module.exports = exports = FileStore
<commit_msg>Add status code 400 to unsupported write mode error<commit_after>const path = require('path')
const fs = require('fs-extra')

const Request = require('./Request')

const debug = require('debug')('Nexus:FileStore')

/**
 * Default options
 * @type {Object}
 */
const DEFAULT_OPTIONS = {
  checkRootExistence: true,
  ensureRoot: false,
  maxDepth: 0
}

/**
 * Class representing a local file store.
 */
class FileStore {
  /**
   * Supported read modes
   * @type {Array}
   */
  static get MODES_READ () { return [ 'r' ] }
  /**
   * Supported write modes
   * @type {Array}
   */
  static get MODES_WRITE () { return [ 'w', 'a' ] }

  /**
   * Read mode (r) (default)
   * @type {String}
   */
  static get MODE_READ () { return 'r' }
  /**
   * Append mode (a)
   * @type {String}
   */
  static get MODE_APPEND () { return 'a' }
  /**
   * Write mode
   * @type {String}
   */
  static get MODE_WRITE () { return 'w' }

  /**
   * Creates a new FileStore.
   * @param {String} [root=null] The absolute root path
   * @param {Object} [options={}] Options
   * @param {Boolean} [options.checkRootExistence=true] Check to make sure the root path is valid
   * @param {Boolean} [options.ensureRoot=false] Create the root path if it does not exist
   * @param {Number} [options.maxDepth=0] If set to a value higher than zero, limits the resource depth
   */
  constructor (root = null, options = {}) {
    this._options = Object.assign({}, DEFAULT_OPTIONS, options)
    if (root === null) {
      throw new TypeError('root can not be null')
    } else if (!path.isAbsolute(root)) {
      throw new TypeError('root must be an absolute path')
    } else if (this._options.checkRootExistence && !fs.existsSync(root)) {
      if (!this._options.ensureRoot) throw new Error('root does not exist')
      fs.ensureDirSync(root)
    }
    this._root = root
  }

  /**
   * Creates a new read stream to the provided resource.
   * @param {String} resource The path to the resource
   * @param {String} [mode=FileStore.MODE_READ] Mode to open resource in
   * @param {Object} [options] Stream options
   * @param {Number} [options.start=0] Start reading at this byte index
   * @param {Number} [options.end] Stop reading at this byte index
   * @return {Promise} Resolves with a readable stream to the resource
   */
  createReadStream (resource, mode = FileStore.MODE_READ, options = {}) {
    debug(`createReadStream ('${resource}', '${mode}')`)
    return new Promise((resolve, reject) => {
      if (!isNaN(this._options.maxDepth) && this._options.maxDepth > 0 && (resource.split('/').length - 1) > this._options.maxDepth) {
        return reject(new Request.Error(`Maximum Resource Depth (${this._options.maxDepth}) Exceeded`, Request.Error.BAD_REQUEST))
      }
      const resourcePath = this._getResourcePath(resource)
      if (FileStore.MODES_READ.indexOf(mode) === -1) {
        return reject(new Request.Error(`Unsupported Read Mode (${mode})`, Request.Error.BAD_REQUEST))
      }
      fs.stat(resourcePath, (err, stats) => {
        if (err) return reject(err)
        options = Object.assign({ start: 0 }, options, { flags: mode })
        if ((!isNaN(options.start) && options.start > stats.size) || (!isNaN(options.end) && options.end > stats.size)) {
          return reject(new Request.Error('Range Not Satisfiable', Request.Error.RANGE_NOT_SATISFIABLE))
        }
        resolve({ stream: fs.createReadStream(resourcePath, options), stats: stats })
      })
    })
  }

  /**
   * Creates a new write stream to the provided resource.
   * @param {String} resource The path to the resourc
   * @param {String} [mode=FileStore.MODE_WRITE] Mode to open the resource in
   * @param {Object} [options] Stream options
   * @param {Number} [options.start=0] Start writing at this byte index
   * @return {Promise} Resolves with a writable stream to the resource
   */
  createWriteStream (resource, mode = FileStore.MODE_WRITE, options = {}) {
    debug(`createWriteStream ('${resource}', '${mode}')`)
    return new Promise((resolve, reject) => {
      if (this._options.maxDepth > 0 && (resource.split('/').length - 1) > this._options.maxDepth) {
        return reject(new Request.Error(`Maximum Resource Depth (${this._options.maxDepth}) Exceeded`, Request.Error.BAD_REQUEST))
      }
      const resourcePath = this._getResourcePath(resource)
      if (FileStore.MODES_WRITE.indexOf(mode) === -1) {
        return reject(new Request.Error(`Unsupported Write Mode (${mode})`, Request.Error.BAD_REQUEST))
      }
      fs.ensureFile(resourcePath, err => {
        if (err) return reject(err)
        options = Object.assign({ start: 0 }, options, { flags: mode })
        resolve(fs.createWriteStream(resourcePath, options))
      })
    })
  }

  /**
   * Converts the resource path to an absolute file system path.
   * @param {String} resource The resource path
   * @return {String} An absolute path to the resource
   */
  _getResourcePath (resource) {
    let resourcePath = path.resolve(this._root, `.${resource}`)
    // With no extension add a period, so the file system will see it as a file
    if (path.extname(resourcePath) === '') resourcePath += '.'
    return resourcePath
  }
}

module.exports = exports = FileStore
<|endoftext|>


<commit_before>"use strict";

// Currently using Sequelize and Postgresql for fastest possible implementataion.
// Those model classes should be refactored someday to support other database layers
// Ideally there should be a modular interface for the model layer. All activities are saved to
// elastic search through the logs. Based on https://www.w3.org/TR/activitystreams-core/

var async = require("async");
var log = require('../utils/logger');
var queue = require('../workers/queue');
var toJson = require('../utils/to_json');
var commonIndexForActivitiesAndNewsFeeds = require('../engine/news_feeds/activity_and_item_index_definitions').commonIndexForActivitiesAndNewsFeeds;
var _ = require('lodash');

var setupDefaultAssociations = function (activity, user, domain, community, group, done) {
  async.parallel([
    function(callback) {
      activity.setDomain(domain).then(function (results) {
        callback(results ? null : true);
      });
    },
    function(callback) {
      if (user) {
        activity.setUser(user).then(function (results) {
          callback(results ? null : true);
        });
      } else {
        callback();
      }
    },
    function(callback) {
      if (community) {
        activity.setCommunity(community).then(function (results) {
          callback(results ? null : true);
        });
      } else {
        callback();
      }
    },
    function(callback) {
      if (group) {
        activity.setGroup(group).then(function (results) {
          callback(results ? null : true);
        });
      } else {
        callback();
      }
    }
  ], function(error) {
    done(error)
  });
};

module.exports = function(sequelize, DataTypes) {
  var AcActivity = sequelize.define("AcActivity", {
    access: { type: DataTypes.INTEGER, allowNull: false },
    type: { type: DataTypes.STRING, allowNull: false },
    sub_type: { type: DataTypes.STRING, allowNull: true },
    status: { type: DataTypes.STRING, allowNull: false },
    object: DataTypes.JSONB,
    actor: DataTypes.JSONB,
    target: DataTypes.JSONB,
    context: DataTypes.JSONB,
    user_interaction_profile: DataTypes.JSONB,
    deleted: { type: DataTypes.BOOLEAN, allowNull: false, defaultValue: false }
  }, {

    defaultScope: {
      where: {
        deleted: false,
        status: 'active'
      }
    },

    timestamps: true,

    indexes: _.concat(commonIndexForActivitiesAndNewsFeeds('created_at'), [
      {
        name: 'activity_public_and_active_by_type',
        fields: ['type'],
        where: {
          access: 0,
          status: 'active',
          deleted: false
        }
      },
      {
        name: 'activity_active_by_type',
        fields: ['type'],
        where: {
          status: 'active',
          deleted: false
        }
      },
      {
        name: 'activity_public_and_active_by_domain_id',
        fields: ['domain_id'],
        where: {
          access: 0,
          status: 'active',
          deleted: false
        }
      },
      {
        name: 'activity_public_and_active_by_community_id',
        fields: ['community_id'],
        where: {
          access: 0,
          status: 'active',
          deleted: false
        }
      },
      {
        name: 'activity_active_by_community_id',
        fields: ['community_id'],
        where: {
          status: 'active',
          deleted: false
        }
      },
      {
        name: 'activity_public_and_active_by_group_id',
        fields: ['group_id'],
        where: {
          access: 0,
          status: 'active',
          deleted: false
        }
      },
      {
        name: 'activity_active_by_group_id',
        fields: ['group_id'],
        where: {
          status: 'active',
          deleted: false
        }
      },
      {
        name: 'activity_public_and_active_by_post_id',
        fields: ['post_id'],
        where: {
          access: 0,
          status: 'active',
          deleted: false
        }
      },
      {
        name: 'userid_groupid_deleted',
        fields: ['user_id','group_id','deleted']
      },
      {
        name: 'activity_active_by_post_id',
        fields: ['post_id'],
        where: {
          status: 'active',
          deleted: false
        }
      },
      {
        name: 'activity_all_by_type',
        fields: ['type']
      },
      {
        fields: ['object'],
        using: 'gin',
        operator: 'jsonb_path_ops'
      },
      {
        fields: ['actor'],
        using: 'gin',
        operator: 'jsonb_path_ops'
      },
      {
        fields: ['target'],
        using: 'gin',
        operator: 'jsonb_path_ops'
      },
      {
        fields: ['context'],
        using: 'gin',
        operator: 'jsonb_path_ops'
      },
      {
        fields: ['user_interaction_profile'],
        using: 'gin',
        operator: 'jsonb_path_ops'
      }
    ]),

    underscored: true,

    tableName: 'ac_activities',

    classMethods: {

      ACCESS_PUBLIC: 0,
      ACCESS_COMMUNITY: 1,
      ACCESS_GROUP: 2,
      ACCESS_PRIVATE: 3,

      associate: function(models) {
        AcActivity.belongsTo(models.Domain);
        AcActivity.belongsTo(models.Community);
        AcActivity.belongsTo(models.Group);
        AcActivity.belongsTo(models.Post);
        AcActivity.belongsTo(models.Point);
        AcActivity.belongsTo(models.Invite);
        AcActivity.belongsTo(models.User);
        AcActivity.belongsTo(models.Image);
        AcActivity.belongsTo(models.PostStatusChange);
        AcActivity.belongsToMany(models.User, { through: 'other_users' });
        AcActivity.belongsToMany(models.AcNotification, { as: 'AcActivities', through: 'notification_activities' });
      },

      createActivity: function(options, callback) {
        queue.create('delayed-job', { type: 'create-priority-activity', workData: options }).priority('critical').removeOnComplete(true).save();
        callback();
      },

      createPasswordRecovery: function(user, domain, community, token, done) {
        sequelize.models.AcActivity.build({
          type: "activity.password.recovery",
          status: 'active',
          actor: { user: user },
          object: {
            domainId: domain.id,
            communityId: community ? community.id : null,
            token: token
          },
          domain_id: domain.id,
          community_id: community ? community.id : null,
          user_id: user.id,
          access: sequelize.models.AcActivity.ACCESS_PRIVATE
        }).save().then(function(activity) {
          if (activity) {
            queue.create('process-activity', activity).priority('critical').removeOnComplete(true).save();
            log.info('Activity Created', { activity: toJson(activity), user: toJson(user) });
            done(null);
          } else {
            done('Activity Not Found');
          }
        }).catch(function(error) {
          log.error('Activity Created Error', { err: error });
          done(error);
        });
      },

      inviteCreated: function(options, done) {
        sequelize.models.AcActivity.build({
          type: "activity.user.invite",
          status: 'active',
          actor: { user_id: options.user_id, sender_user_id: options.sender_user_id },
          object: {
            email: options.email,
            token: options.token,
            invite_id: options.invite_id,
            sender_name: options.sender_name
          },
          community_id: options.community_id,
          group_id: options.group_id,
          domain_id: options.domain_id,
          user_id: options.user_id,
          access: sequelize.models.AcActivity.ACCESS_PRIVATE
        }).save().then(function(activity) {
          if (activity) {
            queue.create('process-activity', activity).priority('critical').removeOnComplete(true).save();
            log.info('Activity Created', { activity: toJson(activity), userId: options.user_id, email: options.email });
            done(null);
          } else {
            done('Activity Not Found');
          }
       }).catch(function(error) {
          log.error('Activity Created Error', { err: error });
          done(error);
        });
      }
    }
  });

  return AcActivity;
};
<commit_msg>Remove unused indexes<commit_after>"use strict";

// Currently using Sequelize and Postgresql for fastest possible implementataion.
// Those model classes should be refactored someday to support other database layers
// Ideally there should be a modular interface for the model layer. All activities are saved to
// elastic search through the logs. Based on https://www.w3.org/TR/activitystreams-core/

var async = require("async");
var log = require('../utils/logger');
var queue = require('../workers/queue');
var toJson = require('../utils/to_json');
var commonIndexForActivitiesAndNewsFeeds = require('../engine/news_feeds/activity_and_item_index_definitions').commonIndexForActivitiesAndNewsFeeds;
var _ = require('lodash');

var setupDefaultAssociations = function (activity, user, domain, community, group, done) {
  async.parallel([
    function(callback) {
      activity.setDomain(domain).then(function (results) {
        callback(results ? null : true);
      });
    },
    function(callback) {
      if (user) {
        activity.setUser(user).then(function (results) {
          callback(results ? null : true);
        });
      } else {
        callback();
      }
    },
    function(callback) {
      if (community) {
        activity.setCommunity(community).then(function (results) {
          callback(results ? null : true);
        });
      } else {
        callback();
      }
    },
    function(callback) {
      if (group) {
        activity.setGroup(group).then(function (results) {
          callback(results ? null : true);
        });
      } else {
        callback();
      }
    }
  ], function(error) {
    done(error)
  });
};

module.exports = function(sequelize, DataTypes) {
  var AcActivity = sequelize.define("AcActivity", {
    access: { type: DataTypes.INTEGER, allowNull: false },
    type: { type: DataTypes.STRING, allowNull: false },
    sub_type: { type: DataTypes.STRING, allowNull: true },
    status: { type: DataTypes.STRING, allowNull: false },
    object: DataTypes.JSONB,
    actor: DataTypes.JSONB,
    target: DataTypes.JSONB,
    context: DataTypes.JSONB,
    user_interaction_profile: DataTypes.JSONB,
    deleted: { type: DataTypes.BOOLEAN, allowNull: false, defaultValue: false }
  }, {

    defaultScope: {
      where: {
        deleted: false,
        status: 'active'
      }
    },

    timestamps: true,

    indexes: _.concat(commonIndexForActivitiesAndNewsFeeds('created_at'), [
      {
        name: 'activity_public_and_active_by_type',
        fields: ['type'],
        where: {
          access: 0,
          status: 'active',
          deleted: false
        }
      },
      {
        name: 'activity_active_by_type',
        fields: ['type'],
        where: {
          status: 'active',
          deleted: false
        }
      },
      {
        name: 'activity_public_and_active_by_domain_id',
        fields: ['domain_id'],
        where: {
          access: 0,
          status: 'active',
          deleted: false
        }
      },
      {
        name: 'activity_public_and_active_by_community_id',
        fields: ['community_id'],
        where: {
          access: 0,
          status: 'active',
          deleted: false
        }
      },
      {
        name: 'activity_active_by_community_id',
        fields: ['community_id'],
        where: {
          status: 'active',
          deleted: false
        }
      },
      {
        name: 'activity_public_and_active_by_group_id',
        fields: ['group_id'],
        where: {
          access: 0,
          status: 'active',
          deleted: false
        }
      },
      {
        name: 'activity_active_by_group_id',
        fields: ['group_id'],
        where: {
          status: 'active',
          deleted: false
        }
      },
      {
        name: 'activity_public_and_active_by_post_id',
        fields: ['post_id'],
        where: {
          access: 0,
          status: 'active',
          deleted: false
        }
      },
      {
        name: 'userid_groupid_deleted',
        fields: ['user_id','group_id','deleted']
      },
      {
        name: 'activity_active_by_post_id',
        fields: ['post_id'],
        where: {
          status: 'active',
          deleted: false
        }
      },
      {
        name: 'activity_all_by_type',
        fields: ['type']
      }
    ]),

    underscored: true,

    tableName: 'ac_activities',

    classMethods: {

      ACCESS_PUBLIC: 0,
      ACCESS_COMMUNITY: 1,
      ACCESS_GROUP: 2,
      ACCESS_PRIVATE: 3,

      associate: function(models) {
        AcActivity.belongsTo(models.Domain);
        AcActivity.belongsTo(models.Community);
        AcActivity.belongsTo(models.Group);
        AcActivity.belongsTo(models.Post);
        AcActivity.belongsTo(models.Point);
        AcActivity.belongsTo(models.Invite);
        AcActivity.belongsTo(models.User);
        AcActivity.belongsTo(models.Image);
        AcActivity.belongsTo(models.PostStatusChange);
        AcActivity.belongsToMany(models.User, { through: 'other_users' });
        AcActivity.belongsToMany(models.AcNotification, { as: 'AcActivities', through: 'notification_activities' });
      },

      createActivity: function(options, callback) {
        queue.create('delayed-job', { type: 'create-priority-activity', workData: options }).priority('critical').removeOnComplete(true).save();
        callback();
      },

      createPasswordRecovery: function(user, domain, community, token, done) {
        sequelize.models.AcActivity.build({
          type: "activity.password.recovery",
          status: 'active',
          actor: { user: user },
          object: {
            domainId: domain.id,
            communityId: community ? community.id : null,
            token: token
          },
          domain_id: domain.id,
          community_id: community ? community.id : null,
          user_id: user.id,
          access: sequelize.models.AcActivity.ACCESS_PRIVATE
        }).save().then(function(activity) {
          if (activity) {
            queue.create('process-activity', activity).priority('critical').removeOnComplete(true).save();
            log.info('Activity Created', { activity: toJson(activity), user: toJson(user) });
            done(null);
          } else {
            done('Activity Not Found');
          }
        }).catch(function(error) {
          log.error('Activity Created Error', { err: error });
          done(error);
        });
      },

      inviteCreated: function(options, done) {
        sequelize.models.AcActivity.build({
          type: "activity.user.invite",
          status: 'active',
          actor: { user_id: options.user_id, sender_user_id: options.sender_user_id },
          object: {
            email: options.email,
            token: options.token,
            invite_id: options.invite_id,
            sender_name: options.sender_name
          },
          community_id: options.community_id,
          group_id: options.group_id,
          domain_id: options.domain_id,
          user_id: options.user_id,
          access: sequelize.models.AcActivity.ACCESS_PRIVATE
        }).save().then(function(activity) {
          if (activity) {
            queue.create('process-activity', activity).priority('critical').removeOnComplete(true).save();
            log.info('Activity Created', { activity: toJson(activity), userId: options.user_id, email: options.email });
            done(null);
          } else {
            done('Activity Not Found');
          }
       }).catch(function(error) {
          log.error('Activity Created Error', { err: error });
          done(error);
        });
      }
    }
  });

  return AcActivity;
};
<|endoftext|>


<commit_before>const path = require('path')
const fs = require('fs-extra')

const debug = require('debug')('Nexus:FileStore')

/**
 * Default options
 * @type {Object}
 */
const DEFAULT_OPTIONS = {
  checkRootExistence: true,
  ensureRoot: false,
  maxDepth: 0
}

/**
 * Class representing a local file store.
 */
class FileStore {
  /**
   * Supported read modes
   * @type {Array}
   */
  static get MODES_READ () { return [ 'r' ] }
  /**
   * Supported write modes
   * @type {Array}
   */
  static get MODES_WRITE () { return [ 'w', 'a' ] }

  /**
   * Read mode (r) (default)
   * @type {String}
   */
  static get MODE_READ () { return 'r' }
  /**
   * Append mode (a)
   * @type {String}
   */
  static get MODE_APPEND () { return 'a' }
  /**
   * Write mode
   * @type {String}
   */
  static get MODE_WRITE () { return 'w' }

  /**
   * Creates a new FileStore.
   * @param {String} [root=null] The absolute root path
   * @param {Object} [options={}] Options
   * @param {Boolean} [options.checkRootExistence=true] Check to make sure the root path is valid
   * @param {Boolean} [options.ensureRoot=false] Create the root path if it does not exist
   * @param {Number} [options.maxDepth=0] If set to a value higher than zero, limits the resource depth
   */
  constructor (root = null, options = {}) {
    this._options = Object.assign({}, DEFAULT_OPTIONS, options)
    if (root === null) {
      throw new TypeError('root can not be null')
    } else if (!path.isAbsolute(root)) {
      throw new TypeError('root must be an absolute path')
    } else if (this._options.checkRootExistence && !fs.existsSync(root)) {
      if (!this._options.ensureRoot) throw new Error('root does not exist')
      fs.ensureDirSync(root)
    }
    this._root = root
  }

  /**
   * Creates a new read stream to the provided resource.
   * @param {String} resource The path to the resource
   * @param {String} [mode=FileStore.MODE_READ] Mode to open resource in
   * @param {Object} [options] Stream options
   * @param {Number} [options.start=0] Start reading at this byte index
   * @param {Number} [options.end] Stop reading at this byte index
   * @return {Promise} Resolves with a readable stream to the resource
   */
  createReadStream (resource, mode = FileStore.MODE_READ, options = { start: 0 }) {
    debug(`createReadStream ('${resource}', '${mode}')`)
    return new Promise((resolve, reject) => {
      if (this._options.maxDepth > 0 && (resource.split('/').length - 1) > this._options.maxDepth) {
        return reject(new Error(`maximum resource depth (${this._options.maxDepth}) exceeded`))
      }
      const resourcePath = this._getResourcePath(resource)
      if (FileStore.MODES_READ.indexOf(mode) === -1) {
        return reject(new TypeError(`unsupported read mode (${mode})`))
      }
      fs.access(resourcePath, fs.constants.R_OK, err => {
        if (err) return reject(err)
        resolve(fs.createReadStream(resourcePath, { flags: mode, start: options.start || 0 }))
      })
    })
  }

  /**
   * Creates a new write stream to the provided resource.
   * @param {String} resource The path to the resourc
   * @param {String} [mode=FileStore.MODE_WRITE] Mode to open the resource in
   * @param {Object} [options] Stream options
   * @param {Number} [options.start=0] Start writing at this byte index
   * @return {Promise} Resolves with a writable stream to the resource
   */
  createWriteStream (resource, mode = FileStore.MODE_WRITE, options = { start: 0 }) {
    debug(`createWriteStream ('${resource}', '${mode}')`)
    return new Promise((resolve, reject) => {
      if (this._options.maxDepth > 0 && (resource.split('/').length - 1) > this._options.maxDepth) {
        return reject(new Error(`maximum resource depth (${this._options.maxDepth}) exceeded`))
      }
      const resourcePath = this._getResourcePath(resource)
      if (FileStore.MODES_WRITE.indexOf(mode) === -1) {
        return reject(new TypeError(`unsupported write mode (${mode})`))
      }
      fs.ensureFile(resourcePath, err => {
        if (err) return reject(err)
        options = Object.assign({}, { start: 0 }, options, { flags: mode })
        resolve(fs.createWriteStream(resourcePath, options))
      })
    })
  }

  /**
   * Converts the resource path to an absolute file system path.
   * @param {String} resource The resource path
   * @return {String} An absolute path to the resource
   */
  _getResourcePath (resource) {
    let resourcePath = path.resolve(this._root, `.${resource}`)
    // With no extension add a period, so the file system will see it as a file
    if (path.extname(resourcePath) === '') resourcePath += '.'
    return resourcePath
  }
}

module.exports = exports = FileStore
<commit_msg>Simplify read/write options passing<commit_after>const path = require('path')
const fs = require('fs-extra')

const debug = require('debug')('Nexus:FileStore')

/**
 * Default options
 * @type {Object}
 */
const DEFAULT_OPTIONS = {
  checkRootExistence: true,
  ensureRoot: false,
  maxDepth: 0
}

/**
 * Class representing a local file store.
 */
class FileStore {
  /**
   * Supported read modes
   * @type {Array}
   */
  static get MODES_READ () { return [ 'r' ] }
  /**
   * Supported write modes
   * @type {Array}
   */
  static get MODES_WRITE () { return [ 'w', 'a' ] }

  /**
   * Read mode (r) (default)
   * @type {String}
   */
  static get MODE_READ () { return 'r' }
  /**
   * Append mode (a)
   * @type {String}
   */
  static get MODE_APPEND () { return 'a' }
  /**
   * Write mode
   * @type {String}
   */
  static get MODE_WRITE () { return 'w' }

  /**
   * Creates a new FileStore.
   * @param {String} [root=null] The absolute root path
   * @param {Object} [options={}] Options
   * @param {Boolean} [options.checkRootExistence=true] Check to make sure the root path is valid
   * @param {Boolean} [options.ensureRoot=false] Create the root path if it does not exist
   * @param {Number} [options.maxDepth=0] If set to a value higher than zero, limits the resource depth
   */
  constructor (root = null, options = {}) {
    this._options = Object.assign({}, DEFAULT_OPTIONS, options)
    if (root === null) {
      throw new TypeError('root can not be null')
    } else if (!path.isAbsolute(root)) {
      throw new TypeError('root must be an absolute path')
    } else if (this._options.checkRootExistence && !fs.existsSync(root)) {
      if (!this._options.ensureRoot) throw new Error('root does not exist')
      fs.ensureDirSync(root)
    }
    this._root = root
  }

  /**
   * Creates a new read stream to the provided resource.
   * @param {String} resource The path to the resource
   * @param {String} [mode=FileStore.MODE_READ] Mode to open resource in
   * @param {Object} [options] Stream options
   * @param {Number} [options.start=0] Start reading at this byte index
   * @param {Number} [options.end] Stop reading at this byte index
   * @return {Promise} Resolves with a readable stream to the resource
   */
  createReadStream (resource, mode = FileStore.MODE_READ, options = {}) {
    debug(`createReadStream ('${resource}', '${mode}')`)
    return new Promise((resolve, reject) => {
      if (this._options.maxDepth > 0 && (resource.split('/').length - 1) > this._options.maxDepth) {
        return reject(new Error(`maximum resource depth (${this._options.maxDepth}) exceeded`))
      }
      const resourcePath = this._getResourcePath(resource)
      if (FileStore.MODES_READ.indexOf(mode) === -1) {
        return reject(new TypeError(`unsupported read mode (${mode})`))
      }
      fs.access(resourcePath, fs.constants.R_OK, err => {
        if (err) return reject(err)
        options = Object.assign({ start: 0 }, options, { flags: mode })
        resolve(fs.createReadStream(resourcePath, options))
      })
    })
  }

  /**
   * Creates a new write stream to the provided resource.
   * @param {String} resource The path to the resourc
   * @param {String} [mode=FileStore.MODE_WRITE] Mode to open the resource in
   * @param {Object} [options] Stream options
   * @param {Number} [options.start=0] Start writing at this byte index
   * @return {Promise} Resolves with a writable stream to the resource
   */
  createWriteStream (resource, mode = FileStore.MODE_WRITE, options = {}) {
    debug(`createWriteStream ('${resource}', '${mode}')`)
    return new Promise((resolve, reject) => {
      if (this._options.maxDepth > 0 && (resource.split('/').length - 1) > this._options.maxDepth) {
        return reject(new Error(`maximum resource depth (${this._options.maxDepth}) exceeded`))
      }
      const resourcePath = this._getResourcePath(resource)
      if (FileStore.MODES_WRITE.indexOf(mode) === -1) {
        return reject(new TypeError(`unsupported write mode (${mode})`))
      }
      fs.ensureFile(resourcePath, err => {
        if (err) return reject(err)
        options = Object.assign({ start: 0 }, options, { flags: mode })
        resolve(fs.createWriteStream(resourcePath, options))
      })
    })
  }

  /**
   * Converts the resource path to an absolute file system path.
   * @param {String} resource The resource path
   * @return {String} An absolute path to the resource
   */
  _getResourcePath (resource) {
    let resourcePath = path.resolve(this._root, `.${resource}`)
    // With no extension add a period, so the file system will see it as a file
    if (path.extname(resourcePath) === '') resourcePath += '.'
    return resourcePath
  }
}

module.exports = exports = FileStore
<|endoftext|>


<commit_before>if (!PhoneGap.hasResource("network")) {
	PhoneGap.addResource("network");

// //////////////////////////////////////////////////////////////////

Connection = function() {
	/*
	 * One of the connection constants below.
	 */
	this.type = Connection.UNKNOWN;

	/* initialize from the extended DeviceInfo properties */
    try {
		this.type	= DeviceInfo.connection.type;
    }
	catch(e) {
    }
};

Connection.UNKNOWN = "unknown"; // Unknown connection type
Connection.ETHERNET = "ethernet";
Connection.WIFI = "wifi";
Connection.CELL_2G = "2g";
Connection.CELL_3G = "3g";
Connection.CELL_4G = "4g";
Connection.NONE = "none"; // NO connectivity

// //////////////////////////////////////////////////////////////////

/**
 * This class contains information about any NetworkStatus.
 * @constructor
 */
NetworkStatus = function() {
	this.code = null;
	this.message = "";
}

NetworkStatus.NOT_REACHABLE = 0;
NetworkStatus.REACHABLE_VIA_CARRIER_DATA_NETWORK = 1;
NetworkStatus.REACHABLE_VIA_WIFI_NETWORK = 2;

/**
 * This class provides access to device Network data (reachability).
 * @constructor
 */
Network = function() {
};

/**
 *
 * @param {Function} successCallback
 * @param {Function} errorCallback
 * @param {Object} options
 */
Network.prototype.isReachable = function(hostName, successCallback, options) {
	console.warn("Network.isReachable is deprecated and will be removed in 1.0. Please use the Network Information API instead.");
	PhoneGap.exec("Network.isReachable", hostName, GetFunctionName(successCallback), options);
};

PhoneGap.addConstructor(function() {
    if (typeof navigator.network == "undefined") navigator.network = new Network();
    if (typeof navigator.network.connection == "undefined") navigator.network.connection = new Connection();
});

};<commit_msg>Removed JavaScript interface for #157<commit_after>if (!PhoneGap.hasResource("network")) {
	PhoneGap.addResource("network");

// //////////////////////////////////////////////////////////////////

Connection = function() {
	/*
	 * One of the connection constants below.
	 */
	this.type = Connection.UNKNOWN;

	/* initialize from the extended DeviceInfo properties */
    try {
		this.type	= DeviceInfo.connection.type;
    }
	catch(e) {
    }
};

Connection.UNKNOWN = "unknown"; // Unknown connection type
Connection.ETHERNET = "ethernet";
Connection.WIFI = "wifi";
Connection.CELL_2G = "2g"; // the default for iOS, for any cellular connection
Connection.CELL_3G = "3g";
Connection.CELL_4G = "4g";
Connection.NONE = "none"; // NO connectivity

PhoneGap.addConstructor(function() {
    if (typeof navigator.network.connection == "undefined") navigator.network.connection = new Connection();
});

};<|endoftext|>


<commit_before>module.exports = function (grunt) {
    grunt.initConfig({
        pkg: grunt.file.readJSON('package.json'),
        jshint: {
            all: '../test/*.js'
        },
        qunit: {
            all: '../test/index.html'
        }
    });

    grunt.loadNpmTasks('grunt-contrib-qunit');
    grunt.loadNpmTasks('grunt-contrib-jshint');

    grunt.registerTask('test', ['jshint', 'qunit']);
    grunt.registerTask('default', ['test']);
};
<commit_msg>Delete Gruntfile.js<commit_after><|endoftext|>


<commit_before>'use strict';

const Sequelize = require('sequelize');

const sequelize = require('../../lib/sequelize')('shard');

module.exports = sequelize.define('transfer', {
  transfer_id: {
    type: Sequelize.INTEGER,
    allowNull: false,
    primaryKey: true,
    autoIncrement: true,
    comment: '流量 Id',
  },
  user_id: {
    type: Sequelize.STRING(32),
    allowNull: false,
    comment: '用户 Id',
  },
  node_id: {
    type: Sequelize.INTEGER,
    allowNull: false,
    comment: '节点 Id',
  },
  flow_up: {
    type: Sequelize.BIGINT,
    allowNull: false,
    defaultValue: 0,
    comment: '上传流量',
  },
  flow_down: {
    type: Sequelize.BIGINT,
    allowNull: false,
    defaultValue: 0,
    comment: '下载流量',
  },
}, {
  updatedAt: false,
  underscored: true,
  freezeTableName: true,
  tableName: 'ss_transfer',
});
<commit_msg>feat:修改数据模型<commit_after>'use strict';

const Sequelize = require('sequelize');

const sequelize = require('../../lib/sequelize')('shard');

module.exports = sequelize.define('transfer', {
  transfer_id: {
    type: Sequelize.INTEGER,
    allowNull: false,
    primaryKey: true,
    autoIncrement: true,
    comment: '流量 Id',
  },
  user_id: {
    type: Sequelize.STRING(32),
    allowNull: false,
    comment: '用户 Id',
  },
  node_id: {
    type: Sequelize.INTEGER,
    allowNull: false,
    comment: '节点 Id',
  },
  flow_up: {
    type: Sequelize.BIGINT,
    allowNull: false,
    defaultValue: 0,
    comment: '上传流量',
  },
  flow_down: {
    type: Sequelize.BIGINT,
    allowNull: false,
    defaultValue: 0,
    comment: '下载流量',
  },
  active_at: {
    type: Sequelize.DATE,
    defaultValue: Sequelize.NOW,
    allowNull: false,
    comment: '活跃时间',
  },
}, {
  createdAt: false,
  updatedAt: false,
  underscored: true,
  freezeTableName: true,
  tableName: 'ss_transfer',
});
<|endoftext|>


<commit_before>define(function (require, exports, module) {
  'use strict';

  var L20n = require('../l20n');
  var io = require('./platform/io');

  var ctx;
  var isBootstrapped = false;
  var isPretranslated;
  var rtlLocales = ['ar', 'fa', 'he', 'ps', 'ur'];

  if (typeof(document) === 'undefined') {
    // during build time, we don't bootstrap until mozL10n.language.code is set
    Object.defineProperty(navigator, 'mozL10n', {
      get: function() {
        isBootstrapped = false;
        ctx = L20n.getContext();
        return createPublicAPI(ctx);
      },
      enumerable: true
    });
  } else {
    ctx = L20n.getContext();
    navigator.mozL10n = createPublicAPI(ctx);
    isPretranslated = document.documentElement.lang === navigator.language;

    window.addEventListener('load', function() {
      bootstrap();
    });
    if (!isPretranslated) {
      if (document.readyState === 'loading') {
        // wait for interactive to perform inline localization
        document.addEventListener('DOMContentLoaded', function() {
          inlineLocalization();
        });
      } else {
        // perform inline localization right now
        inlineLocalization();
      }
    }
  }

  function inlineLocalization() {
    var body = document.body;
    var scripts = body.querySelectorAll('script[type="application/l10n"]');
    if (scripts.length) {
      var inline = L20n.getContext();
      var langs = [];
      for (var i = 0; i < scripts.length; i++) {
        var lang = scripts[i].getAttribute('lang');
        langs.push(lang);
        // pass the node to save memory
        inline.addDictionary(scripts[i], lang);
      }
      inline.once(function() {
        translateFragment(inline);
        isPretranslated = true;
      });
      inline.registerLocales('en-US', langs);
      inline.requestLocales(navigator.language);
    }
  }

  function bootstrap(forcedLocale) {
    isBootstrapped = true;
    ctx.addEventListener('error', console.warn.bind(console));
    ctx.addEventListener('warning', console.info.bind(console));

    var availableLocales = [];

    var head = document.head;
    var iniLinks = head.querySelectorAll('link[type="application/l10n"]' +
                                         '[href$=".ini"]');
    var jsonLinks = head.querySelectorAll('link[type="application/l10n"]' +
                                          '[href$=".json"]');

    for (var i = 0; i < jsonLinks.length; i++) {
      var uri = jsonLinks[i].getAttribute('href');
      ctx.linkResource(uri.replace.bind(uri, /\{\{\s*locale\s*\}\}/));
    }

    ctx.ready(function() {
      // XXX instead of using a flag, we could store the list of
      // yet-to-localize nodes that we get from the inline context, and
      // localize them here.
      if (!isPretranslated) {
        translateFragment(ctx);
      }
      isPretranslated = false;
      fireLocalizedEvent(ctx);
    });

    // listen to language change events
    if ('mozSettings' in navigator && navigator.mozSettings) {
      navigator.mozSettings.addObserver('language.current', function(event) {
        ctx.requestLocales(event.settingValue);
      });
    }

    var iniToLoad = iniLinks.length;
    if (iniToLoad === 0) {
      ctx.registerLocales('en-US', getAvailable());
      ctx.requestLocales(forcedLocale || navigator.language);
      return;
    }

    for (var i = 0; i < iniLinks.length; i++) {
      var url = iniLinks[i].getAttribute('href');
      io.load(url, iniLoaded.bind(null, url));
    }

    function iniLoaded(url, err, text) {
      if (err) {
        throw err;
      }
      var ini = parseINI(text, url);
      availableLocales.push.apply(availableLocales, ini.locales);
      for (var i = 0; i < ini.resources.length; i++) {
        var uri = ini.resources[i].replace('en-US', '{{locale}}');
        ctx.linkResource(uri.replace.bind(uri, '{{locale}}'));
      }
      iniToLoad--;
      if (iniToLoad == 0) {
        ctx.registerLocales('en-US', availableLocales);
        ctx.requestLocales(forcedLocale || navigator.language);
      }
    }

  }

  function getAvailable() {
    var metaLocs = document.head.querySelector('meta[name="locales"]');
    if (metaLocs) {
      return metaLocs.getAttribute('content').split(',').map(String.trim);
    } else {
      return [];
    }
  }

  var patterns = {
    ini: {
      section: /^\s*\[(.*)\]\s*$/,
      import: /^\s*@import\s+url\((.*)\)\s*$/i
    }
  };

  function parseINI(source, iniPath) {
    var entries = source.split(/[\r\n]+/);
    var locales = ['en-US'];
    var genericSection = true;
    var uris = [];

    for (var i = 0; i < entries.length; i++) {
      var line = entries[i];
      // we only care about en-US resources
      if (genericSection && patterns['ini']['import'].test(line)) {
        var match = patterns['ini']['import'].exec(line);
        var uri = relativePath(iniPath, match[1]);
        uris.push(uri);
        continue;
      }
      // but we need the list of all locales in the ini, too
      if (patterns['ini']['section'].test(line)) {
        genericSection = false;
        var match = patterns['ini']['section'].exec(line);
        locales.push(match[1]);
      }
    }
    return {
      locales: locales,
      resources: uris
    };
  }

  function relativePath(baseUrl, url) {
    if (url[0] == '/') {
      return url;
    }
    var dirs = baseUrl.split('/')
      .slice(0, -1)
      .concat(url.split('/'))
      .filter(function(elem) {
        return elem !== '.';
      });

    return dirs.join('/');
  }

  function createPublicAPI(ctx) {
    return {
      get: ctx.get.bind(ctx),
      localize: localizeElement.bind(null, ctx),
      translate: translateFragment.bind(null, ctx),
      language: {
        get code() {
          return ctx.supportedLocales[0];
        },
        set code(lang) {
          if (!isBootstrapped) {
            // build-time optimization uses this
            bootstrap(lang);
          } else {
            ctx.requestLocales(lang);
          }
        },
        get direction() {
          if (rtlLocales.indexOf(ctx.supportedLocales[0]) >= 0) {
            return 'rtl';
          } else {
            return 'ltr';
          }
        }
      },
      ready: ctx.ready.bind(ctx),
      getDictionary: getSubDictionary,
      get readyState() {
        return ctx.isReady ? 'complete' : 'loading';
      }
    };
  }

  // return a sub-dictionary sufficient to translate a given fragment
  function getSubDictionary(fragment) {
    var ast = {
      type: 'WebL10n',
      body: []
    };

    if (!fragment) {
      ast.body = ctx.getSources();
      return ast;
    }

    var elements = getTranslatableChildren(fragment);

    for (var i = 0, l = elements.length; i < l; i++) {
      var id = elements[i].getAttribute('data-l10n-id');
      var source = ctx.getSource(id);
      if (!source) {
        continue;
      }

      ast.body.push(source);
      // check for any dependencies
      // XXX should this be recursive?
      if (source.value && source.value.type === 'ComplexString') {
        source.value.body.forEach(function (chunk) {
          if (chunk.type == 'Identifier') {
            ast.body.push(ctx.getSource(chunk.name));
          }
        });
      }
    }
    return ast;
  }

  function getTranslatableChildren(element) {
    return element ? element.querySelectorAll('*[data-l10n-id]') : [];
  }

  function getL10nAttributes(element) {
    if (!element) {
      return {};
    }

    var l10nId = element.getAttribute('data-l10n-id');
    var l10nArgs = element.getAttribute('data-l10n-args');
    var args = {};
    if (l10nArgs) {
      try {
        args = JSON.parse(l10nArgs);
      } catch (e) {
        consoleWarn('could not parse arguments for #' + l10nId);
      }
    }
    return { id: l10nId, args: args };
  }

  function setTextContent(element, text) {
    // standard case: no element children
    if (!element.firstElementChild) {
      element.textContent = text;
      return;
    }

    // this element has element children: replace the content of the first
    // (non-blank) child textNode and clear other child textNodes
    var found = false;
    var reNotBlank = /\S/;
    for (var child = element.firstChild; child; child = child.nextSibling) {
      if (child.nodeType === 3 && reNotBlank.test(child.nodeValue)) {
        if (found) {
          child.nodeValue = '';
        } else {
          child.nodeValue = text;
          found = true;
        }
      }
    }
    // if no (non-empty) textNode is found, insert a textNode before the
    // element's first child.
    if (!found) {
      element.insertBefore(document.createTextNode(text), element.firstChild);
    }
  }

  function translateNode(ctx, node) {
    var attrs = getL10nAttributes(node);
    if (!attrs.id) {
      return true;
    }
    var entity = ctx.getEntity(attrs.id, attrs.args);
    if (!entity) {
      return false;
    }
    setTextContent(node, entity.value);

    for (var i in entity.attributes) {
      node.setAttribute(i, entity.attributes[i]);
    }
  }

  // localize an element as soon as ctx is ready
  function localizeElement(ctx, element, id, args) {
    if (!element || !id) {
      return;
    }

    // set the data-l10n-[id|args] attributes
    element.setAttribute('data-l10n-id', id);
    if (args) {
      element.setAttribute('data-l10n-args', JSON.stringify(args));
    } else {
      element.removeAttribute('data-l10n-args');
    }

    // if ctx is ready, translate now;
    // if not, the element will be translated along with the document anyway.
    if (ctx.isReady) {
      translateNode(ctx, element);
    }
  }

  // translate an array of HTML elements
  // -- returns an array of elements that could not be translated
  function translateElements(ctx, elements) {
    var untranslated = [];
    for (var i = 0, l = elements.length; i < l; i++) {
      if (!translateNode(ctx, elements[i])) {
        untranslated.push(elements[i]);
      }
    }
    return untranslated;
  }

  // translate an HTML subtree
  // -- returns an array of elements that could not be translated
  function translateFragment(ctx, element) {
    element = element || document.documentElement;
    var untranslated = translateElements(ctx, getTranslatableChildren(element));
    if (!translateNode(ctx, element)) {
      untranslated.push(element);
    }
    return untranslated;
  }

  function fireLocalizedEvent(ctx) {
    var event = document.createEvent('Event');
    event.initEvent('localized', false, false);
    event.language = ctx.supportedLocales[0];
    window.dispatchEvent(event);
  }

  return L20n;
});
<commit_msg>window.addEventListener('load', …)<commit_after>define(function (require, exports, module) {
  'use strict';

  var L20n = require('../l20n');
  var io = require('./platform/io');

  var ctx;
  var isBootstrapped = false;
  var isPretranslated;
  var rtlLocales = ['ar', 'fa', 'he', 'ps', 'ur'];

  if (typeof(document) === 'undefined') {
    // during build time, we don't bootstrap until mozL10n.language.code is set
    Object.defineProperty(navigator, 'mozL10n', {
      get: function() {
        isBootstrapped = false;
        ctx = L20n.getContext();
        return createPublicAPI(ctx);
      },
      enumerable: true
    });
  } else {
    ctx = L20n.getContext();
    navigator.mozL10n = createPublicAPI(ctx);
    isPretranslated = document.documentElement.lang === navigator.language;

    if (isPretranslated) {
      window.addEventListener('load', function() {
        window.setTimeout(bootstrap);
      });
    } else {
      if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', pretranslate);
      } else {
        pretranslate();
      }
    }
  }

  function pretranslate() {
    if (inlineLocalization()) {
      window.addEventListener('load', function() {
        window.setTimeout(bootstrap);
      });
    } else {
      bootstrap();
    }
  }

  function inlineLocalization() {
    var body = document.body;
    var scripts = body.querySelectorAll('script[type="application/l10n"]');
    if (scripts.length === 0) {
      return false;
    }
    var inline = L20n.getContext();
    var langs = [];
    for (var i = 0; i < scripts.length; i++) {
      var lang = scripts[i].getAttribute('lang');
      langs.push(lang);
      // pass the node to save memory
      inline.addDictionary(scripts[i], lang);
    }
    inline.once(function() {
      translateFragment(inline);
      isPretranslated = true;
    });
    inline.registerLocales('en-US', langs);
    inline.requestLocales(navigator.language);
    // XXX check if we actually negotiatied navigator.language (i.e. the
    // corresponding <script> was present)?
    return true;
  }

  function bootstrap(forcedLocale) {
    isBootstrapped = true;
    ctx.addEventListener('error', console.warn.bind(console));
    ctx.addEventListener('warning', console.info.bind(console));

    var availableLocales = [];

    var head = document.head;
    var iniLinks = head.querySelectorAll('link[type="application/l10n"]' +
                                         '[href$=".ini"]');
    var jsonLinks = head.querySelectorAll('link[type="application/l10n"]' +
                                          '[href$=".json"]');

    for (var i = 0; i < jsonLinks.length; i++) {
      var uri = jsonLinks[i].getAttribute('href');
      ctx.linkResource(uri.replace.bind(uri, /\{\{\s*locale\s*\}\}/));
    }

    ctx.ready(function() {
      // XXX instead of using a flag, we could store the list of
      // yet-to-localize nodes that we get from the inline context, and
      // localize them here.
      if (!isPretranslated) {
        translateFragment(ctx);
      }
      isPretranslated = false;
      fireLocalizedEvent(ctx);
    });

    // listen to language change events
    if ('mozSettings' in navigator && navigator.mozSettings) {
      navigator.mozSettings.addObserver('language.current', function(event) {
        ctx.requestLocales(event.settingValue);
      });
    }

    var iniToLoad = iniLinks.length;
    if (iniToLoad === 0) {
      ctx.registerLocales('en-US', getAvailable());
      ctx.requestLocales(forcedLocale || navigator.language);
      return;
    }

    for (var i = 0; i < iniLinks.length; i++) {
      var url = iniLinks[i].getAttribute('href');
      io.load(url, iniLoaded.bind(null, url));
    }

    function iniLoaded(url, err, text) {
      if (err) {
        throw err;
      }
      var ini = parseINI(text, url);
      availableLocales.push.apply(availableLocales, ini.locales);
      for (var i = 0; i < ini.resources.length; i++) {
        var uri = ini.resources[i].replace('en-US', '{{locale}}');
        ctx.linkResource(uri.replace.bind(uri, '{{locale}}'));
      }
      iniToLoad--;
      if (iniToLoad == 0) {
        ctx.registerLocales('en-US', availableLocales);
        ctx.requestLocales(forcedLocale || navigator.language);
      }
    }

  }

  function getAvailable() {
    var metaLocs = document.head.querySelector('meta[name="locales"]');
    if (metaLocs) {
      return metaLocs.getAttribute('content').split(',').map(String.trim);
    } else {
      return [];
    }
  }

  var patterns = {
    ini: {
      section: /^\s*\[(.*)\]\s*$/,
      import: /^\s*@import\s+url\((.*)\)\s*$/i
    }
  };

  function parseINI(source, iniPath) {
    var entries = source.split(/[\r\n]+/);
    var locales = ['en-US'];
    var genericSection = true;
    var uris = [];

    for (var i = 0; i < entries.length; i++) {
      var line = entries[i];
      // we only care about en-US resources
      if (genericSection && patterns['ini']['import'].test(line)) {
        var match = patterns['ini']['import'].exec(line);
        var uri = relativePath(iniPath, match[1]);
        uris.push(uri);
        continue;
      }
      // but we need the list of all locales in the ini, too
      if (patterns['ini']['section'].test(line)) {
        genericSection = false;
        var match = patterns['ini']['section'].exec(line);
        locales.push(match[1]);
      }
    }
    return {
      locales: locales,
      resources: uris
    };
  }

  function relativePath(baseUrl, url) {
    if (url[0] == '/') {
      return url;
    }
    var dirs = baseUrl.split('/')
      .slice(0, -1)
      .concat(url.split('/'))
      .filter(function(elem) {
        return elem !== '.';
      });

    return dirs.join('/');
  }

  function createPublicAPI(ctx) {
    return {
      get: ctx.get.bind(ctx),
      localize: localizeElement.bind(null, ctx),
      translate: translateFragment.bind(null, ctx),
      language: {
        get code() {
          return ctx.supportedLocales[0];
        },
        set code(lang) {
          if (!isBootstrapped) {
            // build-time optimization uses this
            bootstrap(lang);
          } else {
            ctx.requestLocales(lang);
          }
        },
        get direction() {
          if (rtlLocales.indexOf(ctx.supportedLocales[0]) >= 0) {
            return 'rtl';
          } else {
            return 'ltr';
          }
        }
      },
      ready: ctx.ready.bind(ctx),
      getDictionary: getSubDictionary,
      get readyState() {
        return ctx.isReady ? 'complete' : 'loading';
      }
    };
  }

  // return a sub-dictionary sufficient to translate a given fragment
  function getSubDictionary(fragment) {
    var ast = {
      type: 'WebL10n',
      body: []
    };

    if (!fragment) {
      ast.body = ctx.getSources();
      return ast;
    }

    var elements = getTranslatableChildren(fragment);

    for (var i = 0, l = elements.length; i < l; i++) {
      var id = elements[i].getAttribute('data-l10n-id');
      var source = ctx.getSource(id);
      if (!source) {
        continue;
      }

      ast.body.push(source);
      // check for any dependencies
      // XXX should this be recursive?
      if (source.value && source.value.type === 'ComplexString') {
        source.value.body.forEach(function (chunk) {
          if (chunk.type == 'Identifier') {
            ast.body.push(ctx.getSource(chunk.name));
          }
        });
      }
    }
    return ast;
  }

  function getTranslatableChildren(element) {
    return element ? element.querySelectorAll('*[data-l10n-id]') : [];
  }

  function getL10nAttributes(element) {
    if (!element) {
      return {};
    }

    var l10nId = element.getAttribute('data-l10n-id');
    var l10nArgs = element.getAttribute('data-l10n-args');
    var args = {};
    if (l10nArgs) {
      try {
        args = JSON.parse(l10nArgs);
      } catch (e) {
        consoleWarn('could not parse arguments for #' + l10nId);
      }
    }
    return { id: l10nId, args: args };
  }

  function setTextContent(element, text) {
    // standard case: no element children
    if (!element.firstElementChild) {
      element.textContent = text;
      return;
    }

    // this element has element children: replace the content of the first
    // (non-blank) child textNode and clear other child textNodes
    var found = false;
    var reNotBlank = /\S/;
    for (var child = element.firstChild; child; child = child.nextSibling) {
      if (child.nodeType === 3 && reNotBlank.test(child.nodeValue)) {
        if (found) {
          child.nodeValue = '';
        } else {
          child.nodeValue = text;
          found = true;
        }
      }
    }
    // if no (non-empty) textNode is found, insert a textNode before the
    // element's first child.
    if (!found) {
      element.insertBefore(document.createTextNode(text), element.firstChild);
    }
  }

  function translateNode(ctx, node) {
    var attrs = getL10nAttributes(node);
    if (!attrs.id) {
      return true;
    }
    var entity = ctx.getEntity(attrs.id, attrs.args);
    if (!entity) {
      return false;
    }
    setTextContent(node, entity.value);

    for (var i in entity.attributes) {
      node.setAttribute(i, entity.attributes[i]);
    }
  }

  // localize an element as soon as ctx is ready
  function localizeElement(ctx, element, id, args) {
    if (!element || !id) {
      return;
    }

    // set the data-l10n-[id|args] attributes
    element.setAttribute('data-l10n-id', id);
    if (args) {
      element.setAttribute('data-l10n-args', JSON.stringify(args));
    } else {
      element.removeAttribute('data-l10n-args');
    }

    // if ctx is ready, translate now;
    // if not, the element will be translated along with the document anyway.
    if (ctx.isReady) {
      translateNode(ctx, element);
    }
  }

  // translate an array of HTML elements
  // -- returns an array of elements that could not be translated
  function translateElements(ctx, elements) {
    var untranslated = [];
    for (var i = 0, l = elements.length; i < l; i++) {
      if (!translateNode(ctx, elements[i])) {
        untranslated.push(elements[i]);
      }
    }
    return untranslated;
  }

  // translate an HTML subtree
  // -- returns an array of elements that could not be translated
  function translateFragment(ctx, element) {
    element = element || document.documentElement;
    var untranslated = translateElements(ctx, getTranslatableChildren(element));
    if (!translateNode(ctx, element)) {
      untranslated.push(element);
    }
    return untranslated;
  }

  function fireLocalizedEvent(ctx) {
    var event = document.createEvent('Event');
    event.initEvent('localized', false, false);
    event.language = ctx.supportedLocales[0];
    window.dispatchEvent(event);
  }

  return L20n;
});
<|endoftext|>