function factory() {
	var lambda;
	var opts;
	var rand;
	var prng;

	if ( arguments.length === 0 ) {
		rand = randu();
	} else if (
		arguments.length === 1 &&
		isObject( arguments[ 0 ] )
	) {
		opts = arguments[ 0 ];
		if ( hasOwnProp( opts, 'prng' ) ) {
			if ( !isFunction( opts.prng ) ) {
				throw new TypeError( format( 'invalid option. `%s` option must be a pseudorandom number generator function. Option: `%s`.', 'prng', opts.prng ) );
			}
			rand = opts.prng;
		} else {
			rand = randu( opts );
		}
	} else {
		lambda = arguments[ 0 ];
		if ( !isPositive( lambda ) ) {
			throw new TypeError( format( 'invalid argument. First argument must be a positive number. Value: `%s`.', lambda ) );
		}
		if ( arguments.length > 1 ) {
			opts = arguments[ 1 ];
			if ( !isObject( opts ) ) {
				throw new TypeError( format( 'invalid argument. Options argument must be an object. Value: `%s`.', opts ) );
			}
			if ( hasOwnProp( opts, 'prng' ) ) {
				if ( !isFunction( opts.prng ) ) {
					throw new TypeError( format( 'invalid option. `%s` option must be a pseudorandom number generator function. Option: `%s`.', 'prng', opts.prng ) );
				}
				rand = opts.prng;
			} else {
				rand = randu( opts );
			}
		} else {
			rand = randu();
		}
	}
	if ( lambda === void 0 ) {
		prng = poisson2;
	} else {
		prng = poisson1;
	}
	setReadOnly( prng, 'NAME', 'poisson' );

	// If we are provided an "external" PRNG, we don't support getting or setting PRNG state, as we'd need to check for compatible state value types, etc, entailing considerable complexity.
	if ( opts && opts.prng ) {
		setReadOnly( prng, 'seed', null );
		setReadOnly( prng, 'seedLength', null );
		setReadWriteAccessor( prng, 'state', constantFunction( null ), noop );
		setReadOnly( prng, 'stateLength', null );
		setReadOnly( prng, 'byteLength', null );
		setReadOnly( prng, 'toJSON', constantFunction( null ) );
		setReadOnly( prng, 'PRNG', rand );
	} else {
		setReadOnlyAccessor( prng, 'seed', getSeed );
		setReadOnlyAccessor( prng, 'seedLength', getSeedLength );
		setReadWriteAccessor( prng, 'state', getState, setState );
		setReadOnlyAccessor( prng, 'stateLength', getStateLength );
		setReadOnlyAccessor( prng, 'byteLength', getStateSize );
		setReadOnly( prng, 'toJSON', toJSON );
		setReadOnly( prng, 'PRNG', rand );
		rand = rand.normalized;
	}
	return prng;

	/**
	* Returns the PRNG seed.
	*
	* @private
	* @returns {PRNGSeedMT19937} seed
	*/
	function getSeed() {
		return rand.seed;
	}

	/**
	* Returns the PRNG seed length.
	*
	* @private
	* @returns {PositiveInteger} seed length
	*/
	function getSeedLength() {
		return rand.seedLength;
	}

	/**
	* Returns the PRNG state length.
	*
	* @private
	* @returns {PositiveInteger} state length
	*/
	function getStateLength() {
		return rand.stateLength;
	}

	/**
	* Returns the PRNG state size (in bytes).
	*
	* @private
	* @returns {PositiveInteger} state size (in bytes)
	*/
	function getStateSize() {
		return rand.byteLength;
	}

	/**
	* Returns the current pseudorandom number generator state.
	*
	* @private
	* @returns {PRNGStateMT19937} current state
	*/
	function getState() {
		return rand.state;
	}

	/**
	* Sets the pseudorandom number generator state.
	*
	* @private
	* @param {PRNGStateMT19937} s - generator state
	* @throws {Error} must provide a valid state
	*/
	function setState( s ) {
		rand.state = s;
	}

	/**
	* Serializes the pseudorandom number generator as a JSON object.
	*
	* ## Notes
	*
	* -   `JSON.stringify()` implicitly calls this method when stringifying a PRNG.
	*
	* @private
	* @returns {Object} JSON representation
	*/
	function toJSON() {
		var out = {};
		out.type = 'PRNG';
		out.name = prng.NAME;
		out.state = typedarray2json( rand.state );
		if ( lambda === void 0 ) {
			out.params = [];
		} else {
			out.params = [ lambda ];
		}
		return out;
	}

	/**
	* Returns a pseudorandom number drawn from a Poisson distribution.
	*
	* @private
	* @returns {NonNegativeInteger} pseudorandom number
	*
	* @example
	* var v = poisson1();
	* // returns <number>
	*/
	function poisson1() {
		return poisson0( rand, lambda );
	}

	/**
	* Returns a pseudorandom number drawn from a Poisson distribution.
	*
	* @private
	* @param {PositiveNumber} lambda - mean
	* @returns {NonNegativeInteger} pseudorandom number
	*
	* @example
	* var v = poisson2( 0.5 );
	* // returns <number>
	*
	* @example
	* var v = poisson2( NaN );
	* // returns NaN
	*
	* @example
	* var v = poisson2( -1.0 );
	* // returns NaN
	*/
	function poisson2( lambda ) {
		if (
			isnan( lambda ) ||
			lambda <= 0.0
		) {
			return NaN;
		}
		return poisson0( rand, lambda );
	}
}
Returns a pseudorandom number generator for generating Poisson distributed random numbers.

@param {PositiveNumber} [lambda] - mean
@param {Options} [options] - function options
@param {PRNG} [options.prng] - pseudorandom number generator which generates uniformly distributed pseudorandom numbers
@param {PRNGSeedMT19937} [options.seed] - pseudorandom number generator seed
@param {PRNGStateMT19937} [options.state] - pseudorandom number generator state
@param {boolean} [options.copy=true] - boolean indicating whether to copy a provided pseudorandom number generator state
@throws {TypeError} `lambda` must be a positive number
@throws {TypeError} options argument must be an object
@throws {TypeError} must provide valid options
@throws {Error} must provide a valid state
@returns {PRNG} pseudorandom number generator

@example
var poisson = factory( 5.0 );
var v = poisson();
// returns <number>

@example
var poisson = factory( 8.0, {
    'seed': 297
});
var v = poisson();
// returns <number>

@example
var poisson = factory();
var v = poisson( 0.5 );
// returns <number>