docs: function Customize (config, parentConfig, engines) {
    var _config = mergeWith({}, parentConfig, config, customOverrider)
  
    // Debug logging
    if (debugState.enabled) {
      deep(_config).then(function (config) {
        debugState('New configuration', config)
      }, /* istanbul ignore next */
      function (e) {
        console.error('Error while debug-logging the built configuration ' + e.stack) // eslint-disable-line no-console
      })
    }
  
    /**
     * Register an engine
     * @param {string} id the identifier of the engine. This identifier is also used
     *  within the config as key within the configuration object to identify the
     *  sub-configuration stored for this engine.
     * @param {object} engine  a customize engine that is registered
     * @param {object=} engine.defaultConfig the default configuration of the engine
     * @param {function(object):object=} engine.preprocessConfig a preprocessor to convert a merge-configuration to the internal format of the engine
     * @param {function(object):object} engine.run the execution function of the engine (the merged config is passed as parameter
     * @param {function(object):object} engine.run the execution function of the engine (the merged config is passed as parameter)
     * @param {object=} engine.schema a JSON-schema to validate the merge-configurations against.
     *
     * @public
     */
    this.registerEngine = function (id, engine) {
      debug('Registering engine \'' + id + '\'')
      if (typeof id !== 'string') {
        throw new Error('Engine-id must be a string, but is ' + id)
      }
      if (id.substr(0, 1) === '_') {
        throw new Error('Engine-id may not start with an underscore ("_"), but is ' + id)
      }
      if (engine['run'] == null) {
        throw new Error('Engine ' + id + ' needs a run method')
      }
  
      // This is only allowed if no engine with the same id exists.
      if (engines[id] != null || _config[id] != null) {
        var error = new Error('Engine \'' + id + '\' already registered.', 'ERR_ENGINE_EXISTS')
        error.engine = engines[id]
        error.config = _config[id]
        throw error
      }
  
      var _engines = mapValues(engines) // clone
      _engines[id] = engine
      var _defaultConfig = {}
      _defaultConfig[id] = {
        config: engine.defaultConfig || {},
        watched: engine.defaultWatched || []
      }
      return new Customize(_defaultConfig, _config, _engines)
    }
  
    /**
     * Returns the JSON-schema that configuration objects must match for this
     * configuration. The schema does not contain main description property
     */
    this.configSchema = function () {
      return {
        'id': 'http://json-schema.org/draft-04/schema#',
        '$schema': 'http://json-schema.org/draft-04/schema#',
        'type': 'object',
        'properties': mapValues(engines, function (engine) {
          return engine.schema || {
            type: 'object',
            description: 'No expicit schema has been provided for this engine'
          }
        })
  
      }
    }
  
    /**
     * Creates a new instance of Customize. The configuration values of the current Customize
     * are used as default values and are overridden by the configuration provided as parameter.
     * @param {object} config configuration overriding the current configuration
     * @return {Customize} the new Customize instance
     * @api public
     */
    this.merge = function (config) {
      if (config == null) {
        throw new Error('Cannot merge undefined \'config\'')
      }
  
      debug('Calling merge', config)
  
      // Assert that for each key in the other configuration, there is an engine present
      // Apply engine preprocessor to each config
      var preprocessedConfig = mapValues(config, function (engineConf, engineName) {
        var engine = engines[engineName]
        if (engine == null) {
          throw new Error('Engine \'' + engineName + '\' not found. Refusing to store configuration')
        }
        // Load preprocessor with identity as default
        var preprocessor = engine.preprocessConfig || function (a) { return a }
        // Watch no files by default (constant [])
        var watched = engine.watched || constant([])
  
        return Promise.resolve(engineConf).then(function (engineConf) {
          if (engine.schema) {
            debug('Validating schema for ', engineName)
            /**
             * The overriding configuration must validate against the [JSON-schema for configurations](./config-schema.html)
             * Otherwise we refuse to proceed.
             */
            var validationErrors = validator.validate(engineConf, engine.schema).errors
            if (validationErrors.length > 0) {
              debug('Error while validating config for engine \'' + engineName + '\': ', engineConf)
              debug('Errors: ', validationErrors.map(String).join('\n'))
              var error = new Error('Error while validating Customize configuration')
              error.validationErrors = validationErrors
              throw error
            }
          }
  
          return {
            config: preprocessor(engineConf),
            watched: watched(engineConf).filter(isString)
          }
        }).then(function (config) {
          debug('Merging preprocessed config', config)
          return config
        })
      })
  
      return new Customize(preprocessedConfig, _config, engines)
    }
  
    /**
     * Inherit configuration config from another module.
     * a Customizer-module usually exports a `function(Customize):Customize`
     * which in tern calls `Customize.merge` to create a new Customize instance.
     * This function needs to be passed in here.
     *
     * A new Customize will be returned that overrides the current configuration
     * with the configuration of the module.
     * @param {function(Customize):Customize} customizeModule  that receives a Customize as paramater
     *  and returns a Customize with changed configuration.
     * @return {Customize} the Customize instance returned by the module
     * @public
     */
    this.load = function (customizeModule) {
      // Container for configuration metadata (e.g. versions of loaded modules)
      var _metadata = {
        config: {
          modules: []
        }
      }
      if (customizeModule.package) {
        debugVersions('Loading', customizeModule.package.name, customizeModule.package.version)
        _metadata.config.modules.push(customizeModule.package)
      }
  
      return customizeModule(new Customize({ _metadata: _metadata }, _config, engines))
    }
  
    /**
     * Return a promise for the merged configuration.
     * This functions is only needed to inspect intermediate configuration results
     * (i.e. for testing and documentation purposes)
     * @return {Promise<object>} a promise for the whole configuration
     * @public
     */
    this.buildConfig = function () {
      return deep(_config).then(function (config) {
        return mapValues(config, 'config')
      }).then(function (config) {
        debug('Building', config)
        return config
      })
    }
  
    /**
     * Return a promise for the files needing to be watched in watch-mode,
     * indexed by engine.
     * @return {Promise<object<string[]>>} a promise for the files to be watched.
     *
     * @public
     */
    this.watched = function () {
      return deep(_config).then(function (config) {
        return mapValues(config, 'watched')
      }).then(function (watchedFiles) {
        debug('Watched files', watchedFiles)
        return watchedFiles
      })
    }
  
    /**
     * Run each engine with its part of the config.
     *
     * @param {object=} options optional paramters
     * @param {string=} options.onlyEngine the name of an engine if only a single engine should
     *  be executed
     * @return {Promise<object>} an object containing on property per registered engine
     *  (the key is the engine-id) containing the result of each engine
     * @public
     */
    this.run = function (options) {
      var onlyEngine = options && options.onlyEngine
      return this.buildConfig().then(function (resolvedConfig) {
        var result = mapValues(engines, function (engine, key) {
          // if "onlyEngine" is set to a value, execute on the engine with the same name
          if (!onlyEngine || onlyEngine === key) {
            return engine.run(resolvedConfig[key])
          }
        })
        return deep(result)
      })
    }
  }