    /*
    	This file was derived from the p5.js source code at
    	https://github.com/processing/p5.js

    	Copyright (c) the p5.js contributors and Andre Seidelt <superilu@yahoo.com>

        This library is free software; you can redistribute it and/or
        modify it under the terms of the GNU Lesser General Public
        License as published by the Free Software Foundation; either
        version 2.1 of the License, or (at your option) any later version.

        This library is distributed in the hope that it will be useful,
        but WITHOUT ANY WARRANTY; without even the implied warranty of
        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
        Lesser General Public License for more details.

        You should have received a copy of the GNU Lesser General Public
        License along with this library; if not, write to the Free Software
        Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
     */

    /**
    * @module p5compat
    */

    /**
     * Creates a new PVector (the datatype for storing vectors). This provides a
     * two or three dimensional vector, specifically a Euclidean (also known as
     * geometric) vector. A vector is an entity that has both magnitude and
     * direction.
     *
     * @method createVector
     * @param {Number} [x] x component of the vector
     * @param {Number} [y] y component of the vector
     * @param {Number} [z] z component of the vector
     * @return {p5.Vector}
     * @example
     * function setup() {
     *   createCanvas(100, 100, WEBGL);
     *   noStroke();
     *   fill(255, 102, 204);
     * }
     *
     * function draw() {
     *   background(255);
     *   pointLight(color(255), createVector(sin(millis() / 1000) * 20, -40, -10));
     *   scale(0.75);
     *   sphere();
     * }
     */
    exports.createVector = function (x, y, z) {
    	return new PVector(x, y, z);
    };

    /**********************************************************************************************************************
     * Calculations
     */

    /**
     * Calculates the absolute value (magnitude) of a number. Maps to Math.abs().
     * The absolute value of a number is always positive.
     *
     * @method abs
     * @param  {Number} n number to compute
     * @return {Number}   absolute value of given number
     * @example
     * function setup() {
     *   let x = -3;
     *   let y = abs(x);
     *
     *   print(x); // -3
     *   print(y); // 3
     * }
     */
    exports.abs = Math.abs;

    /**
     * Calculates the closest int value that is greater than or equal to the
     * value of the parameter. Maps to Math.ceil(). For example, ceil(9.03)
     * returns the value 10.
     *
     * @method ceil
     * @param  {Number} n number to round up
     * @return {Integer}   rounded up number
     * @example
     * function draw() {
     *   background(200);
     *   // map, mouseX between 0 and 5.
     *   let ax = map(mouseX, 0, 100, 0, 5);
     *   let ay = 66;
     *
     *   //Get the ceiling of the mapped number.
     *   let bx = ceil(map(mouseX, 0, 100, 0, 5));
     *   let by = 33;
     *
     *   // Multiply the mapped numbers by 20 to more easily
     *   // see the changes.
     *   stroke(0);
     *   fill(0);
     *   line(0, ay, ax * 20, ay);
     *   line(0, by, bx * 20, by);
     *
     *   // Reformat the float returned by map and draw it.
     *   noStroke();
     *   text(nfc(ax, 2), ax, ay - 5);
     *   text(nfc(bx, 1), bx, by - 5);
     * }
     */
    exports.ceil = Math.ceil;

    /**
     * Constrains a value between a minimum and maximum value.
     *
     * @method constrain
     * @param  {Number} n    number to constrain
     * @param  {Number} low  minimum limit
     * @param  {Number} high maximum limit
     * @return {Number}      constrained number
     * @example
     * function draw() {
     *   background(200);
     *
     *   let leftWall = 25;
     *   let rightWall = 75;
     *
     *   // xm is just the mouseX, while
     *   // xc is the mouseX, but constrained
     *   // between the leftWall and rightWall!
     *   let xm = mouseX;
     *   let xc = constrain(mouseX, leftWall, rightWall);
     *
     *   // Draw the walls.
     *   stroke(150);
     *   line(leftWall, 0, leftWall, height);
     *   line(rightWall, 0, rightWall, height);
     *
     *   // Draw xm and xc as circles.
     *   noStroke();
     *   fill(150);
     *   ellipse(xm, 33, 9, 9); // Not Constrained
     *   fill(0);
     *   ellipse(xc, 66, 9, 9); // Constrained
     * }
     */
    exports.constrain = function (n, low, high) {
    	return Math.max(Math.min(n, high), low);
    };

    /**
     * Calculates the distance between two points.
     *
     * @method dist
     * @param  {Number} x1 x-coordinate of the first point
     * @param  {Number} y1 y-coordinate of the first point
     * @param  {Number} x2 x-coordinate of the second point
     * @param  {Number} y2 y-coordinate of the second point
     * @return {Number}    distance between the two points
     *
     * @example
     * // Move your mouse inside the canvas to see the
     * // change in distance between two points!
     * function draw() {
     *   background(200);
     *   fill(0);
     *
     *   let x1 = 10;
     *   let y1 = 90;
     *   let x2 = mouseX;
     *   let y2 = mouseY;
     *
     *   line(x1, y1, x2, y2);
     *   ellipse(x1, y1, 7, 7);
     *   ellipse(x2, y2, 7, 7);
     *
     *   // d is the length of the line
     *   // the distance from point 1 to point 2.
     *   let d = int(dist(x1, y1, x2, y2));
     *
     *   // Let's write d along the line we are drawing!
     *   push();
     *   translate((x1 + x2) / 2, (y1 + y2) / 2);
     *   rotate(atan2(y2 - y1, x2 - x1));
     *   text(nfc(d, 1), 0, -5);
     *   pop();
     *   // Fancy!
     * }
     */
    exports.dist = function () {
    	if (arguments.length === 4) {
    		//2D
    		return hypot(arguments[2] - arguments[0], arguments[3] - arguments[1]);
    	} else if (arguments.length === 6) {
    		//3D
    		return hypot(
    			arguments[3] - arguments[0],
    			arguments[4] - arguments[1],
    			arguments[5] - arguments[2]
    		);
    	}
    };

    /**
     * Returns Euler's number e (2.71828...) raised to the power of the n
     * parameter. Maps to Math.exp().
     *
     * @method exp
     * @param  {Number} n exponent to raise
     * @return {Number}   e^n
     * @example
     * function draw() {
     *   background(200);
     *
     *   // Compute the exp() function with a value between 0 and 2
     *   let xValue = map(mouseX, 0, width, 0, 2);
     *   let yValue = exp(xValue);
     *
     *   let y = map(yValue, 0, 8, height, 0);
     *
     *   let legend = 'exp (' + nfc(xValue, 3) + ')\n= ' + nf(yValue, 1, 4);
     *   stroke(150);
     *   line(mouseX, y, mouseX, height);
     *   fill(0);
     *   text(legend, 5, 15);
     *   noStroke();
     *   ellipse(mouseX, y, 7, 7);
     *
     *   // Draw the exp(x) curve,
     *   // over the domain of x from 0 to 2
     *   noFill();
     *   stroke(0);
     *   beginShape();
     *   for (let x = 0; x < width; x++) {
     *     xValue = map(x, 0, width, 0, 2);
     *     yValue = exp(xValue);
     *     y = map(yValue, 0, 8, height, 0);
     *     vertex(x, y);
     *   }
     *
     *   endShape();
     *   line(0, 0, 0, height);
     *   line(0, height - 1, width, height - 1);
     * }
     */
    exports.exp = Math.exp;

    /**
     * Calculates the closest int value that is less than or equal to the
     * value of the parameter. Maps to Math.floor().
     *
     * @method floor
     * @param  {Number} n number to round down
     * @return {Integer}  rounded down number
     * @example
     * function draw() {
     *   background(200);
     *   //map, mouseX between 0 and 5.
     *   let ax = map(mouseX, 0, 100, 0, 5);
     *   let ay = 66;
     *
     *   //Get the floor of the mapped number.
     *   let bx = floor(map(mouseX, 0, 100, 0, 5));
     *   let by = 33;
     *
     *   // Multiply the mapped numbers by 20 to more easily
     *   // see the changes.
     *   stroke(0);
     *   fill(0);
     *   line(0, ay, ax * 20, ay);
     *   line(0, by, bx * 20, by);
     *
     *   // Reformat the float returned by map and draw it.
     *   noStroke();
     *   text(nfc(ax, 2), ax, ay - 5);
     *   text(nfc(bx, 1), bx, by - 5);
     * }
     */
    exports.floor = Math.floor;

    /**
     * Calculates a number between two numbers at a specific increment. The amt
     * parameter is the amount to interpolate between the two values where 0.0
     * equal to the first point, 0.1 is very near the first point, 0.5 is
     * half-way in between, and 1.0 is equal to the second point. If the
     * value of amt is more than 1.0 or less than 0.0, the number will be
     * calculated accordingly in the ratio of the two given numbers. The lerp
     * function is convenient for creating motion along a straight
     * path and for drawing dotted lines.
     *
     * @method lerp
     * @param  {Number} start first value
     * @param  {Number} stop  second value
     * @param  {Number} amt   number
     * @return {Number}       lerped value
     * @example
     * function setup() {
     *   background(200);
     *   let a = 20;
     *   let b = 80;
     *   let c = lerp(a, b, 0.2);
     *   let d = lerp(a, b, 0.5);
     *   let e = lerp(a, b, 0.8);
     *
     *   let y = 50;
     *
     *   strokeWeight(5);
     *   stroke(0); // Draw the original points in black
     *   point(a, y);
     *   point(b, y);
     *
     *   stroke(100); // Draw the lerp points in gray
     *   point(c, y);
     *   point(d, y);
     *   point(e, y);
     * }
     */
    exports.lerp = function (start, stop, amt) {
    	return amt * (stop - start) + start;
    };

    /**
     * Calculates the natural logarithm (the base-e logarithm) of a number. This
     * function expects the n parameter to be a value greater than 0.0. Maps to
     * Math.log().
     *
     * @method log
     * @param  {Number} n number greater than 0
     * @return {Number}   natural logarithm of n
     * @example
     * function draw() {
     *   background(200);
     *   let maxX = 2.8;
     *   let maxY = 1.5;
     *
     *   // Compute the natural log of a value between 0 and maxX
     *   let xValue = map(mouseX, 0, width, 0, maxX);
     *   let yValue, y;
     *   if (xValue > 0) {
     *   // Cannot take the log of a negative number.
     *     yValue = log(xValue);
     *     y = map(yValue, -maxY, maxY, height, 0);
     *
     *     // Display the calculation occurring.
     *     let legend = 'log(' + nf(xValue, 1, 2) + ')\n= ' + nf(yValue, 1, 3);
     *     stroke(150);
     *     line(mouseX, y, mouseX, height);
     *     fill(0);
     *     text(legend, 5, 15);
     *     noStroke();
     *     ellipse(mouseX, y, 7, 7);
     *   }
     *
     *   // Draw the log(x) curve,
     *   // over the domain of x from 0 to maxX
     *   noFill();
     *   stroke(0);
     *   beginShape();
     *   for (let x = 0; x < width; x++) {
     *     xValue = map(x, 0, width, 0, maxX);
     *     yValue = log(xValue);
     *     y = map(yValue, -maxY, maxY, height, 0);
     *     vertex(x, y);
     *   }
     *   endShape();
     *   line(0, 0, 0, height);
     *   line(0, height / 2, width, height / 2);
     * }
     */
    exports.log = Math.log;

    /**
     * Calculates the magnitude (or length) of a vector. A vector is a direction
     * in space commonly used in computer graphics and linear algebra. Because it
     * has no "start" position, the magnitude of a vector can be thought of as
     * the distance from the coordinate 0,0 to its x,y value. Therefore, mag() is
     * a shortcut for writing dist(0, 0, x, y).
     *
     * @method mag
     * @param  {Number} a first value
     * @param  {Number} b second value
     * @return {Number}   magnitude of vector from (0,0) to (a,b)
     * @example
     * function setup() {
     *   let x1 = 20;
     *   let x2 = 80;
     *   let y1 = 30;
     *   let y2 = 70;
     *
     *   line(0, 0, x1, y1);
     *   print(mag(x1, y1)); // Prints "36.05551275463989"
     *   line(0, 0, x2, y1);
     *   print(mag(x2, y1)); // Prints "85.44003745317531"
     *   line(0, 0, x1, y2);
     *   print(mag(x1, y2)); // Prints "72.80109889280519"
     *   line(0, 0, x2, y2);
     *   print(mag(x2, y2)); // Prints "106.3014581273465"
     * }
     */
    exports.mag = function (x, y) {
    	return hypot(x, y);
    };

    /**
     * Re-maps a number from one range to another.
     * <br><br>
     * In the first example above, the number 25 is converted from a value in the
     * range of 0 to 100 into a value that ranges from the left edge of the
     * window (0) to the right edge (width).
     *
     * @method map
     * @param  {Number} value  the incoming value to be converted
     * @param  {Number} start1 lower bound of the value's current range
     * @param  {Number} stop1  upper bound of the value's current range
     * @param  {Number} start2 lower bound of the value's target range
     * @param  {Number} stop2  upper bound of the value's target range
     * @param  {Boolean} [withinBounds] constrain the value to the newly mapped range
     * @return {Number}        remapped number
     * @example
     * let value = 25;
     * let m = map(value, 0, 100, 0, width);
     * ellipse(m, 50, 10, 10);
     *
     * function setup() {
     *   noStroke();
     * }
     *
     * function draw() {
     *   background(204);
     *   let x1 = map(mouseX, 0, width, 25, 75);
     *   ellipse(x1, 25, 25, 25);
     *   //This ellipse is constrained to the 0-100 range
     *   //after setting withinBounds to true
     *   let x2 = map(mouseX, 0, width, 0, 100, true);
     *   ellipse(x2, 75, 25, 25);
     * }
     */
    exports.map = function (n, start1, stop1, start2, stop2, withinBounds) {
    	var newval = (n - start1) / (stop1 - start1) * (stop2 - start2) + start2;
    	if (!withinBounds) {
    		return newval;
    	}
    	if (start2 < stop2) {
    		return this.constrain(newval, start2, stop2);
    	} else {
    		return this.constrain(newval, stop2, start2);
    	}
    };

    /**
     * Determines the largest value in a sequence of numbers, and then returns
     * that value. max() accepts any number of Number parameters, or an Array
     * of any length.
     *
     * @method max
     * @param  {Number} n0 Number to compare
     * @param  {Number} n1 Number to compare
     * @return {Number}             maximum Number
     * @example
     * function setup() {
     *   // Change the elements in the array and run the sketch
     *   // to show how max() works!
     *   let numArray = [2, 1, 5, 4, 8, 9];
     *   fill(0);
     *   noStroke();
     *   text('Array Elements', 0, 10);
     *   // Draw all numbers in the array
     *   let spacing = 15;
     *   let elemsY = 25;
     *   for (let i = 0; i < numArray.length; i++) {
     *     text(numArray[i], i * spacing, elemsY);
     *   }
     *   let maxX = 33;
     *   let maxY = 80;
     *   // Draw the Maximum value in the array.
     *   textSize(32);
     *   text(max(numArray), maxX, maxY);
     * }
     */
    exports.max = function () {
    	if (arguments[0] instanceof Array) {
    		return Math.max.apply(null, arguments[0]);
    	} else {
    		return Math.max.apply(null, arguments);
    	}
    };

    /**
     * Determines the smallest value in a sequence of numbers, and then returns
     * that value. min() accepts any number of Number parameters, or an Array
     * of any length.
     *
     * @method min
     * @param  {Number} n0 Number to compare
     * @param  {Number} n1 Number to compare
     * @return {Number}             minimum Number
     * @example
     * function setup() {
     *   // Change the elements in the array and run the sketch
     *   // to show how min() works!
     *   let numArray = [2, 1, 5, 4, 8, 9];
     *   fill(0);
     *   noStroke();
     *   text('Array Elements', 0, 10);
     *   // Draw all numbers in the array
     *   let spacing = 15;
     *   let elemsY = 25;
     *   for (let i = 0; i < numArray.length; i++) {
     *     text(numArray[i], i * spacing, elemsY);
     *   }
     *   let maxX = 33;
     *   let maxY = 80;
     *   // Draw the Minimum value in the array.
     *   textSize(32);
     *   text(min(numArray), maxX, maxY);
     * }
     */
    exports.min = function () {
    	if (arguments[0] instanceof Array) {
    		return Math.min.apply(null, arguments[0]);
    	} else {
    		return Math.min.apply(null, arguments);
    	}
    };

    /**
     * Normalizes a number from another range into a value between 0 and 1.
     * Identical to map(value, low, high, 0, 1).
     * Numbers outside of the range are not clamped to 0 and 1, because
     * out-of-range values are often intentional and useful. (See the second
     * example above.)
     *
     * @method norm
     * @param  {Number} value incoming value to be normalized
     * @param  {Number} start lower bound of the value's current range
     * @param  {Number} stop  upper bound of the value's current range
     * @return {Number}       normalized number
     * @example
     * function draw() {
     *   background(200);
     *   let currentNum = mouseX;
     *   let lowerBound = 0;
     *   let upperBound = width; //100;
     *   let normalized = norm(currentNum, lowerBound, upperBound);
     *   let lineY = 70;
     *   line(0, lineY, width, lineY);
     *   //Draw an ellipse mapped to the non-normalized value.
     *   noStroke();
     *   fill(50);
     *   let s = 7; // ellipse size
     *   ellipse(currentNum, lineY, s, s);
     *
     *   // Draw the guide
     *   let guideY = lineY + 15;
     *   text('0', 0, guideY);
     *   textAlign(RIGHT);
     *   text('100', width, guideY);
     *
     *   // Draw the normalized value
     *   textAlign(LEFT);
     *   fill(0);
     *   textSize(32);
     *   let normalY = 40;
     *   let normalX = 20;
     *   text(normalized, normalX, normalY);
     * }
     */
    exports.norm = function (n, start, stop) {
    	return this.map(n, start, stop, 0, 1);
    };

    /**
     * Facilitates exponential expressions. The pow() function is an efficient
     * way of multiplying numbers by themselves (or their reciprocals) in large
     * quantities. For example, pow(3, 5) is equivalent to the expression
     * 3*3*3*3*3 and pow(3, -5) is equivalent to 1 / 3*3*3*3*3. Maps to
     * Math.pow().
     *
     * @method pow
     * @param  {Number} n base of the exponential expression
     * @param  {Number} e power by which to raise the base
     * @return {Number}   n^e
     * @example
     * function setup() {
     *   //Exponentially increase the size of an ellipse.
     *   let eSize = 3; // Original Size
     *   let eLoc = 10; // Original Location
     *
     *   ellipse(eLoc, eLoc, eSize, eSize);
     *
     *   ellipse(eLoc * 2, eLoc * 2, pow(eSize, 2), pow(eSize, 2));
     *
     *   ellipse(eLoc * 4, eLoc * 4, pow(eSize, 3), pow(eSize, 3));
     *
     *   ellipse(eLoc * 8, eLoc * 8, pow(eSize, 4), pow(eSize, 4));
     * }
     */
    exports.pow = Math.pow;

    /**
     * Calculates the integer closest to the n parameter. For example,
     * round(133.8) returns the value 134. Maps to Math.round().
     *
     * @method round
     * @param  {Number} n number to round
     * @return {Integer}  rounded number
     * @example
     * function draw() {
     *   background(200);
     *   //map, mouseX between 0 and 5.
     *   let ax = map(mouseX, 0, 100, 0, 5);
     *   let ay = 66;
     *
     *   // Round the mapped number.
     *   let bx = round(map(mouseX, 0, 100, 0, 5));
     *   let by = 33;
     *
     *   // Multiply the mapped numbers by 20 to more easily
     *   // see the changes.
     *   stroke(0);
     *   fill(0);
     *   line(0, ay, ax * 20, ay);
     *   line(0, by, bx * 20, by);
     *
     *   // Reformat the float returned by map and draw it.
     *   noStroke();
     *   text(nfc(ax, 2), ax, ay - 5);
     *   text(nfc(bx, 1), bx, by - 5);
     * }
     */
    exports.round = Math.round;

    /**
     * Squares a number (multiplies a number by itself). The result is always a
     * positive number, as multiplying two negative numbers always yields a
     * positive result. For example, -1 * -1 = 1.
     *
     * @method sq
     * @param  {Number} n number to square
     * @return {Number}   squared number
     * @example
     * function draw() {
     *   background(200);
     *   let eSize = 7;
     *   let x1 = map(mouseX, 0, width, 0, 10);
     *   let y1 = 80;
     *   let x2 = sq(x1);
     *   let y2 = 20;
     *
     *   // Draw the non-squared.
     *   line(0, y1, width, y1);
     *   ellipse(x1, y1, eSize, eSize);
     *
     *   // Draw the squared.
     *   line(0, y2, width, y2);
     *   ellipse(x2, y2, eSize, eSize);
     *
     *   // Draw dividing line.
     *   stroke(100);
     *   line(0, height / 2, width, height / 2);
     *
     *   // Draw text.
     *   let spacing = 15;
     *   noStroke();
     *   fill(0);
     *   text('x = ' + x1, 0, y1 + spacing);
     *   text('sq(x) = ' + x2, 0, y2 + spacing);
     * }
     */
    exports.sq = function (n) {
    	return n * n;
    };

    /**
     * Calculates the square root of a number. The square root of a number is
     * always positive, even though there may be a valid negative root. The
     * square root s of number a is such that s*s = a. It is the opposite of
     * squaring. Maps to Math.sqrt().
     *
     * @method sqrt
     * @param  {Number} n non-negative number to square root
     * @return {Number}   square root of number
     * @example
     * function draw() {
     *   background(200);
     *   let eSize = 7;
     *   let x1 = mouseX;
     *   let y1 = 80;
     *   let x2 = sqrt(x1);
     *   let y2 = 20;
     *
     *   // Draw the non-squared.
     *   line(0, y1, width, y1);
     *   ellipse(x1, y1, eSize, eSize);
     *
     *   // Draw the squared.
     *   line(0, y2, width, y2);
     *   ellipse(x2, y2, eSize, eSize);
     *
     *   // Draw dividing line.
     *   stroke(100);
     *   line(0, height / 2, width, height / 2);
     *
     *   // Draw text.
     *   noStroke();
     *   fill(0);
     *   let spacing = 15;
     *   text('x = ' + x1, 0, y1 + spacing);
     *   text('sqrt(x) = ' + x2, 0, y2 + spacing);
     * }
     */
    exports.sqrt = Math.sqrt;

    // Calculate the length of the hypotenuse of a right triangle
    // This won't under- or overflow in intermediate steps
    // https://en.wikipedia.org/wiki/Hypot
    function hypot(x, y, z) {
    	// Use the native implementation if it's available
    	if (typeof Math.hypot === 'function') {
    		return Math.hypot.apply(null, arguments);
    	}

    	// Otherwise use the V8 implementation
    	// https://github.com/v8/v8/blob/8cd3cf297287e581a49e487067f5cbd991b27123/src/js/math.js#L217
    	var length = arguments.length;
    	var args = [];
    	var max = 0;
    	for (var i = 0; i < length; i++) {
    		var n = arguments[i];
    		n = +n;
    		if (n === Infinity || n === -Infinity) {
    			return Infinity;
    		}
    		n = Math.abs(n);
    		if (n > max) {
    			max = n;
    		}
    		args[i] = n;
    	}

    	if (max === 0) {
    		max = 1;
    	}
    	var sum = 0;
    	var compensation = 0;
    	for (var j = 0; j < length; j++) {
    		var m = args[j] / max;
    		var summand = m * m - compensation;
    		var preliminary = sum + summand;
    		compensation = preliminary - sum - summand;
    		sum = preliminary;
    	}
    	return Math.sqrt(sum) * max;
    }

    /**********************************************************************************************************************
     * Random
     */

    var seeded = false;
    var previous = false;
    var y2 = 0;

    // Linear Congruential Generator
    // Variant of a Lehman Generator
    var lcg = (function () {
    	// Set to values from http://en.wikipedia.org/wiki/Numerical_Recipes
    	// m is basically chosen to be large (as it is the max period)
    	// and for its relationships to a and c
    	var m = 4294967296,
    		// a - 1 should be divisible by m's prime factors
    		a = 1664525,
    		// c and m should be co-prime
    		c = 1013904223,
    		seed,
    		z;
    	return {
    		setSeed: function (val) {
    			// pick a random seed if val is undefined or null
    			// the >>> 0 casts the seed to an unsigned 32-bit integer
    			z = seed = (val == null ? Math.random() * m : val) >>> 0;
    		},
    		getSeed: function () {
    			return seed;
    		},
    		rand: function () {
    			// define the recurrence relationship
    			z = (a * z + c) % m;
    			// return a float in [0, 1)
    			// if z = m then z / m = 0 therefore (z % m) / m < 1 always
    			return z / m;
    		}
    	};
    })();

    /**
     * Sets the seed value for random().
     *
     * By default, random() produces different results each time the program
     * is run. Set the seed parameter to a constant to return the same
     * pseudo-random numbers each time the software is run.
     *
     * @method randomSeed
     * @param {Number} seed   the seed value
     * @example
     * randomSeed(99);
     * for (let i = 0; i < 100; i++) {
     *   let r = random(0, 255);
     *   stroke(r);
     *   line(i, 0, i, 100);
     * }
     */
    exports.randomSeed = function (seed) {
    	lcg.setSeed(seed);
    	seeded = true;
    	previous = false;
    };

    /**
     * Return a random floating-point number.
     *
     * Takes either 0, 1 or 2 arguments.
     *
     * If no argument is given, returns a random number from 0
     * up to (but not including) 1.
     *
     * If one argument is given and it is a number, returns a random number from 0
     * up to (but not including) the number.
     *
     * If one argument is given and it is an array, returns a random element from
     * that array.
     *
     * If two arguments are given, returns a random number from the
     * first argument up to (but not including) the second argument.
     *
     * @method random
     * @param  {Number} [min]   the lower bound (inclusive)
     * @param  {Number} [max]   the upper bound (exclusive)
     * @return {Number} the random number
     * @example
     * for (let i = 0; i < 100; i++) {
     *   let r = random(50);
     *   stroke(r * 5);
     *   line(50, i, 50 + r, i);
     * }
     *
     * for (let i = 0; i < 100; i++) {
     *   let r = random(-50, 50);
     *   line(50, i, 50 + r, i);
     * }
     *
     * // Get a random element from an array using the random(Array) syntax
     * let words = ['apple', 'bear', 'cat', 'dog'];
     * let word = random(words); // select random word
     * text(word, 10, 50); // draw the word
     */
    exports.random = function (min, max) {
    	var rand;

    	if (seeded) {
    		rand = lcg.rand();
    	} else {
    		rand = Math.random();
    	}
    	if (typeof min === 'undefined') {
    		return rand;
    	} else if (typeof max === 'undefined') {
    		if (min instanceof Array) {
    			return min[Math.floor(rand * min.length)];
    		} else {
    			return rand * min;
    		}
    	} else {
    		if (min > max) {
    			var tmp = min;
    			min = max;
    			max = tmp;
    		}

    		return rand * (max - min) + min;
    	}
    };

    /**
     *
     * Returns a random number fitting a Gaussian, or
     * normal, distribution. There is theoretically no minimum or maximum
     * value that randomGaussian() might return. Rather, there is
     * just a very low probability that values far from the mean will be
     * returned; and a higher probability that numbers near the mean will
     * be returned.
     * <br><br>
     * Takes either 0, 1 or 2 arguments.<br>
     * If no args, returns a mean of 0 and standard deviation of 1.<br>
     * If one arg, that arg is the mean (standard deviation is 1).<br>
     * If two args, first is mean, second is standard deviation.
     *
     * @method randomGaussian
     * @param  {Number} mean  the mean
     * @param  {Number} sd    the standard deviation
     * @return {Number} the random number
     * @example
     * for (let y = 0; y < 100; y++) {
     *   let x = randomGaussian(50, 15);
     *   line(50, y, x, y);
     * }
     *
     * let distribution = new Array(360);
     *
     * function setup() {
     *   createCanvas(100, 100);
     *   for (let i = 0; i < distribution.length; i++) {
     *     distribution[i] = floor(randomGaussian(0, 15));
     *   }
     * }
     *
     * function draw() {
     *   background(204);
     *
     *   translate(width / 2, width / 2);
     *
     *   for (let i = 0; i < distribution.length; i++) {
     *     rotate(TWO_PI / distribution.length);
     *     stroke(0);
     *     let dist = abs(distribution[i]);
     *     line(0, 0, dist, 0);
     *   }
     * }
     */
    exports.randomGaussian = function (mean, sd) {
    	var y1, x1, x2, w;
    	if (previous) {
    		y1 = y2;
    		previous = false;
    	} else {
    		do {
    			x1 = this.random(2) - 1;
    			x2 = this.random(2) - 1;
    			w = x1 * x1 + x2 * x2;
    		} while (w >= 1);
    		w = Math.sqrt(-2 * Math.log(w) / w);
    		y1 = x1 * w;
    		y2 = x2 * w;
    		previous = true;
    	}

    	var m = mean || 0;
    	var s = sd || 1;
    	return y1 * s + m;
    };

    /**********************************************************************************************************************
     * noise
     */

    var PERLIN_YWRAPB = 4;
    var PERLIN_YWRAP = 1 << PERLIN_YWRAPB;
    var PERLIN_ZWRAPB = 8;
    var PERLIN_ZWRAP = 1 << PERLIN_ZWRAPB;
    var PERLIN_SIZE = 4095;

    var perlin_octaves = 4; // default to medium smooth
    var perlin_amp_falloff = 0.5; // 50% reduction/octave

    var scaled_cosine = function (i) {
    	return 0.5 * (1.0 - Math.cos(i * Math.PI));
    };

    var perlin; // will be initialized lazily by noise() or noiseSeed()

    /**
     * Returns the Perlin noise value at specified coordinates. Perlin noise is
     * a random sequence generator producing a more natural ordered, harmonic
     * succession of numbers compared to the standard <b>random()</b> function.
     * It was invented by Ken Perlin in the 1980s and been used since in
     * graphical applications to produce procedural textures, natural motion,
     * shapes, terrains etc.<br /><br /> The main difference to the
     * <b>random()</b> function is that Perlin noise is defined in an infinite
     * n-dimensional space where each pair of coordinates corresponds to a
     * fixed semi-random value (fixed only for the lifespan of the program; see
     * the noiseSeed() function). p5.js can compute 1D, 2D and 3D noise,
     * depending on the number of coordinates given. The resulting value will
     * always be between 0.0 and 1.0. The noise value can be animated by moving
     * through the noise space as demonstrated in the example above. The 2nd
     * and 3rd dimension can also be interpreted as time.<br /><br />The actual
     * noise is structured similar to an audio signal, in respect to the
     * function's use of frequencies. Similar to the concept of harmonics in
     * physics, perlin noise is computed over several octaves which are added
     * together for the final result. <br /><br />Another way to adjust the
     * character of the resulting sequence is the scale of the input
     * coordinates. As the function works within an infinite space the value of
     * the coordinates doesn't matter as such, only the distance between
     * successive coordinates does (eg. when using <b>noise()</b> within a
     * loop). As a general rule the smaller the difference between coordinates,
     * the smoother the resulting noise sequence will be. Steps of 0.005-0.03
     * work best for most applications, but this will differ depending on use.
     *
     *
     * @method noise
     * @param  {Number} x   x-coordinate in noise space
     * @param  {Number} [y] y-coordinate in noise space
     * @param  {Number} [z] z-coordinate in noise space
     * @return {Number}     Perlin noise value (between 0 and 1) at specified
     *                      coordinates
     * @example
     * let xoff = 0.0;
     *
     * function draw() {
     *   background(204);
     *   xoff = xoff + 0.01;
     *   let n = noise(xoff) * width;
     *   line(n, 0, n, height);
     * }
     *
     * let noiseScale=0.02;
     *
     * function draw() {
     *   background(0);
     *   for (let x=0; x < width; x++) {
     *     let noiseVal = noise((mouseX+x)*noiseScale, mouseY*noiseScale);
     *     stroke(noiseVal*255);
     *     line(x, mouseY+noiseVal*80, x, height);
     *   }
     * }
     */
    exports.noise = function (x, y, z) {
    	y = y || 0;
    	z = z || 0;

    	if (perlin == null) {
    		perlin = new Array(PERLIN_SIZE + 1);
    		for (var i = 0; i < PERLIN_SIZE + 1; i++) {
    			perlin[i] = Math.random();
    		}
    	}

    	if (x < 0) {
    		x = -x;
    	}
    	if (y < 0) {
    		y = -y;
    	}
    	if (z < 0) {
    		z = -z;
    	}

    	var xi = Math.floor(x),
    		yi = Math.floor(y),
    		zi = Math.floor(z);
    	var xf = x - xi;
    	var yf = y - yi;
    	var zf = z - zi;
    	var rxf, ryf;

    	var r = 0;
    	var ampl = 0.5;

    	var n1, n2, n3;

    	for (var o = 0; o < perlin_octaves; o++) {
    		var of = xi + (yi << PERLIN_YWRAPB) + (zi << PERLIN_ZWRAPB);

    		rxf = scaled_cosine(xf);
    		ryf = scaled_cosine(yf);

    		n1 = perlin[of & PERLIN_SIZE];
    		n1 += rxf * (perlin[(of + 1) & PERLIN_SIZE] - n1);
    		n2 = perlin[(of + PERLIN_YWRAP) & PERLIN_SIZE];
    		n2 += rxf * (perlin[(of + PERLIN_YWRAP + 1) & PERLIN_SIZE] - n2);
    		n1 += ryf * (n2 - n1);

    		of += PERLIN_ZWRAP;
    		n2 = perlin[of & PERLIN_SIZE];
    		n2 += rxf * (perlin[(of + 1) & PERLIN_SIZE] - n2);
    		n3 = perlin[(of + PERLIN_YWRAP) & PERLIN_SIZE];
    		n3 += rxf * (perlin[(of + PERLIN_YWRAP + 1) & PERLIN_SIZE] - n3);
    		n2 += ryf * (n3 - n2);

    		n1 += scaled_cosine(zf) * (n2 - n1);

    		r += n1 * ampl;
    		ampl *= perlin_amp_falloff;
    		xi <<= 1;
    		xf *= 2;
    		yi <<= 1;
    		yf *= 2;
    		zi <<= 1;
    		zf *= 2;

    		if (xf >= 1.0) {
    			xi++;
    			xf--;
    		}
    		if (yf >= 1.0) {
    			yi++;
    			yf--;
    		}
    		if (zf >= 1.0) {
    			zi++;
    			zf--;
    		}
    	}
    	return r;
    };

    exports.noiseDetail = function (lod, falloff) {
    	if (lod > 0) {
    		perlin_octaves = lod;
    	}
    	if (falloff > 0) {
    		perlin_amp_falloff = falloff;
    	}
    };

    /**
     *
     * Adjusts the character and level of detail produced by the Perlin noise
     * function. Similar to harmonics in physics, noise is computed over
     * several octaves. Lower octaves contribute more to the output signal and
     * as such define the overall intensity of the noise, whereas higher octaves
     * create finer grained details in the noise sequence.
     * <br><br>
     * By default, noise is computed over 4 octaves with each octave contributing
     * exactly half than its predecessor, starting at 50% strength for the 1st
     * octave. This falloff amount can be changed by adding an additional function
     * parameter. Eg. a falloff factor of 0.75 means each octave will now have
     * 75% impact (25% less) of the previous lower octave. Any value between
     * 0.0 and 1.0 is valid, however note that values greater than 0.5 might
     * result in greater than 1.0 values returned by <b>noise()</b>.
     * <br><br>
     * By changing these parameters, the signal created by the <b>noise()</b>
     * function can be adapted to fit very specific needs and characteristics.
     *
     * @method noiseDetail
     * @param {Number} lod number of octaves to be used by the noise
     * @param {Number} falloff falloff factor for each octave
     * @example
     * let noiseVal;
     * let noiseScale = 0.02;
     *
     * function setup() {
     *   createCanvas(100, 100);
     * }
     *
     * function draw() {
     *   background(0);
     *   for (let y = 0; y < height; y++) {
     *     for (let x = 0; x < width / 2; x++) {
     *       noiseDetail(2, 0.2);
     *       noiseVal = noise((mouseX + x) * noiseScale, (mouseY + y) * noiseScale);
     *       stroke(noiseVal * 255);
     *       point(x, y);
     *       noiseDetail(8, 0.65);
     *       noiseVal = noise(
     *         (mouseX + x + width / 2) * noiseScale,
     *         (mouseY + y) * noiseScale
     *       );
     *       stroke(noiseVal * 255);
     *       point(x + width / 2, y);
     *     }
     *   }
     * }
     */
    exports.noiseSeed = function (seed) {
    	// Linear Congruential Generator
    	// Variant of a Lehman Generator
    	var lcg = (function () {
    		// Set to values from http://en.wikipedia.org/wiki/Numerical_Recipes
    		// m is basically chosen to be large (as it is the max period)
    		// and for its relationships to a and c
    		var m = 4294967296;
    		// a - 1 should be divisible by m's prime factors
    		var a = 1664525;
    		// c and m should be co-prime
    		var c = 1013904223;
    		var seed, z;
    		return {
    			setSeed: function (val) {
    				// pick a random seed if val is undefined or null
    				// the >>> 0 casts the seed to an unsigned 32-bit integer
    				z = seed = (val == null ? Math.random() * m : val) >>> 0;
    			},
    			getSeed: function () {
    				return seed;
    			},
    			rand: function () {
    				// define the recurrence relationship
    				z = (a * z + c) % m;
    				// return a float in [0, 1)
    				// if z = m then z / m = 0 therefore (z % m) / m < 1 always
    				return z / m;
    			}
    		};
    	})();

    	lcg.setSeed(seed);
    	perlin = new Array(PERLIN_SIZE + 1);
    	for (var i = 0; i < PERLIN_SIZE + 1; i++) {
    		perlin[i] = lcg.rand();
    	}
    };

    /**********************************************************************************************************************
     * trigonometry
     */

    /*
     * all DEGREES/RADIANS conversion should be done in the p5 instance
     * if possible, using the p5._toRadians(), p5._fromRadians() methods.
     */
    var _angleMode = RADIANS;

    /**
     * The inverse of cos(), returns the arc cosine of a value. This function
     * expects the values in the range of -1 to 1 and values are returned in
     * the range 0 to PI (3.1415927).
     *
     * @method acos
     * @param  {Number} value the value whose arc cosine is to be returned
     * @return {Number}       the arc cosine of the given value
     *
     * @example
     * let a = PI;
     * let c = cos(a);
     * let ac = acos(c);
     * // Prints: "3.1415927 : -1.0 : 3.1415927"
     * print(a + ' : ' + c + ' : ' + ac);
     *
     * let a = PI + PI / 4.0;
     * let c = cos(a);
     * let ac = acos(c);
     * // Prints: "3.926991 : -0.70710665 : 2.3561943"
     * print(a + ' : ' + c + ' : ' + ac);
     */
    exports.acos = function (ratio) {
    	return _fromRadians(Math.acos(ratio));
    };

    /**
     * The inverse of sin(), returns the arc sine of a value. This function
     * expects the values in the range of -1 to 1 and values are returned
     * in the range -PI/2 to PI/2.
     *
     * @method asin
     * @param  {Number} value the value whose arc sine is to be returned
     * @return {Number}       the arc sine of the given value
     *
     * @example
     * let a = PI + PI / 3;
     * let s = sin(a);
     * let as = asin(s);
     * // Prints: "1.0471976 : 0.86602545 : 1.0471976"
     * print(a + ' : ' + s + ' : ' + as);
     *
     * let a = PI + PI / 3.0;
     * let s = sin(a);
     * let as = asin(s);
     * // Prints: "4.1887903 : -0.86602545 : -1.0471976"
     * print(a + ' : ' + s + ' : ' + as);
     *
     */
    exports.asin = function (ratio) {
    	return _fromRadians(Math.asin(ratio));
    };

    /**
     * The inverse of tan(), returns the arc tangent of a value. This function
     * expects the values in the range of -Infinity to Infinity (exclusive) and
     * values are returned in the range -PI/2 to PI/2.
     *
     * @method atan
     * @param  {Number} value the value whose arc tangent is to be returned
     * @return {Number}       the arc tangent of the given value
     *
     * @example
     * let a = PI + PI / 3;
     * let t = tan(a);
     * let at = atan(t);
     * // Prints: "1.0471976 : 1.7320509 : 1.0471976"
     * print(a + ' : ' + t + ' : ' + at);
     *
     * let a = PI + PI / 3.0;
     * let t = tan(a);
     * let at = atan(t);
     * // Prints: "4.1887903 : 1.7320513 : 1.0471977"
     * print(a + ' : ' + t + ' : ' + at);
     *
     */
    exports.atan = function (ratio) {
    	return _fromRadians(Math.atan(ratio));
    };

    /**
     * Calculates the angle (in radians) from a specified point to the coordinate
     * origin as measured from the positive x-axis. Values are returned as a
     * float in the range from PI to -PI. The atan2() function is most often used
     * for orienting geometry to the position of the cursor.
     * <br><br>
     * Note: The y-coordinate of the point is the first parameter, and the
     * x-coordinate is the second parameter, due the the structure of calculating
     * the tangent.
     *
     * @method atan2
     * @param  {Number} y y-coordinate of the point
     * @param  {Number} x x-coordinate of the point
     * @return {Number}   the arc tangent of the given point
     *
     * @example
     * function draw() {
     *   background(204);
     *   translate(width / 2, height / 2);
     *   let a = atan2(mouseY - height / 2, mouseX - width / 2);
     *   rotate(a);
     *   rect(-30, -5, 60, 10);
     * }
     */
    exports.atan2 = function (y, x) {
    	return _fromRadians(Math.atan2(y, x));
    };

    /**
     * Calculates the cosine of an angle. This function takes into account the
     * current angleMode. Values are returned in the range -1 to 1.
     *
     * @method cos
     * @param  {Number} angle the angle
     * @return {Number}       the cosine of the angle
     *
     * @example
     * let a = 0.0;
     * let inc = TWO_PI / 25.0;
     * for (let i = 0; i < 25; i++) {
     *   line(i * 4, 50, i * 4, 50 + cos(a) * 40.0);
     *   a = a + inc;
     * }
     */
    exports.cos = function (angle) {
    	return Math.cos(_toRadians(angle));
    };

    /**
     * Calculates the sine of an angle. This function takes into account the
     * current angleMode. Values are returned in the range -1 to 1.
     *
     * @method sin
     * @param  {Number} angle the angle
     * @return {Number}       the sine of the angle
     *
     * @example
     * let a = 0.0;
     * let inc = TWO_PI / 25.0;
     * for (let i = 0; i < 25; i++) {
     *   line(i * 4, 50, i * 4, 50 + sin(a) * 40.0);
     *   a = a + inc;
     * }
     */
    exports.sin = function (angle) {
    	return Math.sin(_toRadians(angle));
    };

    /**
     * Calculates the tangent of an angle. This function takes into account
     * the current angleMode. Values are returned in the range -1 to 1.
     *
     * @method tan
     * @param  {Number} angle the angle
     * @return {Number}       the tangent of the angle
     *
     * @example
     * let a = 0.0;
     * let inc = TWO_PI / 50.0;
     * for (let i = 0; i < 100; i = i + 2) {
     *   line(i, 50, i, 50 + tan(a) * 2.0);
     *   a = a + inc;
     * }
     */
    exports.tan = function (angle) {
    	return Math.tan(_toRadians(angle));
    };

    /**
     * Converts a radian measurement to its corresponding value in degrees.
     * Radians and degrees are two ways of measuring the same thing. There are
     * 360 degrees in a circle and 2*PI radians in a circle. For example,
     * 90° = PI/2 = 1.5707964. This function does not take into account the
     * current angleMode.
     *
     * @method degrees
     * @param  {Number} radians the radians value to convert to degrees
     * @return {Number}         the converted angle
     *
     *
     * @example
     * let rad = PI / 4;
     * let deg = degrees(rad);
     * print(rad + ' radians is ' + deg + ' degrees');
     * // Prints: 0.7853981633974483 radians is 45 degrees
     */
    exports.degrees = function (angle) {
    	return angle * RAD_TO_DEG;
    };

    /**
     * Converts a degree measurement to its corresponding value in radians.
     * Radians and degrees are two ways of measuring the same thing. There are
     * 360 degrees in a circle and 2*PI radians in a circle. For example,
     * 90° = PI/2 = 1.5707964. This function does not take into account the
     * current angleMode.
     *
     * @method radians
     * @param  {Number} degrees the degree value to convert to radians
     * @return {Number}         the converted angle
     *
     * @example
     * let deg = 45.0;
     * let rad = radians(deg);
     * print(deg + ' degrees is ' + rad + ' radians');
     * // Prints: 45 degrees is 0.7853981633974483 radians
     */
    exports.radians = function (angle) {
    	return angle * DEG_TO_RAD;
    };

    /**
     * Sets the current mode of p5 to given mode. Default mode is RADIANS.
     *
     * @method angleMode
     * @param {Constant} mode either RADIANS or DEGREES
     *
     * @example
     * function draw() {
     *   background(204);
     *   angleMode(DEGREES); // Change the mode to DEGREES
     *   let a = atan2(mouseY - height / 2, mouseX - width / 2);
     *   translate(width / 2, height / 2);
     *   push();
     *   rotate(a);
     *   rect(-20, -5, 40, 10); // Larger rectangle is rotating in degrees
     *   pop();
     *   angleMode(RADIANS); // Change the mode to RADIANS
     *   rotate(a); // variable a stays the same
     *   rect(-40, -5, 20, 10); // Smaller rectangle is rotating in radians
     * }
     */
    exports.angleMode = function (mode) {
    	if (mode === DEGREES || mode === RADIANS) {
    		_angleMode = mode;
    	}
    };

    /**
     * converts angles from the current angleMode to RADIANS
     *
     * @method _toRadians
     * @private
     * @param {Number} angle
     * @returns {Number}
     */
    exports._toRadians = function (angle) {
    	if (_angleMode === DEGREES) {
    		return angle * DEG_TO_RAD;
    	}
    	return angle;
    };

    /**
     * converts angles from the current angleMode to DEGREES
     *
     * @method _toDegrees
     * @private
     * @param {Number} angle
     * @returns {Number}
     */
    exports._toDegrees = function (angle) {
    	if (_angleMode === RADIANS) {
    		return angle * RAD_TO_DEG;
    	}
    	return angle;
    };

    /**
     * converts angles from RADIANS into the current angleMode
     *
     * @method _fromRadians
     * @private
     * @param {Number} angle
     * @returns {Number}
     */
    exports._fromRadians = function (angle) {
    	if (_angleMode === DEGREES) {
    		return angle * RAD_TO_DEG;
    	}
    	return angle;
    };