function shuffle( arr, options ) {
		var strflg;
		var level;
		var copy;
		var opts;
		var err;
		var out;
		var tmp;
		var N;
		var i;
		var j;

		if ( !( isArrayLike( arr ) || isTypedArrayLike( arr ) ) ) {
			throw new TypeError( format( 'invalid argument. First argument must be array-like. Value: `%s`.', arr ) );
		}
		if ( arguments.length > 1 ) {
			opts = {};
			err = validate( opts, options );
			if ( err ) {
				throw err;
			}
		}
		copy = ( opts && opts.copy ) ? opts.copy : conf.copy;

		strflg = isString( arr );
		if ( strflg ) {
			arr = arr.split( '' );
			copy = 'none';
		}

		level = 0;
		if ( copy === 'shallow' ) {
			level += 1;
		} else if ( copy === 'deep' ) {
			level += 2;
		}
		N = arr.length;
		out = deepCopy( arr, level );

		// Note: we skip the first element, as no further swaps are possible given that all other indices are excluded from swapping...
		for ( i = N - 1; i > 0; i-- ) {
			// Generate an integer index on the interval [0,i]:
			j = floor( rand() * (i+1.0) );

			// Swap elements:
			tmp = out[ i ];
			out[ i ] = out[ j ];
			out[ j ] = tmp;
		}

		if ( strflg ) {
			out = arr.join( '' );
		}
		return out;
	}
Returns a random permutation of elements in `arr`.

@private
@param {(ArrayLike|TypedArrayLike)} arr - array-like object to shuffle
@param {Options} [options] - function options
@param {string} [options.copy] - string indicating whether to return a copy (`deep`,`shallow` or `none`)
@throws {TypeError} first argument must be array-like
@throws {TypeError} options must be an object
@throws {TypeError} must provide valid options
@returns {ArrayLike} the shuffled array-like object

@example
var data = [ 1, 2, 3 ];
var out = shuffle( data );
// e.g., returns [ 3, 1, 2 ]

@example
var data = [ 1, 2, 3 ];
var out = shuffle( data, {
    'copy': 'none'
});
var bool = ( data === out );
// returns true