    /*
    	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
    */

    /**********************************************************************************************************************
     * array functions
     */

    /**
     * Adds a value to the end of an array. Extends the length of
     * the array by one. Maps to Array.push().
     *
     * @method append
     * @param {Array} array Array to append
     * @param {any} value to be added to the Array
     * @return {Array} the array that was appended to
     * @example
     * function setup() {
     *   var myArray = ['Mango', 'Apple', 'Papaya'];
     *   print(myArray); // ['Mango', 'Apple', 'Papaya']
     *
     *   append(myArray, 'Peach');
     *   print(myArray); // ['Mango', 'Apple', 'Papaya', 'Peach']
     * }
     */
    exports.append = function (array, value) {
    	array.push(value);
    	return array;
    };

    /**
     * Copies an array (or part of an array) to another array. The src array is
     * copied to the dst array, beginning at the position specified by
     * srcPosition and into the position specified by dstPosition. The number of
     * elements to copy is determined by length. Note that copying values
     * overwrites existing values in the destination array. To append values
     * instead of overwriting them, use concat().
     * <br><br>
     * The simplified version with only two arguments, arrayCopy(src, dst),
     * copies an entire array to another of the same size. It is equivalent to
     * arrayCopy(src, 0, dst, 0, src.length).
     * <br><br>
     * Using this function is far more efficient for copying array data than
     * iterating through a for() loop and copying each element individually.
     *
     * @method arrayCopy
     * @deprecated
     * @param {Array}  src           the source Array
     * @param {Integer} srcPosition  starting position in the source Array
     * @param {Array}  dst           the destination Array
     * @param {Integer} dstPosition   starting position in the destination Array
     * @param {Integer} length        number of Array elements to be copied
     *
     * @example
     * var src = ['A', 'B', 'C'];
     * var dst = [1, 2, 3];
     * var srcPosition = 1;
     * var dstPosition = 0;
     * var length = 2;
     *
     * print(src); // ['A', 'B', 'C']
     * print(dst); // [ 1 ,  2 ,  3 ]
     *
     * arrayCopy(src, srcPosition, dst, dstPosition, length);
     * print(dst); // ['B', 'C', 3]
     */
    exports.arrayCopy = function (src, srcPosition, dst, dstPosition, length) {
    	// the index to begin splicing from dst array
    	var start;
    	var end;

    	if (typeof length !== 'undefined') {
    		end = Math.min(length, src.length);
    		start = dstPosition;
    		src = src.slice(srcPosition, end + srcPosition);
    	} else {
    		if (typeof dst !== 'undefined') {
    			// src, dst, length
    			// rename  so we don't get confused
    			end = dst;
    			end = Math.min(end, src.length);
    		} else {
    			// src, dst
    			end = src.length;
    		}

    		start = 0;
    		// rename  so we don't get confused
    		dst = srcPosition;
    		src = src.slice(0, end);
    	}

    	// Since we are not returning the array and JavaScript is pass by reference
    	// we must modify the actual values of the array
    	// instead of reassigning arrays
    	Array.prototype.splice.apply(dst, [start, end].concat(src));
    };

    /**
     * Concatenates two arrays, maps to Array.concat(). Does not modify the
     * input arrays.
     *
     * @method concat
     * @param {Array} a first Array to concatenate
     * @param {Array} b second Array to concatenate
     * @return {Array} concatenated array
     *
     * @example
     * function setup() {
     *   var arr1 = ['A', 'B', 'C'];
     *   var arr2 = [1, 2, 3];
     *
     *   print(arr1); // ['A','B','C']
     *   print(arr2); // [1,2,3]
     *
     *   var arr3 = concat(arr1, arr2);
     *
     *   print(arr1); // ['A','B','C']
     *   print(arr2); // [1, 2, 3]
     *   print(arr3); // ['A','B','C', 1, 2, 3]
     * }
     */
    exports.concat = function (list0, list1) {
    	return list0.concat(list1);
    };

    /**
     * Reverses the order of an array, maps to Array.reverse()
     *
     * @method reverse
     * @param {Array} list Array to reverse
     * @return {Array} the reversed list
     * @example
     * function setup() {
     *   var myArray = ['A', 'B', 'C'];
     *   print(myArray); // ['A','B','C']
     *
     *   reverse(myArray);
     *   print(myArray); // ['C','B','A']
     * }
     */
    exports.reverse = function (list) {
    	return list.reverse();
    };

    /**
     * Decreases an array by one element and returns the shortened array,
     * maps to Array.pop().
     *
     * @method shorten
     * @param  {Array} list Array to shorten
     * @return {Array} shortened Array
     * @example
     * function setup() {
     *   var myArray = ['A', 'B', 'C'];
     *   print(myArray); // ['A', 'B', 'C']
     *   var newArray = shorten(myArray);
     *   print(myArray); // ['A','B','C']
     *   print(newArray); // ['A','B']
     * }
     */
    exports.shorten = function (list) {
    	list.pop();
    	return list;
    };

    /**
     * Randomizes the order of the elements of an array. Implements
     * <a href='http://Bost.Ocks.org/mike/shuffle/' target=_blank>
     * Fisher-Yates Shuffle Algorithm</a>.
     *
     * @method shuffle
     * @param  {Array}   array  Array to shuffle
     * @param  {Boolean} [bool] modify passed array
     * @return {Array}   shuffled Array
     * @example
     * function setup() {
     *   var regularArr = ['ABC', 'def', createVector(), TAU, Math.E];
     *   print(regularArr);
     *   shuffle(regularArr, true); // force modifications to passed array
     *   print(regularArr);
     *
     *   // By default shuffle() returns a shuffled cloned array:
     *   var newArr = shuffle(regularArr);
     *   print(regularArr);
     *   print(newArr);
     * }
     */
    exports.shuffle = function (arr, bool) {
    	var isView = ArrayBuffer && ArrayBuffer.isView && ArrayBuffer.isView(arr);
    	arr = bool || isView ? arr : arr.slice();

    	var rnd,
    		tmp,
    		idx = arr.length;
    	while (idx > 1) {
    		rnd = (Math.random() * idx) | 0;

    		tmp = arr[--idx];
    		arr[idx] = arr[rnd];
    		arr[rnd] = tmp;
    	}

    	return arr;
    };

    /**
     * Sorts an array of numbers from smallest to largest, or puts an array of
     * words in alphabetical order. The original array is not modified; a
     * re-ordered array is returned. The count parameter states the number of
     * elements to sort. For example, if there are 12 elements in an array and
     * count is set to 5, only the first 5 elements in the array will be sorted.
     *
     * @method sort
     * @param {Array} list Array to sort
     * @param {Integer} [count] number of elements to sort, starting from 0
     * @return {Array} the sorted list
     *
     * @example
     * function setup() {
     *   var words = ['banana', 'apple', 'pear', 'lime'];
     *   print(words); // ['banana', 'apple', 'pear', 'lime']
     *   var count = 4; // length of array
     *
     *   words = sort(words, count);
     *   print(words); // ['apple', 'banana', 'lime', 'pear']
     * }
     *
     * function setup() {
     *   var numbers = [2, 6, 1, 5, 14, 9, 8, 12];
     *   print(numbers); // [2, 6, 1, 5, 14, 9, 8, 12]
     *   var count = 5; // Less than the length of the array
     *
     *   numbers = sort(numbers, count);
     *   print(numbers); // [1,2,5,6,14,9,8,12]
     * }
     */
    exports.sort = function (list, count) {
    	var arr = count ? list.slice(0, Math.min(count, list.length)) : list;
    	var rest = count ? list.slice(Math.min(count, list.length)) : [];
    	if (typeof arr[0] === 'string') {
    		arr = arr.sort();
    	} else {
    		arr = arr.sort(function (a, b) {
    			return a - b;
    		});
    	}
    	return arr.concat(rest);
    };

    /**
     * Inserts a value or an array of values into an existing array. The first
     * parameter specifies the initial array to be modified, and the second
     * parameter defines the data to be inserted. The third parameter is an index
     * value which specifies the array position from which to insert data.
     * (Remember that array index numbering starts at zero, so the first position
     * is 0, the second position is 1, and so on.)
     *
     * @method splice
     * @param {Array}  list Array to splice into
     * @param {any}    value value to be spliced in
     * @param {Integer} position in the array from which to insert data
     * @return {Array} the list
     *
     * @example
     * function setup() {
     *   var myArray = [0, 1, 2, 3, 4];
     *   var insArray = ['A', 'B', 'C'];
     *   print(myArray); // [0, 1, 2, 3, 4]
     *   print(insArray); // ['A','B','C']
     *
     *   splice(myArray, insArray, 3);
     *   print(myArray); // [0,1,2,'A','B','C',3,4]
     * }
     */
    exports.splice = function (list, value, index) {
    	// note that splice returns spliced elements and not an array
    	Array.prototype.splice.apply(list, [index, 0].concat(value));

    	return list;
    };

    /**
     * Extracts an array of elements from an existing array. The list parameter
     * defines the array from which the elements will be copied, and the start
     * and count parameters specify which elements to extract. If no count is
     * given, elements will be extracted from the start to the end of the array.
     * When specifying the start, remember that the first array element is 0.
     * This function does not change the source array.
     *
     * @method subset
     * @param  {Array}  list    Array to extract from
     * @param  {Integer} start   position to begin
     * @param  {Integer} [count] number of values to extract
     * @return {Array}          Array of extracted elements
     *
     * @example
     * function setup() {
     *   var myArray = [1, 2, 3, 4, 5];
     *   print(myArray); // [1, 2, 3, 4, 5]
     *
     *   var sub1 = subset(myArray, 0, 3);
     *   var sub2 = subset(myArray, 2, 2);
     *   print(sub1); // [1,2,3]
     *   print(sub2); // [3,4]
     * }
     */
    exports.subset = function (list, start, count) {
    	if (typeof count !== 'undefined') {
    		return list.slice(start, start + count);
    	} else {
    		return list.slice(start, list.length);
    	}
    };

    /**********************************************************************************************************************
     * conversion functions
     */

    /**
     * Converts a string to its floating point representation. The contents of a
     * string must resemble a number, or NaN (not a number) will be returned.
     * For example, float("1234.56") evaluates to 1234.56, but float("giraffe")
     * will return NaN.
     *
     * When an array of values is passed in, then an array of floats of the same
     * length is returned.
     *
     * @method float
     * @param {String}  str float string to parse
     * @return {Number}     floating point representation of string
     * @example
     * var str = '20';
     * var diameter = float(str);
     * ellipse(width / 2, height / 2, diameter, diameter);
     */
    exports.float = function (str) {
    	if (str instanceof Array) {
    		return str.map(parseFloat);
    	}
    	return parseFloat(str);
    };

    /**
     * Converts a boolean, string, or float to its integer representation.
     * When an array of values is passed in, then an int array of the same length
     * is returned.
     *
     * @method int
     * @param {String|Boolean|Number}       n value to parse
     * @param {Integer}       [radix] the radix to convert to (default: 10)
     * @return {Number}                     integer representation of value
     *
     * @example
     * print(int('10')); // 10
     * print(int(10.31)); // 10
     * print(int(-10)); // -10
     * print(int(true)); // 1
     * print(int(false)); // 0
     * print(int([false, true, '10.3', 9.8])); // [0, 1, 10, 9]
     */
    exports.int = function (n, radix) {
    	radix = radix || 10;
    	if (typeof n === 'string') {
    		return parseInt(n, radix);
    	} else if (typeof n === 'number') {
    		return n | 0;
    	} else if (typeof n === 'boolean') {
    		return n ? 1 : 0;
    	} else if (n instanceof Array) {
    		return n.map(function (n) {
    			return exports.int(n, radix);
    		});
    	}
    };

    /**
     * Converts a boolean, string or number to its string representation.
     * When an array of values is passed in, then an array of strings of the same
     * length is returned.
     *
     * @method str
     * @param {String|Boolean|Number|Array} n value to parse
     * @return {String}                     string representation of value
     * @example
     * print(str('10')); // "10"
     * print(str(10.31)); // "10.31"
     * print(str(-10)); // "-10"
     * print(str(true)); // "true"
     * print(str(false)); // "false"
     * print(str([true, '10.3', 9.8])); // [ "true", "10.3", "9.8" ]
     */
    exports.str = function (n) {
    	if (n instanceof Array) {
    		return n.map(exports.str);
    	} else {
    		return String(n);
    	}
    };

    /**
     * Converts a number or string to its boolean representation.
     * For a number, any non-zero value (positive or negative) evaluates to true,
     * while zero evaluates to false. For a string, the value "true" evaluates to
     * true, while any other value evaluates to false. When an array of number or
     * string values is passed in, then a array of booleans of the same length is
     * returned.
     *
     * @method boolean
     * @param {String|Boolean|Number|Array} n value to parse
     * @return {Boolean}                    boolean representation of value
     * @example
     * print(boolean(0)); // false
     * print(boolean(1)); // true
     * print(boolean('true')); // true
     * print(boolean('abcd')); // false
     * print(boolean([0, 12, 'true'])); // [false, true, false]
     */
    exports.boolean = function (n) {
    	if (typeof n === 'number') {
    		return n !== 0;
    	} else if (typeof n === 'string') {
    		return n.toLowerCase() === 'true';
    	} else if (typeof n === 'boolean') {
    		return n;
    	} else if (n instanceof Array) {
    		return n.map(exports.boolean);
    	}
    };

    /**
     * Converts a number, string representation of a number, or boolean to its byte
     * representation. A byte can be only a whole number between -128 and 127, so
     * when a value outside of this range is converted, it wraps around to the
     * corresponding byte representation. When an array of number, string or boolean
     * values is passed in, then an array of bytes the same length is returned.
     *
     * @method byte
     * @param {String|Boolean|Number}       n value to parse
     * @return {Number}                     byte representation of value
     *
     * @example
     * print(byte(127)); // 127
     * print(byte(128)); // -128
     * print(byte(23.4)); // 23
     * print(byte('23.4')); // 23
     * print(byte('hello')); // NaN
     * print(byte(true)); // 1
     * print(byte([0, 255, '100'])); // [0, -1, 100]
     */
    exports.byte = function (n) {
    	var nn = exports.int(n, 10);
    	if (typeof nn === 'number') {
    		return (nn + 128) % 256 - 128;
    	} else if (nn instanceof Array) {
    		return nn.map(exports.byte);
    	}
    };

    /**
     * Converts a number or string to its corresponding single-character
     * string representation. If a string parameter is provided, it is first
     * parsed as an integer and then translated into a single-character string.
     * When an array of number or string values is passed in, then an array of
     * single-character strings of the same length is returned.
     *
     * @method char
     * @param {String|Number}       n value to parse
     * @return {String}             string representation of value
     *
     * @example
     * print(char(65)); // "A"
     * print(char('65')); // "A"
     * print(char([65, 66, 67])); // [ "A", "B", "C" ]
     * print(join(char([65, 66, 67]), '')); // "ABC"
     */
    exports.char = function (n) {
    	if (typeof n === 'number' && !isNaN(n)) {
    		return String.fromCharCode(n);
    	} else if (n instanceof Array) {
    		return n.map(exports.char);
    	} else if (typeof n === 'string') {
    		return exports.char(parseInt(n, 10));
    	}
    };

    /**
     * Converts a single-character string to its corresponding integer
     * representation. When an array of single-character string values is passed
     * in, then an array of integers of the same length is returned.
     *
     * @method unchar
     * @param {String} n     value to parse
     * @return {Number}      integer representation of value
     *
     * @example
     * print(unchar('A')); // 65
     * print(unchar(['A', 'B', 'C'])); // [ 65, 66, 67 ]
     * print(unchar(split('ABC', ''))); // [ 65, 66, 67 ]
     */
    exports.unchar = function (n) {
    	if (typeof n === 'string' && n.length === 1) {
    		return n.charCodeAt(0);
    	} else if (n instanceof Array) {
    		return n.map(exports.unchar);
    	}
    };

    /**
     * Converts a number to a string in its equivalent hexadecimal notation. If a
     * second parameter is passed, it is used to set the number of characters to
     * generate in the hexadecimal notation. When an array is passed in, an
     * array of strings in hexadecimal notation of the same length is returned.
     *
     * @method hex
     * @param {Number} n     value to parse
     * @param {Number} [digits]
     * @return {String}      hexadecimal string representation of value
     *
     * @example
     * print(hex(255)); // "000000FF"
     * print(hex(255, 6)); // "0000FF"
     * print(hex([0, 127, 255], 6)); // [ "000000", "00007F", "0000FF" ]
     */
    exports.hex = function (n, digits) {
    	digits = digits === undefined || digits === null ? (digits = 8) : digits;
    	if (n instanceof Array) {
    		return n.map(function (n) {
    			return exports.hex(n, digits);
    		});
    	} else if (typeof n === 'number') {
    		if (n < 0) {
    			n = 0xffffffff + n + 1;
    		}
    		var hex = Number(n)
    			.toString(16)
    			.toUpperCase();
    		while (hex.length < digits) {
    			hex = '0' + hex;
    		}
    		if (hex.length >= digits) {
    			hex = hex.substring(hex.length - digits, hex.length);
    		}
    		return hex;
    	}
    };

    /**
     * Converts a string representation of a hexadecimal number to its equivalent
     * integer value. When an array of strings in hexadecimal notation is passed
     * in, an array of integers of the same length is returned.
     *
     * @method unhex
     * @param {String} n value to parse
     * @return {Number}      integer representation of hexadecimal value
     *
     * @example
     * print(unhex('A')); // 10
     * print(unhex('FF')); // 255
     * print(unhex(['FF', 'AA', '00'])); // [ 255, 170, 0 ]
     */
    exports.unhex = function (n) {
    	if (n instanceof Array) {
    		return n.map(exports.unhex);
    	} else {
    		return parseInt('0x' + n, 16);
    	}
    };

    /**********************************************************************************************************************
     * string functions
     */

    /**
     * Combines an array of Strings into one String, each separated by the
     * character(s) used for the separator parameter. To join arrays of ints or
     * floats, it's necessary to first convert them to Strings using nf() or
     * nfs().
     *
     * @method join
     * @param  {Array}  list      array of Strings to be joined
     * @param  {String} separator String to be placed between each item
     * @return {String}           joined String
     * @example
     * var array = ['Hello', 'world!'];
     * var separator = ' ';
     * var message = join(array, separator);
     * text(message, 5, 50);
     */
    exports.join = function (list, separator) {
    	p5._validateParameters('join', arguments);
    	return list.join(separator);
    };

    /**
     * This function is used to apply a regular expression to a piece of text,
     * and return matching groups (elements found inside parentheses) as a
     * String array. If there are no matches, a null value will be returned.
     * If no groups are specified in the regular expression, but the sequence
     * matches, an array of length 1 (with the matched text as the first element
     * of the array) will be returned.
     * <br><br>
     * To use the function, first check to see if the result is null. If the
     * result is null, then the sequence did not match at all. If the sequence
     * did match, an array is returned.
     * <br><br>
     * If there are groups (specified by sets of parentheses) in the regular
     * expression, then the contents of each will be returned in the array.
     * Element [0] of a regular expression match returns the entire matching
     * string, and the match groups start at element [1] (the first group is [1],
     * the second [2], and so on).
     *
     * @method match
     * @param  {String} str    the String to be searched
     * @param  {String} regexp the regexp to be used for matching
     * @return {String[]}      Array of Strings found
     * @example
     * var string = 'Hello p5js*!';
     * var regexp = 'p5js\\*';
     * var m = match(string, regexp);
     * text(m, 5, 50);
     */
    exports.match = function (str, reg) {
    	p5._validateParameters('match', arguments);
    	return str.match(reg);
    };

    /**
     * This function is used to apply a regular expression to a piece of text,
     * and return a list of matching groups (elements found inside parentheses)
     * as a two-dimensional String array. If there are no matches, a null value
     * will be returned. If no groups are specified in the regular expression,
     * but the sequence matches, a two dimensional array is still returned, but
     * the second dimension is only of length one.
     * <br><br>
     * To use the function, first check to see if the result is null. If the
     * result is null, then the sequence did not match at all. If the sequence
     * did match, a 2D array is returned.
     * <br><br>
     * If there are groups (specified by sets of parentheses) in the regular
     * expression, then the contents of each will be returned in the array.
     * Assuming a loop with counter variable i, element [i][0] of a regular
     * expression match returns the entire matching string, and the match groups
     * start at element [i][1] (the first group is [i][1], the second [i][2],
     * and so on).
     *
     * @method matchAll
     * @param  {String} str    the String to be searched
     * @param  {String} regexp the regexp to be used for matching
     * @return {String[]}         2d Array of Strings found
     * @example
     * var string = 'Hello p5js*! Hello world!';
     * var regexp = 'Hello';
     * matchAll(string, regexp);
     */
    exports.matchAll = function (str, reg) {
    	p5._validateParameters('matchAll', arguments);
    	var re = new RegExp(reg, 'g');
    	var match = re.exec(str);
    	var matches = [];
    	while (match !== null) {
    		matches.push(match);
    		// matched text: match[0]
    		// match start: match.index
    		// capturing group n: match[n]
    		match = re.exec(str);
    	}
    	return matches;
    };

    /**
     * Utility function for formatting numbers into strings. There are two
     * versions: one for formatting floats, and one for formatting ints.
     * The values for the digits, left, and right parameters should always
     * be positive integers.
     * (NOTE): Be cautious when using left and right parameters as it prepends numbers of 0's if the parameter
     * if greater than the current length of the number.
     * For example if number is 123.2 and left parameter passed is 4 which is greater than length of 123
     * (integer part) i.e 3 than result will be 0123.2. Same case for right parameter i.e. if right is 3 than
     * the result will be 123.200.
     *
     * @method nf
     * @param {Number|String}       num      the Number to format
     * @param {Integer|String}      [left]   number of digits to the left of the
     *                                decimal point
     * @param {Integer|String}      [right]  number of digits to the right of the
     *                                decimal point
     * @return {String}               formatted String
     *
     * @example
     * var myFont;
     * function preload() {
     *   myFont = loadFont('assets/fonts/inconsolata.ttf');
     * }
     * function setup() {
     *   background(200);
     *   var num1 = 321;
     *   var num2 = -1321;
     *
     *   noStroke();
     *   fill(0);
     *   textFont(myFont);
     *   textSize(22);
     *
     *   text(nf(num1, 4, 2), 10, 30);
     *   text(nf(num2, 4, 2), 10, 80);
     *   // Draw dividing line
     *   stroke(120);
     *   line(0, 50, width, 50);
     * }
     */
    exports.nf = function (nums, left, right) {
    	p5._validateParameters('nf', arguments);
    	if (nums instanceof Array) {
    		return nums.map(function (x) {
    			return doNf(x, left, right);
    		});
    	} else {
    		var typeOfFirst = Object.prototype.toString.call(nums);
    		if (typeOfFirst === '[object Arguments]') {
    			if (nums.length === 3) {
    				return this.nf(nums[0], nums[1], nums[2]);
    			} else if (nums.length === 2) {
    				return this.nf(nums[0], nums[1]);
    			} else {
    				return this.nf(nums[0]);
    			}
    		} else {
    			return doNf(nums, left, right);
    		}
    	}
    };

    function doNf(num, left, right) {
    	var neg = num < 0;
    	var n = neg ? num.toString().substring(1) : num.toString();
    	var decimalInd = n.indexOf('.');
    	var intPart = decimalInd !== -1 ? n.substring(0, decimalInd) : n;
    	var decPart = decimalInd !== -1 ? n.substring(decimalInd + 1) : '';
    	var str = neg ? '-' : '';
    	if (typeof right !== 'undefined') {
    		var decimal = '';
    		if (decimalInd !== -1 || right - decPart.length > 0) {
    			decimal = '.';
    		}
    		if (decPart.length > right) {
    			decPart = decPart.substring(0, right);
    		}
    		for (var i = 0; i < left - intPart.length; i++) {
    			str += '0';
    		}
    		str += intPart;
    		str += decimal;
    		str += decPart;
    		for (var j = 0; j < right - decPart.length; j++) {
    			str += '0';
    		}
    		return str;
    	} else {
    		for (var k = 0; k < Math.max(left - intPart.length, 0); k++) {
    			str += '0';
    		}
    		str += n;
    		return str;
    	}
    }

    /**
     * Utility function for formatting numbers into strings and placing
     * appropriate commas to mark units of 1000. There are two versions: one
     * for formatting ints, and one for formatting an array of ints. The value
     * for the right parameter should always be a positive integer.
     *
     * @method nfc
     * @param  {Number|String}   num     the Number to format
     * @param  {Integer|String}  [right] number of digits to the right of the
     *                                  decimal point
     * @return {String}           formatted String
     *
     * @example
     * function setup() {
     *   background(200);
     *   var num = 11253106.115;
     *   var numArr = [1, 1, 2];
     *
     *   noStroke();
     *   fill(0);
     *   textSize(12);
     *
     *   // Draw formatted numbers
     *   text(nfc(num, 4), 10, 30);
     *   text(nfc(numArr, 2), 10, 80);
     *
     *   // Draw dividing line
     *   stroke(120);
     *   line(0, 50, width, 50);
     * }
     */
    exports.nfc = function (num, right) {
    	p5._validateParameters('nfc', arguments);
    	if (num instanceof Array) {
    		return num.map(function (x) {
    			return doNfc(x, right);
    		});
    	} else {
    		return doNfc(num, right);
    	}
    };

    function doNfc(num, right) {
    	num = num.toString();
    	var dec = num.indexOf('.');
    	var rem = dec !== -1 ? num.substring(dec) : '';
    	var n = dec !== -1 ? num.substring(0, dec) : num;
    	n = n.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
    	if (right === 0) {
    		rem = '';
    	} else if (typeof right !== 'undefined') {
    		if (right > rem.length) {
    			rem += dec === -1 ? '.' : '';
    			var len = right - rem.length + 1;
    			for (var i = 0; i < len; i++) {
    				rem += '0';
    			}
    		} else {
    			rem = rem.substring(0, right + 1);
    		}
    	}
    	return n + rem;
    }

    /**
     * Utility function for formatting numbers into strings. Similar to nf() but
     * puts a "+" in front of positive numbers and a "-" in front of negative
     * numbers. There are two versions: one for formatting floats, and one for
     * formatting ints. The values for left, and right parameters
     * should always be positive integers.
     *
     * @method nfp
     * @param {Number} num      the Number to format
     * @param {Integer}      [left]   number of digits to the left of the decimal
     *                                point
     * @param {Integer}      [right]  number of digits to the right of the
     *                                decimal point
     * @return {String}         formatted String
     *
     * @example
     * function setup() {
     *   background(200);
     *   var num1 = 11253106.115;
     *   var num2 = -11253106.115;
     *
     *   noStroke();
     *   fill(0);
     *   textSize(12);
     *
     *   // Draw formatted numbers
     *   text(nfp(num1, 4, 2), 10, 30);
     *   text(nfp(num2, 4, 2), 10, 80);
     *
     *   // Draw dividing line
     *   stroke(120);
     *   line(0, 50, width, 50);
     * }
     */
    exports.nfp = function () {
    	p5._validateParameters('nfp', arguments);
    	var nfRes = exports.nf.apply(this, arguments);
    	if (nfRes instanceof Array) {
    		return nfRes.map(addNfp);
    	} else {
    		return addNfp(nfRes);
    	}
    };

    function addNfp(num) {
    	return parseFloat(num) > 0 ? '+' + num.toString() : num.toString();
    }

    /**
     * Utility function for formatting numbers into strings. Similar to nf() but
     * puts an additional "_" (space) in front of positive numbers just in case to align it with negative
     * numbers which includes "-" (minus) sign.
     * The main usecase of nfs() can be seen when one wants to align the digits (place values) of a positive
     * number with some negative number (See the example to get a clear picture).
     * There are two versions: one for formatting float, and one for formatting int.
     * The values for the digits, left, and right parameters should always be positive integers.
     * (IMP): The result on the canvas basically the expected alignment can vary based on the typeface you are using.
     * (NOTE): Be cautious when using left and right parameters as it prepends numbers of 0's if the parameter
     * if greater than the current length of the number.
     * For example if number is 123.2 and left parameter passed is 4 which is greater than length of 123
     * (integer part) i.e 3 than result will be 0123.2. Same case for right parameter i.e. if right is 3 than
     * the result will be 123.200.
     *
     * @method nfs
     * @param {Number}       num      the Number to format
     * @param {Integer}      [left]   number of digits to the left of the decimal
     *                                point
     * @param {Integer}      [right]  number of digits to the right of the
     *                                decimal point
     * @return {String}         formatted String
     *
     * @example
     * var myFont;
     * function preload() {
     *   myFont = loadFont('assets/fonts/inconsolata.ttf');
     * }
     * function setup() {
     *   background(200);
     *   var num1 = 321;
     *   var num2 = -1321;
     *
     *   noStroke();
     *   fill(0);
     *   textFont(myFont);
     *   textSize(22);
     *
     *   // nfs() aligns num1 (positive number) with num2 (negative number) by
     *   // adding a blank space in front of the num1 (positive number)
     *   // [left = 4] in num1 add one 0 in front, to align the digits with num2
     *   // [right = 2] in num1 and num2 adds two 0's after both numbers
     *   // To see the differences check the example of nf() too.
     *   text(nfs(num1, 4, 2), 10, 30);
     *   text(nfs(num2, 4, 2), 10, 80);
     *   // Draw dividing line
     *   stroke(120);
     *   line(0, 50, width, 50);
     * }
     */
    exports.nfs = function () {
    	p5._validateParameters('nfs', arguments);
    	var nfRes = exports.nf.apply(this, arguments);
    	if (nfRes instanceof Array) {
    		return nfRes.map(addNfs);
    	} else {
    		return addNfs(nfRes);
    	}
    };

    function addNfs(num) {
    	return parseFloat(num) > 0 ? ' ' + num.toString() : num.toString();
    }

    /**
     * The split() function maps to String.split(), it breaks a String into
     * pieces using a character or string as the delimiter. The delim parameter
     * specifies the character or characters that mark the boundaries between
     * each piece. A String[] array is returned that contains each of the pieces.
     *
     * The splitTokens() function works in a similar fashion, except that it
     * splits using a range of characters instead of a specific character or
     * sequence.
     *
     * @method split
     * @param  {String} value the String to be split
     * @param  {String} delim the String used to separate the data
     * @return {String[]}  Array of Strings
     * @example
     * var names = 'Pat,Xio,Alex';
     * var splitString = split(names, ',');
     * text(splitString[0], 5, 30);
     * text(splitString[1], 5, 50);
     * text(splitString[2], 5, 70);
     */
    exports.split = function (str, delim) {
    	p5._validateParameters('split', arguments);
    	return str.split(delim);
    };

    /**
     * The splitTokens() function splits a String at one or many character
     * delimiters or "tokens." The delim parameter specifies the character or
     * characters to be used as a boundary.
     * <br><br>
     * If no delim characters are specified, any whitespace character is used to
     * split. Whitespace characters include tab (\t), line feed (\n), carriage
     * return (\r), form feed (\f), and space.
     *
     * @method splitTokens
     * @param  {String} value   the String to be split
     * @param  {String} [delim] list of individual Strings that will be used as
     *                          separators
     * @return {String[]}          Array of Strings
     * @example
     * function setup() {
     *   var myStr = 'Mango, Banana, Lime';
     *   var myStrArr = splitTokens(myStr, ',');
     *
     *   print(myStrArr); // prints : ["Mango"," Banana"," Lime"]
     * }
     */
    exports.splitTokens = function (value, delims) {
    	p5._validateParameters('splitTokens', arguments);
    	var d;
    	if (typeof delims !== 'undefined') {
    		var str = delims;
    		var sqc = /\]/g.exec(str);
    		var sqo = /\[/g.exec(str);
    		if (sqo && sqc) {
    			str = str.slice(0, sqc.index) + str.slice(sqc.index + 1);
    			sqo = /\[/g.exec(str);
    			str = str.slice(0, sqo.index) + str.slice(sqo.index + 1);
    			d = new RegExp('[\\[' + str + '\\]]', 'g');
    		} else if (sqc) {
    			str = str.slice(0, sqc.index) + str.slice(sqc.index + 1);
    			d = new RegExp('[' + str + '\\]]', 'g');
    		} else if (sqo) {
    			str = str.slice(0, sqo.index) + str.slice(sqo.index + 1);
    			d = new RegExp('[' + str + '\\[]', 'g');
    		} else {
    			d = new RegExp('[' + str + ']', 'g');
    		}
    	} else {
    		d = /\s/g;
    	}
    	return value.split(d).filter(function (n) {
    		return n;
    	});
    };

    /**
     * Removes whitespace characters from the beginning and end of a String. In
     * addition to standard whitespace characters such as space, carriage return,
     * and tab, this function also removes the Unicode "nbsp" character.
     *
     * @method trim
     * @param  {String} str a String to be trimmed
     * @return {String}       a trimmed String
     *
     * @example
     * var string = trim('  No new lines\n   ');
     * text(string + ' here', 2, 50);
     */
    exports.trim = function (str) {
    	p5._validateParameters('trim', arguments);
    	if (str instanceof Array) {
    		return str.map(this.trim);
    	} else {
    		return str.trim();
    	}
    };

    /**********************************************************************************************************************
     * date functions
     */

    /**
     * The day() function
     * returns the current day as a value from 1 - 31.
     *
     * @method day
     * @return {Integer} the current day
     * @example
     * var d = day();
     * text('Current day: \n' + d, 5, 50);
     */
    exports.day = function () {
    	return new Date().getDate();
    };

    /**
     * The hour() function
     * returns the current hour as a value from 0 - 23.
     *
     * @method hour
     * @return {Integer} the current hour
     * @example
     * var h = hour();
     * text('Current hour:\n' + h, 5, 50);
     */
    exports.hour = function () {
    	return new Date().getHours();
    };

    /**
     * The minute() function
     * returns the current minute as a value from 0 - 59.
     *
     * @method minute
     * @return {Integer} the current minute
     * @example
     * var m = minute();
     * text('Current minute: \n' + m, 5, 50);
     */
    exports.minute = function () {
    	return new Date().getMinutes();
    };

    /**
     * Returns the number of milliseconds (thousandths of a second) since
     * starting the program. This information is often used for timing events and
     * animation sequences.
     *
     * @method millis
     * @return {Number} the number of milliseconds since starting the program
     * @example
     * var millisecond = millis();
     * text('Milliseconds \nrunning: \n' + millisecond, 5, 40);
     */
    exports.millis = function () {
    	return MsecTime();
    };

    /**
     * The month() function returns the current month as a value from 1 - 12.
     *
     * @method month
     * @return {Integer} the current month
     * @example
     * var m = month();
     * text('Current month: \n' + m, 5, 50);
     */
    exports.month = function () {
    	return new Date().getMonth() + 1; //January is 0!
    };

    /**
     * The second() function returns the current second as a value from 0 - 59.
     *
     * @method second
     * @return {Integer} the current second
     * @example
     * var s = second();
     * text('Current second: \n' + s, 5, 50);
     */
    exports.second = function () {
    	return new Date().getSeconds();
    };

    /**
     * The year() returns the current year as an integer (2014, 2015, 2016, etc).
     *
     * @method year
     * @return {Integer} the current year
     * @example
     * var y = year();
     * text('Current year: \n' + y, 5, 50);
     */
    exports.year = function () {
    	return new Date().getFullYear();
    };

    /**********************************************************************************************************************
     * dictionary
     */

    /**
     *
     * Creates a new instance of p5.StringDict using the key-value pair
     * or the object you provide.
     *
     * @method createStringDict
     * @param {String} key
     * @param {String} value
     * @return {StringDict}
     *
     * @example
     * function setup() {
     *   let myDictionary = createStringDict('p5', 'js');
     *   print(myDictionary.hasKey('p5')); // logs true to console
     *
     *   let anotherDictionary = createStringDict({ happy: 'coding' });
     *   print(anotherDictionary.hasKey('happy')); // logs true to console
     * }
     */
    exports.createStringDict = function (key, value) {
    	return new StringDict(key, value);
    };

    /**
     *
     * Creates a new instance of NumberDict using the key-value pair
     * or object you provide.
     *
     * @method createNumberDict
     * @param {Number} key
     * @param {Number} value
     * @return {NumberDict}
     *
     * @example
     * function setup() {
     *   let myDictionary = createNumberDict(100, 42);
     *   print(myDictionary.hasKey(100)); // logs true to console
     *
     *   let anotherDictionary = createNumberDict({ 200: 84 });
     *   print(anotherDictionary.hasKey(200)); // logs true to console
     * }
     */
    exports.createNumberDict = function (key, value) {
    	return new NumberDict(key, value);
    };

    /**
    * @module p5compat.TypedDict
    */

    /**
     * Base class for all p5.Dictionary types. Specifically
     * typed Dictionary classes inherit from this class.
     *
     * @class TypedDict
     */
    exports.TypedDict = function (key, value) {
    	if (key instanceof Object) {
    		this.data = key;
    	} else {
    		this.data = {};
    		this.data[key] = value;
    	}
    	return this;
    };

    /**
     * Returns the number of key-value pairs currently stored in the Dictionary.
     *
     * @method size
     * @return {Integer} the number of key-value pairs in the Dictionary
     *
     * @example
     * function setup() {
     *   let myDictionary = createNumberDict(1, 10);
     *   myDictionary.create(2, 20);
     *   myDictionary.create(3, 30);
     *   print(myDictionary.size()); // logs 3 to the console
     * }
     */
    exports.TypedDict.prototype.size = function () {
    	return Object.keys(this.data).length;
    };

    /**
     * Returns true if the given key exists in the Dictionary,
     * otherwise returns false.
     *
     * @method hasKey
     * @param {Number|String} key that you want to look up
     * @return {Boolean} whether that key exists in Dictionary
     *
     * @example
     * function setup() {
     *   let myDictionary = createStringDict('p5', 'js');
     *   print(myDictionary.hasKey('p5')); // logs true to console
     * }
     */
    exports.TypedDict.prototype.hasKey = function (key) {
    	return this.data.hasOwnProperty(key);
    };

    /**
     * Returns the value stored at the given key.
     *
     * @method get
     * @param {Number|String} the key you want to access
     * @return {Number|String} the value stored at that key
     *
     * @example
     * function setup() {
     *   let myDictionary = createStringDict('p5', 'js');
     *   let myValue = myDictionary.get('p5');
     *   print(myValue === 'js'); // logs true to console
     * }
     */
    exports.TypedDict.prototype.get = function (key) {
    	if (this.data.hasOwnProperty(key)) {
    		return this.data[key];
    	} else {
    		Println(key + ' does not exist in this Dictionary');
    	}
    };

    /**
     * Updates the value associated with the given key in case it already exists
     * in the Dictionary. Otherwise a new key-value pair is added.
     *
     * @method set
     * @param {Number|String} key
     * @param {Number|String} value
     *
     * @example
     * function setup() {
     *   let myDictionary = createStringDict('p5', 'js');
     *   myDictionary.set('p5', 'JS');
     *   myDictionary.print(); // logs "key: p5 - value: JS" to console
     * }
     */

    exports.TypedDict.prototype.set = function (key, value) {
    	if (this._validate(value)) {
    		this.data[key] = value;
    	} else {
    		Println('Those values dont work for this dictionary type.');
    	}
    };

    /**
     * private helper function to handle the user passing in objects
     * during construction or calls to create()
     */
    exports.TypedDict.prototype._addObj = function (obj) {
    	for (var key in obj) {
    		this.set(key, obj[key]);
    	}
    };

    /**
     * Creates a new key-value pair in the Dictionary.
     *
     * @method create
     * @param {Number|String} key
     * @param {Number|String} value
     *
     * @example
     * function setup() {
     *   let myDictionary = createStringDict('p5', 'js');
     *   myDictionary.create('happy', 'coding');
     *   myDictionary.print();
     *   // above logs "key: p5 - value: js, key: happy - value: coding" to console
     * }
     */
    exports.TypedDict.prototype.create = function (key, value) {
    	if (key instanceof Object && typeof value === 'undefined') {
    		this._addObj(key);
    	} else if (typeof key !== 'undefined') {
    		this.set(key, value);
    	} else {
    		Println(
    			'In order to create a new Dictionary entry you must pass ' +
    			'an object or a key, value pair'
    		);
    	}
    };

    /**
     * Removes all previously stored key-value pairs from the Dictionary.
     *
     * @method clear
     * @example
     * function setup() {
     *   let myDictionary = createStringDict('p5', 'js');
     *   print(myDictionary.hasKey('p5')); // prints 'true'
     *   myDictionary.clear();
     *   print(myDictionary.hasKey('p5')); // prints 'false'
     * }
     */
    exports.TypedDict.prototype.clear = function () {
    	this.data = {};
    };

    /**
     * Removes the key-value pair stored at the given key from the Dictionary.
     *
     * @method remove
     * @param {Number|String} key for the pair to remove
     *
     * @example
     * function setup() {
     *   let myDictionary = createStringDict('p5', 'js');
     *   myDictionary.create('happy', 'coding');
     *   myDictionary.print();
     *   // above logs "key: p5 - value: js, key: happy - value: coding" to console
     *   myDictionary.remove('p5');
     *   myDictionary.print();
     *   // above logs "key: happy value: coding" to console
     * }
     */
    exports.TypedDict.prototype.remove = function (key) {
    	if (this.data.hasOwnProperty(key)) {
    		delete this.data[key];
    	} else {
    		throw new Error(key + ' does not exist in this Dictionary');
    	}
    };

    /**
     * Logs the set of items currently stored in the Dictionary to the console.
     *
     * @method print
     *
     * @example
     * function setup() {
     *   let myDictionary = createStringDict('p5', 'js');
     *   myDictionary.create('happy', 'coding');
     *   myDictionary.print();
     *   // above logs "key: p5 - value: js, key: happy - value: coding" to console
     * }
     */
    exports.TypedDict.prototype.print = function () {
    	for (var item in this.data) {
    		Println('key:' + item + ' value:' + this.data[item]);
    	}
    };

    /**
     * Converts the Dictionary into a JSON file for local download.
     *
     * @method saveJSON
     * @example
     * function setup() {
     *   createCanvas(100, 100);
     *   background(200);
     *   text('click here to save', 10, 10, 70, 80);
     * }
     *
     * function mousePressed() {
     *   if (mouseX > 0 && mouseX < width && mouseY > 0 && mouseY < height) {
     *     createStringDict({
     *       john: 1940,
     *       paul: 1942,
     *       george: 1943,
     *       ringo: 1940
     *     }).saveJSON('beatles');
     *   }
     * }
     */
    exports.TypedDict.prototype.saveJSON = function (filename, opt) {
    	prototype.saveJSON(this.data, filename, opt);
    };

    /**
     * private helper function to ensure that the user passed in valid
     * values for the Dictionary type
     */
    exports.TypedDict.prototype._validate = function (value) {
    	return true;
    };

    /**
    * @module p5compat.StringDict
    */

    /**
     * A simple Dictionary class for Strings.
     *
     * @class StringDict
     * @extends TypedDict
     */

    exports.StringDict = function () {
    	TypedDict.apply(this, arguments);
    };

    exports.StringDict.prototype = Object.create(exports.TypedDict.prototype);

    exports.StringDict.prototype._validate = function (value) {
    	return typeof value === 'string';
    };

    /**
    * @module p5compat.NumberDict
    */

    /**
     * A simple Dictionary class for Numbers.
     *
     * @class NumberDict
     * @extends TypedDict
     */
    exports.NumberDict = function () {
    	TypedDict.apply(this, arguments);
    };

    exports.NumberDict.prototype = Object.create(exports.TypedDict.prototype);

    /**
     * private helper function to ensure that the user passed in valid
     * values for the Dictionary type
     */
    exports.NumberDict.prototype._validate = function (value) {
    	return typeof value === 'number';
    };

    /**
     * Add the given number to the value currently stored at the given key.
     * The sum then replaces the value previously stored in the Dictionary.
     *
     * @method add
     * @param {Number} Key for the value you wish to add to
     * @param {Number} Number to add to the value
     * @example
     * function setup() {
     *   let myDictionary = createNumberDict(2, 5);
     *   myDictionary.add(2, 2);
     *   print(myDictionary.get(2)); // logs 7 to console.
     * }
     */
    exports.NumberDict.prototype.add = function (key, amount) {
    	if (this.data.hasOwnProperty(key)) {
    		this.data[key] += amount;
    	} else {
    		Println('The key - ' + key + ' does not exist in this dictionary.');
    	}
    };

    /**
     * Subtract the given number from the value currently stored at the given key.
     * The difference then replaces the value previously stored in the Dictionary.
     *
     * @method sub
     * @param {Number} Key for the value you wish to subtract from
     * @param {Number} Number to subtract from the value
     * @example
     * function setup() {
     *   let myDictionary = createNumberDict(2, 5);
     *   myDictionary.sub(2, 2);
     *   print(myDictionary.get(2)); // logs 3 to console.
     * }
     */
    exports.NumberDict.prototype.sub = function (key, amount) {
    	this.add(key, -amount);
    };

    /**
     * Multiply the given number with the value currently stored at the given key.
     * The product then replaces the value previously stored in the Dictionary.
     *
     * @method mult
     * @param {Number} Key for value you wish to multiply
     * @param {Number} Amount to multiply the value by
     * @example
     * function setup() {
     *   let myDictionary = createNumberDict(2, 4);
     *   myDictionary.mult(2, 2);
     *   print(myDictionary.get(2)); // logs 8 to console.
     * }
     */
    exports.NumberDict.prototype.mult = function (key, amount) {
    	if (this.data.hasOwnProperty(key)) {
    		this.data[key] *= amount;
    	} else {
    		Println('The key - ' + key + ' does not exist in this dictionary.');
    	}
    };

    /**
     * Divide the given number with the value currently stored at the given key.
     * The quotient then replaces the value previously stored in the Dictionary.
     *
     * @method div
     * @param {Number} Key for value you wish to divide
     * @param {Number} Amount to divide the value by
     * @example
     * function setup() {
     *   let myDictionary = createNumberDict(2, 8);
     *   myDictionary.div(2, 2);
     *   print(myDictionary.get(2)); // logs 4 to console.
     * }
     */
    exports.NumberDict.prototype.div = function (key, amount) {
    	if (this.data.hasOwnProperty(key)) {
    		this.data[key] /= amount;
    	} else {
    		Println('The key - ' + key + ' does not exist in this dictionary.');
    	}
    };

    /**
     * private helper function for finding lowest or highest value
     * the argument 'flip' is used to flip the comparison arrow
     * from 'less than' to 'greater than'
     */
    exports.NumberDict.prototype._valueTest = function (flip) {
    	if (Object.keys(this.data).length === 0) {
    		throw new Error(
    			'Unable to search for a minimum or maximum value on an empty NumberDict'
    		);
    	} else if (Object.keys(this.data).length === 1) {
    		return this.data[Object.keys(this.data)[0]];
    	} else {
    		var result = this.data[Object.keys(this.data)[0]];
    		for (var key in this.data) {
    			if (this.data[key] * flip < result * flip) {
    				result = this.data[key];
    			}
    		}
    		return result;
    	}
    };

    /**
     * Return the lowest number currently stored in the Dictionary.
     *
     * @method minValue
     * @return {Number}
     * @example
     * function setup() {
     *   let myDictionary = createNumberDict({ 2: -10, 4: 0.65, 1.2: 3 });
     *   let lowestValue = myDictionary.minValue(); // value is -10
     *   print(lowestValue);
     * }
     *
     */
    exports.NumberDict.prototype.minValue = function () {
    	return this._valueTest(1);
    };

    /**
     * Return the highest number currently stored in the Dictionary.
     *
     * @method maxValue
     * @return {Number}
     * @example
     * function setup() {
     *   let myDictionary = createNumberDict({ 2: -10, 4: 0.65, 1.2: 3 });
     *   let highestValue = myDictionary.maxValue(); // value is 3
     *   print(highestValue);
     * }
     */
    exports.NumberDict.prototype.maxValue = function () {
    	return this._valueTest(-1);
    };

    /**
     * private helper function for finding lowest or highest key
     * the argument 'flip' is used to flip the comparison arrow
     * from 'less than' to 'greater than'
     *
     */
    exports.NumberDict.prototype._keyTest = function (flip) {
    	if (Object.keys(this.data).length === 0) {
    		throw new Error('Unable to use minValue on an empty NumberDict');
    	} else if (Object.keys(this.data).length === 1) {
    		return Object.keys(this.data)[0];
    	} else {
    		var result = Object.keys(this.data)[0];
    		for (var i = 1; i < Object.keys(this.data).length; i++) {
    			if (Object.keys(this.data)[i] * flip < result * flip) {
    				result = Object.keys(this.data)[i];
    			}
    		}
    		return result;
    	}
    };

    /**
     * Return the lowest key currently used in the Dictionary.
     *
     * @method minKey
     * @return {Number}
     * @example
     * function setup() {
     *   let myDictionary = createNumberDict({ 2: 4, 4: 6, 1.2: 3 });
     *   let lowestKey = myDictionary.minKey(); // value is 1.2
     *   print(lowestKey);
     * }
     */
    exports.NumberDict.prototype.minKey = function () {
    	return this._keyTest(1);
    };

    /**
     * Return the highest key currently used in the Dictionary.
     *
     * @method maxKey
     * @return {Number}
     * @example
     * function setup() {
     *   let myDictionary = createNumberDict({ 2: 4, 4: 6, 1.2: 3 });
     *   let highestKey = myDictionary.maxKey(); // value is 4
     *   print(highestKey);
     * }
     */
    exports.NumberDict.prototype.maxKey = function () {
    	return this._keyTest(-1);
    };