diff --git a/configs/client-default.js b/configs/client-default.js index c0859368..50593d86 100644 --- a/configs/client-default.js +++ b/configs/client-default.js @@ -709,7 +709,6 @@ module.exports = function(options) { premium: options.project.premium, } }, - "plugins/c9.ide.abtesting/abtesting", { packagePath: "plugins/c9.ide.welcome/welcome", staticPrefix: staticPrefix + "/plugins/c9.ide.welcome", diff --git a/configs/standalone.js b/configs/standalone.js index 44c95a36..bb6f596e 100644 --- a/configs/standalone.js +++ b/configs/standalone.js @@ -158,6 +158,7 @@ module.exports = function(config, optimist) { "c9.vfs.client": true, "c9.cli.bridge": true, "c9.nodeapi": true, + "c9.ide.experiment": true, "saucelabs.preview": true, "salesforce.sync": true, "salesforce.language": true @@ -193,6 +194,7 @@ module.exports = function(config, optimist) { "./c9.vfs.server/statics", "./c9.analytics/mock_analytics", "./c9.metrics/mock_metrics", + "./c9.ide.experiment/mock_experiment", { packagePath: "./c9.vfs.server/vfs.connect.standalone", workspaceDir: baseProc, diff --git a/package.json b/package.json index 29ac5a8c..9613ac17 100644 --- a/package.json +++ b/package.json @@ -67,7 +67,7 @@ "c9.ide.language.javascript.infer": "#18acb93a3a", "c9.ide.language.jsonalyzer": "#4b329741b1", "c9.ide.language.codeintel": "#253ae15f5e", - "c9.ide.collab": "#28129e17ae", + "c9.ide.collab": "#9c8fec5d78", "c9.ide.local": "#10eb45842a", "c9.ide.find": "#e33fbaed2f", "c9.ide.find.infiles": "#c0a13737ef", diff --git a/plugins/c9.abtesting/abtesting.js b/plugins/c9.abtesting/abtesting.js deleted file mode 100644 index 44fc2b00..00000000 --- a/plugins/c9.abtesting/abtesting.js +++ /dev/null @@ -1,86 +0,0 @@ -/** - * Server-side support for A/B testing experiments. - * - * Note that this plugin demands users and user IDs for most of its API, - * where this is optional in the client-side implementation. - */ -main.consumes = ["analytics"]; -main.provides = ["abtesting"]; -module.exports = main; - -function main(options, imports, register) { - var analytics = imports["analytics"]; - var outplan = require("outplan"); - - var MS_PER_DAY = 1000 * 60 * 60 * 24; - - outplan.configure({ - logFunction: function(e) { - var label = e.name + " - " + e.event; - analytics.track(label, { variation: e.params.name }); - } - }); - - function create(name, choices, options) { - return outplan.create(name, choices, options); - } - - function expose(experimentName, userId, options) { - return outplan.expose(experimentName, userId, options); - } - - function isUserCreatedAfter(experimentDate, user) { - if (!user || !user.date_add) - throw new Error("Expected: user"); - var diffDays = (experimentDate - Date.now()) / MS_PER_DAY; - if (diffDays > 20) { - // Sanity check: new Date() takes zero-based month argument, one-based day argument - throw new Error("Passed a date far in the future to isUserCreatedAfter()"); - } - return user.date_add > experimentDate; - } - - register(null, { - "abtesting": { - /** - * Create a new experiment. Alias for require("outplan").create() - * - * @param {String} name - * The name of the experiment. - * @param {String[]|Object[]} choices - * A list of variations, e.g. ["A", "B"], - * or variation objects, e.g. [{ name: "A", color: "#AAA" }, { name: "B", color: "#BBB" }] - * @param {Object} [option] - * Options for the experiment. This may also include - * arguments for the distribution operator, e.g. weight. - * @param {Function} [options.operator] - * The distribution operator, e.g. outplan.WeightedChoice. - */ - create: create, - - /** - * Get the selected variation of an experiment, and call the log function with - * an "expose" event to track its exposure. - * - * @param {String} name The experiment name. - * @param {Number} userId A unique identifier for the current user. - * @param {Object} [options] Options - * @param {Boolean} [options.log=true] Whether to log an "exposure event" - */ - expose: expose, - - /** - * Helper to determine if the current user was created after the start of an experiment. - * - * @throws {Error} when a date in the future (~20 days from now) is passed. - * This error is thrown as a sanity check to make sure `new Date()` - * is called with a zero-based month argument (and a one-based day). - * - * @param {Date} experimentDate - * @param {Object} user A user object - * @param {Number} user.date_add - */ - isUserCreatedAfter: isUserCreatedAfter, - } - }); -} diff --git a/plugins/c9.ide.abtesting/abtesting.js b/plugins/c9.ide.abtesting/abtesting.js deleted file mode 100644 index 1a7160db..00000000 --- a/plugins/c9.ide.abtesting/abtesting.js +++ /dev/null @@ -1,105 +0,0 @@ -/** - * Client-side support for A/B testing experiments. - */ -define(function(require, exports, module) { - "use strict"; - - main.consumes = ["Plugin", "info", "c9.analytics"]; - main.provides = ["abtesting"]; - return main; - - function main(options, imports, register) { - var Plugin = imports.Plugin; - var plugin = new Plugin("Ajax.org", main.consumes); - var info = imports.info; - var analytics = imports["c9.analytics"]; - var outplan = require("outplan"); - - var MS_PER_DAY = 1000 * 60 * 60 * 24; - - var userId; - - plugin.on("load", function() { - userId = info.getUser().id; - outplan.configure({ - logFunction: function(e) { - var label = e.name + " - " + e.event; - analytics.track(label, { variation: e.params.name }); - } - }); - }); - - plugin.on("unload", function() { - userId = undefined; - }); - - function create(name, choices, options) { - var experiment = outplan.create(name, choices, options); - experiment.expose = expose.bind(null, name); - return experiment; - } - - function expose(experimentName, overrideUserId, options) { - if (overrideUserId && typeof overrideUserId === "object") - return expose(experimentName, null, options); - - return outplan.expose(experimentName, overrideUserId == null ? userId : overrideUserId, options); - } - - function isUserCreatedAfter(experimentDate) { - var diffDays = (experimentDate - Date.now()) / MS_PER_DAY; - if (diffDays > 20) { - // Sanity check: new Date() takes zero-based month argument, one-based day argument - throw new Error("Passed a date far in the future to isUserCreatedAfter()"); - } - return info.getUser().date_add > experimentDate; - } - - /** - * Support for A/B testing experiments. - */ - plugin.freezePublicAPI({ - /** - * Create a new experiment. Alias for require("outplan").create() - * - * @param {String} name - * The name of the experiment. - * @param {String[]|Object[]} choices - * A list of variations, e.g. ["A", "B"], - * or variation objects, e.g. [{ name: "A", color: "#AAA" }, { name: "B", color: "#BBB" }] - * @param {Object} [option] - * Options for the experiment. This may also include - * arguments for the distribution operator, e.g. weight. - * @param {Function} [options.operator] - * The distribution operator, e.g. outplan.WeightedChoice. - */ - create: create, - - /** - * Get the selected variation of an experiment, and call the log function with - * an "expose" event to track its exposure. - * - * @param {String} name The experiment name. - * @param {Number} [userId] A unique identifier for the current user. - * @param {Object} [options] Options - * @param {Boolean} [options.log=true] Whether to log an "exposure event" - */ - expose: expose, - - /** - * Helper to determine if the current user was created after the start of an experiment. - * - * @throws {Error} when a date in the future (~20 days from now) is passed. - * This error is thrown as a sanity check to make sure `new Date()` - * is called with a zero-based month argument (and a one-based day). - * - * @param {Date} experimentDate - */ - isUserCreatedAfter: isUserCreatedAfter, - }); - - register(null, { - "abtesting": plugin - }); - } -}); diff --git a/plugins/c9.ide.experiment/mock_experiment.js b/plugins/c9.ide.experiment/mock_experiment.js new file mode 100644 index 00000000..e3b80734 --- /dev/null +++ b/plugins/c9.ide.experiment/mock_experiment.js @@ -0,0 +1,26 @@ +/** + * Dummy implementation of experiments. + */ +"use strict"; + +plugin.consumes = []; +plugin.provides = ["experiment"]; + +module.exports = plugin; + +function plugin(options, imports, register) { + + register(null, { + "experiment": { + configure: function() {}, + onStart: function() { + var chain = { + variation: function() { + return chain; + } + }; + return chain; + } + } + }); +} \ No newline at end of file diff --git a/plugins/c9.ide.server/plugins.js b/plugins/c9.ide.server/plugins.js index d8ef4ca4..64c2fe89 100644 --- a/plugins/c9.ide.server/plugins.js +++ b/plugins/c9.ide.server/plugins.js @@ -41,7 +41,6 @@ define(function(require, exports, module) { ui: "lib/ui", c9: "lib/c9", frontdoor: "lib/frontdoor", - outplan: "lib/outplan/dist/outplan", }; if (whitelist === "*") { @@ -71,7 +70,6 @@ define(function(require, exports, module) { "ui", "emmet", "frontdoor", - "outplan", "mocha", // TESTING "chai", // TESTING ].forEach(function(name) {