Socket
Socket
Sign inDemoInstall

planout

Package Overview
Dependencies
4
Maintainers
3
Versions
38
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 3.0.3 to 4.0.0

build/planoutAPIFactory.js

2

__tests__/testExperiment.js

@@ -299,3 +299,3 @@ var Interpreter = require.requireActual('../dist/planout.js').Interpreter;

};
experimentTester(TestInterpretedExperiment);
experimentTester(TestInterpretedExperiment, true);
});

@@ -302,0 +302,0 @@

@@ -69,3 +69,3 @@ var UniformChoice = require.requireActual('../dist/planout.js').Ops.Random.UniformChoice;

assign(params, args) {
params.set('foo', new UniformChoice({'choices': ['a', 'b'], 'unit': args.userid}));
params.set('foo', new UniformChoiceCompat({'choices': ['a', 'b'], 'unit': args.userid}));
params.set('paramVal', args.paramVal);

@@ -78,3 +78,3 @@ params.set('funcVal', args.funcVal);

assign(params, args) {
params.set('foobar', new UniformChoice({'choices': ['a', 'b'], 'unit': args.userid}));
params.set('foobar', new UniformChoiceCompat({'choices': ['a', 'b'], 'unit': args.userid}));
params.set('paramVal', args.paramVal);

@@ -112,4 +112,4 @@ params.set('funcVal', args.funcVal);

setupExperiments() {
this.addExperiment('Experiment1', Experiment1, 50);
this.addExperiment('Experiment2', Experiment2, 50);
this.addExperiment('Experiment1', Experiment1Compat, 50);
this.addExperiment('Experiment2', Experiment2Compat, 50);
}

@@ -152,4 +152,4 @@ };

var namespace2 = new TestNamespace();
expect(namespace2.get('foo')).toEqual(undefined);
expect(namespace2.get('paramVal')).toEqual(undefined);
expect(namespace2.get('foo')).toBeUndefined();
expect(namespace2.get('paramVal')).toBeUndefined();
});

@@ -170,4 +170,4 @@

var namespace2 = new TestNamespace();
expect(namespace2.get('foo')).toEqual(undefined);
expect(namespace2.get('paramVal')).toEqual(undefined);
expect(namespace2.get('foo')).toEqual('b');
expect(namespace2.get('paramVal')).toBeUndefined();
});

@@ -174,0 +174,0 @@

var Interpreter = require.requireActual('../dist/planout.js').Interpreter;
var PlanOutOpCommutative = require.requireActual('../dist/planout.js').Ops.Base.PlanOutOpCommutative;
var InterpreterCompat = require.requireActual('../dist/planout_core_compatible.js').Interpreter;
var PlanOutOpCommutative = require('../es6/ops/base').PlanOutOpCommutative;
var PlanOutOpCommutativeCompat = require.requireActual('../dist/planout_core_compatible.js').Ops.Base.PlanOutOpCommutative;
class CustomOp extends PlanOutOpCommutative {

@@ -15,3 +17,13 @@ commutativeExecute(values) {

var compiled =
class CustomOpCompat extends PlanOutOpCommutativeCompat {
commutativeExecute(values) {
var value = 0;
for (var i = 0; i < values.length; i++) {
value += values[i];
}
return value;
}
}
var compiled =
{"op":"seq","seq":[{"op":"set","var":"group_size","value":{"choices":{"op":"array","values":[1,10]},"unit":{"op":"get","var":"userid"},"op":"uniformChoice"}},{"op":"set","var":"specific_goal","value":{"p":0.8,"unit":{"op":"get","var":"userid"},"op":"bernoulliTrial"}},{"op":"cond","cond":[{"if":{"op":"get","var":"specific_goal"},"then":{"op":"seq","seq":[{"op":"set","var":"ratings_per_user_goal","value":{"choices":{"op":"array","values":[8,16,32,64]},"unit":{"op":"get","var":"userid"},"op":"uniformChoice"}},{"op":"set","var":"ratings_goal","value":{"op":"product","values":[{"op":"get","var":"group_size"},{"op":"get","var":"ratings_per_user_goal"}]}}]}}]}]};

@@ -30,5 +42,5 @@ var interpreterSalt = 'foo';

expect(proc.getParams().specific_goal).toEqual(1);
expect(proc.getParams().ratings_goal).toEqual(64);
expect(proc.getParams().ratings_goal).toEqual(320);
});
it('should allow overrides', function() {

@@ -116,5 +128,5 @@ var proc = new Interpreter(compiled, interpreterSalt, { 'userid': 123454});

var proc = new InterpreterCompat(customOpScript, interpreterSalt, { userId: 123454 });
proc.registerCustomOperators({ 'customOp': CustomOp });
proc.registerCustomOperators({ 'customOp': CustomOpCompat });
expect(proc.getParams()['x']).toEqual(6);
});
});

@@ -1,2 +0,5 @@

var Utils = require('../es6/lib/utils.js');
// This is not exposed by the built library, so we load it directly here.
var Utils = require.requireActual('../es6/lib/utils.js');
// Load up our built library implementations for testing
var Namespace = require.requireActual('../dist/planout.js').Namespace;

@@ -9,3 +12,2 @@ var Experiment = require.requireActual('../dist/planout.js').Experiment;

class BaseExperiment extends Experiment {

@@ -187,2 +189,8 @@ configureLogger() {

validateSegments(namespace, segValidation);
expect(new TestNamespace({'userid': 'a'}).get('test')).toEqual(1);
expect(new TestNamespace({'userid': 'b'}).get('test')).toEqual(1);
expect(new TestNamespace({'userid': 'c'}).get('test')).toEqual(2);
expect(new TestNamespace({'userid': 'd'}).get('test')).toEqual(1);
expect(new TestNamespace({'userid': 'e'}).get('test')).toEqual(2);
});

@@ -207,2 +215,8 @@

validateSegments(namespace, segValidation);
expect(new TestNamespace({'userid': 'a'}).get('test')).toEqual(2);
expect(new TestNamespace({'userid': 'b'}).get('test')).toEqual(2);
expect(new TestNamespace({'userid': 'c'}).get('test')).toEqual(1);
expect(new TestNamespace({'userid': 'd'}).get('test')).toEqual(2);
expect(new TestNamespace({'userid': 'e'}).get('test')).toEqual(2);
});

@@ -273,3 +287,3 @@

expect(globalLog.length).toEqual(1);
expect(namespace.get('test'));
expect(namespace.get('test')).toBeUndefined();
validateLog("Experiment3");

@@ -291,6 +305,6 @@ });

var namespace = new TestNamespace({'userid': 'hi'});
expect(namespace.get('test2')).toEqual(3);
expect(namespace.get('test')).toEqual(1);
expect(globalLog.length).toEqual(1);
expect(namespace.get('test'));
validateLog("Experiment3");
expect(namespace.get('test2')).toBeUndefined();
validateLog("Experiment1");
});

@@ -297,0 +311,0 @@

@@ -142,3 +142,3 @@ var Assignment = require.requireActual('../dist/planout.js').Assignment;

});
it('works for uniform choice', function() {

@@ -212,2 +212,18 @@ var N = 10000;

testDistributions();
// Test that falsy choices don't get skipped
// null is omitted since it gets converted to undefined in Assignment.get()
var counts = {};
counts[0] = 0;
counts[1] = 0;
counts[false] = 0;
counts[undefined] = 0;
for (var i = 0; i < N; i++) {
var a = new Assignment('falsy');
a.set('x', new Random.WeightedChoice({ 'choices': [0, false, undefined, 1], 'weights': [1, 1, 1, 1], 'unit': i}));
counts[a.get('x')]++;
}
Object.keys(counts).forEach(function(key) {
expect(counts[key]).not.toBe(0);
});
});

@@ -243,2 +259,18 @@

testDistributions();
// Test that falsy choices don't get skipped
// null is omitted since it gets converted to undefined in Assignment.get()
var counts = {};
counts[0] = 0;
counts[1] = 0;
counts[false] = 0;
counts[undefined] = 0;
for (var i = 0; i < N; i++) {
var a = new Assignment('falsy');
a.set('x', new Random.WeightedChoice({ 'choices': [0, false, undefined, 1], 'weights': [1, 1, 1, 1], 'unit': i}));
counts[a.get('x')]++;
}
Object.keys(counts).forEach(function(key) {
expect(counts[key]).not.toBe(0);
});
});

@@ -262,3 +294,3 @@

/* bad equivalent to zip() from python */
/* bad equivalent to zip() from python */
xsList.forEach(function(xs, i){

@@ -276,3 +308,3 @@ xs.forEach(function(x, j) {

});
}
}
});

@@ -310,3 +342,3 @@ }

/* bad equivalent to zip() from python */
/* bad equivalent to zip() from python */
xsList.forEach(function(xs, i){

@@ -324,3 +356,3 @@ xs.forEach(function(x, j) {

});
}
}
});

@@ -327,0 +359,0 @@ }

{
"name": "planout",
"main": "dist/planout.js",
"version": "3.0.2",
"version": "4.0.0",
"homepage": "https://www.github.com/HubSpot/PlanOut.js",

@@ -6,0 +6,0 @@ "author": "Guy Aridor <garidor@gmail.com>",

@@ -1,20 +0,4 @@

import Experiment from '../es6/experiment';
import Interpreter from '../es6/interpreter';
import RandomPlanoutCoreCompatible from '../es6/ops/randomPlanoutCoreCompatible';
import Core from '../es6/ops/core';
import * as Namespace from '../es6/namespace';
import Assignment from '../es6/assignment';
import ExperimentSetup from '../es6/experimentSetup';
import planoutAPIFactory from './planoutAPIFactory';
import * as Random from '../es6/ops/randomPlanoutCoreCompatible';
export default {
Namespace: Namespace,
Assignment: Assignment,
Interpreter: Interpreter,
Experiment: Experiment,
ExperimentSetup: ExperimentSetup,
Ops: {
Random: RandomPlanoutCoreCompatible,
Core: Core
}
};
export default planoutAPIFactory({Random});

@@ -1,19 +0,4 @@

import Experiment from '../es6/experiment';
import Interpreter from '../es6/interpreter';
import Random from '../es6/ops/random';
import Core from '../es6/ops/core';
import * as Namespace from '../es6/namespace';
import Assignment from '../es6/assignment';
import ExperimentSetup from '../es6/experimentSetup';
import planoutAPIFactory from './planoutAPIFactory';
import * as Random from '../es6/ops/random';
export default {
Namespace: Namespace,
Assignment: Assignment,
Interpreter: Interpreter,
Experiment: Experiment,
ExperimentSetup: ExperimentSetup,
Ops: {
Random: Random,
Core: Core
}
};
export default planoutAPIFactory({Random});

@@ -0,1 +1,11 @@

##Changes in 4.0##
- Core compatible bundle fixes:
- Core compatible namespace allocations now match core reference namespace allocations from python version of planout.
- Core compatible interpreted experiment enrollment now matches core reference interpreted experiment enrollment from python version of planout.
- Separated the concerns of planout core random operations, and the planout API. The planout.js API (experiment, assignment, namespace, etc) are now composed with the random operations they are passed. This change has no effect on the usage of planout.js and only affects the development experience for contributors.
- Added ```planoutAPIFactory.js``` to keep planout bundles consistent, and to make it easier to compose new planout bundles with the random operations of choice.
- Made experiment & namespace names required to fix https://github.com/HubSpot/PlanOut.js/issues/57
- Fixes ```WeightedChoice``` with false-y choices.
- Fixes tests on windows + running the travis tests on windows as well if this is possible.
##Changes in 3.0##

@@ -18,3 +28,3 @@ - Separate out compat + non-compat bundles to reduce filesize of the main bundle by removing the BigNumber dependency (https://github.com/HubSpot/PlanOut.js/pull/29/). The default distribution on npm is the non-compat bundle, but the compat bundle is available in the `dist` folder

##Changes in 1.2.3##
- Exposure now only gets logged on the get function call if it is a valid parameter as defined by getParamNames()
- Exposure now only gets logged on the get function call if it is a valid parameter as defined by getParamNames()

@@ -26,2 +36,2 @@ * Changes in 1.2

- getParams(experimentName) is now a function on the namespace class
- getParams(experimentName) is now a function on the namespace class

@@ -1,96 +0,97 @@

import { PlanOutOpRandom } from "./ops/random";
import { shallowCopy, forEach, hasKey } from "./lib/utils";
class Assignment {
constructor(experimentSalt, overrides) {
if (!overrides) {
overrides = {};
export default function provideAssignment(Random) {
class Assignment {
constructor(experimentSalt, overrides) {
if (!overrides) {
overrides = {};
}
this.experimentSalt = experimentSalt;
this._overrides = shallowCopy(overrides);
this._data = shallowCopy(overrides);
this.saltSeparator = '.';
}
this.experimentSalt = experimentSalt;
this._overrides = shallowCopy(overrides);
this._data = shallowCopy(overrides);
this.saltSeparator = '.';
}
evaluate(value) {
return value;
}
evaluate(value) {
return value;
}
getOverrides() {
return this._overrides;
}
getOverrides() {
return this._overrides;
}
addOverride(key, value) {
this._overrides[key] = value;
this._data[key] = value;
}
addOverride(key, value) {
this._overrides[key] = value;
this._data[key] = value;
}
setOverrides(overrides) {
this._overrides = shallowCopy(overrides);
var self = this;
forEach(Object.keys(this._overrides), function(overrideKey) {
self._data[overrideKey] = self._overrides[overrideKey];
});
}
setOverrides(overrides) {
this._overrides = shallowCopy(overrides);
var self = this;
forEach(Object.keys(this._overrides), function(overrideKey) {
self._data[overrideKey] = self._overrides[overrideKey];
});
}
set(name, value) {
if (name === '_data') {
this._data = value;
return;
} else if (name === '_overrides') {
this._overrides = value;
return;
} else if (name === 'experimentSalt') {
this.experimentSalt = value;
return;
} else if (name === 'saltSeparator') {
this.saltSeparator = value;
return;
set(name, value) {
if (name === '_data') {
this._data = value;
return;
} else if (name === '_overrides') {
this._overrides = value;
return;
} else if (name === 'experimentSalt') {
this.experimentSalt = value;
return;
} else if (name === 'saltSeparator') {
this.saltSeparator = value;
return;
}
if (hasKey(this._overrides, name)) {
return;
}
if (value instanceof Random.PlanOutOpRandom) {
if (!value.args.salt) {
value.args.salt = name;
}
this._data[name] = value.execute(this);
} else {
this._data[name] = value;
}
}
if (hasKey(this._overrides, name)) {
return;
}
if (value instanceof PlanOutOpRandom) {
if (!value.args.salt) {
value.args.salt = name;
get(name, defaultVal) {
if (name === '_data') {
return this._data;
} else if(name === '_overrides') {
return this._overrides;
} else if (name === 'experimentSalt') {
return this.experimentSalt;
} else if (name === 'saltSeparator') {
return this.saltSeparator;
} else {
var value = this._data[name];
return value === null || value === undefined ? defaultVal : value;
}
this._data[name] = value.execute(this);
} else {
this._data[name] = value;
}
}
get(name, defaultVal) {
if (name === '_data') {
getParams() {
return this._data;
} else if(name === '_overrides') {
return this._overrides;
} else if (name === 'experimentSalt') {
return this.experimentSalt;
} else if (name === 'saltSeparator') {
return this.saltSeparator;
} else {
var value = this._data[name];
return value === null || value === undefined ? defaultVal : value;
}
}
getParams() {
return this._data;
}
del(name) {
delete this._data[name];
}
del(name) {
delete this._data[name];
}
toString() {
return String(this._data);
}
toString() {
return String(this._data);
}
length() {
return Object.keys(this._data).length;
}
};
length() {
return Object.keys(this._data).length;
}
};
export default Assignment;
return Assignment;
}

@@ -1,213 +0,204 @@

import Assignment from './assignment';
import { shallowCopy, extend, isObject, forEach, map, trimTrailingWhitespace } from './lib/utils';
class Experiment {
constructor(inputs) {
this.inputs = inputs;
this._exposureLogged = false;
this._salt = null;
this._inExperiment = true;
export default function provideExperiment(Assignment) {
class Experiment {
constructor(inputs) {
this.inputs = inputs;
this._exposureLogged = false;
this._salt = null;
this._inExperiment = true;
this._autoExposureLog = true;
this.name = this.getDefaultExperimentName();
this._autoExposureLog = true;
this.setup();
if (!this.name) {
throw "setup() must set an experiment name via this.setName()";
}
this.setup();
this._assignment = new Assignment(this.getSalt());
this._assigned = false;
}
this._assignment = new Assignment(this.getSalt());
this._assigned = false;
}
/* default implementation of fetching the range of experiment parameters that this experiment can take */
getDefaultParamNames() {
var assignmentFxn = this.assign.toString();
var possibleKeys = assignmentFxn.split('.set(');
possibleKeys.splice(0, 1); //remove first index since it'll have the function definitions
return map(possibleKeys, (val) => {
var str = trimTrailingWhitespace(val.split(',')[0]);
return str.substr(1, str.length-2); //remove string chars
});
}
//helper function to return the class name of the current experiment class
getDefaultExperimentName() {
if (isObject(this) && this.constructor && this !== this.window) {
var arr = this.constructor.toString().match(/function\s*(\w+)/);
if (arr && arr.length === 2) {
return arr[1];
requireAssignment() {
if (!this._assigned) {
this._assign();
}
}
return "GenericExperiment";
}
/* default implementation of fetching the range of experiment parameters that this experiment can take */
getDefaultParamNames() {
var assignmentFxn = this.assign.toString();
var possibleKeys = assignmentFxn.split('.set(');
possibleKeys.splice(0, 1); //remove first index since it'll have the function definitions
return map(possibleKeys, (val) => {
var str = trimTrailingWhitespace(val.split(',')[0]);
return str.substr(1, str.length-2); //remove string chars
});
}
requireExposureLogging(paramName) {
if (this.shouldLogExposure(paramName)) {
this.logExposure();
}
}
requireAssignment() {
if (!this._assigned) {
this._assign();
_assign() {
this.configureLogger();
var assignVal = this.assign(this._assignment, this.inputs);
if (assignVal || assignVal === undefined) {
this._inExperiment = true;
} else {
this._inExperiment = false;
}
this._assigned = true;
}
}
requireExposureLogging(paramName) {
if (this.shouldLogExposure(paramName)) {
this.logExposure();
setup() {
throw "IMPLEMENT setup";
}
}
_assign() {
this.configureLogger();
var assignVal = this.assign(this._assignment, this.inputs);
if (assignVal || assignVal === undefined) {
this._inExperiment = true;
} else {
this._inExperiment = false;
inExperiment() {
return this._inExperiment;
}
this._assigned = true;
}
setup() {
return;
}
addOverride(key, value) {
this._assignment.addOverride(key, value);
}
inExperiment() {
return this._inExperiment;
}
setOverrides(value) {
this._assignment.setOverrides(value);
var o = this._assignment.getOverrides();
var self = this;
forEach(Object.keys(o), function(key) {
if (self.inputs[key] !== undefined) {
self.inputs[key] = o[key];
}
});
}
addOverride(key, value) {
this._assignment.addOverride(key, value);
}
getSalt() {
if (this._salt) {
return this._salt;
} else {
return this.name;
}
}
setOverrides(value) {
this._assignment.setOverrides(value);
var o = this._assignment.getOverrides();
var self = this;
forEach(Object.keys(o), function(key) {
if (self.inputs[key] !== undefined) {
self.inputs[key] = o[key];
setSalt(value) {
this._salt = value;
if (this._assignment) {
this._assignment.experimentSalt = value;
}
});
}
}
getSalt() {
if (this._salt) {
return this._salt;
} else {
getName() {
return this.name;
}
}
setSalt(value) {
this._salt = value;
if (this._assignment) {
this._assignment.experimentSalt = value;
assign(params, args) {
throw "IMPLEMENT assign";
}
}
getName() {
return this.name;
}
/*
This function should return a list of the possible parameter names that the assignment procedure may assign.
You can optionally override this function to always return this.getDefaultParamNames()
which will analyze your program at runtime to determine what the range of possible experimental parameters are.
Otherwise, simply return a fixed list of the experimental parameters that your assignment procedure may assign.
*/
assign(params, args) {
throw "IMPLEMENT assign";
}
getParamNames() {
throw "IMPLEMENT getParamNames";
}
/*
This function should return a list of the possible parameter names that the assignment procedure may assign.
You can optionally override this function to always return this.getDefaultParamNames()
which will analyze your program at runtime to determine what the range of possible experimental parameters are.
Otherwise, simply return a fixed list of the experimental parameters that your assignment procedure may assign.
*/
getParamNames() {
throw "IMPLEMENT getParamNames";
}
shouldFetchExperimentParameter(name) {
const experimentalParams = this.getParamNames();
return experimentalParams.indexOf(name) >= 0;
}
shouldFetchExperimentParameter(name) {
const experimentalParams = this.getParamNames();
return experimentalParams.indexOf(name) >= 0;
}
setName(value) {
var re = /\s+/g;
this.name = value.replace(re, '-');
if (this._assignment) {
this._assignment.experimentSalt = this.getSalt();
}
}
setName(value) {
var re = /\s+/g;
this.name = value.replace(re, '-');
if (this._assignment) {
this._assignment.experimentSalt = this.getSalt();
__asBlob(extras={}) {
var d = {
'name': this.getName(),
'time': new Date().getTime() / 1000,
'salt': this.getSalt(),
'inputs': this.inputs,
'params': this._assignment.getParams()
};
extend(d, extras);
return d;
}
}
__asBlob(extras={}) {
var d = {
'name': this.getName(),
'time': new Date().getTime() / 1000,
'salt': this.getSalt(),
'inputs': this.inputs,
'params': this._assignment.getParams()
};
extend(d, extras);
return d;
}
setAutoExposureLogging(value) {
this._autoExposureLog = value;
}
setAutoExposureLogging(value) {
this._autoExposureLog = value;
}
getParams() {
this.requireAssignment();
this.requireExposureLogging();
return this._assignment.getParams();
}
getParams() {
this.requireAssignment();
this.requireExposureLogging();
return this._assignment.getParams();
}
get(name, def) {
this.requireAssignment();
this.requireExposureLogging(name);
return this._assignment.get(name, def);
}
get(name, def) {
this.requireAssignment();
this.requireExposureLogging(name);
return this._assignment.get(name, def);
}
toString() {
this.requireAssignment();
this.requireExposureLogging();
return JSON.stringify(this.__asBlob());
}
logExposure(extras) {
if (!this.inExperiment()) {
return;
toString() {
this.requireAssignment();
this.requireExposureLogging();
return JSON.stringify(this.__asBlob());
}
this._exposureLogged = true;
this.logEvent('exposure', extras);
}
shouldLogExposure(paramName) {
if (paramName !== undefined && !this.shouldFetchExperimentParameter(paramName)) {
return false;
logExposure(extras) {
if (!this.inExperiment()) {
return;
}
this._exposureLogged = true;
this.logEvent('exposure', extras);
}
return this._autoExposureLog && !this.previouslyLogged();
}
logEvent(eventType, extras) {
if (!this.inExperiment()) {
return;
shouldLogExposure(paramName) {
if (paramName !== undefined && !this.shouldFetchExperimentParameter(paramName)) {
return false;
}
return this._autoExposureLog && !this.previouslyLogged();
}
var extraPayload;
logEvent(eventType, extras) {
if (!this.inExperiment()) {
return;
}
if (extras) {
extraPayload = { 'event': eventType, 'extra_data': shallowCopy(extras)};
} else {
extraPayload = { 'event': eventType };
var extraPayload;
if (extras) {
extraPayload = { 'event': eventType, 'extra_data': shallowCopy(extras)};
} else {
extraPayload = { 'event': eventType };
}
this.log(this.__asBlob(extraPayload));
}
this.log(this.__asBlob(extraPayload));
}
configureLogger() {
throw "IMPLEMENT configureLogger";
}
configureLogger() {
throw "IMPLEMENT configureLogger";
}
log(data) {
throw "IMPLEMENT log";
}
log(data) {
throw "IMPLEMENT log";
previouslyLogged() {
throw "IMPLEMENT previouslyLogged";
}
}
previouslyLogged() {
throw "IMPLEMENT previouslyLogged";
}
return Experiment;
}
export default Experiment;

@@ -7,4 +7,4 @@ import { extend, shallowCopy, forEach, isFunction } from './lib/utils';

const fetchInputs = (args) => {
if (!args) {
return {};
if (!args) {
return {};
}

@@ -43,2 +43,2 @@

export default { registerExperimentInput, getExperimentInputs };
export { registerExperimentInput, getExperimentInputs };

@@ -1,100 +0,100 @@

import Assignment from './assignment';
import { operatorInstance, StopPlanOutException, registerOperators } from './ops/utils';
import { shallowCopy, deepCopy, isObject, isArray, map } from "./lib/utils";
class Interpreter {
constructor(serialization, experimentSalt='global_salt', inputs={}, environment) {
this._serialization = deepCopy(serialization);
if (!environment) {
this._env = new Assignment(experimentSalt);
} else {
this._env = environment;
export default function provideInterpreter(OpsUtils, Assignment) {
class Interpreter {
constructor(serialization, experimentSalt='global_salt', inputs={}, environment) {
this._serialization = deepCopy(serialization);
if (!environment) {
this._env = new Assignment(experimentSalt);
} else {
this._env = environment;
}
this.experimentSalt = this._experimentSalt = experimentSalt;
this._evaluated = false;
this._inExperiment = false;
this._inputs = shallowCopy(inputs);
}
this.experimentSalt = this._experimentSalt = experimentSalt;
this._evaluated = false;
this._inExperiment = false;
this._inputs = shallowCopy(inputs);
}
inExperiment() {
return this._inExperiment;
}
inExperiment() {
return this._inExperiment;
}
setEnv(newEnv) {
this._env = deepCopy(newEnv);
return this;
}
setEnv(newEnv) {
this._env = deepCopy(newEnv);
return this;
}
has(name) {
return this._env[name];
}
has(name) {
return this._env[name];
}
get(name, defaultVal) {
var inputVal = this._inputs[name];
if (inputVal === null || inputVal === undefined) {
inputVal = defaultVal;
get(name, defaultVal) {
var inputVal = this._inputs[name];
if (inputVal === null || inputVal === undefined) {
inputVal = defaultVal;
}
var envVal = this._env.get(name);
if (envVal !== undefined && envVal !== null) {
return envVal;
}
return inputVal;
}
var envVal = this._env.get(name);
if (envVal !== undefined && envVal !== null) {
return envVal;
}
return inputVal;
}
getParams() {
if (!this._evaluated) {
try {
this.evaluate(this._serialization);
} catch(err) {
if (err instanceof StopPlanOutException) {
this._inExperiment = err.inExperiment;
getParams() {
if (!this._evaluated) {
try {
this.evaluate(this._serialization);
} catch(err) {
if (err instanceof OpsUtils.StopPlanOutException) {
this._inExperiment = err.inExperiment;
}
}
this._evaluated = true;
}
this._evaluated = true;
return this._env.getParams();
}
return this._env.getParams();
}
set(name, value) {
this._env.set(name, value);
return this;
}
set(name, value) {
this._env.set(name, value);
return this;
}
getSaltSeparator() {
return this._env.saltSeparator;
}
getSaltSeparator() {
return this._env.saltSeparator;
}
setOverrides(overrides) {
this._env.setOverrides(overrides);
return this;
}
setOverrides(overrides) {
this._env.setOverrides(overrides);
return this;
}
getOverrides() {
return this._env.getOverrides();
}
getOverrides() {
return this._env.getOverrides();
}
hasOverride(name) {
var overrides = this.getOverrides();
return overrides && overrides[name] !== undefined;
}
hasOverride(name) {
var overrides = this.getOverrides();
return overrides && overrides[name] !== undefined;
}
registerCustomOperators(operators) {
registerOperators(operators);
}
registerCustomOperators(operators) {
OpsUtils.registerOperators(operators);
}
evaluate(planoutCode) {
if (isObject(planoutCode) && planoutCode.op) {
return operatorInstance(planoutCode).execute(this);
} else if (isArray(planoutCode)) {
var self = this;
return map(planoutCode, function(obj) {
return self.evaluate(obj);
});
} else {
return planoutCode;
evaluate(planoutCode) {
if (isObject(planoutCode) && planoutCode.op) {
return OpsUtils.operatorInstance(planoutCode).execute(this);
} else if (isArray(planoutCode)) {
var self = this;
return map(planoutCode, function(obj) {
return self.evaluate(obj);
});
} else {
return planoutCode;
}
}
}
return Interpreter;
}
export default Interpreter;

@@ -279,2 +279,2 @@ /* Most of these functions are from the wonderful Underscore package http://underscorejs.org/

export default { deepCopy, map, reduce, getParameterByName, forEach, isFunction, trimTrailingWhitespace, hasKey, shallowCopy, extend, isObject, isArray, range };
export { deepCopy, map, reduce, getParameterByName, forEach, isFunction, trimTrailingWhitespace, hasKey, shallowCopy, extend, isObject, isArray, range };

@@ -1,313 +0,302 @@

import Experiment from "./experiment.js";
import Assignment from "./assignment.js";
import { Sample, RandomInteger } from "./ops/random.js";
import { range, isObject, forEach, getParameterByName, hasKey, extend } from "./lib/utils.js";
import { getExperimentInputs } from './experimentSetup';
export default function provideNamespace(Random, Assignment, Experiment) {
class DefaultExperiment extends Experiment {
configureLogger() {
return;
}
class DefaultExperiment extends Experiment {
configureLogger() {
return;
}
setup() {
this.name = 'test_name';
}
setup() {
this.name = 'test_name';
}
log(data) {
return;
}
log(data) {
return;
}
getParamNames() {
return this.getDefaultParamNames();
}
getParamNames() {
return this.getDefaultParamNames();
}
previouslyLogged() {
return true;
}
previouslyLogged() {
return true;
}
assign(params, args) {
return;
assign(params, args) {
return;
}
}
}
class Namespace {
class Namespace {
addExperiment(name, obj, segments) {
throw "IMPLEMENT addExperiment";
}
addExperiment(name, obj, segments) {
throw "IMPLEMENT addExperiment";
}
removeExperiment(name) {
throw "IMPLEMENT removeExperiment";
}
removeExperiment(name) {
throw "IMPLEMENT removeExperiment";
}
setAutoExposureLogging(value) {
throw "IMPLEMENT setAutoExposureLogging";
}
setAutoExposureLogging(value) {
throw "IMPLEMENT setAutoExposureLogging";
}
inExperiment() {
throw "IMPLEMENT inExperiment";
}
inExperiment() {
throw "IMPLEMENT inExperiment";
}
get(name, defaultVal) {
throw "IMPLEMENT get";
}
get(name, defaultVal) {
throw "IMPLEMENT get";
}
logExposure(extras) {
throw "IMPLEMENT logExposure";
}
logExposure(extras) {
throw "IMPLEMENT logExposure";
}
logEvent(eventType, extras) {
throw "IMPLEMENT logEvent";
}
logEvent(eventType, extras) {
throw "IMPLEMENT logEvent";
}
requireExperiment() {
if (!this._experiment) {
this._assignExperiment();
requireExperiment() {
if (!this._experiment) {
this._assignExperiment();
}
}
}
requireDefaultExperiment() {
if (!this._defaultExperiment) {
this._assignDefaultExperiment();
requireDefaultExperiment() {
if (!this._defaultExperiment) {
this._assignDefaultExperiment();
}
}
}
}
class SimpleNamespace extends Namespace {
constructor(args) {
super(args);
this.name = this.getDefaultNamespaceName();
this.inputs = args || {};
this.numSegments = 1;
this.segmentAllocations = {};
this.currentExperiments = {};
class SimpleNamespace extends Namespace {
constructor(args) {
super(args);
this.inputs = args || {};
this.numSegments = 1;
this.segmentAllocations = {};
this.currentExperiments = {};
this._experiment = null;
this._defaultExperiment = null;
this.defaultExperimentClass = DefaultExperiment
this._inExperiment = false;
this._experiment = null;
this._defaultExperiment = null;
this.defaultExperimentClass = DefaultExperiment;
this._inExperiment = false;
this.setupDefaults();
this.setup();
this.availableSegments = range(this.numSegments);
this.setupDefaults();
this.setup();
if (!this.name) {
throw "setup() must set a namespace name via this.setName()";
}
this.availableSegments = range(this.numSegments);
this.setupExperiments();
}
this.setupExperiments();
}
setupDefaults() {
return;
}
setupDefaults() {
return;
}
setup() {
throw "IMPLEMENT setup";
}
setup() {
throw "IMPLEMENT setup";
}
setupExperiments() {
throw "IMPLEMENT setupExperiments";
}
setupExperiments() {
throw "IMPLEMENT setupExperiments";
}
getPrimaryUnit() {
return this._primaryUnit;
}
getPrimaryUnit() {
return this._primaryUnit;
}
allowedOverride() {
return false;
}
getOverrides() {
return {};
}
setPrimaryUnit(value) {
this._primaryUnit = value;
}
addExperiment(name, expObject, segments) {
var numberAvailable = this.availableSegments.length;
if (numberAvailable < segments) {
allowedOverride() {
return false;
} else if (this.currentExperiments[name] !== undefined) {
return false;
}
var a = new Assignment(this.name);
a.set('sampled_segments', new Sample({'choices': this.availableSegments, 'draws': segments, 'unit': name}));
var sample = a.get('sampled_segments');
for(var i = 0; i < sample.length; i++) {
this.segmentAllocations[sample[i]] = name;
var currentIndex = this.availableSegments.indexOf(sample[i]);
this.availableSegments[currentIndex] = this.availableSegments[numberAvailable - 1];
this.availableSegments.splice(numberAvailable - 1, 1);
numberAvailable -= 1;
getOverrides() {
return {};
}
this.currentExperiments[name] = expObject
}
removeExperiment(name) {
if (this.currentExperiments[name] === undefined) {
return false;
setPrimaryUnit(value) {
this._primaryUnit = value;
}
forEach(Object.keys(this.segmentAllocations), (cur) => {
if(this.segmentAllocations[cur] === name) {
delete this.segmentAllocations[cur];
this.availableSegments.push(cur);
addExperiment(name, expObject, segments) {
var numberAvailable = this.availableSegments.length;
if (numberAvailable < segments) {
return false;
} else if (this.currentExperiments[name] !== undefined) {
return false;
}
});
var a = new Assignment(this.name);
a.set('sampled_segments', new Random.Sample({'choices': this.availableSegments, 'draws': segments, 'unit': name}));
var sample = a.get('sampled_segments');
for(var i = 0; i < sample.length; i++) {
this.segmentAllocations[sample[i]] = name;
var currentIndex = this.availableSegments.indexOf(sample[i]);
this.availableSegments[currentIndex] = this.availableSegments[numberAvailable - 1];
this.availableSegments.splice(numberAvailable - 1, 1);
numberAvailable -= 1;
}
this.currentExperiments[name] = expObject
delete this.currentExperiments[name];
return true;
}
}
getSegment() {
var a = new Assignment(this.name);
var segment = new RandomInteger({'min': 0, 'max': this.numSegments-1, 'unit': this.inputs[this.getPrimaryUnit()]});
a.set('segment', segment);
return a.get('segment');
}
removeExperiment(name) {
if (this.currentExperiments[name] === undefined) {
return false;
}
_assignExperiment() {
this.inputs = extend(this.inputs, getExperimentInputs(this.getName()));
var segment = this.getSegment();
forEach(Object.keys(this.segmentAllocations), (cur) => {
if(this.segmentAllocations[cur] === name) {
delete this.segmentAllocations[cur];
this.availableSegments.push(cur);
}
});
if (this.segmentAllocations[segment] !== undefined) {
var experimentName = this.segmentAllocations[segment];
this._assignExperimentObject(experimentName);
delete this.currentExperiments[name];
return true;
}
}
_assignExperimentObject(experimentName) {
var experiment = new this.currentExperiments[experimentName](this.inputs);
experiment.setName(`${this.getName()}-${experimentName}`);
experiment.setSalt(`${this.getName()}-${experimentName}`);
this._experiment = experiment;
this._inExperiment = experiment.inExperiment();
if (!this._inExperiment) {
this._assignDefaultExperiment();
getSegment() {
var a = new Assignment(this.name);
var segment = new Random.RandomInteger({'min': 0, 'max': this.numSegments-1, 'unit': this.inputs[this.getPrimaryUnit()]});
a.set('segment', segment);
return a.get('segment');
}
}
_assignDefaultExperiment() {
this._defaultExperiment = new this.defaultExperimentClass(this.inputs);
}
_assignExperiment() {
this.inputs = extend(this.inputs, getExperimentInputs(this.getName()));
var segment = this.getSegment();
defaultGet(name, default_val) {
super.requireDefaultExperiment();
return this._defaultExperiment.get(name, default_val);
}
if (this.segmentAllocations[segment] !== undefined) {
var experimentName = this.segmentAllocations[segment];
this._assignExperimentObject(experimentName);
}
}
getName() {
return this.name;
}
_assignExperimentObject(experimentName) {
var experiment = new this.currentExperiments[experimentName](this.inputs);
experiment.setName(`${this.getName()}-${experimentName}`);
experiment.setSalt(`${this.getName()}-${experimentName}`);
this._experiment = experiment;
this._inExperiment = experiment.inExperiment();
if (!this._inExperiment) {
this._assignDefaultExperiment();
}
}
setName(name) {
this.name = name;
}
_assignDefaultExperiment() {
this._defaultExperiment = new this.defaultExperimentClass(this.inputs);
}
previouslyLogged() {
if (this._experiment) {
return this._experiment.previouslyLogged();
defaultGet(name, default_val) {
super.requireDefaultExperiment();
return this._defaultExperiment.get(name, default_val);
}
return null;
}
inExperiment() {
super.requireExperiment();
return this._inExperiment;
}
getName() {
return this.name;
}
setAutoExposureLogging(value) {
this._autoExposureLoggingSet = value;
if (this._defaultExperiment) {
this._defaultExperiment.setAutoExposureLogging(value);
setName(name) {
this.name = name;
}
if (this._experiment) {
this._experiment.setAutoExposureLogging(value);
}
}
setGlobalOverride(name) {
var globalOverrides = this.getOverrides();
if(globalOverrides && hasKey(globalOverrides, name)) {
var overrides = globalOverrides[name];
if (overrides && hasKey(this.currentExperiments, overrides.experimentName)) {
this._assignExperimentObject(overrides.experimentName);
this._experiment.addOverride(name, overrides.value);
previouslyLogged() {
if (this._experiment) {
return this._experiment.previouslyLogged();
}
return null;
}
}
setLocalOverride(name) {
var experimentName = getParameterByName('experimentOverride');
if (experimentName && hasKey(this.currentExperiments, experimentName)) {
this._assignExperimentObject(experimentName);
if (getParameterByName(name)) {
this._experiment.addOverride(name, getParameterByName(name));
inExperiment() {
super.requireExperiment();
return this._inExperiment;
}
setAutoExposureLogging(value) {
this._autoExposureLoggingSet = value;
if (this._defaultExperiment) {
this._defaultExperiment.setAutoExposureLogging(value);
}
if (this._experiment) {
this._experiment.setAutoExposureLogging(value);
}
}
}
getParams(experimentName) {
super.requireExperiment();
if (this._experiment && this.getOriginalExperimentName() === experimentName) {
return this._experiment.getParams();
} else {
return null;
setGlobalOverride(name) {
var globalOverrides = this.getOverrides();
if(globalOverrides && hasKey(globalOverrides, name)) {
var overrides = globalOverrides[name];
if (overrides && hasKey(this.currentExperiments, overrides.experimentName)) {
this._assignExperimentObject(overrides.experimentName);
this._experiment.addOverride(name, overrides.value);
}
}
}
}
getOriginalExperimentName() {
if (this._experiment) {
return this._experiment.getName().split('-')[1];
setLocalOverride(name) {
var experimentName = getParameterByName('experimentOverride');
if (experimentName && hasKey(this.currentExperiments, experimentName)) {
this._assignExperimentObject(experimentName);
if (getParameterByName(name)) {
this._experiment.addOverride(name, getParameterByName(name));
}
}
}
return null;
}
get(name, defaultVal) {
super.requireExperiment();
if (this.allowedOverride()) {
this.setGlobalOverride(name);
getParams(experimentName) {
super.requireExperiment();
if (this._experiment && this.getOriginalExperimentName() === experimentName) {
return this._experiment.getParams();
} else {
return null;
}
}
this.setLocalOverride(name);
if (!this._experiment) {
return this.defaultGet(name, defaultVal);
} else {
if (this._autoExposureLoggingSet !== undefined) {
this._experiment.setAutoExposureLogging(this._autoExposureLoggingSet);
getOriginalExperimentName() {
if (this._experiment) {
return this._experiment.getName().split('-')[1];
}
return this._experiment.get(name, this.defaultGet(name, defaultVal));
return null;
}
}
logExposure(extras) {
super.requireExperiment();
if (!this._experiment) {
return;
get(name, defaultVal) {
super.requireExperiment();
if (this.allowedOverride()) {
this.setGlobalOverride(name);
}
this.setLocalOverride(name);
if (!this._experiment) {
return this.defaultGet(name, defaultVal);
} else {
if (this._autoExposureLoggingSet !== undefined) {
this._experiment.setAutoExposureLogging(this._autoExposureLoggingSet);
}
return this._experiment.get(name, this.defaultGet(name, defaultVal));
}
}
this._experiment.logExposure(extras);
}
logEvent(eventType, extras) {
super.requireExperiment();
if (!this._experiment) {
return;
logExposure(extras) {
super.requireExperiment();
if (!this._experiment) {
return;
}
this._experiment.logExposure(extras);
}
this._experiment.logEvent(eventType, extras);
}
//helper function to return the class name of the current experiment class
getDefaultNamespaceName() {
if (isObject(this) && this.constructor && this !== this.window) {
var arr = this.constructor.toString().match(/function\s*(\w+)/);
if (arr && arr.length === 2) {
return arr[1];
logEvent(eventType, extras) {
super.requireExperiment();
if (!this._experiment) {
return;
}
this._experiment.logEvent(eventType, extras);
}
return "GenericNamespace";
}
return { Namespace: Namespace, SimpleNamespace: SimpleNamespace };
}
export { Namespace, SimpleNamespace }

@@ -23,4 +23,4 @@ import { forEach } from "../lib/utils";

}
getArgNumber(name) {

@@ -93,3 +93,3 @@ var cur = this.getArgMixed(name);

class PlanOutOpBinary extends PlanOutOpSimple {
simpleExecute() {
simpleExecute() {
var left = this.getArgMixed('left');

@@ -123,2 +123,2 @@ var right = this.getArgMixed('right');

export { PlanOutOp, PlanOutOpSimple, PlanOutOpCommutative, PlanOutOpBinary, PlanOutOpUnary }
export { PlanOutOp, PlanOutOpSimple, PlanOutOpCommutative, PlanOutOpBinary, PlanOutOpUnary };

@@ -247,2 +247,2 @@ import {PlanOutOp, PlanOutOpSimple, PlanOutOpBinary, PlanOutOpUnary, PlanOutOpCommutative} from "./base";

export { Literal, Get, Seq, Set, Arr, Map, Coalesce, Index, Cond, And, Or, Product, Sum, Equals, GreaterThan, LessThan, LessThanOrEqualTo, GreaterThanOrEqualTo, Mod, Divide, Round, Not, Negative, Min, Max, Length, Return }
export { Literal, Get, Seq, Set, Arr, Map, Coalesce, Index, Cond, And, Or, Product, Sum, Equals, GreaterThan, LessThan, LessThanOrEqualTo, GreaterThanOrEqualTo, Mod, Divide, Round, Not, Negative, Min, Max, Length, Return };

@@ -1,208 +0,29 @@

import { PlanOutOpSimple } from "./base";
import sha1 from "sha1";
import { shallowCopy, reduce, isArray } from "../lib/utils";
class PlanOutOpRandom extends PlanOutOpSimple {
constructor(args) {
super(args);
this.LONG_SCALE = 0xFFFFFFFFFFFFF;
}
compatHashCalculation(hash) {
return parseInt(hash.substr(0, 13), 16);
}
compatZeroToOneCalculation(appendedUnit) {
return this.getHash(appendedUnit) / this.LONG_SCALE;
}
getUnit(appendedUnit) {
var unit = this.getArgMixed('unit');
if (!isArray(unit)) {
unit = [unit];
}
if (appendedUnit) {
unit.push(appendedUnit);
}
return unit;
}
getUniform(minVal=0.0, maxVal=1.0, appendedUnit) {
var zeroToOne = this.compatZeroToOneCalculation(appendedUnit);
return zeroToOne * (maxVal - minVal) + (minVal);
}
getHash(appendedUnit) {
var fullSalt;
if (this.args.full_salt) {
fullSalt = this.getArgString('full_salt') + '.';
} else {
var salt = this.getArgString('salt');
fullSalt = this.mapper.get('experimentSalt') + '.' + salt + this.mapper.get('saltSeparator');
}
var unitStr = this.getUnit(appendedUnit).map(element =>
String(element)
).join('.');
var hashStr = fullSalt + unitStr;
var hash = sha1(hashStr);
return this.compatHashCalculation(hash);
}
}
const RandomFloatBuilder = (RandomOpsClass) => class extends RandomOpsClass {
simpleExecute() {
var minVal = this.getArgNumber('min');
var maxVal = this.getArgNumber('max');
return this.getUniform(minVal, maxVal);
}
}
const RandomIntegerBuilder = (RandomOpsClass) => class extends RandomOpsClass {
compatRandomIntegerCalculation(minVal, maxVal) {
return (this.getHash() + minVal) % (maxVal - minVal + 1);
}
simpleExecute() {
var minVal = this.getArgNumber('min');
var maxVal = this.getArgNumber('max');
return this.compatRandomIntegerCalculation(minVal, maxVal);
}
}
const BernoulliTrialBuilder = (RandomOpsClass) => class extends RandomOpsClass {
simpleExecute() {
var p = this.getArgNumber('p');
if (p < 0 || p > 1) {
throw "Invalid probability";
}
if (this.getUniform(0.0, 1.0) <= p) {
return 1;
} else {
return 0;
}
}
}
const BernoulliFilterBuilder = (RandomOpsClass) => class extends RandomOpsClass {
simpleExecute() {
var p = this.getArgNumber('p');
var values = this.getArgList('choices');
if (p < 0 || p > 1) {
throw "Invalid probability";
}
if (values.length == 0) {
return [];
}
var ret = [];
for (var i = 0; i < values.length; i++) {
var cur = values[i];
if (this.getUniform(0.0, 1.0, cur) <= p) {
ret.push(cur);
}
}
return ret;
}
}
const UniformChoiceBuilder = (OpRandomClass) => class extends OpRandomClass {
compatRandomIndexCalculation(choices) {
return this.getHash() % (choices.length);
}
simpleExecute() {
var choices = this.getArgList('choices');
if (choices.length === 0) {
return [];
}
var randIndex = this.compatRandomIndexCalculation(choices);
return choices[randIndex];
}
}
const WeightedChoiceBuilder = (RandomOpsClass) => class extends RandomOpsClass {
simpleExecute() {
var choices = this.getArgList('choices');
var weights = this.getArgList('weights');
if (choices.length === 0) {
return [];
}
var cumSum = 0;
var cumWeights = weights.map(function(weight) {
cumSum += weight;
return cumSum;
});
var stopVal = this.getUniform(0.0, cumSum);
return reduce(cumWeights, function(retVal, curVal, i) {
if (retVal) {
return retVal;
}
if (stopVal <= curVal) {
return choices[i];
}
return retVal;
}, null);
}
}
const SampleBuilder = (RandomOpsClass) => class extends RandomOpsClass {
compatSampleIndexCalculation(i) {
return this.getHash(i) % (i+1);
}
compatAllowSampleStoppingPoint() {
return true;
}
sample(array, numDraws) {
var len = array.length;
var stoppingPoint = len - numDraws;
var allowStoppingPoint = this.compatAllowSampleStoppingPoint();
for (var i = len - 1; i > 0; i--) {
var j = this.compatSampleIndexCalculation(i);
var temp = array[i];
array[i] = array[j];
array[j] = temp;
if (allowStoppingPoint && stoppingPoint === i) {
return array.slice(i, len);
}
}
return array.slice(0, numDraws);
}
simpleExecute() {
var choices = shallowCopy(this.getArgList('choices'));
var numDraws = 0;
if (this.args.draws !== undefined) {
numDraws = this.getArgNumber('draws');
} else {
numDraws = choices.length;
}
return this.sample(choices, numDraws);
}
}
export default {
import {
PlanOutOpRandom,
SampleBuilder,
Sample: SampleBuilder(PlanOutOpRandom),
WeightedChoiceBuilder,
WeightedChoice: WeightedChoiceBuilder(PlanOutOpRandom),
UniformChoiceBuilder,
UniformChoice: UniformChoiceBuilder(PlanOutOpRandom),
BernoulliFilterBuilder,
BernoulliFilter: BernoulliFilterBuilder(PlanOutOpRandom),
BernoulliTrialBuilder,
BernoulliTrial: BernoulliTrialBuilder(PlanOutOpRandom),
RandomIntegerBuilder,
RandomInteger: RandomIntegerBuilder(PlanOutOpRandom),
RandomFloatBuilder,
RandomFloat: RandomFloatBuilder(PlanOutOpRandom)
RandomFloatBuilder
} from "./randomBase";
var Sample = SampleBuilder(PlanOutOpRandom);
var WeightedChoice = WeightedChoiceBuilder(PlanOutOpRandom);
var UniformChoice = UniformChoiceBuilder(PlanOutOpRandom);
var BernoulliFilter = BernoulliFilterBuilder(PlanOutOpRandom);
var BernoulliTrial = BernoulliTrialBuilder(PlanOutOpRandom);
var RandomInteger = RandomIntegerBuilder(PlanOutOpRandom);
var RandomFloat = RandomFloatBuilder(PlanOutOpRandom);
export {
PlanOutOpRandom,
Sample,
WeightedChoice,
UniformChoice,
BernoulliFilter,
BernoulliTrial,
RandomInteger,
RandomFloat
};
import {
PlanOutOpRandom,
Sample,
SampleBuilder,
WeightedChoice,
WeightedChoiceBuilder,
UniformChoice,
UniformChoiceBuilder,
BernoulliFilter,
BernoulliFilterBuilder,
BernoulliTrial,
BernoulliTrialBuilder,
RandomInteger,
RandomIntegerBuilder,
RandomFloat,
RandomFloatBuilder
} from "./random";
} from "./randomBase";
import BigNumber from "bignumber.js";
const LONG_SCALE = new BigNumber("FFFFFFFFFFFFFFF", 16);
class PlanOutOpRandomCoreCompatible extends PlanOutOpRandom {
constructor(args) {
super(args);
this.LONG_SCALE = new BigNumber("FFFFFFFFFFFFFFF", 16);
}
compatHashCalculation(hash) {
hashCalculation(hash) {
return new BigNumber(hash.substr(0, 15), 16);
}
compatZeroToOneCalculation(appendedUnit) {
return this.getHash(appendedUnit).dividedBy(this.LONG_SCALE).toNumber();
zeroToOneCalculation(appendedUnit) {
return this.getHash(appendedUnit).dividedBy(LONG_SCALE).toNumber();
}

@@ -36,3 +26,3 @@ }

class RandomIntegerCoreCompatible extends RandomIntegerBuilder(PlanOutOpRandomCoreCompatible) {
compatRandomIntegerCalculation(minVal, maxVal) {
randomIntegerCalculation(minVal, maxVal) {
return this.getHash().plus(minVal).modulo(maxVal - minVal + 1).toNumber();

@@ -43,3 +33,3 @@ }

class UniformChoiceCoreCompatible extends UniformChoiceBuilder(PlanOutOpRandomCoreCompatible) {
compatRandomIndexCalculation(choices) {
randomIndexCalculation(choices) {
return this.getHash().modulo(choices.length).toNumber();

@@ -50,7 +40,7 @@ }

class SampleCoreCompatible extends SampleBuilder(PlanOutOpRandomCoreCompatible) {
compatSampleIndexCalculation(i) {
sampleIndexCalculation(i) {
return this.getHash(i).modulo(i+1).toNumber();
}
compatAllowSampleStoppingPoint() {
allowSampleStoppingPoint() {
return false;

@@ -60,11 +50,16 @@ }

export default {
PlanOutOpRandom: PlanOutOpRandomCoreCompatible,
Sample: SampleCoreCompatible,
WeightedChoice: WeightedChoiceBuilder(PlanOutOpRandomCoreCompatible),
UniformChoice: UniformChoiceCoreCompatible,
BernoulliFilter: BernoulliFilterBuilder(PlanOutOpRandomCoreCompatible),
BernoulliTrial: BernoulliTrialBuilder(PlanOutOpRandomCoreCompatible),
RandomInteger: RandomIntegerCoreCompatible,
RandomFloat: RandomFloatBuilder(PlanOutOpRandomCoreCompatible)
const WeightedChoiceCoreCompatible = WeightedChoiceBuilder(PlanOutOpRandomCoreCompatible);
const BernoulliFilterCoreCompatible = BernoulliFilterBuilder(PlanOutOpRandomCoreCompatible);
const BernoulliTrialCoreCompatible = BernoulliTrialBuilder(PlanOutOpRandomCoreCompatible);
const RandomFloatCoreCompatible = RandomFloatBuilder(PlanOutOpRandomCoreCompatible);
export {
PlanOutOpRandomCoreCompatible as PlanOutOpRandom,
SampleCoreCompatible as Sample,
WeightedChoiceCoreCompatible as WeightedChoice,
UniformChoiceCoreCompatible as UniformChoice,
BernoulliFilterCoreCompatible as BernoulliFilter,
BernoulliTrialCoreCompatible as BernoulliTrial,
RandomIntegerCoreCompatible as RandomInteger,
RandomFloatCoreCompatible as RandomFloat
};

@@ -1,46 +0,53 @@

import * as core from './core';
import * as random from './random';
import { isObject, forEach } from '../lib/utils';
var initFactory = function() {
return {
'literal': core.Literal,
'get': core.Get,
'set': core.Set,
'seq': core.Seq,
'return': core.Return,
'index': core.Index,
'array': core.Arr,
'equals': core.Equals,
'and': core.And,
'or': core.Or,
">": core.GreaterThan,
"<": core.LessThan,
">=": core.GreaterThanOrEqualTo,
"<=": core.LessThanOrEqualTo,
"%": core.Mod,
"/": core.Divide,
"not": core.Not,
"round": core.Round,
"negative": core.Negative,
"min": core.Min,
"max": core.Max,
"length": core.Length,
"coalesce": core.Coalesce,
"map": core.Map,
"cond": core.Cond,
"product": core.Product,
"sum": core.Sum,
"randomFloat": random.RandomFloat,
"randomInteger": random.RandomInteger,
"bernoulliTrial": random.BernoulliTrial,
"bernoulliFilter": random.BernoulliFilter,
"uniformChoice": random.UniformChoice,
"weightedChoice": random.WeightedChoice,
"sample": random.Sample
};
var initializeOperators = function(Core, Random) {
registerOperators({
'literal': Core.Literal,
'get': Core.Get,
'set': Core.Set,
'seq': Core.Seq,
'return': Core.Return,
'index': Core.Index,
'array': Core.Arr,
'equals': Core.Equals,
'and': Core.And,
'or': Core.Or,
">": Core.GreaterThan,
"<": Core.LessThan,
">=": Core.GreaterThanOrEqualTo,
"<=": Core.LessThanOrEqualTo,
"%": Core.Mod,
"/": Core.Divide,
"not": Core.Not,
"round": Core.Round,
"negative": Core.Negative,
"min": Core.Min,
"max": Core.Max,
"length": Core.Length,
"coalesce": Core.Coalesce,
"map": Core.Map,
"cond": Core.Cond,
"product": Core.Product,
"sum": Core.Sum,
"randomFloat": Random.RandomFloat,
"randomInteger": Random.RandomInteger,
"bernoulliTrial": Random.BernoulliTrial,
"bernoulliFilter": Random.BernoulliFilter,
"uniformChoice": Random.UniformChoice,
"weightedChoice": Random.WeightedChoice,
"sample": Random.Sample
});
}
var operators = {};
var operators = initFactory();
var registerOperators = function (ops) {
forEach(ops, function (value, op) {
if (operators[op]) {
throw `${op} already is defined`;
} else {
operators[op] = value;
}
});
}

@@ -56,15 +63,6 @@ var isOperator = function(op) {

}
return new operators[op](params);
}
var registerOperators = function (ops) {
forEach(ops, function (value, op) {
if (operators[op]) {
throw `${op} already is defined`;
} else {
operators[op] = value;
}
});
}
class StopPlanOutException {

@@ -76,2 +74,2 @@ constructor(inExperiment) {

export { operators, initFactory, isOperator, operatorInstance, StopPlanOutException, registerOperators }
export { initializeOperators, registerOperators, isOperator, operatorInstance, StopPlanOutException };
{
"name": "planout",
"version": "3.0.3",
"version": "4.0.0",
"dependencies": {

@@ -5,0 +5,0 @@ "sha1": "1.1.0",

@@ -57,2 +57,3 @@ # PlanOut.js

//set experiment name, etc.
this.setName('MyExperiment');
}

@@ -59,0 +60,0 @@

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc