code: function(config) {
      try {
        var hasLogger = false;
        config = config || {};
  
        // TODO warn about setting per instance errorHandler / logger / logLevel
        if (config.errorHandler) {
          logging.setErrorHandler(config.errorHandler);
        }
        if (config.logger) {
          // only set a logger in node if one is provided, by not setting we are noop-ing
          hasLogger = true;
          logging.setLogHandler(config.logger);
          // respect the logger's shouldLog functionality
          logging.setLogLevel(logging.LogLevel.NOTSET);
        }
        if (config.logLevel !== undefined) {
          logging.setLogLevel(config.logLevel);
        }
  
        try {
          configValidator.validate(config);
          config.isValidInstance = true;
        } catch (ex) {
          if (hasLogger) {
            logger.error(ex);
          } else {
            console.error(ex.message);
          }
          config.isValidInstance = false;
        }
  
        config = fns.assign(
          {
            eventDispatcher: defaultEventDispatcher,
            jsonSchemaValidator: jsonSchemaValidator,
            skipJSONValidation: false,
          },
          config,
          {
            clientEngine: enums.NODE_CLIENT_ENGINE,
            // always get the OptimizelyLogger facade from logging
            logger: logger,
            errorHandler: logging.getErrorHandler(),
          }
        );
  
        return new Optimizely(config);
      } catch (e) {
        logger.error(e);
        return null;
      }
    }
docs: Creates an instance of the Optimizely class
  @param  {Object} config
  @param  {Object} config.datafile
  @param  {Object} config.errorHandler
  @param  {Object} config.eventDispatcher
  @param  {Object} config.jsonSchemaValidator
  @param  {Object} config.logger
  @param  {Object} config.userProfileService
  @param {Object} config.eventBatchSize
  @param {Object} config.eventFlushInterval
  @return {Object} the Optimizely object