UNPKG

react-alpha-beta

Version:

Simple declarative A/B testing component for React.

1,517 lines (1,204 loc) 70.4 kB
(function webpackUniversalModuleDefinition(root, factory) { if(typeof exports === 'object' && typeof module === 'object') module.exports = factory(require("react")); else if(typeof define === 'function' && define.amd) define(["react"], factory); else if(typeof exports === 'object') exports["ReactAlphaBeta"] = factory(require("react")); else root["ReactAlphaBeta"] = factory(root["React"]); })(this, function(__WEBPACK_EXTERNAL_MODULE_10__) { return /******/ (function(modules) { // webpackBootstrap /******/ // The module cache /******/ var installedModules = {}; /******/ // The require function /******/ function __webpack_require__(moduleId) { /******/ // Check if module is in cache /******/ if(installedModules[moduleId]) /******/ return installedModules[moduleId].exports; /******/ // Create a new module (and put it into the cache) /******/ var module = installedModules[moduleId] = { /******/ exports: {}, /******/ id: moduleId, /******/ loaded: false /******/ }; /******/ // Execute the module function /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); /******/ // Flag the module as loaded /******/ module.loaded = true; /******/ // Return the exports of the module /******/ return module.exports; /******/ } /******/ // expose the modules object (__webpack_modules__) /******/ __webpack_require__.m = modules; /******/ // expose the module cache /******/ __webpack_require__.c = installedModules; /******/ // __webpack_public_path__ /******/ __webpack_require__.p = ""; /******/ // Load entry module and return exports /******/ return __webpack_require__(0); /******/ }) /************************************************************************/ /******/ ([ /* 0 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; var _react = __webpack_require__(10); var _react2 = _interopRequireDefault(_react); var _ABComponent = __webpack_require__(31); var _ABComponent2 = _interopRequireDefault(_ABComponent); var _Experiment = __webpack_require__(11); var _Experiment2 = _interopRequireDefault(_Experiment); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } module.exports = { ABComponent: _ABComponent2.default, DevTools: false ? function () { return _react2.default.createElement('div', null); } : __webpack_require__(33).default, getExperimentData: _Experiment2.default }; /***/ }, /* 1 */ /***/ function(module, exports) { var $Object = Object; module.exports = { create: $Object.create, getProto: $Object.getPrototypeOf, isEnum: {}.propertyIsEnumerable, getDesc: $Object.getOwnPropertyDescriptor, setDesc: $Object.defineProperty, setDescs: $Object.defineProperties, getKeys: $Object.keys, getNames: $Object.getOwnPropertyNames, getSymbols: $Object.getOwnPropertySymbols, each: [].forEach }; /***/ }, /* 2 */ /***/ function(module, exports) { var core = module.exports = {version: '1.2.6'}; if(typeof __e == 'number')__e = core; // eslint-disable-line no-undef /***/ }, /* 3 */ /***/ function(module, exports, __webpack_require__) { var global = __webpack_require__(5) , core = __webpack_require__(2) , ctx = __webpack_require__(20) , PROTOTYPE = 'prototype'; var $export = function(type, name, source){ var IS_FORCED = type & $export.F , IS_GLOBAL = type & $export.G , IS_STATIC = type & $export.S , IS_PROTO = type & $export.P , IS_BIND = type & $export.B , IS_WRAP = type & $export.W , exports = IS_GLOBAL ? core : core[name] || (core[name] = {}) , target = IS_GLOBAL ? global : IS_STATIC ? global[name] : (global[name] || {})[PROTOTYPE] , key, own, out; if(IS_GLOBAL)source = name; for(key in source){ // contains in native own = !IS_FORCED && target && key in target; if(own && key in exports)continue; // export native or passed out = own ? target[key] : source[key]; // prevent global pollution for namespaces exports[key] = IS_GLOBAL && typeof target[key] != 'function' ? source[key] // bind timers to global for call from export context : IS_BIND && own ? ctx(out, global) // wrap global constructors for prevent change them in library : IS_WRAP && target[key] == out ? (function(C){ var F = function(param){ return this instanceof C ? new C(param) : C(param); }; F[PROTOTYPE] = C[PROTOTYPE]; return F; // make static versions for prototype methods })(out) : IS_PROTO && typeof out == 'function' ? ctx(Function.call, out) : out; if(IS_PROTO)(exports[PROTOTYPE] || (exports[PROTOTYPE] = {}))[key] = out; } }; // type bitmap $export.F = 1; // forced $export.G = 2; // global $export.S = 4; // static $export.P = 8; // proto $export.B = 16; // bind $export.W = 32; // wrap module.exports = $export; /***/ }, /* 4 */ /***/ function(module, exports) { module.exports = function(exec){ try { return !!exec(); } catch(e){ return true; } }; /***/ }, /* 5 */ /***/ function(module, exports) { // https://github.com/zloirock/core-js/issues/86#issuecomment-115759028 var global = module.exports = typeof window != 'undefined' && window.Math == Math ? window : typeof self != 'undefined' && self.Math == Math ? self : Function('return this')(); if(typeof __g == 'number')__g = global; // eslint-disable-line no-undef /***/ }, /* 6 */ /***/ function(module, exports) { 'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); var localStorageKey = exports.localStorageKey = 'alphaBetaMap'; /***/ }, /* 7 */ /***/ function(module, exports, __webpack_require__) { module.exports = { "default": __webpack_require__(44), __esModule: true }; /***/ }, /* 8 */ /***/ function(module, exports, __webpack_require__) { // to indexed object, toObject with fallback for non-array-like ES3 strings var IObject = __webpack_require__(24) , defined = __webpack_require__(21); module.exports = function(it){ return IObject(defined(it)); }; /***/ }, /* 9 */ /***/ function(module, exports, __webpack_require__) { // 7.1.13 ToObject(argument) var defined = __webpack_require__(21); module.exports = function(it){ return Object(defined(it)); }; /***/ }, /* 10 */ /***/ function(module, exports) { module.exports = __WEBPACK_EXTERNAL_MODULE_10__; /***/ }, /* 11 */ /***/ function(module, exports, __webpack_require__) { /* WEBPACK VAR INJECTION */(function(global) {'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); var _stringify = __webpack_require__(7); var _stringify2 = _interopRequireDefault(_stringify); exports.postExperimentData = postExperimentData; exports.getPooledVariance = getPooledVariance; exports.getPooledStandardDeviation = getPooledStandardDeviation; exports.getUnpooledVariance = getUnpooledVariance; exports.assumeNormalDistribution = assumeNormalDistribution; exports.computeStats = computeStats; exports.getExperimentData = getExperimentData; var _isomorphicFetch = __webpack_require__(69); var _isomorphicFetch2 = _interopRequireDefault(_isomorphicFetch); var _config = __webpack_require__(34); var _config2 = _interopRequireDefault(_config); var _zTable = __webpack_require__(35); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function postExperimentData(experimentId, variant) { var success = arguments.length <= 2 || arguments[2] === undefined ? null : arguments[2]; var metaId = arguments.length <= 3 || arguments[3] === undefined ? null : arguments[3]; return (0, _isomorphicFetch2.default)(_config2.default.endPoint + '/' + experimentId + '/', { method: 'POST', credentials: 'same-origin', headers: { 'Accept': 'application/json', 'Content-Type': 'application/json' }, body: (0, _stringify2.default)({ experimentId: experimentId, metaId: metaId, success: success, userCohortValue: JSON.parse(global.localStorage.getItem('alphaBetaMap'))[experimentId], variant: variant }) }); } function getPooledVariance(trialsA, trialsB, successA, successB) { var successPooled = (successA + successB) / (trialsA + trialsB); return successPooled * (1 - successPooled) * (1 / trialsA + 1 / trialsB); } /** * Function to return the pooled estimate of the common standard deviation (Sp). */ function getPooledStandardDeviation(trialsA, trialsB, successA, successB) { return Math.sqrt(getPooledVariance(trialsA, trialsB, successA, successB)); } function getUnpooledVariance(trialsA, trialsB, varianceA, varianceB) { return Math.sqrt(varianceA / trialsA + varianceB / trialsB); } function assumeNormalDistribution(trials, probabilityMean) { // heuristic: when the # of trials * the mean probability of success is > 5, // it's safe to assume the normal distrabution can be used (instead of the // binomieal distrabution) return trials * probabilityMean > 5; } function testDetails(probabilityMeanDifference, marginOfError, confidenceInterval) { // a function that turns the numeric data from a test into a short, human readable // description of the findings var differenceFloor = probabilityMeanDifference - marginOfError; var differenceCeiling = probabilityMeanDifference + marginOfError; var details = void 0; var range = 'We are ' + Math.round(confidenceInterval * 100, -2) + '% confident the true difference is between ' + Math.round(differenceFloor * 100, -2) + '% and ' + Math.round(differenceCeiling * 100, -2) + '%.'; var recommendation = void 0; if (probabilityMeanDifference > 0) { details = 'Our best estimate is that the absolute rate of success is ' + Math.round(Math.abs(probabilityMeanDifference) * 100, -2) + '% higher with variant B'; } else { details = 'Our best estimate is that the absolute rate of success is ' + Math.round(Math.abs(probabilityMeanDifference) * 100, -2) + '% lower with variant B'; } if (differenceFloor * differenceCeiling > 0) { details = details + ', and this result is statistically significant'; if (probabilityMeanDifference > 0) { recommendation = 'It looks like a safe bet to go with variant B.'; } else { recommendation = 'Given this information, you should probably stick with variant A.'; } } else { details = details + ', but this result is not statistically significant'; recommendation = 'You don\'t yet have enough information to make a confident decision, so you should keep running this experiment.'; } return details + ' (' + range + '). ' + recommendation; } function computeStats(json) { var variantATrialCount = json.variantA.trialCount; var variantBTrialCount = json.variantB.trialCount; var variantASuccessCount = json.variantA.successCount; var variantBSuccessCount = json.variantB.successCount; var confidenceInterval = json.confidenceInterval; var probabilityMeanA = variantASuccessCount / variantATrialCount; var probabilityMeanB = variantBSuccessCount / variantBTrialCount; var probabilityMeanDifference = probabilityMeanB - probabilityMeanA; var probabilityVarianceA = variantATrialCount * probabilityMeanA * (1 - probabilityMeanA); var probabilityVarianceB = variantBTrialCount * probabilityMeanB * (1 - probabilityMeanB); var varianceRatio = probabilityVarianceA / probabilityVarianceB; var probabilityVariancePooled = getPooledStandardDeviation(variantATrialCount, variantBTrialCount, variantASuccessCount, variantBSuccessCount); var probabilityVarianceUnpooled = getUnpooledVariance(variantATrialCount, variantBTrialCount, probabilityVarianceA, probabilityVarianceB); var zScore = (0, _zTable.zScoreByConfidenceInterval)(confidenceInterval); var assumeNormalDistributionA = assumeNormalDistribution(variantATrialCount, probabilityMeanA); var assumeNormalDistributionB = assumeNormalDistribution(variantBTrialCount, probabilityMeanB); if (assumeNormalDistributionA === false || assumeNormalDistributionB === false) { return { statisticalSignificance: false, details: 'You do not have enough sample data for one or both of your variants to make any assertions.' }; } var marginOfError = void 0; if (varianceRatio <= 0.5 || varianceRatio >= 2) { // heuristic: when one variance is more than double the other, we cannot use the // pooled estimate of the common standard deviation. marginOfError = zScore * probabilityVarianceUnpooled * Math.sqrt(1 / variantATrialCount + 1 / variantBTrialCount); } else { marginOfError = zScore * probabilityVariancePooled * Math.sqrt(1 / variantATrialCount + 1 / variantBTrialCount); } var differenceFloor = probabilityMeanDifference - marginOfError; var differenceCeiling = probabilityMeanDifference + marginOfError; var statisticalSignificance = differenceFloor * differenceCeiling > 0; var result = { statisticalSignificance: statisticalSignificance, meanDifferenceValue: probabilityMeanDifference, marginOfError: marginOfError, details: testDetails(probabilityMeanDifference, marginOfError, confidenceInterval) }; return result; } function getExperimentData(experimentId) { return (0, _isomorphicFetch2.default)(_config2.default.endPoint + '/' + experimentId + '/', { method: 'GET', credentials: 'same-origin', headers: { 'Accept': 'application/json', 'Content-Type': 'application/json' } }).then(function (response) { return response.json(); }).then(function (json) { return computeStats(json); }); } /* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }()))) /***/ }, /* 12 */ /***/ function(module, exports, __webpack_require__) { module.exports = { "default": __webpack_require__(47), __esModule: true }; /***/ }, /* 13 */ /***/ function(module, exports, __webpack_require__) { module.exports = { "default": __webpack_require__(48), __esModule: true }; /***/ }, /* 14 */ /***/ function(module, exports) { "use strict"; exports.__esModule = true; exports.default = function (instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }; /***/ }, /* 15 */ /***/ function(module, exports, __webpack_require__) { "use strict"; exports.__esModule = true; var _defineProperty = __webpack_require__(12); var _defineProperty2 = _interopRequireDefault(_defineProperty); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } exports.default = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; (0, _defineProperty2.default)(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); /***/ }, /* 16 */ /***/ function(module, exports, __webpack_require__) { "use strict"; var _Object$create = __webpack_require__(37)["default"]; var _Object$setPrototypeOf = __webpack_require__(39)["default"]; exports["default"] = function (subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = _Object$create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) _Object$setPrototypeOf ? _Object$setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }; exports.__esModule = true; /***/ }, /* 17 */ /***/ function(module, exports, __webpack_require__) { "use strict"; exports.__esModule = true; var _typeof2 = __webpack_require__(43); var _typeof3 = _interopRequireDefault(_typeof2); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } exports.default = function (self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && ((typeof call === "undefined" ? "undefined" : (0, _typeof3.default)(call)) === "object" || typeof call === "function") ? call : self; }; /***/ }, /* 18 */ /***/ function(module, exports, __webpack_require__) { var isObject = __webpack_require__(25); module.exports = function(it){ if(!isObject(it))throw TypeError(it + ' is not an object!'); return it; }; /***/ }, /* 19 */ /***/ function(module, exports) { var toString = {}.toString; module.exports = function(it){ return toString.call(it).slice(8, -1); }; /***/ }, /* 20 */ /***/ function(module, exports, __webpack_require__) { // optional / simple context binding var aFunction = __webpack_require__(52); module.exports = function(fn, that, length){ aFunction(fn); if(that === undefined)return fn; switch(length){ case 1: return function(a){ return fn.call(that, a); }; case 2: return function(a, b){ return fn.call(that, a, b); }; case 3: return function(a, b, c){ return fn.call(that, a, b, c); }; } return function(/* ...args */){ return fn.apply(that, arguments); }; }; /***/ }, /* 21 */ /***/ function(module, exports) { // 7.2.1 RequireObjectCoercible(argument) module.exports = function(it){ if(it == undefined)throw TypeError("Can't call method on " + it); return it; }; /***/ }, /* 22 */ /***/ function(module, exports, __webpack_require__) { // Thank's IE8 for his funny defineProperty module.exports = !__webpack_require__(4)(function(){ return Object.defineProperty({}, 'a', {get: function(){ return 7; }}).a != 7; }); /***/ }, /* 23 */ /***/ function(module, exports) { var hasOwnProperty = {}.hasOwnProperty; module.exports = function(it, key){ return hasOwnProperty.call(it, key); }; /***/ }, /* 24 */ /***/ function(module, exports, __webpack_require__) { // fallback for non-array-like ES3 and non-enumerable old V8 strings var cof = __webpack_require__(19); module.exports = Object('z').propertyIsEnumerable(0) ? Object : function(it){ return cof(it) == 'String' ? it.split('') : Object(it); }; /***/ }, /* 25 */ /***/ function(module, exports) { module.exports = function(it){ return typeof it === 'object' ? it !== null : typeof it === 'function'; }; /***/ }, /* 26 */ /***/ function(module, exports, __webpack_require__) { // most Object methods by ES6 should accept primitives var $export = __webpack_require__(3) , core = __webpack_require__(2) , fails = __webpack_require__(4); module.exports = function(KEY, exec){ var fn = (core.Object || {})[KEY] || Object[KEY] , exp = {}; exp[KEY] = exec(fn); $export($export.S + $export.F * fails(function(){ fn(1); }), 'Object', exp); }; /***/ }, /* 27 */ /***/ function(module, exports) { module.exports = function(bitmap, value){ return { enumerable : !(bitmap & 1), configurable: !(bitmap & 2), writable : !(bitmap & 4), value : value }; }; /***/ }, /* 28 */ /***/ function(module, exports, __webpack_require__) { var global = __webpack_require__(5) , SHARED = '__core-js_shared__' , store = global[SHARED] || (global[SHARED] = {}); module.exports = function(key){ return store[key] || (store[key] = {}); }; /***/ }, /* 29 */ /***/ function(module, exports) { var id = 0 , px = Math.random(); module.exports = function(key){ return 'Symbol('.concat(key === undefined ? '' : key, ')_', (++id + px).toString(36)); }; /***/ }, /* 30 */ /***/ function(module, exports, __webpack_require__) { var store = __webpack_require__(28)('wks') , uid = __webpack_require__(29) , Symbol = __webpack_require__(5).Symbol; module.exports = function(name){ return store[name] || (store[name] = Symbol && Symbol[name] || (Symbol || uid)('Symbol.' + name)); }; /***/ }, /* 31 */ /***/ function(module, exports, __webpack_require__) { /* WEBPACK VAR INJECTION */(function(global) {'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); var _getPrototypeOf = __webpack_require__(13); var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf); var _classCallCheck2 = __webpack_require__(14); var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); var _createClass2 = __webpack_require__(15); var _createClass3 = _interopRequireDefault(_createClass2); var _possibleConstructorReturn2 = __webpack_require__(17); var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2); var _inherits2 = __webpack_require__(16); var _inherits3 = _interopRequireDefault(_inherits2); var _react = __webpack_require__(10); var _react2 = _interopRequireDefault(_react); var _Cohort = __webpack_require__(32); var _constants = __webpack_require__(6); var _Experiment = __webpack_require__(11); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } /** * @fileOverview Given two variants of React Component (or Element), it displays * the appropriate one depending on the experiment context. */ var ABComponent = function (_React$Component) { (0, _inherits3.default)(ABComponent, _React$Component); // cohortStore: React.PropTypes.object, function ABComponent(props) { (0, _classCallCheck3.default)(this, ABComponent); var _this = (0, _possibleConstructorReturn3.default)(this, (0, _getPrototypeOf2.default)(ABComponent).call(this, props)); _this.successAction = function () { // TODO: Move this up to be a method var variant = _this.state.isInCohort ? 'b' : 'a'; var experimentId = _this.props.experimentParams.id; (0, _Experiment.postExperimentData)(experimentId, variant, true); if (_this.props.successAction) { var _this$props; (_this$props = _this.props).successAction.apply(_this$props, arguments); } }; _this.onStorageEvent = function (event) { if (event.key === _constants.localStorageKey) { _this.setState({ isInCohort: (0, _Cohort.isInCohort)(_this.props.experimentParams) }); } }; _this.state = { isInCohort: false }; return _this; } (0, _createClass3.default)(ABComponent, [{ key: 'componentWillMount', value: function componentWillMount() { this.setState({ isInCohort: (0, _Cohort.isInCohort)(this.props.experimentParams) }); global.addEventListener('storage', this.onStorageEvent); } }, { key: 'componentDidMount', value: function componentDidMount() { // Determine an exposable label for the fields shown // TODO: Make this a bit more user facing var variant = this.state.isInCohort ? 'b' : 'a'; // Record that the AlphaBeta component was loaded var experimentId = this.props.experimentParams.id; (0, _Experiment.postExperimentData)(experimentId, variant, false); } }, { key: 'componentWillUnmount', value: function componentWillUnmount() { global.removeEventListener('storage', this.onStorageEvent); } }, { key: 'renderElementOrComponent', /** * Whether it is passed React element or React component, it renders accordingly. * It also injects `successAction` into the props. * @param {React.Component|React.element} elemOrComp * @return {React.element} */ value: function renderElementOrComponent(elemOrComp) { var props = { successAction: this.successAction }; return _react2.default.isValidElement(elemOrComp) ? _react2.default.cloneElement(elemOrComp, props) : _react2.default.createElement(elemOrComp, props); } }, { key: 'render', value: function render() { var _props = this.props; var ComponentA = _props.ComponentA; var ComponentB = _props.ComponentB; return this.state.isInCohort ? this.renderElementOrComponent(ComponentB) : this.renderElementOrComponent(ComponentA); } }]); return ABComponent; }(_react2.default.Component); ABComponent.displayName = 'ABComponent'; ABComponent.propTypes = { experimentParams: _react2.default.PropTypes.object, // ComponentA/B can be either React element or React component. ComponentA: _react2.default.PropTypes.oneOfType([_react2.default.PropTypes.element, // https://github.com/facebook/react/issues/5143#issuecomment-147473269 _react2.default.PropTypes.oneOfType([_react2.default.PropTypes.string, _react2.default.PropTypes.func])]), ComponentB: _react2.default.PropTypes.oneOfType([_react2.default.PropTypes.element, _react2.default.PropTypes.oneOfType([_react2.default.PropTypes.string, _react2.default.PropTypes.func])]), successAction: _react2.default.PropTypes.func }; exports.default = ABComponent; /* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }()))) /***/ }, /* 32 */ /***/ function(module, exports, __webpack_require__) { /* WEBPACK VAR INJECTION */(function(global) {'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); var _stringify = __webpack_require__(7); var _stringify2 = _interopRequireDefault(_stringify); exports.isInCohort = isInCohort; var _constants = __webpack_require__(6); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } /** * Given an `experimentParams` object with `id` and `testCohortSize`, * it determines whether the user is in the control group or the experimental * group. * It maintains a global registery of experiments in an object. This consists of * a mapping of experiment ids to random numbers, that can be used to determine * if the user is in the experimental group or not. * @params {string} experimentParams.testId - Experiment id. * @params {number} experimentParams.testCohortSize - Number between 0 and 1 * that indicates the portion of the users that need to be in the experimental * group. */ function isInCohort(experimentParams) { var experimentId = experimentParams.id; // Retrieve from storage or create experiment registery var alphaBetaMap = void 0; try { var jsonStr = global.localStorage.getItem(_constants.localStorageKey); alphaBetaMap = jsonStr && JSON.parse(jsonStr) || {}; } catch (err) { alphaBetaMap = {}; } // Get and set a random number (<1) in the registery of the experimentId if (!(experimentId in alphaBetaMap)) { alphaBetaMap[experimentId] = Math.random(); var _jsonStr = (0, _stringify2.default)(alphaBetaMap); global.localStorage.setItem(_constants.localStorageKey, _jsonStr); } // Return if this user is in the experiment, // if they are below the treshold they are in the cohort return alphaBetaMap[experimentId] < experimentParams.testCohortSize; } /* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }()))) /***/ }, /* 33 */ /***/ function(module, exports, __webpack_require__) { /* WEBPACK VAR INJECTION */(function(global) {'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); var _keys = __webpack_require__(38); var _keys2 = _interopRequireDefault(_keys); var _stringify = __webpack_require__(7); var _stringify2 = _interopRequireDefault(_stringify); var _defineProperty2 = __webpack_require__(41); var _defineProperty3 = _interopRequireDefault(_defineProperty2); var _extends3 = __webpack_require__(42); var _extends4 = _interopRequireDefault(_extends3); var _getPrototypeOf = __webpack_require__(13); var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf); var _classCallCheck2 = __webpack_require__(14); var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); var _createClass2 = __webpack_require__(15); var _createClass3 = _interopRequireDefault(_createClass2); var _possibleConstructorReturn2 = __webpack_require__(17); var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2); var _inherits2 = __webpack_require__(16); var _inherits3 = _interopRequireDefault(_inherits2); var _react = __webpack_require__(10); var _react2 = _interopRequireDefault(_react); var _constants = __webpack_require__(6); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } var DevTools = function (_React$Component) { (0, _inherits3.default)(DevTools, _React$Component); function DevTools(props) { (0, _classCallCheck3.default)(this, DevTools); var _this = (0, _possibleConstructorReturn3.default)(this, (0, _getPrototypeOf2.default)(DevTools).call(this, props)); _this.onChange = function (event) { var newAlphaBetaMap = (0, _extends4.default)({}, _this.state.alphaBetaMap, (0, _defineProperty3.default)({}, event.target.name, event.target.value)); _this.setState({ alphaBetaMap: newAlphaBetaMap, hasChanged: true }); var jsonStr = (0, _stringify2.default)(newAlphaBetaMap); global.localStorage.setItem(_constants.localStorageKey, jsonStr); }; try { var jsonStr = global.localStorage.getItem(_constants.localStorageKey); _this.state = { alphaBetaMap: jsonStr && JSON.parse(jsonStr) || {}, hasChanged: false }; } catch (err) { _this.state = { alphaBetaMap: {}, hasChanged: false }; } return _this; } (0, _createClass3.default)(DevTools, [{ key: 'renderExperiment', value: function renderExperiment(id, value) { return _react2.default.createElement( 'tr', null, _react2.default.createElement( 'td', null, id ), _react2.default.createElement( 'td', { style: { 'display': 'flex', 'paddingLeft': '1em' } }, '0:', _react2.default.createElement('input', { type: 'range', min: '0', max: '1', step: '0.01', name: id, value: value, onChange: this.onChange }), ':1 (', value, ')' ) ); } }, { key: 'render', value: function render() { var _this2 = this; var alphaBetaMap = this.state.alphaBetaMap; var refreshMessage = void 0; if (this.state.hasChanged === true) { refreshMessage = _react2.default.createElement( 'div', { style: { fontSize: 'small', color: 'red' } }, '(Refresh this page for your changes to take effect)' ); } return _react2.default.createElement( 'div', { style: { position: 'fixed', bottom: 0, right: 0, margin: '1em', minWidth: '25%', padding: '1em', background: '#eee', border: '2px solid #777' } }, _react2.default.createElement( 'label', { style: { 'textDecoration': 'underline' } }, 'Dev Tools' ), refreshMessage, _react2.default.createElement( 'table', null, _react2.default.createElement( 'thead', null, _react2.default.createElement( 'tr', null, _react2.default.createElement( 'th', null, 'Id' ), _react2.default.createElement( 'th', null, 'Value' ) ) ), _react2.default.createElement( 'tbody', null, (0, _keys2.default)(alphaBetaMap).map(function (id) { return _this2.renderExperiment(id, alphaBetaMap[id]); }) ) ) ); } }]); return DevTools; }(_react2.default.Component); DevTools.displayName = 'DevTools'; DevTools.propTypes = {}; exports.default = DevTools; /* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }()))) /***/ }, /* 34 */ /***/ function(module, exports, __webpack_require__) { /* WEBPACK VAR INJECTION */(function(process) {'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); /** * @overview Anything that is configurable should be in config.js. */ exports.default = { endPoint: process.env.ALPHA_BETA_ENDPOINT || 'http://127.0.0.1:8000/api/alphabeta' }; /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(70))) /***/ }, /* 35 */ /***/ function(module, exports) { 'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); exports.zScoreByConfidenceInterval = zScoreByConfidenceInterval; var zTable = [ // [area left of z, z] [0.9997, 3.49], [0.9996, 3.39], [0.9995, 3.33], [0.9994, 3.27], [0.9993, 3.22], [0.9992, 3.18], [0.9991, 3.14], [0.9990, 3.11], [0.9989, 3.08], [0.9988, 3.05], [0.9987, 3.03], [0.9986, 3.00], [0.9985, 2.98], [0.9984, 2.96], [0.9983, 2.94], [0.9982, 2.93], [0.9981, 2.91], [0.9980, 2.89], [0.9979, 2.88], [0.9978, 2.86], [0.9977, 2.85], [0.9976, 2.83], [0.9975, 2.82], [0.9974, 2.81], [0.9973, 2.79], [0.9972, 2.78], [0.9971, 2.77], [0.9970, 2.76], [0.9969, 2.75], [0.9968, 2.74], [0.9967, 2.73], [0.9966, 2.72], [0.9965, 2.71], [0.9964, 2.70], [0.9963, 2.69], [0.9962, 2.68], [0.9961, 2.67], [0.9960, 2.66], [0.9959, 2.65], [0.9957, 2.64], [0.9956, 2.63], [0.9955, 2.62], [0.9953, 2.61], [0.9952, 2.60], [0.9951, 2.59], [0.9949, 2.58], [0.9948, 2.57], [0.9946, 2.56], [0.9945, 2.55], [0.9943, 2.54], [0.9941, 2.53], [0.9940, 2.52], [0.9938, 2.51], [0.9936, 2.50], [0.9934, 2.49], [0.9932, 2.48], [0.9931, 2.47], [0.9929, 2.46], [0.9927, 2.45], [0.9925, 2.44], [0.9922, 2.43], [0.9920, 2.42], [0.9918, 2.41], [0.9916, 2.40], [0.9913, 2.39], [0.9911, 2.38], [0.9909, 2.37], [0.9906, 2.36], [0.9904, 2.35], [0.9901, 2.34], [0.9898, 2.33], [0.9896, 2.32], [0.9893, 2.31], [0.9890, 2.30], [0.9887, 2.29], [0.9884, 2.28], [0.9881, 2.27], [0.9878, 2.26], [0.9875, 2.25], [0.9871, 2.24], [0.9868, 2.23], [0.9864, 2.22], [0.9861, 2.21], [0.9857, 2.20], [0.9854, 2.19], [0.9850, 2.18], [0.9846, 2.17], [0.9842, 2.16], [0.9838, 2.15], [0.9834, 2.14], [0.9830, 2.13], [0.9826, 2.12], [0.9821, 2.11], [0.9817, 2.10], [0.9812, 2.09], [0.9808, 2.08], [0.9803, 2.07], [0.9798, 2.06], [0.9793, 2.05], [0.9788, 2.04], [0.9783, 2.03], [0.9778, 2.02], [0.9772, 2.01], [0.9767, 2.00], [0.9761, 1.99], [0.9756, 1.98], [0.9750, 1.97], [0.9744, 1.96], [0.9738, 1.95], [0.9732, 1.94], [0.9726, 1.93], [0.9719, 1.92], [0.9713, 1.91], [0.9706, 1.90], [0.9699, 1.89], [0.9693, 1.88], [0.9686, 1.87], [0.9678, 1.86], [0.9671, 1.85], [0.9664, 1.84], [0.9656, 1.83], [0.9649, 1.82], [0.9641, 1.81], [0.9633, 1.80], [0.9625, 1.79], [0.9616, 1.78], [0.9608, 1.77], [0.9599, 1.76], [0.9591, 1.75], [0.9582, 1.74], [0.9573, 1.73], [0.9564, 1.72], [0.9554, 1.71], [0.9545, 1.70], [0.9535, 1.69], [0.9525, 1.68], [0.9515, 1.67], [0.9505, 1.66], [0.9495, 1.65], [0.9484, 1.64], [0.9474, 1.63], [0.9463, 1.62], [0.9452, 1.61], [0.9441, 1.60], [0.9429, 1.59], [0.9418, 1.58], [0.9406, 1.57], [0.9394, 1.56], [0.9382, 1.55], [0.9370, 1.54], [0.9357, 1.53], [0.9345, 1.52], [0.9332, 1.51], [0.9319, 1.50], [0.9306, 1.49], [0.9292, 1.48], [0.9279, 1.47], [0.9265, 1.46], [0.9251, 1.45], [0.9236, 1.44], [0.9222, 1.43], [0.9207, 1.42], [0.9192, 1.41], [0.9177, 1.40], [0.9162, 1.39], [0.9147, 1.38], [0.9131, 1.37], [0.9115, 1.36], [0.9099, 1.35], [0.9082, 1.34], [0.9066, 1.33], [0.9049, 1.32], [0.9032, 1.31], [0.9015, 1.30], [0.8997, 1.29], [0.8980, 1.28], [0.8962, 1.27], [0.8944, 1.26], [0.8925, 1.25], [0.8907, 1.24], [0.8888, 1.23], [0.8869, 1.22], [0.8849, 1.21], [0.8830, 1.20], [0.8810, 1.19], [0.8790, 1.18], [0.8770, 1.17], [0.8749, 1.16], [0.8729, 1.15], [0.8708, 1.14], [0.8686, 1.13], [0.8665, 1.12], [0.8643, 1.11], [0.8621, 1.10], [0.8599, 1.09], [0.8577, 1.08], [0.8554, 1.07], [0.8531, 1.06], [0.8508, 1.05], [0.8485, 1.04], [0.8461, 1.03], [0.8438, 1.02], [0.8413, 1.01], [0.8389, 1.00], [0.8365, 0.99], [0.8340, 0.98], [0.8315, 0.97], [0.8289, 0.96], [0.8264, 0.95], [0.8238, 0.94], [0.8212, 0.93], [0.8186, 0.92], [0.8159, 0.91], [0.8133, 0.90], [0.8106, 0.89], [0.8078, 0.88], [0.8051, 0.87], [0.8023, 0.86], [0.7995, 0.85], [0.7967, 0.84], [0.7939, 0.83], [0.7910, 0.82], [0.7881, 0.81], [0.7852, 0.80], [0.7823, 0.79], [0.7794, 0.78], [0.7764, 0.77], [0.7734, 0.76], [0.7704, 0.75], [0.7673, 0.74], [0.7642, 0.73], [0.7611, 0.72], [0.7580, 0.71], [0.7549, 0.70], [0.7517, 0.69], [0.7486, 0.68], [0.7454, 0.67], [0.7422, 0.66], [0.7389, 0.65], [0.7357, 0.64], [0.7324, 0.63], [0.7291, 0.62], [0.7257, 0.61], [0.7224, 0.60], [0.7190, 0.59], [0.7157, 0.58], [0.7123, 0.57], [0.7088, 0.56], [0.7054, 0.55], [0.7019, 0.54], [0.6985, 0.53], [0.6950, 0.52], [0.6915, 0.51], [0.6879, 0.50], [0.6844, 0.49], [0.6808, 0.48], [0.6772, 0.47], [0.6736, 0.46], [0.6700, 0.45], [0.6664, 0.44], [0.6628, 0.43], [0.6591, 0.42], [0.6554, 0.41], [0.6517, 0.40], [0.6480, 0.39], [0.6443, 0.38], [0.6406, 0.37], [0.6368, 0.36], [0.6331, 0.35], [0.6293, 0.34], [0.6255, 0.33], [0.6217, 0.32], [0.6179, 0.31], [0.6141, 0.30], [0.6103, 0.29], [0.6064, 0.28], [0.6026, 0.27], [0.5987, 0.26], [0.5948, 0.25], [0.5910, 0.24], [0.5871, 0.23], [0.5832, 0.22], [0.5793, 0.21], [0.5753, 0.20], [0.5714, 0.19], [0.5675, 0.18], [0.5636, 0.17], [0.5596, 0.16], [0.5557, 0.15], [0.5517, 0.14], [0.5478, 0.13], [0.5438, 0.12], [0.5398, 0.11], [0.5359, 0.10], [0.5319, 0.09], [0.5279, 0.08], [0.5239, 0.07], [0.5199, 0.06], [0.5160, 0.05], [0.5120, 0.04], [0.5080, 0.03], [0.5040, 0.02], [0.5000, 0.01]]; /** * Function to return a Z-score for a given confidence interval. */ function zScoreByConfidenceInterval(confidenceInterval) { var twoTailed = arguments.length <= 1 || arguments[1] === undefined ? true : arguments[1]; var zScore = 0.00; var tailedConfidenceInterval = twoTailed ? 1 - (1 - confidenceInterval) / 2 : confidenceInterval; if (tailedConfidenceInterval < 0.5000 || tailedConfidenceInterval > 0.9998) { if (twoTailed) { throw new Error('Your confidenceInterval must be between 0.5000 and 0.9996'); } else { throw new Error('Your confidenceInterval must be between 0.5000 and 0.9998'); } } for (var i = 0; i < zTable.length; i++) { if (tailedConfidenceInterval > zTable[i][0]) { zScore = zTable[i][1]; break; } } return zScore; } /***/ }, /* 36 */ /***/ function(module, exports, __webpack_require__) { module.exports = { "default": __webpack_require__(45), __esModule: true }; /***/ }, /* 37 */ /***/ function(module, exports, __webpack_require__) { module.exports = { "default": __webpack_require__(46), __esModule: true }; /***/ }, /* 38 */ /***/ function(module, exports, __webpack_require__) { module.exports = { "default": __webpack_require__(49), __esModule: true }; /***/ }, /* 39 */ /***/ function(module, exports, __webpack_require__) { module.exports = { "default": __webpack_require__(50), __esModule: true }; /***/ }, /* 40 */ /***/ function(module, exports, __webpack_require__) { module.exports = { "default": __webpack_require__(51), __esModule: true }; /***/ }, /* 41 */ /***/ function(module, exports, __webpack_require__) { "use strict"; exports.__esModule = true; var _defineProperty = __webpack_require__(12); var _defineProperty2 = _interopRequireDefault(_defineProperty); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } exports.default = function (obj, key, value) { if (key in obj) { (0, _defineProperty2.default)(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }; /***/ }, /* 42 */ /***/ function(module, exports, __webpack_require__) { "use strict"; var _Object$assign = __webpack_require__(36)["default"]; exports["default"] = _Object$assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; exports.__esModule = true; /***/ }, /* 43 */ /***/ function(module, exports, __webpack_require__) { "use strict"; var _Symbol = __webpack_require__(40)["default"]; exports["default"] = function (obj) { return obj && obj.constructor === _Symbol ? "symbol" : typeof obj; }; exports.__esModule = true; /***/ }, /* 44 */ /***/ function(module, exports, __webpack_require__) { var core = __webpack_require__(2); module.exports = function stringify(it){ // eslint-disable-line no-unused-vars return (core.JSON && core.JSON.stringify || JSON.stringify).apply(JSON, arguments); }; /***/ }, /* 45 */ /***/ function(module, exports, __webpack_require__) { __webpack_require__(63); module.exports = __webpack_require__(2).Object.assign; /***/ }, /* 46 */ /***/ function(module, exports, __webpack_require__) { var $ = __webpack_require__(1); module.exports = function create(P, D){ return $.create(P, D); }; /***/ }, /* 47 */ /***/ function(module, exports, __webpack_require__) { var $ = __webpack_require__(1); module.exports = function defineProperty(it, key, desc){ return $.setDesc(it, key, desc); }; /***/ }, /* 48 */ /***/ function(module, exports, __webpack_require__) { __webpack_require__(64); module.exports = __webpack_require__(2).Object.getPrototypeOf; /***/ }, /* 49 */ /***/ function(module, exports, __webpack_require__) { __webpack_require__(65); module.exports = __webpack_require__(2).Object.keys; /***/ }, /* 50 */ /***/ function(module, exports, __webpack_require__) { __webpack_require__(66); module.exports = __webpack_require__(2).Object.setPrototypeOf; /***/ }, /* 51 */ /***/ function(module, exports, __webpack_require__) { __webpack_require__(68); __webpack_require__(67); module.exports = __webpack_require__(2).Symbol; /***/ }, /* 52 */ /***/ function(module, exports) { module.exports = function(it){ if(typeof it != 'function')throw TypeError(it + ' is not a function!'); return it; }; /***/ }, /* 53 */ /***/ function(module, exports, __webpack_require__) { // all enumerable object keys, includes symbols var $ = __webpack_require__(1); module.exports = function(it){ var keys = $.getKeys(it) , getSymbols = $.getSymbols; if(getSymbols){ var symbols = getSymbols(it) , isEnum = $.isEnum , i = 0 , key; while(symbols.length > i)if(isEnum.call(it, key = symbols[i++]))keys.push(key); } return keys; }; /***/ }, /* 54 */ /***/ function(module, exports, __webpack_require__) { // fallback for IE11 buggy Object.getOwnPropertyNames with iframe and window var toIObject = __webpack_require__(8) , getNames = __webpack_require__(1).getNames , toString = {}.toString; var windowNames = typeof window == 'object' && Object.getOwnPropertyNames ? Object.getOwnPropertyNames(window) : []; var getWindowNames = function(it){ try { return getNames(it); } catch(e){ return windowNames.slice(); } }; module.exports.get = function getOwnPropertyNames(it){ if(windowNames && toString.call(it) == '[object Window]')return getWindowNames(it); return getNames(toIObject(it)); }; /***/ }, /* 55 */ /***/ function(module, exports, __webpack_require__) { var $ = __webpack_require__(1) , createDesc = __webpack_require__(27); module.exports = __webpack_require__(22) ? function(object, key, value){ return $.setDesc(object, key, createDesc(1, value)); } : function(object, key, value){ object[key] = value; return object; }; /***/ }, /* 56 */ /***/ function(module, exports, __webpack_require__) { // 7.2.2 IsArray(argument) var cof = __webpack_require__(19); module.exports = Array.isArray || function(arg){ return cof(arg) == 'Array'; }; /***/ }, /* 57 */ /***/ function(module, exports, __webpack_require__) { var $ = __webpack_require__(1) , toIObject = __webpack_require__(8); module.exports = function(object, el){ var O = toIObject(object) , keys = $.getKeys(O) , length = keys.length , index = 0 , key; while(length > index)if(O[key = keys[index++]] === el)return key; }; /***/ }, /* 58 */ /***/ function(module, exports) { module.exports = true; /***/ }, /* 59 */ /***/ function(module, exports, __webpack_require__) { // 19.1.2.1 Object.assign(target, source, ...) var $ = __webpack_require__(1) , toObject = __webpack_require__(9) , IObject = __webpack_require__(24); // should work with symbols and should have deterministic property order (V8 bug) module.exports = __webpack_require__(4)(function(){ var a = Object.assign , A = {} , B = {} , S = Symbol() , K = 'abcdefghijklmnopqrst'; A[S] = 7; K.split('').forEach(function(k){ B[k] = k; }); return a({}, A)[S] != 7 || Object.keys(a({}, B)).join('') != K; }) ? function assign(target, source){ // eslint-disable-line no-unused-vars var T = toObject(target) , $$ = arguments , $$len = $$.length , index = 1 , getKeys = $.getKeys , getSymbols = $.getSymbols , isEnum = $.isEnum; while($$len > index){ var S = IObject($$[index++]) , keys = getSymbols ? getKeys(S).concat(getSymbols(S)) : getKeys(S) , length = keys.length , j = 0 , key; while(length > j)if(isEnum.call(S, key = keys[j++]))T[key] = S[key]; } return T; } : Object.assign; /***/ }, /* 60 */ /***/ function(module, exports, __webpack_require__) { module.exports = __webpack_require__(55); /***/ }, /* 61 */ /***/ function(module, exports, __webpack_require__) { // Works with __proto__ only. Old v8 can't work with null proto objects. /* eslint-disable no-proto */ var getDesc = __webpack_require__(1).getDesc , isObject = __webpack_require__(25) , anObject = __webpack_require__(18); var check = function(O, proto){ anObject(O); if(!isObject(proto) && proto !== null)throw TypeError(proto + ": can't set as prototype!"); }; module.exports = { set: Object.setPrototypeOf || ('__proto__' in {} ? // eslint-disable-line function(test, buggy, set){ try { set = __webpack_require__(20)(Function.call, getDesc(Object.prototype, '__proto__').set, 2); set(test, []); buggy = !(test instanceof Array); } catch(e){ buggy = true; } return function setPrototypeOf(O, proto){ check(O, proto); if(buggy)O.__proto__ = proto; else set(O, proto); return O; }; }({}, false) : undefined), check: check }; /***/ }, /* 62 */ /***/ function(module, exports, __webpack_require__) { var def = __webpack_require__(1).setDesc , has = __webpack_require__(23) , TAG = __webpack_require__(30)('toStringTag'); module.exports = function(it, tag, stat){ if(it && !has(it = stat ? it : it.prototype, TAG))def(it, TAG, {configurable: true, value: tag}); }; /***/ }, /* 63 */ /***/ function(module, exports, __webpack_require__) { // 19.1.3.1 Object.assign(target, source) var $export = __webpack_require__(3); $export($export.S + $export.F, 'Object', {assign: __webpack_require__(59)}); /***/ }, /* 64 */ /***/ function(module, exports, __webpack_require__) { // 19.1.2.9 Object.getPrototypeOf(O) var toObject = __webpack_require__(9); __webpack_require__(26)('getPrototypeOf', function($getPrototypeOf){ return function getPrototypeOf(it){ return $getPrototypeOf(toObject(it)); }; }); /***/ }, /* 65 */ /***/ function(module, exports, __webpack_require__) { // 19.1.2.14 Object.keys(O) var toObject = __webpack_require__(9); __webpack_require__(26)('keys', function($keys){ return function keys(it){ return $keys(toObject(it)); }; }); /***/ }, /* 66 */ /***/ function(module, exports, __webpack_require__) { // 19.1.3.19 Object.setPrototypeOf(O, proto) var $export = __webpack_require__(3); $export($export.S, 'Object', {setPrototypeOf: __webpack_require__(61).set}); /***/ }, /* 67 */ /***/ function(module, exports) { /***/ }, /* 68 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; // ECMAScript 6 symbols shim var $ = __webpack_require__(1) , global = __webpack_require__(5) , has = __webpack_require__(23) , DESCRIPTORS = __webpack_require__(22) , $export = __webpack_require__(3) , redefine = __webpack_require__(60) , $fails = __webpack_require__(4) , shared = __webpack_require__(28) , setToStringTag = __webpack_require__(62) , uid = __webpack_require__(29) , wks = __webpack_require__(30) , keyOf = __webpack_require__(57) , $names = __webpack_require__(54) , enumKeys = __webpack_require__(53) , isArray