text: /**
   * math.js
   * https://github.com/josdejong/mathjs
   *
   * Math.js is an extensive math library for JavaScript and Node.js,
   * It features real and complex numbers, units, matrices, a large set of
   * mathematical functions, and a flexible expression parser.
   *
   * @version 0.17.1
   * @date    2013-12-19
   *
   * @license
   * Copyright (C) 2013 Jos de Jong <wjosdejong@gmail.com>
   *
   * Licensed under the Apache License, Version 2.0 (the "License"); you may not
   * use this file except in compliance with the License. You may obtain a copy
   * of the License at
   *
   * http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
   * License for the specific language governing permissions and limitations under
   * the License.
   */
  !function(e){"object"==typeof exports?module.exports=e():"function"==typeof define&&define.amd?define(e):"undefined"!=typeof window?window.mathjs=e():"undefined"!=typeof global?global.mathjs=e():"undefined"!=typeof self&&(self.mathjs=e())}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
  module.exports = require('./lib/math.js');
  
  },{"./lib/math.js":202}],2:[function(require,module,exports){
  module.exports = function (math) {
    var string = require('../util/string');
  
    /**
     * @constructor Selector
     * Wrap any value in a Selector, allowing to perform chained operations on
     * the value.
     *
     * All methods available in the math.js library can be called upon the selector,
     * and then will be evaluated with the value itself as first argument.
     * The selector can be closed by executing selector.done(), which will return
     * the final value.
     *
     * The Selector has a number of special functions:
     * - done()             Finalize the chained operation and return the
     *                      selectors value.
     * - valueOf()          The same as done()
     * - toString()         Returns a string representation of the selectors value.
     *
     * @param {*} [value]
     */
    function Selector (value) {
      if (!(this instanceof Selector)) {
        throw new SyntaxError(
            'Selector constructor must be called with the new operator');
      }
  
      if (value instanceof Selector) {
        this.value = value.value;
      }
      else {
        this.value = value;
      }
    }
  
    /**
     * Close the selector. Returns the final value.
     * Does the same as method valueOf()
     * @returns {*} value
     */
    Selector.prototype.done = function () {
      return this.value;
    };
  
    /**
     * Close the selector. Returns the final value.
     * Does the same as method done()
     * @returns {*} value
     */
    Selector.prototype.valueOf = function () {
      return this.value;
    };
  
    /**
     * Get a string representation of the value in the selector
     * @returns {String}
     */
    Selector.prototype.toString = function () {
      return string.format(this.value);
    };
  
    /**
     * Create a proxy method for the selector
     * @param {String} name
     * @param {*} value       The value or function to be proxied
     */
    function createProxy(name, value) {
      var slice = Array.prototype.slice;
      if (typeof value === 'function') {
        // a function
        Selector.prototype[name] = function () {
          var args = [this.value].concat(slice.call(arguments, 0));
          return new Selector(value.apply(this, args));
        }
      }
      else {
        // a constant
        Selector.prototype[name] = new Selector(value);
      }
    }
  
    Selector.createProxy = createProxy;
  
    /**
     * initialise the Chain prototype with all functions and constants in math
     */
    for (var prop in math) {
      if (math.hasOwnProperty(prop) && prop) {
        createProxy(prop, math[prop]);
      }
    }
  
    return Selector;
  };
  
  },{"../util/string":216}],3:[function(require,module,exports){
  module.exports = function (math) {
    var Complex = require('./type/Complex');
  
    math.pi          = Math.PI;
    math.e           = Math.E;
    math.tau         = Math.PI * 2;
    math.i           = new Complex(0, 1);
  
    math['Infinity'] = Infinity;
    math['NaN']      = NaN;
    math['true']     = true;
    math['false']    = false;
  
    // uppercase constants (for compatibility with built-in Math)
    math.E           = Math.E;
    math.LN2         = Math.LN2;
    math.LN10        = Math.LN10;
    math.LOG2E       = Math.LOG2E;
    math.LOG10E      = Math.LOG10E;
    math.PI          = Math.PI;
    math.SQRT1_2     = Math.SQRT1_2;
    math.SQRT2       = Math.SQRT2;
  };
  
  },{"./type/Complex":203}],4:[function(require,module,exports){
  var Scope = require('./Scope');
  
  /**
   * @constructor Parser
   * Parser contains methods to evaluate or parse expressions, and has a number
   * of convenience methods to get, set, and remove variables from memory. Parser
   * keeps a scope containing variables in memory, which is used for all
   * evaluations.
   *
   * Methods:
   *    var result = parser.eval(expr);    // evaluate an expression
   *    var value = parser.get(name);      // retrieve a variable from the parser
   *    parser.set(name, value);           // set a variable in the parser
   *    parser.remove(name);               // clear a variable from the
   *                                       // parsers scope
   *    parser.clear();                    // clear the parsers scope
   *
   *    // it is possible to parse an expression into a node tree:
   *    var node = parser.parse(expr);     // parse an expression into a node tree
   *    var result = node.eval();          // evaluate a parsed node
   *
   * Example usage:
   *    var parser = new Parser(math);
   *    // Note: there is a convenience method which can be used instead:
   *    // var parser = new math.parser();
   *
   *    // evaluate expressions
   *    parser.eval('sqrt(3^2 + 4^2)');         // 5
   *    parser.eval('sqrt(-4)');                // 2i
   *    parser.eval('2 inch in cm');            // 5.08 cm
   *    parser.eval('cos(45 deg)');             // 0.7071067811865476
   *
   *    // define variables and functions
   *    parser.eval('x = 7 / 2');               // 3.5
   *    parser.eval('x + 3');                   // 6.5
   *    parser.eval('function f(x, y) = x^y');  // f(x, y)
   *    parser.eval('f(2, 3)');                 // 8
   *
   *    // get and set variables and functions
   *    var x = parser.get('x');                // 7
   *    var f = parser.get('f');                // function
   *    var g = f(3, 2);                        // 9
   *    parser.set('h', 500);
   *    var i = parser.eval('h / 2');           // 250
   *    parser.set('hello', function (name) {
   *        return 'hello, ' + name + '!';
   *    });
   *    parser.eval('hello("user")');           // "hello, user!"
   *
   *    // clear defined functions and variables
   *    parser.clear();
   *
   *
   * @param {Object} math     Link to the math.js namespace
   */
  function Parser(math) {
    if (!(this instanceof Parser)) {
      throw new SyntaxError(
          'Parser constructor must be called with the new operator');
    }
  
    this.math = math;
    this.scope = new Scope(math);
  }
  
  /**
   * Parse an expression end return the parsed function node.
   * The node can be evaluated via node.eval()
   * @param {String} expr
   * @return {Node} node
   * @throws {Error}
   */
  Parser.prototype.parse = function (expr) {
    // TODO: validate arguments
    return this.math.parse(expr, this.scope);
  };
  
  /**
   * Parse and evaluate the given expression
   * @param {String} expr   A string containing an expression, for example "2+3"
   * @return {*} result     The result, or undefined when the expression was empty
   * @throws {Error}
   */
  Parser.prototype.eval = function (expr) {
    // TODO: validate arguments
    var node = this.math.parse(expr, this.scope);
    return node.eval();
  };
  
  /**
   * Get a variable (a function or variable) by name from the parsers scope.
   * Returns undefined when not found
   * @param {String} name
   * @return {* | undefined} value
   */
  Parser.prototype.get = function (name) {
    // TODO: validate arguments
    return this.scope.get(name);
  };
  
  /**
   * Set a symbol (a function or variable) by name from the parsers scope.
   * @param {String} name
   * @param {* | undefined} value
   */
  Parser.prototype.set = function (name, value) {
    // TODO: validate arguments
    return this.scope.set(name, value);
  };
  
  /**
   * Remove a variable from the parsers scope
   * @param {String} name
   */
  Parser.prototype.remove = function (name) {
    // TODO: validate arguments
    this.scope.remove(name);
  };
  
  /**
   * Clear the scope with variables and functions
   */
  Parser.prototype.clear = function () {
    this.scope.clear();
  };
  
  module.exports = Parser;
  
  },{"./Scope":5}],5:[function(require,module,exports){
  var Unit = require('../type/Unit');
  
  /**
   * Scope
   * A scope stores values of symbols: variables and functions.
   *
   * Syntax:
   *     var scope = new Scope(math);
   *     var scope = new Scope(math, parentScope);
   *     var scope = new Scope(math, symbols);
   *     var scope = new Scope(math, parentScope, symbols);
   *
   * Where:
   *     {Object} math                Link to the (static) math.js namespace
   *     {Scope | Object} parentScope Scope will be linked to a parent scope,
   *                                  which is traversed when resolving
   *                                  symbols.
   *     {Object} symbols             A custom object that will be used to
   *                                  resolve and store variables.
   *
   * @constructor Scope
   * @param {...} [math]
   * @param {*} [arg1]
   * @param {*} [arg2]
   */
  function Scope(math, arg1, arg2) {
    this.math = math;
  
    /** @type {Scope} */
    this.parentScope = null;
    // TODO: rename parentScope to previousScope, add a nextScope, change Scope to a linked list node
  
    /** @type {Scope[]} */
    this.subScopes = null;
    // TODO: rename subScopes to childScopes (or childNodes?)
  
    /** @type {Object.<String, *>} */
    this.symbols = {};  // variables and functions
  
    /** @type {Object.<String, Object>} */
    this.cache = {};    // cache, referring to the scope.symbols object where
    // a variable was last found
  
    // read second argument (can be parentScope or symbols map)
    if (arg1) {
      if (arg1 instanceof Scope) {
        this.parentScope = arg1;
      }
      else if (arg1 instanceof Object) {
        this.symbols = arg1;
      }
    }
  
    // read second argument (can be symbols map)
    if (arg2) {
      if (arg2 instanceof Object) {
        this.symbols = arg2;
      }
    }
  }
  
  Scope.prototype = {
    /**
     * Create a sub scope
     * The variables in a sub scope are not accessible from the parent scope
     * @return {Scope} subScope
     */
    createSubScope: function () {
      var subScope = new Scope(this.math, this);
      if (!this.subScopes) {
        this.subScopes = [];
      }
      this.subScopes.push(subScope);
      return subScope;
    },
  
    /**
     * Get a symbol value by name.
     * Returns undefined if the symbol is not found in this scope or any of
     * its parent scopes.
     * @param {String} name
     * @returns {* | undefined} value
     */
    get: function (name) {
      var value;
  
      // check itself
      value = this.symbols[name];
      if (value !== undefined) {
        return value;
      }
  
      // read from cache
      var symbols = this.cache[name];
      if (symbols) {
        return symbols[name];
      }
  
      // check parent scope
      var parent = this.parentScope;
      while (parent) {
        value = parent.symbols[name];
        if (value !== undefined) {
          this.cache[name] = parent.symbols;
          return value;
        }
        parent = parent.parentScope;
      }
  
      // check static context
      value = this.math[name];
      if (value !== undefined) {
        this.cache[name] = this.math;
        return value;
      }
  
      // check if name is a unit
      if (Unit.isPlainUnit(name)) {
        value = new Unit(null, name);
        this.cache[name] = {};
        this.cache[name][name] = value;
        return value;
      }
  
      return undefined;
    },
  
    /**
     * Test whether this scope contains a symbol (will not check parent scopes)
     * @param {String} name
     * @return {Boolean} hasSymbol
     */
    has: function (name) {
      return (this.symbols[name] !== undefined);
    },
  
    /**
     * Set a symbol value
     * @param {String} name
     * @param {*} value
     * @return {*} value
     */
    set: function (name, value) {
      return this.symbols[name] = value;
    },
  
    /**
     * Remove a symbol by name
     * @param {String} name
     */
    remove: function(name) {
      delete this.symbols[name];
    },
  
    /**
     * Clear all symbols in this scope, its sub scopes, and clear the cache.
     * Parent scopes will not be cleared.
     */
    clear: function () {
      var symbols = this.symbols;
      for (var name in symbols) {
        if (symbols.hasOwnProperty(name)) {
          delete symbols[name];
        }
      }
  
      if (this.subScopes) {
        var subScopes = this.subScopes;
        for (var i = 0, iMax = subScopes.length; i < iMax; i++) {
          subScopes[i].clear();
        }
      }
  
      this.clearCache();
    },
  
    /**
     * Clear cached links to symbols in other scopes
     */
    clearCache: function () {
      this.cache = {};
    }
  };
  
  Scope.context = []; // static context, for example the math namespace
  
  module.exports = Scope;
  
  },{"../type/Unit":208}],6:[function(require,module,exports){
  module.exports = {
    'name': 'Infinity',
    'category': 'Constants',
    'syntax': [
      'Infinity'
    ],
    'description': 'Infinity, a number which is larger than the maximum number that can be handled by a floating point number.',
    'examples': [
      'Infinity',
      '1 / 0'
    ],
    'seealso': []
  };
  
  },{}],7:[function(require,module,exports){
  module.exports = {
    'name': 'LN10',
    'category': 'Constants',
    'syntax': [
      'LN10'
    ],
    'description': 'Returns the natural logarithm of 10, approximately equal to 2.302',
    'examples': [
      'LN10',
      'log(10)'
    ],
    'seealso': []
  };
  
  },{}],8:[function(require,module,exports){
  module.exports = {
    'name': 'LN2',
    'category': 'Constants',
    'syntax': [
      'LN2'
    ],
    'description': 'Returns the natural logarithm of 2, approximately equal to 0.693',
    'examples': [
      'LN2',
      'log(2)'
    ],
    'seealso': []
  };
  
  },{}],9:[function(require,module,exports){
  module.exports = {
    'name': 'LOG10E',
    'category': 'Constants',
    'syntax': [
      'LOG10E'
    ],
    'description': 'Returns the base-10 logarithm of E, approximately equal to 0.434',
    'examples': [
      'LOG10E',
      'log(e, 10)'
    ],
    'seealso': []
  };
  
  },{}],10:[function(require,module,exports){
  module.exports = {
    'name': 'LOG2E',
    'category': 'Constants',
    'syntax': [
      'LOG2E'
    ],
    'description': 'Returns the base-2 logarithm of E, approximately equal to 1.442',
    'examples': [
      'LOG2E',
      'log(e, 2)'
    ],
    'seealso': []
  };
  
  },{}],11:[function(require,module,exports){
  module.exports = {
    'name': 'NaN',
    'category': 'Constants',
    'syntax': [
      'NaN'
    ],
    'description': 'Not a number',
    'examples': [
      'NaN',
      '0 / 0'
    ],
    'seealso': []
  };
  
  },{}],12:[function(require,module,exports){
  module.exports = {
    'name': 'SQRT1_2',
    'category': 'Constants',
    'syntax': [
      'SQRT1_2'
    ],
    'description': 'Returns the square root of 1/2, approximately equal to 0.707',
    'examples': [
      'SQRT1_2',
      'sqrt(1/2)'
    ],
    'seealso': []
  };
  
  },{}],13:[function(require,module,exports){
  module.exports = {
    'name': 'SQRT2',
    'category': 'Constants',
    'syntax': [
      'SQRT2'
    ],
    'description': 'Returns the square root of 2, approximately equal to 1.414',
    'examples': [
      'SQRT2',
      'sqrt(2)'
    ],
    'seealso': []
  };
  
  },{}],14:[function(require,module,exports){
  module.exports = {
    'name': 'e',
    'category': 'Constants',
    'syntax': [
      'e'
    ],
    'description': 'Euler\'s number, the base of the natural logarithm. Approximately equal to 2.71828',
    'examples': [
      'e',
      'e ^ 2',
      'exp(2)',
      'log(e)'
    ],
    'seealso': ['exp']
  };
  
  },{}],15:[function(require,module,exports){
  module.exports = {
    'name': 'false',
    'category': 'Constants',
    'syntax': [
      'false'
    ],
    'description': 'Boolean value false',
    'examples': [
      'false'
    ],
    'seealso': ['true']
  };
  
  },{}],16:[function(require,module,exports){
  module.exports = {
    'name': 'i',
    'category': 'Constants',
    'syntax': [
      'i'
    ],
    'description': 'Imaginary unit, defined as i*i=-1. A complex number is described as a + b*i, where a is the real part, and b is the imaginary part.',
    'examples': [
      'i',
      'i * i',
      'sqrt(-1)'
    ],
    'seealso': []
  };
  
  },{}],17:[function(require,module,exports){
  module.exports = {
    'name': 'pi',
    'category': 'Constants',
    'syntax': [
      'pi'
    ],
    'description': 'The number pi is a mathematical constant that is the ratio of a circle\'s circumference to its diameter, and is approximately equal to 3.14159',
    'examples': [
      'pi',
      'sin(pi/2)'
    ],
    'seealso': ['tau']
  };
  
  },{}],18:[function(require,module,exports){
  module.exports = {
    'name': 'tau',
    'category': 'Constants',
    'syntax': [
      'pi'
    ],
    'description': 'Tau is the ratio constant of a circle\'s circumference to radius, equal to 2 * pi, approximately 6.2832.',
    'examples': [
      'tau',
      '2 * pi'
    ],
    'seealso': ['pi']
  };
  
  },{}],19:[function(require,module,exports){
  module.exports = {
    'name': 'true',
    'category': 'Constants',
    'syntax': [
      'true'
    ],
    'description': 'Boolean value true',
    'examples': [
      'true'
    ],
    'seealso': ['false']
  };
  
  },{}],20:[function(require,module,exports){
  module.exports = {
    'name': 'abs',
    'category': 'Arithmetic',
    'syntax': [
      'abs(x)'
    ],
    'description': 'Compute the absolute value.',
    'examples': [
      'abs(3.5)',
      'abs(-4.2)'
    ],
    'seealso': ['sign']
  };
  
  },{}],21:[function(require,module,exports){
  module.exports = {
    'name': 'add',
    'category': 'Operators',
    'syntax': [
      'x + y',
      'add(x, y)'
    ],
    'description': 'Add two values.',
    'examples': [
      '2.1 + 3.6',
      'ans - 3.6',
      '3 + 2i',
      '"hello" + " world"',
      '3 cm + 2 inch'
    ],
    'seealso': [
      'subtract'
    ]
  };
  
  },{}],22:[function(require,module,exports){
  module.exports = {
    'name': 'ceil',
    'category': 'Arithmetic',
    'syntax': [
      'ceil(x)'
    ],
    'description':
        'Round a value towards plus infinity.If x is complex, both real and imaginary part are rounded towards plus infinity.',
    'examples': [
      'ceil(3.2)',
      'ceil(3.8)',
      'ceil(-4.2)'
    ],
    'seealso': ['floor', 'fix', 'round']
  };
  
  },{}],23:[function(require,module,exports){
  module.exports = {
    'name': 'cube',
    'category': 'Arithmetic',
    'syntax': [
      'cube(x)'
    ],
    'description': 'Compute the cube of a value. The cube of x is x * x * x.',
    'examples': [
      'cube(2)',
      '2^3',
      '2 * 2 * 2'
    ],
    'seealso': [
      'multiply',
      'square',
      'pow'
    ]
  };
  
  },{}],24:[function(require,module,exports){
  module.exports = {
    'name': 'divide',
    'category': 'Operators',
    'syntax': [
      'x / y',
      'divide(x, y)'
    ],
    'description': 'Divide two values.',
    'examples': [
      '2 / 3',
      'ans * 3',
      '4.5 / 2',
      '3 + 4 / 2',
      '(3 + 4) / 2',
      '18 km / 4.5'
    ],
    'seealso': [
      'multiply'
    ]
  };
  
  },{}],25:[function(require,module,exports){
  module.exports = {
    'name': 'edivide',
    'category': 'Operators',
    'syntax': [
      'x ./ y',
      'edivide(x, y)'
    ],
    'description': 'divide two values element wise.',
    'examples': [
      'a = [1, 2, 3; 4, 5, 6]',
      'b = [2, 1, 1; 3, 2, 5]',
      'a ./ b'
    ],
    'seealso': [
      'multiply',
      'emultiply',
      'divide'
    ]
  };
  
  },{}],26:[function(require,module,exports){
  module.exports = {
    'name': 'emultiply',
    'category': 'Operators',
    'syntax': [
      'x .* y',
      'emultiply(x, y)'
    ],
    'description': 'multiply two values element wise.',
    'examples': [
      'a = [1, 2, 3; 4, 5, 6]',
      'b = [2, 1, 1; 3, 2, 5]',
      'a .* b'
    ],
    'seealso': [
      'multiply',
      'divide',
      'edivide'
    ]
  };
  
  },{}],27:[function(require,module,exports){
  module.exports = {
    'name': 'epow',
    'category': 'Operators',
    'syntax': [
      'x .^ y',
      'epow(x, y)'
    ],
    'description':
        'Calculates the power of x to y element wise.',
    'examples': [
      'a = [1, 2, 3; 4, 5, 6]',
      'a .^ 2'
    ],
    'seealso': [
      'pow'
    ]
  };
  
  },{}],28:[function(require,module,exports){
  module.exports = {
    'name': 'equal',
    'category': 'Operators',
    'syntax': [
      'x == y',
      'equal(x, y)'
    ],
    'description':
        'Check equality of two values. Returns 1 if the values are equal, and 0 if not.',
    'examples': [
      '2+2 == 3',
      '2+2 == 4',
      'a = 3.2',
      'b = 6-2.8',
      'a == b',
      '50cm == 0.5m'
    ],
    'seealso': [
      'unequal', 'smaller', 'larger', 'smallereq', 'largereq'
    ]
  };
  
  },{}],29:[function(require,module,exports){
  module.exports = {
    'name': 'exp',
    'category': 'Arithmetic',
    'syntax': [
      'exp(x)'
    ],
    'description': 'Calculate the exponent of a value.',
    'examples': [
      'exp(1.3)',
      'e ^ 1.3',
      'log(exp(1.3))',
      'x = 2.4',
      '(exp(i*x) == cos(x) + i*sin(x))   # Euler\'s formula'
    ],
    'seealso': [
      'square',
      'multiply',
      'log'
    ]
  };
  
  },{}],30:[function(require,module,exports){
  module.exports = {
    'name': 'fix',
    'category': 'Arithmetic',
    'syntax': [
      'fix(x)'
    ],
    'description':
        'Round a value towards zero.If x is complex, both real and imaginary part are rounded towards zero.',
    'examples': [
      'fix(3.2)',
      'fix(3.8)',
      'fix(-4.2)',
      'fix(-4.8)'
    ],
    'seealso': ['ceil', 'floor', 'round']
  };
  
  },{}],31:[function(require,module,exports){
  module.exports = {
    'name': 'floor',
    'category': 'Arithmetic',
    'syntax': [
      'floor(x)'
    ],
    'description':
        'Round a value towards minus infinity.If x is complex, both real and imaginary part are rounded towards minus infinity.',
    'examples': [
      'floor(3.2)',
      'floor(3.8)',
      'floor(-4.2)'
    ],
    'seealso': ['ceil', 'fix', 'round']
  };
  
  },{}],32:[function(require,module,exports){
  module.exports = {
    'name': 'gcd',
    'category': 'Arithmetic',
    'syntax': [
      'gcd(a, b)',
      'gcd(a, b, c, ...)'
    ],
    'description': 'Compute the greatest common divisor.',
    'examples': [
      'gcd(8, 12)',
      'gcd(-4, 6)',
      'gcd(25, 15, -10)'
    ],
    'seealso': [ 'lcm', 'xgcd' ]
  };
  
  },{}],33:[function(require,module,exports){
  module.exports = {
    'name': 'larger',
    'category': 'Operators',
    'syntax': [
      'x > y',
      'larger(x, y)'
    ],
    'description':
        'Check if value x is larger than y. Returns 1 if x is larger than y, and 0 if not.',
    'examples': [
      '2 > 3',
      '5 > 2*2',
      'a = 3.3',
      'b = 6-2.8',
      '(a > b)',
      '(b < a)',
      '5 cm > 2 inch'
    ],
    'seealso': [
      'equal', 'unequal', 'smaller', 'smallereq', 'largereq'
    ]
  };
  
  },{}],34:[function(require,module,exports){
  module.exports = {
    'name': 'largereq',
    'category': 'Operators',
    'syntax': [
      'x >= y',
      'largereq(x, y)'
    ],
    'description':
        'Check if value x is larger or equal to y. Returns 1 if x is larger or equal to y, and 0 if not.',
    'examples': [
      '2 > 1+1',
      '2 >= 1+1',
      'a = 3.2',
      'b = 6-2.8',
      '(a > b)'
    ],
    'seealso': [
      'equal', 'unequal', 'smallereq', 'smaller', 'largereq'
    ]
  };
  
  },{}],35:[function(require,module,exports){
  module.exports = {
    'name': 'lcm',
    'category': 'Arithmetic',
    'syntax': [
      'lcm(x, y)'
    ],
    'description': 'Compute the least common multiple.',
    'examples': [
      'lcm(4, 6)',
      'lcm(6, 21)',
      'lcm(6, 21, 5)'
    ],
    'seealso': [ 'gcd' ]
  };
  
  },{}],36:[function(require,module,exports){
  module.exports = {
    'name': 'log',
    'category': 'Arithmetic',
    'syntax': [
      'log(x)',
      'log(x, base)'
    ],
    'description': 'Compute the logarithm of a value. If no base is provided, the natural logarithm of x is calculated. If base if provided, the logarithm is calculated for the specified base. log(x, base) is defined as log(x) / log(base).',
    'examples': [
      'log(3.5)',
      'a = log(2.4)',
      'exp(a)',
      '10 ^ 3',
      'log(1000, 10)',
      'log(1000) / log(10)',
      'b = logb(1024, 2)',
      '2 ^ b'
    ],
    'seealso': [
      'exp',
      'log10'
    ]
  };
  },{}],37:[function(require,module,exports){
  module.exports = {
    'name': 'log10',
    'category': 'Arithmetic',
    'syntax': [
      'log10(x)'
    ],
    'description': 'Compute the 10-base logarithm of a value.',
    'examples': [
      'log10(1000)',
      '10 ^ 3',
      'log10(0.01)',
      'log(1000) / log(10)',
      'log(1000, 10)'
    ],
    'seealso': [
      'exp',
      'log'
    ]
  };
  
  },{}],38:[function(require,module,exports){
  module.exports = {
    'name': 'mod',
    'category': 'Operators',
    'syntax': [
      'x % y',
      'x mod y',
      'mod(x, y)'
    ],
    'description':
        'Calculates the modulus, the remainder of an integer division.',
    'examples': [
      '7 % 3',
      '11 % 2',
      '10 mod 4',
      'function isOdd(x) = x % 2',
      'isOdd(2)',
      'isOdd(3)'
    ],
    'seealso': []
  };
  
  },{}],39:[function(require,module,exports){
  module.exports = {
    'name': 'multiply',
    'category': 'Operators',
    'syntax': [
      'x * y',
      'multiply(x, y)'
    ],
    'description': 'multiply two values.',
    'examples': [
      '2.1 * 3.6',
      'ans / 3.6',
      '2 * 3 + 4',
      '2 * (3 + 4)',
      '3 * 2.1 km'
    ],
    'seealso': [
      'divide'
    ]
  };
  
  },{}],40:[function(require,module,exports){
  module.exports = {
    'name': 'pow',
    'category': 'Operators',
    'syntax': [
      'x ^ y',
      'pow(x, y)'
    ],
    'description':
        'Calculates the power of x to y, x^y.',
    'examples': [
      '2^3 = 8',
      '2*2*2',
      '1 + e ^ (pi * i)'
    ],
    'seealso': [
      'unequal', 'smaller', 'larger', 'smallereq', 'largereq'
    ]
  };
  
  },{}],41:[function(require,module,exports){
  module.exports = {
    'name': 'round',
    'category': 'Arithmetic',
    'syntax': [
      'round(x)',
      'round(x, n)'
    ],
    'description':
        'round a value towards the nearest integer.If x is complex, both real and imaginary part are rounded towards the nearest integer. When n is specified, the value is rounded to n decimals.',
    'examples': [
      'round(3.2)',
      'round(3.8)',
      'round(-4.2)',
      'round(-4.8)',
      'round(pi, 3)',
      'round(123.45678, 2)'
    ],
    'seealso': ['ceil', 'floor', 'fix']
  };
  
  },{}],42:[function(require,module,exports){
  module.exports = {
    'name': 'sign',
    'category': 'Arithmetic',
    'syntax': [
      'sign(x)'
    ],
    'description':
        'Compute the sign of a value. The sign of a value x is 1 when x>1, -1 when x<0, and 0 when x=0.',
    'examples': [
      'sign(3.5)',
      'sign(-4.2)',
      'sign(0)'
    ],
    'seealso': [
      'abs'
    ]
  };
  
  },{}],43:[function(require,module,exports){
  module.exports = {
    'name': 'smaller',
    'category': 'Operators',
    'syntax': [
      'x < y',
      'smaller(x, y)'
    ],
    'description':
        'Check if value x is smaller than value y. Returns 1 if x is smaller than y, and 0 if not.',
    'examples': [
      '2 < 3',
      '5 < 2*2',
      'a = 3.3',
      'b = 6-2.8',
      '(a < b)',
      '5 cm < 2 inch'
    ],
    'seealso': [
      'equal', 'unequal', 'larger', 'smallereq', 'largereq'
    ]
  };
  
  },{}],44:[function(require,module,exports){
  module.exports = {
    'name': 'smallereq',
    'category': 'Operators',
    'syntax': [
      'x <= y',
      'smallereq(x, y)'
    ],
    'description':
        'Check if value x is smaller or equal to value y. Returns 1 if x is smaller than y, and 0 if not.',
    'examples': [
      '2 < 1+1',
      '2 <= 1+1',
      'a = 3.2',
      'b = 6-2.8',
      '(a < b)'
    ],
    'seealso': [
      'equal', 'unequal', 'larger', 'smaller', 'largereq'
    ]
  };
  
  },{}],45:[function(require,module,exports){
  module.exports = {
    'name': 'sqrt',
    'category': 'Arithmetic',
    'syntax': [
      'sqrt(x)'
    ],
    'description':
        'Compute the square root value. If x = y * y, then y is the square root of x.',
    'examples': [
      'sqrt(25)',
      '5 * 5',
      'sqrt(-1)'
    ],
    'seealso': [
      'square',
      'multiply'
    ]
  };
  
  },{}],46:[function(require,module,exports){
  module.exports = {
    'name': 'square',
    'category': 'Arithmetic',
    'syntax': [
      'square(x)'
    ],
    'description':
        'Compute the square of a value. The square of x is x * x.',
    'examples': [
      'square(3)',
      'sqrt(9)',
      '3^2',
      '3 * 3'
    ],
    'seealso': [
      'multiply',
      'pow',
      'sqrt',
      'cube'
    ]
  };
  
  },{}],47:[function(require,module,exports){
  module.exports = {
    'name': 'subtract',
    'category': 'Operators',
    'syntax': [
      'x - y',
      'subtract(x, y)'
    ],
    'description': 'subtract two values.',
    'examples': [
      '5.3 - 2',
      'ans + 2',
      '2/3 - 1/6',
      '2 * 3 - 3',
      '2.1 km - 500m'
    ],
    'seealso': [
      'add'
    ]
  };
  
  },{}],48:[function(require,module,exports){
  module.exports = {
    'name': 'unary',
    'category': 'Operators',
    'syntax': [
      '-x',
      'unary(x)'
    ],
    'description':
        'Inverse the sign of a value.',
    'examples': [
      '-4.5',
      '-(-5.6)'
    ],
    'seealso': [
      'add', 'subtract'
    ]
  };
  
  },{}],49:[function(require,module,exports){
  module.exports = {
    'name': 'unequal',
    'category': 'Operators',
    'syntax': [
      'x != y',
      'unequal(x, y)'
    ],
    'description':
        'Check unequality of two values. Returns 1 if the values are unequal, and 0 if they are equal.',
    'examples': [
      '2+2 != 3',
      '2+2 != 4',
      'a = 3.2',
      'b = 6-2.8',
      'a != b',
      '50cm != 0.5m',
      '5 cm != 2 inch'
    ],
    'seealso': [
      'equal', 'smaller', 'larger', 'smallereq', 'largereq'
    ]
  };
  
  },{}],50:[function(require,module,exports){
  module.exports = {
    'name': 'xgcd',
    'category': 'Arithmetic',
    'syntax': [
      'xgcd(a, b)'
    ],
    'description': 'Calculate the extended greatest common divisor for two values',
    'examples': [
      'xgcd(8, 12)',
      'gcd(8, 12)',
      'xgcd(36163, 21199)'
    ],
    'seealso': [ 'gcd', 'lcm' ]
  };
  
  },{}],51:[function(require,module,exports){
  module.exports = {
    'name': 'arg',
    'category': 'Complex',
    'syntax': [
      'arg(x)'
    ],
    'description':
        'Compute the argument of a complex value. If x = a+bi, the argument is computed as atan2(b, a).',
    'examples': [
      'arg(2 + 2i)',
      'atan2(3, 2)',
      'arg(2 - 3i)'
    ],
    'seealso': [
      're',
      'im',
      'conj',
      'abs'
    ]
  };
  
  },{}],52:[function(require,module,exports){
  module.exports = {
    'name': 'conj',
    'category': 'Complex',
    'syntax': [
      'conj(x)'
    ],
    'description':
        'Compute the complex conjugate of a complex value. If x = a+bi, the complex conjugate is a-bi.',
    'examples': [
      'conj(2 + 3i)',
      'conj(2 - 3i)',
      'conj(-5.2i)'
    ],
    'seealso': [
      're',
      'im',
      'abs',
      'arg'
    ]
  };
  
  },{}],53:[function(require,module,exports){
  module.exports = {
    'name': 'im',
    'category': 'Complex',
    'syntax': [
      'im(x)'
    ],
    'description': 'Get the imaginary part of a complex number.',
    'examples': [
      'im(2 + 3i)',
      're(2 + 3i)',
      'im(-5.2i)',
      'im(2.4)'
    ],
    'seealso': [
      're',
      'conj',
      'abs',
      'arg'
    ]
  };
  
  },{}],54:[function(require,module,exports){
  module.exports = {
    'name': 're',
    'category': 'Complex',
    'syntax': [
      're(x)'
    ],
    'description': 'Get the real part of a complex number.',
    'examples': [
      're(2 + 3i)',
      'im(2 + 3i)',
      're(-5.2i)',
      're(2.4)'
    ],
    'seealso': [
      'im',
      'conj',
      'abs',
      'arg'
    ]
  };
  
  },{}],55:[function(require,module,exports){
  module.exports = {
    'name': 'bignumber',
    'category': 'Type',
    'syntax': [
      'bignumber(x)'
    ],
    'description':
        'Create a big number from a number or string.',
    'examples': [
      '0.1 + 0.2',
      'bignumber(0.1) + bignumber(0.2)',
      'bignumber("7.2")',
      'bignumber("7.2e500")',
      'bignumber([0.1, 0.2, 0.3])'
    ],
    'seealso': [
      'boolean', 'complex', 'index', 'matrix', 'string', 'unit'
    ]
  };
  
  },{}],56:[function(require,module,exports){
  module.exports = {
    'name': 'boolean',
    'category': 'Type',
    'syntax': [
      'x',
      'boolean(x)'
    ],
    'description':
        'Convert a string or number into a boolean.',
    'examples': [
      'boolean(0)',
      'boolean(1)',
      'boolean(3)',
      'boolean("true")',
      'boolean("false")',
      'boolean([1, 0, 1, 1])'
    ],
    'seealso': [
      'bignumber', 'complex', 'index', 'matrix', 'number', 'string', 'unit'
    ]
  };
  
  },{}],57:[function(require,module,exports){
  module.exports = {
    'name': 'complex',
    'category': 'Type',
    'syntax': [
      'complex()',
      'complex(re, im)',
      'complex(string)'
    ],
    'description':
        'Create a complex number.',
    'examples': [
      'complex()',
      'complex(2, 3)',
      'complex("7 - 2i")'
    ],
    'seealso': [
      'bignumber', 'boolean', 'index', 'matrix', 'number', 'string', 'unit'
    ]
  };
  
  },{}],58:[function(require,module,exports){
  module.exports = {
    'name': 'index',
    'category': 'Type',
    'syntax': [
      '[start]',
      '[start:end]',
      '[start:step:end]',
      '[start1, start 2, ...]',
      '[start1:end1, start2:end2, ...]',
      '[start1:step1:end1, start2:step2:end2, ...]'
    ],
    'description':
        'Create an index to get or replace a subset of a matrix',
    'examples': [
      '[]',
      '[1, 2, 3]',
      'A = [1, 2, 3; 4, 5, 6]',
      'A[1, :]',
      'A[1, 2] = 50',
      'A[0:2, 0:2] = ones(2, 2)'
    ],
    'seealso': [
      'bignumber', 'boolean', 'complex', 'matrix,', 'number', 'range', 'string', 'unit'
    ]
  };
  
  },{}],59:[function(require,module,exports){
  module.exports = {
    'name': 'matrix',
    'category': 'Type',
    'syntax': [
      '[]',
      '[a1, b1, ...; a2, b2, ...]',
      'matrix()',
      'matrix([...])'
    ],
    'description':
        'Create a matrix.',
    'examples': [
      '[]',
      '[1, 2, 3]',
      '[1, 2, 3; 4, 5, 6]',
      'matrix()',
      'matrix([3, 4])'
    ],
    'seealso': [
      'bignumber', 'boolean', 'complex', 'index', 'number', 'string', 'unit'
    ]
  };
  
  },{}],60:[function(require,module,exports){
  module.exports = {
    'name': 'number',
    'category': 'Type',
    'syntax': [
      'x',
      'number(x)'
    ],
    'description':
        'Create a number or convert a string or boolean into a number.',
    'examples': [
      '2',
      '2e3',
      '4.05',
      'number(2)',
      'number("7.2")',
      'number(true)',
      'number([true, false, true, true])'
    ],
    'seealso': [
      'bignumber', 'boolean', 'complex', 'index', 'matrix', 'string', 'unit'
    ]
  };
  
  },{}],61:[function(require,module,exports){
  module.exports = {
    'name': 'string',
    'category': 'Type',
    'syntax': [
      '"text"',
      'string(x)'
    ],
    'description':
        'Create a string or convert a value to a string',
    'examples': [
      '"Hello World!"',
      'string(4.2)',
      'string(3 + 2i)'
    ],
    'seealso': [
      'bignumber', 'boolean', 'complex', 'index', 'matrix', 'number', 'unit'
    ]
  };
  
  },{}],62:[function(require,module,exports){
  module.exports = {
    'name': 'unit',
    'category': 'Type',
    'syntax': [
      'value unit',
      'unit(value, unit)',
      'unit(string)'
    ],
    'description':
        'Create a unit.',
    'examples': [
      '5.5 mm',
      '3 inch',
      'unit(7.1, "kilogram")',
      'unit("23 deg")'
    ],
    'seealso': [
      'bignumber', 'boolean', 'complex', 'index', 'matrix', 'number', 'string'
    ]
  };
  
  },{}],63:[function(require,module,exports){
  module.exports = {
    'name': 'eval',
    'category': 'Expression',
    'syntax': [
      'eval(expression)',
      'eval([expr1, expr2, expr3, ...])'
    ],
    'description': 'Evaluate an expression or an array with expressions.',
    'examples': [
      'eval("2 + 3")',
      'eval("sqrt(" + 4 + ")")'
    ],
    'seealso': []
  };
  
  },{}],64:[function(require,module,exports){
  module.exports = {
    'name': 'help',
    'category': 'Expression',
    'syntax': [
      'help(object)',
      'help(string)'
    ],
    'description': 'Display documentation on a function or data type.',
    'examples': [
      'help(sqrt)',
      'help("complex")'
    ],
    'seealso': []
  };
  
  },{}],65:[function(require,module,exports){
  module.exports = {
    'name': 'concat',
    'category': 'Matrix',
    'syntax': [
      'concat(a, b, c, ...)',
      'concat(a, b, c, ..., dim)'
    ],
    'description': 'Concatenate matrices. By default, the matrices are concatenated by the first dimension. The dimension on which to concatenate can be provided as last argument.',
    'examples': [
      'a = [1, 2; 5, 6]',
      'b = [3, 4; 7, 8]',
      'concat(a, b)',
      '[a, b]',
      'concat(a, b, 2)',
      '[a; b]'
    ],
    'seealso': [
      'det', 'diag', 'eye', 'inv', 'ones', 'range', 'size', 'squeeze', 'subset', 'transpose', 'zeros'
    ]
  };
  
  },{}],66:[function(require,module,exports){
  module.exports = {
    'name': 'det',
    'category': 'Matrix',
    'syntax': [
      'det(x)'
    ],
    'description': 'Calculate the determinant of a matrix',
    'examples': [
      'det([1, 2; 3, 4])',
      'det([-2, 2, 3; -1, 1, 3; 2, 0, -1])'
    ],
    'seealso': [
      'concat', 'diag', 'eye', 'inv', 'ones', 'range', 'size', 'squeeze', 'subset', 'transpose', 'zeros'
    ]
  };
  
  },{}],67:[function(require,module,exports){
  module.exports = {
    'name': 'diag',
    'category': 'Matrix',
    'syntax': [
      'diag(x)',
      'diag(x, k)'
    ],
    'description': 'Create a diagonal matrix or retrieve the diagonal of a matrix. When x is a vector, a matrix with the vector values on the diagonal will be returned. When x is a matrix, a vector with the diagonal values of the matrix is returned.When k is provided, the k-th diagonal will be filled in or retrieved, if k is positive, the values are placed on the super diagonal. When k is negative, the values are placed on the sub diagonal.',
    'examples': [
      'diag(1:3)',
      'diag(1:3, 1)',
      'a = [1, 2, 3; 4, 5, 6; 7, 8, 9]',
      'diag(a)'
    ],
    'seealso': [
      'concat', 'det', 'eye', 'inv', 'ones', 'range', 'size', 'squeeze', 'subset', 'transpose', 'zeros'
    ]
  };
  
  },{}],68:[function(require,module,exports){
  module.exports = {
    'name': 'eye',
    'category': 'Matrix',
    'syntax': [
      'eye(n)',
      'eye(m, n)',
      'eye([m, n])',
      'eye'
    ],
    'description': 'Returns the identity matrix with size m-by-n. The matrix has ones on the diagonal and zeros elsewhere.',
    'examples': [
      'eye(3)',
      'eye(3, 5)',
      'a = [1, 2, 3; 4, 5, 6]',
      'eye(size(a))'
    ],
    'seealso': [
      'concat', 'det', 'diag', 'inv', 'ones', 'range', 'size', 'squeeze', 'subset', 'transpose', 'zeros'
    ]
  };
  
  },{}],69:[function(require,module,exports){
  module.exports = {
    'name': 'inv',
    'category': 'Matrix',
    'syntax': [
      'inv(x)'
    ],
    'description': 'Calculate the inverse of a matrix',
    'examples': [
      'inv([1, 2; 3, 4])',
      'inv(4)',
      '1 / 4'
    ],
    'seealso': [
      'concat', 'det', 'diag', 'eye', 'ones', 'range', 'size', 'squeeze', 'subset', 'transpose', 'zeros'
    ]
  };
  
  },{}],70:[function(require,module,exports){
  module.exports = {
    'name': 'ones',
    'category': 'Matrix',
    'syntax': [
      'ones(m)',
      'ones(m, n)',
      'ones(m, n, p, ...)',
      'ones([m])',
      'ones([m, n])',
      'ones([m, n, p, ...])',
      'ones'
    ],
    'description': 'Create a matrix containing ones.',
    'examples': [
      'ones(3)',
      'ones(3, 5)',
      'ones([2,3]) * 4.5',
      'a = [1, 2, 3; 4, 5, 6]',
      'ones(size(a))'
    ],
    'seealso': [
      'concat', 'det', 'diag', 'eye', 'inv', 'range', 'size', 'squeeze', 'subset', 'transpose', 'zeros'
    ]
  };
  
  },{}],71:[function(require,module,exports){
  module.exports = {
    'name': 'range',
    'category': 'Type',
    'syntax': [
      'start:end',
      'start:step:end',
      'range(start, end)',
      'range(start, end, step)',
      'range(string)'
    ],
    'description':
        'Create a range. Lower bound of the range is included, upper bound is excluded.',
    'examples': [
      '1:5',
      '3:-1:-3',
      'range(3, 7)',
      'range(0, 12, 2)',
      'range("4:10")',
      'a = [1, 2, 3, 4; 5, 6, 7, 8]',
      'a(1:2, 1:2)'
    ],
    'seealso': [
      'concat', 'det', 'diag', 'eye', 'inv', 'ones', 'size', 'squeeze', 'subset', 'transpose', 'zeros'
    ]
  };
  
  },{}],72:[function(require,module,exports){
  module.exports = {
    'name': 'resize',
    'category': 'Matrix',
    'syntax': [
      'resize(x, size)',
      'resize(x, size, defaultValue)'
    ],
    'description': 'Resize a matrix.',
    'examples': [
      'resize([1,2,3,4,5], [3])',
      'resize([1,2,3], [5], 0)',
      'resize(2, [2, 3], 0)',
      'resize("hello", [8], "!")'
    ],
    'seealso': [
      'size', 'subset', 'squeeze'
    ]
  };
  
  },{}],73:[function(require,module,exports){
  module.exports = {
    'name': 'size',
    'category': 'Matrix',
    'syntax': [
      'size(x)'
    ],
    'description': 'Calculate the size of a matrix.',
    'examples': [
      'size(2.3)',
      'size("hello world")',
      'a = [1, 2; 3, 4; 5, 6]',
      'size(a)',
      'size(1:6)'
    ],
    'seealso': [
      'concat', 'det', 'diag', 'eye', 'inv', 'ones', 'range', 'squeeze', 'subset', 'transpose', 'zeros'
    ]
  };
  
  },{}],74:[function(require,module,exports){
  module.exports = {
    'name': 'squeeze',
    'category': 'Matrix',
    'syntax': [
      'squeeze(x)'
    ],
    'description': 'Remove singleton dimensions from a matrix.',
    'examples': [
      'a = zeros(1,3,2)',
      'size(squeeze(a))',
      'b = zeros(3,1,1)',
      'size(squeeze(b))'
    ],
    'seealso': [
      'concat', 'det', 'diag', 'eye', 'inv', 'ones', 'range', 'size', 'subset', 'transpose', 'zeros'
    ]
  };
  
  },{}],75:[function(require,module,exports){
  module.exports = {
    'name': 'subset',
    'category': 'Matrix',
    'syntax': [
      'value(index)',
      'value(index) = replacement',
      'subset(value, [index])',
      'subset(value, [index], replacement)'
    ],
    'description': 'Get or set a subset of a matrix or string. ' +
        'Indexes are one-based. ' +
        'Both the ranges lower-bound and upper-bound are included.',
    'examples': [
      'd = [1, 2; 3, 4]',
      'e = []',
      'e(1, 1:2) = [5, 6]',
      'e(2, :) = [7, 8]',
      'f = d * e',
      'f(2, 1)',
      'f(:, 1)'
    ],
    'seealso': [
      'concat', 'det', 'diag', 'eye', 'inv', 'ones', 'range', 'size', 'squeeze', 'transpose', 'zeros'
    ]
  };
  
  },{}],76:[function(require,module,exports){
  module.exports = {
    'name': 'transpose',
    'category': 'Matrix',
    'syntax': [
      'x\'',
      'transpose(x)'
    ],
    'description': 'Transpose a matrix',
    'examples': [
      'a = [1, 2, 3; 4, 5, 6]',
      'a\'',
      'transpose(a)'
    ],
    'seealso': [
      'concat', 'det', 'diag', 'eye', 'inv', 'ones', 'range', 'size', 'squeeze', 'subset', 'zeros'
    ]
  };
  
  },{}],77:[function(require,module,exports){
  module.exports = {
    'name': 'zeros',
    'category': 'Matrix',
    'syntax': [
      'zeros(m)',
      'zeros(m, n)',
      'zeros(m, n, p, ...)',
      'zeros([m])',
      'zeros([m, n])',
      'zeros([m, n, p, ...])',
      'zeros'
    ],
    'description': 'Create a matrix containing zeros.',
    'examples': [
      'zeros(3)',
      'zeros(3, 5)',
      'a = [1, 2, 3; 4, 5, 6]',
      'zeros(size(a))'
    ],
    'seealso': [
      'concat', 'det', 'diag', 'eye', 'inv', 'ones', 'range', 'size', 'squeeze', 'subset', 'transpose'
    ]
  };
  
  },{}],78:[function(require,module,exports){
  module.exports = {
    'name': 'distribution',
    'category': 'Probability',
    'syntax': [
      'distribution(name)',
      'distribution(name, arg1, arg2, ...)'
    ],
    'description':
        'Create a distribution object of a specific type. ' +
            'A distribution object contains functions `random([size,] [min,] [max])`, ' +
            '`randomInt([size,] [min,] [max])`, and `pickRandom(array)`. ' +
            'Available types of distributions: "uniform", "normal". ' +
            'Note that the function distribution is currently not available via the expression parser.',
    'examples': [
    ],
    'seealso': ['random', 'randomInt']
  };
  
  },{}],79:[function(require,module,exports){
  module.exports = {
    'name': 'factorial',
    'category': 'Probability',
    'syntax': [
      'x!',
      'factorial(x)'
    ],
    'description': 'Compute the factorial of a value',
    'examples': [
      '5!',
      '5*4*3*2*1',
      '3!'
    ],
    'seealso': []
  };
  
  },{}],80:[function(require,module,exports){
  module.exports = {
    'name': 'pickRandom',
    'category': 'Probability',
    'syntax': [
      'pickRandom(array)'
    ],
    'description':
        'Pick a random entry from a given array.',
    'examples': [
      'pickRandom(0:10)',
      'pickRandom([1, 3, 1, 6])'
    ],
    'seealso': ['distribution', 'random', 'randomInt']
  };
  
  },{}],81:[function(require,module,exports){
  module.exports = {
    'name': 'random',
    'category': 'Probability',
    'syntax': [
      'random()',
      'random(max)',
      'random(min, max)',
      'random(size)',
      'random(size, max)',
      'random(size, min, max)'
    ],
    'description':
        'Return a random number.',
    'examples': [
      'random()',
      'random(10, 20)',
      'random([2, 3])'
    ],
    'seealso': ['distribution', 'pickRandom', 'randomInt']
  };
  
  },{}],82:[function(require,module,exports){
  module.exports = {
    'name': 'randInt',
    'category': 'Probability',
    'syntax': [
      'randInt()',
      'randInt(max)',
      'randInt(min, max)',
      'randInt(size)',
      'randInt(size, max)',
      'randInt(size, min, max)'
    ],
    'description':
        'Return a random integer number',
    'examples': [
      'randInt()',
      'randInt(10, 20)',
      'randInt([2, 3], 10)'
    ],
    'seealso': ['distribution', 'pickRandom', 'random']
  };
  },{}],83:[function(require,module,exports){
  module.exports = {
    'name': 'max',
    'category': 'Statistics',
    'syntax': [
      'max(a, b, c, ...)',
      'max(A)',
      'max(A, dim)'
    ],
    'description': 'Compute the maximum value of a list of values.',
    'examples': [
      'max(2, 3, 4, 1)',
      'max([2, 3, 4, 1])',
      'max([2, 5; 4, 3], 0)',
      'max([2, 5; 4, 3], 1)',
      'max(2.7, 7.1, -4.5, 2.0, 4.1)',
      'min(2.7, 7.1, -4.5, 2.0, 4.1)'
    ],
    'seealso': [
      //'sum',
      //'prod',
      //'avg',
      //'var',
      //'std',
      'mean',
      //'median',
      'min'
    ]
  };
  
  },{}],84:[function(require,module,exports){
  module.exports = {
    'name': 'mean',
    'category': 'Statistics',
    'syntax': [
      'mean(a, b, c, ...)',
      'mean(A)',
      'mean(A, dim)'
    ],
    'description': 'Compute the arithmetic mean of a list of values.',
    'examples': [
      'mean(2, 3, 4, 1)',
      'mean([2, 3, 4, 1])',
      'mean([2, 5; 4, 3], 0)',
      'mean([2, 5; 4, 3], 1)',
      'mean([1.0, 2.7, 3.2, 4.0])'
    ],
    'seealso': [
      //'sum',
      //'prod',
      //'avg',
      //'var',
      //'std',
  	  'max',
      'min'
      //'median'
    ]
  };
  
  },{}],85:[function(require,module,exports){
  module.exports = {
    'name': 'min',
    'category': 'Statistics',
    'syntax': [
      'min(a, b, c, ...)',
      'min(A)',
      'min(A, dim)'
    ],
    'description': 'Compute the minimum value of a list of values.',
    'examples': [
      'min(2, 3, 4, 1)',
      'min([2, 3, 4, 1])',
      'min([2, 5; 4, 3], 0)',
      'min([2, 5; 4, 3], 1)',
      'min(2.7, 7.1, -4.5, 2.0, 4.1)',
      'max(2.7, 7.1, -4.5, 2.0, 4.1)'
    ],
    'seealso': [
      //'sum',
      //'prod',
      //'avg',
      //'var',
      //'std',
      'max',
      'mean',
      //'median',
      'min'
    ]
  };
  
  },{}],86:[function(require,module,exports){
  module.exports = {
    'name': 'acos',
    'category': 'Trigonometry',
    'syntax': [
      'acos(x)'
    ],
    'description': 'Compute the inverse cosine of a value in radians.',
    'examples': [
      'acos(0.5)',
      'acos(cos(2.3))'
    ],
    'seealso': [
      'cos',
      'acos',
      'asin'
    ]
  };
  
  },{}],87:[function(require,module,exports){
  module.exports = {
    'name': 'asin',
    'category': 'Trigonometry',
    'syntax': [
      'asin(x)'
    ],
    'description': 'Compute the inverse sine of a value in radians.',
    'examples': [
      'asin(0.5)',
      'asin(sin(2.3))'
    ],
    'seealso': [
      'sin',
      'acos',
      'asin'
    ]
  };
  
  },{}],88:[function(require,module,exports){
  module.exports = {
    'name': 'atan',
    'category': 'Trigonometry',
    'syntax': [
      'atan(x)'
    ],
    'description': 'Compute the inverse tangent of a value in radians.',
    'examples': [
      'atan(0.5)',
      'atan(tan(2.3))'
    ],
    'seealso': [
      'tan',
      'acos',
      'asin'
    ]
  };
  
  },{}],89:[function(require,module,exports){
  module.exports = {
    'name': 'atan2',
    'category': 'Trigonometry',
    'syntax': [
      'atan2(y, x)'
    ],
    'description':
        'Computes the principal value of the arc tangent of y/x in radians.',
    'examples': [
      'atan2(2, 2) / pi',
      'angle = 60 deg in rad',
      'x = cos(angle)',
      'y = sin(angle)',
      'atan2(y, x)'
    ],
    'seealso': [
      'sin',
      'cos',
      'tan'
    ]
  };
  
  },{}],90:[function(require,module,exports){
  module.exports = {
    'name': 'cos',
    'category': 'Trigonometry',
    'syntax': [
      'cos(x)'
    ],
    'description': 'Compute the cosine of x in radians.',
    'examples': [
      'cos(2)',
      'cos(pi / 4) ^ 2',
      'cos(180 deg)',
      'cos(60 deg)',
      'sin(0.2)^2 + cos(0.2)^2'
    ],
    'seealso': [
      'acos',
      'sin',
      'tan'
    ]
  };
  
  },{}],91:[function(require,module,exports){
  module.exports = {
    'name': 'cot',
    'category': 'Trigonometry',
    'syntax': [
      'cot(x)'
    ],
    'description': 'Compute the cotangent of x in radians. Defined as 1/tan(x)',
    'examples': [
      'cot(2)',
      '1 / tan(2)'
    ],
    'seealso': [
      'sec',
      'csc',
      'tan'
    ]
  };
  
  },{}],92:[function(require,module,exports){
  module.exports = {
    'name': 'csc',
    'category': 'Trigonometry',
    'syntax': [
      'csc(x)'
    ],
    'description': 'Compute the cosecant of x in radians. Defined as 1/sin(x)',
    'examples': [
      'csc(2)',
      '1 / sin(2)'
    ],
    'seealso': [
      'sec',
      'cot',
      'sin'
    ]
  };
  
  },{}],93:[function(require,module,exports){
  module.exports = {
    'name': 'sec',
    'category': 'Trigonometry',
    'syntax': [
      'sec(x)'
    ],
    'description': 'Compute the secant of x in radians. Defined as 1/cos(x)',
    'examples': [
      'sec(2)',
      '1 / cos(2)'
    ],
    'seealso': [
      'cot',
      'csc',
      'cos'
    ]
  };
  
  },{}],94:[function(require,module,exports){
  module.exports = {
    'name': 'sin',
    'category': 'Trigonometry',
    'syntax': [
      'sin(x)'
    ],
    'description': 'Compute the sine of x in radians.',
    'examples': [
      'sin(2)',
      'sin(pi / 4) ^ 2',
      'sin(90 deg)',
      'sin(30 deg)',
      'sin(0.2)^2 + cos(0.2)^2'
    ],
    'seealso': [
      'asin',
      'cos',
      'tan'
    ]
  };
  
  },{}],95:[function(require,module,exports){
  module.exports = {
    'name': 'tan',
    'category': 'Trigonometry',
    'syntax': [
      'tan(x)'
    ],
    'description': 'Compute the tangent of x in radians.',
    'examples': [
      'tan(0.5)',
      'sin(0.5) / cos(0.5)',
      'tan(pi / 4)',
      'tan(45 deg)'
    ],
    'seealso': [
      'atan',
      'sin',
      'cos'
    ]
  };
  
  },{}],96:[function(require,module,exports){
  module.exports = {
    'name': 'in',
    'category': 'Units',
    'syntax': [
      'x in unit',
      'in(x, unit)'
    ],
    'description': 'Change the unit of a value.',
    'examples': [
      '5 inch in cm',
      '3.2kg in g',
      '16 bytes in bits'
    ],
    'seealso': []
  };
  
  },{}],97:[function(require,module,exports){
  module.exports = {
    'name': 'clone',
    'category': 'Utils',
    'syntax': [
      'clone(x)'
    ],
    'description': 'Clone a variable. Creates a copy of primitive variables,and a deep copy of matrices',
    'examples': [
      'clone(3.5)',
      'clone(2 - 4i)',
      'clone(45 deg)',
      'clone([1, 2; 3, 4])',
      'clone("hello world")'
    ],
    'seealso': []
  };
  
  },{}],98:[function(require,module,exports){
  module.exports = {
    'name': 'forEach',
    'category': 'Utils',
    'syntax': [
      'forEach(x, callback)'
    ],
    'description': 'Iterates over all elements of a matrix/array, and executes the given callback.',
    'examples': [
      'forEach([1, 2, 3], function(val) { console.log(val) })'
    ],
    'seealso': []
  };
  
  },{}],99:[function(require,module,exports){
  module.exports = {
    'name': 'format',
    'category': 'Utils',
    'syntax': [
      'format(value)',
      'format(value, precision)'
    ],
    'description': 'Format a value of any type as string.',
    'examples': [
      'format(2.3)',
      'format(3 - 4i)',
      'format([])',
      'format(pi, 3)'
    ],
    'seealso': ['print']
  };
  
  },{}],100:[function(require,module,exports){
  module.exports = {
    'name': 'import',
    'category': 'Utils',
    'syntax': [
      'import(string)'
    ],
    'description': 'Import functions from a file.',
    'examples': [
      'import("numbers")',
      'import("./mylib.js")'
    ],
    'seealso': []
  };
  
  },{}],101:[function(require,module,exports){
  module.exports = {
    'name': 'map',
    'category': 'Utils',
    'syntax': [
      'map(x, callback)'
    ],
    'description': 'Create a new matrix or array with the results of the callback function executed on each entry of the matrix/array.',
    'examples': [
      'map([1, 2, 3], function(val) { return math.max(val, 1.5) })'
    ],
    'seealso': []
  };
  
  },{}],102:[function(require,module,exports){
  module.exports = {
    'name': 'typeof',
    'category': 'Utils',
    'syntax': [
      'typeof(x)'
    ],
    'description': 'Get the type of a variable.',
    'examples': [
      'typeof(3.5)',
      'typeof(2 - 4i)',
      'typeof(45 deg)',
      'typeof("hello world")'
    ],
    'seealso': []
  };
  
  },{}],103:[function(require,module,exports){
  // constants
  exports.e = require('./constants/e');
  exports.E = require('./constants/e');
  exports['false'] = require('./constants/false');
  exports.i = require('./constants/i');
  exports['Infinity'] = require('./constants/Infinity');
  exports.LN2 = require('./constants/LN2');
  exports.LN10 = require('./constants/LN10');
  exports.LOG2E = require('./constants/LOG2E');
  exports.LOG10E = require('./constants/LOG10E');
  exports.NaN = require('./constants/NaN');
  exports.pi = require('./constants/pi');
  exports.PI = require('./constants/pi');
  exports.SQRT1_2 = require('./constants/SQRT1_2');
  exports.SQRT2 = require('./constants/SQRT2');
  exports.tau = require('./constants/tau');
  exports['true'] = require('./constants/true');
  
  // functions - arithmetic
  exports.abs = require('./function/arithmetic/abs');
  exports.add = require('./function/arithmetic/add');
  exports.ceil = require('./function/arithmetic/ceil');
  exports.cube = require('./function/arithmetic/cube');
  exports.divide = require('./function/arithmetic/divide');
  exports.edivide = require('./function/arithmetic/edivide');
  exports.emultiply = require('./function/arithmetic/emultiply');
  exports.epow = require('./function/arithmetic/epow');
  exports.equal = require('./function/arithmetic/equal');
  exports.exp = require('./function/arithmetic/exp');
  exports.fix = require('./function/arithmetic/fix');
  exports.floor = require('./function/arithmetic/floor');
  exports.gcd = require('./function/arithmetic/gcd');
  exports.larger = require('./function/arithmetic/larger');
  exports.largereq = require('./function/arithmetic/largereq');
  exports.lcm = require('./function/arithmetic/lcm');
  exports.log = require('./function/arithmetic/log');
  exports.log10 = require('./function/arithmetic/log10');
  exports.mod = require('./function/arithmetic/mod');
  exports.multiply = require('./function/arithmetic/multiply');
  exports.pow = require('./function/arithmetic/pow');
  exports.round = require('./function/arithmetic/round');
  exports.sign = require('./function/arithmetic/sign');
  exports.smaller = require('./function/arithmetic/smaller');
  exports.smallereq = require('./function/arithmetic/smallereq');
  exports.sqrt = require('./function/arithmetic/sqrt');
  exports.square = require('./function/arithmetic/square');
  exports.subtract = require('./function/arithmetic/subtract');
  exports.unary = require('./function/arithmetic/unary');
  exports.unequal = require('./function/arithmetic/unequal');
  exports.xgcd = require('./function/arithmetic/xgcd');
  
  // functions - complex
  exports.arg = require('./function/complex/arg');
  exports.conj = require('./function/complex/conj');
  exports.re = require('./function/complex/re');
  exports.im = require('./function/complex/im');
  
  // functions - construction
  exports.bignumber = require('./function/construction/bignumber');
  exports['boolean'] = require('./function/construction/boolean');
  exports.complex = require('./function/construction/complex');
  exports.index = require('./function/construction/index');
  exports.matrix = require('./function/construction/matrix');
  exports.number = require('./function/construction/number');
  exports.string = require('./function/construction/string');
  exports.unit = require('./function/construction/unit');
  
  // functions - epxression
  exports['eval'] =  require('./function/expression/eval');
  exports.help =  require('./function/expression/help');
  
  // functions - matrix
  exports.concat = require('./function/matrix/concat');
  exports.det = require('./function/matrix/det');
  exports.diag = require('./function/matrix/diag');
  exports.eye = require('./function/matrix/eye');
  exports.inv = require('./function/matrix/inv');
  exports.ones = require('./function/matrix/ones');
  exports.range = require('./function/matrix/range');
  exports.resize = require('./function/matrix/resize');
  exports.size = require('./function/matrix/size');
  exports.squeeze = require('./function/matrix/squeeze');
  exports.subset = require('./function/matrix/subset');
  exports.transpose = require('./function/matrix/transpose');
  exports.zeros = require('./function/matrix/zeros');
  
  // functions - probability
  exports.factorial = require('./function/probability/factorial');
  exports.distribution = require('./function/probability/distribution');
  exports.pickRandom = require('./function/probability/pickRandom');
  exports.random = require('./function/probability/random');
  exports.randomInt = require('./function/probability/randomInt');
  
  // functions - statistics
  exports.min = require('./function/statistics/min');
  exports.mean = require('./function/statistics/mean');
  exports.max = require('./function/statistics/max');
  
  // functions - trigonometry
  exports.acos = require('./function/trigonometry/acos');
  exports.asin = require('./function/trigonometry/asin');
  exports.atan = require('./function/trigonometry/atan');
  exports.atan2 = require('./function/trigonometry/atan2');
  exports.cos = require('./function/trigonometry/cos');
  exports.cot = require('./function/trigonometry/cot');
  exports.csc = require('./function/trigonometry/csc');
  exports.sec = require('./function/trigonometry/sec');
  exports.sin = require('./function/trigonometry/sin');
  exports.tan = require('./function/trigonometry/tan');
  
  // functions - units
  exports['in'] = require('./function/units/in');
  
  // functions - utils
  exports.clone =  require('./function/utils/clone');
  exports.map =  require('./function/utils/map');
  exports.forEach =  require('./function/utils/forEach');
  exports.format =  require('./function/utils/format');
  // exports.print =  require('./function/utils/print'); // TODO: add documentation for print as soon as the parser supports objects.
  exports['import'] =  require('./function/utils/import');
  exports['typeof'] =  require('./function/utils/typeof');
  
  },{"./constants/Infinity":6,"./constants/LN10":7,"./constants/LN2":8,"./constants/LOG10E":9,"./constants/LOG2E":10,"./constants/NaN":11,"./constants/SQRT1_2":12,"./constants/SQRT2":13,"./constants/e":14,"./constants/false":15,"./constants/i":16,"./constants/pi":17,"./constants/tau":18,"./constants/true":19,"./function/arithmetic/abs":20,"./function/arithmetic/add":21,"./function/arithmetic/ceil":22,"./function/arithmetic/cube":23,"./function/arithmetic/divide":24,"./function/arithmetic/edivide":25,"./function/arithmetic/emultiply":26,"./function/arithmetic/epow":27,"./function/arithmetic/equal":28,"./function/arithmetic/exp":29,"./function/arithmetic/fix":30,"./function/arithmetic/floor":31,"./function/arithmetic/gcd":32,"./function/arithmetic/larger":33,"./function/arithmetic/largereq":34,"./function/arithmetic/lcm":35,"./function/arithmetic/log":36,"./function/arithmetic/log10":37,"./function/arithmetic/mod":38,"./function/arithmetic/multiply":39,"./function/arithmetic/pow":40,"./function/arithmetic/round":41,"./function/arithmetic/sign":42,"./function/arithmetic/smaller":43,"./function/arithmetic/smallereq":44,"./function/arithmetic/sqrt":45,"./function/arithmetic/square":46,"./function/arithmetic/subtract":47,"./function/arithmetic/unary":48,"./function/arithmetic/unequal":49,"./function/arithmetic/xgcd":50,"./function/complex/arg":51,"./function/complex/conj":52,"./function/complex/im":53,"./function/complex/re":54,"./function/construction/bignumber":55,"./function/construction/boolean":56,"./function/construction/complex":57,"./function/construction/index":58,"./function/construction/matrix":59,"./function/construction/number":60,"./function/construction/string":61,"./function/construction/unit":62,"./function/expression/eval":63,"./function/expression/help":64,"./function/matrix/concat":65,"./function/matrix/det":66,"./function/matrix/diag":67,"./function/matrix/eye":68,"./function/matrix/inv":69,"./function/matrix/ones":70,"./function/matrix/range":71,"./function/matrix/resize":72,"./function/matrix/size":73,"./function/matrix/squeeze":74,"./function/matrix/subset":75,"./function/matrix/transpose":76,"./function/matrix/zeros":77,"./function/probability/distribution":78,"./function/probability/factorial":79,"./function/probability/pickRandom":80,"./function/probability/random":81,"./function/probability/randomInt":82,"./function/statistics/max":83,"./function/statistics/mean":84,"./function/statistics/min":85,"./function/trigonometry/acos":86,"./function/trigonometry/asin":87,"./function/trigonometry/atan":88,"./function/trigonometry/atan2":89,"./function/trigonometry/cos":90,"./function/trigonometry/cot":91,"./function/trigonometry/csc":92,"./function/trigonometry/sec":93,"./function/trigonometry/sin":94,"./function/trigonometry/tan":95,"./function/units/in":96,"./function/utils/clone":97,"./function/utils/forEach":98,"./function/utils/format":99,"./function/utils/import":100,"./function/utils/map":101,"./function/utils/typeof":102}],104:[function(require,module,exports){
  var Node = require('./Node'),
      object = require('../../util/object'),
      string = require('../../util/string'),
      collection = require('../../type/collection'),
      Matrix = require('../../type/Matrix');
  
  /**
   * @constructor ArrayNode
   * Holds an 1-dimensional array with nodes
   * @param {Object} settings Object with the math.js configuration settings
   * @param {Array} nodes    1 dimensional array with nodes
   * @extends {Node}
   */
  function ArrayNode(settings, nodes) {
    this.settings = settings; // math.js settings
    this.nodes = nodes || [];
  }
  
  ArrayNode.prototype = new Node();
  
  /**
   * Evaluate the array
   * @return {Matrix | Array} results
   * @override
   */
  ArrayNode.prototype.eval = function() {
    // evaluate all nodes in the array, and merge the results into a matrix
    var nodes = this.nodes,
        results = [];
  
    for (var i = 0, ii = nodes.length; i < ii; i++) {
      var node = nodes[i];
      var result = node.eval();
      results[i] = (result instanceof Matrix) ? result.valueOf() : result;
    }
  
    return (this.settings.matrix === 'array') ? results : new Matrix(results);
  };
  
  /**
   * Find all nodes matching given filter
   * @param {Object} filter  See Node.find for a description of the filter settings
   * @returns {Node[]} nodes
   */
  ArrayNode.prototype.find = function (filter) {
    var results = [];
  
    // check itself
    if (this.match(filter)) {
      results.push(this);
    }
  
    // search in all nodes
    var nodes = this.nodes;
    for (var r = 0, rows = nodes.length; r < rows; r++) {
      var nodes_r = nodes[r];
      for (var c = 0, cols = nodes_r.length; c < cols; c++) {
        results = results.concat(nodes_r[c].find(filter));
      }
    }
  
    return results;
  };
  
  /**
   * Get string representation
   * @return {String} str
   * @override
   */
  ArrayNode.prototype.toString = function() {
    return string.format(this.nodes);
  };
  
  module.exports = ArrayNode;
  
  },{"../../type/Matrix":206,"../../type/collection":209,"../../util/object":215,"../../util/string":216,"./Node":109}],105:[function(require,module,exports){
  var Node = require('./Node');
  
  /**
   * @constructor AssignmentNode
   * Define a symbol, like "a = 3.2"
   *
   * @param {String} name       Symbol name
   * @param {Node} expr         The expression defining the symbol
   * @param {Scope} scope       Scope to store the result
   */
  function AssignmentNode(name, expr, scope) {
    this.name = name;
    this.expr = expr;
    this.scope = scope;
  }
  
  AssignmentNode.prototype = new Node();
  
  /**
   * Evaluate the assignment
   * @return {*} result
   */
  AssignmentNode.prototype.eval = function() {
    if (this.expr === undefined) {
      throw new Error('Undefined symbol ' + this.name);
    }
  
    var result = this.expr.eval();
    this.scope.set(this.name, result);
  
    return result;
  };
  
  /**
   * Find all nodes matching given filter
   * @param {Object} filter  See Node.find for a description of the filter settings
   * @returns {Node[]} nodes
   */
  AssignmentNode.prototype.find = function (filter) {
    var nodes = [];
  
    // check itself
    if (this.match(filter)) {
      nodes.push(this);
    }
  
    // search in expression
    if (this.expr) {
      nodes = nodes.concat(this.expr.find(filter));
    }
  
    return nodes;
  };
  
  /**
   * Get string representation
   * @return {String}
   */
  AssignmentNode.prototype.toString = function() {
    return this.name + ' = ' + this.expr.toString();
  };
  
  module.exports = AssignmentNode;
  },{"./Node":109}],106:[function(require,module,exports){
  var Node = require('./Node');
  
  /**
   * @constructor BlockNode
   * Holds a set with nodes
   * @extends {Node}
   */
  function BlockNode() {
    this.params = [];
    this.visible = [];
  }
  
  BlockNode.prototype = new Node();
  
  /**
   * Add a parameter
   * @param {Node} param
   * @param {Boolean} [visible]   true by default
   */
  BlockNode.prototype.add = function (param, visible) {
    var index = this.params.length;
    this.params[index] = param;
    this.visible[index] = (visible != undefined) ? visible : true;
  };
  
  /**
   * Evaluate the set
   * @return {*[]} results
   * @override
   */
  BlockNode.prototype.eval = function() {
    // evaluate the parameters
    var results = [];
    for (var i = 0, iMax = this.params.length; i < iMax; i++) {
      var result = this.params[i].eval();
      if (this.visible[i]) {
        results.push(result);
      }
    }
  
    return results;
  };
  
  /**
   * Find all nodes matching given filter
   * @param {Object} filter  See Node.find for a description of the filter settings
   * @returns {Node[]} nodes
   */
  BlockNode.prototype.find = function (filter) {
    var nodes = [];
  
    // check itself
    if (this.match(filter)) {
      nodes.push(this);
    }
  
    // search in parameters
    var params = this.params;
    if (params) {
      for (var i = 0, len = params.length; i < len; i++) {
        nodes = nodes.concat(params[i].find(filter));
      }
    }
  
    return nodes;
  };
  
  /**
   * Get string representation
   * @return {String} str
   * @override
   */
  BlockNode.prototype.toString = function() {
    var strings = [];
  
    for (var i = 0, iMax = this.params.length; i < iMax; i++) {
      if (this.visible[i]) {
        strings.push('\n  ' + this.params[i].toString());
      }
    }
  
    return '[' + strings.join(',') + '\n]';
  };
  
  module.exports = BlockNode;
  
  },{"./Node":109}],107:[function(require,module,exports){
  var Node = require('./Node'),
      string = require('../../util/string');
  
  /**
   * @constructor ConstantNode
   * @param {*} value
   * @extends {Node}
   */
  function ConstantNode(value) {
    this.value = value;
  }
  
  ConstantNode.prototype = new Node();
  
  /**
   * Evaluate the constant (just return it)
   * @return {*} value
   */
  ConstantNode.prototype.eval = function () {
    return this.value;
  };
  
  /**
   * Get string representation
   * @return {String} str
   */
  ConstantNode.prototype.toString = function() {
    return string.format(this.value);
  };
  
  module.exports = ConstantNode;
  
  },{"../../util/string":216,"./Node":109}],108:[function(require,module,exports){
  var Node = require('./Node');
  
  /**
   * @constructor FunctionNode
   * Function assignment
   *
   * @param {String} name           Function name
   * @param {String[]} variables    Variable names
   * @param {Node} expr             The function expression
   * @param {Scope} functionScope   Scope in which to write variable values
   * @param {Scope} scope           Scope to store the resulting function assignment
   */
  function FunctionNode(name, variables, expr, functionScope, scope) {
    this.name = name;
    this.variables = variables;
    this.expr = expr;
    this.scope = scope;
  
    // create function
    this.fn = function () {
      var num = variables ? variables.length : 0;
  
      // validate correct number of arguments
      if (arguments.length != num) {
        throw new SyntaxError('Wrong number of arguments in function ' + name +
            ' (' + arguments.length + ' provided, ' + num + ' expected)');
      }
  
      // fill in the provided arguments in the functionScope variables
      for (var i = 0; i < num; i++) {
        functionScope.set(variables[i], arguments[i]);
      }
  
      // evaluate the expression
      return expr.eval();
    };
  
    // add a field describing the function syntax
    this.fn.syntax = name + '(' + variables.join(', ') + ')';
  }
  
  FunctionNode.prototype = new Node();
  
  /**
   * Evaluate the function assignment
   * @return {function} fn
   */
  FunctionNode.prototype.eval = function() {
    // put the definition in the scope
    this.scope.set(this.name, this.fn);
  
    return this.fn;
  };
  
  /**
   * Find all nodes matching given filter
   * @param {Object} filter  See Node.find for a description of the filter settings
   * @returns {Node[]} nodes
   */
  FunctionNode.prototype.find = function (filter) {
    var nodes = [];
  
    // check itself
    if (this.match(filter)) {
      nodes.push(this);
    }
  
    // search in expression
    if (this.expr) {
      nodes = nodes.concat(this.expr.find(filter));
    }
  
    return nodes;
  };
  
  /**
   * get string representation
   * @return {String} str
   */
  FunctionNode.prototype.toString = function() {
    return this.fn.description;
  };
  
  module.exports = FunctionNode;
  
  },{"./Node":109}],109:[function(require,module,exports){
  /**
   * Node
   */
  function Node() {}
  
  /**
   * Evaluate the node
   * @return {*} result
   */
  Node.prototype.eval = function () {
    throw new Error('Cannot evaluate a Node interface');
  };
  
  /**
   * Find any node in the node tree matching given filter. For example, to
   * find all nodes of type SymbolNode having name 'x':
   *
   *     var results = Node.find({
   *         type: SymbolNode,
   *         properties: {
   *             name: 'x'
   *         }
   *     });
   *
   * @param {Object} filter       Available parameters:
   *                                  {Function} type
   *                                  {Object<String, String>} properties
   * @return {Node[]} nodes       An array with nodes matching given filter criteria
   */
  Node.prototype.find = function (filter) {
    return this.match(filter) ? [this] : [];
  };
  
  /**
   * Test if this object matches given filter
   * @param {Object} filter       Available parameters:
   *                              {Function} type
   *                              {Object<String, String>} properties
   * @return {Boolean} matches    True if there is a match
   */
  Node.prototype.match = function (filter) {
    var match = true;
  
    if (filter) {
      if (filter.type && !(this instanceof filter.type)) {
        match = false;
      }
      if (match && filter.properties) {
        for (var prop in filter.properties) {
          if (filter.properties.hasOwnProperty(prop)) {
            if (this[prop] != filter.properties[prop]) {
              match = false;
              break;
            }
          }
        }
      }
    }
  
    return match;
  };
  
  /**
   * Get string representation
   * @return {String}
   */
  Node.prototype.toString = function() {
    return '';
  };
  
  module.exports = Node;
  
  },{}],110:[function(require,module,exports){
  var Node = require('./Node');
  
  /**
   * @constructor OperatorNode
   * An operator with two arguments, like 2+3
   * @param {String} name     Function name, for example '+'
   * @param {function} fn     Function, for example math.add
   * @param {Node[]} params   Parameters
   */
  function OperatorNode (name, fn, params) {
    this.name = name;
    this.fn = fn;
    this.params = params;
  }
  
  OperatorNode.prototype = new Node();
  
  /**
   * Evaluate the parameters
   * @return {*} result
   */
  OperatorNode.prototype.eval = function() {
    return this.fn.apply(this, this.params.map(function (param) {
      return param.eval();
    }));
  };
  
  /**
   * Find all nodes matching given filter
   * @param {Object} filter  See Node.find for a description of the filter settings
   * @returns {Node[]} nodes
   */
  OperatorNode.prototype.find = function (filter) {
    var nodes = [];
  
    // check itself
    if (this.match(filter)) {
      nodes.push(this);
    }
  
    // search in parameters
    var params = this.params;
    if (params) {
      for (var i = 0, len = params.length; i < len; i++) {
        nodes = nodes.concat(params[i].find(filter));
      }
    }
  
    return nodes;
  };
  
  /**
   * Get string representation
   * @return {String} str
   */
  OperatorNode.prototype.toString = function() {
    var params = this.params;
  
    switch (params.length) {
      case 1:
        if (this.name == '-') {
          // special case: unary minus
          return '-' + params[0].toString();
        }
        else {
          // for example '5!'
          return params[0].toString() + this.name;
        }
  
      case 2: // for example '2+3'
        var lhs = params[0].toString();
        if (params[0] instanceof OperatorNode) {
          lhs = '(' + lhs + ')';
        }
        var rhs = params[1].toString();
        if (params[1] instanceof OperatorNode) {
          rhs = '(' + rhs + ')';
        }
        return lhs + ' ' + this.name + ' ' + rhs;
  
      default: // this should occur. format as a function call
        return this.name + '(' + this.params.join(', ') + ')';
    }
  };
  
  module.exports = OperatorNode;
  
  },{"./Node":109}],111:[function(require,module,exports){
  var number= require('../../util/number'),
  
      Node = require('./Node'),
      RangeNode = require('./RangeNode'),
      SymbolNode = require('./SymbolNode'),
  
      BigNumber = require('bignumber.js'),
      Index = require('../../type/Index'),
      Range = require('../../type/Range'),
  
      isNumber = number.isNumber,
      toNumber = number.toNumber;
  
  /**
   * @constructor ParamsNode
   * invoke a list with parameters on the results of a node
   * @param {Object} math             The math namespace containing all functions
   * @param {Node} object
   * @param {Node[]} params
   * @param {Scope[]} paramScopes     A scope for every parameter, where the
   *                                  index variable 'end' can be defined.
   */
  function ParamsNode (math, object, params, paramScopes) {
    this.math = math;
  
    this.object = object;
    this.params = params;
    this.paramScopes = paramScopes;
  
    // check whether any of the params expressions uses the context symbol 'end'
    this.hasContextParams = false;
    if (params) {
      var filter = {
        type: SymbolNode,
        properties: {
          name: 'end'
        }
      };
  
      for (var i = 0, len = params.length; i < len; i++) {
        if (params[i].find(filter).length > 0) {
          this.hasContextParams = true;
          break;
        }
      }
    }
  }
  
  ParamsNode.prototype = new Node();
  
  /**
   * Evaluate the parameters
   * @return {*} result
   */
  ParamsNode.prototype.eval = function() {
    var i, len, params, results;
  
    // evaluate the object
    var object = this.object;
    if (object == undefined) {
      throw new Error ('Node undefined');
    }
    var obj = object.eval();
  
    // evaluate the values of context parameter 'end' when needed
    if (this.hasContextParams && typeof obj !== 'function') {
      var paramScopes = this.paramScopes,
          size = this.math.size(obj).valueOf();
  
      if (paramScopes && size) {
        for (i = 0, len = this.params.length; i < len; i++) {
          var paramScope = paramScopes[i];
          if (paramScope) {
            paramScope.set('end', size[i]);
          }
        }
      }
    }
  
    if (typeof obj === 'function') {
      // evaluate the parameters
      params = this.params;
      results = [];
      for (i = 0, len = this.params.length; i < len; i++) {
        results[i] = params[i].eval();
      }
  
      // invoke a function with the parameters
      return obj.apply(this, results);
    }
    else {
      // evaluate the parameters as index
      params = this.params;
      results = [];
      for (i = 0, len = this.params.length; i < len; i++) {
        var param = params[i];
        var result;
  
        if (param instanceof RangeNode) {
          result = param.toRange();
        }
        else {
          result = param.eval();
        }
  
        // convert big number to number
        if (result instanceof BigNumber) result = toNumber(result);
  
        // TODO: implement support for BigNumber
  
        // change from one-based to zero-based range
        if (result instanceof Range) {
          result.start --;
          result.end --;
        }
        else if (isNumber(result)) {
          // number
          result--;
        }
        else {
          throw new TypeError('Number or Range expected');
        }
  
        results[i] = result;
      }
  
      // get a subset of the object
      var index = Index.create(results);
      return this.math.subset(obj, index);
    }
  };
  
  /**
   * Find all nodes matching given filter
   * @param {Object} filter  See Node.find for a description of the filter settings
   * @returns {Node[]} nodes
   */
  ParamsNode.prototype.find = function (filter) {
    var nodes = [];
  
    // check itself
    if (this.match(filter)) {
      nodes.push(this);
    }
  
    // search object
    if (this.object) {
      nodes = nodes.concat(this.object.find(filter));
    }
  
    // search in parameters
    var params = this.params;
    if (params) {
      for (var i = 0, len = params.length; i < len; i++) {
        nodes = nodes.concat(params[i].find(filter));
      }
    }
  
    return nodes;
  };
  
  /**
   * Get string representation
   * @return {String} str
   */
  ParamsNode.prototype.toString = function() {
    // format the parameters like "(2, 4.2)"
    var str = this.object ? this.object.toString() : '';
    if (this.params) {
      str += '(' + this.params.join(', ') + ')';
    }
    return str;
  };
  
  module.exports = ParamsNode;
  
  },{"../../type/Index":205,"../../type/Range":207,"../../util/number":214,"./Node":109,"./RangeNode":112,"./SymbolNode":113,"bignumber.js":218}],112:[function(require,module,exports){
  var number = require('../../util/number'),
      Node = require('./Node'),
  
      BigNumber = require('bignumber.js'),
      Range = require('../../type/Range'),
      Matrix = require('../../type/Matrix'),
  
      toNumber = number.toNumber;
  
  /**
   * @constructor RangeNode
   * create a range
   * @param {Object} math             The math namespace containing all functions
   * @param {Object} settings         Settings of the math
   * @param {Node[]} params
   */
  function RangeNode (math, settings, params) {
    this.math = math;
    this.settings = settings;
  
    this.start = null;  // included lower-bound
    this.end = null;    // included upper-bound
    this.step = null;   // optional step
  
    if (params.length == 2) {
      this.start = params[0];
      this.end = params[1];
    }
    else if (params.length == 3) {
      this.start = params[0];
      this.step = params[1];
      this.end = params[2];
    }
    else {
      // TODO: better error message
      throw new SyntaxError('Wrong number of arguments');
    }
  }
  
  RangeNode.prototype = new Node();
  
  /**
   * Evaluate the range
   * @return {*} result
   */
  RangeNode.prototype.eval = function() {
    // evaluate the parameters
    var range = this._evalParams(),
        start = range.start,
        step = range.step,
        end = range.end;
  
    // generate the range (upper-bound included!)
    var array = [],
        x = start;
    if (step > 0) {
      while (x <= end) {
        array.push(x);
        x += step;
      }
    }
    else if (step < 0) {
      while (x >= end) {
        array.push(x);
        x += step;
      }
    }
  
    return (this.settings.matrix === 'array') ? array : new Matrix(array);
  };
  
  /**
   * Create a Range from a RangeNode
   * @return {Range} range
   */
  RangeNode.prototype.toRange = function() {
    // evaluate the parameters
    var range = this._evalParams(),
        start = range.start,
        step = range.step,
        end = range.end;
  
    // upper-bound be included, so compensate for that
    // NOTE: this only works for integer values!
    end = this.math.add(end, (step > 0) ? 1 : -1);
  
    // create the range
    return new Range(start, end, step);
  };
  
  /**
   * Evaluate the range parameters start, step, end
   * @returns {{start: Number, end: Number, step: Number}} range
   * @private
   */
  RangeNode.prototype._evalParams = function _evalParams() {
    var start = this.start.eval();
    var end = this.end.eval();
    var step = this.step ? this.step.eval() : 1;
  
    // TODO: implement support for big numbers
  
    // convert big numbers to numbers
    if (start instanceof BigNumber) start = toNumber(start);
    if (end instanceof BigNumber)   end   = toNumber(end);
    if (step instanceof BigNumber)  step  = toNumber(step);
  
    // validate parameters
    if (!number.isNumber(start)) throw new TypeError('Parameter start must be a number');
    if (!number.isNumber(end))   throw new TypeError('Parameter end must be a number');
    if (!number.isNumber(step))  throw new TypeError('Parameter step must be a number');
  
    return {
      start: start,
      end: end,
      step: step
    };
  };
  
  /**
   * Find all nodes matching given filter
   * @param {Object} filter  See Node.find for a description of the filter settings
   * @returns {Node[]} nodes
   */
  RangeNode.prototype.find = function (filter) {
    var nodes = [];
  
    // check itself
    if (this.match(filter)) {
      nodes.push(this);
    }
  
    // search in parameters
    if (this.start) {
      nodes = nodes.concat(this.start.find(filter));
    }
    if (this.step) {
      nodes = nodes.concat(this.step.find(filter));
    }
    if (this.end) {
      nodes = nodes.concat(this.end.find(filter));
    }
  
    return nodes;
  };
  
  /**
   * Get string representation
   * @return {String} str
   */
  RangeNode.prototype.toString = function() {
    // format the range like "start:step:end"
    var str = this.start.toString();
    if (this.step) {
      str += ':' + this.step.toString();
    }
    str += ':' + this.end.toString();
  
    return str;
  };
  
  module.exports = RangeNode;
  
  },{"../../type/Matrix":206,"../../type/Range":207,"../../util/number":214,"./Node":109,"bignumber.js":218}],113:[function(require,module,exports){
  var Node = require('./Node');
  
  /**
   * @constructor SymbolNode
   * A symbol node can hold and resolve a symbol
   * @param {String} name
   * @param {Scope} scope
   * @extends {Node}
   */
  function SymbolNode(name, scope) {
    this.name = name;
    this.scope = scope;
  }
  
  SymbolNode.prototype = new Node();
  
  /**
   * Evaluate the symbol. Throws an error when the symbol is undefined.
   * @return {*} result
   * @override
   */
  SymbolNode.prototype.eval = function() {
    // return the value of the symbol
    var value = this.scope.get(this.name);
  
    if (value === undefined) {
      throw new Error('Undefined symbol ' + this.name);
    }
  
    return value;
  };
  
  /**
   * Get string representation
   * @return {String} str
   * @override
   */
  SymbolNode.prototype.toString = function() {
    return this.name;
  };
  
  module.exports = SymbolNode;
  
  },{"./Node":109}],114:[function(require,module,exports){
  var Node = require('./Node'),
  
      BigNumber = require('bignumber.js'),
      Complex = require('../../type/Complex'),
      Unit = require('../../type/Unit'),
  
      number = require('../../util/number'),
      toNumber = number.toNumber;
  
  /**
   * @constructor UnitNode
   * Construct a unit, like '3 cm'
   * @param {Node} value
   * @param {String} unit     Unit name, for example  'meter' 'kg'
   */
  function UnitNode (value, unit) {
    this.value = value;
    this.unit = unit;
  }
  
  UnitNode.prototype = new Node();
  
  /**
   * Evaluate the parameters
   * @return {*} result
   */
  UnitNode.prototype.eval = function() {
    // evaluate the value
    var value = this.value.eval();
  
    // convert bignumber to number as Unit doesn't support BigNumber
    value = (value instanceof BigNumber) ? toNumber(value) : value;
  
    // create the unit
    if (Unit.isPlainUnit(this.unit)) {
      return new Unit(value, this.unit);
    }
    else {
      throw new TypeError('Unknown unit "' + this.unit + '"');
    }
  };
  
  /**
   * Find all nodes matching given filter
   * @param {Object} filter  See Node.find for a description of the filter settings
   * @returns {Node[]} nodes
   */
  UnitNode.prototype.find = function (filter) {
    var nodes = [];
  
    // check itself
    if (this.match(filter)) {
      nodes.push(this);
    }
  
    // check value
    nodes = nodes.concat(this.value.find(filter));
  
    return nodes;
  };
  
  /**
   * Get string representation
   * @return {String} str
   */
  UnitNode.prototype.toString = function() {
    return this.value + ' ' + this.unit;
  };
  
  module.exports = UnitNode;
  
  },{"../../type/Complex":203,"../../type/Unit":208,"../../util/number":214,"./Node":109,"bignumber.js":218}],115:[function(require,module,exports){
  var number= require('../../util/number'),
  
      Node = require('./Node'),
      RangeNode = require('./RangeNode'),
      SymbolNode = require('./SymbolNode'),
  
      BigNumber = require('bignumber.js'),
      Index = require('../../type/Index'),
      Range = require('../../type/Range'),
  
      isNumber = number.isNumber,
      toNumber = number.toNumber;
  
  /**
   * @constructor UpdateNode
   * Update a symbol value, like a(2,3) = 4.5
   *
   * @param {Object} math                 The math namespace containing all functions
   * @param {String} name                 Symbol name
   * @param {Node[] | undefined} params   One or more parameters
   * @param {Scope[]}  paramScopes        A scope for every parameter, where the
   *                                      index variable 'end' can be defined.
   * @param {Node} expr                   The expression defining the symbol
   * @param {Scope} scope                 Scope to store the result
   */
  function UpdateNode(math, name, params, paramScopes, expr, scope) {
    this.math = math;
  
    this.name = name;
    this.params = params;
    this.paramScopes = paramScopes;
    this.expr = expr;
    this.scope = scope;
  
    // check whether any of the params expressions uses the context symbol 'end'
    this.hasContextParams = false;
    var filter = {
      type: SymbolNode,
      properties: {
        name: 'end'
      }
    };
  
    for (var i = 0, len = params.length; i < len; i++) {
      if (params[i].find(filter).length > 0) {
        this.hasContextParams = true;
        break;
      }
    }
  }
  
  UpdateNode.prototype = new Node();
  
  /**
   * Evaluate the assignment
   * @return {*} result
   */
  UpdateNode.prototype.eval = function() {
    if (this.expr === undefined) {
      throw new Error('Undefined symbol ' + this.name);
    }
  
    var result;
  
    // test if definition is currently undefined
    var prevResult = this.scope.get(this.name);
    if (prevResult == undefined) {
      throw new Error('Undefined symbol ' + this.name);
    }
  
    // evaluate the values of context parameter 'end' when needed
    if (this.hasContextParams && typeof prevResult !== 'function') {
      var paramScopes = this.paramScopes,
          size = this.math.size(prevResult).valueOf();
  
      if (paramScopes && size) {
        for (var i = 0, len = this.params.length; i < len; i++) {
          var paramScope = paramScopes[i];
          if (paramScope) {
            paramScope.set('end', size[i]);
          }
        }
      }
    }
  
    // change part of a matrix, for example "a=[]", "a(2,3)=4.5"
    var paramResults = [];
    this.params.forEach(function (param) {
      var result;
  
      if (param instanceof RangeNode) {
        result = param.toRange();
      }
      else {
        result = param.eval();
      }
  
      // convert big number to number
      if (result instanceof BigNumber) result = toNumber(result);
  
      // TODO: implement support for BigNumber
  
      // change from one-based to zero-based range
      if (result instanceof Range) {
        result.start --;
        result.end --;
      }
      else if (isNumber(result)) {
        // number
        result--;
      }
      else {
        throw new TypeError('Number or Range expected');
      }
  
      paramResults.push(result);
    });
  
    // evaluate the expression
    var exprResult = this.expr.eval();
  
    // replace subset
    var index = Index.create(paramResults);
    result = this.math.subset(prevResult, index, exprResult);
  
    this.scope.set(this.name, result);
  
    return result;
  };
  
  /**
   * Find all nodes matching given filter
   * @param {Object} filter  See Node.find for a description of the filter settings
   * @returns {Node[]} nodes
   */
  UpdateNode.prototype.find = function (filter) {
    var nodes = [];
  
    // check itself
    if (this.match(filter)) {
      nodes.push(this);
    }
  
    // search in parameters
    var params = this.params;
    if (params) {
      for (var i = 0, len = params.length; i < len; i++) {
        nodes = nodes.concat(params[i].find(filter));
      }
    }
  
    // search in expression
    if (this.expr) {
      nodes = nodes.concat(this.expr.find(filter));
    }
  
    return nodes;
  };
  
  /**
   * Get string representation
   * @return {String}
   */
  UpdateNode.prototype.toString = function() {
    var str = '';
  
    str += this.name;
    if (this.params && this.params.length) {
      str += '(' + this.params.join(', ') + ')';
    }
    str += ' = ';
    str += this.expr.toString();
  
    return str;
  };
  
  module.exports = UpdateNode;
  
  },{"../../type/Index":205,"../../type/Range":207,"../../util/number":214,"./Node":109,"./RangeNode":112,"./SymbolNode":113,"bignumber.js":218}],116:[function(require,module,exports){
  /**
   * Custom node handlers,
   * (can be added to the exports object)
   */
  
  },{}],117:[function(require,module,exports){
  exports.AssignmentNode = require('./AssignmentNode');
  exports.BlockNode = require('./BlockNode');
  exports.ConstantNode = require('./ConstantNode');
  exports.UnitNode = require('./UnitNode');
  exports.FunctionNode = require('./FunctionNode');
  exports.ArrayNode = require('./ArrayNode');
  exports.Node = require('./Node');
  exports.OperatorNode = require('./OperatorNode');
  exports.ParamsNode = require('./ParamsNode');
  exports.RangeNode = require('./RangeNode');
  exports.SymbolNode = require('./SymbolNode');
  exports.UpdateNode = require('./UpdateNode');
  
  exports.handlers = require('./handlers');
  
  },{"./ArrayNode":104,"./AssignmentNode":105,"./BlockNode":106,"./ConstantNode":107,"./FunctionNode":108,"./Node":109,"./OperatorNode":110,"./ParamsNode":111,"./RangeNode":112,"./SymbolNode":113,"./UnitNode":114,"./UpdateNode":115,"./handlers":116}],118:[function(require,module,exports){
  module.exports = function (math) {
    var util = require('../../util/index'),
  
        BigNumber = require('bignumber.js'),
        Complex = require('../../type/Complex'),
        Matrix = require('../../type/Matrix'),
        collection = require('../../type/collection'),
  
        isNumber = util.number.isNumber,
        isBoolean = util['boolean'].isBoolean,
        isComplex = Complex.isComplex,
        isCollection = collection.isCollection;
  
    /**
     * Calculate the absolute value of a value.
     *
     *     abs(x)
     *
     * For matrices, the function is evaluated element wise.
     *
     * @param  {Number | BigNumber | Boolean | Complex | Array | Matrix} x
     * @return {Number | BigNumber | Complex | Array | Matrix} res
     */
    math.abs = function abs(x) {
      if (arguments.length != 1) {
        throw new math.error.ArgumentsError('abs', arguments.length, 1);
      }
  
      if (isNumber(x)) {
        return Math.abs(x);
      }
  
      if (isComplex(x)) {
        return Math.sqrt(x.re * x.re + x.im * x.im);
      }
  
      if (x instanceof BigNumber) {
        return x.abs();
      }
  
      if (isCollection(x)) {
        return collection.deepMap(x, abs);
      }
  
      if (isBoolean(x)) {
        return Math.abs(x);
      }
  
      throw new math.error.UnsupportedTypeError('abs', x);
    };
  };
  
  },{"../../type/Complex":203,"../../type/Matrix":206,"../../type/collection":209,"../../util/index":213,"bignumber.js":218}],119:[function(require,module,exports){
  module.exports = function (math) {
    var util = require('../../util/index'),
  
        BigNumber = require('bignumber.js'),
        Complex = require('../../type/Complex'),
        Matrix = require('../../type/Matrix'),
        Unit = require('../../type/Unit'),
        collection = require('../../type/collection'),
  
        isBoolean = util['boolean'].isBoolean,
        isNumber = util.number.isNumber,
        toNumber = util.number.toNumber,
        toBigNumber = util.number.toBigNumber,
        isString = util.string.isString,
        isComplex = Complex.isComplex,
        isUnit = Unit.isUnit,
        isCollection = collection.isCollection;
  
    /**
     * Add two values
     *
     *     x + y
     *     add(x, y)
     *
     * For matrices, the function is evaluated element wise.
     *
     * @param  {Number | BigNumber | Boolean | Complex | Unit | String | Array | Matrix} x
     * @param  {Number | BigNumber | Boolean | Complex | Unit | String | Array | Matrix} y
     * @return {Number | BigNumber | Complex | Unit | String | Array | Matrix} res
     */
    math.add = function add(x, y) {
      if (arguments.length != 2) {
        throw new math.error.ArgumentsError('add', arguments.length, 2);
      }
  
      if (isNumber(x)) {
        if (isNumber(y)) {
          // number + number
          return x + y;
        }
        else if (isComplex(y)) {
          // number + complex
          return new Complex(
              x + y.re,
              y.im
          )
        }
      }
  
      if (isComplex(x)) {
        if (isComplex(y)) {
          // complex + complex
          return new Complex(
              x.re + y.re,
              x.im + y.im
          );
        }
        else if (isNumber(y)) {
          // complex + number
          return new Complex(
              x.re + y,
              x.im
          )
        }
      }
  
      if (isUnit(x)) {
        if (isUnit(y)) {
          if (!x.equalBase(y)) {
            throw new Error('Units do not match');
          }
  
          if (x.value == null) {
            throw new Error('Unit on left hand side of operator + has an undefined value');
          }
  
          if (y.value == null) {
            throw new Error('Unit on right hand side of operator + has an undefined value');
          }
  
          var res = x.clone();
          res.value += y.value;
          res.fixPrefix = false;
          return res;
        }
      }
  
      if (x instanceof BigNumber) {
        // try to convert to big number
        if (isNumber(y)) {
          y = toBigNumber(y);
        }
        else if (isBoolean(y)) {
          y = new BigNumber(y ? 1 : 0);
        }
  
        if (y instanceof BigNumber) {
          return x.plus(y);
        }
  
        // downgrade to Number
        return add(toNumber(x), y);
      }
      if (y instanceof BigNumber) {
        // try to convert to big number
        if (isNumber(x)) {
          x = toBigNumber(x);
        }
        else if (isBoolean(x)) {
          x = new BigNumber(x ? 1 : 0);
        }
  
        if (x instanceof BigNumber) {
          return x.plus(y)
        }
  
        // downgrade to Number
        return add(x, toNumber(y));
      }
  
      if (isString(x) || isString(y)) {
        return x + y;
      }
  
      if (isCollection(x) || isCollection(y)) {
        return collection.deepMap2(x, y, add);
      }
  
      if (isBoolean(x)) {
        return add(+x, y);
      }
      if (isBoolean(y)) {
        return add(x, +y);
      }
  
      throw new math.error.UnsupportedTypeError('add', x, y);
    };
  };
  
  },{"../../type/Complex":203,"../../type/Matrix":206,"../../type/Unit":208,"../../type/collection":209,"../../util/index":213,"bignumber.js":218}],120:[function(require,module,exports){
  module.exports = function (math) {
    var util = require('../../util/index'),
  
        BigNumber = require('bignumber.js'),
        Complex = require('../../type/Complex'),
        collection = require('../../type/collection'),
  
        isNumber = util.number.isNumber,
        isBoolean = util['boolean'].isBoolean,
        isCollection =collection.isCollection,
        isComplex = Complex.isComplex;
  
    /**
     * Round a value towards plus infinity
     *
     *     ceil(x)
     *
     * For matrices, the function is evaluated element wise.
     *
     * @param  {Number | BigNumber | Boolean | Complex | Array | Matrix} x
     * @return {Number | BigNumber | Complex | Array | Matrix} res
     */
    math.ceil = function ceil(x) {
      if (arguments.length != 1) {
        throw new math.error.ArgumentsError('ceil', arguments.length, 1);
      }
  
      if (isNumber(x)) {
        return Math.ceil(x);
      }
  
      if (isComplex(x)) {
        return new Complex (
            Math.ceil(x.re),
            Math.ceil(x.im)
        );
      }
  
      if (x instanceof BigNumber) {
        return x.ceil();
      }
  
      if (isCollection(x)) {
        return collection.deepMap(x, ceil);
      }
  
      if (isBoolean(x)) {
        return Math.ceil(x);
      }
  
      throw new math.error.UnsupportedTypeError('ceil', x);
    };
  };
  
  },{"../../type/Complex":203,"../../type/collection":209,"../../util/index":213,"bignumber.js":218}],121:[function(require,module,exports){
  module.exports = function (math) {
    var util = require('../../util/index'),
  
        BigNumber = require('bignumber.js'),
        Complex = require('../../type/Complex'),
        collection = require('../../type/collection'),
  
        isNumber = util.number.isNumber,
        isBoolean = util['boolean'].isBoolean,
        isComplex = Complex.isComplex,
        isCollection = collection.isCollection;
  
    /**
     * Compute the cube of a value
     *
     *     x .* x .* x
     *     cube(x)
     *
     * For matrices, the function is evaluated element wise.
     *
     * @param  {Number | BigNumber | Boolean | Complex | Array | Matrix} x
     * @return {Number | BigNumber | Complex | Array | Matrix} res
     */
    math.cube = function cube(x) {
      if (arguments.length != 1) {
        throw new math.error.ArgumentsError('cube', arguments.length, 1);
      }
  
      if (isNumber(x)) {
        return x * x * x;
      }
  
      if (isComplex(x)) {
        return math.multiply(math.multiply(x, x), x);
      }
  
      if (x instanceof BigNumber) {
        return x.times(x).times(x);
      }
  
      if (isCollection(x)) {
        return collection.deepMap(x, cube);
      }
  
      if (isBoolean(x)) {
        return cube(+x);
      }
  
      throw new math.error.UnsupportedTypeError('cube', x);
    };
  };
  
  },{"../../type/Complex":203,"../../type/collection":209,"../../util/index":213,"bignumber.js":218}],122:[function(require,module,exports){
  module.exports = function(math) {
    var util = require('../../util/index'),
  
        BigNumber = require('bignumber.js'),
        Complex = require('../../type/Complex'),
        Matrix = require('../../type/Matrix'),
        Unit = require('../../type/Unit'),
        collection = require('../../type/collection'),
  
        isNumber = util.number.isNumber,
        toNumber = util.number.toNumber,
        toBigNumber = util.number.toBigNumber,
        isBoolean = util['boolean'].isBoolean,
        isComplex = Complex.isComplex,
        isUnit = Unit.isUnit,
        isCollection = collection.isCollection;
  
    /**
     * Divide two values.
     *
     *     x / y
     *     divide(x, y)
     *
     * @param  {Number | BigNumber | Boolean | Complex | Unit | Array | Matrix} x
     * @param  {Number | BigNumber | Boolean | Complex} y
     * @return {Number | BigNumber | Complex | Unit | Array | Matrix} res
     */
    math.divide = function divide(x, y) {
      if (arguments.length != 2) {
        throw new math.error.ArgumentsError('divide', arguments.length, 2);
      }
  
      if (isNumber(x)) {
        if (isNumber(y)) {
          // number / number
          return x / y;
        }
        else if (isComplex(y)) {
          // number / complex
          return _divideComplex(new Complex(x, 0), y);
        }
      }
  
      if (isComplex(x)) {
        if (isComplex(y)) {
          // complex / complex
          return _divideComplex(x, y);
        }
        else if (isNumber(y)) {
          // complex / number
          return _divideComplex(x, new Complex(y, 0));
        }
      }
  
      if (x instanceof BigNumber) {
        // try to convert to big number
        if (isNumber(y)) {
          y = toBigNumber(y);
        }
        else if (isBoolean(y)) {
          y = new BigNumber(y ? 1 : 0);
        }
  
        if (y instanceof BigNumber) {
          return x.div(y);
        }
  
        // downgrade to Number
        return divide(toNumber(x), y);
      }
      if (y instanceof BigNumber) {
        // try to convert to big number
        if (isNumber(x)) {
          x = toBigNumber(x);
        }
        else if (isBoolean(x)) {
          x = new BigNumber(x ? 1 : 0);
        }
  
        if (x instanceof BigNumber) {
          return x.div(y)
        }
  
        // downgrade to Number
        return divide(x, toNumber(y));
      }
  
      if (isUnit(x)) {
        if (isNumber(y)) {
          var res = x.clone();
          res.value /= y;
          return res;
        }
      }
  
      if (isCollection(x)) {
        if (isCollection(y)) {
          // TODO: implement matrix right division using pseudo inverse
          // http://www.mathworks.nl/help/matlab/ref/mrdivide.html
          // http://www.gnu.org/software/octave/doc/interpreter/Arithmetic-Ops.html
          // http://stackoverflow.com/questions/12263932/how-does-gnu-octave-matrix-division-work-getting-unexpected-behaviour
          return math.multiply(x, math.inv(y));
        }
        else {
          // matrix / scalar
          return collection.deepMap2(x, y, divide);
        }
      }
  
      if (isCollection(y)) {
        // TODO: implement matrix right division using pseudo inverse
        return math.multiply(x, math.inv(y));
      }
  
      if (isBoolean(x)) {
        return divide(+x, y);
      }
      if (isBoolean(y)) {
        return divide(x, +y);
      }
  
      throw new math.error.UnsupportedTypeError('divide', x, y);
    };
  
    /**
     * Divide two complex numbers. x / y or divide(x, y)
     * @param {Complex} x
     * @param {Complex} y
     * @return {Complex} res
     * @private
     */
    function _divideComplex (x, y) {
      var den = y.re * y.re + y.im * y.im;
      if (den != 0) {
        return new Complex(
            (x.re * y.re + x.im * y.im) / den,
            (x.im * y.re - x.re * y.im) / den
        );
      }
      else {
        // both y.re and y.im are zero
        return new Complex(
            (x.re != 0) ? (x.re / 0) : 0,
            (x.im != 0) ? (x.im / 0) : 0
        );
      }
    }
  };
  
  },{"../../type/Complex":203,"../../type/Matrix":206,"../../type/Unit":208,"../../type/collection":209,"../../util/index":213,"bignumber.js":218}],123:[function(require,module,exports){
  module.exports = function (math) {
    var collection = require('../../type/collection');
  
    /**
     * Divide two values element wise.
     *
     *     x ./ y
     *     edivide(x, y)
     *
     * @param  {Number | BigNumber | Boolean | Complex | Unit | Array | Matrix} x
     * @param  {Number | BigNumber | Boolean | Complex | Unit | Array | Matrix} y
     * @return {Number | BigNumber | Complex | Unit | Array | Matrix} res
     */
    math.edivide = function edivide(x, y) {
      if (arguments.length != 2) {
        throw new math.error.ArgumentsError('edivide', arguments.length, 2);
      }
  
      return collection.deepMap2(x, y, math.divide);
    };
  };
  
  },{"../../type/collection":209}],124:[function(require,module,exports){
  module.exports = function (math) {
    var collection = require('../../type/collection');
  
    /**
     * Multiply two values element wise.
     *
     *     x .* y
     *     emultiply(x, y)
     *
     * @param  {Number | BigNumber | Boolean | Complex | Unit | Array | Matrix} x
     * @param  {Number | BigNumber | Boolean | Complex | Unit | Array | Matrix} y
     * @return {Number | BigNumber | Complex | Unit | Array | Matrix} res
     */
    math.emultiply = function emultiply(x, y) {
      if (arguments.length != 2) {
        throw new math.error.ArgumentsError('emultiply', arguments.length, 2);
      }
  
      return collection.deepMap2(x, y, math.multiply);
    };
  };
  
  },{"../../type/collection":209}],125:[function(require,module,exports){
  module.exports = function (math) {
    var collection = require('../../type/collection');
  
    /**
     * Calculates the power of x to y element wise
     *
     *     x .^ y
     *     epow(x, y)
     *
     * @param  {Number | BigNumber | Boolean | Complex | Unit | Array | Matrix} x
     * @param  {Number | BigNumber | Boolean | Complex | Unit | Array | Matrix} y
     * @return {Number | BigNumber | Complex | Unit | Array | Matrix} res
     */
    math.epow = function epow(x, y) {
      if (arguments.length != 2) {
        throw new math.error.ArgumentsError('epow', arguments.length, 2);
      }
  
      return collection.deepMap2(x, y, math.pow);
    };
  };
  
  },{"../../type/collection":209}],126:[function(require,module,exports){
  module.exports = function (math) {
    var util = require('../../util/index'),
  
        BigNumber = require('bignumber.js'),
        Complex = require('../../type/Complex'),
        Unit = require('../../type/Unit'),
        collection = require('../../type/collection'),
  
        isNumber = util.number.isNumber,
        toNumber = util.number.toNumber,
        toBigNumber = util.number.toBigNumber,
        isBoolean = util['boolean'].isBoolean,
        isString = util.string.isString,
        isComplex = Complex.isComplex,
        isUnit = Unit.isUnit,
        isCollection = collection.isCollection;
  
    /**
     * Check if value x equals y,
     *
     *     x == y
     *     equal(x, y)
     *
     * For matrices, the function is evaluated element wise.
     * In case of complex numbers, x.re must equal y.re, and x.im must equal y.im.
     *
     * @param  {Number | BigNumber | Boolean | Complex | Unit | String | Array | Matrix} x
     * @param  {Number | BigNumber | Boolean | Complex | Unit | String | Array | Matrix} y
     * @return {Boolean | Array | Matrix} res
     */
    math.equal = function equal(x, y) {
      if (arguments.length != 2) {
        throw new math.error.ArgumentsError('equal', arguments.length, 2);
      }
  
      if (isNumber(x)) {
        if (isNumber(y)) {
          return x == y;
        }
        else if (isComplex(y)) {
          return (x == y.re) && (y.im == 0);
        }
      }
  
      if (isComplex(x)) {
        if (isNumber(y)) {
          return (x.re == y) && (x.im == 0);
        }
        else if (isComplex(y)) {
          return (x.re == y.re) && (x.im == y.im);
        }
      }
  
      if (x instanceof BigNumber) {
        // try to convert to big number
        if (isNumber(y)) {
          y = toBigNumber(y);
        }
        else if (isBoolean(y)) {
          y = new BigNumber(y ? 1 : 0);
        }
  
        if (y instanceof BigNumber) {
          return x.eq(y);
        }
  
        // downgrade to Number
        return equal(toNumber(x), y);
      }
      if (y instanceof BigNumber) {
        // try to convert to big number
        if (isNumber(x)) {
          x = toBigNumber(x);
        }
        else if (isBoolean(x)) {
          x = new BigNumber(x ? 1 : 0);
        }
  
        if (x instanceof BigNumber) {
          return x.eq(y)
        }
  
        // downgrade to Number
        return equal(x, toNumber(y));
      }
  
      if ((isUnit(x)) && (isUnit(y))) {
        if (!x.equalBase(y)) {
          throw new Error('Cannot compare units with different base');
        }
        return x.value == y.value;
      }
  
      if (isString(x) || isString(y)) {
        return x == y;
      }
  
      if (isCollection(x) || isCollection(y)) {
        return collection.deepMap2(x, y, equal);
      }
  
      if (isBoolean(x)) {
        return equal(+x, y);
      }
      if (isBoolean(y)) {
        return equal(x, +y);
      }
  
      throw new math.error.UnsupportedTypeError('equal', x, y);
    };
  };
  
  },{"../../type/Complex":203,"../../type/Unit":208,"../../type/collection":209,"../../util/index":213,"bignumber.js":218}],127:[function(require,module,exports){
  module.exports = function (math) {
    var util = require('../../util/index'),
  
        BigNumber = require('bignumber.js'),
        Complex = require('../../type/Complex'),
        Matrix = require('../../type/Matrix'),
        collection = require('../../type/collection'),
  
        isNumber = util.number.isNumber,
        isBoolean = util['boolean'].isBoolean,
        isComplex = Complex.isComplex,
        isCollection = collection.isCollection;
  
    /**
     * Calculate the exponent of a value
     *
     *     exp(x)
     *
     * For matrices, the function is evaluated element wise.
     *
     * @param {Number | Boolean | Complex | Array | Matrix} x
     * @return {Number | Complex | Array | Matrix} res
     */
    math.exp = function exp (x) {
      if (arguments.length != 1) {
        throw new math.error.ArgumentsError('exp', arguments.length, 1);
      }
  
      if (isNumber(x)) {
        return Math.exp(x);
      }
  
      if (isComplex(x)) {
        var r = Math.exp(x.re);
        return new Complex(
            r * Math.cos(x.im),
            r * Math.sin(x.im)
        );
      }
  
      if (x instanceof BigNumber) {
        // TODO: implement BigNumber support
        // downgrade to Number
        return exp(util.number.toNumber(x));
      }
  
      if (isCollection(x)) {
        return collection.deepMap(x, exp);
      }
  
      if (isBoolean(x)) {
        return Math.exp(x);
      }
  
      throw new math.error.UnsupportedTypeError('exp', x);
    };
  };
  
  },{"../../type/Complex":203,"../../type/Matrix":206,"../../type/collection":209,"../../util/index":213,"bignumber.js":218}],128:[function(require,module,exports){
  module.exports = function (math) {
    var util = require('../../util/index'),
  
        BigNumber = require('bignumber.js'),
        Complex = require('../../type/Complex'),
        collection = require('../../type/collection'),
  
        isNumber = util.number.isNumber,
        isBoolean = util['boolean'].isBoolean,
        isComplex = Complex.isComplex,
        isCollection = collection.isCollection;
  
    /**
     * Round a value towards zero
     *
     *     fix(x)
     *
     * For matrices, the function is evaluated element wise.
     *
     * @param {Number | Boolean | Complex | Array | Matrix} x
     * @return {Number | Complex | Array | Matrix} res
     */
    math.fix = function fix(x) {
      if (arguments.length != 1) {
        throw new math.error.ArgumentsError('fix', arguments.length, 1);
      }
  
      if (isNumber(x)) {
        return (x > 0) ? Math.floor(x) : Math.ceil(x);
      }
  
      if (isComplex(x)) {
        return new Complex(
            (x.re > 0) ? Math.floor(x.re) : Math.ceil(x.re),
            (x.im > 0) ? Math.floor(x.im) : Math.ceil(x.im)
        );
      }
  
      if (x instanceof BigNumber) {
        return x.isNegative() ? x.ceil() : x.floor();
      }
  
      if (isCollection(x)) {
        return collection.deepMap(x, fix);
      }
  
      if (isBoolean(x)) {
        return fix(+x);
      }
  
      throw new math.error.UnsupportedTypeError('fix', x);
    };
  };
  
  },{"../../type/Complex":203,"../../type/collection":209,"../../util/index":213,"bignumber.js":218}],129:[function(require,module,exports){
  module.exports = function (math) {
    var util = require('../../util/index'),
  
        BigNumber = require('bignumber.js'),
        Complex = require('../../type/Complex'),
        collection = require('../../type/collection'),
  
        isNumber = util.number.isNumber,
        isBoolean = util['boolean'].isBoolean,
        isComplex = Complex.isComplex,
        isCollection = collection.isCollection;
  
    /**
     * Round a value towards minus infinity
     *
     *     floor(x)
     *
     * For matrices, the function is evaluated element wise.
     *
     * @param  {Number | BigNumber | Boolean | Complex | Array | Matrix} x
     * @return {Number | BigNumber | Complex | Array | Matrix} res
     */
    math.floor = function floor(x) {
      if (arguments.length != 1) {
        throw new math.error.ArgumentsError('floor', arguments.length, 1);
      }
  
      if (isNumber(x)) {
        return Math.floor(x);
      }
  
      if (isComplex(x)) {
        return new Complex (
            Math.floor(x.re),
            Math.floor(x.im)
        );
      }
  
      if (x instanceof BigNumber) {
        return x.floor();
      }
  
      if (isCollection(x)) {
        return collection.deepMap(x, floor);
      }
  
      if (isBoolean(x)) {
        return floor(+x);
      }
  
      throw new math.error.UnsupportedTypeError('floor', x);
    };
  };
  
  },{"../../type/Complex":203,"../../type/collection":209,"../../util/index":213,"bignumber.js":218}],130:[function(require,module,exports){
  module.exports = function (math) {
    var util = require('../../util/index'),
  
        BigNumber = require('bignumber.js'),
        collection = require('../../type/collection'),
  
        isNumber = util.number.isNumber,
        toNumber = util.number.toNumber,
        isBoolean = util['boolean'].isBoolean,
        isInteger = util.number.isInteger,
        isCollection = collection.isCollection;
  
    /**
     * Calculate the greatest common divisor for two or more values or arrays.
     *
     *     gcd(a, b)
     *     gcd(a, b, c, ...)
     *
     * For matrices, the function is evaluated element wise.
     *
     * @param {... Number | Boolean | Array | Matrix} args    two or more integer numbers
     * @return {Number | Array | Matrix} greatest common divisor
     */
    math.gcd = function gcd(args) {
      var a = arguments[0],
          b = arguments[1],
          r; // remainder
  
      if (arguments.length == 2) {
        // two arguments
        if (isNumber(a) && isNumber(b)) {
          if (!isInteger(a) || !isInteger(b)) {
            throw new Error('Parameters in function gcd must be integer numbers');
          }
  
          // http://en.wikipedia.org/wiki/Euclidean_algorithm
          while (b != 0) {
            r = a % b;
            a = b;
            b = r;
          }
          return (a < 0) ? -a : a;
        }
  
        // evaluate gcd element wise
        if (isCollection(a) || isCollection(b)) {
          return collection.deepMap2(a, b, gcd);
        }
  
        // TODO: implement BigNumber support for gcd
  
        // downgrade bignumbers to numbers
        if (a instanceof BigNumber) {
          return gcd(toNumber(a), b);
        }
        if (b instanceof BigNumber) {
          return gcd(a, toNumber(b));
        }
  
        if (isBoolean(a)) {
          return gcd(+a, b);
        }
        if (isBoolean(b)) {
          return gcd(a, +b);
        }
  
        throw new math.error.UnsupportedTypeError('gcd', a, b);
      }
  
      if (arguments.length > 2) {
        // multiple arguments. Evaluate them iteratively
        for (var i = 1; i < arguments.length; i++) {
          a = gcd(a, arguments[i]);
        }
        return a;
      }
  
      // zero or one argument
      throw new SyntaxError('Function gcd expects two or more arguments');
    };
  };
  
  },{"../../type/collection":209,"../../util/index":213,"bignumber.js":218}],131:[function(require,module,exports){
  module.exports = function (math) {
    var util = require('../../util/index'),
  
        BigNumber = require('bignumber.js'),
        Complex = require('../../type/Complex'),
        Unit = require('../../type/Unit'),
        collection = require('../../type/collection'),
  
        isNumber = util.number.isNumber,
        toNumber = util.number.toNumber,
        toBigNumber = util.number.toBigNumber,
        isBoolean = util['boolean'].isBoolean,
        isString = util.string.isString,
        isComplex = Complex.isComplex,
        isUnit = Unit.isUnit,
        isCollection = collection.isCollection;
  
    /**
     * Check if value x is larger y
     *
     *    x > y
     *    larger(x, y)
     *
     * For matrices, the function is evaluated element wise.
     * In case of complex numbers, the absolute values of a and b are compared.
     *
     * @param  {Number | BigNumber | Boolean | Unit | String | Array | Matrix} x
     * @param  {Number | BigNumber | Boolean | Unit | String | Array | Matrix} y
     * @return {Boolean | Array | Matrix} res
     */
    math.larger = function larger(x, y) {
      if (arguments.length != 2) {
        throw new math.error.ArgumentsError('larger', arguments.length, 2);
      }
  
      if (isNumber(x) && isNumber(y)) {
        return x > y;
      }
  
      if (x instanceof BigNumber) {
        // try to convert to big number
        if (isNumber(y)) {
          y = toBigNumber(y);
        }
        else if (isBoolean(y)) {
          y = new BigNumber(y ? 1 : 0);
        }
  
        if (y instanceof BigNumber) {
          return x.gt(y);
        }
  
        // downgrade to Number
        return larger(toNumber(x), y);
      }
      if (y instanceof BigNumber) {
        // try to convert to big number
        if (isNumber(x)) {
          x = toBigNumber(x);
        }
        else if (isBoolean(x)) {
          x = new BigNumber(x ? 1 : 0);
        }
  
        if (x instanceof BigNumber) {
          return x.gt(y)
        }
  
        // downgrade to Number
        return larger(x, toNumber(y));
      }
  
      if ((isUnit(x)) && (isUnit(y))) {
        if (!x.equalBase(y)) {
          throw new Error('Cannot compare units with different base');
        }
        return x.value > y.value;
      }
  
      if (isString(x) || isString(y)) {
        return x > y;
      }
  
      if (isCollection(x) || isCollection(y)) {
        return collection.deepMap2(x, y, larger);
      }
  
      if (isBoolean(x)) {
        return larger(+x, y);
      }
      if (isBoolean(y)) {
        return larger(x, +y);
      }
  
      if (isComplex(x) || isComplex(y)) {
        throw new TypeError('No ordering relation is defined for complex numbers');
      }
  
      throw new math.error.UnsupportedTypeError('larger', x, y);
    };
  };
  
  },{"../../type/Complex":203,"../../type/Unit":208,"../../type/collection":209,"../../util/index":213,"bignumber.js":218}],132:[function(require,module,exports){
  module.exports = function (math) {
    var util = require('../../util/index'),
  
        BigNumber = require('bignumber.js'),
        Complex = require('../../type/Complex'),
        Unit = require('../../type/Unit'),
        collection = require('../../type/collection'),
  
        isNumber = util.number.isNumber,
        toNumber = util.number.toNumber,
        toBigNumber = util.number.toBigNumber,
        isBoolean = util['boolean'].isBoolean,
        isString = util.string.isString,
        isComplex = Complex.isComplex,
        isUnit = Unit.isUnit,
        isCollection = collection.isCollection;
  
    /**
     * Check if value x is larger or equal to y
     *
     *     x >= y
     *     largereq(x, y)
     *
     * For matrices, the function is evaluated element wise.
     * In case of complex numbers, the absolute values of a and b are compared.
     *
     * @param  {Number | BigNumber | Boolean | Unit | String | Array | Matrix} x
     * @param  {Number | BigNumber | Boolean | Unit | String | Array | Matrix} y
     * @return {Boolean | Array | Matrix} res
     */
    math.largereq = function largereq(x, y) {
      if (arguments.length != 2) {
        throw new math.error.ArgumentsError('largereq', arguments.length, 2);
      }
  
      if (isNumber(x) && isNumber(y)) {
        return x >= y;
      }
  
      if (x instanceof BigNumber) {
        // try to convert to big number
        if (isNumber(y)) {
          y = toBigNumber(y);
        }
        else if (isBoolean(y)) {
          y = new BigNumber(y ? 1 : 0);
        }
  
        if (y instanceof BigNumber) {
          return x.gte(y);
        }
  
        // downgrade to Number
        return largereq(toNumber(x), y);
      }
      if (y instanceof BigNumber) {
        // try to convert to big number
        if (isNumber(x)) {
          x = toBigNumber(x);
        }
        else if (isBoolean(x)) {
          x = new BigNumber(x ? 1 : 0);
        }
  
        if (x instanceof BigNumber) {
          return x.gte(y)
        }
  
        // downgrade to Number
        return largereq(x, toNumber(y));
      }
  
      if ((isUnit(x)) && (isUnit(y))) {
        if (!x.equalBase(y)) {
          throw new Error('Cannot compare units with different base');
        }
        return x.value >= y.value;
      }
  
      if (isString(x) || isString(y)) {
        return x >= y;
      }
  
      if (isCollection(x) || isCollection(y)) {
        return collection.deepMap2(x, y, largereq);
      }
  
      if (isBoolean(x)) {
        return largereq(+x, y);
      }
      if (isBoolean(y)) {
        return largereq(x, +y);
      }
  
      if (isComplex(x) || isComplex(y)) {
        throw new TypeError('No ordering relation is defined for complex numbers');
      }
  
      throw new math.error.UnsupportedTypeError('largereq', x, y);
    };
  };
  
  },{"../../type/Complex":203,"../../type/Unit":208,"../../type/collection":209,"../../util/index":213,"bignumber.js":218}],133:[function(require,module,exports){
  module.exports = function (math) {
    var util = require('../../util/index'),
  
        BigNumber = require('bignumber.js'),
        collection = require('../../type/collection'),
  
        isNumber = util.number.isNumber,
        toNumber = util.number.toNumber,
        isBoolean = util['boolean'].isBoolean,
        isInteger = util.number.isInteger,
        isCollection = collection.isCollection;
  
    /**
     * Calculate the least common multiple for two or more values or arrays.
     *
     *     lcm(a, b)
     *     lcm(a, b, c, ...)
     *
     * lcm is defined as:
     *     lcm(a, b) = abs(a * b) / gcd(a, b)
     *
     * For matrices, the function is evaluated element wise.
     *
     * @param {... Number | Boolean | Array | Matrix} args    two or more integer numbers
     * @return {Number | Array | Matrix} least common multiple
     */
    math.lcm = function lcm(args) {
      var a = arguments[0],
          b = arguments[1],
          t;
  
      if (arguments.length == 2) {
        // two arguments
        if (isNumber(a) && isNumber(b)) {
          if (!isInteger(a) || !isInteger(b)) {
            throw new Error('Parameters in function lcm must be integer numbers');
          }
  
          if (a == 0 || b == 0) {
            return 0;
          }
  
          // http://en.wikipedia.org/wiki/Euclidean_algorithm
          // evaluate gcd here inline to reduce overhead
          var prod = a * b;
          while (b != 0) {
            t = b;
            b = a % t;
            a = t;
          }
          return Math.abs(prod / a);
        }
  
        // evaluate lcm element wise
        if (isCollection(a) || isCollection(b)) {
          return collection.deepMap2(a, b, lcm);
        }
  
        if (isBoolean(a)) {
          return lcm(+a, b);
        }
        if (isBoolean(b)) {
          return lcm(a, +b);
        }
  
        // TODO: implement BigNumber support for lcm
  
        // downgrade bignumbers to numbers
        if (a instanceof BigNumber) {
          return lcm(toNumber(a), b);
        }
        if (b instanceof BigNumber) {
          return lcm(a, toNumber(b));
        }
  
        throw new math.error.UnsupportedTypeError('lcm', a, b);
      }
  
      if (arguments.length > 2) {
        // multiple arguments. Evaluate them iteratively
        for (var i = 1; i < arguments.length; i++) {
          a = lcm(a, arguments[i]);
        }
        return a;
      }
  
      // zero or one argument
      throw new SyntaxError('Function lcm expects two or more arguments');
    };
  };
  
  },{"../../type/collection":209,"../../util/index":213,"bignumber.js":218}],134:[function(require,module,exports){
  module.exports = function (math) {
    var util = require('../../util/index'),
  
        BigNumber = require('bignumber.js'),
        Complex = require('../../type/Complex'),
        collection = require('../../type/collection'),
  
        isNumber = util.number.isNumber,
        isBoolean = util['boolean'].isBoolean,
        isComplex = Complex.isComplex,
        isCollection = collection.isCollection;
  
    /**
     * Calculate the logarithm of a value
     *
     *     log(x)
     *     log(x, base)
     *
     * base is optional. If not provided, the natural logarithm of x is calculated.
     * For matrices, the function is evaluated element wise.
     *
     * @param {Number | Boolean | Complex | Array | Matrix} x
     * @param {Number | Boolean | Complex} [base]
     * @return {Number | Complex | Array | Matrix} res
     */
    math.log = function log(x, base) {
      if (arguments.length == 1) {
        // calculate natural logarithm, log(x)
        if (isNumber(x)) {
          if (x >= 0) {
            return Math.log(x);
          }
          else {
            // negative value -> complex value computation
            return log(new Complex(x, 0));
          }
        }
  
        if (isComplex(x)) {
          return new Complex (
              Math.log(Math.sqrt(x.re * x.re + x.im * x.im)),
              Math.atan2(x.im, x.re)
          );
        }
  
        if (x instanceof BigNumber) {
          // TODO: implement BigNumber support
          // downgrade to Number
          return log(util.number.toNumber(x));
        }
  
        if (isCollection(x)) {
          return collection.deepMap(x, log);
        }
  
        if (isBoolean(x)) {
          return log(+x);
        }
  
        throw new math.error.UnsupportedTypeError('log', x);
      }
      else if (arguments.length == 2) {
        // calculate logarithm for a specified base, log(x, base)
        return math.divide(log(x), log(base));
      }
      else {
        throw new math.error.ArgumentsError('log', arguments.length, 1, 2);
      }
    };
  };
  
  },{"../../type/Complex":203,"../../type/collection":209,"../../util/index":213,"bignumber.js":218}],135:[function(require,module,exports){
  module.exports = function (math) {
    var util = require('../../util/index'),
  
        BigNumber = require('bignumber.js'),
        Complex = require('../../type/Complex'),
        collection = require('../../type/collection'),
  
        isNumber = util.number.isNumber,
        isBoolean = util['boolean'].isBoolean,
        isComplex = Complex.isComplex,
        isCollection = collection.isCollection;
  
    /**
     * Calculate the 10-base logarithm of a value
     *
     *     log10(x)
     *
     * For matrices, the function is evaluated element wise.
     *
     * @param {Number | Boolean | Complex | Array | Matrix} x
     * @return {Number | Complex | Array | Matrix} res
     */
    math.log10 = function log10(x) {
      if (arguments.length != 1) {
        throw new math.error.ArgumentsError('log10', arguments.length, 1);
      }
  
      if (isNumber(x)) {
        if (x >= 0) {
          return Math.log(x) / Math.LN10;
        }
        else {
          // negative value -> complex value computation
          return log10(new Complex(x, 0));
        }
      }
  
      if (x instanceof BigNumber) {
        // TODO: implement BigNumber support
        // downgrade to Number
        return log10(util.number.toNumber(x));
      }
  
      if (isComplex(x)) {
        return new Complex (
            Math.log(Math.sqrt(x.re * x.re + x.im * x.im)) / Math.LN10,
            Math.atan2(x.im, x.re) / Math.LN10
        );
      }
  
      if (isCollection(x)) {
        return collection.deepMap(x, log10);
      }
  
      if (isBoolean(x)) {
        return log10(+x);
      }
  
      throw new math.error.UnsupportedTypeError('log10', x);
    };
  };
  
  },{"../../type/Complex":203,"../../type/collection":209,"../../util/index":213,"bignumber.js":218}],136:[function(require,module,exports){
  module.exports = function (math) {
    var util = require('../../util/index'),
  
        BigNumber = require('bignumber.js'),
        collection = require('../../type/collection'),
  
        isNumber = util.number.isNumber,
        toNumber = util.number.toNumber,
        toBigNumber = util.number.toBigNumber,
        isBoolean = util['boolean'].isBoolean,
        isCollection = collection.isCollection;
  
    /**
     * Calculates the modulus, the remainder of an integer division.
     *
     *     x % y
     *     mod(x, y)
     *
     * For matrices, the function is evaluated element wise.
     *
     * @param  {Number | BigNumber | Boolean | Array | Matrix} x
     * @param  {Number | BigNumber | Boolean | Array | Matrix} y
     * @return {Number | BigNumber | Array | Matrix} res
     */
    math.mod = function mod(x, y) {
      if (arguments.length != 2) {
        throw new math.error.ArgumentsError('mod', arguments.length, 2);
      }
  
      // see http://functions.wolfram.com/IntegerFunctions/Mod/
  
      if (isNumber(x)) {
        if (isNumber(y)) {
          // number % number
          return _mod(x, y);
        }
      }
  
      if (x instanceof BigNumber) {
        // try to convert to big number
        if (isNumber(y)) {
          y = toBigNumber(y);
        }
        else if (isBoolean(y)) {
          y = new BigNumber(y ? 1 : 0);
        }
  
        if (y instanceof BigNumber) {
          return x.mod(y);
        }
  
        // downgrade to Number
        return mod(toNumber(x), y);
      }
      if (y instanceof BigNumber) {
        // try to convert to big number
        if (isNumber(x)) {
          x = toBigNumber(x);
        }
        else if (isBoolean(x)) {
          x = new BigNumber(x ? 1 : 0);
        }
  
        if (x instanceof BigNumber) {
          return x.mod(y)
        }
  
        // downgrade to Number
        return mod(x, toNumber(y));
      }
  
      // TODO: implement mod for complex values
  
      if (isCollection(x) || isCollection(y)) {
        return collection.deepMap2(x, y, mod);
      }
  
      if (isBoolean(x)) {
        return mod(+x, y);
      }
      if (isBoolean(y)) {
        return mod(x, +y);
      }
  
      throw new math.error.UnsupportedTypeError('mod', x, y);
    };
  
    /**
     * Calculate the modulus of two numbers
     * @param {Number} x
     * @param {Number} y
     * @returns {number} res
     * @private
     */
    function _mod(x, y) {
      if (y > 0) {
        if (x > 0) {
          return x % y;
        }
        else if (x == 0) {
          return 0;
        }
        else { // x < 0
          return x - y * Math.floor(x / y);
        }
      }
      else if (y == 0) {
        return x;
      }
      else { // y < 0
        // TODO: implement mod for a negative divisor
        throw new Error('Cannot calculate mod for a negative divisor');
      }
    }
  };
  
  },{"../../type/collection":209,"../../util/index":213,"bignumber.js":218}],137:[function(require,module,exports){
  module.exports = function(math) {
    var util = require('../../util/index'),
  
        BigNumber = require('bignumber.js'),
        Complex = require('../../type/Complex'),
        Matrix = require('../../type/Matrix'),
        Unit = require('../../type/Unit'),
        collection = require('../../type/collection'),
  
        array = util.array,
        isNumber = util.number.isNumber,
        toNumber = util.number.toNumber,
        toBigNumber = util.number.toBigNumber,
        isBoolean = util['boolean'].isBoolean,
        isComplex = Complex.isComplex,
        isArray = Array.isArray,
        isUnit = Unit.isUnit;
  
    /**
     * Multiply two values.
     *
     *     x * y
     *     multiply(x, y)
     *
     * @param  {Number | BigNumber | Boolean | Complex | Unit | Array | Matrix} x
     * @param  {Number | BigNumber | Boolean | Complex | Unit | Array | Matrix} y
     * @return {Number | BigNumber | Complex | Unit | Array | Matrix} res
     */
    math.multiply = function multiply(x, y) {
      if (arguments.length != 2) {
        throw new math.error.ArgumentsError('multiply', arguments.length, 2);
      }
  
      if (isNumber(x)) {
        if (isNumber(y)) {
          // number * number
          return x * y;
        }
        else if (isComplex(y)) {
          // number * complex
          return _multiplyComplex (new Complex(x, 0), y);
        }
        else if (isUnit(y)) {
          res = y.clone();
          res.value *= x;
          return res;
        }
      }
  
      if (isComplex(x)) {
        if (isNumber(y)) {
          // complex * number
          return _multiplyComplex (x, new Complex(y, 0));
        }
        else if (isComplex(y)) {
          // complex * complex
          return _multiplyComplex (x, y);
        }
      }
  
      if (x instanceof BigNumber) {
        // try to convert to big number
        if (isNumber(y)) {
          y = toBigNumber(y);
        }
        else if (isBoolean(y)) {
          y = new BigNumber(y ? 1 : 0);
        }
  
        if (y instanceof BigNumber) {
          return x.times(y);
        }
  
        // downgrade to Number
        return multiply(toNumber(x), y);
      }
      if (y instanceof BigNumber) {
        // try to convert to big number
        if (isNumber(x)) {
          x = toBigNumber(x);
        }
        else if (isBoolean(x)) {
          x = new BigNumber(x ? 1 : 0);
        }
  
        if (x instanceof BigNumber) {
          return x.times(y)
        }
  
        // downgrade to Number
        return multiply(x, toNumber(y));
      }
  
      if (isUnit(x)) {
        if (isNumber(y)) {
          res = x.clone();
          res.value *= y;
          return res;
        }
      }
  
      if (isArray(x)) {
        if (isArray(y)) {
          // array * array
          var sizeX = array.size(x);
          var sizeY = array.size(y);
  
          if (sizeX.length == 1) {
            if (sizeY.length == 1) {
              // vector * vector
              if (sizeX[0] != sizeY[0]) {
                throw new RangeError('Dimensions mismatch in multiplication. ' +
                    'Length of A must match length of B ' +
                    '(A is ' + sizeX[0] +
                    ', B is ' + sizeY[0] +
                    sizeX[0] + ' != ' + sizeY[0] + ')');
              }
  
              return _multiplyVectorVector(x, y);
            }
            else if (sizeY.length == 2) {
              // vector * matrix
              if (sizeX[0] != sizeY[0]) {
                throw new RangeError('Dimensions mismatch in multiplication. ' +
                    'Length of A must match rows of B ' +
                    '(A is ' + sizeX[0] +
                    ', B is ' + sizeY[0] + 'x' + sizeY[1] + ', ' +
                    sizeX[0] + ' != ' + sizeY[0] + ')');
              }
  
              return _multiplyVectorMatrix(x, y);
            }
            else {
              throw new Error('Can only multiply a 1 or 2 dimensional matrix ' +
                  '(B has ' + sizeY.length + ' dimensions)');
            }
          }
          else if (sizeX.length == 2) {
            if (sizeY.length == 1) {
              // matrix * vector
              if (sizeX[1] != sizeY[0]) {
                throw new RangeError('Dimensions mismatch in multiplication. ' +
                    'Columns of A must match length of B ' +
                    '(A is ' + sizeX[0] + 'x' + sizeX[0] +
                    ', B is ' + sizeY[0] + ', ' +
                    sizeX[1] + ' != ' + sizeY[0] + ')');
              }
  
              return _multiplyMatrixVector(x, y);
            }
            else if (sizeY.length == 2) {
              // matrix * matrix
              if (sizeX[1] != sizeY[0]) {
                throw new RangeError('Dimensions mismatch in multiplication. ' +
                    'Columns of A must match rows of B ' +
                    '(A is ' + sizeX[0] + 'x' + sizeX[1] +
                    ', B is ' + sizeY[0] + 'x' + sizeY[1] + ', ' +
                    sizeX[1] + ' != ' + sizeY[0] + ')');
              }
  
              return _multiplyMatrixMatrix(x, y);
            }
            else {
              throw new Error('Can only multiply a 1 or 2 dimensional matrix ' +
                  '(B has ' + sizeY.length + ' dimensions)');
            }
          }
          else {
            throw new Error('Can only multiply a 1 or 2 dimensional matrix ' +
                '(A has ' + sizeX.length + ' dimensions)');
          }
        }
        else if (y instanceof Matrix) {
          // array * matrix
          return new Matrix(multiply(x, y.valueOf()));
        }
        else {
          // array * scalar
          return collection.deepMap2(x, y, multiply);
        }
      }
  
      if (x instanceof Matrix) {
        if (y instanceof Matrix) {
          // matrix * matrix
          return new Matrix(multiply(x.valueOf(), y.valueOf()));
        }
        else {
          // matrix * array
          // matrix * scalar
          return new Matrix(multiply(x.valueOf(), y));
        }
      }
  
      if (isArray(y)) {
        // scalar * array
        return collection.deepMap2(x, y, multiply);
      }
      else if (y instanceof Matrix) {
        // scalar * matrix
        return new Matrix(collection.deepMap2(x, y.valueOf(), multiply));
      }
  
      if (isBoolean(x)) {
        return multiply(+x, y);
      }
      if (isBoolean(y)) {
        return multiply(x, +y);
      }
  
      throw new math.error.UnsupportedTypeError('multiply', x, y);
    };
  
    /**
     * Multiply two 2-dimensional matrices.
     * The size of the matrices is not validated.
     * @param {Array} x   A 2d matrix
     * @param {Array} y   A 2d matrix
     * @return {Array} result
     * @private
     */
    function _multiplyMatrixMatrix(x, y) {
      // TODO: performance of matrix multiplication can be improved
      var res = [],
          rows = x.length,
          cols = y[0].length,
          num = x[0].length;
  
      for (var r = 0; r < rows; r++) {
        res[r] = [];
        for (var c = 0; c < cols; c++) {
          var result = null;
          for (var n = 0; n < num; n++) {
            var p = math.multiply(x[r][n], y[n][c]);
            result = (result === null) ? p : math.add(result, p);
          }
          res[r][c] = result;
        }
      }
  
      return res;
    }
  
    /**
     * Multiply a vector with a 2-dimensional matrix
     * The size of the matrices is not validated.
     * @param {Array} x   A vector
     * @param {Array} y   A 2d matrix
     * @return {Array} result
     * @private
     */
    function _multiplyVectorMatrix(x, y) {
      // TODO: performance of matrix multiplication can be improved
      var res = [],
          rows = y.length,
          cols = y[0].length;
  
      for (var c = 0; c < cols; c++) {
        var result = null;
        for (var r = 0; r < rows; r++) {
          var p = math.multiply(x[r], y[r][c]);
          result = (r === 0) ? p : math.add(result, p);
        }
        res[c] = result;
      }
  
      return res;
    }
  
    /**
     * Multiply a 2-dimensional matrix with a vector
     * The size of the matrices is not validated.
     * @param {Array} x   A 2d matrix
     * @param {Array} y   A vector
     * @return {Array} result
     * @private
     */
    function _multiplyMatrixVector(x, y) {
      // TODO: performance of matrix multiplication can be improved
      var res = [],
          rows = x.length,
          cols = x[0].length;
  
      for (var r = 0; r < rows; r++) {
        var result = null;
        for (var c = 0; c < cols; c++) {
          var p = math.multiply(x[r][c], y[c]);
          result = (c === 0) ? p : math.add(result, p);
        }
        res[r] = result;
      }
  
      return res;
    }
  
    /**
     * Multiply two vectors, calculate the dot product
     * The size of the matrices is not validated.
     * @param {Array} x   A vector
     * @param {Array} y   A vector
     * @return {Number} dotProduct
     * @private
     */
    function _multiplyVectorVector(x, y) {
      // TODO: performance of matrix multiplication can be improved
      var len = x.length,
          dot = null;
  
      if (len) {
        dot = 0;
  
        for (var i = 0, ii = x.length; i < ii; i++) {
          dot = math.add(dot, math.multiply(x[i], y[i]));
        }
      }
  
      return dot;
    }
  
    /**
     * Multiply two complex numbers. x * y or multiply(x, y)
     * @param {Complex} x
     * @param {Complex} y
     * @return {Complex | Number} res
     * @private
     */
    function _multiplyComplex (x, y) {
      // Note: we test whether x or y are pure real or pure complex,
      // to prevent unnecessary NaN values. For example, Infinity*i should
      // result in Infinity*i, and not in NaN+Infinity*i
  
      if (x.im == 0) {
        // x is pure real
        if (y.im == 0) {
          // y is pure real
          return new Complex(x.re * y.re, 0);
        }
        else if (y.re == 0) {
          // y is pure complex
          return new Complex(
              0,
              x.re * y.im
          );
        }
        else {
          // y has a real and complex part
          return new Complex(
              x.re * y.re,
              x.re * y.im
          );
        }
      }
      else if (x.re == 0) {
        // x is pure complex
        if (y.im == 0) {
          // y is pure real
          return new Complex(
              0,
              x.im * y.re
          );
        }
        else if (y.re == 0) {
          // y is pure complex
          return new Complex(-x.im * y.im, 0);
        }
        else {
          // y has a real and complex part
          return new Complex(
              -x.im * y.im,
              x.im * y.re
          );
        }
      }
      else {
        // x has a real and complex part
        if (y.im == 0) {
          // y is pure real
          return new Complex(
              x.re * y.re,
              x.im * y.re
          );
        }
        else if (y.re == 0) {
          // y is pure complex
          return new Complex(
              -x.im * y.im,
              x.re * y.im
          );
        }
        else {
          // y has a real and complex part
          return new Complex(
              x.re * y.re - x.im * y.im,
              x.re * y.im + x.im * y.re
          );
        }
      }
    }
  };
  
  },{"../../type/Complex":203,"../../type/Matrix":206,"../../type/Unit":208,"../../type/collection":209,"../../util/index":213,"bignumber.js":218}],138:[function(require,module,exports){
  module.exports = function (math) {
    var util = require('../../util/index'),
  
        BigNumber = require('bignumber.js'),
        Complex = require('../../type/Complex'),
        Matrix = require('../../type/Matrix'),
        collection = require('../../type/collection'),
  
        array = util.array,
        isNumber = util.number.isNumber,
        toNumber = util.number.toNumber,
        toBigNumber = util.number.toBigNumber,
        isBoolean = util['boolean'].isBoolean,
        isArray = Array.isArray,
        isInteger = util.number.isInteger,
        isComplex = Complex.isComplex;
  
    /**
     * Calculates the power of x to y
     *
     *     x ^ y
     *     pow(x, y)
     *
     * @param  {Number | BigNumber | Boolean | Complex | Array | Matrix} x
     * @param  {Number | BigNumber | Boolean | Complex} y
     * @return {Number | BigNumber | Complex | Array | Matrix} res
     */
    math.pow = function pow(x, y) {
      if (arguments.length != 2) {
        throw new math.error.ArgumentsError('pow', arguments.length, 2);
      }
  
      if (isNumber(x)) {
        if (isNumber(y)) {
          if (isInteger(y) || x >= 0) {
            // real value computation
            return Math.pow(x, y);
          }
          else {
            return powComplex(new Complex(x, 0), new Complex(y, 0));
          }
        }
        else if (isComplex(y)) {
          return powComplex(new Complex(x, 0), y);
        }
      }
  
      if (isComplex(x)) {
        if (isNumber(y)) {
          return powComplex(x, new Complex(y, 0));
        }
        else if (isComplex(y)) {
          return powComplex(x, y);
        }
      }
  
      // TODO: pow for complex numbers and bignumbers
  
      if (x instanceof BigNumber) {
        // try to convert to big number
        if (isNumber(y)) {
          y = toBigNumber(y);
        }
        else if (isBoolean(y)) {
          y = new BigNumber(y ? 1 : 0);
        }
  
        if (y instanceof BigNumber) {
          return x.pow(y);
        }
  
        // downgrade to Number
        return pow(toNumber(x), y);
      }
      if (y instanceof BigNumber) {
        // try to convert to big number
        if (isNumber(x)) {
          x = toBigNumber(x);
        }
        else if (isBoolean(x)) {
          x = new BigNumber(x ? 1 : 0);
        }
  
        if (x instanceof BigNumber) {
          return x.pow(y)
        }
  
        // downgrade to Number
        return pow(x, toNumber(y));
      }
  
  
      if (isArray(x)) {
        if (!isNumber(y) || !isInteger(y) || y < 0) {
          throw new TypeError('For A^b, b must be a positive integer ' +
              '(value is ' + y + ')');
        }
        // verify that A is a 2 dimensional square matrix
        var s = array.size(x);
        if (s.length != 2) {
          throw new Error('For A^b, A must be 2 dimensional ' +
              '(A has ' + s.length + ' dimensions)');
        }
        if (s[0] != s[1]) {
          throw new Error('For A^b, A must be square ' +
              '(size is ' + s[0] + 'x' + s[1] + ')');
        }
  
        if (y == 0) {
          // return the identity matrix
          return math.eye(s[0]);
        }
        else {
          // value > 0
          var res = x;
          for (var i = 1; i < y; i++) {
            res = math.multiply(x, res);
          }
          return res;
        }
      }
      else if (x instanceof Matrix) {
        return new Matrix(pow(x.valueOf(), y));
      }
  
      if (isBoolean(x)) {
        return pow(+x, y);
      }
      if (isBoolean(y)) {
        return pow(x, +y);
      }
  
      throw new math.error.UnsupportedTypeError('pow', x, y);
    };
  
    /**
     * Calculates the power of x to y, x^y, for two complex numbers.
     * @param {Complex} x
     * @param {Complex} y
     * @return {Complex} res
     * @private
     */
    function powComplex (x, y) {
      // complex computation
      // x^y = exp(log(x)*y) = exp((abs(x)+i*arg(x))*y)
      var temp1 = math.log(x);
      var temp2 = math.multiply(temp1, y);
      return math.exp(temp2);
    }
  };
  
  },{"../../type/Complex":203,"../../type/Matrix":206,"../../type/collection":209,"../../util/index":213,"bignumber.js":218}],139:[function(require,module,exports){
  module.exports = function (math) {
    var util = require('../../util/index'),
  
        BigNumber = require('bignumber.js'),
        Complex = require('../../type/Complex'),
        collection = require('../../type/collection'),
  
        isNumber = util.number.isNumber,
        isInteger = util.number.isInteger,
        isBoolean = util['boolean'].isBoolean,
        isComplex = Complex.isComplex,
        isCollection = collection.isCollection;
  
    /**
     * Round a value towards the nearest integer
     *
     *     round(x)
     *     round(x, n)
     *
     * For matrices, the function is evaluated element wise.
     *
     * @param  {Number | BigNumber | Boolean | Complex | Array | Matrix} x
     * @param  {Number | BigNumber | Boolean | Array} [n] number of decimals (by default n=0)
     * @return {Number | BigNumber | Complex | Array | Matrix} res
     */
    math.round = function round(x, n) {
      if (arguments.length != 1 && arguments.length != 2) {
        throw new math.error.ArgumentsError('round', arguments.length, 1, 2);
      }
  
      if (n == undefined) {
        // round (x)
        if (isNumber(x)) {
          return Math.round(x);
        }
  
        if (isComplex(x)) {
          return new Complex (
              Math.round(x.re),
              Math.round(x.im)
          );
        }
  
        if (x instanceof BigNumber) {
          return x.round();
        }
  
        if (isCollection(x)) {
          return collection.deepMap(x, round);
        }
  
        if (isBoolean(x)) {
          return Math.round(x);
        }
  
        throw new math.error.UnsupportedTypeError('round', x);
      }
      else {
        // round (x, n)
        if (n instanceof BigNumber) {
          n = parseFloat(n.valueOf());
        }
  
        if (!isNumber(n) || !isInteger(n)) {
          throw new TypeError('Number of decimals in function round must be an integer');
        }
        if (n < 0 || n > 9) {
          throw new Error ('Number of decimals in function round must be in te range of 0-9');
        }
  
        if (isNumber(x)) {
          return roundNumber(x, n);
        }
  
        if (isComplex(x)) {
          return new Complex (
              roundNumber(x.re, n),
              roundNumber(x.im, n)
          );
        }
  
        if (x instanceof BigNumber) {
          if (isNumber(n)) {
            return x.round(n);
          }
        }
  
        if (isCollection(x) || isCollection(n)) {
          return collection.deepMap2(x, n, round);
        }
  
        if (isBoolean(x)) {
          return round(+x, n);
        }
        if (isBoolean(n)) {
          return round(x, +n);
        }
  
        throw new math.error.UnsupportedTypeError('round', x, n);
      }
    };
  
    /**
     * round a number to the given number of decimals, or to zero if decimals is
     * not provided
     * @param {Number} value
     * @param {Number} [decimals]  number of decimals, between 0 and 15 (0 by default)
     * @return {Number} roundedValue
     */
    function roundNumber (value, decimals) {
      if (decimals) {
        var p = Math.pow(10, decimals);
        return Math.round(value * p) / p;
      }
      else {
        return Math.round(value);
      }
    }
  };
  
  },{"../../type/Complex":203,"../../type/collection":209,"../../util/index":213,"bignumber.js":218}],140:[function(require,module,exports){
  module.exports = function (math) {
    var util = require('../../util/index'),
  
        BigNumber = require('bignumber.js'),
        Complex = require('../../type/Complex'),
        collection = require('../../type/collection'),
  
        number = util.number,
        isNumber = util.number.isNumber,
        isBoolean = util['boolean'].isBoolean,
        isComplex = Complex.isComplex,
        isCollection = collection.isCollection;
  
    /**
     * Compute the sign of a value.
     *
     *     sign(x)
     *
     * The sign of a value x is 1 when x > 1, -1 when x < 0, and 0 when x == 0
     * For matrices, the function is evaluated element wise.
     *
     * @param {Number | BigNumber | Boolean | Complex | Array | Matrix} x
     * @return {Number | BigNumber | Complex | Array | Matrix} res
     */
    math.sign = function sign(x) {
      if (arguments.length != 1) {
        throw new math.error.ArgumentsError('sign', arguments.length, 1);
      }
  
      if (isNumber(x)) {
        return number.sign(x);
      }
  
      if (isComplex(x)) {
        var abs = Math.sqrt(x.re * x.re + x.im * x.im);
        return new Complex(x.re / abs, x.im / abs);
      }
  
      if (x instanceof BigNumber) {
        return new BigNumber(x.cmp(0));
      }
  
      if (isCollection(x)) {
        return collection.deepMap(x, sign);
      }
  
      if (isBoolean(x)) {
        return number.sign(x);
      }
  
      throw new math.error.UnsupportedTypeError('sign', x);
    };
  };
  
  },{"../../type/Complex":203,"../../type/collection":209,"../../util/index":213,"bignumber.js":218}],141:[function(require,module,exports){
  module.exports = function (math) {
    var util = require('../../util/index'),
  
        BigNumber = require('bignumber.js'),
        Complex = require('../../type/Complex'),
        Unit = require('../../type/Unit'),
        collection = require('../../type/collection'),
  
        isNumber = util.number.isNumber,
        toNumber = util.number.toNumber,
        toBigNumber = util.number.toBigNumber,
        isBoolean = util['boolean'].isBoolean,
        isString = util.string.isString,
        isComplex = Complex.isComplex,
        isUnit = Unit.isUnit,
        isCollection = collection.isCollection;
  
    /**
     * Check if value x is smaller y
     *
     *     x < y
     *     smaller(x, y)
     *
     * For matrices, the function is evaluated element wise.
     * In case of complex numbers, the absolute values of a and b are compared.
     *
     * @param  {Number | BigNumber | Boolean | Unit | String | Array | Matrix} x
     * @param  {Number | BigNumber | Boolean | Unit | String | Array | Matrix} y
     * @return {Boolean | Array | Matrix} res
     */
    math.smaller = function smaller(x, y) {
      if (arguments.length != 2) {
        throw new math.error.ArgumentsError('smaller', arguments.length, 2);
      }
  
      if (isNumber(x) && isNumber(y)) {
        return x < y;
      }
  
      if (x instanceof BigNumber) {
        // try to convert to big number
        if (isNumber(y)) {
          y = toBigNumber(y);
        }
        else if (isBoolean(y)) {
          y = new BigNumber(y ? 1 : 0);
        }
  
        if (y instanceof BigNumber) {
          return x.lt(y);
        }
  
        // downgrade to Number
        return smaller(toNumber(x), y);
      }
      if (y instanceof BigNumber) {
        // try to convert to big number
        if (isNumber(x)) {
          x = toBigNumber(x);
        }
        else if (isBoolean(x)) {
          x = new BigNumber(x ? 1 : 0);
        }
  
        if (x instanceof BigNumber) {
          return x.lt(y)
        }
  
        // downgrade to Number
        return smaller(x, toNumber(y));
      }
  
      if ((isUnit(x)) && (isUnit(y))) {
        if (!x.equalBase(y)) {
          throw new Error('Cannot compare units with different base');
        }
        return x.value < y.value;
      }
  
      if (isString(x) || isString(y)) {
        return x < y;
      }
  
      if (isCollection(x) || isCollection(y)) {
        return collection.deepMap2(x, y, smaller);
      }
  
      if (isBoolean(x)) {
        return smaller(+x, y);
      }
      if (isBoolean(y)) {
        return smaller(x, +y);
      }
  
      if (isComplex(x) || isComplex(y)) {
        throw new TypeError('No ordering relation is defined for complex numbers');
      }
  
      throw new math.error.UnsupportedTypeError('smaller', x, y);
    };
  };
  
  },{"../../type/Complex":203,"../../type/Unit":208,"../../type/collection":209,"../../util/index":213,"bignumber.js":218}],142:[function(require,module,exports){
  module.exports = function (math) {
    var util = require('../../util/index'),
  
        BigNumber = require('bignumber.js'),
        Complex = require('../../type/Complex'),
        Unit = require('../../type/Unit'),
        collection = require('../../type/collection'),
  
        isNumber = util.number.isNumber,
        toNumber = util.number.toNumber,
        toBigNumber = util.number.toBigNumber,
        isBoolean = util['boolean'].isBoolean,
        isString = util.string.isString,
        isComplex = Complex.isComplex,
        isUnit = Unit.isUnit,
        isCollection = collection.isCollection;
  
    /**
     * Check if value a is smaller or equal to b
     *
     *     a <= b
     *     smallereq(a, b)
     *
     * For matrices, the function is evaluated element wise.
     * In case of complex numbers, the absolute values of a and b are compared.
     *
     * @param  {Number | BigNumber | Boolean | Complex | Unit | String | Array | Matrix} x
     * @param  {Number | BigNumber | Boolean | Complex | Unit | String | Array | Matrix} y
     * @return {Boolean | Array | Matrix} res
     */
    math.smallereq = function smallereq(x, y) {
      if (arguments.length != 2) {
        throw new math.error.ArgumentsError('smallereq', arguments.length, 2);
      }
  
      if (isNumber(x) && isNumber(y)) {
        return x <= y;
      }
  
      if (x instanceof BigNumber) {
        // try to convert to big number
        if (isNumber(y)) {
          y = toBigNumber(y);
        }
        else if (isBoolean(y)) {
          y = new BigNumber(y ? 1 : 0);
        }
  
        if (y instanceof BigNumber) {
          return x.lte(y);
        }
  
        // downgrade to Number
        return smallereq(toNumber(x), y);
      }
      if (y instanceof BigNumber) {
        // try to convert to big number
        if (isNumber(x)) {
          x = toBigNumber(x);
        }
        else if (isBoolean(x)) {
          x = new BigNumber(x ? 1 : 0);
        }
  
        if (x instanceof BigNumber) {
          return x.lte(y)
        }
  
        // downgrade to Number
        return smallereq(x, toNumber(y));
      }
  
      if ((isUnit(x)) && (isUnit(y))) {
        if (!x.equalBase(y)) {
          throw new Error('Cannot compare units with different base');
        }
        return x.value <= y.value;
      }
  
      if (isString(x) || isString(y)) {
        return x <= y;
      }
  
      if (isCollection(x) || isCollection(y)) {
        return collection.deepMap2(x, y, smallereq);
      }
  
      if (isBoolean(x)) {
        return smallereq(+x, y);
      }
      if (isBoolean(y)) {
        return smallereq(x, +y);
      }
  
      if (isComplex(x) || isComplex(y)) {
        throw new TypeError('No ordering relation is defined for complex numbers');
      }
  
      throw new math.error.UnsupportedTypeError('smallereq', x, y);
    };
  };
  
  },{"../../type/Complex":203,"../../type/Unit":208,"../../type/collection":209,"../../util/index":213,"bignumber.js":218}],143:[function(require,module,exports){
  module.exports = function (math) {
    var util = require('../../util/index'),
  
        BigNumber = require('bignumber.js'),
        Complex = require('../../type/Complex'),
        collection = require('../../type/collection'),
  
        isNumber = util.number.isNumber,
        isBoolean = util['boolean'].isBoolean,
        isComplex = Complex.isComplex,
        isCollection = collection.isCollection;
  
    /**
     * Calculate the square root of a value
     *
     *     sqrt(x)
     *
     * For matrices, the function is evaluated element wise.
     *
     * @param {Number | Boolean | Complex | Array | Matrix} x
     * @return {Number | Complex | Array | Matrix} res
     */
    math.sqrt = function sqrt (x) {
      if (arguments.length != 1) {
        throw new math.error.ArgumentsError('sqrt', arguments.length, 1);
      }
  
      if (isNumber(x)) {
        if (x >= 0) {
          return Math.sqrt(x);
        }
        else {
          return sqrt(new Complex(x, 0));
        }
      }
  
      if (isComplex(x)) {
        var r = Math.sqrt(x.re * x.re + x.im * x.im);
        if (x.im >= 0) {
          return new Complex(
              0.5 * Math.sqrt(2.0 * (r + x.re)),
              0.5 * Math.sqrt(2.0 * (r - x.re))
          );
        }
        else {
          return new Complex(
              0.5 * Math.sqrt(2.0 * (r + x.re)),
              -0.5 * Math.sqrt(2.0 * (r - x.re))
          );
        }
      }
  
      if (x instanceof BigNumber) {
        return x.sqrt();
      }
  
      if (isCollection(x)) {
        return collection.deepMap(x, sqrt);
      }
  
      if (isBoolean(x)) {
        return sqrt(+x);
      }
  
      throw new math.error.UnsupportedTypeError('sqrt', x);
    };
  };
  
  },{"../../type/Complex":203,"../../type/collection":209,"../../util/index":213,"bignumber.js":218}],144:[function(require,module,exports){
  module.exports = function (math) {
    var util = require('../../util/index'),
  
        BigNumber = require('bignumber.js'),
        Complex = require('../../type/Complex'),
        collection = require('../../type/collection'),
  
        isNumber = util.number.isNumber,
        isBoolean = util['boolean'].isBoolean,
        isComplex = Complex.isComplex,
        isCollection = collection.isCollection;
  
    /**
     * Compute the square of a value
     *
     *     x .* x
     *     square(x)
     *
     * For matrices, the function is evaluated element wise.
     *
     * @param  {Number | BigNumber | Boolean | Complex | Array | Matrix} x
     * @return {Number | BigNumber | Complex | Array | Matrix} res
     */
    math.square = function square(x) {
      if (arguments.length != 1) {
        throw new math.error.ArgumentsError('square', arguments.length, 1);
      }
  
      if (isNumber(x)) {
        return x * x;
      }
  
      if (isComplex(x)) {
        return math.multiply(x, x);
      }
  
      if (x instanceof BigNumber) {
        return x.times(x);
      }
  
      if (isCollection(x)) {
        return collection.deepMap(x, square);
      }
  
      if (isBoolean(x)) {
        return x * x;
      }
  
      throw new math.error.UnsupportedTypeError('square', x);
    };
  };
  
  },{"../../type/Complex":203,"../../type/collection":209,"../../util/index":213,"bignumber.js":218}],145:[function(require,module,exports){
  module.exports = function (math) {
    var util = require('../../util/index'),
  
        BigNumber = require('bignumber.js'),
        Complex = require('../../type/Complex'),
        Matrix = require('../../type/Matrix'),
        Unit = require('../../type/Unit'),
        collection = require('../../type/collection'),
  
        toNumber = util.number.toNumber,
        toBigNumber = util.number.toBigNumber,
        isBoolean = util['boolean'].isBoolean,
        isNumber = util.number.isNumber,
        isComplex = Complex.isComplex,
        isUnit = Unit.isUnit,
        isCollection = collection.isCollection;
  
    /**
     * Subtract two values
     *
     *     x - y
     *     subtract(x, y)
     *
     * For matrices, the function is evaluated element wise.
     *
     * @param  {Number | BigNumber | Boolean | Complex | Unit | Array | Matrix} x
     * @param  {Number | BigNumber | Boolean | Complex | Unit | Array | Matrix} y
     * @return {Number | BigNumber | Complex | Unit | Array | Matrix} res
     */
    math.subtract = function subtract(x, y) {
      if (arguments.length != 2) {
        throw new math.error.ArgumentsError('subtract', arguments.length, 2);
      }
  
      if (isNumber(x)) {
        if (isNumber(y)) {
          // number - number
          return x - y;
        }
        else if (isComplex(y)) {
          // number - complex
          return new Complex (
              x - y.re,
              - y.im
          );
        }
      }
      else if (isComplex(x)) {
        if (isNumber(y)) {
          // complex - number
          return new Complex (
              x.re - y,
              x.im
          )
        }
        else if (isComplex(y)) {
          // complex - complex
          return new Complex (
              x.re - y.re,
              x.im - y.im
          )
        }
      }
  
      if (x instanceof BigNumber) {
        // try to convert to big number
        if (isNumber(y)) {
          y = toBigNumber(y);
        }
        else if (isBoolean(y)) {
          y = new BigNumber(y ? 1 : 0);
        }
  
        if (y instanceof BigNumber) {
          return x.minus(y);
        }
  
        // downgrade to Number
        return subtract(toNumber(x), y);
      }
      if (y instanceof BigNumber) {
        // try to convert to big number
        if (isNumber(x)) {
          x = toBigNumber(x);
        }
        else if (isBoolean(x)) {
          x = new BigNumber(x ? 1 : 0);
        }
  
        if (x instanceof BigNumber) {
          return x.minus(y)
        }
  
        // downgrade to Number
        return subtract(x, toNumber(y));
      }
  
      if (isUnit(x)) {
        if (isUnit(y)) {
          if (!x.equalBase(y)) {
            throw new Error('Units do not match');
          }
  
          if (x.value == null) {
            throw new Error('Unit on left hand side of operator - has an undefined value');
          }
  
          if (y.value == null) {
            throw new Error('Unit on right hand side of operator - has an undefined value');
          }
  
          var res = x.clone();
          res.value -= y.value;
          res.fixPrefix = false;
  
          return res;
        }
      }
  
      if (isCollection(x) || isCollection(y)) {
        return collection.deepMap2(x, y, subtract);
      }
  
      if (isBoolean(x)) {
        return subtract(+x, y);
      }
      if (isBoolean(y)) {
        return subtract(x, +y);
      }
  
      throw new math.error.UnsupportedTypeError('subtract', x, y);
    };
  };
  
  },{"../../type/Complex":203,"../../type/Matrix":206,"../../type/Unit":208,"../../type/collection":209,"../../util/index":213,"bignumber.js":218}],146:[function(require,module,exports){
  module.exports = function (math) {
    var util = require('../../util/index'),
  
        BigNumber = require('bignumber.js'),
        Complex = require('../../type/Complex'),
        Unit = require('../../type/Unit'),
        collection = require('../../type/collection'),
  
        isNumber = util.number.isNumber,
        isBoolean = util['boolean'].isBoolean,
        isComplex = Complex.isComplex,
        isUnit = Unit.isUnit,
        isCollection = collection.isCollection;
  
    /**
     * Inverse the sign of a value.
     *
     *     -x
     *     unary(x)
     *
     * For matrices, the function is evaluated element wise.
     *
     * @param  {Number | BigNumber | Boolean | Complex | Unit | Array | Matrix} x
     * @return {Number | BigNumber | Complex | Unit | Array | Matrix} res
     */
    math.unary = function unary(x) {
      if (arguments.length != 1) {
        throw new math.error.ArgumentsError('unary', arguments.length, 1);
      }
  
      if (isNumber(x)) {
        return -x;
      }
  
      if (isComplex(x)) {
        return new Complex(
            -x.re,
            -x.im
        );
      }
  
      if (x instanceof BigNumber) {
        return x.neg();
      }
  
      if (isUnit(x)) {
        var res = x.clone();
        res.value = -x.value;
        return res;
      }
  
      if (isCollection(x)) {
        return collection.deepMap(x, unary);
      }
  
      if (isBoolean(x)) {
        return -x;
      }
  
      throw new math.error.UnsupportedTypeError('unary', x);
    };
  };
  
  },{"../../type/Complex":203,"../../type/Unit":208,"../../type/collection":209,"../../util/index":213,"bignumber.js":218}],147:[function(require,module,exports){
  module.exports = function (math) {
    var util = require('../../util/index'),
  
        BigNumber = require('bignumber.js'),
        Complex = require('../../type/Complex'),
        Unit = require('../../type/Unit'),
        collection = require('../../type/collection'),
  
        isNumber = util.number.isNumber,
        toNumber = util.number.toNumber,
        toBigNumber = util.number.toBigNumber,
        isBoolean = util['boolean'].isBoolean,
        isString = util.string.isString,
        isComplex = Complex.isComplex,
        isUnit = Unit.isUnit,
        isCollection = collection.isCollection;
  
    /**
     * Check if value x unequals y, x != y
     * In case of complex numbers, x.re must unequal y.re, or x.im must unequal y.im
     * @param  {Number | BigNumber | Boolean | Complex | Unit | String | Array | Matrix} x
     * @param  {Number | BigNumber | Boolean | Complex | Unit | String | Array | Matrix} y
     * @return {Boolean | Array | Matrix} res
     */
    math.unequal = function unequal(x, y) {
      if (arguments.length != 2) {
        throw new math.error.ArgumentsError('unequal', arguments.length, 2);
      }
  
      if (isNumber(x)) {
        if (isNumber(y)) {
          return x != y;
        }
        else if (isComplex(y)) {
          return (x != y.re) || (y.im != 0);
        }
      }
  
      if (isComplex(x)) {
        if (isNumber(y)) {
          return (x.re != y) || (x.im != 0);
        }
        else if (isComplex(y)) {
          return (x.re != y.re) || (x.im != y.im);
        }
      }
  
      if (x instanceof BigNumber) {
        // try to convert to big number
        if (isNumber(y)) {
          y = toBigNumber(y);
        }
        else if (isBoolean(y)) {
          y = new BigNumber(y ? 1 : 0);
        }
  
        if (y instanceof BigNumber) {
          return !x.eq(y);
        }
  
        // downgrade to Number
        return unequal(toNumber(x), y);
      }
      if (y instanceof BigNumber) {
        // try to convert to big number
        if (isNumber(x)) {
          x = toBigNumber(x);
        }
        else if (isBoolean(x)) {
          x = new BigNumber(x ? 1 : 0);
        }
  
        if (x instanceof BigNumber) {
          return !x.eq(y)
        }
  
        // downgrade to Number
        return unequal(x, toNumber(y));
      }
  
      if ((isUnit(x)) && (isUnit(y))) {
        if (!x.equalBase(y)) {
          throw new Error('Cannot compare units with different base');
        }
        return x.value != y.value;
      }
  
      if (isString(x) || isString(y)) {
        return x != y;
      }
  
      if (isCollection(x) || isCollection(y)) {
        return collection.deepMap2(x, y, unequal);
      }
  
      if (isBoolean(x)) {
        return unequal(+x, y);
      }
      if (isBoolean(y)) {
        return unequal(x, +y);
      }
  
      throw new math.error.UnsupportedTypeError('unequal', x, y);
    };
  };
  
  },{"../../type/Complex":203,"../../type/Unit":208,"../../type/collection":209,"../../util/index":213,"bignumber.js":218}],148:[function(require,module,exports){
  module.exports = function (math) {
    var util = require('../../util/index'),
  
        BigNumber = require('bignumber.js'),
  
        toNumber = util.number.toNumber,
        isNumber = util.number.isNumber,
        isBoolean = util['boolean'].isBoolean,
        isInteger = util.number.isInteger;
  
    /**
     * Calculate the extended greatest common divisor for two values.
     *
     *     xgcd(a, b)
     *
     * @param {Number | Boolean} a  An integer number
     * @param {Number | Boolean} b  An integer number
     * @return {Array}              An array containing 3 integers [div, m, n]
     *                              where div = gcd(a, b) and a*m + b*n = div
     *
     * @see http://en.wikipedia.org/wiki/Extended_Euclidean_algorithm
     */
    math.xgcd = function xgcd(a, b) {
      if (arguments.length == 2) {
        // two arguments
        if (isNumber(a) && isNumber(b)) {
          if (!isInteger(a) || !isInteger(b)) {
            throw new Error('Parameters in function xgcd must be integer numbers');
          }
  
          return _xgcd(a, b);
        }
  
        // TODO: implement BigNumber support for xgcd
  
        // downgrade bignumbers to numbers
        if (a instanceof BigNumber) {
          return xgcd(toNumber(a), b);
        }
        if (b instanceof BigNumber) {
          return xgcd(a, toNumber(b));
        }
  
        if (isBoolean(a)) {
          return xgcd(+a, b);
        }
        if (isBoolean(b)) {
          return xgcd(a, +b);
        }
  
        throw new math.error.UnsupportedTypeError('xgcd', a, b);
      }
  
      // zero or one argument
      throw new SyntaxError('Function xgcd expects two arguments');
    };
  
    /**
     * Calculate xgcd for two numbers
     * @param {Number} a
     * @param {Number} b
     * @private
     */
    function _xgcd(a, b) {
      //*
      // source: http://en.wikipedia.org/wiki/Extended_Euclidean_algorithm
      var t, // used to swap two variables
          q, // quotient
          r, // remainder
          x = 0, lastx = 1,
          y = 1, lasty = 0;
  
      while (b) {
        q = Math.floor(a / b);
        r = a % b;
  
        t = x;
        x = lastx - q * x;
        lastx = t;
  
        t = y;
        y = lasty - q * y;
        lasty = t;
  
        a = b;
        b = r;
      }
  
      if (a < 0) {
        return [-a, a ? -lastx : 0, -lasty];
      }
      else {
        return [a, a ? lastx : 0, lasty];
      }
    }
  };
  
  },{"../../util/index":213,"bignumber.js":218}],149:[function(require,module,exports){
  module.exports = function (math) {
    var util = require('../../util/index'),
  
        BigNumber = require('bignumber.js'),
        Complex = require('../../type/Complex'),
        collection = require('../../type/collection'),
  
        isNumber = util.number.isNumber,
        isBoolean = util['boolean'].isBoolean,
        isCollection = collection.isCollection,
        isComplex = Complex.isComplex;
  
    /**
     * Compute the argument of a complex value.
     * If x = a + bi, the argument is computed as atan2(b, a).
     *
     *     arg(x)
     *
     * For matrices, the function is evaluated element wise.
     *
     * @param {Number | Complex | Array | Matrix | Boolean} x
     * @return {Number | Array | Matrix} res
     */
    math.arg = function arg(x) {
      if (arguments.length != 1) {
        throw new math.error.ArgumentsError('arg', arguments.length, 1);
      }
  
      if (isNumber(x)) {
        return Math.atan2(0, x);
      }
  
      if (isComplex(x)) {
        return Math.atan2(x.im, x.re);
      }
  
      if (isCollection(x)) {
        return collection.deepMap(x, arg);
      }
  
      if (isBoolean(x)) {
        return arg(+x);
      }
  
      if (x instanceof BigNumber) {
        // downgrade to Number
        // TODO: implement BigNumber support
        return arg(util.number.toNumber(x));
      }
  
      throw new math.error.UnsupportedTypeError('arg', x);
    };
  };
  
  },{"../../type/Complex":203,"../../type/collection":209,"../../util/index":213,"bignumber.js":218}],150:[function(require,module,exports){
  module.exports = function (math) {
    var util = require('../../util/index'),
  
        BigNumber = require('bignumber.js'),
        Complex = require('../../type/Complex'),
        collection = require('../../type/collection'),
  
        object = util.object,
        isNumber = util.number.isNumber,
        isBoolean = util['boolean'].isBoolean,
        isCollection =collection.isCollection,
        isComplex = Complex.isComplex;
  
    /**
     * Compute the complex conjugate of a complex value.
     * If x = a+bi, the complex conjugate is a-bi.
     *
     *     conj(x)
     *
     * For matrices, the function is evaluated element wise.
     *
     * @param {Number | BigNumber | Complex | Array | Matrix | Boolean} x
     * @return {Number | BigNumber | Complex | Array | Matrix} res
     */
    math.conj = function conj(x) {
      if (arguments.length != 1) {
        throw new math.error.ArgumentsError('conj', arguments.length, 1);
      }
  
      if (isNumber(x)) {
        return x;
      }
  
      if (x instanceof BigNumber) {
        return new BigNumber(x);
      }
  
      if (isComplex(x)) {
        return new Complex(x.re, -x.im);
      }
  
      if (isCollection(x)) {
        return collection.deepMap(x, conj);
      }
  
      if (isBoolean(x)) {
        return +x;
      }
  
      // return a clone of the value for non-complex values
      return object.clone(x);
    };
  };
  
  },{"../../type/Complex":203,"../../type/collection":209,"../../util/index":213,"bignumber.js":218}],151:[function(require,module,exports){
  module.exports = function (math) {
    var util = require('../../util/index'),
  
        BigNumber = require('bignumber.js'),
        Complex = require('../../type/Complex'),
        collection = require('../../type/collection'),
  
        isNumber = util.number.isNumber,
        isBoolean = util['boolean'].isBoolean,
        isCollection =collection.isCollection,
        isComplex = Complex.isComplex;
  
    /**
     * Get the imaginary part of a complex number.
     *
     *     im(x)
     *
     * For matrices, the function is evaluated element wise.
     *
     * @param {Number | BigNumber | Complex | Array | Matrix | Boolean} x
     * @return {Number | BigNumber | Array | Matrix} im
     */
    math.im = function im(x) {
      if (arguments.length != 1) {
        throw new math.error.ArgumentsError('im', arguments.length, 1);
      }
  
      if (isNumber(x)) {
        return 0;
      }
  
      if (x instanceof BigNumber) {
        return new BigNumber(0);
      }
  
      if (isComplex(x)) {
        return x.im;
      }
  
      if (isCollection(x)) {
        return collection.deepMap(x, im);
      }
  
      if (isBoolean(x)) {
        return 0;
      }
  
      // return 0 for all non-complex values
      return 0;
    };
  };
  
  },{"../../type/Complex":203,"../../type/collection":209,"../../util/index":213,"bignumber.js":218}],152:[function(require,module,exports){
  module.exports = function (math) {
    var util = require('../../util/index'),
  
        BigNumber = require('bignumber.js'),
        Complex = require('../../type/Complex'),
        collection = require('../../type/collection'),
  
        object = util.object,
        isNumber = util.number.isNumber,
        isBoolean = util['boolean'].isBoolean,
        isCollection = collection.isCollection,
        isComplex = Complex.isComplex;
  
    /**
     * Get the real part of a complex number.
     *
     *     re(x)
     *
     * For matrices, the function is evaluated element wise.
     *
     * @param {Number | BigNumber | Complex | Array | Matrix | Boolean} x
     * @return {Number | BigNumber | Array | Matrix} re
     */
    math.re = function re(x) {
      if (arguments.length != 1) {
        throw new math.error.ArgumentsError('re', arguments.length, 1);
      }
  
      if (isNumber(x)) {
        return x;
      }
  
      if (x instanceof BigNumber) {
        return new BigNumber(x);
      }
  
      if (isComplex(x)) {
        return x.re;
      }
  
      if (isCollection(x)) {
        return collection.deepMap(x, re);
      }
  
      if (isBoolean(x)) {
        return +x;
      }
  
      // return a clone of the value itself for all non-complex values
      return object.clone(x);
    };
  };
  
  },{"../../type/Complex":203,"../../type/collection":209,"../../util/index":213,"bignumber.js":218}],153:[function(require,module,exports){
  module.exports = function (math) {
    var util = require('../../util/index'),
  
        BigNumber = require('bignumber.js'),
        collection = require('../../type/collection'),
  
        isCollection = collection.isCollection,
        isNumber = util.number.isNumber,
        isString = util.string.isString,
        isBoolean = util['boolean'].isBoolean;
  
    // extend BigNumber with a function clone
    if (typeof BigNumber.prototype.clone !== 'function') {
      /**
       * Clone a bignumber
       * @return {BigNumber} clone
       */
      BigNumber.prototype.clone = function clone () {
        return new BigNumber(this);
      };
    }
  
    /**
     * Create a big number, which can store numbers with higher precision than
     * a JavaScript Number.
     * When value is a matrix, all elements will be converted to bignumber.
     *
     * @param {Number | String | Array | Matrix} [value]  Value for the big number,
     *                                                    0 by default.
     */
    math.bignumber = function bignumber(value) {
      if (arguments.length > 1) {
        throw new math.error.ArgumentsError('bignumber', arguments.length, 0, 1);
      }
  
      if ((value instanceof BigNumber) || isNumber(value) || isString(value)) {
        return new BigNumber(value);
      }
  
      if (isBoolean(value)) {
        return new BigNumber(+value);
      }
  
      if (isCollection(value)) {
        return collection.deepMap(value, bignumber);
      }
  
      if (arguments.length == 0) {
        return new BigNumber(0);
      }
  
      throw new math.error.UnsupportedTypeError('bignumber', value);
    };
  };
  
  },{"../../type/collection":209,"../../util/index":213,"bignumber.js":218}],154:[function(require,module,exports){
  module.exports = function (math) {
    var util = require('../../util/index'),
  
        BigNumber = require('bignumber.js'),
        collection = require('../../type/collection'),
  
        isCollection = collection.isCollection,
        isNumber = util.number.isNumber,
        isString = util.string.isString;
  
    /**
     * Create a boolean or convert a string or number to a boolean.
     * In case of a number, true is returned for non-zero numbers, and false in
     * case of zero.
     * Strings can be 'true' or 'false', or can contain a number.
     * When value is a matrix, all elements will be converted to boolean.
     * @param {String | Number | Boolean | Array | Matrix} value
     * @return {Boolean | Array | Matrix} bool
     */
    math['boolean'] = function bool (value) {
      if (arguments.length != 1) {
        throw new math.error.ArgumentsError('boolean', arguments.length, 0, 1);
      }
  
      if (value === 'true' || value === true) {
        return true;
      }
  
      if (value === 'false' || value === false) {
        return false;
      }
  
      if (value instanceof Boolean) {
        return value ? true : false;
      }
  
      if (isNumber(value)) {
        return (value !== 0);
      }
  
      if (value instanceof BigNumber) {
        return !value.isZero();
      }
  
      if (isString(value)) {
        // try case insensitive
        var lcase = value.toLowerCase();
        if (lcase === 'true') {
          return true;
        }
        else if (lcase === 'false') {
          return false;
        }
  
        // test whether value is a valid number
        var num = Number(value);
        if (value != '' && !isNaN(num)) {
          return (num !== 0);
        }
      }
  
      if (isCollection(value)) {
        return collection.deepMap(value, bool);
      }
  
      throw new SyntaxError(value.toString() + ' is no valid boolean');
    };
  };
  
  },{"../../type/collection":209,"../../util/index":213,"bignumber.js":218}],155:[function(require,module,exports){
  module.exports = function (math) {
    var util = require('../../util/index'),
  
        BigNumber = require('bignumber.js'),
        Complex = require('../../type/Complex'),
        collection = require('../../type/collection'),
  
        isCollection = collection.isCollection,
        isNumber = util.number.isNumber,
        toNumber = util.number.toNumber,
        isString = util.string.isString,
        isComplex = Complex.isComplex;
  
    /**
     * Create a complex value or convert a value to a complex value.
     *
     * The method accepts the following arguments:
     *     complex()                           creates a complex value with zero
     *                                         as real and imaginary part.
     *     complex(re : number, im : string)   creates a complex value with provided
     *                                         values for real and imaginary part.
     *     complex(re : number)                creates a complex value with provided
     *                                         real value and zero imaginary part.
     *     complex(complex : Complex)          clones the provided complex value.
     *     complex(arg : string)               parses a string into a complex value.
     *     complex(array : Array)              converts the elements of the array
     *                                         or matrix element wise into a
     *                                         complex value.
     *
     * Example usage:
     *     var a = math.complex(3, -4);     // 3 - 4i
     *     a.re = 5;                        // a = 5 - 4i
     *     var i = a.im;                    // -4;
     *     var b = math.complex('2 + 6i');  // 2 + 6i
     *     var c = math.complex();          // 0 + 0i
     *     var d = math.add(a, b);          // 5 + 2i
     *
     * @param {* | Array | Matrix} [args]
     * @return {Complex | Array | Matrix} value
     */
    math.complex = function complex(args) {
      switch (arguments.length) {
        case 0:
          // no parameters. Set re and im zero
          return new Complex(0, 0);
          break;
  
        case 1:
          // parse string into a complex number
          var arg = arguments[0];
  
          if (isNumber(arg)) {
            return new Complex(arg, 0);
          }
  
          if (arg instanceof BigNumber) {
            // convert to Number
            return new Complex(toNumber(arg), 0);
          }
  
          if (isComplex(arg)) {
            // create a clone
            return arg.clone();
          }
  
          if (isString(arg)) {
            var c = Complex.parse(arg);
            if (c) {
              return c;
            }
            else {
              throw new SyntaxError('String "' + arg + '" is no valid complex number');
            }
          }
  
          if (isCollection(arg)) {
            return collection.deepMap(arg, complex);
          }
  
          throw new TypeError(
              'Two numbers or a single string expected in function complex');
          break;
  
        case 2:
          // re and im provided
          var re = arguments[0],
              im = arguments[1];
  
          // convert re to number
          if (re instanceof BigNumber) {
            re = toNumber(re);
          }
  
          // convert im to number
          if (im instanceof BigNumber) {
            im = toNumber(im);
          }
  
          if (isNumber(re) && isNumber(im)) {
            return new Complex(re, im);
          }
          else {
            throw new TypeError(
                'Two numbers or a single string expected in function complex');
          }
  
          break;
  
        default:
          throw new math.error.ArgumentsError('complex', arguments.length, 0, 2);
      }
    };
  };
  
  },{"../../type/Complex":203,"../../type/collection":209,"../../util/index":213,"bignumber.js":218}],156:[function(require,module,exports){
  module.exports = function (math) {
    var util = require('../../util/index'),
  
        BigNumber = require('bignumber.js'),
        Index = require('../../type/Index'),
  
        toNumber = util.number.toNumber;
  
    /**
     * Create an index. An Index can store ranges having start, step, and end
     * for multiple dimensions.
     * Matrix.get, Matrix.set, and math.subset accept an Index as input.
     *
     * Usage:
     *     var index = math.index(range1, range2, ...);
     *
     * Where each range can be any of:
     *     An array [start, end]
     *     An array [start, end, step]
     *     A number
     *     null, this will create select the whole dimension
     *
     * The parameters start, end, and step must be integer numbers.
     *
     * @param {...*} ranges
     */
    math.index = function matrix(ranges) {
      var i = new Index();
  
      // downgrade BigNumber to Number
      var args = Array.prototype.slice.apply(arguments).map(function (arg) {
        if (arg instanceof BigNumber) {
          return toNumber(arg);
        }
        else if (Array.isArray(arg)) {
          return arg.map(function (elem) {
            return (elem instanceof BigNumber) ? toNumber (elem) : elem;
          });
        }
        else {
          return arg;
        }
      });
  
      Index.apply(i, args);
      return i;
    };
  };
  
  },{"../../type/Index":205,"../../util/index":213,"bignumber.js":218}],157:[function(require,module,exports){
  module.exports = function (math) {
    var Matrix = require('../../type/Matrix');
  
    /**
     * Create a matrix. The function creates a new math.type.Matrix object.
     *
     * The method accepts the following arguments:
     *     matrix()       creates an empty matrix
     *     matrix(data)   creates a matrix with initial data.
     *
     * Example usage:
     *     var m = matrix([[1, 2], [3, 4]);
     *     m.size();                        // [2, 2]
     *     m.resize([3, 2], 5);
     *     m.valueOf();                     // [[1, 2], [3, 4], [5, 5]]
     *     m.get([1, 0])                    // 3
     *
     * @param {Array | Matrix} [data]    A multi dimensional array
     * @return {Matrix} matrix
     */
    math.matrix = function matrix(data) {
      if (arguments.length > 1) {
        throw new math.error.ArgumentsError('matrix', arguments.length, 0, 1);
      }
  
      return new Matrix(data);
    };
  };
  
  },{"../../type/Matrix":206}],158:[function(require,module,exports){
  module.exports = function (math) {
    var util = require('../../util/index'),
  
        BigNumber = require('bignumber.js'),
        collection = require('../../type/collection'),
  
        isCollection = collection.isCollection,
        toNumber = util.number.toNumber;
  
    /**
     * Create a number or convert a string to a number.
     * When value is a matrix, all elements will be converted to number.
     * @param {String | Number | Boolean | Array | Matrix} [value]
     * @return {Number | Array | Matrix} num
     */
    math.number = function number (value) {
      switch (arguments.length) {
        case 0:
          return 0;
  
        case 1:
          if (isCollection(value)) {
            return collection.deepMap(value, number);
          }
  
          if (value instanceof BigNumber) {
            return toNumber(value);
          }
  
          var num = Number(value);
          if (isNaN(num)) {
            num = Number(value.valueOf());
          }
          if (isNaN(num)) {
            throw new SyntaxError(value.toString() + ' is no valid number');
          }
          return num;
        default:
          throw new math.error.ArgumentsError('number', arguments.length, 0, 1);
      }
    };
  };
  
  },{"../../type/collection":209,"../../util/index":213,"bignumber.js":218}],159:[function(require,module,exports){
  module.exports = function (math) {
    var Parser = require('../../expression/Parser');
  
    /**
     * Create a parser. The function creates a new math.expression.Parser object.
     *
     *    parser()
     *
     * Example usage:
     *     var parser = new math.parser();
     *
     *     // evaluate expressions
     *     var a = parser.eval('sqrt(3^2 + 4^2)'); // 5
     *     var b = parser.eval('sqrt(-4)');        // 2i
     *     var c = parser.eval('2 inch in cm');    // 5.08 cm
     *     var d = parser.eval('cos(45 deg)');     // 0.7071067811865476
     *
     *     // define variables and functions
     *     parser.eval('x = 7 / 2');               // 3.5
     *     parser.eval('x + 3');                   // 6.5
     *     parser.eval('function f(x, y) = x^y');  // f(x, y)
     *     parser.eval('f(2, 3)');                 // 8
     *
     *     // get and set variables and functions
     *     var x = parser.get('x');                // 7
     *     var f = parser.get('f');                // function
     *     var g = f(3, 2);                        // 9
     *     parser.set('h', 500);
     *     var i = parser.eval('h / 2');           // 250
     *     parser.set('hello', function (name) {
   *         return 'hello, ' + name + '!';
   *     });
     *     parser.eval('hello("user")');           // "hello, user!"
     *
     *     // clear defined functions and variables
     *     parser.clear();
     *
     * @return {Parser} Parser
     */
    math.parser = function parser() {
      return new Parser(math);
    };
  };
  
  },{"../../expression/Parser":4}],160:[function(require,module,exports){
  module.exports = function (math) {
    /**
     * Wrap any value in a Selector, allowing to perform chained operations on
     * the value.
     *
     * All methods available in the math.js library can be called upon the selector,
     * and then will be evaluated with the value itself as first argument.
     * The selector can be closed by executing selector.done(), which will return
     * the final value.
     *
     * Example usage:
     *     math.select(3)
     *         .add(4)
     *         .subtract(2)
     *         .done();     // 5
     *     math.select( [[1, 2], [3, 4]] )
     *         .set([1, 1], 8)
     *         .multiply(3)
     *         .done();     // [[24, 6], [9, 12]]
     *
     * The Selector has a number of special functions:
     * - done()     Finalize the chained operation and return the selectors value.
     * - valueOf()  The same as done()
     * - toString() Executes math.format() onto the selectors value, returning
     *              a string representation of the value.
     * - get(...)   Get a subselection of the selectors value. Only applicable when
     *              the value has a method get, for example when value is a Matrix
     *              or Array.
     * - set(...)   Replace a subselection of the selectors value. Only applicable
     *              when the value has a method get, for example when value is a
     *              Matrix or Array.
     *
     * @param {*} value
     * @return {math.chaining.Selector} selector
     */
    math.select = function select(value) {
      // TODO: check number of arguments
      return new math.chaining.Selector(value);
    };
  };
  
  },{}],161:[function(require,module,exports){
  module.exports = function (math) {
    var util = require('../../util/index'),
  
        collection = require('../../type/collection'),
  
        number = util.number,
        isNumber = util.number.isNumber,
        isCollection = collection.isCollection;
  
    /**
     * Create a string or convert any object into a string.
     * Elements of Arrays and Matrices are processed element wise
     * @param {* | Array | Matrix} [value]
     * @return {String | Array | Matrix} str
     */
    math.string = function string (value) {
      switch (arguments.length) {
        case 0:
          return '';
  
        case 1:
          if (isNumber(value)) {
            return number.format(value);
          }
  
          if (isCollection(value)) {
            return collection.deepMap(value, string);
          }
  
          if (value === null) {
            return 'null';
          }
  
          return value.toString();
  
        default:
          throw new math.error.ArgumentsError('string', arguments.length, 0, 1);
      }
    };
  };
  
  },{"../../type/collection":209,"../../util/index":213}],162:[function(require,module,exports){
  module.exports = function (math) {
    var util = require('../../util/index'),
  
        BigNumber = require('bignumber.js'),
        Unit = require('../../type/Unit'),
        collection = require('../../type/collection'),
  
        isCollection = collection.isCollection,
        toNumber = util.number.toNumber,
        isString = util.string.isString;
  
    /**
     * Create a unit. Depending on the passed arguments, the function
     * will create and return a new math.type.Unit object.
     * When a matrix is provided, all elements will be converted to units.
     *
     * The method accepts the following arguments:
     *     unit(unit : string)
     *     unit(value : number, unit : string)
     *
     * Example usage:
     *     var a = math.unit(5, 'cm');          // 50 mm
     *     var b = math.unit('23 kg');          // 23 kg
     *     var c = math.in(a, math.unit('m');   // 0.05 m
     *
     * @param {* | Array | Matrix} args
     * @return {Unit | Array | Matrix} value
     */
    math.unit = function unit(args) {
      switch(arguments.length) {
        case 1:
          // parse a string
          var arg = arguments[0];
  
          if (arg instanceof Unit) {
            // create a clone of the unit
            return arg.clone();
          }
  
          if (isString(arg)) {
            if (Unit.isPlainUnit(arg)) {
              return new Unit(null, arg); // a pure unit
            }
  
            var u = Unit.parse(arg);        // a unit with value, like '5cm'
            if (u) {
              return u;
            }
  
            throw new SyntaxError('String "' + arg + '" is no valid unit');
          }
  
          if (isCollection(args)) {
            return collection.deepMap(args, unit);
          }
  
          throw new TypeError('A string or a number and string expected in function unit');
          break;
  
        case 2:
          // a number and a unit
  
          if (arguments[0] instanceof BigNumber) {
            // convert value to number
            return new Unit(toNumber(arguments[0]), arguments[1]);
          }
          else {
            return new Unit(arguments[0], arguments[1]);
          }
          break;
  
        default:
          throw new math.error.ArgumentsError('unit', arguments.length, 1, 2);
      }
    };
  };
  
  },{"../../type/Unit":208,"../../type/collection":209,"../../util/index":213,"bignumber.js":218}],163:[function(require,module,exports){
  module.exports = function (math) {
    var util = require('../../util/index'),
  
        Scope = require('../../expression/Scope'),
  
        collection = require('../../type/collection'),
  
        isString = util.string.isString,
        isCollection = collection.isCollection;
  
    /**
     * Evaluate an expression.
     *
     * Syntax:
     *
     *     math.eval(expr)
     *     math.eval(expr, scope)
     *     math.eval([expr1, expr2, expr3, ...])
     *     math.eval([expr1, expr2, expr3, ...], scope)
     *
     * Example:
     *
     *     math.eval('(2+3)/4');                // 1.25
     *     math.eval('sqrt(3^2 + 4^2)');        // 5
     *     math.eval('sqrt(-4)');               // 2i
     *     math.eval(['a=3', 'b=4', 'a*b']);,   // [3, 4, 12]
     *
     *     var scope = {a:3, b:4};
     *     math.eval('a * b', scope);           // 12
     *
     * @param {String | String[] | Matrix} expr
     * @param {Scope | Object} [scope]
     * @return {*} res
     * @throws {Error}
     */
    math.eval = function _eval (expr, scope) {
      if (arguments.length != 1 && arguments.length != 2) {
        throw new math.error.ArgumentsError('eval', arguments.length, 1, 2);
      }
  
      // instantiate a scope
      var evalScope;
      if (scope) {
        if (scope instanceof Scope) {
          evalScope = scope;
        }
        else {
          evalScope = new Scope(math, scope);
        }
      }
      else {
        evalScope = new Scope(math);
      }
  
      if (isString(expr)) {
        // evaluate a single expression
        var node = math.parse(expr, evalScope);
        return node.eval();
      }
      else if (isCollection(expr)) {
        // evaluate an array or matrix with expressions
        return collection.deepMap(expr, function (elem) {
          var node = math.parse(elem, evalScope);
          return node.eval();
        });
      }
      else {
        // oops
        throw new TypeError('String or matrix expected');
      }
    };
  };
  
  },{"../../expression/Scope":5,"../../type/collection":209,"../../util/index":213}],164:[function(require,module,exports){
  module.exports = function (math) {
    var Help = require('../../type/Help');
  
    /**
     * Retrieve help on a function or data type.
     * Help files are retrieved from the documentation in math.expression.docs.
     * @param {function | string | Object} search
     * @return {Help} help
     */
    math.help = function help(search) {
      if (arguments.length != 1) {
        throw new SyntaxError('Wrong number of arguments in function help ' +
            '(' + arguments.length + ' provided, 1 expected)');
      }
  
      var text = null;
      if ((search instanceof String) || (typeof(search) === 'string')) {
        text = search;
      }
      else {
        var prop;
        for (prop in math) {
          // search in functions and constants
          if (math.hasOwnProperty(prop)) {
            if (search === math[prop]) {
              text = prop;
              break;
            }
          }
        }
  
        if (!text) {
          // search data type
          for (prop in math.type) {
            if (math.type.hasOwnProperty(prop)) {
              if (search === math.type[prop]) {
                text = prop;
                break;
              }
            }
          }
        }
      }
  
      if (!text) {
        throw new Error('Could not find search term "' + search + '"');
      }
      else {
        var doc = math.expression.docs[text];
        if (!doc) {
          throw new Error('No documentation found on "' + text + '"');
        }
        return new Help(math, doc);
      }
    };
  };
  
  },{"../../type/Help":204}],165:[function(require,module,exports){
  module.exports = function (math, settings) {
    var util = require('../../util/index'),
  
        toNumber = util.number.toNumber,
        isString = util.string.isString,
        isArray = Array.isArray,
  
        // types
        BigNumber = require('bignumber.js'),
        Complex = require('./../../type/Complex'),
        Matrix = require('./../../type/Matrix'),
        Unit = require('./../../type/Unit'),
        collection = require('../../type/collection'),
  
        // scope and nodes
        Scope = require('./../../expression/Scope'),
        ArrayNode = require('../../expression/node/ArrayNode'),
        AssignmentNode = require('../../expression/node/AssignmentNode'),
        BlockNode = require('../../expression/node/BlockNode'),
        ConstantNode = require('../../expression/node/ConstantNode'),
        FunctionNode = require('../../expression/node/FunctionNode'),
        OperatorNode = require('../../expression/node/OperatorNode'),
        ParamsNode = require('../../expression/node/ParamsNode'),
        RangeNode = require('../../expression/node/RangeNode'),
        SymbolNode = require('../../expression/node/SymbolNode'),
        UnitNode = require('../../expression/node/UnitNode'),
        UpdateNode = require('../../expression/node/UpdateNode'),
        handlers = require('../../expression/node/handlers');
  
    /**
     * Parse an expression. Returns a node tree, which can be evaluated by
     * invoking node.eval();
     *
     * Syntax:
     *
     *     math.parse(expr)
     *     math.parse(expr, scope)
     *     math.parse([expr1, expr2, expr3, ...])
     *     math.parse([expr1, expr2, expr3, ...], scope)
     *
     * Example:
     *
     *     var node = math.parse('sqrt(3^2 + 4^2)');
     *     node.eval(); // 5
     *
     *     var scope = {a:3, b:4}
     *     var node = math.parse('a * b', scope); // 12
     *     node.eval(); // 12
     *     scope.a = 5;
     *     node.eval(); // 20
     *
     *     var nodes = math.parse(['a = 3', 'b = 4', 'a * b']);
     *     nodes[2].eval(); // 12
     *
     * @param {String | String[] | Matrix} expr
     * @param {Scope | Object} [scope]
     * @return {Node | Node[]} node
     * @throws {Error}
     */
    math.parse = function parse (expr, scope) {
      if (arguments.length != 1 && arguments.length != 2) {
        throw new math.error.ArgumentsError('parse', arguments.length, 1, 2);
      }
  
      // instantiate a scope
      var parseScope;
      if (scope) {
        if (scope instanceof Scope) {
          parseScope = scope;
        }
        else {
          parseScope = new Scope(math, scope);
        }
      }
      else {
        parseScope = new Scope(math);
      }
  
      if (isString(expr)) {
        // parse a single expression
        expression = expr || '';
        return parseStart(parseScope);
      }
      else if (isArray(expr) || expr instanceof Matrix) {
        // parse an array or matrix with expressions
        return collection.deepMap(expr, function (elem) {
          expression = elem || '';
          return parseStart(parseScope);
        });
      }
      else {
        // oops
        throw new TypeError('String or matrix expected');
      }
    };
  
    // token types enumeration
    var TOKENTYPE = {
      NULL : 0,
      DELIMITER : 1,
      NUMBER : 2,
      SYMBOL : 3,
      UNKNOWN : 4
    };
  
    // map with all delimiters
    var DELIMITERS = {
      ',': true,
      '(': true,
      ')': true,
      '[': true,
      ']': true,
      '\"': true,
      '\n': true,
      ';': true,
  
      '+': true,
      '-': true,
      '*': true,
      '.*': true,
      '/': true,
      './': true,
      '%': true,
      '^': true,
      '.^': true,
      '!': true,
      '\'': true,
      '=': true,
      ':': true,
  
      '==': true,
      '!=': true,
      '<': true,
      '>': true,
      '<=': true,
      '>=': true
    };
  
      // map with all named delimiters
    var NAMED_DELIMITERS = {
        'mod': true,
        'in': true
    };
  
    var expression = '';  // current expression
    var index = 0;        // current index in expr
    var c = '';           // current token character in expr
    var token = '';       // current token
    var token_type = TOKENTYPE.NULL; // type of the token
  
    /**
     * Get the first character from the expression.
     * The character is stored into the char c. If the end of the expression is
     * reached, the function puts an empty string in c.
     * @private
     */
    function first() {
      index = 0;
      c = expression.charAt(0);
    }
  
    /**
     * Get the next character from the expression.
     * The character is stored into the char c. If the end of the expression is
     * reached, the function puts an empty string in c.
     * @private
     */
    function next() {
      index++;
      c = expression.charAt(index);
    }
  
    /**
     * Preview the next character from the expression.
     * @return {String} cNext
     * @private
     */
    function nextPreview() {
      return expression.charAt(index + 1);
    }
  
    /**
     * Get next token in the current string expr.
     * The token and token type are available as token and token_type
     * @private
     */
    function getToken() {
      token_type = TOKENTYPE.NULL;
      token = '';
  
      // skip over whitespaces
      while (c == ' ' || c == '\t') {  // space or tab
        next();
      }
  
      // skip comment
      if (c == '#') {
        while (c != '\n' && c != '') {
          next();
        }
      }
  
      // check for end of expression
      if (c == '') {
        // token is still empty
        token_type = TOKENTYPE.DELIMITER;
        return;
      }
  
      // check for delimiters consisting of 2 characters
      var c2 = c + nextPreview();
      if (DELIMITERS[c2]) {
        token_type = TOKENTYPE.DELIMITER;
        token = c2;
        next();
        next();
        return;
      }
  
      // check for delimiters consisting of 1 character
      if (DELIMITERS[c]) {
        token_type = TOKENTYPE.DELIMITER;
        token = c;
        next();
        return;
      }
  
      // check for a number
      if (isDigitDot(c)) {
        token_type = TOKENTYPE.NUMBER;
  
        // get number, can have a single dot
        if (c == '.') {
          token += c;
          next();
  
          if (!isDigit(c)) {
            // this is no legal number, it is just a dot
            token_type = TOKENTYPE.UNKNOWN;
          }
        }
        else {
          while (isDigit(c)) {
            token += c;
            next();
          }
          if (c == '.') {
            token += c;
            next();
          }
        }
        while (isDigit(c)) {
          token += c;
          next();
        }
  
        // check for exponential notation like "2.3e-4" or "1.23e50"
        if (c == 'E' || c == 'e') {
          token += c;
          next();
  
          if (c == '+' || c == '-') {
            token += c;
            next();
          }
  
          // Scientific notation MUST be followed by an exponent
          if (!isDigit(c)) {
            // this is no legal number, exponent is missing.
            token_type = TOKENTYPE.UNKNOWN;
          }
  
          while (isDigit(c)) {
            token += c;
            next();
          }
        }
  
        return;
      }
  
      // check for variables, functions, named operators
      if (isAlpha(c)) {
        while (isAlpha(c) || isDigit(c)) {
          token += c;
          next();
        }
  
        if (NAMED_DELIMITERS[token]) {
          token_type = TOKENTYPE.DELIMITER;
        }
        else {
          token_type = TOKENTYPE.SYMBOL;
        }
  
        return;
      }
  
      // something unknown is found, wrong characters -> a syntax error
      token_type = TOKENTYPE.UNKNOWN;
      while (c != '') {
        token += c;
        next();
      }
      throw createSyntaxError('Syntax error in part "' + token + '"');
    }
  
    /**
     * Check if a given name is valid
     * if not, an error is thrown
     * @param {String} name
     * @return {boolean} valid
     * @private
     */
      // TODO: check for valid symbol name
    function isValidSymbolName (name) {
      for (var i = 0, iMax = name.length; i < iMax; i++) {
        var c = name.charAt(i);
        //var valid = (isAlpha(c) || (i > 0 && isDigit(c))); // TODO: allow digits in symbol name
        var valid = (isAlpha(c));
        if (!valid) {
          return false;
        }
      }
  
      return true;
    }
  
    /**
     * checks if the given char c is a letter (upper or lower case)
     * or underscore
     * @param {String} c   a string with one character
     * @return {Boolean}
     * @private
     */
    function isAlpha (c) {
      return ((c >= 'a' && c <= 'z') ||
          (c >= 'A' && c <= 'Z') ||
          c == '_');
    }
  
    /**
     * checks if the given char c is a digit or dot
     * @param {String} c   a string with one character
     * @return {Boolean}
     * @private
     */
    function isDigitDot (c) {
      return ((c >= '0' && c <= '9') ||
          c == '.');
    }
  
    /**
     * checks if the given char c is a digit
     * @param {String} c   a string with one character
     * @return {Boolean}
     * @private
     */
    function isDigit (c) {
      return ((c >= '0' && c <= '9'));
    }
  
    /**
     * Start of the parse levels below, in order of precedence
     * @param {Scope} scope
     * @return {Node} node
     * @private
     */
    function parseStart (scope) {
      // get the first character in expression
      first();
  
      getToken();
  
      var node;
      if (token == '') {
        // empty expression
        node = new ConstantNode(undefined);
      }
      else {
        node = parseBlock(scope);
      }
  
      // check for garbage at the end of the expression
      // an expression ends with a empty character '' and token_type DELIMITER
      if (token != '') {
        if (token_type == TOKENTYPE.DELIMITER) {
          // user entered a not existing operator like "//"
  
          // TODO: give hints for aliases, for example with "<>" give as hint " did you mean != ?"
          throw createError('Unknown operator ' + token);
        }
        else {
          throw createSyntaxError('Unexpected part "' + token + '"');
        }
      }
  
      return node;
    }
  
    /**
     * Parse a block with expressions. Expressions can be separated by a newline
     * character '\n', or by a semicolon ';'. In case of a semicolon, no output
     * of the preceding line is returned.
     * @param {Scope} scope
     * @return {Node} node
     * @private
     */
    function parseBlock (scope) {
      var node, block, visible;
  
      if (token != '\n' && token != ';' && token != '') {
        node = parseAns(scope);
      }
  
      while (token == '\n' || token == ';') {
        if (!block) {
          // initialize the block
          block = new BlockNode();
          if (node) {
            visible = (token != ';');
            block.add(node, visible);
          }
        }
  
        getToken();
        if (token != '\n' && token != ';' && token != '') {
          node = parseAns(scope);
  
          visible = (token != ';');
          block.add(node, visible);
        }
      }
  
      if (block) {
        return block;
      }
  
      if (!node) {
        node = parseAns(scope);
      }
  
      return node;
    }
  
    /**
     * Parse assignment of ans.
     * Ans is assigned when the expression itself is no variable or function
     * assignment
     * @param {Scope} scope
     * @return {Node} node
     * @private
     */
    function parseAns (scope) {
      var expression = parseFunctionAssignment(scope);
  
      // create a variable definition for ans
      var name = 'ans';
      return new AssignmentNode(name, expression, scope);
    }
  
    /**
     * Parse a function assignment like "function f(a,b) = a*b"
     * @param {Scope} scope
     * @return {Node} node
     * @private
     */
    function parseFunctionAssignment (scope) {
      // TODO: keyword 'function' must become a reserved keyword
      // TODO: replace the 'function' keyword with an assignment operator '=>'
      if (token_type == TOKENTYPE.SYMBOL && token == 'function') {
        // get function name
        getToken();
        if (token_type != TOKENTYPE.SYMBOL) {
          throw createSyntaxError('Function name expected');
        }
        var name = token;
  
        // get parenthesis open
        getToken();
        if (token != '(') {
          throw createSyntaxError('Opening parenthesis ( expected');
        }
  
        // get function variables
        var functionScope = scope.createSubScope();
        var variables = [];
        while (true) {
          getToken();
          if (token_type == TOKENTYPE.SYMBOL) {
            // store variable name
            variables.push(token);
  
            getToken();
          }
  
          if (token == ',') {
            // ok, nothing to do, read next variable
          }
          else if (token == ')') {
            // end of variable list encountered. break loop
            break;
          }
          else {
            throw createSyntaxError('Comma , or closing parenthesis ) expected"');
          }
        }
  
        getToken();
        if (token != '=') {
          throw createSyntaxError('Equal sign = expected');
        }
  
        // parse the expression, with the correct function scope
        getToken();
        var expression = parseAssignment(functionScope);
  
        return new FunctionNode(name, variables, expression, functionScope, scope);
      }
  
      return parseAssignment(scope);
    }
  
    /**
     * Assignment of a variable, can be a variable like "a=2.3" or a updating an
     * existing variable like "matrix(2,3:5)=[6,7,8]"
     * @param {Scope} scope
     * @return {Node} node
     * @private
     */
    function parseAssignment (scope) {
      var name, params, paramScopes, expr;
  
      var node = parseRange(scope);
  
      if (token == '=') {
        if (node instanceof SymbolNode) {
          // parse the expression, with the correct function scope
          getToken();
          name = node.name;
          params = null;
          expr = parseAssignment(scope);
          return new AssignmentNode(name, expr, scope);
        }
        else if ((node instanceof ParamsNode) && (node.object instanceof SymbolNode)) {
          // parse the expression, with the correct function scope
          getToken();
          name = node.object.name;
          params = node.params;
          paramScopes = node.paramScopes;
          expr = parseAssignment(scope);
          return new UpdateNode(math, name, params, paramScopes, expr, scope);
        }
        else {
          throw createSyntaxError('Symbol expected at the left hand side ' +
              'of assignment operator =');
        }
      }
  
      return node;
    }
  
    /**
     * parse range, "start:end", "start:step:end", ":", "start:", ":end", etc
     * @param {Scope} scope
     * @return {Node} node
     * @private
     */
    function parseRange (scope) {
      var node, params = [];
  
      if (token == ':') {
        // implicit start=1 (one-based)
        var one = (settings.number === 'bignumber') ? new BigNumber(1) : 1;
        node = new ConstantNode(one);
      }
      else {
        // explicit start
        node = parseBitwiseConditions(scope);
      }
  
      if (token == ':') {
        params.push(node);
  
        // parse step and end
        while (token == ':') {
          getToken();
          if (token == ')' || token == ',' || token == '') {
            // implicit end
            params.push(new SymbolNode('end', scope));
          }
          else {
            // explicit end
            params.push(parseBitwiseConditions(scope));
          }
        }
  
        if (params.length) {
          node = new RangeNode(math, settings, params);
        }
      }
  
      return node;
    }
  
    /**
     * conditional operators and bitshift
     * @param {Scope} scope
     * @return {Node} node
     * @private
     */
    function parseBitwiseConditions (scope) {
      var node = parseComparison(scope);
  
      /* TODO: implement bitwise conditions
       var operators = {
       '&' : bitwiseand,
       '|' : bitwiseor,
       // todo: bitwise xor?
       '<<': bitshiftleft,
       '>>': bitshiftright
       };
       while (token in operators) {
       var name = token;
       var fn = operators[name];
  
       getToken();
       var params = [node, parseComparison()];
       node = new OperatorNode(name, fn, params);
       }
       */
  
      return node;
    }
  
    /**
     * comparison operators
     * @param {Scope} scope
     * @return {Node} node
     * @private
     */
    function parseComparison (scope) {
      var node, operators, name, fn, params;
  
      node = parseConditions(scope);
  
      operators = {
        '==': math.equal,
        '!=': math.unequal,
        '<': math.smaller,
        '>': math.larger,
        '<=': math.smallereq,
        '>=': math.largereq
      };
      while (token in operators) {
        name = token;
        fn = operators[name];
  
        getToken();
        params = [node, parseConditions(scope)];
        node = new OperatorNode(name, fn, params);
      }
  
      return node;
    }
  
    /**
     * conditions like and, or, in
     * @param {Scope} scope
     * @return {Node} node
     * @private
     */
    function parseConditions (scope) {
      var node, operators, name, fn, params;
  
      node = parseAddSubtract(scope);
  
      // TODO: precedence of And above Or?
      // TODO: implement a method for unit to number conversion
      operators = {
        'in' : math['in']
        /* TODO: implement conditions
         'and' : 'and',
         '&&' : 'and',
         'or': 'or',
         '||': 'or',
         'xor': 'xor'
         */
      };
  
      while (token in operators) {
        name = token;
        fn = operators[name];
  
        getToken();
        params = [node, parseAddSubtract(scope)];
        node = new OperatorNode(name, fn, params);
      }
  
      return node;
    }
  
    /**
     * add or subtract
     * @param {Scope} scope
     * @return {Node} node
     * @private
     */
    function parseAddSubtract (scope)  {
      var node, operators, name, fn, params;
  
      node = parseMultiplyDivide(scope);
  
      operators = {
        '+': math.add,
        '-': math.subtract
      };
      while (token in operators) {
        name = token;
        fn = operators[name];
  
        getToken();
        params = [node, parseMultiplyDivide(scope)];
        node = new OperatorNode(name, fn, params);
      }
  
      return node;
    }
  
    /**
     * multiply, divide, modulus
     * @param {Scope} scope
     * @return {Node} node
     * @private
     */
    function parseMultiplyDivide (scope) {
      var node, operators, name, fn, params;
  
      node = parseUnit(scope);
  
      operators = {
        '*': math.multiply,
        '.*': math.emultiply,
        '/': math.divide,
        './': math.edivide,
        '%': math.mod,
        'mod': math.mod
      };
  
      while (token in operators) {
        name = token;
        fn = operators[name];
  
        getToken();
        params = [node, parseUnit(scope)];
        node = new OperatorNode(name, fn, params);
      }
  
      return node;
    }
  
    /**
     * parse units like in '2i', '2 cm'
     * @param {Scope} scope
     * @return {Node} node
     * @private
     */
    function parseUnit(scope) {
      var node, symbol;
  
      node = parseUnary(scope);
  
      while (token_type == TOKENTYPE.SYMBOL) {
        symbol = token;
  
        getToken();
  
        node = new UnitNode(node, symbol);
      }
  
      return node;
    }
  
    /**
     * Unary minus
     * @param {Scope} scope
     * @return {Node} node
     * @private
     */
    function parseUnary (scope) {
      var name, fn, params;
  
      if (token == '-') {
        name = token;
        fn = math.unary;
        getToken();
        params = [parseUnary(scope)];
  
        return new OperatorNode(name, fn, params);
      }
  
      return parsePow(scope);
    }
  
    /**
     * power
     * Note: power operator is right associative
     * @param {Scope} scope
     * @return {Node} node
     * @private
     */
    function parsePow (scope) {
      var node, leftNode, nodes, ops, name, fn, params;
  
      nodes = [
        parseLeftHandOperators(scope)
      ];
      ops = [];
  
      // stack all operands of a chained power operator (like '2^3^3')
      while (token == '^' || token == '.^') {
        ops.push(token);
        getToken();
        nodes.push(parseLeftHandOperators(scope));
      }
  
      // evaluate the operands from right to left (right associative)
      node = nodes.pop();
      while (nodes.length) {
        leftNode = nodes.pop();
        name = ops.pop();
        fn = (name == '^') ? math.pow : math.epow;
        params = [leftNode, node];
        node = new OperatorNode(name, fn, params);
      }
  
      return node;
    }
  
    /**
     * Left hand operators: factorial x!, transpose x'
     * @param {Scope} scope
     * @return {Node} node
     * @private
     */
    function parseLeftHandOperators (scope)  {
      var node, operators, name, fn, params;
  
      node = parseNodeHandler(scope);
  
      operators = {
        '!': math.factorial,
        '\'': math.transpose
      };
  
      while (token in operators) {
        name = token;
        fn = operators[name];
  
        getToken();
        params = [node];
  
        node = new OperatorNode(name, fn, params);
      }
  
      return node;
    }
  
    /**
     * Parse a custom node handler. A node handler can be used to process
     * nodes in a custom way, for example for handling a plot.
     *
     * A handler must be defined in the namespace math.expression.node.handlers,
     * and must extend math.expression.node.Node, and the handler must contain
     * functions eval(), find(filter), and toString().
     *
     * For example:
     *
     *     math.expression.node.handlers['plot'] = PlotHandler;
     *
     * The constructor of the handler is called as:
     *
     *     node = new PlotHandler(params, paramScopes);
     *
     * The handler will be invoked when evaluating an expression like:
     *
     *     node = math.parse('plot(sin(x), x)');
     *
     * @param {Scope} scope
     * @return {Node} node
     * @private
     */
    function parseNodeHandler (scope) {
      var params,
          paramScopes,
          paramScope,
          handler;
  
      if (token_type == TOKENTYPE.SYMBOL && handlers[token]) {
        handler = handlers[token];
  
        getToken();
  
        // parse parameters
        if (token == '(') {
          params = [];
          paramScopes = [];
  
          getToken();
  
          if (token != ')') {
            paramScope = scope.createSubScope();
            paramScopes.push(paramScope);
            params.push(parseRange(paramScope));
  
            // parse a list with parameters
            while (token == ',') {
              getToken();
  
              paramScope = scope.createSubScope();
              paramScopes.push(paramScope);
              params.push(parseRange(paramScope));
            }
          }
  
          if (token != ')') {
            throw createSyntaxError('Parenthesis ) expected');
          }
          getToken();
        }
  
        // create a new node handler
        //noinspection JSValidateTypes
        return new handler(params, paramScopes);
      }
  
      return parseSymbol(scope);
    }
  
    /**
     * parse symbols: functions, variables, constants, units
     * @param {Scope} scope
     * @return {Node} node
     * @private
     */
    function parseSymbol (scope) {
      var node, name;
  
      if (token_type == TOKENTYPE.SYMBOL ||
          (token_type == TOKENTYPE.DELIMITER && token in NAMED_DELIMITERS)) {
        name = token;
  
        getToken();
  
        // create a symbol
        node = new SymbolNode(name, scope);
  
        // parse parameters
        return parseParams(scope, node);
      }
  
      return parseString(scope);
    }
  
    /**
     * parse parameters, enclosed in parenthesis
     * @param {Scope} scope
     * @param {Node} node    Node on which to apply the parameters. If there
     *                       are no parameters in the expression, the node
     *                       itself is returned
     * @return {Node} node
     * @private
     */
    function parseParams (scope, node) {
      var bracket,
          params,
          paramScopes,
          paramScope;
  
      while (token == '(') {
        bracket = token;
        params = [];
        paramScopes = [];
  
        getToken();
  
        if (token != ')') {
          paramScope = scope.createSubScope();
          paramScopes.push(paramScope);
          params.push(parseRange(paramScope));
  
          // parse a list with parameters
          while (token == ',') {
            getToken();
  
            paramScope = scope.createSubScope();
            paramScopes.push(paramScope);
            params.push(parseRange(paramScope));
          }
        }
  
        if ((bracket == '(' && token != ')')) {
          throw createSyntaxError('Parenthesis ) expected');
        }
        getToken();
  
        node = new ParamsNode(math, node, params, paramScopes);
      }
  
      return node;
    }
  
    /**
     * parse a string.
     * A string is enclosed by double quotes
     * @param {Scope} scope
     * @return {Node} node
     * @private
     */
    function parseString (scope) {
      var node, str, tPrev;
  
      if (token == '"') {
        // string "..."
        str = '';
        tPrev = '';
        while (c != '' && (c != '\"' || tPrev == '\\')) { // also handle escape character
          str += c;
          tPrev = c;
          next();
        }
  
        getToken();
        if (token != '"') {
          throw createSyntaxError('End of string " expected');
        }
        getToken();
  
        // create constant
        node = new ConstantNode(str);
  
        // parse parameters
        node = parseParams(scope, node);
  
        return node;
      }
  
      return parseMatrix(scope);
    }
  
    /**
     * parse the matrix
     * @param {Scope} scope
     * @return {Node} node
     * @private
     */
    function parseMatrix (scope) {
      var array, params, rows, cols;
  
      if (token == '[') {
        // matrix [...]
  
        // skip newlines
        getToken();
        while (token == '\n') {
          getToken();
        }
  
        if (token != ']') {
          // this is a non-empty matrix
          var row = parseRow(scope);
  
          if (token == ';') {
            // 2 dimensional array
            rows = 1;
            params = [row];
  
            // the rows of the matrix are separated by dot-comma's
            while (token == ';') {
              getToken();
  
              // skip newlines
              while (token == '\n') {
                getToken();
              }
  
              params[rows] = parseRow(scope);
              rows++;
  
              // skip newlines
              while (token == '\n') {
                getToken();
              }
            }
  
            if (token != ']') {
              throw createSyntaxError('End of matrix ] expected');
            }
            getToken();
  
            // check if the number of columns matches in all rows
            cols = (params.length > 0) ? params[0].length : 0;
            for (var r = 1; r < rows; r++) {
              if (params[r].length != cols) {
                throw createError('Number of columns must match ' +
                    '(' + params[r].length + ' != ' + cols + ')');
              }
            }
  
            array = new ArrayNode(settings, params);
          }
          else {
            // 1 dimensional vector
            if (token != ']') {
              throw createSyntaxError('End of matrix ] expected');
            }
            getToken();
  
            array = row;
          }
        }
        else {
          // this is an empty matrix "[ ]"
          getToken();
          array = new ArrayNode(settings, []);
        }
  
        // parse parameters
        array = parseParams(scope, array);
  
        return array;
      }
  
      return parseNumber(scope);
    }
  
    /**
     * Parse a single comma-separated row from a matrix, like 'a, b, c'
     * @param {Scope} scope
     * @return {ArrayNode} node
     */
    function parseRow (scope) {
      var params = [parseAssignment(scope)];
      var len = 1;
  
      while (token == ',') {
        getToken();
  
        // skip newlines
        while (token == '\n') {
          getToken();
        }
  
        // parse expression
        params[len] = parseAssignment(scope);
        len++;
  
        // skip newlines
        while (token == '\n') {
          getToken();
        }
      }
  
      return new ArrayNode(settings, params);
    }
  
    /**
     * parse a number
     * @param {Scope} scope
     * @return {Node} node
     * @private
     */
    function parseNumber (scope) {
      var node, value, number;
  
      if (token_type == TOKENTYPE.NUMBER) {
        // this is a number
        if (settings.number == 'bignumber') {
          // parse a big number
          number = new BigNumber((token == '.') ? 0 : token);
        }
        else {
          // parse a regular number
          number = (token == '.') ? 0 : Number(token);
        }
        getToken();
  
        if (token == 'i' || token == 'I') {
          // create a complex number
  
          // convert bignumber to number as Complex doesn't support BigNumber
          number = (number instanceof BigNumber) ? toNumber(number) : number;
  
          value = new Complex(0, number);
          getToken();
          node = new ConstantNode(value);
        }
        else {
          // a real number
          node = new ConstantNode(number);
        }
  
        // parse parameters
        node = parseParams(scope, node);
  
        return node;
      }
  
      return parseParentheses(scope);
    }
  
    /**
     * parentheses
     * @param {Scope} scope
     * @return {Node} node
     * @private
     */
    function parseParentheses (scope) {
      var node;
  
      // check if it is a parenthesized expression
      if (token == '(') {
        // parentheses (...)
        getToken();
        node = parseAssignment(scope); // start again
  
        if (token != ')') {
          throw createSyntaxError('Parenthesis ) expected');
        }
        getToken();
  
        /* TODO: implicit multiplication?
         // TODO: how to calculate a=3; 2/2a ? is this (2/2)*a or 2/(2*a) ?
         // check for implicit multiplication
         if (token_type == TOKENTYPE.SYMBOL) {
         node = multiply(node, parsePow());
         }
         //*/
  
        // parse parameters
        node = parseParams(scope, node);
  
        return node;
      }
  
      return parseEnd(scope);
    }
  
    /**
     * Evaluated when the expression is not yet ended but expected to end
     * @param {Scope} scope
     * @return {Node} res
     * @private
     */
    function parseEnd (scope) {
      if (token == '') {
        // syntax error or unexpected end of expression
        throw createSyntaxError('Unexpected end of expression');
      } else {
        throw createSyntaxError('Value expected');
      }
    }
  
    /**
     * Shortcut for getting the current row value (one based)
     * Returns the line of the currently handled expression
     * @private
     */
    function row () {
      // TODO: also register row number during parsing
      return undefined;
    }
  
    /**
     * Shortcut for getting the current col value (one based)
     * Returns the column (position) where the last token starts
     * @private
     */
    function col () {
      return index - token.length + 1;
    }
  
    /**
     * Build up an error message
     * @param {String} message
     * @return {String} message with row and column information
     * @private
     */
    function createErrorMessage (message) {
      var r = row();
      var c = col();
      if (r === undefined) {
        if (c === undefined) {
          return message;
        } else {
          return message + ' (char ' + c + ')';
        }
      } else {
        return message + ' (line ' + r + ', char ' + c + ')';
      }
    }
  
    /**
     * Create an error
     * @param {String} message
     * @return {SyntaxError} instantiated error
     * @private
     */
    function createSyntaxError (message) {
      return new SyntaxError(createErrorMessage(message));
    }
  
    /**
     * Create an error
     * @param {String} message
     * @return {TypeError} instantiated error
     * @private
     */
    function createTypeError(message) {
      return new TypeError(createErrorMessage(message));
    }
  
    /**
     * Create an error
     * @param {String} message
     * @return {Error} instantiated error
     * @private
     */
    function createError (message) {
      return new Error(createErrorMessage(message));
    }
  };
  
  },{"../../expression/node/ArrayNode":104,"../../expression/node/AssignmentNode":105,"../../expression/node/BlockNode":106,"../../expression/node/ConstantNode":107,"../../expression/node/FunctionNode":108,"../../expression/node/OperatorNode":110,"../../expression/node/ParamsNode":111,"../../expression/node/RangeNode":112,"../../expression/node/SymbolNode":113,"../../expression/node/UnitNode":114,"../../expression/node/UpdateNode":115,"../../expression/node/handlers":116,"../../type/collection":209,"../../util/index":213,"./../../expression/Scope":5,"./../../type/Complex":203,"./../../type/Matrix":206,"./../../type/Unit":208,"bignumber.js":218}],166:[function(require,module,exports){
  module.exports = function (math) {
    var util = require('../../util/index'),
  
        Matrix = require('../../type/Matrix'),
        collection = require('../../type/collection'),
  
        object = util.object,
        array = util.array,
        isNumber = util.number.isNumber,
        isInteger = util.number.isInteger,
        isCollection = collection.isCollection;
  
    /**
     * Concatenate two or more matrices
     * Usage:
     *     math.concat(A, B, C, ...)
     *     math.concat(A, B, C, ..., dim)
     *
     * Where the optional dim is the zero-based number of the dimension to be
     * concatenated.
     *
     * @param {... Array | Matrix} args
     * @return {Array | Matrix} res
     */
    math.concat = function concat (args) {
      var i,
          len = arguments.length,
          dim = -1,  // zero-based dimension
          prevDim,
          asMatrix = false,
          matrices = [];  // contains multi dimensional arrays
  
      for (i = 0; i < len; i++) {
        var arg = arguments[i];
  
        // test whether we need to return a Matrix (if not we return an Array)
        if (arg instanceof Matrix) {
          asMatrix = true;
        }
  
        if ((i == len - 1) && isNumber(arg)) {
          // last argument contains the dimension on which to concatenate
          prevDim = dim;
          dim = arg;
  
          if (!isInteger(dim) || dim < 0) {
            throw new TypeError('Dimension number must be a positive integer ' +
                '(dim = ' + dim + ')');
          }
  
          if (i > 0 && dim > prevDim) {
            throw new RangeError('Dimension out of range ' +
                '(' + dim + ' > ' + prevDim + ')');
          }
        }
        else if (isCollection(arg)) {
          // this is a matrix or array
          var matrix = object.clone(arg).valueOf();
          var size = array.size(arg.valueOf());
          matrices[i] = matrix;
          prevDim = dim;
          dim = size.length - 1;
  
          // verify whether each of the matrices has the same number of dimensions
          if (i > 0 && dim != prevDim) {
            throw new RangeError('Dimension mismatch ' +
                '(' + prevDim + ' != ' + dim + ')');
          }
        }
        else {
          throw new math.error.UnsupportedTypeError('concat', arg);
        }
      }
  
      if (matrices.length == 0) {
        throw new SyntaxError('At least one matrix expected');
      }
  
      var res = matrices.shift();
      while (matrices.length) {
        res = _concat(res, matrices.shift(), dim, 0);
      }
  
      return asMatrix ? new Matrix(res) : res;
    };
  
    /**
     * Recursively concatenate two matrices.
     * The contents of the matrices is not cloned.
     * @param {Array} a             Multi dimensional array
     * @param {Array} b             Multi dimensional array
     * @param {Number} concatDim    The dimension on which to concatenate (zero-based)
     * @param {Number} dim          The current dim (zero-based)
     * @return {Array} c            The concatenated matrix
     * @private
     */
    function _concat(a, b, concatDim, dim) {
      if (dim < concatDim) {
        // recurse into next dimension
        if (a.length != b.length) {
          throw new Error('Dimensions mismatch (' + a.length + ' != ' + b.length + ')');
        }
  
        var c = [];
        for (var i = 0; i < a.length; i++) {
          c[i] = _concat(a[i], b[i], concatDim, dim + 1);
        }
        return c;
      }
      else {
        // concatenate this dimension
        return a.concat(b);
      }
    }
  };
  
  },{"../../type/Matrix":206,"../../type/collection":209,"../../util/index":213}],167:[function(require,module,exports){
  module.exports = function (math) {
    var util = require('../../util/index'),
  
        Matrix = require('../../type/Matrix'),
  
        object = util.object,
        array = util.array,
        string = util.string;
  
    /**
     * @constructor det
     * Calculate the determinant of a matrix
     *
     *     det(x)
     *
     * @param {Array | Matrix} x
     * @return {Number} determinant
     */
    math.det = function det (x) {
      if (arguments.length != 1) {
        throw new math.error.ArgumentsError('det', arguments.length, 1);
      }
  
      var size = array.size(x.valueOf());
      switch (size.length) {
        case 0:
          // scalar
          return object.clone(x);
          break;
  
        case 1:
          // vector
          if (size[0] == 1) {
            return object.clone(x.valueOf()[0]);
          }
          else {
            throw new RangeError('Matrix must be square ' +
                '(size: ' + string.format(size) + ')');
          }
          break;
  
        case 2:
          // two dimensional array
          var rows = size[0];
          var cols = size[1];
          if (rows == cols) {
            return _det(x.valueOf(), rows, cols);
          }
          else {
            throw new RangeError('Matrix must be square ' +
                '(size: ' + string.format(size) + ')');
          }
          break;
  
        default:
          // multi dimensional array
          throw new RangeError('Matrix must be two dimensional ' +
              '(size: ' + string.format(size) + ')');
      }
    };
  
    /**
     * Calculate the determinant of a matrix
     * @param {Array[]} matrix  A square, two dimensional matrix
     * @param {Number} rows     Number of rows of the matrix (zero-based)
     * @param {Number} cols     Number of columns of the matrix (zero-based)
     * @returns {Number} det
     * @private
     */
    function _det (matrix, rows, cols) {
      if (rows == 1) {
        // this is a 1 x 1 matrix
        return matrix[0][0];
      }
      else if (rows == 2) {
        // this is a 2 x 2 matrix
        // the determinant of [a11,a12;a21,a22] is det = a11*a22-a21*a12
        return math.subtract(
            math.multiply(matrix[0][0], matrix[1][1]),
            math.multiply(matrix[1][0], matrix[0][1])
        );
      }
      else {
        // this is an n x n matrix
        var d = 1;
        var lead = 0;
        for (var r = 0; r < rows; r++) {
          if (lead >= cols) {
            break;
          }
          var i = r;
          // Find the pivot element.
          while (matrix[i][lead] == 0) {
            i++;
            if (i == rows) {
              i = r;
              lead++;
              if (lead == cols) {
                // We found the last pivot.
                if (object.deepEqual(matrix, eye(rows).valueOf())) {
                  return math.round(d, 6);
                } else {
                  return 0;
                }
              }
            }
          }
          if (i != r) {
            // Swap rows i and r, which negates the determinant.
            for (var a = 0; a < cols; a++) {
              var temp = matrix[i][a];
              matrix[i][a] = matrix[r][a];
              matrix[r][a] = temp;
            }
            d *= -1;
          }
          // Scale row r and the determinant simultaneously.
          var div = matrix[r][lead];
          for (var a = 0; a < cols; a++) {
            matrix[r][a] = matrix[r][a] / div;
          }
          d *= div;
          // Back-substitute upwards.
          for (var j = 0; j < rows; j++) {
            if (j != r) {
              // Taking linear combinations does not change the det.
              var c = matrix[j][lead];
              for (var a = 0; a < cols; a++) {
                matrix[j][a] = matrix[j][a] - matrix[r][a] * c;
              }
            }
          }
          lead++; // Now looking for a pivot further right.
        }
        // If reduction did not result in the identity, the matrix is singular.
        if (object.deepEqual(matrix, math.eye(rows).valueOf())) {
          return math.round(d, 6);
        } else {
          return 0;
        }
      }
    }
  };
  
  },{"../../type/Matrix":206,"../../util/index":213}],168:[function(require,module,exports){
  module.exports = function (math, settings) {
    var util = require('../../util/index'),
  
        Matrix = require('../../type/Matrix'),
        collection = require('../../type/collection'),
  
        object = util.object,
        isArray = util.array.isArray,
        isNumber = util.number.isNumber,
        isInteger = util.number.isInteger;
  
    /**
     * Create a diagonal matrix or retrieve the diagonal of a matrix
     *
     *     diag(v)
     *     diag(v, k)
     *     diag(X)
     *     diag(X, k)
     *
     * TODO: more documentation on diag
     *
     * @param {Matrix | Array} x
     * @param {Number} [k]
     * @return {Matrix | Array} matrix
     */
    math.diag = function diag (x, k) {
      var data, vector, i, iMax;
  
      if (arguments.length != 1 && arguments.length != 2) {
        throw new math.error.ArgumentsError('diag', arguments.length, 1, 2);
      }
  
      if (k) {
        if (!isNumber(k) || !isInteger(k)) {
          throw new TypeError ('Second parameter in function diag must be an integer');
        }
      }
      else {
        k = 0;
      }
      var kSuper = k > 0 ? k : 0;
      var kSub = k < 0 ? -k : 0;
  
      // check type of input
      if (x instanceof Matrix) {
        // nice, nothing to do
      }
      else if (isArray(x)) {
        // convert to matrix
        x = new Matrix(x);
      }
      else {
        throw new TypeError ('First parameter in function diag must be a Matrix or Array');
      }
  
      var s = x.size();
      switch (s.length) {
        case 1:
          // x is a vector. create diagonal matrix
          vector = x.valueOf();
          var matrix = new Matrix();
          var defaultValue = 0;
          matrix.resize([vector.length + kSub, vector.length + kSuper], defaultValue);
          data = matrix.valueOf();
          iMax = vector.length;
          for (i = 0; i < iMax; i++) {
            data[i + kSub][i + kSuper] = object.clone(vector[i]);
          }
          return (settings.matrix === 'array') ? matrix.valueOf() : matrix;
          break;
  
        case 2:
          // x is a matrix get diagonal from matrix
          vector = [];
          data = x.valueOf();
          iMax = Math.min(s[0] - kSub, s[1] - kSuper);
          for (i = 0; i < iMax; i++) {
            vector[i] = object.clone(data[i + kSub][i + kSuper]);
          }
          return (settings.matrix === 'array') ? vector : new Matrix(vector);
          break;
  
        default:
          throw new RangeError('Matrix for function diag must be 2 dimensional');
      }
    };
  };
  
  },{"../../type/Matrix":206,"../../type/collection":209,"../../util/index":213}],169:[function(require,module,exports){
  module.exports = function (math, settings) {
    var util = require('../../util/index'),
  
        BigNumber = require('bignumber.js'),
        Matrix = require('../../type/Matrix'),
        collection = require('../../type/collection'),
  
        toNumber = util.number.toNumber,
        isNumber = util.number.isNumber,
        isInteger = util.number.isInteger,
        isArray = Array.isArray;
  
    /**
     * Create a 2-dimensional identity matrix with size m x n or n x n
     *
     *     eye(n)
     *     eye(m, n)
     *     eye([m, n])
     *
     * TODO: more documentation on eye
     *
     * @param {...Number | Matrix | Array} size
     * @return {Matrix | Array | Number} matrix
     */
    math.eye = function eye (size) {
      var args = collection.argsToArray(arguments),
          asMatrix = (size instanceof Matrix) ? true :
          (isArray(size) ? false : (settings.matrix === 'matrix'));
  
  
      if (args.length == 0) {
        // return an empty array
        return asMatrix ? new Matrix() : [];
      }
      else if (args.length == 1) {
        // change to a 2-dimensional square
        args[1] = args[0];
      }
      else if (args.length > 2) {
        // error in case of an n-dimensional size
        throw new math.error.ArgumentsError('eye', args.length, 0, 2);
      }
  
      var asBigNumber = args[0] instanceof BigNumber,
          rows = args[0],
          cols = args[1];
  
      if (rows instanceof BigNumber) {
        rows = toNumber(rows);
      }
      if (cols instanceof BigNumber) {
        cols = toNumber(cols);
      }
  
      if (!isNumber(rows) || !isInteger(rows) || rows < 1) {
        throw new Error('Parameters in function eye must be positive integers');
      }
      if (cols) {
        if (!isNumber(cols) || !isInteger(cols) || cols < 1) {
          throw new Error('Parameters in function eye must be positive integers');
        }
      }
  
      // create and args the matrix
      var matrix = new Matrix();
      var one = asBigNumber ? new BigNumber(1) : 1;
      var defaultValue = asBigNumber ? new BigNumber(0) : 0;
      matrix.resize(args.map(toNumber), defaultValue);
  
      // fill in ones on the diagonal
      var minimum = math.min(args);
      var data = matrix.valueOf();
      for (var d = 0; d < minimum; d++) {
        data[d][d] = one;
      }
  
      return asMatrix ? matrix : matrix.valueOf();
    };
  };
  
  },{"../../type/Matrix":206,"../../type/collection":209,"../../util/index":213,"bignumber.js":218}],170:[function(require,module,exports){
  module.exports = function (math) {
    var string = require('../../util/string'),
  
        Matrix = require('../../type/Matrix'),
        collection = require('../../type/collection');
  
    /**
     * Calculate the inverse of a matrix
     *
     *     inv(x)
     *
     * TODO: more documentation on inv
     *
     * @param {Number | Complex | Array | Matrix} x
     * @return {Number | Complex | Array | Matrix} inv
     */
    math.inv = function inv (x) {
      if (arguments.length != 1) {
        throw new math.error.ArgumentsError('inv', arguments.length, 1);
      }
      var size = math.size(x).valueOf();
      switch (size.length) {
        case 0:
          // scalar
          return math.divide(1, x);
          break;
  
        case 1:
          // vector
          if (size[0] == 1) {
            if (x instanceof Matrix) {
              return new Matrix([
                math.divide(1, x.valueOf()[0])
              ]);
            }
            else {
              return [
                math.divide(1, x[0])
              ];
            }
          }
          else {
            throw new RangeError('Matrix must be square ' +
                '(size: ' + string.format(size) + ')');
          }
          break;
  
        case 2:
          // two dimensional array
          var rows = size[0];
          var cols = size[1];
          if (rows == cols) {
            if (x instanceof Matrix) {
              return new Matrix(
                  _inv(x.valueOf(), rows, cols)
              );
            }
            else {
              // return an Array
              return _inv(x, rows, cols);
            }
          }
          else {
            throw new RangeError('Matrix must be square ' +
                '(size: ' + string.format(size) + ')');
          }
          break;
  
        default:
          // multi dimensional array
          throw new RangeError('Matrix must be two dimensional ' +
              '(size: ' + string.format(size) + ')');
      }
    };
  
    /**
     * Calculate the inverse of a square matrix
     * @param {Array[]} matrix  A square matrix
     * @param {Number} rows     Number of rows
     * @param {Number} cols     Number of columns, must equal rows
     * @return {Array[]} inv    Inverse matrix
     * @private
     */
    function _inv (matrix, rows, cols){
      var r, s, f, value, temp;
  
      if (rows == 1) {
        // this is a 1 x 1 matrix
        value = matrix[0][0];
        if (value == 0) {
          throw Error('Cannot calculate inverse, determinant is zero');
        }
        return [[
          math.divide(1, value)
        ]];
      }
      else if (rows == 2) {
        // this is a 2 x 2 matrix
        var d = math.det(matrix);
        if (d == 0) {
          throw Error('Cannot calculate inverse, determinant is zero');
        }
        return [
          [
            math.divide(matrix[1][1], d),
            math.divide(math.unary(matrix[0][1]), d)
          ],
          [
            math.divide(math.unary(matrix[1][0]), d),
            math.divide(matrix[0][0], d)
          ]
        ];
      }
      else {
        // this is a matrix of 3 x 3 or larger
        // calculate inverse using gauss-jordan elimination
        //      http://en.wikipedia.org/wiki/Gaussian_elimination
        //      http://mathworld.wolfram.com/MatrixInverse.html
        //      http://math.uww.edu/~mcfarlat/inverse.htm
  
        // make a copy of the matrix (only the arrays, not of the elements)
        var A = matrix.concat();
        for (r = 0; r < rows; r++) {
          A[r] = A[r].concat();
        }
  
        // create an identity matrix which in the end will contain the
        // matrix inverse
        var B = math.eye(rows).valueOf();
  
        // loop over all columns, and perform row reductions
        for (var c = 0; c < cols; c++) {
          // element Acc should be non zero. if not, swap content
          // with one of the lower rows
          r = c;
          while (r < rows && A[r][c] == 0) {
            r++;
          }
          if (r == rows || A[r][c] == 0) {
            throw Error('Cannot calculate inverse, determinant is zero');
          }
          if (r != c) {
            temp = A[c]; A[c] = A[r]; A[r] = temp;
            temp = B[c]; B[c] = B[r]; B[r] = temp;
          }
  
          // eliminate non-zero values on the other rows at column c
          var Ac = A[c],
              Bc = B[c];
          for (r = 0; r < rows; r++) {
            var Ar = A[r],
                Br = B[r];
            if(r != c) {
              // eliminate value at column c and row r
              if (Ar[c] != 0) {
                f = math.divide(math.unary(Ar[c]), Ac[c]);
  
                // add (f * row c) to row r to eliminate the value
                // at column c
                for (s = c; s < cols; s++) {
                  Ar[s] = math.add(Ar[s], math.multiply(f, Ac[s]));
                }
                for (s = 0; s < cols; s++) {
                  Br[s] = math.add(Br[s],  math.multiply(f, Bc[s]));
                }
              }
            }
            else {
              // normalize value at Acc to 1,
              // divide each value on row r with the value at Acc
              f = Ac[c];
              for (s = c; s < cols; s++) {
                Ar[s] = math.divide(Ar[s], f);
              }
              for (s = 0; s < cols; s++) {
                Br[s] = math.divide(Br[s], f);
              }
            }
          }
        }
        return B;
      }
    }
  };
  
  },{"../../type/Matrix":206,"../../type/collection":209,"../../util/string":216}],171:[function(require,module,exports){
  module.exports = function (math, settings) {
    var util = require('../../util/index'),
  
        BigNumber = require('bignumber.js'),
        Matrix = require('../../type/Matrix'),
        collection = require('../../type/collection'),
  
        array = util.array,
  
        toNumber = util.number.toNumber,
        isArray = Array.isArray;
  
    /**
     * Create a matrix filled with ones
     *
     *     ones(m)
     *     ones(m, n)
     *     ones([m, n])
     *     ones([m, n, p, ...])
     *
     * @param {...Number | Array} size
     * @return {Array | Matrix | Number} matrix
     */
    math.ones = function ones (size) {
      var args = collection.argsToArray(arguments);
      var asMatrix = (size instanceof Matrix) ? true :
          (isArray(size) ? false : (settings.matrix === 'matrix'));
  
      if (args.length == 0) {
        // output an empty matrix
        return asMatrix ? new Matrix() : [];
      }
      else {
        // output an array or matrix
        var res = [];
        var defaultValue = (args[0] instanceof BigNumber) ? new BigNumber(1) : 1;
        res = array.resize(res, args.map(toNumber), defaultValue);
  
        return asMatrix ? new Matrix(res) : res;
      }
    };
  };
  
  },{"../../type/Matrix":206,"../../type/collection":209,"../../util/index":213,"bignumber.js":218}],172:[function(require,module,exports){
  module.exports = function (math, settings) {
    var util = require('../../util/index'),
  
        BigNumber = require('bignumber.js'),
        Matrix = require('../../type/Matrix'),
        collection = require('../../type/collection'),
  
        isString = util.string.isString,
        isNumber = util.number.isNumber,
        toNumber = util.number.toNumber,
        toBigNumber = util.number.toBigNumber;
  
    /**
     * Create an array from a range.
     *
     * The method accepts the following arguments
     *     range(str)                   Create a range from a string, where the
     *                                  string contains the start, optional step,
     *                                  and end, separated by a colon.
     *     range(start, end)            Create a range with start and end and a
     *                                  default step size of 1
     *     range(start, end, step)      Create a range with start, step, and end.
     *
     * Example usage:
     *     math.range(2, 6);        // [2,3,4,5]
     *     math.range(2, -3, -1);   // [2,1,0,-1,-2]
     *     math.range('2:1:6');     // [2,3,4,5]
     *
     * @param {...*} args
     * @return {Array | Matrix} range
     */
    math.range = function range(args) {
      var start, end, step;
  
      switch (arguments.length) {
        case 1:
          // parse string into a range
          if (isString(args)) {
            var r = _parse(args);
            if (!r){
              throw new SyntaxError('String "' + r + '" is no valid range');
            }
  
            start = r.start;
            end = r.end;
            step = r.step;
          }
          else {
            throw new TypeError(
                'Two or three numbers or a single string expected in function range');
          }
          break;
  
        case 2:
          // range(start, end)
          start = arguments[0];
          end = arguments[1];
          step = 1;
          break;
  
        case 3:
          // range(start, end, step)
          start = arguments[0];
          end = arguments[1];
          step = arguments[2];
          break;
  
        default:
          throw new math.error.ArgumentsError('range', arguments.length, 2, 3);
      }
  
      // verify type of parameters
      if (!isNumber(start) && !(start instanceof BigNumber)) {
        throw new TypeError('Parameter start must be a number');
      }
      if (!isNumber(end) && !(end instanceof BigNumber)) {
        throw new TypeError('Parameter end must be a number');
      }
      if (!isNumber(step) && !(step instanceof BigNumber)) {
        throw new TypeError('Parameter step must be a number');
      }
  
      // go big
      if (start instanceof BigNumber || end instanceof BigNumber || step instanceof BigNumber) {
        // create a range with big numbers
        var asBigNumber = true;
  
        // convert start, end, step to BigNumber
        if (!(start instanceof BigNumber)) {
          start = toBigNumber(start);
        }
        if (!(end instanceof BigNumber)) {
          end = toBigNumber(end);
        }
        if (!(step instanceof BigNumber)) {
          step = toBigNumber(step);
        }
  
        if (!(start instanceof BigNumber) || !(end instanceof BigNumber) || !(step instanceof BigNumber)) {
          // not all values can be converted to big number :(
          // fall back to numbers
          asBigNumber = false;
          start = toNumber(start);
          end   = toNumber(end);
          step  = toNumber(step);
        }
      }
  
      // generate the range
      var array = asBigNumber ? _bigRange(start, end, step) : _range(start, end, step);
  
      // return as array or matrix
      return (settings.matrix === 'array') ? array : new Matrix(array);
    };
  
    /**
     * Create a range with numbers
     * @param {Number} start
     * @param {Number} end
     * @param {Number} step
     * @returns {Array} range
     * @private
     */
    function _range (start, end, step) {
      var array = [],
          x = start;
      if (step > 0) {
        while (x < end) {
          array.push(x);
          x += step;
        }
      }
      else if (step < 0) {
        while (x > end) {
          array.push(x);
          x += step;
        }
      }
  
      return array;
    }
  
    /**
     * Create a range with big numbers
     * @param {BigNumber} start
     * @param {BigNumber} end
     * @param {BigNumber} step
     * @returns {Array} range
     * @private
     */
    function _bigRange (start, end, step) {
      var array = [],
          x = start.clone(),
          zero = new BigNumber(0);
      if (step.gt(zero)) {
        while (x.lt(end)) {
          array.push(x);
          x = x.plus(step);
        }
      }
      else if (step.lt(zero)) {
        while (x.gt(end)) {
          array.push(x);
          x = x.plus(step);
        }
      }
  
      return array;
    }
  
    /**
     * Parse a string into a range,
     * The string contains the start, optional step, and end, separated by a colon.
     * If the string does not contain a valid range, null is returned.
     * For example str='0:2:11'.
     * @param {String} str
     * @return {Object | null} range Object containing properties start, end, step
     * @private
     */
    function _parse (str) {
      var args = str.split(':'),
          nums = null;
  
      if (settings.number === 'bignumber') {
        // bignumber
        try {
          nums = args.map(function (arg) {
            return new BigNumber(arg);
          });
        }
        catch (err) {
          return null;
        }
      }
      else {
        // number
        nums = args.map(function (arg) {
          return parseFloat(arg);
        });
  
        var invalid = nums.some(function (num) {
          return isNaN(num);
        });
        if(invalid) {
          return null;
        }
      }
  
      switch (nums.length) {
        case 2:
          return {
            start: nums[0],
            end: nums[1],
            step: 1
          };
  
        case 3:
          return {
            start: nums[0],
            end: nums[2],
            step: nums[1]
          };
  
        default:
          return null;
      }
    }
  
  };
  
  },{"../../type/Matrix":206,"../../type/collection":209,"../../util/index":213,"bignumber.js":218}],173:[function(require,module,exports){
  module.exports = function (math, settings) {
    var util = require('../../util/index'),
  
        BigNumber = require('bignumber.js'),
        Matrix = require('../../type/Matrix'),
  
        array = util.array,
        clone = util.object.clone,
        isString = util.string.isString,
        toNumber = util.number.toNumber,
        isNumber = util.number.isNumber,
        isInteger = util.number.isInteger,
        isArray = array.isArray;
  
    /**
     * Resize a matrix
     *
     *     resize(x, size)
     *     resize(x, size, defaultValue)
     *
     * @param {* | Array | Matrix} x
     * @param {Array | Matrix} size             One dimensional array with numbers
     * @param {Number | String} [defaultValue]  Undefined by default, except in
     *                                          case of a string, in that case
     *                                          defaultValue = ' '
     * @return {* | Array | Matrix} res
     */
    math.resize = function resize (x, size, defaultValue) {
      if (arguments.length != 2 && arguments.length != 3) {
        throw new math.error.ArgumentsError('resize', arguments.length, 2, 3);
      }
  
      var asMatrix = (x instanceof Matrix) ? true : isArray(x) ? false : (settings.matrix !== 'array');
  
      if (x instanceof Matrix) {
        x = x.valueOf(); // get Array
      }
      if (size instanceof Matrix) {
        size = size.valueOf(); // get Array
      }
  
      if (size.length && size[0] instanceof BigNumber) {
        // convert bignumbers to numbers
        size = size.map(toNumber);
      }
  
      if (isString(x)) {
        return _resizeString(x, size, defaultValue);
      }
      else {
        if (size.length == 0) {
          // output a scalar
          while (isArray(x)) {
            x = x[0];
          }
  
          return clone(x);
        }
        else {
          // output an array/matrix
          if (!isArray(x)) {
            x = [x];
          }
          x = clone(x);
  
          var res = array.resize(x, size, defaultValue);
          return asMatrix ? new Matrix(res) : res;
        }
      }
    };
  
    /**
     * Resize a string
     * @param {String} str
     * @param {Number[]} size
     * @param {string} defaultChar
     * @private
     */
    function _resizeString(str, size, defaultChar) {
      if (defaultChar !== undefined) {
        if (!isString(defaultChar) || defaultChar.length !== 1) {
          throw new TypeError('Single character expected as defaultValue');
        }
      }
      else {
        defaultChar = ' ';
      }
  
      if (size.length !== 1) {
        throw new Error('Dimension mismatch: (' + size.length + ' != 1)');
      }
      var len = size[0];
      if (!isNumber(len) || !isInteger(len)) {
        throw new TypeError('Size must contain numbers');
      }
  
      if (str.length > len) {
        return str.substring(0, len);
      }
      else if (str.length < len) {
        var res = str;
        for (var i = 0, ii = len - str.length; i < ii; i++) {
          res += defaultChar;
        }
        return res;
      }
      else {
        return str;
      }
    }
  };
  
  },{"../../type/Matrix":206,"../../util/index":213,"bignumber.js":218}],174:[function(require,module,exports){
  module.exports = function (math, settings) {
    var util = require('../../util/index'),
  
        BigNumber = require('bignumber.js'),
        Complex = require('../../type/Complex'),
        Unit = require('../../type/Unit'),
        Matrix = require('../../type/Matrix'),
  
        array = util.array,
        isNumber = util.number.isNumber,
        isBoolean = util['boolean'].isBoolean,
        isString = util.string.isString,
        isComplex = Complex.isComplex,
        isUnit = Unit.isUnit;
  
    /**
     * Calculate the size of a matrix or scalar
     *
     *     size(x)
     *
     * @param {Boolean | Number | Complex | Unit | String | Array | Matrix} x
     * @return {Array | Matrix} res
     */
    math.size = function size (x) {
      if (arguments.length != 1) {
        throw new math.error.ArgumentsError('size', arguments.length, 1);
      }
  
      var asArray = (settings.matrix === 'array');
  
      if (isNumber(x) || isComplex(x) || isUnit(x) || isBoolean(x) ||
          x == null || x instanceof BigNumber) {
        return asArray ? [] : new Matrix([]);
      }
  
      if (isString(x)) {
        return asArray ? [x.length] : new Matrix([x.length]);
      }
  
      if (Array.isArray(x)) {
        return array.size(x);
      }
  
      if (x instanceof Matrix) {
        return new Matrix(x.size());
      }
  
      throw new math.error.UnsupportedTypeError('size', x);
    };
  };
  
  },{"../../type/Complex":203,"../../type/Matrix":206,"../../type/Unit":208,"../../util/index":213,"bignumber.js":218}],175:[function(require,module,exports){
  module.exports = function (math) {
    var util = require('../../util/index'),
  
        Matrix = require('../../type/Matrix'),
  
        object = util.object,
        array = util.array,
        isArray = Array.isArray;
  
    /**
     * Remove singleton dimensions from a matrix
     *
     *     squeeze(x)
     *
     * @param {Matrix | Array} x
     * @return {Matrix | Array} res
     */
    math.squeeze = function squeeze (x) {
      if (arguments.length != 1) {
        throw new math.error.ArgumentsError('squeeze', arguments.length, 1);
      }
  
      if (isArray(x)) {
        return array.squeeze(object.clone(x));
      }
      else if (x instanceof Matrix) {
        var res = array.squeeze(x.toArray());
        return isArray(res) ? new Matrix(res) : res;
      }
      else {
        // scalar
        return object.clone(x);
      }
    };
  };
  
  },{"../../type/Matrix":206,"../../util/index":213}],176:[function(require,module,exports){
  module.exports = function (math) {
    var util = require('../../util/index'),
  
        Matrix = require('../../type/Matrix'),
        Index = require('../../type/Index'),
  
        array = util.array,
        isString = util.string.isString,
        isArray = Array.isArray;
  
    /**
     * Get or set a subset of a matrix or string
     *
     * Usage:
     *     // retrieve subset:
     *     var subset = math.subset(value, index)
     *
     *     // replace subset:
     *     var value = math.subset(value, index, replacement [, defaultValue])
     *
     * Where:
     *     {Array | Matrix | String} value  An array, matrix, or string
     *     {Index} index                    An index containing ranges for each
     *                                      dimension
     *     {*} replacement                  An array, matrix, or scalar
     *     {*} [defaultValue]        Default value, filled in on new entries when
     *                               the matrix is resized. If not provided,
     *                               new matrix elements will be left undefined.
     * @param args
     * @return res
     */
    math.subset = function subset (args) {
      switch (arguments.length) {
        case 2: // get subset
          return _getSubset(arguments[0], arguments[1]);
  
        // intentional fall through
        case 3: // set subset
        case 4: // set subset with default value
          return _setSubset(arguments[0], arguments[1], arguments[2], arguments[3]);
  
        default: // wrong number of arguments
          throw new math.error.ArgumentsError('subset', arguments.length, 2, 4);
      }
    };
  
    /**
     * Retrieve a subset of an value such as an Array, Matrix, or String
     * @param {Array | Matrix | String} value Object from which to get a subset
     * @param {Index} index                   An index containing ranges for each
     *                                        dimension
     * @returns {Array | Matrix | *} subset
     * @private
     */
    function _getSubset(value, index) {
      var m, subset;
  
      if (isArray(value)) {
        m = new Matrix(value);
        subset = m.subset(index);
        return subset.valueOf();
      }
      else if (value instanceof Matrix) {
        return value.subset(index);
      }
      else if (isString(value)) {
        return _getSubstring(value, index);
      }
      else {
        throw new math.error.UnsupportedTypeError('subset', value);
      }
    }
  
    /**
     * Retrieve a subset of a string
     * @param {String} str            String from which to get a substring
     * @param {Index} index           An index containing ranges for each dimension
     * @returns {string} substring
     * @private
     */
    function _getSubstring(str, index) {
      if (!(index instanceof Index)) {
        // TODO: better error message
        throw new TypeError('Index expected');
      }
      if (index.size().length != 1) {
        throw new RangeError('Dimension mismatch (' + index.size().length + ' != 1)');
      }
  
      var range = index.range(0);
  
      var substr = '';
      var strLen = str.length;
      range.forEach(function (v) {
        array.validateIndex(v, strLen);
        substr += str.charAt(v);
      });
  
      return substr;
    }
  
    /**
     * Replace a subset in an value such as an Array, Matrix, or String
     * @param {Array | Matrix | String} value Object to be replaced
     * @param {Index} index                   An index containing ranges for each
     *                                        dimension
     * @param {Array | Matrix | *} replacement
     * @param {*} [defaultValue]        Default value, filled in on new entries when
     *                                  the matrix is resized. If not provided,
     *                                  new matrix elements will be left undefined.
     * @returns {*} result
     * @private
     */
    function _setSubset(value, index, replacement, defaultValue) {
      var m;
  
      if (isArray(value)) {
        m = new Matrix(math.clone(value));
        m.subset(index, replacement, defaultValue);
        return m.valueOf();
      }
      else if (value instanceof Matrix) {
        return value.clone().subset(index, replacement, defaultValue);
      }
      else if (isString(value)) {
        return _setSubstring(value, index, replacement, defaultValue);
      }
      else {
        throw new math.error.UnsupportedTypeError('subset', value);
      }
    }
  
    /**
     * Replace a substring in a string
     * @param {String} str            String to be replaced
     * @param {Index} index           An index containing ranges for each dimension
     * @param {String} replacement    Replacement string
     * @param {String} [defaultValue] Default value to be uses when resizing
     *                                the string. is ' ' by default
     * @returns {string} result
     * @private
     */
    function _setSubstring(str, index, replacement, defaultValue) {
      if (!(index instanceof Index)) {
        // TODO: better error message
        throw new TypeError('Index expected');
      }
      if (index.size().length != 1) {
        throw new RangeError('Dimension mismatch (' + index.size().length + ' != 1)');
      }
      if (defaultValue !== undefined) {
        if (!isString(defaultValue) || defaultValue.length !== 1) {
          throw new TypeError('Single character expected as defaultValue');
        }
      }
      else {
        defaultValue = ' ';
      }
  
      var range = index.range(0);
      var len = range.size()[0];
  
      if (len != replacement.length) {
        throw new RangeError('Dimension mismatch ' +
            '(' + range.size()[0] + ' != ' + replacement.length + ')');
      }
  
      // copy the string into an array with characters
      var strLen = str.length;
      var chars = [];
      for (var i = 0; i < strLen; i++) {
        chars[i] = str.charAt(i);
      }
  
      range.forEach(function (v, i) {
        array.validateIndex(v);
        chars[v] = replacement.charAt(i);
      });
  
      // initialize undefined characters with a space
      if (chars.length > strLen) {
        for (i = strLen - 1, len = chars.length; i < len; i++) {
          if (!chars[i]) {
            chars[i] = defaultValue;
          }
        }
      }
  
      return chars.join('');
    }
  };
  
  },{"../../type/Index":205,"../../type/Matrix":206,"../../util/index":213}],177:[function(require,module,exports){
  module.exports = function (math) {
    var util = require('../../util/index'),
  
        Matrix = require('../../type/Matrix'),
        collection = require('../../type/collection'),
  
        object = util.object,
        string = util.string;
  
    /**
     * Create the transpose of a matrix
     *
     *     transpose(x)
     *
     * @param {Array | Matrix} x
     * @return {Array | Matrix} transpose
     */
    math.transpose = function transpose (x) {
      if (arguments.length != 1) {
        throw new math.error.ArgumentsError('transpose', arguments.length, 1);
      }
  
      var size = math.size(x).valueOf();
      switch (size.length) {
        case 0:
          // scalar
          return object.clone(x);
          break;
  
        case 1:
          // vector
          return object.clone(x);
          break;
  
        case 2:
          // two dimensional array
          var rows = size[1],
              cols = size[0],
              asMatrix = (x instanceof Matrix),
              data = x.valueOf(),
              transposed = [],
              transposedRow,
              clone = object.clone;
  
          if (rows === 0) {
            // whoops
            throw new RangeError('Cannot transpose a 2D matrix with no rows' +
                '(size: ' + string.format(size) + ')');
          }
  
          for (var r = 0; r < rows; r++) {
            transposedRow = transposed[r] = [];
            for (var c = 0; c < cols; c++) {
              transposedRow[c] = clone(data[c][r]);
            }
          }
          if (cols == 0) {
            transposed[0] = [];
          }
  
          return asMatrix ? new Matrix(transposed) : transposed;
          break;
  
        default:
          // multi dimensional array
          throw new RangeError('Matrix must be two dimensional ' +
              '(size: ' + string.format(size) + ')');
      }
    };
  };
  
  },{"../../type/Matrix":206,"../../type/collection":209,"../../util/index":213}],178:[function(require,module,exports){
  module.exports = function (math, settings) {
    var util = require('../../util/index'),
  
        BigNumber = require('bignumber.js'),
        Matrix = require('../../type/Matrix'),
        collection = require('../../type/collection'),
  
        array = util.array,
        toNumber = util.number.toNumber,
        isArray = Array.isArray;
  
    /**
     * create a matrix filled with zeros
     *
     *     zeros(m)
     *     zeros(m, n)
     *     zeros([m, n])
     *     zeros([m, n, p, ...])
     *
     * @param {...Number | Array} size
     * @return {Array | Matrix | Number} matrix
     */
    math.zeros = function zeros (size) {
      var args = collection.argsToArray(arguments);
      var asMatrix = (size instanceof Matrix) ? true :
          (isArray(size) ? false : (settings.matrix === 'matrix'));
  
      if (args.length == 0) {
        // output an empty matrix
        return asMatrix ? new Matrix() : [];
      }
      else {
        // output an array or matrix
        var res = [];
        var defaultValue = (args[0] instanceof BigNumber) ? new BigNumber(0) : 0;
        res = array.resize(res, args.map(toNumber), defaultValue);
  
        return asMatrix ? new Matrix(res) : res;
      }
    };
  };
  
  },{"../../type/Matrix":206,"../../type/collection":209,"../../util/index":213,"bignumber.js":218}],179:[function(require,module,exports){
  module.exports = function (math) {
    var util = require('../../util/index'),
  
        BigNumber = require('bignumber.js'),
        collection = require('../../type/collection'),
  
        isNumber = util.number.isNumber,
        isBoolean = util['boolean'].isBoolean,
        isInteger = util.number.isInteger,
        isCollection = collection.isCollection;
  
    /**
     * Compute the factorial of a value
     *
     *     x!
     *     factorial(x)
     *
     * Factorial only supports an integer value as argument.
     * For matrices, the function is evaluated element wise.
     *
     * @Param {Number | BigNumber | Array | Matrix} x
     * @return {Number | BigNumber | Array | Matrix} res
     */
    math.factorial = function factorial (x) {
      var value, res;
  
      if (arguments.length != 1) {
        throw new math.error.ArgumentsError('factorial', arguments.length, 1);
      }
  
      if (isNumber(x)) {
        if (!isInteger(x) || x < 0) {
          throw new TypeError('Positive integer value expected in function factorial');
        }
  
        value = x - 1;
        res = x;
        while (value > 1) {
          res *= value;
          value--;
        }
  
        if (res == 0) {
          res = 1;        // 0! is per definition 1
        }
  
        return res;
      }
  
      if (x instanceof BigNumber) {
        if (!x.round().equals(x) || x.lt(0)) {
          throw new TypeError('Positive integer value expected in function factorial');
        }
  
        var one = new BigNumber(1);
  
        value = x.minus(one);
        res = x;
        while (value.gt(one)) {
          res = res.times(value);
          value = value.minus(one);
        }
  
        if (res.equals(0)) {
          res = one;        // 0! is per definition 1
        }
  
        return res;
      }
  
      if (isBoolean(x)) {
        return 1; // factorial(1) = 1, factorial(0) = 1
      }
  
      if (isCollection(x)) {
        return collection.deepMap(x, factorial);
      }
  
      throw new math.error.UnsupportedTypeError('factorial', x);
    };
  };
  
  },{"../../type/collection":209,"../../util/index":213,"bignumber.js":218}],180:[function(require,module,exports){
  module.exports = function (math, settings) {
    var Matrix = require('../../type/Matrix'),
        collection = require('../../type/collection');
  
    // TODO: implement BigNumber support for random
  
    /**
     * Return a random number between 0 and 1
     *
     *     random()
     *
     * @return {Number} res
     */
  
    // Each distribution is a function that takes no argument and when called returns
    // a number between 0 and 1.
    var distributions = {
  
      uniform: function() {
        return Math.random;
      },
  
      // Implementation of normal distribution using Box-Muller transform
      // ref : http://en.wikipedia.org/wiki/Box%E2%80%93Muller_transform
      // We take : mean = 0.5, standard deviation = 1/6
      // so that 99.7% values are in [0, 1].
      normal: function() {
        return function() {
          var u1, u2,
              picked = -1;
          // We reject values outside of the interval [0, 1]
          // TODO: check if it is ok to do that?
          while (picked < 0 || picked > 1) {
            u1 = Math.random();
            u2 = Math.random();
            picked = 1/6 * Math.pow(-2 * Math.log(u1), 0.5) * Math.cos(2 * Math.PI * u2) + 0.5;
          }
          return picked;
        }
      }
    };
  
    /**
     * Create a distribution object.
     * @param {String} name           Name of a distribution.
     *                                Choose from 'uniform', 'normal'.
     * @return {Object} distribution  A distribution object containing functions:
     *                                    random([size, min, max])
     *                                    randomInt([min, max])
     *                                    pickRandom(array)
     */
    math.distribution = function(name) {
      if (!distributions.hasOwnProperty(name))
        throw new Error('unknown distribution ' + name);
  
      var args = Array.prototype.slice.call(arguments, 1),
          distribution = distributions[name].apply(this, args);
  
      return (function(distribution) {
  
        // This is the public API for all distributions
        var randFunctions = {
  
          random: function(arg1, arg2, arg3) {
            var size, min, max;
            if (arguments.length > 3) {
              throw new math.error.ArgumentsError('random', arguments.length, 0, 3);
  
            // `random(max)` or `random(size)`
            } else if (arguments.length === 1) {
              if (Array.isArray(arg1))
                size = arg1;
              else
                max = arg1;
            // `random(min, max)` or `random(size, max)`
            } else if (arguments.length === 2) {
              if (Array.isArray(arg1))
                size = arg1;
              else {
                min = arg1;
                max = arg2;
              }
            // `random(size, min, max)`
            } else {
              size = arg1;
              min = arg2;
              max = arg3;
            }
  
            if (max === undefined) max = 1;
            if (min === undefined) min = 0;
            if (size !== undefined) {
              var res = _randomDataForMatrix(size, min, max, _random);
              return (settings.matrix === 'array') ? res : new Matrix(res);
            }
            else return _random(min, max);
          },
  
          randomInt: function(arg1, arg2, arg3) {
            var size, min, max;
            if (arguments.length > 3 || arguments.length < 1)
              throw new math.error.ArgumentsError('randomInt', arguments.length, 1, 3);
  
            // `randomInt(max)`
            else if (arguments.length === 1) max = arg1;
            // `randomInt(min, max)` or `randomInt(size, max)`
            else if (arguments.length === 2) {
              if (Object.prototype.toString.call(arg1) === '[object Array]')
                size = arg1;
              else {
                min = arg1;
                max = arg2;
              }
            // `randomInt(size, min, max)`
            } else {
              size = arg1;
              min = arg2;
              max = arg3;
            }
  
            if (min === undefined) min = 0;
            if (size !== undefined) {
              var res = _randomDataForMatrix(size, min, max, _randomInt);
              return (settings.matrix === 'array') ? res : new Matrix(res);
            }
            else return _randomInt(min, max);
          },
  
          pickRandom: function(possibles) {
            if (arguments.length !== 1) {
              throw new math.error.ArgumentsError('pickRandom', arguments.length, 1);
            }
            if (!Array.isArray(possibles)) {
              throw new math.error.UnsupportedTypeError('pickRandom', possibles);
            }
  
            // TODO: add support for matrices
            return possibles[Math.floor(Math.random() * possibles.length)];
          }
  
        };
  
        var _random = function(min, max) {
          return min + distribution() * (max - min);
        };
  
        var _randomInt = function(min, max) {
          return Math.floor(min + distribution() * (max - min));
        };
  
        // This is a function for generating a random matrix recursively.
        var _randomDataForMatrix = function(size, min, max, randFunc) {
          var data = [], length, i;
          size = size.slice(0);
  
          if (size.length > 1) {
            for (i = 0, length = size.shift(); i < length; i++)
              data.push(_randomDataForMatrix(size, min, max, randFunc));
          } else {
            for (i = 0, length = size.shift(); i < length; i++)
              data.push(randFunc(min, max));
          }
  
          return data;
        };
  
        return randFunctions;
  
      })(distribution);
  
    };
  
    // Default random functions use uniform distribution
    // TODO: put random functions in separate files?
    var uniformRandFunctions = math.distribution('uniform');
    math.random = uniformRandFunctions.random;
    math.randomInt = uniformRandFunctions.randomInt;
    math.pickRandom = uniformRandFunctions.pickRandom;
  };
  
  },{"../../type/Matrix":206,"../../type/collection":209}],181:[function(require,module,exports){
  module.exports = function (math) {
    var Matrix = require('../../type/Matrix'),
        collection = require('../../type/collection'),
  
        isCollection = collection.isCollection;
  
    /**
     * Compute the maximum value of a list of values
     * In case of a multi dimensional array, the maximum of the flattened array
     * will be calculated. When dim is provided, the maximum over the selected
     * dimension will be calculated.
     *
     *     max(a, b, c, ...)
     *     max(A)
     *     max(A, dim)
     *
     * @param {... *} args  A single matrix or or multiple scalar values
     * @return {*} res
     */
    math.max = function max(args) {
      if (arguments.length == 0) {
        throw new SyntaxError('Function max requires one or more parameters (0 provided)');
      }
  
      if (isCollection(args)) {
        if (arguments.length == 1) {
          // max([a, b, c, d, ...])
          return _max(args);
        }
        else if (arguments.length == 2) {
          // max([a, b, c, d, ...], dim)
          return collection.reduce(arguments[0], arguments[1], _getlarger);
        }
        else {
          throw new SyntaxError('Wrong number of parameters');
        }
      }
      else {
        // max(a, b, c, d, ...)
        return _max(arguments);
      }
    };
  
    function _getlarger(x, y){
  	  if( math.larger(x,y) )
  		  return x;
  	  else
  		  return y;
    }
  
    /**
     * Recursively calculate the maximum value in an n-dimensional array
     * @param {Array} array
     * @return {Number} max
     * @private
     */
    function _max(array) {
      var max = null;
  
      collection.deepForEach(array, function (value) {
        if (max === null || math.larger(value, max)) {
          max = value;
        }
      });
  
      if (max === null) {
        throw new Error('Cannot calculate max of an empty array');
      }
  
      return max;
    }
  };
  
  },{"../../type/Matrix":206,"../../type/collection":209}],182:[function(require,module,exports){
  module.exports = function (math) {
    var Matrix = require('../../type/Matrix'),
        collection = require('../../type/collection'),
  
        isCollection = collection.isCollection;
  
    /**
     * Compute the mean value of a list of values
     * In case of a multi dimensional array, the mean of the flattened array
     * will be calculated. When dim is provided, the maximum over the selected
     * dimension will be calculated.
     *
     *     mean(a, b, c, ...)
     *     mean(A)
     *     mean(A, dim)
     *
     * @param {... *} args  A single matrix or or multiple scalar values
     * @return {*} res
     */
    math.mean = function mean(args) {
      if (arguments.length == 0) {
        throw new SyntaxError('Function mean requires one or more parameters (0 provided)');
      }
  
      if (isCollection(args)) {
        if (arguments.length == 1) {
          // mean([a, b, c, d, ...])
          return _mean(args);
        }
        else if (arguments.length == 2) {
          // mean([a, b, c, d, ...], dim)
          return _nmean(arguments[0], arguments[1]);
        }
        else {
          throw new SyntaxError('Wrong number of parameters');
        }
      }
      else {
        // mean(a, b, c, d, ...)
        return _mean(arguments);
      }
    };
  
    /**
     * Calculate the mean value in an n-dimensional array, returning a
     * n-1 dimensional array
     * @param {Array} array
     * @param {Number} dim
     * @return {Number} mean
     * @private
     */
    function _nmean(array, dim){
  	  var sum;
  	  sum = collection.reduce(array, dim, math.add);
  	  return math.divide(sum, size(array)[dim]);
    };
  
    /**
     * Recursively calculate the mean value in an n-dimensional array
     * @param {Array} array
     * @return {Number} mean
     * @private
     */
    function _mean(array) {
      var sum = 0;
      var num = 0;
  
      collection.deepForEach(array, function (value) {
        sum = math.add(sum, value);
        num++;
      });
  
      if (num === 0) {
        throw new Error('Cannot calculate mean of an empty array');
      }
  
      return math.divide(sum, num);
    }
  };
  
  },{"../../type/Matrix":206,"../../type/collection":209}],183:[function(require,module,exports){
  module.exports = function (math) {
    var Matrix = require('../../type/Matrix'),
        collection = require('../../type/collection'),
  
        isCollection = collection.isCollection;
  
    /**
     * Compute the minimum value of a list of values.
     * In case of a multi dimensional array, the minimum of the flattened array
     * will be calculated. When dim is provided, the maximum over the selected
     * dimension will be calculated.
     *
     *     min(a, b, c, ...)
     *     min(A)
     *     min(A, dim)
     *
     * @param {... *} args  A single matrix or multiple scalar values
     * @return {*} res
     */
    math.min = function min(args) {
      if (arguments.length == 0) {
        throw new SyntaxError('Function min requires one or more parameters (0 provided)');
      }
  
      if (isCollection(args)) {
        if (arguments.length == 1) {
          // min([a, b, c, d, ...])
          return _min(args);
        }
        else if (arguments.length == 2) {
          // min([a, b, c, d, ...], dim)
          return collection.reduce(arguments[0], arguments[1], _getsmaller);
        }
        else {
          throw new SyntaxError('Wrong number of parameters');
        }
      }
      else {
        // min(a, b, c, d, ...)
        return _min(arguments);
      }
    };
  
    function _getsmaller(x, y){
  	  if( math.smaller(x,y) )
  		  return x;
  	  else
  		  return y;
    }
  
    /**
     * Recursively calculate the minimum value in an n-dimensional array
     * @param {Array} array
     * @return {Number} min
     * @private
     */
    function _min(array) {
      var min = null;
  
      collection.deepForEach(array, function (value) {
        if (min === null || math.smaller(value, min)) {
          min = value;
        }
      });
  
      if (min === null) {
        throw new Error('Cannot calculate min of an empty array');
      }
  
      return min;
    }
  };
  
  },{"../../type/Matrix":206,"../../type/collection":209}],184:[function(require,module,exports){
  module.exports = function (math) {
    var util = require('../../util/index'),
  
        BigNumber = require('bignumber.js'),
        Complex = require('../../type/Complex'),
        collection = require('../../type/collection'),
  
        isNumber = util.number.isNumber,
        isBoolean = util['boolean'].isBoolean,
        isComplex = Complex.isComplex,
        isCollection = collection.isCollection;
  
    /**
     * Calculate the inverse cosine of a value
     *
     *     acos(x)
     *
     * For matrices, the function is evaluated element wise.
     *
     * @param {Number | Boolean | Complex | Array | Matrix} x
     * @return {Number | Complex | Array | Matrix} res
     *
     * @see http://mathworld.wolfram.com/InverseCosine.html
     */
    math.acos = function acos(x) {
      if (arguments.length != 1) {
        throw new math.error.ArgumentsError('acos', arguments.length, 1);
      }
  
      if (isNumber(x)) {
        if (x >= -1 && x <= 1) {
          return Math.acos(x);
        }
        else {
          return acos(new Complex(x, 0));
        }
      }
  
      if (isComplex(x)) {
        // acos(z) = 0.5*pi + i*log(iz + sqrt(1-z^2))
        var temp1 = new Complex(
            x.im * x.im - x.re * x.re + 1.0,
            -2.0 * x.re * x.im
        );
        var temp2 = math.sqrt(temp1);
        var temp3;
        if (temp2 instanceof Complex) {
          temp3 = new Complex(
              temp2.re - x.im,
              temp2.im + x.re
          )
        }
        else {
          temp3 = new Complex(
              temp2 - x.im,
              x.re
          )
        }
        var temp4 = math.log(temp3);
  
        // 0.5*pi = 1.5707963267948966192313216916398
        if (temp4 instanceof Complex) {
          return new Complex(
              1.57079632679489661923 - temp4.im,
              temp4.re
          );
        }
        else {
          return new Complex(
              1.57079632679489661923,
              temp4
          );
        }
      }
  
      if (isCollection(x)) {
        return collection.deepMap(x, acos);
      }
  
      if (isBoolean(x)) {
        return Math.acos(x);
      }
  
      if (x instanceof BigNumber) {
        // TODO: implement BigNumber support
        // downgrade to Number
        return acos(util.number.toNumber(x));
      }
  
      throw new math.error.UnsupportedTypeError('acos', x);
    };
  };
  
  },{"../../type/Complex":203,"../../type/collection":209,"../../util/index":213,"bignumber.js":218}],185:[function(require,module,exports){
  module.exports = function (math) {
    var util = require('../../util/index'),
  
        BigNumber = require('bignumber.js'),
        Complex = require('../../type/Complex'),
        collection = require('../../type/collection'),
  
        isNumber = util.number.isNumber,
        isBoolean = util['boolean'].isBoolean,
        isComplex = Complex.isComplex,
        isCollection = collection.isCollection;
  
    /**
     * Calculate the inverse sine of a value
     *
     *     asin(x)
     *
     * For matrices, the function is evaluated element wise.
     *
     * @param {Number | Boolean | Complex | Array | Matrix} x
     * @return {Number | Complex | Array | Matrix} res
     *
     * @see http://mathworld.wolfram.com/InverseSine.html
     */
    math.asin = function asin(x) {
      if (arguments.length != 1) {
        throw new math.error.ArgumentsError('asin', arguments.length, 1);
      }
  
      if (isNumber(x)) {
        if (x >= -1 && x <= 1) {
          return Math.asin(x);
        }
        else {
          return asin(new Complex(x, 0));
        }
      }
  
      if (isComplex(x)) {
        // asin(z) = -i*log(iz + sqrt(1-z^2))
        var re = x.re;
        var im = x.im;
        var temp1 = new Complex(
            im * im - re * re + 1.0,
            -2.0 * re * im
        );
  
        var temp2 = math.sqrt(temp1);
        var temp3;
        if (temp2 instanceof Complex) {
          temp3 = new Complex(
              temp2.re - im,
              temp2.im + re
          );
        }
        else {
          temp3 = new Complex(
              temp2 - im,
              re
          );
        }
  
        var temp4 = math.log(temp3);
  
        if (temp4 instanceof Complex) {
          return new Complex(temp4.im, -temp4.re);
        }
        else {
          return new Complex(0, -temp4);
        }
      }
  
      if (isCollection(x)) {
        return collection.deepMap(x, asin);
      }
  
      if (isBoolean(x)) {
        return Math.asin(x);
      }
  
      if (x instanceof BigNumber) {
        // TODO: implement BigNumber support
        // downgrade to Number
        return asin(util.number.toNumber(x));
      }
  
      throw new math.error.UnsupportedTypeError('asin', x);
    };
  };
  
  },{"../../type/Complex":203,"../../type/collection":209,"../../util/index":213,"bignumber.js":218}],186:[function(require,module,exports){
  module.exports = function (math) {
    var util = require('../../util/index'),
  
        BigNumber = require('bignumber.js'),
        Complex = require('../../type/Complex'),
        collection = require('../../type/collection'),
  
        isNumber = util.number.isNumber,
        isBoolean = util['boolean'].isBoolean,
        isComplex = Complex.isComplex,
        isCollection = collection.isCollection;
  
    /**
     * Calculate the inverse tangent of a value
     *
     *     atan(x)
     *
     * For matrices, the function is evaluated element wise.
     *
     * @param {Number | Boolean | Complex | Array | Matrix} x
     * @return {Number | Complex | Array | Matrix} res
     *
     * @see http://mathworld.wolfram.com/InverseTangent.html
     */
    math.atan = function atan(x) {
      if (arguments.length != 1) {
        throw new math.error.ArgumentsError('atan', arguments.length, 1);
      }
  
      if (isNumber(x)) {
        return Math.atan(x);
      }
  
      if (isComplex(x)) {
        // atan(z) = 1/2 * i * (ln(1-iz) - ln(1+iz))
        var re = x.re;
        var im = x.im;
        var den = re * re + (1.0 - im) * (1.0 - im);
  
        var temp1 = new Complex(
            (1.0 - im * im - re * re) / den,
            (-2.0 * re) / den
        );
        var temp2 = math.log(temp1);
  
        if (temp2 instanceof Complex) {
          return new Complex(
              -0.5 * temp2.im,
              0.5 * temp2.re
          );
        }
        else {
          return new Complex(
              0,
              0.5 * temp2
          );
        }
      }
  
      if (isCollection(x)) {
        return collection.deepMap(x, atan);
      }
  
      if (isBoolean(x)) {
        return Math.atan(x);
      }
  
      if (x instanceof BigNumber) {
        // TODO: implement BigNumber support
        // downgrade to Number
        return atan(util.number.toNumber(x));
      }
  
      throw new math.error.UnsupportedTypeError('atan', x);
    };
  };
  
  },{"../../type/Complex":203,"../../type/collection":209,"../../util/index":213,"bignumber.js":218}],187:[function(require,module,exports){
  module.exports = function (math) {
    var util = require('../../util/index'),
  
        BigNumber = require('bignumber.js'),
        Complex = require('../../type/Complex'),
        collection = require('../../type/collection'),
  
        toNumber = util.number.toNumber,
        isNumber = util.number.isNumber,
        isBoolean = util['boolean'].isBoolean,
        isComplex = Complex.isComplex,
        isCollection = collection.isCollection;
  
    /**
     * Computes the principal value of the arc tangent of y/x in radians
     *
     *     atan2(y, x)
     *
     * For matrices, the function is evaluated element wise.
     *
     * @param {Number | Boolean | Complex | Array | Matrix} y
     * @param {Number | Boolean | Complex | Array | Matrix} x
     * @return {Number | Complex | Array | Matrix} res
     *
     * @see http://mathworld.wolfram.com/InverseTangent.html
     */
    math.atan2 = function atan2(y, x) {
      if (arguments.length != 2) {
        throw new math.error.ArgumentsError('atan2', arguments.length, 2);
      }
  
      if (isNumber(y)) {
        if (isNumber(x)) {
          return Math.atan2(y, x);
        }
        /* TODO: support for complex computation of atan2
         else if (isComplex(x)) {
         return Math.atan2(y.re, x.re);
         }
         */
      }
      else if (isComplex(y)) {
        if (isNumber(x)) {
          return Math.atan2(y.re, x);
        }
        /* TODO: support for complex computation of atan2
         else if (isComplex(x)) {
         return Math.atan2(y.re, x.re);
         }
         */
      }
  
      if (isCollection(y) || isCollection(x)) {
        return collection.deepMap2(y, x, atan2);
      }
  
      if (isBoolean(y)) {
        return atan2(+y, x);
      }
      if (isBoolean(x)) {
        return atan2(y, +x);
      }
  
      // TODO: implement bignumber support
      if (y instanceof BigNumber) {
        return atan2(toNumber(y), x);
      }
      if (x instanceof BigNumber) {
        return atan2(y, toNumber(x));
      }
  
      throw new math.error.UnsupportedTypeError('atan2', y, x);
    };
  };
  
  },{"../../type/Complex":203,"../../type/collection":209,"../../util/index":213,"bignumber.js":218}],188:[function(require,module,exports){
  module.exports = function (math) {
    var util = require('../../util/index'),
  
        BigNumber = require('bignumber.js'),
        Complex = require('../../type/Complex'),
        Unit = require('../../type/Unit'),
        collection = require('../../type/collection'),
  
        isNumber = util.number.isNumber,
        isBoolean = util['boolean'].isBoolean,
        isComplex = Complex.isComplex,
        isUnit = Unit.isUnit,
        isCollection = collection.isCollection;
  
    /**
     * Calculate the cosine of a value
     *
     *     cos(x)
     *
     * For matrices, the function is evaluated element wise.
     *
     * @param {Number | Boolean | Complex | Unit | Array | Matrix} x
     * @return {Number | Complex | Array | Matrix} res
     *
     * @see http://mathworld.wolfram.com/Cosine.html
     */
    math.cos = function cos(x) {
      if (arguments.length != 1) {
        throw new math.error.ArgumentsError('cos', arguments.length, 1);
      }
  
      if (isNumber(x)) {
        return Math.cos(x);
      }
  
      if (isComplex(x)) {
        // cos(z) = (exp(iz) + exp(-iz)) / 2
        return new Complex(
            0.5 * Math.cos(x.re) * (Math.exp(-x.im) + Math.exp(x.im)),
            0.5 * Math.sin(x.re) * (Math.exp(-x.im) - Math.exp(x.im))
        );
      }
  
      if (isUnit(x)) {
        if (!x.hasBase(Unit.BASE_UNITS.ANGLE)) {
          throw new TypeError ('Unit in function cos is no angle');
        }
        return Math.cos(x.value);
      }
  
      if (isCollection(x)) {
        return collection.deepMap(x, cos);
      }
  
      if (isBoolean(x)) {
        return Math.cos(x);
      }
  
      if (x instanceof BigNumber) {
        // TODO: implement BigNumber support
        // downgrade to Number
        return cos(util.number.toNumber(x));
      }
  
      throw new math.error.UnsupportedTypeError('cos', x);
    };
  };
  
  },{"../../type/Complex":203,"../../type/Unit":208,"../../type/collection":209,"../../util/index":213,"bignumber.js":218}],189:[function(require,module,exports){
  module.exports = function (math) {
    var util = require('../../util/index'),
  
        BigNumber = require('bignumber.js'),
        Complex = require('../../type/Complex'),
        Unit = require('../../type/Unit'),
        collection = require('../../type/collection'),
  
        isNumber = util.number.isNumber,
        isBoolean = util['boolean'].isBoolean,
        isComplex = Complex.isComplex,
        isUnit = Unit.isUnit,
        isCollection = collection.isCollection;
  
    /**
     * Calculate the cotangent of a value. cot(x) is defined as 1 / tan(x)
     *
     *     cot(x)
     *
     * For matrices, the function is evaluated element wise.
     *
     * @param {Number | Boolean | Complex | Unit | Array | Matrix} x
     * @return {Number | Complex | Array | Matrix} res
     */
    math.cot = function cot(x) {
      if (arguments.length != 1) {
        throw new math.error.ArgumentsError('cot', arguments.length, 1);
      }
  
      if (isNumber(x)) {
        return 1 / Math.tan(x);
      }
  
      if (isComplex(x)) {
        var den = Math.exp(-4.0 * x.im) -
            2.0 * Math.exp(-2.0 * x.im) * Math.cos(2.0 * x.re) + 1.0;
  
        return new Complex(
            2.0 * Math.exp(-2.0 * x.im) * Math.sin(2.0 * x.re) / den,
            (Math.exp(-4.0 * x.im) - 1.0) / den
        );
      }
  
      if (isUnit(x)) {
        if (!x.hasBase(Unit.BASE_UNITS.ANGLE)) {
          throw new TypeError ('Unit in function cot is no angle');
        }
        return 1 / Math.tan(x.value);
      }
  
      if (isCollection(x)) {
        return collection.deepMap(x, cot);
      }
  
      if (isBoolean(x)) {
        return cot(+x);
      }
  
      if (x instanceof BigNumber) {
        // TODO: implement BigNumber support
        // downgrade to Number
        return cot(util.number.toNumber(x));
      }
  
      throw new math.error.UnsupportedTypeError('cot', x);
    };
  };
  
  },{"../../type/Complex":203,"../../type/Unit":208,"../../type/collection":209,"../../util/index":213,"bignumber.js":218}],190:[function(require,module,exports){
  module.exports = function (math) {
    var util = require('../../util/index'),
  
        BigNumber = require('bignumber.js'),
        Complex = require('../../type/Complex'),
        Unit = require('../../type/Unit'),
        collection = require('../../type/collection'),
  
        isNumber = util.number.isNumber,
        isBoolean = util['boolean'].isBoolean,
        isComplex = Complex.isComplex,
        isUnit = Unit.isUnit,
        isCollection = collection.isCollection;
  
    /**
     * Calculate the cosecant of a value, csc(x) = 1/sin(x)
     *
     *     csc(x)
     *
     * For matrices, the function is evaluated element wise.
     *
     * @param {Number | Boolean | Complex | Unit | Array | Matrix} x
     * @return {Number | Complex | Array | Matrix} res
     */
    math.csc = function csc(x) {
      if (arguments.length != 1) {
        throw new math.error.ArgumentsError('csc', arguments.length, 1);
      }
  
      if (isNumber(x)) {
        return 1 / Math.sin(x);
      }
  
      if (isComplex(x)) {
        // csc(z) = 1/sin(z) = (2i) / (exp(iz) - exp(-iz))
        var den = 0.25 * (Math.exp(-2.0 * x.im) + Math.exp(2.0 * x.im)) -
            0.5 * Math.cos(2.0 * x.re);
  
        return new Complex (
            0.5 * Math.sin(x.re) * (Math.exp(-x.im) + Math.exp(x.im)) / den,
            0.5 * Math.cos(x.re) * (Math.exp(-x.im) - Math.exp(x.im)) / den
        );
      }
  
      if (isUnit(x)) {
        if (!x.hasBase(Unit.BASE_UNITS.ANGLE)) {
          throw new TypeError ('Unit in function csc is no angle');
        }
        return 1 / Math.sin(x.value);
      }
  
      if (isCollection(x)) {
        return collection.deepMap(x, csc);
      }
  
      if (isBoolean(x)) {
        return csc(+x);
      }
  
      if (x instanceof BigNumber) {
        // TODO: implement BigNumber support
        // downgrade to Number
        return csc(util.number.toNumber(x));
      }
  
      throw new math.error.UnsupportedTypeError('csc', x);
    };
  };
  
  },{"../../type/Complex":203,"../../type/Unit":208,"../../type/collection":209,"../../util/index":213,"bignumber.js":218}],191:[function(require,module,exports){
  module.exports = function (math) {
    var util = require('../../util/index'),
  
        BigNumber = require('bignumber.js'),
        Complex = require('../../type/Complex'),
        Unit = require('../../type/Unit'),
        collection = require('../../type/collection'),
  
        isNumber = util.number.isNumber,
        isBoolean = util['boolean'].isBoolean,
        isComplex = Complex.isComplex,
        isUnit = Unit.isUnit,
        isCollection = collection.isCollection;
  
    /**
     * Calculate the secant of a value, sec(x) = 1/cos(x)
     *
     *     sec(x)
     *
     * For matrices, the function is evaluated element wise.
     *
     * @param {Number | Boolean | Complex | Unit | Array | Matrix} x
     * @return {Number | Complex | Array | Matrix} res
     */
    math.sec = function sec(x) {
      if (arguments.length != 1) {
        throw new math.error.ArgumentsError('sec', arguments.length, 1);
      }
  
      if (isNumber(x)) {
        return 1 / Math.cos(x);
      }
  
      if (isComplex(x)) {
        // sec(z) = 1/cos(z) = 2 / (exp(iz) + exp(-iz))
        var den = 0.25 * (Math.exp(-2.0 * x.im) + Math.exp(2.0 * x.im)) +
            0.5 * Math.cos(2.0 * x.re);
        return new Complex(
            0.5 * Math.cos(x.re) * (Math.exp(-x.im) + Math.exp( x.im)) / den,
            0.5 * Math.sin(x.re) * (Math.exp( x.im) - Math.exp(-x.im)) / den
        );
      }
  
      if (isUnit(x)) {
        if (!x.hasBase(Unit.BASE_UNITS.ANGLE)) {
          throw new TypeError ('Unit in function sec is no angle');
        }
        return 1 / Math.cos(x.value);
      }
  
      if (isCollection(x)) {
        return collection.deepMap(x, sec);
      }
  
      if (isBoolean(x)) {
        return sec(+x);
      }
  
      if (x instanceof BigNumber) {
        // TODO: implement BigNumber support
        // downgrade to Number
        return sec(util.number.toNumber(x));
      }
  
      throw new math.error.UnsupportedTypeError('sec', x);
    };
  };
  
  },{"../../type/Complex":203,"../../type/Unit":208,"../../type/collection":209,"../../util/index":213,"bignumber.js":218}],192:[function(require,module,exports){
  module.exports = function (math) {
    var util = require('../../util/index'),
  
        BigNumber = require('bignumber.js'),
        Complex = require('../../type/Complex'),
        Unit = require('../../type/Unit'),
        collection = require('../../type/collection'),
  
        isNumber = util.number.isNumber,
        isBoolean = util['boolean'].isBoolean,
        isComplex = Complex.isComplex,
        isUnit = Unit.isUnit,
        isCollection = collection.isCollection;
  
    /**
     * Calculate the sine of a value
     *
     *     sin(x)
     *
     * For matrices, the function is evaluated element wise.
     *
     * @param {Number | Boolean | Complex | Unit | Array | Matrix} x
     * @return {Number | Complex | Array | Matrix} res
     *
     * @see http://mathworld.wolfram.com/Sine.html
     */
    math.sin = function sin(x) {
      if (arguments.length != 1) {
        throw new math.error.ArgumentsError('sin', arguments.length, 1);
      }
  
      if (isNumber(x)) {
        return Math.sin(x);
      }
  
      if (isComplex(x)) {
        return new Complex(
            0.5 * Math.sin(x.re) * (Math.exp(-x.im) + Math.exp( x.im)),
            0.5 * Math.cos(x.re) * (Math.exp( x.im) - Math.exp(-x.im))
        );
      }
  
      if (isUnit(x)) {
        if (!x.hasBase(Unit.BASE_UNITS.ANGLE)) {
          throw new TypeError ('Unit in function sin is no angle');
        }
        return Math.sin(x.value);
      }
  
      if (isCollection(x)) {
        return collection.deepMap(x, sin);
      }
  
      if (isBoolean(x)) {
        return Math.sin(x);
      }
  
      if (x instanceof BigNumber) {
        // TODO: implement BigNumber support
        // downgrade to Number
        return sin(util.number.toNumber(x));
      }
  
      throw new math.error.UnsupportedTypeError('sin', x);
    };
  };
  
  },{"../../type/Complex":203,"../../type/Unit":208,"../../type/collection":209,"../../util/index":213,"bignumber.js":218}],193:[function(require,module,exports){
  module.exports = function (math) {
    var util = require('../../util/index'),
  
        BigNumber = require('bignumber.js'),
        Complex = require('../../type/Complex'),
        Unit = require('../../type/Unit'),
        collection = require('../../type/collection'),
  
        isNumber = util.number.isNumber,
        isBoolean = util['boolean'].isBoolean,
        isComplex = Complex.isComplex,
        isUnit = Unit.isUnit,
        isCollection = collection.isCollection;
  
    /**
     * Calculate the tangent of a value
     *
     *     tan(x)
     *
     * For matrices, the function is evaluated element wise.
     *
     * @param {Number | Boolean | Complex | Unit | Array | Matrix} x
     * @return {Number | Complex | Array | Matrix} res
     *
     * @see http://mathworld.wolfram.com/Tangent.html
     */
    math.tan = function tan(x) {
      if (arguments.length != 1) {
        throw new math.error.ArgumentsError('tan', arguments.length, 1);
      }
  
      if (isNumber(x)) {
        return Math.tan(x);
      }
  
      if (isComplex(x)) {
        var den = Math.exp(-4.0 * x.im) +
            2.0 * Math.exp(-2.0 * x.im) * Math.cos(2.0 * x.re) +
            1.0;
  
        return new Complex(
            2.0 * Math.exp(-2.0 * x.im) * Math.sin(2.0 * x.re) / den,
            (1.0 - Math.exp(-4.0 * x.im)) / den
        );
      }
  
      if (isUnit(x)) {
        if (!x.hasBase(Unit.BASE_UNITS.ANGLE)) {
          throw new TypeError ('Unit in function tan is no angle');
        }
        return Math.tan(x.value);
      }
  
      if (isCollection(x)) {
        return collection.deepMap(x, tan);
      }
  
      if (isBoolean(x)) {
        return Math.tan(x);
      }
  
      if (x instanceof BigNumber) {
        // TODO: implement BigNumber support
        // downgrade to Number
        return tan(util.number.toNumber(x));
      }
  
      throw new math.error.UnsupportedTypeError('tan', x);
    };
  };
  
  },{"../../type/Complex":203,"../../type/Unit":208,"../../type/collection":209,"../../util/index":213,"bignumber.js":218}],194:[function(require,module,exports){
  module.exports = function (math) {
    var util = require('../../util/index'),
  
        Unit = require('../../type/Unit'),
        collection = require('../../type/collection'),
  
        isString = util.string.isString,
        isUnit = Unit.isUnit,
        isCollection = collection.isCollection;
  
    /**
     * Change the unit of a value.
     *
     *     x in unit
     *     in(x, unit)
     *
     * For matrices, the function is evaluated element wise.
     *
     * @param {Unit | Array | Matrix} x
     * @param {Unit | Array | Matrix} unit
     * @return {Unit | Array | Matrix} res
     */
    math['in'] = function unit_in(x, unit) {
      if (arguments.length != 2) {
        throw new math.error.ArgumentsError('in', arguments.length, 2);
      }
  
      if (isUnit(x)) {
        if (isUnit(unit) || isString(unit)) {
          return x['in'](unit);
        }
      }
  
      // TODO: add support for string, in that case, convert to unit
  
      if (isCollection(x) || isCollection(unit)) {
        return collection.deepMap2(x, unit, unit_in);
      }
  
      throw new math.error.UnsupportedTypeError('in', x, unit);
    };
  };
  
  },{"../../type/Unit":208,"../../type/collection":209,"../../util/index":213}],195:[function(require,module,exports){
  module.exports = function (math) {
    var object = require('../../util/object');
  
    /**
     * Clone an object
     *
     *     clone(x)
     *
     * @param {*} x
     * @return {*} clone
     */
    math.clone = function clone (x) {
      if (arguments.length != 1) {
        throw new math.error.ArgumentsError('clone', arguments.length, 1);
      }
  
      return object.clone(x);
    };
  };
  
  },{"../../util/object":215}],196:[function(require,module,exports){
  module.exports = function (math) {
    var isMatrix = require('../../type/Matrix').isMatrix;
  
    /**
     * Execute a callback method on each entry of the matrix or the array.
     * @param {Matrix/array} x      The container to iterate on.
     * @param {function} callback   The callback method is invoked with three
     *                              parameters: the value of the element, the index
     *                              of the element, and the Matrix/array being traversed.
     */
    math.forEach = function (x, callback) {
      if (arguments.length != 2) {
        throw new math.error.ArgumentsError('forEach', arguments.length, 2);
      }
  
      if (Array.isArray(x)) {
        return _forEachArray(x, callback);
      } else if (isMatrix(x)) {
        return x.forEach(callback);
      } else {
        throw new math.error.UnsupportedTypeError('forEach', x);
      }
    };
  
    function _forEachArray (array, callback) {
      var index = [];
      var recurse = function (value, dim) {
        if (Array.isArray(value)) {
          value.forEach(function (child, i) {
            index[dim] = i; // zero-based index
            recurse(child, dim + 1);
          });
        }
        else {
          callback(value, index, array);
        }
      };
      recurse(array, 0);
    };
  
  };
  },{"../../type/Matrix":206}],197:[function(require,module,exports){
  module.exports = function (math) {
    var string = require('../../util/string');
  
    /**
     * Format a value of any type into a string.
     *
     * Syntax:
     *
     *    format(value)
     *    format(value, options)
     *    format(value, precision)
     *    format(value, fn)
     *
     * Where:
     *
     *    {*} value        The value to be formatted
     *    {Object} options An object with formatting options. Available options:
     *                     {String} notation
     *                         Number notation. Choose from:
     *                         'fixed'          Always use regular number notation.
     *                                          For example '123.40' and '14000000'
     *                         'exponential'    Always use exponential notation.
     *                                          For example '1.234e+2' and '1.4e+7'
     *                         'auto' (default) Regular number notation for numbers
     *                                          having an absolute value between
     *                                          `lower` and `upper` bounds, and uses
     *                                          exponential notation elsewhere.
     *                                          Lower bound is included, upper bound
     *                                          is excluded.
     *                                          For example '123.4' and '1.4e7'.
     *                     {Number} precision   A number between 0 and 16 to round
     *                                          the digits of the number.
     *                                          In case of notations 'exponential' and
     *                                          'auto', `precision` defines the total
     *                                          number of significant digits returned
     *                                          and is undefined by default.
     *                                          In case of notation 'fixed',
     *                                          `precision` defines the number of
     *                                          significant digits after the decimal
     *                                          point, and is 0 by default.
     *                     {Object} exponential An object containing two parameters,
     *                                          {Number} lower and {Number} upper,
     *                                          used by notation 'auto' to determine
     *                                          when to return exponential notation.
     *                                          Default values are `lower=1e-3` and
     *                                          `upper=1e5`.
     *                                          Only applicable for notation `auto`.
     *    {Function} fn    A custom formatting function. Can be used to override the
     *                     built-in notations. Function `fn` is called with `value` as
     *                     parameter and must return a string. Is useful for example to
     *                     format all values inside a matrix in a particular way.
     *
     * Examples:
     *
     *    format(6.4);                                        // '6.4'
     *    format(1240000);                                    // '1.24e6'
     *    format(1/3);                                        // '0.3333333333333333'
     *    format(1/3, 3);                                     // '0.333'
     *    format(21385, 2);                                   // '21000'
     *    format(12.071, {notation: 'fixed'});                // '12'
     *    format(2.3,    {notation: 'fixed', precision: 2});  // '2.30'
     *    format(52.8,   {notation: 'exponential'});          // '5.28e+1'
     *
     * @param {*} value             Value to be stringified
     * @param {Object | Function | Number} [options]
     * @return {String} str The formatted value
     */
    math.format = function format (value, options) {
      var num = arguments.length;
      if (num !== 1 && num !== 2) {
        throw new math.error.ArgumentsError('format', num, 1, 2);
      }
  
      return string.format(value, options);
    };
  };
  
  },{"../../util/string":216}],198:[function(require,module,exports){
  module.exports = function (math) {
    var util = require('../../util/index'),
  
        Complex = require('../../type/Complex'),
        Unit = require('../../type/Unit'),
  
        isNumber = util.number.isNumber,
        isString = util.string.isString,
        isComplex = Complex.isComplex,
        isUnit = Unit.isUnit;
  
    /**
     * Import functions from an object or a file
     * @param {function | String | Object} object
     * @param {Object} [options]        Available options:
     *                                  {Boolean} override
     *                                      If true, existing functions will be
     *                                      overwritten. False by default.
     *                                  {Boolean} wrap
     *                                      If true (default), the functions will
     *                                      be wrapped in a wrapper function which
     *                                      converts data types like Matrix to
     *                                      primitive data types like Array.
     *                                      The wrapper is needed when extending
     *                                      math.js with libraries which do not
     *                                      support the math.js data types.
     */
  // TODO: return status information
    math['import'] = function math_import(object, options) {
      var name;
      var opts = {
        override: false,
        wrap: true
      };
      if (options && options instanceof Object) {
        util.object.extend(opts, options);
      }
  
      if (isString(object)) {
        // a string with a filename
        if (typeof (require) !== 'undefined') {
          // load the file using require
          var _module = require(object);
          math_import(_module);
        }
        else {
          throw new Error('Cannot load file: require not available.');
        }
      }
      else if (isSupportedType(object)) {
        // a single function
        name = object.name;
        if (name) {
          if (opts.override || math[name] === undefined) {
            _import(name, object, opts);
          }
        }
        else {
          throw new Error('Cannot import an unnamed function or object');
        }
      }
      else if (object instanceof Object) {
        // a map with functions
        for (name in object) {
          if (object.hasOwnProperty(name)) {
            var value = object[name];
            if (isSupportedType(value)) {
              _import(name, value, opts);
            }
            else {
              math_import(value);
            }
          }
        }
      }
    };
  
    /**
     * Add a property to the math namespace and create a chain proxy for it.
     * @param {String} name
     * @param {*} value
     * @param {Object} options  See import for a description of the options
     * @private
     */
    function _import(name, value, options) {
      if (options.override || math[name] === undefined) {
        // add to math namespace
        if (options.wrap && typeof value === 'function') {
          // create a wrapper around the function
          math[name] = function () {
            var args = [];
            for (var i = 0, len = arguments.length; i < len; i++) {
              args[i] = arguments[i].valueOf();
            }
            return value.apply(math, args);
          };
        }
        else {
          // just create a link to the function or value
          math[name] = value;
        }
  
        // create a proxy for the Selector
        math.chaining.Selector.createProxy(name, value);
      }
    }
  
    /**
     * Check whether given object is a supported type
     * @param object
     * @return {Boolean}
     * @private
     */
    function isSupportedType(object) {
      return (typeof object == 'function') ||
          isNumber(object) || isString(object) ||
          isComplex(object) || isUnit(object);
      // TODO: add boolean?
    }
  };
  
  },{"../../type/Complex":203,"../../type/Unit":208,"../../util/index":213}],199:[function(require,module,exports){
  module.exports = function (math) {
    var isMatrix = require('../../type/Matrix').isMatrix;
  
    /**
     * Create a new matrix or array with the results of the callback function executed on
     * each entry of the matrix/array.
     * @param {Matrix/array} x      The container to iterate on.
     * @param {function} callback   The callback method is invoked with three
     *                              parameters: the value of the element, the index
     *                              of the element, and the Matrix being traversed.
     * @return {Matrix/array} container
     */
    math.map = function (x, callback) {
      if (arguments.length != 2) {
        throw new math.error.ArgumentsError('map', arguments.length, 2);
      }
  
      if (Array.isArray(x)) {
        return _mapArray(x, callback);
      } else if (isMatrix(x)) {
        return x.map(callback);
      } else {
        throw new math.error.UnsupportedTypeError('map', x);
      }
    };
  
    function _mapArray (arrayIn, callback) {
      var index = [];
      var recurse = function (value, dim) {
        if (Array.isArray(value)) {
          return value.map(function (child, i) {
            index[dim] = i;
            return recurse(child, dim + 1);
          });
        }
        else {
          return callback(value, index, arrayIn);
        }
      };
  
      return recurse(arrayIn, 0);
    };
  };
  
  },{"../../type/Matrix":206}],200:[function(require,module,exports){
  module.exports = function (math) {
    var string = require('../../util/string'),
  
        isString = string.isString;
  
    /**
     * Interpolate values into a string template.
     *     math.print(template, values)
     *     math.print(template, values, precision)
     *
     * Example usage:
     *
     *     // the following outputs: 'The value of pi is 3.141592654'
     *     math.format('The value of pi is $pi', {pi: math.pi}, 10);
     *
     *     // the following outputs: 'hello Mary! The date is 2013-03-23'
     *     math.format('Hello $user.name! The date is $date', {
     *       user: {
     *         name: 'Mary',
     *       },
     *       date: new Date().toISOString().substring(0, 10)
     *     });
     *
     * @param {String} template
     * @param {Object} values
     * @param {Number} [precision]  Number of digits to format numbers.
     *                              If not provided, the value will not be rounded.
     * @return {String} str
     */
    math.print = function print (template, values, precision) {
      var num = arguments.length;
      if (num != 2 && num != 3) {
        throw new math.error.ArgumentsError('print', num, 2, 3);
      }
  
      if (!isString(template)) {
        throw new TypeError('String expected as first parameter in function format');
      }
      if (!(values instanceof Object)) {
        throw new TypeError('Object expected as second parameter in function format');
      }
  
      // format values into a string
      return template.replace(/\$([\w\.]+)/g, function (original, key) {
            var keys = key.split('.');
            var value = values[keys.shift()];
            while (keys.length && value !== undefined) {
              var k = keys.shift();
              value = k ? value[k] : value + '.';
            }
  
            if (value !== undefined) {
              if (!isString(value)) {
                return math.format(value, precision);
              }
              else {
                return value;
              }
            }
  
            return original;
          }
      );
    };
  };
  
  },{"../../util/string":216}],201:[function(require,module,exports){
  module.exports = function (math) {
    var types = require('../../util/types'),
  
        BigNumber = require('bignumber.js'),
        Complex = require('../../type/Complex'),
        Matrix = require('../../type/Matrix'),
        Unit = require('../../type/Unit'),
        Index = require('../../type/Index'),
        Range = require('../../type/Range'),
        Help = require('../../type/Help');
  
    /**
     * Determine the type of a variable
     *
     *     typeof(x)
     *
     * @param {*} x
     * @return {String} type  Lower case type, for example 'number', 'string',
     *                        'array'.
     */
    math['typeof'] = function _typeof (x) {
      if (arguments.length != 1) {
        throw new math.error.ArgumentsError('typeof', arguments.length, 1);
      }
  
      // JavaScript types
      var type = types.type(x);
  
      // math.js types
      if (type === 'object') {
        if (x instanceof Complex) return 'complex';
        if (x instanceof BigNumber) return 'bignumber';
        if (x instanceof Matrix) return 'matrix';
        if (x instanceof Unit) return 'unit';
        if (x instanceof Index) return 'index';
        if (x instanceof Range) return 'range';
        if (x instanceof Help) return 'matrix';
  
        if (x instanceof math.chaining.Selector) return 'selector';
      }
  
      return type;
    };
  };
  
  },{"../../type/Complex":203,"../../type/Help":204,"../../type/Index":205,"../../type/Matrix":206,"../../type/Range":207,"../../type/Unit":208,"../../util/types":217,"bignumber.js":218}],202:[function(require,module,exports){
  var object = require('./util/object');
  
  /**
   * math.js factory function.
   *
   * Usage:
   *
   *     var math = mathjs();
   *     var math = mathjs(settings);
   *
   * @param {Object} [settings] Available settings:
   *                            {String} matrix
   *                              A string 'matrix' (default) or 'array'.
   *                            {String} number
   *                              A string 'number' (default) or 'bignumber'
   *                            {Number} decimals
   *                              The number of decimals behind the decimal
   *                              point for BigNumber. Not applicable for Numbers.
   */
  function mathjs (settings) {
    // simple test for ES5 support
    if (typeof Array.prototype.map !== 'function') {
      throw new Error('ES5 not supported by this JavaScript engine. ' +
          'Please load the es5-shim library for compatibility.');
    }
  
    // create new namespace
    var math = {};
  
    // create configuration settings. These are private
    var _settings = {
      // type of default matrix output. Choose 'matrix' (default) or 'array'
      matrix: 'matrix',
  
      // type of default number output. Choose 'number' (default) or 'bignumber'
      number: 'number'
    };
  
    /**
     * Set configuration settings for math.js, and get current settings
     * @param {Object} [settings] Available settings:
     *                            {String} matrix
     *                              A string 'matrix' (default) or 'array'.
     *                            {String} number
     *                              A string 'number' (default) or 'bignumber'
     *                            {Number} decimals
     *                              The number of decimals behind the decimal
     *                              point for BigNumber. Not applicable for Numbers.
     * @return {Object} settings   The currently applied settings
     */
    math.config = function config (settings) {
      var BigNumber = require('bignumber.js');
  
      if (settings) {
        // merge settings
        object.deepExtend(_settings, settings);
  
        if (settings.decimals) {
          BigNumber.config({
            DECIMAL_PLACES: settings.decimals
          });
        }
  
        // TODO: remove deprecated setting some day (deprecated since version 0.17.0)
        if (settings.number && settings.number.defaultType) {
          throw new Error('setting `number.defaultType` is deprecated. ' +
              'Use `number` instead.')
        }
  
        // TODO: remove deprecated setting some day (deprecated since version 0.17.0)
        if (settings.number && settings.number.precision) {
          throw new Error('setting `number.precision` is deprecated. ' +
              'Use `decimals` instead.')
        }
  
        // TODO: remove deprecated setting some day (deprecated since version 0.17.0)
        if (settings.matrix && settings.matrix.defaultType) {
          throw new Error('setting `matrix.defaultType` is deprecated. ' +
              'Use `matrix` instead.')
        }
  
        // TODO: remove deprecated setting some day (deprecated since version 0.15.0)
        if (settings.matrix && settings.matrix['default']) {
          throw new Error('setting `matrix.default` is deprecated. ' +
              'Use `matrix` instead.')
        }
      }
  
      // return a clone of the settings
      var current = object.clone(_settings);
      current.decimals = BigNumber.config().DECIMAL_PLACES;
      return current;
    };
  
    // apply provided configuration settings
    math.config(settings);
  
    // expression (Parser, Scope, nodes, docs)
    math.expression = {};
    math.expression.node = require('./expression/node/index.js');
    math.expression.Scope = require('./expression/Scope.js');
    math.expression.Parser = require('./expression/Parser.js');
    math.expression.docs = require('./expression/docs/index.js');
  
    // types (Matrix, Complex, Unit, ...)
    math.type = {};
    math.type.BigNumber = require('bignumber.js');
    math.type.Complex = require('./type/Complex');
    math.type.Range = require('./type/Range');
    math.type.Index = require('./type/Index');
    math.type.Matrix = require('./type/Matrix');
    math.type.Unit = require('./type/Unit');
    math.type.Help = require('./type/Help');
  
    math.collection = require('./type/collection');
  
    // error utility functions
    require('./type/error')(math);
  
    // expression parser
    require('./function/expression/eval.js')(math, _settings);
    require('./function/expression/help.js')(math, _settings);
    require('./function/expression/parse.js')(math, _settings);
  
    // functions - arithmetic
    require('./function/arithmetic/abs.js')(math, _settings);
    require('./function/arithmetic/add.js')(math, _settings);
    require('./function/arithmetic/add.js')(math, _settings);
    require('./function/arithmetic/ceil.js')(math, _settings);
    require('./function/arithmetic/cube.js')(math, _settings);
    require('./function/arithmetic/divide.js')(math, _settings);
    require('./function/arithmetic/edivide.js')(math, _settings);
    require('./function/arithmetic/emultiply.js')(math, _settings);
    require('./function/arithmetic/epow.js')(math, _settings);
    require('./function/arithmetic/equal.js')(math, _settings);
    require('./function/arithmetic/exp.js')(math, _settings);
    require('./function/arithmetic/fix.js')(math, _settings);
    require('./function/arithmetic/floor.js')(math, _settings);
    require('./function/arithmetic/gcd.js')(math, _settings);
    require('./function/arithmetic/larger.js')(math, _settings);
    require('./function/arithmetic/largereq.js')(math, _settings);
    require('./function/arithmetic/lcm.js')(math, _settings);
    require('./function/arithmetic/log.js')(math, _settings);
    require('./function/arithmetic/log10.js')(math, _settings);
    require('./function/arithmetic/mod.js')(math, _settings);
    require('./function/arithmetic/multiply.js')(math, _settings);
    require('./function/arithmetic/pow.js')(math, _settings);
    require('./function/arithmetic/round.js')(math, _settings);
    require('./function/arithmetic/sign.js')(math, _settings);
    require('./function/arithmetic/smaller.js')(math, _settings);
    require('./function/arithmetic/smallereq.js')(math, _settings);
    require('./function/arithmetic/sqrt.js')(math, _settings);
    require('./function/arithmetic/square.js')(math, _settings);
    require('./function/arithmetic/subtract.js')(math, _settings);
    require('./function/arithmetic/unary.js')(math, _settings);
    require('./function/arithmetic/unequal.js')(math, _settings);
    require('./function/arithmetic/xgcd.js')(math, _settings);
  
    // functions - complex
    require('./function/complex/arg.js')(math, _settings);
    require('./function/complex/conj.js')(math, _settings);
    require('./function/complex/re.js')(math, _settings);
    require('./function/complex/im.js')(math, _settings);
  
    // functions - construction
    require('./function/construction/bignumber')(math, _settings);
    require('./function/construction/boolean.js')(math, _settings);
    require('./function/construction/complex.js')(math, _settings);
    require('./function/construction/index.js')(math, _settings);
    require('./function/construction/matrix.js')(math, _settings);
    require('./function/construction/number.js')(math, _settings);
    require('./function/construction/parser.js')(math, _settings);
    require('./function/construction/select.js')(math, _settings);
    require('./function/construction/string.js')(math, _settings);
    require('./function/construction/unit.js')(math, _settings);
  
    // functions - matrix
    require('./function/matrix/concat.js')(math, _settings);
    require('./function/matrix/det.js')(math, _settings);
    require('./function/matrix/diag.js')(math, _settings);
    require('./function/matrix/eye.js')(math, _settings);
    require('./function/matrix/inv.js')(math, _settings);
    require('./function/matrix/ones.js')(math, _settings);
    require('./function/matrix/range.js')(math, _settings);
    require('./function/matrix/resize.js')(math, _settings);
    require('./function/matrix/size.js')(math, _settings);
    require('./function/matrix/squeeze.js')(math, _settings);
    require('./function/matrix/subset.js')(math, _settings);
    require('./function/matrix/transpose.js')(math, _settings);
    require('./function/matrix/zeros.js')(math, _settings);
  
    // functions - probability
    require('./function/probability/factorial.js')(math, _settings);
    require('./function/probability/random.js')(math, _settings);
  
    // functions - statistics
    require('./function/statistics/min.js')(math, _settings);
    require('./function/statistics/max.js')(math, _settings);
    require('./function/statistics/mean.js')(math, _settings);
  
    // functions - trigonometry
    require('./function/trigonometry/acos.js')(math, _settings);
    require('./function/trigonometry/asin.js')(math, _settings);
    require('./function/trigonometry/atan.js')(math, _settings);
    require('./function/trigonometry/atan2.js')(math, _settings);
    require('./function/trigonometry/cos.js')(math, _settings);
    require('./function/trigonometry/cot.js')(math, _settings);
    require('./function/trigonometry/csc.js')(math, _settings);
    require('./function/trigonometry/sec.js')(math, _settings);
    require('./function/trigonometry/sin.js')(math, _settings);
    require('./function/trigonometry/tan.js')(math, _settings);
  
    // functions - units
    require('./function/units/in.js')(math, _settings);
  
    // functions - utils
    require('./function/utils/clone.js')(math, _settings);
    require('./function/utils/format.js')(math, _settings);
    require('./function/utils/import.js')(math, _settings);
    require('./function/utils/map.js')(math, _settings);
    require('./function/utils/print.js')(math, _settings);
    require('./function/utils/typeof.js')(math, _settings);
    require('./function/utils/forEach.js')(math, _settings);
  
    // constants
    require('./constants.js')(math, _settings);
  
    // selector (we initialize after all functions are loaded)
    math.chaining = {};
    math.chaining.Selector = require('./chaining/Selector.js')(math, _settings);
  
    // return the new instance
    return math;
  }
  
  
  // return the mathjs factory
  module.exports = mathjs;
  
  },{"./chaining/Selector.js":2,"./constants.js":3,"./expression/Parser.js":4,"./expression/Scope.js":5,"./expression/docs/index.js":103,"./expression/node/index.js":117,"./function/arithmetic/abs.js":118,"./function/arithmetic/add.js":119,"./function/arithmetic/ceil.js":120,"./function/arithmetic/cube.js":121,"./function/arithmetic/divide.js":122,"./function/arithmetic/edivide.js":123,"./function/arithmetic/emultiply.js":124,"./function/arithmetic/epow.js":125,"./function/arithmetic/equal.js":126,"./function/arithmetic/exp.js":127,"./function/arithmetic/fix.js":128,"./function/arithmetic/floor.js":129,"./function/arithmetic/gcd.js":130,"./function/arithmetic/larger.js":131,"./function/arithmetic/largereq.js":132,"./function/arithmetic/lcm.js":133,"./function/arithmetic/log.js":134,"./function/arithmetic/log10.js":135,"./function/arithmetic/mod.js":136,"./function/arithmetic/multiply.js":137,"./function/arithmetic/pow.js":138,"./function/arithmetic/round.js":139,"./function/arithmetic/sign.js":140,"./function/arithmetic/smaller.js":141,"./function/arithmetic/smallereq.js":142,"./function/arithmetic/sqrt.js":143,"./function/arithmetic/square.js":144,"./function/arithmetic/subtract.js":145,"./function/arithmetic/unary.js":146,"./function/arithmetic/unequal.js":147,"./function/arithmetic/xgcd.js":148,"./function/complex/arg.js":149,"./function/complex/conj.js":150,"./function/complex/im.js":151,"./function/complex/re.js":152,"./function/construction/bignumber":153,"./function/construction/boolean.js":154,"./function/construction/complex.js":155,"./function/construction/index.js":156,"./function/construction/matrix.js":157,"./function/construction/number.js":158,"./function/construction/parser.js":159,"./function/construction/select.js":160,"./function/construction/string.js":161,"./function/construction/unit.js":162,"./function/expression/eval.js":163,"./function/expression/help.js":164,"./function/expression/parse.js":165,"./function/matrix/concat.js":166,"./function/matrix/det.js":167,"./function/matrix/diag.js":168,"./function/matrix/eye.js":169,"./function/matrix/inv.js":170,"./function/matrix/ones.js":171,"./function/matrix/range.js":172,"./function/matrix/resize.js":173,"./function/matrix/size.js":174,"./function/matrix/squeeze.js":175,"./function/matrix/subset.js":176,"./function/matrix/transpose.js":177,"./function/matrix/zeros.js":178,"./function/probability/factorial.js":179,"./function/probability/random.js":180,"./function/statistics/max.js":181,"./function/statistics/mean.js":182,"./function/statistics/min.js":183,"./function/trigonometry/acos.js":184,"./function/trigonometry/asin.js":185,"./function/trigonometry/atan.js":186,"./function/trigonometry/atan2.js":187,"./function/trigonometry/cos.js":188,"./function/trigonometry/cot.js":189,"./function/trigonometry/csc.js":190,"./function/trigonometry/sec.js":191,"./function/trigonometry/sin.js":192,"./function/trigonometry/tan.js":193,"./function/units/in.js":194,"./function/utils/clone.js":195,"./function/utils/forEach.js":196,"./function/utils/format.js":197,"./function/utils/import.js":198,"./function/utils/map.js":199,"./function/utils/print.js":200,"./function/utils/typeof.js":201,"./type/Complex":203,"./type/Help":204,"./type/Index":205,"./type/Matrix":206,"./type/Range":207,"./type/Unit":208,"./type/collection":209,"./type/error":210,"./util/object":215,"bignumber.js":218}],203:[function(require,module,exports){
  var util = require('../util/index'),
      number = util.number,
  
      isNumber = util.number.isNumber,
      isString = util.string.isString;
  
  /**
   * @constructor Complex
   *
   * A complex value can be constructed in the following ways:
   *     var a = new Complex();
   *     var b = new Complex(re, im);
   *     var c = Complex.parse(str);
   *
   * Example usage:
   *     var a = new Complex(3, -4);      // 3 - 4i
   *     a.re = 5;                        // a = 5 - 4i
   *     var i = a.im;                    // -4;
   *     var b = Complex.parse('2 + 6i'); // 2 + 6i
   *     var c = new Complex();           // 0 + 0i
   *     var d = math.add(a, b);          // 5 + 2i
   *
   * @param {Number} re       The real part of the complex value
   * @param {Number} [im]     The imaginary part of the complex value
   */
  function Complex(re, im) {
    if (!(this instanceof Complex)) {
      throw new SyntaxError(
          'Complex constructor must be called with the new operator');
    }
  
    switch (arguments.length) {
      case 0:
        this.re = 0;
        this.im = 0;
        break;
  
      case 2:
        if (!isNumber(re) || !isNumber(im)) {
          throw new TypeError('Two numbers expected in Complex constructor');
        }
        this.re = re;
        this.im = im;
        break;
  
      default:
        if (arguments.length != 0 && arguments.length != 2) {
          throw new SyntaxError(
              'Two or zero arguments expected in Complex constructor');
        }
        break;
    }
  }
  
  /**
   * Test whether value is a Complex value
   * @param {*} value
   * @return {Boolean} isComplex
   */
  Complex.isComplex = function isComplex(value) {
    return (value instanceof Complex);
  };
  
  // private variables and functions for the parser
  var text, index, c;
  
  function skipWhitespace() {
    while (c == ' ' || c == '\t') {
      next();
    }
  }
  
  function isDigitDot (c) {
    return ((c >= '0' && c <= '9') || c == '.');
  }
  
  function isDigit (c) {
    return ((c >= '0' && c <= '9'));
  }
  
  function next() {
    index++;
    c = text.charAt(index);
  }
  
  function revert(oldIndex) {
    index = oldIndex;
    c = text.charAt(index);
  }
  
  function parseNumber () {
    var number = '';
    var oldIndex;
    oldIndex = index;
  
    if (c == '+') {
      next();
    }
    else if (c == '-') {
      number += c;
      next();
    }
  
    if (!isDigitDot(c)) {
      // a + or - must be followed by a digit
      revert(oldIndex);
      return null;
    }
  
    // get number, can have a single dot
    if (c == '.') {
      number += c;
      next();
      if (!isDigit(c)) {
        // this is no legal number, it is just a dot
        revert(oldIndex);
        return null;
      }
    }
    else {
      while (isDigit(c)) {
        number += c;
        next();
      }
      if (c == '.') {
        number += c;
        next();
      }
    }
    while (isDigit(c)) {
      number += c;
      next();
    }
  
    // check for exponential notation like "2.3e-4" or "1.23e50"
    if (c == 'E' || c == 'e') {
      number += c;
      next();
  
      if (c == '+' || c == '-') {
        number += c;
        next();
      }
  
      // Scientific notation MUST be followed by an exponent
      if (!isDigit(c)) {
        // this is no legal number, exponent is missing.
        revert(oldIndex);
        return null;
      }
  
      while (isDigit(c)) {
        number += c;
        next();
      }
    }
  
    return number;
  }
  
  function parseComplex () {
    // check for 'i', '-i', '+i'
    var cnext = text.charAt(index + 1);
    if (c == 'I' || c == 'i') {
      next();
      return '1';
    }
    else if ((c == '+' || c == '-') && (cnext == 'I' || cnext == 'i')) {
      var number = (c == '+') ? '1' : '-1';
      next();
      next();
      return number;
    }
  
    return null;
  }
  
  /**
   * Parse a complex number from a string. For example Complex.parse("2 + 3i")
   * will return a Complex value where re = 2, im = 3.
   * Returns null if provided string does not contain a valid complex number.
   * @param {String} str
   * @returns {Complex | null} complex
   */
  Complex.parse = function parse (str) {
    text = str;
    index = -1;
    c = '';
  
    if (!isString(text)) {
      return null;
    }
  
    next();
    skipWhitespace();
    var first = parseNumber();
    if (first) {
      if (c == 'I' || c == 'i') {
        // pure imaginary number
        next();
        skipWhitespace();
        if (c) {
          // garbage at the end. not good.
          return null;
        }
  
        return new Complex(0, Number(first));
      }
      else {
        // complex and real part
        skipWhitespace();
        var separator = c;
        if (separator != '+' && separator != '-') {
          // pure real number
          skipWhitespace();
          if (c) {
            // garbage at the end. not good.
            return null;
          }
  
          return new Complex(Number(first), 0);
        }
        else {
          // complex and real part
          next();
          skipWhitespace();
          var second = parseNumber();
          if (second) {
            if (c != 'I' && c != 'i') {
              // 'i' missing at the end of the complex number
              return null;
            }
            next();
          }
          else {
            second = parseComplex();
            if (!second) {
              // imaginary number missing after separator
              return null;
            }
          }
  
          if (separator == '-') {
            if (second[0] == '-') {
              second =  '+' + second.substring(1);
            }
            else {
              second = '-' + second;
            }
          }
  
          next();
          skipWhitespace();
          if (c) {
            // garbage at the end. not good.
            return null;
          }
  
          return new Complex(Number(first), Number(second));
        }
      }
    }
    else {
      // check for 'i', '-i', '+i'
      first = parseComplex();
      if (first) {
        skipWhitespace();
        if (c) {
          // garbage at the end. not good.
          return null;
        }
  
        return new Complex(0, Number(first));
      }
    }
  
    return null;
  };
  
  /**
   * Create a copy of the complex value
   * @return {Complex} clone
   */
  Complex.prototype.clone = function clone () {
    return new Complex(this.re, this.im);
  };
  
  /**
   * Test whether this complex number equals an other complex value.
   * Two complex numbers are equal when both their real and imaginary parts
   * are equal.
   * @param {Complex} other
   * @return {boolean} isEqual
   */
  Complex.prototype.equals = function equals (other) {
    return (this.re === other.re) && (this.im === other.im);
  };
  
  /**
   * Get a string representation of the complex number,
   * with optional formatting options.
   * @param {Object | Number | Function} [options]  Formatting options. See
   *                                                lib/util/number:format for a
   *                                                description of the available
   *                                                options.
   * @return {String} str
   */
  Complex.prototype.format = function format (options) {
    var str = '',
        strRe = number.format(this.re, options),
        strIm = number.format(this.im, options);
  
    if (this.im == 0) {
      // real value
      str = strRe;
    }
    else if (this.re == 0) {
      // purely complex value
      if (this.im == 1) {
        str = 'i';
      }
      else if (this.im == -1) {
        str = '-i';
      }
      else {
        str = strIm + 'i';
      }
    }
    else {
      // complex value
      if (this.im > 0) {
        if (this.im == 1) {
          str = strRe + ' + i';
        }
        else {
          str = strRe + ' + ' + strIm + 'i';
        }
      }
      else {
        if (this.im == -1) {
          str = strRe + ' - i';
        }
        else {
          str = strRe + ' - ' + strIm.substring(1) + 'i';
        }
      }
    }
  
    return str;
  };
  
  /**
   * Get a string representation of the complex number.
   * @return {String} str
   */
  Complex.prototype.toString = function toString () {
    return this.format();
  };
  
  // exports
  module.exports = Complex;
  
  // to trick my IDE which doesn't get it
  exports.isComplex = Complex.isComplex;
  exports.parse = Complex.parse;
  
  },{"../util/index":213}],204:[function(require,module,exports){
  var util = require('../util/index'),
      object = util.object,
      string = util.string;
  
  /**
   * Documentation object
   * @param {Object} math The math.js namespace
   * @param {Object} doc  Object containing properties:
   *                      {String} name
   *                      {String} category
   *                      {String[]} syntax
   *                      {String[]} examples
   *                      {String[]} seealso
   * @constructor
   */
  function Help (math, doc) {
    this.math = math;
    this.doc = doc;
  }
  
  /**
   * Test whether a value is an instance of Help
   * @param {*} value
   * @return {Boolean} isHelp
   */
  Help.isHelp = function isHelp (value) {
    return (value instanceof Help);
  };
  
  /**
   * Generate readable description from a Help object
   * @return {String} readableDoc
   * @private
   */
  Help.prototype.toString = function () {
    var doc = this.doc || {};
    var desc = '\n';
  
    if (doc.name) {
      desc += 'Name: ' + doc.name + '\n\n';
    }
    if (doc.category) {
      desc += 'Category: ' + doc.category + '\n\n';
    }
    if (doc.description) {
      desc += 'Description:\n    ' + doc.description + '\n\n';
    }
    if (doc.syntax) {
      desc += 'Syntax:\n    ' + doc.syntax.join('\n    ') + '\n\n';
    }
    if (doc.examples) {
      var parser = this.math.parser();
      desc += 'Examples:\n';
      for (var i = 0; i < doc.examples.length; i++) {
        var expr = doc.examples[i];
        var res;
        try {
          res = parser.eval(expr);
        }
        catch (e) {
          res = e;
        }
        desc += '    ' + expr + '\n';
        if (res && !(res instanceof Help)) {
          desc += '        ' + string.format(res) + '\n';
        }
      }
      desc += '\n';
    }
    if (doc.seealso) {
      desc += 'See also: ' + doc.seealso.join(', ') + '\n';
    }
  
    return desc;
  };
  
  // TODO: implement a toHTML function in Help
  
  /**
   * Export the help object to JSON
   */
  Help.prototype.toJSON = function () {
    return object.extend({}, this.doc);
  };
  
  // exports
  module.exports = Help;
  
  // to trick my IDE which doesn't get it
  exports.isHelp = Help.isHelp;
  
  },{"../util/index":213}],205:[function(require,module,exports){
  var util = require('../util/index'),
  
      Range = require('./Range'),
  
      number = util.number,
  
      isNumber = number.isNumber,
      isInteger = number.isInteger,
      isArray = Array.isArray,
      validateIndex = util.array.validateIndex;
  
  /**
   * @Constructor Index
   * Create an index. An Index can store ranges having start, step, and end
   * for multiple dimensions.
   * Matrix.get, Matrix.set, and math.subset accept an Index as input.
   *
   * Usage:
   *     var index = new Index(range1, range2, ...);
   *
   * Where each range can be any of:
   *     An array [start, end]
   *     An array [start, end, step]
   *     A number
   *     An instance of Range
   *
   * The parameters start, end, and step must be integer numbers.
   *
   * @param {...*} ranges
   */
  function Index(ranges) {
    if (!(this instanceof Index)) {
      throw new SyntaxError(
          'Index constructor must be called with the new operator');
    }
  
    this._ranges = [];
  
    for (var i = 0, ii = arguments.length; i < ii; i++) {
      var arg = arguments[i];
  
      if (arg instanceof Range) {
        this._ranges.push(arg);
      }
      else {
        if (arg) {
          arg = arg.valueOf();
        }
  
        if (isArray(arg)) {
          this._ranges.push(_createRange(arg));
        }
        else if (isNumber(arg)) {
          this._ranges.push(_createRange([arg, arg + 1]));
        }
        // TODO: implement support for wildcard '*'
        else {
          throw new TypeError('Range expected as Array, Number, or String');
        }
      }
    }
  }
  
  /**
   * Parse an argument into a range and validate the range
   * @param {Array} arg  An array with [start: Number, end: Number] and
   *                     optional a third element step:Number
   * @return {Range} range
   * @private
   */
  function _createRange(arg) {
    // TODO: make function _createRange simpler/faster
  
    // test whether all arguments are integers
    var num = arg.length;
    for (var i = 0; i < num; i++) {
      if (!isNumber(arg[i]) || !isInteger(arg[i])) {
        throw new TypeError('Index parameters must be integer numbers');
      }
    }
  
    switch (arg.length) {
      case 2:
        return new Range(arg[0], arg[1]); // start, end
      case 3:
        return new Range(arg[0], arg[1], arg[2]); // start, end, step
      default:
        // TODO: improve error message
        throw new SyntaxError('Wrong number of arguments in Index (2 or 3 expected)');
    }
  }
  
  /**
   * Create a clone of the index
   * @return {Index} clone
   */
  Index.prototype.clone = function clone () {
    var index = new Index();
    index._ranges = util.object.clone(this._ranges);
    return index;
  };
  
  /**
   * Test whether an object is an Index
   * @param {*} object
   * @return {Boolean} isIndex
   */
  Index.isIndex = function isIndex(object) {
    return (object instanceof Index);
  };
  
  /**
   * Create an index from an array with ranges/numbers
   * @param {Array.<Array | Number>} ranges
   * @return {Index} index
   * @private
   */
  Index.create = function create(ranges) {
    var index = new Index();
    Index.apply(index, ranges);
    return index;
  };
  
  /**
   * Retrieve the size of the index, the number of elements for each dimension.
   * @returns {Number[]} size
   */
  Index.prototype.size = function size () {
    var size = [];
  
    for (var i = 0, ii = this._ranges.length; i < ii; i++) {
      var range = this._ranges[i];
  
      size[i] = range.size()[0];
    }
  
    return size;
  };
  
  /**
   * Get the maximum value for each of the indexes ranges.
   * @returns {Number[]} max
   */
  Index.prototype.max = function max () {
    var values = [];
  
    for (var i = 0, ii = this._ranges.length; i < ii; i++) {
      var range = this._ranges[i];
      values[i] = range.max();
    }
  
    return values;
  };
  
  /**
   * Get the minimum value for each of the indexes ranges.
   * @returns {Number[]} min
   */
  Index.prototype.min = function min () {
    var values = [];
  
    for (var i = 0, ii = this._ranges.length; i < ii; i++) {
      var range = this._ranges[i];
  
      values[i] = range.min();
    }
  
    return values;
  };
  
  /**
   * Loop over each of the ranges of the index
   * @param {function} callback   Called for each range with a Range as first
   *                              argument, the dimension as second, and the
   *                              index object as third.
   */
  Index.prototype.forEach = function forEach(callback) {
    for (var i = 0, ii = this._ranges.length; i < ii; i++) {
      callback(this._ranges[i], i, this);
    }
  };
  
  /**
   * Retrieve the range for a given dimension number from the index
   * @param {Number} dim                  Number of the dimension
   * @returns {Range | undefined} range
   */
  Index.prototype.range = function range (dim) {
    return this._ranges[dim];
  };
  
  /**
   * Test whether this index contains only a single value
   * @return {boolean} isScalar
   */
  Index.prototype.isScalar = function isScalar () {
    var size = this.size();
  
    for (var i = 0, ii = size.length; i < ii; i++) {
      if (size[i] !== 1) {
        return false;
      }
    }
  
    return true;
  };
  
  /**
   * Expand the Index into an array.
   * For example new Index([0,3], [2,7]) returns [[0,1,2], [2,3,4,5,6]]
   * @returns {Array} array
   */
  Index.prototype.toArray = function toArray() {
    var array = [];
    for (var i = 0, ii = this._ranges.length; i < ii; i++) {
      var range = this._ranges[i],
          row = [],
          x = range.start,
          end = range.end,
          step = range.step;
  
      if (step > 0) {
        while (x < end) {
          row.push(x);
          x += step;
        }
      }
      else if (step < 0) {
        while (x > end) {
          row.push(x);
          x += step;
        }
      }
  
      array.push(row);
    }
  
    return array;
  };
  
  /**
   * Get the primitive value of the Index, a two dimensional array.
   * Equivalent to Index.toArray().
   * @returns {Array} array
   */
  Index.prototype.valueOf = Index.prototype.toArray;
  
  /**
   * Get the string representation of the index, for example '[2:6]' or '[0:2:10, 4:7]'
   * @returns {String} str
   */
  Index.prototype.toString = function () {
    var strings = [];
  
    for (var i = 0, ii = this._ranges.length; i < ii; i++) {
      var range = this._ranges[i];
      var str = number.format(range.start);
      if (range.step != 1) {
        str += ':' + number.format(range.step);
      }
      str += ':' + number.format(range.end);
      strings.push(str);
    }
  
    return '[' + strings.join(',') + ']';
  };
  
  // exports
  module.exports = Index;
  
  // to trick my IDE which doesn't get it
  exports.isIndex = Index.isIndex;
  exports.create = Index.create;
  
  },{"../util/index":213,"./Range":207}],206:[function(require,module,exports){
  var util = require('../util/index'),
      Index = require('./Index'),
  
      number = util.number,
      string = util.string,
      array = util.array,
      object = util.object,
  
      isArray = Array.isArray,
      validateIndex = array.validateIndex;
  
  /**
   * @constructor Matrix
   *
   * A Matrix is a wrapper around an Array. A matrix can hold a multi dimensional
   * array. A matrix can be constructed as:
   *     var matrix = new Matrix(data)
   *
   * Matrix contains the functions to resize, get and set values, get the size,
   * clone the matrix and to convert the matrix to a vector, array, or scalar.
   * Furthermore, one can iterate over the matrix using map and forEach.
   * The internal Array of the Matrix can be accessed using the function valueOf.
   *
   * Example usage:
   *     var matrix = new Matrix([[1, 2], [3, 4]);
   *     matix.size();              // [2, 2]
   *     matrix.resize([3, 2], 5);
   *     matrix.valueOf();          // [[1, 2], [3, 4], [5, 5]]
   *     matrix.subset([1,2])       // 3 (indexes are zero-based)
   *
   * @param {Array | Matrix} [data]    A multi dimensional array
   */
  function Matrix(data) {
    if (!(this instanceof Matrix)) {
      throw new SyntaxError(
          'Matrix constructor must be called with the new operator');
    }
  
    if (data instanceof Matrix) {
      // clone data from a Matrix
      this._data = data.clone()._data;
    }
    else if (isArray(data)) {
      // use array as is
      this._data = data;
    }
    else if (data != null) {
      // unsupported type
      throw new TypeError('Unsupported type of data (' + util.types.type(data) + ')');
    }
    else {
      // nothing provided
      this._data = [];
    }
  
    // verify the size of the array
    this._size = array.size(this._data);
  }
  
  /**
   * Test whether an object is a Matrix
   * @param {*} object
   * @return {Boolean} isMatrix
   */
  Matrix.isMatrix = function isMatrix(object) {
    return (object instanceof Matrix);
  };
  
  /**
   * Get a subset of the matrix, or replace a subset of the matrix.
   *
   * Usage:
   *     var subset = matrix.subset(index)               // retrieve subset
   *     var value = matrix.subset(index, replacement)   // replace subset
   *
   * @param {Index} index
   * @param {Array | Matrix | *} [replacement]
   * @param {*} [defaultValue]        Default value, filled in on new entries when
   *                                  the matrix is resized. If not provided,
   *                                  new matrix elements will be left undefined.
   */
  Matrix.prototype.subset = function subset(index, replacement, defaultValue) {
    switch (arguments.length) {
      case 1:
        return _get(this, index);
  
      // intentional fall through
      case 2:
      case 3:
        return _set(this, index, replacement, defaultValue);
  
      default:
        throw new SyntaxError('Wrong number of arguments');
    }
  };
  
  /**
   * Get a single element from the matrix.
   * @param {Number[]} index   Zero-based index
   * @return {*} value
   */
  Matrix.prototype.get = function get(index) {
    if (!isArray(index)) {
      throw new Error('Array expected');
    }
    if (index.length != this._size.length) {
      throw new RangeError('Dimension mismatch ' +
          '(' + index.length + ' != ' + this._size.length + ')');
    }
  
    var data = this._data;
    for (var i = 0, ii = index.length; i < ii; i++) {
      var index_i = index[i];
      validateIndex(index_i, data.length);
      data = data[index_i];
    }
  
    return object.clone(data);
  };
  
  /**
   * Replace a single element in the matrix.
   * @param {Number[]} index   Zero-based index
   * @param {*} value
   * @param {*} [defaultValue]        Default value, filled in on new entries when
   *                                  the matrix is resized. If not provided,
   *                                  new matrix elements will be left undefined.
   * @return {Matrix} self
   */
  Matrix.prototype.set = function set (index, value, defaultValue) {
    var i, ii;
  
    // validate input type and dimensions
    if (!isArray(index)) {
      throw new Error('Array expected');
    }
    if (index.length < this._size.length) {
      throw new RangeError('Dimension mismatch ' +
          '(' + index.length + ' < ' + this._size.length + ')');
    }
  
    // enlarge matrix when needed
    var size = index.map(function (i) {
      return i + 1;
    });
    _fit(this, size, defaultValue);
  
    // traverse over the dimensions
    var data = this._data;
    for (i = 0, ii = index.length - 1; i < ii; i++) {
      var index_i = index[i];
      validateIndex(index_i, data.length);
      data = data[index_i];
    }
  
    // set new value
    index_i = index[index.length - 1];
    validateIndex(index_i, data.length);
    data[index_i] = value;
  
    return this;
  };
  
  /**
   * Get a submatrix of this matrix
   * @param {Matrix} matrix
   * @param {Index} index   Zero-based index
   * @private
   */
  function _get (matrix, index) {
    if (!(index instanceof Index)) {
      throw new TypeError('Invalid index');
    }
  
    var isScalar = index.isScalar();
    if (isScalar) {
      // return a scalar
      return matrix.get(index.min());
    }
    else {
      // validate dimensions
      var size = index.size();
      if (size.length != matrix._size.length) {
        throw new RangeError('Dimension mismatch ' +
            '(' + size.length + ' != ' + matrix._size.length + ')');
      }
  
      // retrieve submatrix
      var submatrix = new Matrix(_getSubmatrix(matrix._data, index, size.length, 0));
      // TODO: more efficient when creating an empty matrix and setting _data and _size manually
  
      // squeeze matrix output
      while (isArray(submatrix._data) && submatrix._data.length == 1) {
        submatrix._data = submatrix._data[0];
        submatrix._size.shift();
      }
  
      return submatrix;
    }
  }
  
  /**
   * Recursively get a submatrix of a multi dimensional matrix.
   * Index is not checked for correct number of dimensions.
   * @param {Array} data
   * @param {Index} index
   * @param {number} dims   Total number of dimensions
   * @param {number} dim    Current dimension
   * @return {Array} submatrix
   * @private
   */
  function _getSubmatrix (data, index, dims, dim) {
    var last = (dim == dims - 1);
    var range = index.range(dim);
  
    if (last) {
      return range.map(function (i) {
        validateIndex(i, data.length);
        return data[i];
      });
    }
    else {
      return range.map(function (i) {
        validateIndex(i, data.length);
        var child = data[i];
        return _getSubmatrix(child, index, dims, dim + 1);
      });
    }
  }
  
  /**
   * Replace a submatrix in this matrix
   * Indexes are zero-based.
   * @param {Matrix} matrix
   * @param {Index} index
   * @param {Matrix | Array | *} submatrix
   * @param {*} [defaultValue]        Default value, filled in on new entries when
   *                                  the matrix is resized. If not provided,
   *                                  new matrix elements will be left undefined.
   * @return {Matrix} matrix
   * @private
   */
  function _set (matrix, index, submatrix, defaultValue) {
    if (!(index instanceof Index)) {
      throw new TypeError('Invalid index');
    }
  
    // get index size and check whether the index contains a single value
    var iSize = index.size(),
        isScalar = index.isScalar();
  
    // calculate the size of the submatrix, and convert it into an Array if needed
    var sSize;
    if (submatrix instanceof Matrix) {
      sSize = submatrix.size();
      submatrix = submatrix.valueOf();
    }
    else {
      sSize = array.size(submatrix);
    }
  
    if (isScalar) {
      // set a scalar
  
      // check whether submatrix is a scalar
      if (sSize.length != 0) {
        throw new TypeError('Scalar value expected');
      }
  
      matrix.set(index.min(), submatrix, defaultValue);
    }
    else {
      // set a submatrix
  
      // validate dimensions
      if (iSize.length < matrix._size.length) {
        throw new RangeError('Dimension mismatch ' +
            '(' + iSize.length + ' < ' + matrix._size.length + ')');
      }
  
      // unsqueeze the submatrix when needed
      for (var i = 0, ii = iSize.length - sSize.length; i < ii; i++) {
        submatrix = [submatrix];
        sSize.unshift(1);
      }
  
      // check whether the size of the submatrix matches the index size
      if (!object.deepEqual(iSize, sSize)) {
        throw new RangeError('Dimensions mismatch ' +
            '(' + string.format(iSize) + ' != '+ string.format(sSize) + ')');
      }
  
      // enlarge matrix when needed
      var size = index.max().map(function (i) {
        return i + 1;
      });
      _fit(matrix, size, defaultValue);
  
      // insert the sub matrix
      var dims = iSize.length,
          dim = 0;
      _setSubmatrix (matrix._data, index, submatrix, dims, dim);
    }
  
    return matrix;
  }
  
  /**
   * Replace a submatrix of a multi dimensional matrix.
   * @param {Array} data
   * @param {Index} index
   * @param {Array} submatrix
   * @param {number} dims   Total number of dimensions
   * @param {number} dim
   * @private
   */
  function _setSubmatrix (data, index, submatrix, dims, dim) {
    var last = (dim == dims - 1),
        range = index.range(dim);
  
    if (last) {
      range.forEach(function (dataIndex, subIndex) {
        validateIndex(dataIndex);
        data[dataIndex] = submatrix[subIndex];
      });
    }
    else {
      range.forEach(function (dataIndex, subIndex) {
        validateIndex(dataIndex);
        _setSubmatrix(data[dataIndex], index, submatrix[subIndex], dims, dim + 1);
      });
    }
  }
  
  /**
   * Resize the matrix
   * @param {Number[]} size
   * @param {*} [defaultValue]        Default value, filled in on new entries.
   *                                  If not provided, the matrix elements will
   *                                  be left undefined.
   * @return {Matrix} self            The matrix itself is returned
   */
  Matrix.prototype.resize = function resize(size, defaultValue) {
    this._size = object.clone(size);
    this._data = array.resize(this._data, this._size, defaultValue);
  
    // return the matrix itself
    return this;
  };
  
  /**
   * Enlarge the matrix when it is smaller than given size.
   * If the matrix is larger or equal sized, nothing is done.
   * @param {Matrix} matrix           The matrix to be resized
   * @param {Number[]} size
   * @param {*} [defaultValue]        Default value, filled in on new entries.
   *                                  If not provided, the matrix elements will
   *                                  be left undefined.
   * @private
   */
  function _fit(matrix, size, defaultValue) {
    if (!isArray(size)) {
      throw new Error('Array expected');
    }
  
    var newSize = object.clone(matrix._size),
        changed = false;
  
    // add dimensions when needed
    while (newSize.length < size.length) {
      newSize.unshift(0);
      changed = true;
    }
  
    // enlarge size when needed
    for (var i = 0, ii = size.length; i < ii; i++) {
      if (size[i] > newSize[i]) {
        newSize[i] = size[i];
        changed = true;
      }
    }
  
    if (changed) {
      // resize only when size is changed
      matrix.resize(newSize, defaultValue);
    }
  }
  
  /**
   * Create a clone of the matrix
   * @return {Matrix} clone
   */
  Matrix.prototype.clone = function clone() {
    var matrix = new Matrix();
    matrix._data = object.clone(this._data);
    matrix._size = object.clone(this._size);
    return matrix;
  };
  
  /**
   * Retrieve the size of the matrix.
   * @returns {Number[]} size
   */
  Matrix.prototype.size = function size() {
    return this._size;
  };
  
  /**
   * Create a new matrix with the results of the callback function executed on
   * each entry of the matrix.
   * @param {function} callback   The callback function is invoked with three
   *                              parameters: the value of the element, the index
   *                              of the element, and the Matrix being traversed.
   * @return {Matrix} matrix
   */
  Matrix.prototype.map = function map(callback) {
    var me = this;
    var matrix = new Matrix();
    var index = [];
    var recurse = function (value, dim) {
      if (isArray(value)) {
        return value.map(function (child, i) {
          index[dim] = i;
          return recurse(child, dim + 1);
        });
      }
      else {
        return callback(value, index, me);
      }
    };
    matrix._data = recurse(this._data, 0);
    matrix._size = object.clone(this._size);
  
    return matrix;
  };
  
  /**
   * Execute a callback function on each entry of the matrix.
   * @param {function} callback   The callback function is invoked with three
   *                              parameters: the value of the element, the index
   *                              of the element, and the Matrix being traversed.
   */
  Matrix.prototype.forEach = function forEach(callback) {
    var me = this;
    var index = [];
    var recurse = function (value, dim) {
      if (isArray(value)) {
        value.forEach(function (child, i) {
          index[dim] = i;
          recurse(child, dim + 1);
        });
      }
      else {
        callback(value, index, me);
      }
    };
    recurse(this._data, 0);
  };
  
  /**
   * Create an Array with a copy of the data of the Matrix
   * @returns {Array} array
   */
  Matrix.prototype.toArray = function toArray() {
    return object.clone(this._data);
  };
  
  /**
   * Get the primitive value of the Matrix: a multidimensional array
   * @returns {Array} array
   */
  Matrix.prototype.valueOf = function valueOf() {
    return this._data;
  };
  
  /**
   * Get a string representation of the matrix, with optional formatting options.
   * @param {Object | Number | Function} [options]  Formatting options. See
   *                                                lib/util/number:format for a
   *                                                description of the available
   *                                                options.
   * @returns {String} str
   */
  Matrix.prototype.format = function format(options) {
    return string.format(this._data, options);
  };
  
  /**
   * Get a string representation of the matrix
   * @returns {String} str
   */
  Matrix.prototype.toString = function toString() {
    return string.format(this._data);
  };
  
  // exports
  module.exports = Matrix;
  
  // to trick my IDE which doesn't get it
  exports.isMatrix = Matrix.isMatrix;
  
  },{"../util/index":213,"./Index":205}],207:[function(require,module,exports){
  var util = require('../util/index'),
  
      number = util.number,
      string = util.string,
      array = util.array;
  
  /**
   * @constructor Range
   * Create a range. A range has a start, step, and end, and contains functions
   * to iterate over the range.
   *
   * A range can be constructed as:
   *     var range = new Range(start, end);
   *     var range = new Range(start, end, step);
   *
   * To get the result of the range:
   *     range.forEach(function (x) {
   *         console.log(x);
   *     });
   *     range.map(function (x) {
   *         return math.sin(x);
   *     });
   *     range.toArray();
   *
   * Example usage:
   *     var c = new Range(2, 6);         // 2:1:5
   *     c.toArray();                     // [2, 3, 4, 5]
   *     var d = new Range(2, -3, -1);    // 2:-1:-2
   *     d.toArray();                     // [2, 1, 0, -1, -2]
   *
   * @param {Number} start  included lower bound
   * @param {Number} end    excluded upper bound
   * @param {Number} [step] step size, default value is 1
   */
  function Range(start, end, step) {
    if (!(this instanceof Range)) {
      throw new SyntaxError(
          'Range constructor must be called with the new operator');
    }
  
    if (start != null && !number.isNumber(start)) {
      throw new TypeError('Parameter start must be a number');
    }
    if (end != null && !number.isNumber(end)) {
      throw new TypeError('Parameter end must be a number');
    }
    if (step != null && !number.isNumber(step)) {
      throw new TypeError('Parameter step must be a number');
    }
  
    this.start = (start != null) ? parseFloat(start) : 0;
    this.end   = (end != null) ? parseFloat(end) : 0;
    this.step  = (step != null) ? parseFloat(step) : 1;
  }
  
  /**
   * Parse a string into a range,
   * The string contains the start, optional step, and end, separated by a colon.
   * If the string does not contain a valid range, null is returned.
   * For example str='0:2:11'.
   * @param {String} str
   * @return {Range | null} range
   */
  Range.parse = function parse (str) {
    if (!string.isString(str)) {
      return null;
    }
  
    var args = str.split(':');
    var nums = args.map(function (arg) {
      return parseFloat(arg);
    });
  
    var invalid = nums.some(function (num) {
      return isNaN(num);
    });
    if(invalid) {
      return null;
    }
  
    switch (nums.length) {
      case 2: return new Range(nums[0], nums[1]);
      case 3: return new Range(nums[0], nums[2], nums[1]);
      default: return null;
    }
  };
  
  /**
   * Create a clone of the range
   * @return {Range} clone
   */
  Range.prototype.clone = function clone() {
    return new Range(this.start, this.end, this.step);
  };
  
  /**
   * Test whether an object is a Range
   * @param {*} object
   * @return {Boolean} isRange
   */
  Range.isRange = function isRange(object) {
    return (object instanceof Range);
  };
  
  /**
   * Retrieve the size of the range.
   * Returns an array containing one number, the number of elements in the range.
   * @returns {Number[]} size
   */
  Range.prototype.size = function size() {
    var len = 0,
        start = this.start,
        step = this.step,
        end = this.end,
        diff = end - start;
  
    if (number.sign(step) == number.sign(diff)) {
      len = Math.ceil((diff) / step);
    }
    else if (diff == 0) {
      len = 0;
    }
  
    if (isNaN(len)) {
      len = 0;
    }
    return [len];
  };
  
  /**
   * Calculate the minimum value in the range
   * @return {Number | undefined} min
   */
  Range.prototype.min = function min () {
    var size = this.size()[0];
  
    if (size > 0) {
      if (this.step > 0) {
        // positive step
        return this.start;
      }
      else {
        // negative step
        return this.start + (size - 1) * this.step;
      }
    }
    else {
      return undefined;
    }
  };
  
  /**
   * Calculate the maximum value in the range
   * @return {Number | undefined} max
   */
  Range.prototype.max = function max () {
    var size = this.size()[0];
  
    if (size > 0) {
      if (this.step > 0) {
        // positive step
        return this.start + (size - 1) * this.step;
      }
      else {
        // negative step
        return this.start;
      }
    }
    else {
      return undefined;
    }
  };
  
  
  /**
   * Execute a callback function for each value in the range.
   * @param {function} callback   The callback method is invoked with three
   *                              parameters: the value of the element, the index
   *                              of the element, and the Matrix being traversed.
   */
  Range.prototype.forEach = function forEach(callback) {
    var x = this.start;
    var step = this.step;
    var end = this.end;
    var i = 0;
  
    if (step > 0) {
      while (x < end) {
        callback(x, i, this);
        x += step;
        i++;
      }
    }
    else if (step < 0) {
      while (x > end) {
        callback(x, i, this);
        x += step;
        i++;
      }
    }
  };
  
  /**
   * Execute a callback function for each value in the Range, and return the
   * results as an array
   * @param {function} callback   The callback method is invoked with three
   *                              parameters: the value of the element, the index
   *                              of the element, and the Matrix being traversed.
   * @returns {Array} array
   */
  Range.prototype.map = function map(callback) {
    var array = [];
    this.forEach(function (value, index, obj) {
      array[index] = callback(value, index, obj);
    });
    return array;
  };
  
  /**
   * Create an Array with a copy of the Ranges data
   * @returns {Array} array
   */
  Range.prototype.toArray = function toArray() {
    var array = [];
    this.forEach(function (value, index) {
      array[index] = value;
    });
    return array;
  };
  
  /**
   * Get the primitive value of the Range, a one dimensional array
   * @returns {Array} array
   */
  Range.prototype.valueOf = function valueOf() {
    // TODO: implement a caching mechanism for range.valueOf()
    return this.toArray();
  };
  
  /**
   * Get a string representation of the range, with optional formatting options.
   * Output is formatted as 'start:step:end', for example '2:6' or '0:0.2:11'
   * @param {Object | Number | Function} [options]  Formatting options. See
   *                                                lib/util/number:format for a
   *                                                description of the available
   *                                                options.
   * @returns {String} str
   */
  Range.prototype.format = function format(options) {
    var str = number.format(this.start, options);
  
    if (this.step != 1) {
      str += ':' + number.format(this.step, options);
    }
    str += ':' + number.format(this.end, options);
    return str;
  };
  
  /**
   * Get a string representation of the range.
   * @returns {String}
   */
  Range.prototype.toString = function toString() {
    return this.format();
  };
  
  // exports
  module.exports = Range;
  
  // to trick my IDE which doesn't get it
  exports.isRange = Range.isRange;
  exports.parse = Range.parse;
  
  },{"../util/index":213}],208:[function(require,module,exports){
  var util = require('../util/index'),
  
      number = util.number,
      string = util.string,
      isNumber = util.number.isNumber,
      isString = util.string.isString;
  
  /**
   * @constructor Unit
   *
   * A unit can be constructed in the following ways:
   *     var a = new Unit(value, unit);
   *     var b = new Unit(null, unit);
   *     var c = Unit.parse(str);
   *
   * Example usage:
   *     var a = new Unit(5, 'cm');               // 50 mm
   *     var b = Unit.parse('23 kg');             // 23 kg
   *     var c = math.in(a, new Unit(null, 'm');  // 0.05 m
   *
   * @param {Number} [value]  A value like 5.2
   * @param {String} [unit]   A unit like "cm" or "inch"
   */
  function Unit(value, unit) {
    if (!(this instanceof Unit)) {
      throw new Error('Unit constructor must be called with the new operator');
    }
  
    if (value != null && !isNumber(value)) {
      throw new TypeError('First parameter in Unit constructor must be a number');
    }
    if (unit != null && !isString(unit)) {
      throw new TypeError('Second parameter in Unit constructor must be a string');
    }
  
    if (unit != null) {
      // find the unit and prefix from the string
      var res = _findUnit(unit);
      if (!res) {
        throw new SyntaxError('String "' + unit + '" is no unit');
      }
      this.unit = res.unit;
      this.prefix = res.prefix;
    }
    else {
      this.unit = UNIT_NONE;
      this.prefix = PREFIX_NONE;  // link to a list with supported prefixes
    }
  
    if (value != null) {
      this.value = this._normalize(value);
      this.fixPrefix = false;  // is set true by the methods Unit.in and math.in
    }
    else {
      this.value = null;
      this.fixPrefix = true;
    }
  }
  
  // private variables and functions for the Unit parser
  var text, index, c;
  
  function skipWhitespace() {
    while (c == ' ' || c == '\t') {
      next();
    }
  }
  
  function isDigitDot (c) {
    return ((c >= '0' && c <= '9') || c == '.');
  }
  
  function isDigit (c) {
    return ((c >= '0' && c <= '9'));
  }
  
  function next() {
    index++;
    c = text.charAt(index);
  }
  
  function revert(oldIndex) {
    index = oldIndex;
    c = text.charAt(index);
  }
  
  function parseNumber () {
    var number = '';
    var oldIndex;
    oldIndex = index;
  
    if (c == '+') {
      next();
    }
    else if (c == '-') {
      number += c;
      next();
    }
  
    if (!isDigitDot(c)) {
      // a + or - must be followed by a digit
      revert(oldIndex);
      return null;
    }
  
    // get number, can have a single dot
    if (c == '.') {
      number += c;
      next();
      if (!isDigit(c)) {
        // this is no legal number, it is just a dot
        revert(oldIndex);
        return null;
      }
    }
    else {
      while (isDigit(c)) {
        number += c;
        next();
      }
      if (c == '.') {
        number += c;
        next();
      }
    }
    while (isDigit(c)) {
      number += c;
      next();
    }
  
    // check for exponential notation like "2.3e-4" or "1.23e50"
    if (c == 'E' || c == 'e') {
      number += c;
      next();
  
      if (c == '+' || c == '-') {
        number += c;
        next();
      }
  
      // Scientific notation MUST be followed by an exponent
      if (!isDigit(c)) {
        // this is no legal number, exponent is missing.
        revert(oldIndex);
        return null;
      }
  
      while (isDigit(c)) {
        number += c;
        next();
      }
    }
  
    return number;
  }
  
  function parseUnit() {
    var unit = '';
  
    skipWhitespace();
    while (c && c != ' ' && c != '\t') {
      unit += c;
      next();
    }
  
    return unit || null;
  }
  
  /**
   * Parse a string into a unit. Returns null if the provided string does not
   * contain a valid unit.
   * @param {String} str        A string like "5.2 inch", "4e2 kg"
   * @return {Unit | null} unit
   */
  Unit.parse = function parse(str) {
    text = str;
    index = -1;
    c = '';
  
    if (!isString(text)) {
      return null;
    }
  
    next();
    skipWhitespace();
    var value = parseNumber();
    var unit;
    if (value) {
      unit = parseUnit();
  
      next();
      skipWhitespace();
      if (c) {
        // garbage at the end. not good.
        return null;
      }
  
      if (value && unit) {
        return new Unit(Number(value), unit);
      }
    }
    else {
      unit = parseUnit();
  
      next();
      skipWhitespace();
      if (c) {
        // garbage at the end. not good.
        return null;
      }
  
      return new Unit(null, unit)
    }
  
    return null;
  };
  
  /**
   * Test whether value is of type Unit
   * @param {*} value
   * @return {Boolean} isUnit
   */
  Unit.isUnit = function isUnit(value) {
    return (value instanceof Unit);
  };
  
  /**
   * create a copy of this unit
   * @return {Unit} clone
   */
  Unit.prototype.clone = function () {
    var clone = new Unit();
  
    for (var p in this) {
      if (this.hasOwnProperty(p)) {
        clone[p] = this[p];
      }
    }
  
    return clone;
  };
  
  /**
   * Normalize a value, based on its currently set unit
   * @param {Number} value
   * @return {Number} normalized value
   * @private
   */
  Unit.prototype._normalize = function(value) {
    return (value + this.unit.offset) *
        this.unit.value * this.prefix.value;
  };
  
  /**
   * Unnormalize a value, based on its currently set unit
   * @param {Number} value
   * @param {Number} [prefixValue]    Optional prefix value to be used
   * @return {Number} unnormalized value
   * @private
   */
  Unit.prototype._unnormalize = function (value, prefixValue) {
    if (prefixValue == undefined) {
      return value / this.unit.value / this.prefix.value -
          this.unit.offset;
    }
    else {
      return value / this.unit.value / prefixValue -
          this.unit.offset;
    }
  };
  
  /**
   * Find a unit from a string
   * @param {String} str              A string like 'cm' or 'inch'
   * @returns {Object | null} result  When found, an object with fields unit and
   *                                  prefix is returned. Else, null is returned.
   * @private
   */
  function _findUnit(str) {
    for (var i = 0, iMax = UNITS.length; i < iMax; i++) {
      var UNIT = UNITS[i];
  
      if (string.endsWith(str, UNIT.name) ) {
        var prefixLen = (str.length - UNIT.name.length);
        var prefixName = str.substring(0, prefixLen);
        var prefix = UNIT.prefixes[prefixName];
        if (prefix !== undefined) {
          // store unit, prefix, and value
          return {
            unit: UNIT,
            prefix: prefix
          };
        }
      }
    }
  
    return null;
  }
  
  /**
   * Test if the given expression is a unit.
   * The unit can have a prefix but cannot have a value.
   * @param {String} unit   A plain unit without value. Can have prefix, like "cm"
   * @return {Boolean}      true if the given string is a unit
   */
  Unit.isPlainUnit = function (unit) {
    return (_findUnit(unit) != null);
  };
  
  /**
   * check if this unit has given base unit
   * @param {BASE_UNITS | undefined} base
   */
  Unit.prototype.hasBase = function(base) {
    if (this.unit.base === undefined) {
      return (base === undefined);
    }
    return (this.unit.base === base);
  };
  
  /**
   * Check if this unit has a base equal to another base
   * @param {Unit} other
   * @return {Boolean} true if equal base
   */
  Unit.prototype.equalBase = function(other) {
    return (this.unit.base === other.unit.base);
  };
  
  /**
   * Check if this unit equals another unit
   * @param {Unit} other
   * @return {Boolean} true if both units are equal
   */
  Unit.prototype.equals = function(other) {
    return (this.equalBase(other) && this.value == other.value);
  };
  
  /**
   * Create a clone of this unit with a representation
   * @param {String | Unit} plainUnit   A plain unit, without value. Can have prefix, like "cm"
   * @returns {Unit} unit having fixed, specified unit
   */
  Unit.prototype['in'] = function (plainUnit) {
    var other;
    if (isString(plainUnit)) {
      other = new Unit(null, plainUnit);
  
      if (!this.equalBase(other)) {
        throw new Error('Units do not match');
      }
  
      other.value = this.value;
      return other;
    }
    else if (plainUnit instanceof Unit) {
      if (!this.equalBase(plainUnit)) {
        throw new Error('Units do not match');
      }
      if (plainUnit.value != null) {
        throw new Error('Cannot convert to a unit with a value');
      }
      if (plainUnit.unit == null) {
        throw new Error('Unit expected on the right hand side of function in');
      }
  
      other = plainUnit.clone();
      other.value = this.value;
      other.fixPrefix = true;
      return other;
    }
    else {
      throw new Error('String or Unit expected as parameter');
    }
  };
  
  /**
   * Return the value of the unit when represented with given plain unit
   * @param {String | Unit} plainUnit    For example 'cm' or 'inch'
   * @return {Number} value
   */
  Unit.prototype.toNumber = function (plainUnit) {
    var other = this['in'](plainUnit);
    var prefix = this.fixPrefix ? other._bestPrefix() : other.prefix;
    return other._unnormalize(other.value, prefix.value);
  };
  
  
  /**
   * Get a string representation of the unit.
   * @return {String}
   */
  Unit.prototype.toString = function toString() {
    return this.format();
  };
  
  /**
   * Get a string representation of the Unit, with optional formatting options.
   * @param {Object | Number | Function} [options]  Formatting options. See
   *                                                lib/util/number:format for a
   *                                                description of the available
   *                                                options.
   * @return {String}
   */
  Unit.prototype.format = function format(options) {
    var value,
        str;
  
    if (!this.fixPrefix) {
      var bestPrefix = this._bestPrefix();
      value = this._unnormalize(this.value, bestPrefix.value);
      str = (this.value != null) ? number.format(value, options) + ' ' : '';
      str += bestPrefix.name + this.unit.name;
    }
    else {
      value = this._unnormalize(this.value);
      str = (this.value != null) ? number.format(value, options) + ' ' : '';
      str += this.prefix.name + this.unit.name;
    }
    return str;
  };
  
  /**
   * Calculate the best prefix using current value.
   * @returns {Object} prefix
   * @private
   */
  Unit.prototype._bestPrefix = function () {
    // find the best prefix value (resulting in the value of which
    // the absolute value of the log10 is closest to zero,
    // though with a little offset of 1.2 for nicer values: you get a
    // sequence 1mm 100mm 500mm 0.6m 1m 10m 100m 500m 0.6km 1km ...
    var absValue = Math.abs(this.value / this.unit.value);
    var bestPrefix = PREFIX_NONE;
    var bestDiff = Math.abs(
        Math.log(absValue / bestPrefix.value) / Math.LN10 - 1.2);
  
    var prefixes = this.unit.prefixes;
    for (var p in prefixes) {
      if (prefixes.hasOwnProperty(p)) {
        var prefix = prefixes[p];
        if (prefix.scientific) {
          var diff = Math.abs(
              Math.log(absValue / prefix.value) / Math.LN10 - 1.2);
  
          if (diff < bestDiff) {
            bestPrefix = prefix;
            bestDiff = diff;
          }
        }
      }
    }
  
    return bestPrefix;
  };
  
  var PREFIXES = {
    'NONE': {
      '': {'name': '', 'value': 1, 'scientific': true}
    },
    'SHORT': {
      '': {'name': '', 'value': 1, 'scientific': true},
  
      'da': {'name': 'da', 'value': 1e1, 'scientific': false},
      'h': {'name': 'h', 'value': 1e2, 'scientific': false},
      'k': {'name': 'k', 'value': 1e3, 'scientific': true},
      'M': {'name': 'M', 'value': 1e6, 'scientific': true},
      'G': {'name': 'G', 'value': 1e9, 'scientific': true},
      'T': {'name': 'T', 'value': 1e12, 'scientific': true},
      'P': {'name': 'P', 'value': 1e15, 'scientific': true},
      'E': {'name': 'E', 'value': 1e18, 'scientific': true},
      'Z': {'name': 'Z', 'value': 1e21, 'scientific': true},
      'Y': {'name': 'Y', 'value': 1e24, 'scientific': true},
  
      'd': {'name': 'd', 'value': 1e-1, 'scientific': false},
      'c': {'name': 'c', 'value': 1e-2, 'scientific': false},
      'm': {'name': 'm', 'value': 1e-3, 'scientific': true},
      'u': {'name': 'u', 'value': 1e-6, 'scientific': true},
      'n': {'name': 'n', 'value': 1e-9, 'scientific': true},
      'p': {'name': 'p', 'value': 1e-12, 'scientific': true},
      'f': {'name': 'f', 'value': 1e-15, 'scientific': true},
      'a': {'name': 'a', 'value': 1e-18, 'scientific': true},
      'z': {'name': 'z', 'value': 1e-21, 'scientific': true},
      'y': {'name': 'y', 'value': 1e-24, 'scientific': true}
    },
    'LONG': {
      '': {'name': '', 'value': 1, 'scientific': true},
  
      'deca': {'name': 'deca', 'value': 1e1, 'scientific': false},
      'hecto': {'name': 'hecto', 'value': 1e2, 'scientific': false},
      'kilo': {'name': 'kilo', 'value': 1e3, 'scientific': true},
      'mega': {'name': 'mega', 'value': 1e6, 'scientific': true},
      'giga': {'name': 'giga', 'value': 1e9, 'scientific': true},
      'tera': {'name': 'tera', 'value': 1e12, 'scientific': true},
      'peta': {'name': 'peta', 'value': 1e15, 'scientific': true},
      'exa': {'name': 'exa', 'value': 1e18, 'scientific': true},
      'zetta': {'name': 'zetta', 'value': 1e21, 'scientific': true},
      'yotta': {'name': 'yotta', 'value': 1e24, 'scientific': true},
  
      'deci': {'name': 'deci', 'value': 1e-1, 'scientific': false},
      'centi': {'name': 'centi', 'value': 1e-2, 'scientific': false},
      'milli': {'name': 'milli', 'value': 1e-3, 'scientific': true},
      'micro': {'name': 'micro', 'value': 1e-6, 'scientific': true},
      'nano': {'name': 'nano', 'value': 1e-9, 'scientific': true},
      'pico': {'name': 'pico', 'value': 1e-12, 'scientific': true},
      'femto': {'name': 'femto', 'value': 1e-15, 'scientific': true},
      'atto': {'name': 'atto', 'value': 1e-18, 'scientific': true},
      'zepto': {'name': 'zepto', 'value': 1e-21, 'scientific': true},
      'yocto': {'name': 'yocto', 'value': 1e-24, 'scientific': true}
    },
    'SQUARED': {
      '': {'name': '', 'value': 1, 'scientific': true},
  
      'da': {'name': 'da', 'value': 1e2, 'scientific': false},
      'h': {'name': 'h', 'value': 1e4, 'scientific': false},
      'k': {'name': 'k', 'value': 1e6, 'scientific': true},
      'M': {'name': 'M', 'value': 1e12, 'scientific': true},
      'G': {'name': 'G', 'value': 1e18, 'scientific': true},
      'T': {'name': 'T', 'value': 1e24, 'scientific': true},
      'P': {'name': 'P', 'value': 1e30, 'scientific': true},
      'E': {'name': 'E', 'value': 1e36, 'scientific': true},
      'Z': {'name': 'Z', 'value': 1e42, 'scientific': true},
      'Y': {'name': 'Y', 'value': 1e48, 'scientific': true},
  
      'd': {'name': 'd', 'value': 1e-2, 'scientific': false},
      'c': {'name': 'c', 'value': 1e-4, 'scientific': false},
      'm': {'name': 'm', 'value': 1e-6, 'scientific': true},
      'u': {'name': 'u', 'value': 1e-12, 'scientific': true},
      'n': {'name': 'n', 'value': 1e-18, 'scientific': true},
      'p': {'name': 'p', 'value': 1e-24, 'scientific': true},
      'f': {'name': 'f', 'value': 1e-30, 'scientific': true},
      'a': {'name': 'a', 'value': 1e-36, 'scientific': true},
      'z': {'name': 'z', 'value': 1e-42, 'scientific': true},
      'y': {'name': 'y', 'value': 1e-42, 'scientific': true}
    },
    'CUBIC': {
      '': {'name': '', 'value': 1, 'scientific': true},
  
      'da': {'name': 'da', 'value': 1e3, 'scientific': false},
      'h': {'name': 'h', 'value': 1e6, 'scientific': false},
      'k': {'name': 'k', 'value': 1e9, 'scientific': true},
      'M': {'name': 'M', 'value': 1e18, 'scientific': true},
      'G': {'name': 'G', 'value': 1e27, 'scientific': true},
      'T': {'name': 'T', 'value': 1e36, 'scientific': true},
      'P': {'name': 'P', 'value': 1e45, 'scientific': true},
      'E': {'name': 'E', 'value': 1e54, 'scientific': true},
      'Z': {'name': 'Z', 'value': 1e63, 'scientific': true},
      'Y': {'name': 'Y', 'value': 1e72, 'scientific': true},
  
      'd': {'name': 'd', 'value': 1e-3, 'scientific': false},
      'c': {'name': 'c', 'value': 1e-6, 'scientific': false},
      'm': {'name': 'm', 'value': 1e-9, 'scientific': true},
      'u': {'name': 'u', 'value': 1e-18, 'scientific': true},
      'n': {'name': 'n', 'value': 1e-27, 'scientific': true},
      'p': {'name': 'p', 'value': 1e-36, 'scientific': true},
      'f': {'name': 'f', 'value': 1e-45, 'scientific': true},
      'a': {'name': 'a', 'value': 1e-54, 'scientific': true},
      'z': {'name': 'z', 'value': 1e-63, 'scientific': true},
      'y': {'name': 'y', 'value': 1e-72, 'scientific': true}
    },
    'BINARY_SHORT': {
      '': {'name': '', 'value': 1, 'scientific': true},
      'k': {'name': 'k', 'value': 1024, 'scientific': true},
      'M': {'name': 'M', 'value': Math.pow(1024, 2), 'scientific': true},
      'G': {'name': 'G', 'value': Math.pow(1024, 3), 'scientific': true},
      'T': {'name': 'T', 'value': Math.pow(1024, 4), 'scientific': true},
      'P': {'name': 'P', 'value': Math.pow(1024, 5), 'scientific': true},
      'E': {'name': 'E', 'value': Math.pow(1024, 6), 'scientific': true},
      'Z': {'name': 'Z', 'value': Math.pow(1024, 7), 'scientific': true},
      'Y': {'name': 'Y', 'value': Math.pow(1024, 8), 'scientific': true},
  
      'Ki': {'name': 'Ki', 'value': 1024, 'scientific': true},
      'Mi': {'name': 'Mi', 'value': Math.pow(1024, 2), 'scientific': true},
      'Gi': {'name': 'Gi', 'value': Math.pow(1024, 3), 'scientific': true},
      'Ti': {'name': 'Ti', 'value': Math.pow(1024, 4), 'scientific': true},
      'Pi': {'name': 'Pi', 'value': Math.pow(1024, 5), 'scientific': true},
      'Ei': {'name': 'Ei', 'value': Math.pow(1024, 6), 'scientific': true},
      'Zi': {'name': 'Zi', 'value': Math.pow(1024, 7), 'scientific': true},
      'Yi': {'name': 'Yi', 'value': Math.pow(1024, 8), 'scientific': true}
    },
    'BINARY_LONG': {
      '': {'name': '', 'value': 1, 'scientific': true},
      'kilo': {'name': 'kilo', 'value': 1024, 'scientific': true},
      'mega': {'name': 'mega', 'value': Math.pow(1024, 2), 'scientific': true},
      'giga': {'name': 'giga', 'value': Math.pow(1024, 3), 'scientific': true},
      'tera': {'name': 'tera', 'value': Math.pow(1024, 4), 'scientific': true},
      'peta': {'name': 'peta', 'value': Math.pow(1024, 5), 'scientific': true},
      'exa': {'name': 'exa', 'value': Math.pow(1024, 6), 'scientific': true},
      'zetta': {'name': 'zetta', 'value': Math.pow(1024, 7), 'scientific': true},
      'yotta': {'name': 'yotta', 'value': Math.pow(1024, 8), 'scientific': true},
  
      'kibi': {'name': 'kibi', 'value': 1024, 'scientific': true},
      'mebi': {'name': 'mebi', 'value': Math.pow(1024, 2), 'scientific': true},
      'gibi': {'name': 'gibi', 'value': Math.pow(1024, 3), 'scientific': true},
      'tebi': {'name': 'tebi', 'value': Math.pow(1024, 4), 'scientific': true},
      'pebi': {'name': 'pebi', 'value': Math.pow(1024, 5), 'scientific': true},
      'exi': {'name': 'exi', 'value': Math.pow(1024, 6), 'scientific': true},
      'zebi': {'name': 'zebi', 'value': Math.pow(1024, 7), 'scientific': true},
      'yobi': {'name': 'yobi', 'value': Math.pow(1024, 8), 'scientific': true}
    }
  };
  
  var PREFIX_NONE = {'name': '', 'value': 1, 'scientific': true};
  
  var BASE_UNITS = {
    'NONE': {},
  
    'LENGTH': {},               // meter
    'MASS': {},                 // kilogram
    'TIME': {},                 // second
    'CURRENT': {},              // ampere
    'TEMPERATURE': {},          // kelvin
    'LUMINOUS_INTENSITY': {},   // candela
    'AMOUNT_OF_SUBSTANCE': {},  // mole
  
    'FORCE': {},        // Newton
    'SURFACE': {},      // m2
    'VOLUME': {},       // m3
    'ANGLE': {},        // rad
    'BIT': {}           // bit (digital)
  };
  
  BASE_UNIT_NONE = {};
  
  UNIT_NONE = {'name': '', 'base': BASE_UNIT_NONE, 'value': 1, 'offset': 0};
  
  var UNITS = [
    // length
    {'name': 'meter', 'base': BASE_UNITS.LENGTH, 'prefixes': PREFIXES.LONG, 'value': 1, 'offset': 0},
    {'name': 'inch', 'base': BASE_UNITS.LENGTH, 'prefixes': PREFIXES.NONE, 'value': 0.0254, 'offset': 0},
    {'name': 'foot', 'base': BASE_UNITS.LENGTH, 'prefixes': PREFIXES.NONE, 'value': 0.3048, 'offset': 0},
    {'name': 'yard', 'base': BASE_UNITS.LENGTH, 'prefixes': PREFIXES.NONE, 'value': 0.9144, 'offset': 0},
    {'name': 'mile', 'base': BASE_UNITS.LENGTH, 'prefixes': PREFIXES.NONE, 'value': 1609.344, 'offset': 0},
    {'name': 'link', 'base': BASE_UNITS.LENGTH, 'prefixes': PREFIXES.NONE, 'value': 0.201168, 'offset': 0},
    {'name': 'rod', 'base': BASE_UNITS.LENGTH, 'prefixes': PREFIXES.NONE, 'value': 5.029210, 'offset': 0},
    {'name': 'chain', 'base': BASE_UNITS.LENGTH, 'prefixes': PREFIXES.NONE, 'value': 20.1168, 'offset': 0},
    {'name': 'angstrom', 'base': BASE_UNITS.LENGTH, 'prefixes': PREFIXES.NONE, 'value': 1e-10, 'offset': 0},
  
    {'name': 'm', 'base': BASE_UNITS.LENGTH, 'prefixes': PREFIXES.SHORT, 'value': 1, 'offset': 0},
    //{'name': 'in', 'base': BASE_UNITS.LENGTH, 'prefixes': PREFIXES.NONE, 'value': 0.0254, 'offset': 0}, not supported, In is an operator
    {'name': 'ft', 'base': BASE_UNITS.LENGTH, 'prefixes': PREFIXES.NONE, 'value': 0.3048, 'offset': 0},
    {'name': 'yd', 'base': BASE_UNITS.LENGTH, 'prefixes': PREFIXES.NONE, 'value': 0.9144, 'offset': 0},
    {'name': 'mi', 'base': BASE_UNITS.LENGTH, 'prefixes': PREFIXES.NONE, 'value': 1609.344, 'offset': 0},
    {'name': 'li', 'base': BASE_UNITS.LENGTH, 'prefixes': PREFIXES.NONE, 'value': 0.201168, 'offset': 0},
    {'name': 'rd', 'base': BASE_UNITS.LENGTH, 'prefixes': PREFIXES.NONE, 'value': 5.029210, 'offset': 0},
    {'name': 'ch', 'base': BASE_UNITS.LENGTH, 'prefixes': PREFIXES.NONE, 'value': 20.1168, 'offset': 0},
    {'name': 'mil', 'base': BASE_UNITS.LENGTH, 'prefixes': PREFIXES.NONE, 'value': 0.0000254, 'offset': 0}, // 1/1000 inch
  
    // Surface
    {'name': 'm2', 'base': BASE_UNITS.SURFACE, 'prefixes': PREFIXES.SQUARED, 'value': 1, 'offset': 0},
    {'name': 'sqin', 'base': BASE_UNITS.SURFACE, 'prefixes': PREFIXES.NONE, 'value': 0.00064516, 'offset': 0}, // 645.16 mm2
    {'name': 'sqft', 'base': BASE_UNITS.SURFACE, 'prefixes': PREFIXES.NONE, 'value': 0.09290304, 'offset': 0}, // 0.09290304 m2
    {'name': 'sqyd', 'base': BASE_UNITS.SURFACE, 'prefixes': PREFIXES.NONE, 'value': 0.83612736, 'offset': 0}, // 0.83612736 m2
    {'name': 'sqmi', 'base': BASE_UNITS.SURFACE, 'prefixes': PREFIXES.NONE, 'value': 2589988.110336, 'offset': 0}, // 2.589988110336 km2
    {'name': 'sqrd', 'base': BASE_UNITS.SURFACE, 'prefixes': PREFIXES.NONE, 'value': 25.29295, 'offset': 0}, // 25.29295 m2
    {'name': 'sqch', 'base': BASE_UNITS.SURFACE, 'prefixes': PREFIXES.NONE, 'value': 404.6873, 'offset': 0}, // 404.6873 m2
    {'name': 'sqmil', 'base': BASE_UNITS.SURFACE, 'prefixes': PREFIXES.NONE, 'value': 6.4516e-10, 'offset': 0}, // 6.4516 * 10^-10 m2
  
    // Volume
    {'name': 'm3', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.CUBIC, 'value': 1, 'offset': 0},
    {'name': 'L', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.SHORT, 'value': 0.001, 'offset': 0}, // litre
    {'name': 'litre', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.LONG, 'value': 0.001, 'offset': 0},
    {'name': 'cuin', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 1.6387064e-5, 'offset': 0}, // 1.6387064e-5 m3
    {'name': 'cuft', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.028316846592, 'offset': 0}, // 28.316 846 592 L
    {'name': 'cuyd', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.764554857984, 'offset': 0}, // 764.554 857 984 L
    {'name': 'teaspoon', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.000005, 'offset': 0}, // 5 mL
    {'name': 'tablespoon', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.000015, 'offset': 0}, // 15 mL
    //{'name': 'cup', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.000240, 'offset': 0}, // 240 mL  // not possible, we have already another cup
  
    // Liquid volume
    {'name': 'minim', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.00000006161152, 'offset': 0}, // 0.06161152 mL
    {'name': 'fluiddram', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.0000036966911, 'offset': 0},  // 3.696691 mL
    {'name': 'fluidounce', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.00002957353, 'offset': 0}, // 29.57353 mL
    {'name': 'gill', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.0001182941, 'offset': 0}, // 118.2941 mL
    {'name': 'cup', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.0002365882, 'offset': 0}, // 236.5882 mL
    {'name': 'pint', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.0004731765, 'offset': 0}, // 473.1765 mL
    {'name': 'quart', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.0009463529, 'offset': 0}, // 946.3529 mL
    {'name': 'gallon', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.003785412, 'offset': 0}, // 3.785412 L
    {'name': 'beerbarrel', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.1173478, 'offset': 0}, // 117.3478 L
    {'name': 'oilbarrel', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.1589873, 'offset': 0}, // 158.9873 L
    {'name': 'hogshead', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.2384810, 'offset': 0}, // 238.4810 L
  
    //{'name': 'min', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.00000006161152, 'offset': 0}, // 0.06161152 mL // min is already in use as minute
    {'name': 'fldr', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.0000036966911, 'offset': 0},  // 3.696691 mL
    {'name': 'floz', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.00002957353, 'offset': 0}, // 29.57353 mL
    {'name': 'gi', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.0001182941, 'offset': 0}, // 118.2941 mL
    {'name': 'cp', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.0002365882, 'offset': 0}, // 236.5882 mL
    {'name': 'pt', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.0004731765, 'offset': 0}, // 473.1765 mL
    {'name': 'qt', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.0009463529, 'offset': 0}, // 946.3529 mL
    {'name': 'gal', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.003785412, 'offset': 0}, // 3.785412 L
    {'name': 'bbl', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.1173478, 'offset': 0}, // 117.3478 L
    {'name': 'obl', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.1589873, 'offset': 0}, // 158.9873 L
    //{'name': 'hogshead', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.2384810, 'offset': 0}, // 238.4810 L // TODO: hh?
  
    // Mass
    {'name': 'g', 'base': BASE_UNITS.MASS, 'prefixes': PREFIXES.SHORT, 'value': 0.001, 'offset': 0},
    {'name': 'gram', 'base': BASE_UNITS.MASS, 'prefixes': PREFIXES.LONG, 'value': 0.001, 'offset': 0},
  
    {'name': 'ton', 'base': BASE_UNITS.MASS, 'prefixes': PREFIXES.SHORT, 'value': 907.18474, 'offset': 0},
    {'name': 'tonne', 'base': BASE_UNITS.MASS, 'prefixes': PREFIXES.SHORT, 'value': 1000, 'offset': 0},
  
    {'name': 'grain', 'base': BASE_UNITS.MASS, 'prefixes': PREFIXES.NONE, 'value': 64.79891e-6, 'offset': 0},
    {'name': 'dram', 'base': BASE_UNITS.MASS, 'prefixes': PREFIXES.NONE, 'value': 1.7718451953125e-3, 'offset': 0},
    {'name': 'ounce', 'base': BASE_UNITS.MASS, 'prefixes': PREFIXES.NONE, 'value': 28.349523125e-3, 'offset': 0},
    {'name': 'poundmass', 'base': BASE_UNITS.MASS, 'prefixes': PREFIXES.NONE, 'value': 453.59237e-3, 'offset': 0},
    {'name': 'hundredweight', 'base': BASE_UNITS.MASS, 'prefixes': PREFIXES.NONE, 'value': 45.359237, 'offset': 0},
    {'name': 'stick', 'base': BASE_UNITS.MASS, 'prefixes': PREFIXES.NONE, 'value': 115e-3, 'offset': 0},
  
    {'name': 'gr', 'base': BASE_UNITS.MASS, 'prefixes': PREFIXES.NONE, 'value': 64.79891e-6, 'offset': 0},
    {'name': 'dr', 'base': BASE_UNITS.MASS, 'prefixes': PREFIXES.NONE, 'value': 1.7718451953125e-3, 'offset': 0},
    {'name': 'oz', 'base': BASE_UNITS.MASS, 'prefixes': PREFIXES.NONE, 'value': 28.349523125e-3, 'offset': 0},
    {'name': 'lbm', 'base': BASE_UNITS.MASS, 'prefixes': PREFIXES.NONE, 'value': 453.59237e-3, 'offset': 0},
    {'name': 'cwt', 'base': BASE_UNITS.MASS, 'prefixes': PREFIXES.NONE, 'value': 45.359237, 'offset': 0},
  
    // Time
    {'name': 's', 'base': BASE_UNITS.TIME, 'prefixes': PREFIXES.SHORT, 'value': 1, 'offset': 0},
    {'name': 'min', 'base': BASE_UNITS.TIME, 'prefixes': PREFIXES.NONE, 'value': 60, 'offset': 0},
    {'name': 'h', 'base': BASE_UNITS.TIME, 'prefixes': PREFIXES.NONE, 'value': 3600, 'offset': 0},
    {'name': 'seconds', 'base': BASE_UNITS.TIME, 'prefixes': PREFIXES.LONG, 'value': 1, 'offset': 0},
    {'name': 'second', 'base': BASE_UNITS.TIME, 'prefixes': PREFIXES.LONG, 'value': 1, 'offset': 0},
    {'name': 'sec', 'base': BASE_UNITS.TIME, 'prefixes': PREFIXES.LONG, 'value': 1, 'offset': 0},
    {'name': 'minutes', 'base': BASE_UNITS.TIME, 'prefixes': PREFIXES.NONE, 'value': 60, 'offset': 0},
    {'name': 'minute', 'base': BASE_UNITS.TIME, 'prefixes': PREFIXES.NONE, 'value': 60, 'offset': 0},
    {'name': 'hours', 'base': BASE_UNITS.TIME, 'prefixes': PREFIXES.NONE, 'value': 3600, 'offset': 0},
    {'name': 'hour', 'base': BASE_UNITS.TIME, 'prefixes': PREFIXES.NONE, 'value': 3600, 'offset': 0},
    {'name': 'day', 'base': BASE_UNITS.TIME, 'prefixes': PREFIXES.NONE, 'value': 86400, 'offset': 0},
    {'name': 'days', 'base': BASE_UNITS.TIME, 'prefixes': PREFIXES.NONE, 'value': 86400, 'offset': 0},
  
    // Angles
    {'name': 'rad', 'base': BASE_UNITS.ANGLE, 'prefixes': PREFIXES.NONE, 'value': 1, 'offset': 0},
    {'name': 'deg', 'base': BASE_UNITS.ANGLE, 'prefixes': PREFIXES.NONE, 'value': 0.017453292519943295769236907684888, 'offset': 0},  // deg = rad / (2*pi) * 360 = rad / 0.017453292519943295769236907684888
    {'name': 'grad', 'base': BASE_UNITS.ANGLE, 'prefixes': PREFIXES.NONE, 'value': 0.015707963267948966192313216916399, 'offset': 0}, // grad = rad / (2*pi) * 400  = rad / 0.015707963267948966192313216916399
    {'name': 'cycle', 'base': BASE_UNITS.ANGLE, 'prefixes': PREFIXES.NONE, 'value': 6.2831853071795864769252867665793, 'offset': 0},  // cycle = rad / (2*pi) = rad / 6.2831853071795864769252867665793
  
    // Electric current
    {'name': 'A', 'base': BASE_UNITS.CURRENT, 'prefixes': PREFIXES.SHORT, 'value': 1, 'offset': 0},
    {'name': 'ampere', 'base': BASE_UNITS.CURRENT, 'prefixes': PREFIXES.LONG, 'value': 1, 'offset': 0},
  
    // Temperature
    // K(C) = °C + 273.15
    // K(F) = (°F + 459.67) / 1.8
    // K(R) = °R / 1.8
    {'name': 'K', 'base': BASE_UNITS.TEMPERATURE, 'prefixes': PREFIXES.NONE, 'value': 1, 'offset': 0},
    {'name': 'degC', 'base': BASE_UNITS.TEMPERATURE, 'prefixes': PREFIXES.NONE, 'value': 1, 'offset': 273.15},
    {'name': 'degF', 'base': BASE_UNITS.TEMPERATURE, 'prefixes': PREFIXES.NONE, 'value': 1/1.8, 'offset': 459.67},
    {'name': 'degR', 'base': BASE_UNITS.TEMPERATURE, 'prefixes': PREFIXES.NONE, 'value': 1/1.8, 'offset': 0},
    {'name': 'kelvin', 'base': BASE_UNITS.TEMPERATURE, 'prefixes': PREFIXES.NONE, 'value': 1, 'offset': 0},
    {'name': 'celsius', 'base': BASE_UNITS.TEMPERATURE, 'prefixes': PREFIXES.NONE, 'value': 1, 'offset': 273.15},
    {'name': 'fahrenheit', 'base': BASE_UNITS.TEMPERATURE, 'prefixes': PREFIXES.NONE, 'value': 1/1.8, 'offset': 459.67},
    {'name': 'rankine', 'base': BASE_UNITS.TEMPERATURE, 'prefixes': PREFIXES.NONE, 'value': 1/1.8, 'offset': 0},
  
    // amount of substance
    {'name': 'mol', 'base': BASE_UNITS.AMOUNT_OF_SUBSTANCE, 'prefixes': PREFIXES.NONE, 'value': 1, 'offset': 0},
    {'name': 'mole', 'base': BASE_UNITS.AMOUNT_OF_SUBSTANCE, 'prefixes': PREFIXES.NONE, 'value': 1, 'offset': 0},
  
    // luminous intensity
    {'name': 'cd', 'base': BASE_UNITS.LUMINOUS_INTENSITY, 'prefixes': PREFIXES.NONE, 'value': 1, 'offset': 0},
    {'name': 'candela', 'base': BASE_UNITS.LUMINOUS_INTENSITY, 'prefixes': PREFIXES.NONE, 'value': 1, 'offset': 0},
    // TODO: units STERADIAN
    //{'name': 'sr', 'base': BASE_UNITS.STERADIAN, 'prefixes': PREFIXES.NONE, 'value': 1, 'offset': 0},
    //{'name': 'steradian', 'base': BASE_UNITS.STERADIAN, 'prefixes': PREFIXES.NONE, 'value': 1, 'offset': 0},
  
    // Force
    {'name': 'N', 'base': BASE_UNITS.FORCE, 'prefixes': PREFIXES.SHORT, 'value': 1, 'offset': 0},
    {'name': 'newton', 'base': BASE_UNITS.FORCE, 'prefixes': PREFIXES.LONG, 'value': 1, 'offset': 0},
    {'name': 'lbf', 'base': BASE_UNITS.FORCE, 'prefixes': PREFIXES.NONE, 'value': 4.4482216152605, 'offset': 0},
    {'name': 'poundforce', 'base': BASE_UNITS.FORCE, 'prefixes': PREFIXES.NONE, 'value': 4.4482216152605, 'offset': 0},
  
    // Binary
    {'name': 'b', 'base': BASE_UNITS.BIT, 'prefixes': PREFIXES.BINARY_SHORT, 'value': 1, 'offset': 0},
    {'name': 'bits', 'base': BASE_UNITS.BIT, 'prefixes': PREFIXES.BINARY_LONG, 'value': 1, 'offset': 0},
    {'name': 'B', 'base': BASE_UNITS.BIT, 'prefixes': PREFIXES.BINARY_SHORT, 'value': 8, 'offset': 0},
    {'name': 'bytes', 'base': BASE_UNITS.BIT, 'prefixes': PREFIXES.BINARY_LONG, 'value': 8, 'offset': 0}
  ];
  
  Unit.PREFIXES = PREFIXES;
  Unit.BASE_UNITS = BASE_UNITS;
  Unit.UNITS = UNITS;
  
  
  // exports
  module.exports = Unit;
  
  // to trick my IDE which doesn't get it
  exports.isUnit = Unit.isUnit;
  exports.isPlainUnit = Unit.isPlainUnit;
  exports.parse = Unit.parse;
  
  },{"../util/index":213}],209:[function(require,module,exports){
  // utility methods for arrays and matrices
  
  var util = require('../util/index'),
  
      Matrix = require('./Matrix'),
  
      isArray = util.array.isArray,
      isString = util.string.isString;
  
  /**
   * Convert function arguments to an array. Arguments can have the following
   * signature:
   *     fn()
   *     fn(n)
   *     fn(m, n, p, ...)
   *     fn([m, n, p, ...])
   * @param {...Number | Array | Matrix} args
   * @returns {Array} array
   */
  exports.argsToArray = function argsToArray(args) {
    var array;
    if (args.length == 0) {
      // fn()
      array = [];
    }
    else if (args.length == 1) {
      // fn(n)
      // fn([m, n, p, ...])
      array = args[0];
      if (array instanceof Matrix) {
        array = array.valueOf();
      }
      if (!isArray(array)) {
        array = [array];
      }
    }
    else {
      // fn(m, n, p, ...)
      array = Array.prototype.slice.apply(args);
    }
    return array;
  };
  
  
  /**
   * Test whether a value is a collection: an Array or Matrix
   * @param {*} x
   * @returns {boolean} isCollection
   */
  exports.isCollection = function isCollection (x) {
    return (isArray(x) || (x instanceof Matrix));
  };
  
  /**
   * Execute the callback function element wise for each element in array and any
   * nested array
   * Returns an array with the results
   * @param {Array | Matrix} array
   * @param {function} callback   The callback is called with two parameters:
   *                              value1 and value2, which contain the current
   *                              element of both arrays.
   * @return {Array | Matrix} res
   */
  exports.deepMap = function deepMap(array, callback) {
    if (array && (typeof array.map === 'function')) {
      return array.map(function (x) {
        return deepMap(x, callback);
      });
    }
    else {
      return callback(array);
    }
  };
  
  /**
   * Execute the callback function element wise for each entry in two given arrays,
   * and for any nested array. Objects can also be scalar objects.
   * Returns an array with the results.
   * @param {Array | Matrix | Object} array1
   * @param {Array | Matrix | Object} array2
   * @param {function} callback   The callback is called with two parameters:
   *                              value1 and value2, which contain the current
   *                              element of both arrays.
   * @return {Array | Matrix} res
   */
  exports.deepMap2 = function deepMap2(array1, array2, callback) {
    var res, len, i;
  
    if (isArray(array1)) {
      if (isArray(array2)) {
        // callback(array, array)
        if (array1.length != array2.length) {
          throw new RangeError('Dimension mismatch ' +
              '(' +  array1.length + ' != ' + array2.length + ')');
        }
  
        res = [];
        len = array1.length;
        for (i = 0; i < len; i++) {
          res[i] = deepMap2(array1[i], array2[i], callback);
        }
      }
      else if (array2 instanceof Matrix) {
        // callback(array, matrix)
        res = deepMap2(array1, array2.valueOf(), callback);
        return new Matrix(res);
      }
      else {
        // callback(array, object)
        res = [];
        len = array1.length;
        for (i = 0; i < len; i++) {
          res[i] = deepMap2(array1[i], array2, callback);
        }
      }
    }
    else if (array1 instanceof Matrix) {
      if (array2 instanceof Matrix) {
        // callback(matrix, matrix)
        res = deepMap2(array1.valueOf(), array2.valueOf(), callback);
        return new Matrix(res);
      }
      else {
        // callback(matrix, array)
        // callback(matrix, object)
        res = deepMap2(array1.valueOf(), array2, callback);
        return new Matrix(res);
      }
    }
    else {
      if (isArray(array2)) {
        // callback(object, array)
        res = [];
        len = array2.length;
        for (i = 0; i < len; i++) {
          res[i] = deepMap2(array1, array2[i], callback);
        }
      }
      else if (array2 instanceof Matrix) {
        // callback(object, matrix)
        res = deepMap2(array1, array2.valueOf(), callback);
        return new Matrix(res);
      }
      else {
        // callback(object, object)
        res = callback(array1, array2);
      }
    }
  
    return res;
  };
  
  /**
   * Reduce a given matrix or array to a new matrix or
   * array with one less dimension, aplying the given
   * callback in the selected dimension.
   * @param {Array | Matrix} mat
   * @param {Number} dim
   * @param {function} callback
   * @return {Array | Matrix} res
   */
  exports.reduce = function reduce (mat, dim, callback) {
  	if (mat instanceof Matrix) {
  		return new Matrix(_reduce(mat.valueOf(), dim, callback));
  	}else {
  		return _reduce(mat, dim, callback);
  	}
  };
  
  /**
   * Recursively reduce a matrix
   * @param {Array} mat
   * @param {Number} dim
   * @param {Function} callback
   * @returns {Array} ret
   * @private
   */
  function _reduce(mat, dim, callback){
    var i, ret, val, tran;
  
  	if(dim<=0){
  		if( !isArray(mat[0]) ){
  			val = mat[0];
  			for(i=1; i<mat.length; i++){
  				val = callback(val, mat[i]);
  			}
  			return val;
  		}else{
  			tran = _switch(mat);
  			ret = [];
  			for(i=0; i<tran.length; i++){
  				ret[i] = _reduce(tran[i], dim-1, callback);
  			}
  			return ret
  		}
  	}else{
  		ret = [];
  		for(i=0; i<mat.length; i++){
  			ret[i] = _reduce(mat[i], dim-1, callback);
  		}
  		return ret;
  	}
  }
  
  /**
   * Transpose a matrix
   * @param {Array} mat
   * @returns {Array} ret
   * @private
   */
  function _switch(mat){
    var I = mat.length;
    var J = mat[0].length;
    var i, j;
    var ret = [];
    for( j=0; j<J; j++) {
      var tmp = [];
      for( i=0; i<I; i++) {
        tmp.push(mat[i][j]);
      }
      ret.push(tmp);
    }
    return ret;
  }
  
  /**
   * Recursively loop over all elements in a given multi dimensional array
   * and invoke the callback on each of the elements.
   * @param {Array | Matrix} array
   * @param {function} callback     The callback method is invoked with one
   *                                parameter: the current element in the array
   */
  exports.deepForEach = function deepForEach (array, callback) {
    if (array instanceof Matrix) {
      array = array.valueOf();
    }
  
    for (var i = 0, ii = array.length; i < ii; i++) {
      var value = array[i];
  
      if (isArray(value)) {
        deepForEach(value, callback);
      }
      else {
        callback(value);
      }
    }
  };
  
  },{"../util/index":213,"./Matrix":206}],210:[function(require,module,exports){
  module.exports = function (math) {
    var types = require('./../util/types');
  
    // export the error constructors to namespace math.error.*
    var error = {};
    math.error = error;
  
    /**
     * Create a TypeError with message:
     *      'Function <fn> does not support a parameter of type <type>';
     * @param {String} name   Function name
     * @param {*} [value1]
     * @param {*...} [value_n]
     * @extends TypeError
     */
    error.UnsupportedTypeError = function UnsupportedTypeError(name, value1, value_n) {
      if (arguments.length == 2) {
        var type1 = math['typeof'](value1);
        this.message = 'Function ' + name + '(' + type1 + ') not supported';
      }
      else if (arguments.length > 2) {
        var values = Array.prototype.splice.call(arguments, 1);
        var types = values.map(function (value) {
          return math['typeof'](value);
        });
        this.message = 'Function ' + name + '(' + types.join(', ') + ') not supported';
      }
      else {
        this.message = 'Unsupported type of argument in function ' + name;
      }
    };
  
    error.UnsupportedTypeError.prototype = new TypeError();
    error.UnsupportedTypeError.prototype.name = 'UnsupportedTypeError';
  
    /**
     * Create a syntax error with the message:
     *     'Wrong number of arguments in function <fn> (<count> provided, <min>-<max> expected)'
     * @param {String} name   Function name
     * @param {Number} count  Actual argument count
     * @param {Number} min    Minimum required argument count
     * @param {Number} [max]  Maximum required argument count
     * @extends SyntaxError
     */
    error.ArgumentsError = function ArgumentsError(name, count, min, max) {
      this.message = 'Wrong number of arguments in function ' + name +
          ' (' + count + ' provided, ' +
          min + ((max != undefined) ? ('-' + max) : '') + ' expected)';
    };
  
    error.ArgumentsError.prototype = new SyntaxError();
    error.ArgumentsError.prototype.name = 'ArgumentError';
  };
  },{"./../util/types":217}],211:[function(require,module,exports){
  var number = require('./number'),
      string = require('./string'),
      object = require('./object'),
      types = require('./types'),
      isArray = Array.isArray;
  
  /**
   * Calculate the size of a multi dimensional array.
   * @param {Array} x
   * @Return {Number[]} size
   * @private
   */
  function _size(x) {
    var size = [];
  
    while (isArray(x)) {
      size.push(x.length);
      x = x[0];
    }
  
    return size;
  }
  
  /**
   * Calculate the size of a multi dimensional array.
   * All elements in the array are checked for matching dimensions using the
   * method validate
   * @param {Array} x
   * @Return {Number[]} size
   * @throws RangeError
   */
  exports.size = function size (x) {
    // calculate the size
    var s = _size(x);
  
    // verify the size
    exports.validate(x, s);
    // TODO: don't validate here? only in a Matrix constructor?
  
    return s;
  };
  
  /**
   * Recursively validate whether each element in a multi dimensional array
   * has a size corresponding to the provided size array.
   * @param {Array} array    Array to be validated
   * @param {Number[]} size  Array with the size of each dimension
   * @param {Number} dim   Current dimension
   * @throws RangeError
   * @private
   */
  function _validate(array, size, dim) {
    var i;
    var len = array.length;
  
    if (len != size[dim]) {
      throw new RangeError('Dimension mismatch (' + len + ' != ' + size[dim] + ')');
    }
  
    if (dim < size.length - 1) {
      // recursively validate each child array
      var dimNext = dim + 1;
      for (i = 0; i < len; i++) {
        var child = array[i];
        if (!isArray(child)) {
          throw new RangeError('Dimension mismatch ' +
              '(' + (size.length - 1) + ' < ' + size.length + ')');
        }
        _validate(array[i], size, dimNext);
      }
    }
    else {
      // last dimension. none of the childs may be an array
      for (i = 0; i < len; i++) {
        if (isArray(array[i])) {
          throw new RangeError('Dimension mismatch ' +
              '(' + (size.length + 1) + ' > ' + size.length + ')');
        }
      }
    }
  }
  
  /**
   * Validate whether each element in a multi dimensional array has
   * a size corresponding to the provided size array.
   * @param {Array} array    Array to be validated
   * @param {Number[]} size  Array with the size of each dimension
   * @throws RangeError
   */
  exports.validate = function validate(array, size) {
    var isScalar = (size.length == 0);
    if (isScalar) {
      // scalar
      if (isArray(array)) {
        throw new RangeError('Dimension mismatch (' + array.length + ' != 0)');
      }
    }
    else {
      // array
      _validate(array, size, 0);
    }
  };
  
  /**
   * Test whether index is an integer number with index >= 0 and index < length
   * @param {*} index         Zero-based index
   * @param {Number} [length] Length of the array
   */
  exports.validateIndex = function validateIndex (index, length) {
    if (!number.isNumber(index) || !number.isInteger(index)) {
      throw new TypeError('Index must be an integer (value: ' + index + ')');
    }
    if (index < 0) {
      throw new RangeError('Index out of range (' + index + ' < 0)');
    }
    if (length !== undefined && index >= length) {
      throw new RangeError('Index out of range (' + index + ' > ' + (length - 1) +  ')');
    }
  };
  
  /**
   * Resize a multi dimensional array. The resized array is returned.
   * @param {Array} array         Array to be resized
   * @param {Array.<Number>} size Array with the size of each dimension
   * @param {*} [defaultValue]    Value to be filled in in new entries,
   *                              undefined by default
   * @return {Array} array         The resized array
   */
  exports.resize = function resize(array, size, defaultValue) {
    // TODO: add support for scalars, having size=[] ?
  
    // check the type of the arguments
    if (!isArray(array) || !isArray(size)) {
      throw new TypeError('Array expected');
    }
    if (size.length === 0) {
      throw new Error('Resizing to scalar is not supported');
    }
  
    // check whether size contains positive integers
    size.forEach(function (value) {
      if (!number.isNumber(value) || !number.isInteger(value) || value < 0) {
        throw new TypeError('Invalid size, must contain positive integers ' +
            '(size: ' + string.format(size) + ')');
      }
    });
  
    // count the current number of dimensions
    var dims = 1;
    var elem = array[0];
    while (isArray(elem)) {
      dims++;
      elem = elem[0];
    }
  
    // adjust the number of dimensions when needed
    while (dims < size.length) { // add dimensions
      array = [array];
      dims++;
    }
    while (dims > size.length) { // remove dimensions
      array = array[0];
      dims--;
    }
  
    // recursively resize the array
    _resize(array, size, 0, defaultValue);
  
    return array;
  };
  
  /**
   * Recursively resize a multi dimensional array
   * @param {Array} array         Array to be resized
   * @param {Number[]} size       Array with the size of each dimension
   * @param {Number} dim          Current dimension
   * @param {*} [defaultValue]    Value to be filled in in new entries,
   *                              undefined by default.
   * @private
   */
  function _resize (array, size, dim, defaultValue) {
    if (!isArray(array)) {
      throw Error('Array expected');
    }
  
    var i, elem,
        oldLen = array.length,
        newLen = size[dim],
        minLen = Math.min(oldLen, newLen);
  
    // apply new length
    array.length = newLen;
  
    if (dim < size.length - 1) {
      // non-last dimension
      var dimNext = dim + 1;
  
      // resize existing child arrays
      for (i = 0; i < minLen; i++) {
        // resize child array
        elem = array[i];
        _resize(elem, size, dimNext, defaultValue);
      }
  
      // create new child arrays
      for (i = minLen; i < newLen; i++) {
        // get child array
        elem = [];
        array[i] = elem;
  
        // resize new child array
        _resize(elem, size, dimNext, defaultValue);
      }
    }
    else {
      // last dimension
      if(defaultValue !== undefined) {
        // fill new elements with the default value
        for (i = oldLen; i < newLen; i++) {
          array[i] = object.clone(defaultValue);
        }
      }
    }
  }
  
  /**
   * Squeeze a multi dimensional array
   * @param {Array} array
   * @return {Array} array
   * @private
   */
  exports.squeeze = function squeeze(array) {
    while(isArray(array) && array.length === 1) {
      array = array[0];
    }
  
    return array;
  };
  
  /**
   * Unsqueeze a multi dimensional array: add dimensions when missing
   * @param {Array} array
   * @param {Number} dims   Number of desired dimensions
   * @return {Array} array
   * @private
   */
  exports.unsqueeze = function unsqueeze(array, dims) {
    var size = exports.size(array);
  
    for (var i = 0, ii = (dims - size.length); i < ii; i++) {
      array = [array];
    }
  
    return array;
  };
  
  /**
   * Test whether an object is an array
   * @param {*} value
   * @return {Boolean} isArray
   */
  exports.isArray = isArray;
  },{"./number":214,"./object":215,"./string":216,"./types":217}],212:[function(require,module,exports){
  /**
   * Test whether value is a Boolean
   * @param {*} value
   * @return {Boolean} isBoolean
   */
  exports.isBoolean = function isBoolean(value) {
    return (value instanceof Boolean) || (typeof value == 'boolean');
  };
  
  },{}],213:[function(require,module,exports){
  exports.array = require('./array');
  exports['boolean'] = require('./boolean');
  exports.number = require('./number');
  exports.object = require('./object');
  exports.string = require('./string');
  exports.types = require('./types');
  
  },{"./array":211,"./boolean":212,"./number":214,"./object":215,"./string":216,"./types":217}],214:[function(require,module,exports){
  var BigNumber = require('bignumber.js');
  
  /**
   * Test whether value is a Number
   * @param {*} value
   * @return {Boolean} isNumber
   */
  exports.isNumber = function isNumber(value) {
    return (value instanceof Number) || (typeof value == 'number');
  };
  
  /**
   * Check if a number is integer
   * @param {Number | Boolean} value
   * @return {Boolean} isInteger
   */
  exports.isInteger = function isInteger(value) {
    return (value == Math.round(value));
    // Note: we use ==, not ===, as we can have Booleans as well
  };
  
  /**
   * Calculate the sign of a number
   * @param {Number} x
   * @returns {*}
   */
  exports.sign = function sign (x) {
    if (x > 0) {
      return 1;
    }
    else if (x < 0) {
      return -1;
    }
    else {
      return 0;
    }
  };
  
  /**
   * Convert a number to a formatted string representation.
   *
   * Syntax:
   *
   *    format(value)
   *    format(value, options)
   *    format(value, precision)
   *    format(value, fn)
   *
   * Where:
   *
   *    {Number} value   The value to be formatted
   *    {Object} options An object with formatting options. Available options:
   *                     {String} notation
   *                         Number notation. Choose from:
   *                         'fixed'          Always use regular number notation.
   *                                          For example '123.40' and '14000000'
   *                         'exponential'    Always use exponential notation.
   *                                          For example '1.234e+2' and '1.4e+7'
   *                         'auto' (default) Regular number notation for numbers
   *                                          having an absolute value between
   *                                          `lower` and `upper` bounds, and uses
   *                                          exponential notation elsewhere.
   *                                          Lower bound is included, upper bound
   *                                          is excluded.
   *                                          For example '123.4' and '1.4e7'.
   *                     {Number} precision   A number between 0 and 16 to round
   *                                          the digits of the number.
   *                                          In case of notations 'exponential' and
   *                                          'auto', `precision` defines the total
   *                                          number of significant digits returned
   *                                          and is undefined by default.
   *                                          In case of notation 'fixed',
   *                                          `precision` defines the number of
   *                                          significant digits after the decimal
   *                                          point, and is 0 by default.
   *                     {Object} exponential An object containing two parameters,
   *                                          {Number} lower and {Number} upper,
   *                                          used by notation 'auto' to determine
   *                                          when to return exponential notation.
   *                                          Default values are `lower=1e-3` and
   *                                          `upper=1e5`.
   *                                          Only applicable for notation `auto`.
   *    {Function} fn    A custom formatting function. Can be used to override the
   *                     built-in notations. Function `fn` is called with `value` as
   *                     parameter and must return a string. Is useful for example to
   *                     format all values inside a matrix in a particular way.
   *
   * Examples:
   *
   *    format(6.4);                                        // '6.4'
   *    format(1240000);                                    // '1.24e6'
   *    format(1/3);                                        // '0.3333333333333333'
   *    format(1/3, 3);                                     // '0.333'
   *    format(21385, 2);                                   // '21000'
   *    format(12.071, {notation: 'fixed'});                // '12'
   *    format(2.3,    {notation: 'fixed', precision: 2});  // '2.30'
   *    format(52.8,   {notation: 'exponential'});          // '5.28e+1'
   *
   * @param {Number | BigNumber} value
   * @param {Object | Function | Number} [options]
   * @return {String} str The formatted value
   */
  exports.format = function format(value, options) {
    if (typeof options === 'function') {
      // handle format(value, fn)
      return options(value);
    }
  
    // handle special cases
    if (value === Infinity) {
      return 'Infinity';
    }
    else if (value === -Infinity) {
      return '-Infinity';
    }
    else if (isNaN(value)) {
      return 'NaN';
    }
  
    // default values for options
    var notation = 'auto';
    var precision = undefined;
  
    if (options !== undefined) {
      // determine notation from options
      if (options.notation) {
        notation = options.notation;
      }
  
      // determine precision from options
      if (options) {
        if (exports.isNumber(options)) {
          precision = options;
        }
        else if (options.precision) {
          precision = options.precision;
        }
      }
    }
  
    // handle the various notations
    switch (notation) {
      case 'fixed':
        return exports.toFixed(value, precision);
  
      // TODO: notation 'scientific' is deprecated since version 0.16.0, remove this some day
      case 'scientific':
        throw new Error('Format notation "scientific" is deprecated. Use "exponential" instead.');
  
      case 'exponential':
        return exports.toExponential(value, precision);
  
      case 'auto':
        // determine lower and upper bound for exponential notation.
          // TODO: implement support for upper and lower to be BigNumbers themselves
        var lower = 1e-3;
        var upper = 1e5;
        if (options && options.exponential) {
          if (options.exponential.lower !== undefined) {
            lower = options.exponential.lower;
          }
          if (options.exponential.upper !== undefined) {
            upper = options.exponential.upper;
          }
        }
        else if (options && options.scientific) {
          // TODO: 'options.scientific' is deprecated since version 0.16.0, remove this some day
          throw new Error('options.scientific is deprecated, use options.exponential instead.');
        }
  
        // adjust BigNumber configuration
        var isBigNumber = value instanceof BigNumber;
        if (isBigNumber) {
          var oldScientific = BigNumber.config().EXPONENTIAL_AT;
          BigNumber.config({
            EXPONENTIAL_AT: [
              Math.round(Math.log(lower) / Math.LN10),
              Math.round(Math.log(upper) / Math.LN10)
            ]
          });
        }
  
        // handle special case zero
        if (_isZero(value)) {
          return '0';
        }
  
        // determine whether or not to output exponential notation
        var str;
        if (_isBetween(value, lower, upper)) {
          // normal number notation
          if (isBigNumber) {
            str = new BigNumber(value.toPrecision(precision)).toString();
          }
          else { // Number
            // Note: IE7 does not allow value.toPrecision(undefined)
            var valueStr = precision ?
                value.toPrecision(Math.min(precision, 21)) :
                value.toPrecision();
            str = parseFloat(valueStr) + '';
          }
        }
        else {
          // exponential notation
          str = exports.toExponential(value, precision);
        }
  
        // restore BigNumber configuration
        if (isBigNumber) {
          BigNumber.config({EXPONENTIAL_AT: oldScientific});
        }
  
        // remove trailing zeros after the decimal point
        return str.replace(/((\.\d*?)(0+))($|e)/, function () {
          var digits = arguments[2];
          var e = arguments[4];
          return (digits !== '.') ? digits + e : e;
        });
  
      default:
        throw new Error('Unknown notation "' + notation + '". ' +
            'Choose "auto", "exponential", or "fixed".');
    }
  };
  
  /**
   * Test whether a value is zero
   * @param {Number | BigNumber} value
   * @return {boolean} isZero
   * @private
   */
  function _isZero (value) {
    return (value instanceof BigNumber) ? value.isZero() : (value === 0);
  }
  
  /**
   * Test whether a value is inside a range:
   *
   *   lower >= value < upper
   *
   * @param {Number | BigNumber} value
   * @param {Number} lower  Included lower bound
   * @param {Number} upper  Excluded upper bound
   * @return {boolean} isBetween
   * @private
   */
  function _isBetween(value, lower, upper) {
    var abs;
    if (value instanceof BigNumber) {
      abs = value.abs();
      return (abs.gte(lower) && abs.lt(upper));
    }
    else {
      abs = Math.abs(value);
      return (abs >= lower && abs < upper);
    }
  }
  
  /**
   * Format a number in exponential notation. Like '1.23e+5', '2.3e+0', '3.500e-3'
   * @param {Number | BigNumber} value
   * @param {Number} [precision]  Number of digits in formatted output.
   *                              If not provided, the maximum available digits
   *                              is used.
   * @returns {string} str
   */
  exports.toExponential = function toExponential (value, precision) {
    if (precision !== undefined) {
      if (value instanceof BigNumber) {
        return value.toExponential(precision - 1);
      }
      else { // Number
        return value.toExponential(Math.min(precision - 1, 20));
      }
    }
    else {
      return value.toExponential();
    }
  };
  
  /**
   * Format a number with fixed notation.
   * @param {Number | BigNumber} value
   * @param {Number} [precision=0]        Optional number of decimals after the
   *                                      decimal point. Zero by default.
   */
  exports.toFixed = function toFixed (value, precision) {
    if (value instanceof BigNumber) {
      return value.toFixed(precision || 0);
      // Note: the (precision || 0) is needed as the toFixed of BigNumber has an
      // undefined default precision instead of 0.
    }
    else { // Number
      return value.toFixed(Math.min(precision, 20));
    }
  };
  
  /**
   * Count the number of significant digits of a number.
   *
   * For example:
   *   2.34 returns 3
   *   0.0034 returns 2
   *   120.5e+3 returns 4
   *
   * @param {Number} value
   * @return {Number} digits   Number of significant digits
   */
  exports.digits = function digits (value) {
    return value
        .toExponential()
        .replace(/e[\+\-0-9]*$/, '')  // remove exponential notation
        .replace( /^0\.0*|\./, '')    // remove decimal point and leading zeros
        .length
  };
  
  /**
   * Convert a Number in to a BigNumber. If the number has 15 or mor significant
   * digits, the Number cannot be converted to BigNumber and will return the
   * original number.
   * @param {Number} number
   * @return {BigNumber | Number} bignumber
   */
  exports.toBigNumber = function toBigNumber (number) {
    if (exports.digits(number) > 15) {
      return number;
    }
    else {
      return new BigNumber(number);
    }
  };
  
  /**
   * Convert a BigNumber into a Number. If the number is out of range, it will
   * get the value Infinity or 0.
   * @param {BigNumber} bignumber
   * @return {Number} number
   */
  exports.toNumber = function toNumber (bignumber) {
    return parseFloat(bignumber.valueOf());
  };
  
  },{"bignumber.js":218}],215:[function(require,module,exports){
  /**
   * Clone an object
   *
   *     clone(x)
   *
   * Can clone any primitive type, array, and object.
   * If x has a function clone, this function will be invoked to clone the object.
   *
   * @param {*} x
   * @return {*} clone
   */
  exports.clone = function clone(x) {
    var type = typeof x;
  
    // immutable primitive types
    if (type === 'number' || type === 'string' || type === 'boolean' ||
        x === null || x === undefined) {
      return x;
    }
  
    // use clone function of the object when available
    if (typeof x.clone === 'function') {
      return x.clone();
    }
  
    // array
    if (Array.isArray(x)) {
      return x.map(function (value) {
        return clone(value);
      });
    }
  
    // object
    if (x instanceof Object) {
      var m = {};
      for (var key in x) {
        if (x.hasOwnProperty(key)) {
          m[key] = clone(x[key]);
        }
      }
      return x;
    }
  
    // this should never happen
    throw new TypeError('Cannot clone ' + x);
  };
  
  /**
   * Extend object a with the properties of object b
   * @param {Object} a
   * @param {Object} b
   * @return {Object} a
   */
  exports.extend = function extend (a, b) {
    for (var prop in b) {
      if (b.hasOwnProperty(prop)) {
        a[prop] = b[prop];
      }
    }
    return a;
  };
  
  /**
   * Deep extend an object a with the properties of object b
   * @param {Object} a
   * @param {Object} b
   * @returns {Object}
   */
  exports.deepExtend = function deepExtend (a, b) {
    for (var prop in b) {
      if (b.hasOwnProperty(prop)) {
        if (b[prop] && b[prop].constructor === Object) {
          if (a[prop] === undefined) {
            a[prop] = {};
          }
          if (a[prop].constructor === Object) {
            deepExtend(a[prop], b[prop]);
          }
          else {
            a[prop] = b[prop];
          }
        } else {
          a[prop] = b[prop];
        }
      }
    }
    return a;
  };
  
  /**
   * Deep test equality of all fields in two pairs of arrays or objects.
   * @param {Array | Object} a
   * @param {Array | Object} b
   * @returns {boolean}
   */
  exports.deepEqual = function deepEqual (a, b) {
    var prop, i, len;
    if (Array.isArray(a)) {
      if (!Array.isArray(b)) {
        return false;
      }
  
      if (a.length != b.length) {
        return false;
      }
  
      for (i = 0, len = a.length; i < len; i++) {
        if (!exports.deepEqual(a[i], b[i])) {
          return false;
        }
      }
      return true;
    }
    else if (a instanceof Object) {
      if (Array.isArray(b) || !(b instanceof Object)) {
        return false;
      }
  
      for (prop in a) {
        if (a.hasOwnProperty(prop)) {
          if (!exports.deepEqual(a[prop], b[prop])) {
            return false;
          }
        }
      }
      for (prop in b) {
        if (b.hasOwnProperty(prop)) {
          if (!exports.deepEqual(a[prop], b[prop])) {
            return false;
          }
        }
      }
      return true;
    }
    else {
      return (a == b);
    }
  };
  
  },{}],216:[function(require,module,exports){
  var number = require('./number'),
      BigNumber = require('bignumber.js');
  
  /**
   * Test whether value is a String
   * @param {*} value
   * @return {Boolean} isString
   */
  exports.isString = function isString(value) {
    return (value instanceof String) || (typeof value == 'string');
  };
  
  /**
   * Check if a text ends with a certain string.
   * @param {String} text
   * @param {String} search
   */
  exports.endsWith = function endsWith(text, search) {
    var start = text.length - search.length;
    var end = text.length;
    return (text.substring(start, end) === search);
  };
  
  /**
   * Format a value of any type into a string.
   *
   * Usage:
   *     math.format(value)
   *     math.format(value, precision)
   *
   * If value is a function, the returned string is 'function' unless the function
   * has a property `description`, in that case this properties value is returned.
   *
   * Example usage:
   *     math.format(2/7);                // '0.2857142857142857'
   *     math.format(math.pi, 3);         // '3.14'
   *     math.format(new Complex(2, 3));  // '2 + 3i'
   *     math.format('hello');            // '"hello"'
   *
   * @param {*} value             Value to be stringified
   * @param {Object | Number | Function} [options]  Formatting options. See
   *                                                lib/util/number:format for a
   *                                                description of the available
   *                                                options.
   * @return {String} str
   */
  exports.format = function format(value, options) {
    if (number.isNumber(value) || value instanceof BigNumber) {
      return number.format(value, options);
    }
  
    if (Array.isArray(value)) {
      return formatArray(value, options);
    }
  
    if (exports.isString(value)) {
      return '"' + value + '"';
    }
  
    if (typeof value === 'function') {
      return value.syntax ? value.syntax + '' : 'function';
    }
  
    if (value instanceof Object) {
      if (typeof value.format === 'function') {
        return value.format(options);
      }
      else {
        return value.toString();
      }
    }
  
    return String(value);
  };
  
  /**
   * Recursively format an n-dimensional matrix
   * Example output: "[[1, 2], [3, 4]]"
   * @param {Array} array
   * @param {Object | Number | Function} [options]  Formatting options. See
   *                                                lib/util/number:format for a
   *                                                description of the available
   *                                                options.
   * @returns {String} str
   */
  function formatArray (array, options) {
    if (Array.isArray(array)) {
      var str = '[';
      var len = array.length;
      for (var i = 0; i < len; i++) {
        if (i != 0) {
          str += ', ';
        }
        str += formatArray(array[i], options);
      }
      str += ']';
      return str;
    }
    else {
      return exports.format(array, options);
    }
  }
  
  },{"./number":214,"bignumber.js":218}],217:[function(require,module,exports){
  /**
   * Determine the type of a variable
   *
   *     typeof(x)
   *
   * @param {*} x
   * @return {String} type  Lower case type, for example 'number', 'string',
   *                        'array', 'date'.
   */
  exports.type = function type (x) {
    var type = typeof x;
  
    if (type === 'object') {
      if (x === null) {
        return 'null';
      }
      if (x instanceof Boolean) {
        return 'boolean';
      }
      if (x instanceof Number) {
        return 'number';
      }
      if (x instanceof String) {
        return 'string';
      }
      if (Array.isArray(x)) {
        return 'array';
      }
      if (x instanceof Date) {
        return 'date';
      }
    }
  
    return type;
  };
  
  },{}],218:[function(require,module,exports){
  /* bignumber.js v1.3.0 https://github.com/MikeMcl/bignumber.js/LICENCE */
  
  /*jslint ass: true, bitwise: true, eqeq: true, plusplus: true, sub: true, white: true, maxerr: 500 */
  /*global module, define */
  
  ;(function ( global ) {
      'use strict';
  
      /*
        bignumber.js v1.3.0
        A JavaScript library for arbitrary-precision arithmetic.
        https://github.com/MikeMcl/bignumber.js
        Copyright (c) 2012 Michael Mclaughlin <M8ch88l@gmail.com>
        MIT Expat Licence
      */
  
      /*********************************** DEFAULTS ************************************/
  
      /*
       * The default values below must be integers within the stated ranges (inclusive).
       * Most of these values can be changed during run-time using BigNumber.config().
       */
  
      /*
       * The limit on the value of DECIMAL_PLACES, TO_EXP_NEG, TO_EXP_POS, MIN_EXP,
       * MAX_EXP, and the argument to toFixed, toPrecision and toExponential, beyond
       * which an exception is thrown (if ERRORS is true).
       */
      var MAX = 1E9,                                   // 0 to 1e+9
  
          // Limit of magnitude of exponent argument to toPower.
          MAX_POWER = 1E6,                             // 1 to 1e+6
  
          // The maximum number of decimal places for operations involving division.
          DECIMAL_PLACES = 20,                         // 0 to MAX
  
          /*
           * The rounding mode used when rounding to the above decimal places, and when
           * using toFixed, toPrecision and toExponential, and round (default value).
           * UP         0 Away from zero.
           * DOWN       1 Towards zero.
           * CEIL       2 Towards +Infinity.
           * FLOOR      3 Towards -Infinity.
           * HALF_UP    4 Towards nearest neighbour. If equidistant, up.
           * HALF_DOWN  5 Towards nearest neighbour. If equidistant, down.
           * HALF_EVEN  6 Towards nearest neighbour. If equidistant, towards even neighbour.
           * HALF_CEIL  7 Towards nearest neighbour. If equidistant, towards +Infinity.
           * HALF_FLOOR 8 Towards nearest neighbour. If equidistant, towards -Infinity.
           */
          ROUNDING_MODE = 4,                           // 0 to 8
  
          // EXPONENTIAL_AT : [TO_EXP_NEG , TO_EXP_POS]
  
          // The exponent value at and beneath which toString returns exponential notation.
          // Number type: -7
          TO_EXP_NEG = -7,                             // 0 to -MAX
  
          // The exponent value at and above which toString returns exponential notation.
          // Number type: 21
          TO_EXP_POS = 21,                             // 0 to MAX
  
          // RANGE : [MIN_EXP, MAX_EXP]
  
          // The minimum exponent value, beneath which underflow to zero occurs.
          // Number type: -324  (5e-324)
          MIN_EXP = -MAX,                              // -1 to -MAX
  
          // The maximum exponent value, above which overflow to Infinity occurs.
          // Number type:  308  (1.7976931348623157e+308)
          MAX_EXP = MAX,                               // 1 to MAX
  
          // Whether BigNumber Errors are ever thrown.
          // CHANGE parseInt to parseFloat if changing ERRORS to false.
          ERRORS = true,                               // true or false
          parse = parseInt,                            // parseInt or parseFloat
  
      /***********************************************************************************/
  
          P = BigNumber.prototype,
          DIGITS = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_',
          outOfRange,
          id = 0,
          isValid = /^-?(\d+(\.\d*)?|\.\d+)(e[+-]?\d+)?$/i,
          trim = String.prototype.trim || function () {return this.replace(/^\s+|\s+$/g, '')},
          ONE = BigNumber(1);
  
  
      // CONSTRUCTOR
  
  
      /*
       * The exported function.
       * Create and return a new instance of a BigNumber object.
       *
       * n {number|string|BigNumber} A numeric value.
       * [b] {number} The base of n. Integer, 2 to 64 inclusive.
       */
      function BigNumber( n, b ) {
          var e, i, isNum, digits, valid, orig,
              x = this;
  
          // Enable constructor usage without new.
          if ( !(x instanceof BigNumber) ) {
              return new BigNumber( n, b )
          }
  
          // Duplicate.
          if ( n instanceof BigNumber ) {
              id = 0;
  
              // e is undefined.
              if ( b !== e ) {
                  n += ''
              } else {
                  x['s'] = n['s'];
                  x['e'] = n['e'];
                  x['c'] = ( n = n['c'] ) ? n.slice() : n;
                  return;
              }
          }
  
          // If number, check if minus zero.
          if ( typeof n != 'string' ) {
              n = ( isNum = typeof n == 'number' ||
                  Object.prototype.toString.call(n) == '[object Number]' ) &&
                      n === 0 && 1 / n < 0 ? '-0' : n + '';
          }
  
          orig = n;
  
          if ( b === e && isValid.test(n) ) {
  
              // Determine sign.
              x['s'] = n.charAt(0) == '-' ? ( n = n.slice(1), -1 ) : 1;
  
          // Either n is not a valid BigNumber or a base has been specified.
          } else {
  
              // Enable exponential notation to be used with base 10 argument.
              // Ensure return value is rounded to DECIMAL_PLACES as with other bases.
              if ( b == 10 ) {
  
                  return setMode( n, DECIMAL_PLACES, ROUNDING_MODE );
              }
  
              n = trim.call(n).replace( /^\+(?!-)/, '' );
  
              x['s'] = n.charAt(0) == '-' ? ( n = n.replace( /^-(?!-)/, '' ), -1 ) : 1;
  
              if ( b != null ) {
  
                  if ( ( b == (b | 0) || !ERRORS ) &&
                    !( outOfRange = !( b >= 2 && b < 65 ) ) ) {
  
                      digits = '[' + DIGITS.slice( 0, b = b | 0 ) + ']+';
  
                      // Before non-decimal number validity test and base conversion
                      // remove the `.` from e.g. '1.', and replace e.g. '.1' with '0.1'.
                      n = n.replace( /\.$/, '' ).replace( /^\./, '0.' );
  
                      // Any number in exponential form will fail due to the e+/-.
                      if ( valid = new RegExp(
                        '^' + digits + '(?:\\.' + digits + ')?$', b < 37 ? 'i' : '' ).test(n) ) {
  
                          if ( isNum ) {
  
                              if ( n.replace( /^0\.0*|\./, '' ).length > 15 ) {
  
                                  // 'new BigNumber() number type has more than 15 significant digits: {n}'
                                  ifExceptionsThrow( orig, 0 );
                              }
  
                              // Prevent later check for length on converted number.
                              isNum = !isNum;
                          }
                          n = convert( n, 10, b, x['s'] );
  
                      } else if ( n != 'Infinity' && n != 'NaN' ) {
  
                          // 'new BigNumber() not a base {b} number: {n}'
                          ifExceptionsThrow( orig, 1, b );
                          n = 'NaN';
                      }
                  } else {
  
                      // 'new BigNumber() base not an integer: {b}'
                      // 'new BigNumber() base out of range: {b}'
                      ifExceptionsThrow( b, 2 );
  
                      // Ignore base.
                      valid = isValid.test(n);
                  }
              } else {
                  valid = isValid.test(n);
              }
  
              if ( !valid ) {
  
                  // Infinity/NaN
                  x['c'] = x['e'] = null;
  
                  // NaN
                  if ( n != 'Infinity' ) {
  
                      // No exception on NaN.
                      if ( n != 'NaN' ) {
  
                          // 'new BigNumber() not a number: {n}'
                          ifExceptionsThrow( orig, 3 );
                      }
                      x['s'] = null;
                  }
                  id = 0;
  
                  return;
              }
          }
  
          // Decimal point?
          if ( ( e = n.indexOf('.') ) > -1 ) {
              n = n.replace( '.', '' );
          }
  
          // Exponential form?
          if ( ( i = n.search( /e/i ) ) > 0 ) {
  
              // Determine exponent.
              if ( e < 0 ) {
                  e = i;
              }
              e += +n.slice( i + 1 );
              n = n.substring( 0, i );
  
          } else if ( e < 0 ) {
  
              // Integer.
              e = n.length;
          }
  
          // Determine leading zeros.
          for ( i = 0; n.charAt(i) == '0'; i++ ) {
          }
  
          b = n.length;
  
          // Disallow numbers with over 15 significant digits if number type.
          if ( isNum && b > 15 && n.slice(i).length > 15 ) {
  
              // 'new BigNumber() number type has more than 15 significant digits: {n}'
              ifExceptionsThrow( orig, 0 );
          }
          id = 0;
  
          // Overflow?
          if ( ( e -= i + 1 ) > MAX_EXP ) {
  
              // Infinity.
              x['c'] = x['e'] = null;
  
          // Zero or underflow?
          } else if ( i == b || e < MIN_EXP ) {
  
              // Zero.
              x['c'] = [ x['e'] = 0 ];
          } else {
  
              // Determine trailing zeros.
              for ( ; n.charAt(--b) == '0'; ) {
              }
  
              x['e'] = e;
              x['c'] = [];
  
              // Convert string to array of digits (without leading and trailing zeros).
              for ( e = 0; i <= b; x['c'][e++] = +n.charAt(i++) ) {
              }
          }
      }
  
  
      // CONSTRUCTOR PROPERTIES/METHODS
  
  
      BigNumber['ROUND_UP'] = 0;
      BigNumber['ROUND_DOWN'] = 1;
      BigNumber['ROUND_CEIL'] = 2;
      BigNumber['ROUND_FLOOR'] = 3;
      BigNumber['ROUND_HALF_UP'] = 4;
      BigNumber['ROUND_HALF_DOWN'] = 5;
      BigNumber['ROUND_HALF_EVEN'] = 6;
      BigNumber['ROUND_HALF_CEIL'] = 7;
      BigNumber['ROUND_HALF_FLOOR'] = 8;
  
  
      /*
       * Configure infrequently-changing library-wide settings.
       *
       * Accept an object or an argument list, with one or many of the following
       * properties or parameters respectively:
       * [ DECIMAL_PLACES [, ROUNDING_MODE [, EXPONENTIAL_AT [, RANGE [, ERRORS ]]]]]
       *
       * E.g.
       * BigNumber.config(20, 4) is equivalent to
       * BigNumber.config({ DECIMAL_PLACES : 20, ROUNDING_MODE : 4 })
       * Ignore properties/parameters set to null or undefined.
       *
       * Return an object with the properties current values.
       */
      BigNumber['config'] = function () {
          var v, p,
              i = 0,
              r = {},
              a = arguments,
              o = a[0],
              c = 'config',
              inRange = function ( n, lo, hi ) {
                return !( ( outOfRange = n < lo || n > hi ) ||
                  parse(n) != n && n !== 0 );
              },
              has = o && typeof o == 'object'
                ? function () {if ( o.hasOwnProperty(p) ) return ( v = o[p] ) != null}
                : function () {if ( a.length > i ) return ( v = a[i++] ) != null};
  
          // [DECIMAL_PLACES] {number} Integer, 0 to MAX inclusive.
          if ( has( p = 'DECIMAL_PLACES' ) ) {
  
              if ( inRange( v, 0, MAX ) ) {
                  DECIMAL_PLACES = v | 0;
              } else {
  
                  // 'config() DECIMAL_PLACES not an integer: {v}'
                  // 'config() DECIMAL_PLACES out of range: {v}'
                  ifExceptionsThrow( v, p, c );
              }
          }
          r[p] = DECIMAL_PLACES;
  
          // [ROUNDING_MODE] {number} Integer, 0 to 8 inclusive.
          if ( has( p = 'ROUNDING_MODE' ) ) {
  
              if ( inRange( v, 0, 8 ) ) {
                  ROUNDING_MODE = v | 0;
              } else {
  
                  // 'config() ROUNDING_MODE not an integer: {v}'
                  // 'config() ROUNDING_MODE out of range: {v}'
                  ifExceptionsThrow( v, p, c );
              }
          }
          r[p] = ROUNDING_MODE;
  
          /*
           * [EXPONENTIAL_AT] {number|number[]} Integer, -MAX to MAX inclusive or
           * [ integer -MAX to 0 inclusive, 0 to MAX inclusive ].
           */
          if ( has( p = 'EXPONENTIAL_AT' ) ) {
  
              if ( inRange( v, -MAX, MAX ) ) {
                  TO_EXP_NEG = -( TO_EXP_POS = ~~( v < 0 ? -v : +v ) );
              } else if ( !outOfRange && v && inRange( v[0], -MAX, 0 ) &&
                inRange( v[1], 0, MAX ) ) {
                  TO_EXP_NEG = ~~v[0];
                  TO_EXP_POS = ~~v[1];
              } else {
  
                  // 'config() EXPONENTIAL_AT not an integer or not [integer, integer]: {v}'
                  // 'config() EXPONENTIAL_AT out of range or not [negative, positive: {v}'
                  ifExceptionsThrow( v, p, c, 1 );
              }
          }
          r[p] = [ TO_EXP_NEG, TO_EXP_POS ];
  
          /*
           * [RANGE][ {number|number[]} Non-zero integer, -MAX to MAX inclusive or
           * [ integer -MAX to -1 inclusive, integer 1 to MAX inclusive ].
           */
          if ( has( p = 'RANGE' ) ) {
  
              if ( inRange( v, -MAX, MAX ) && ~~v ) {
                  MIN_EXP = -( MAX_EXP = ~~( v < 0 ? -v : +v ) );
              } else if ( !outOfRange && v && inRange( v[0], -MAX, -1 ) &&
                inRange( v[1], 1, MAX ) ) {
                  MIN_EXP = ~~v[0], MAX_EXP = ~~v[1];
              } else {
  
                  // 'config() RANGE not a non-zero integer or not [integer, integer]: {v}'
                  // 'config() RANGE out of range or not [negative, positive: {v}'
                  ifExceptionsThrow( v, p, c, 1, 1 );
              }
          }
          r[p] = [ MIN_EXP, MAX_EXP ];
  
          // [ERRORS] {boolean|number} true, false, 1 or 0.
          if ( has( p = 'ERRORS' ) ) {
  
              if ( v === !!v || v === 1 || v === 0 ) {
                  parse = ( outOfRange = id = 0, ERRORS = !!v )
                    ? parseInt
                    : parseFloat;
              } else {
  
                  // 'config() ERRORS not a boolean or binary digit: {v}'
                  ifExceptionsThrow( v, p, c, 0, 0, 1 );
              }
          }
          r[p] = ERRORS;
  
          return r;
      };
  
  
      // PRIVATE FUNCTIONS
  
  
      // Assemble error messages. Throw BigNumber Errors.
      function ifExceptionsThrow( arg, i, j, isArray, isRange, isErrors) {
  
          if ( ERRORS ) {
              var error,
                  method = ['new BigNumber', 'cmp', 'div', 'eq', 'gt', 'gte', 'lt',
                       'lte', 'minus', 'mod', 'plus', 'times', 'toFr'
                      ][ id ? id < 0 ? -id : id : 1 / id < 0 ? 1 : 0 ] + '()',
                  message = outOfRange ? ' out of range' : ' not a' +
                    ( isRange ? ' non-zero' : 'n' ) + ' integer';
  
              message = ( [
                  method + ' number type has more than 15 significant digits',
                  method + ' not a base ' + j + ' number',
                  method + ' base' + message,
                  method + ' not a number' ][i] ||
                    j + '() ' + i + ( isErrors
                      ? ' not a boolean or binary digit'
                      : message + ( isArray
                        ? ' or not [' + ( outOfRange
                          ? ' negative, positive'
                          : ' integer, integer' ) + ' ]'
                        : '' ) ) ) + ': ' + arg;
  
              outOfRange = id = 0;
              error = new Error(message);
              error['name'] = 'BigNumber Error';
  
              throw error;
          }
      }
  
  
      /*
       * Convert a numeric string of baseIn to a numeric string of baseOut.
       */
      function convert( nStr, baseOut, baseIn, sign ) {
          var e, dvs, dvd, nArr, fracArr, fracBN;
  
          // Convert string of base bIn to an array of numbers of baseOut.
          // Eg. strToArr('255', 10) where baseOut is 16, returns [15, 15].
          // Eg. strToArr('ff', 16)  where baseOut is 10, returns [2, 5, 5].
          function strToArr( str, bIn ) {
              var j,
                  i = 0,
                  strL = str.length,
                  arrL,
                  arr = [0];
  
              for ( bIn = bIn || baseIn; i < strL; i++ ) {
  
                  for ( arrL = arr.length, j = 0; j < arrL; arr[j] *= bIn, j++ ) {
                  }
  
                  for ( arr[0] += DIGITS.indexOf( str.charAt(i) ), j = 0;
                        j < arr.length;
                        j++ ) {
  
                      if ( arr[j] > baseOut - 1 ) {
  
                          if ( arr[j + 1] == null ) {
                              arr[j + 1] = 0;
                          }
                          arr[j + 1] += arr[j] / baseOut ^ 0;
                          arr[j] %= baseOut;
                      }
                  }
              }
  
              return arr.reverse();
          }
  
          // Convert array to string.
          // E.g. arrToStr( [9, 10, 11] ) becomes '9ab' (in bases above 11).
          function arrToStr( arr ) {
              var i = 0,
                  arrL = arr.length,
                  str = '';
  
              for ( ; i < arrL; str += DIGITS.charAt( arr[i++] ) ) {
              }
  
              return str;
          }
  
          if ( baseIn < 37 ) {
              nStr = nStr.toLowerCase();
          }
  
          /*
           * If non-integer convert integer part and fraction part separately.
           * Convert the fraction part as if it is an integer than use division to
           * reduce it down again to a value less than one.
           */
          if ( ( e = nStr.indexOf( '.' ) ) > -1 ) {
  
              /*
               * Calculate the power to which to raise the base to get the number
               * to divide the fraction part by after it has been converted as an
               * integer to the required base.
               */
              e = nStr.length - e - 1;
  
              // Use toFixed to avoid possible exponential notation.
              dvs = strToArr( new BigNumber(baseIn)['pow'](e)['toF'](), 10 );
  
              nArr = nStr.split('.');
  
              // Convert the base of the fraction part (as integer).
              dvd = strToArr( nArr[1] );
  
              // Convert the base of the integer part.
              nArr = strToArr( nArr[0] );
  
              // Result will be a BigNumber with a value less than 1.
              fracBN = divide( dvd, dvs, dvd.length - dvs.length, sign, baseOut,
                // Is least significant digit of integer part an odd number?
                nArr[nArr.length - 1] & 1 );
  
              fracArr = fracBN['c'];
  
              // e can be <= 0  ( if e == 0, fracArr is [0] or [1] ).
              if ( e = fracBN['e'] ) {
  
                  // Append zeros according to the exponent of the result.
                  for ( ; ++e; fracArr.unshift(0) ) {
                  }
  
                  // Append the fraction part to the converted integer part.
                  nStr = arrToStr(nArr) + '.' + arrToStr(fracArr);
  
              // fracArr is [1].
              // Fraction digits rounded up, so increment last digit of integer part.
              } else if ( fracArr[0] ) {
  
                  if ( nArr[ e = nArr.length - 1 ] < baseOut - 1 ) {
                      ++nArr[e];
                      nStr = arrToStr(nArr);
                  } else {
                      nStr = new BigNumber( arrToStr(nArr),
                        baseOut )['plus'](ONE)['toS'](baseOut);
                  }
  
              // fracArr is [0]. No fraction digits.
              } else {
                  nStr = arrToStr(nArr);
              }
          } else {
  
              // Simple integer. Convert base.
              nStr = arrToStr( strToArr(nStr) );
          }
  
          return nStr;
      }
  
  
      // Perform division in the specified base. Called by div and convert.
      function divide( dvd, dvs, exp, s, base, isOdd ) {
          var dvsL, dvsT, next, cmp, remI,
              dvsZ = dvs.slice(),
              dvdI = dvsL = dvs.length,
              dvdL = dvd.length,
              rem = dvd.slice( 0, dvsL ),
              remL = rem.length,
              quo = new BigNumber(ONE),
              qc = quo['c'] = [],
              qi = 0,
              dig = DECIMAL_PLACES + ( quo['e'] = exp ) + 1;
  
          quo['s'] = s;
          s = dig < 0 ? 0 : dig;
  
          // Add zeros to make remainder as long as divisor.
          for ( ; remL++ < dvsL; rem.push(0) ) {
          }
  
          // Create version of divisor with leading zero.
          dvsZ.unshift(0);
  
          do {
  
              // 'next' is how many times the divisor goes into the current remainder.
              for ( next = 0; next < base; next++ ) {
  
                  // Compare divisor and remainder.
                  if ( dvsL != ( remL = rem.length ) ) {
                      cmp = dvsL > remL ? 1 : -1;
                  } else {
                      for ( remI = -1, cmp = 0; ++remI < dvsL; ) {
  
                          if ( dvs[remI] != rem[remI] ) {
                              cmp = dvs[remI] > rem[remI] ? 1 : -1;
                              break;
                          }
                      }
                  }
  
                  // Subtract divisor from remainder (if divisor < remainder).
                  if ( cmp < 0 ) {
  
                      // Remainder cannot be more than one digit longer than divisor.
                      // Equalise lengths using divisor with extra leading zero?
                      for ( dvsT = remL == dvsL ? dvs : dvsZ; remL; ) {
  
                          if ( rem[--remL] < dvsT[remL] ) {
  
                              for ( remI = remL;
                                remI && !rem[--remI];
                                  rem[remI] = base - 1 ) {
                              }
                              --rem[remI];
                              rem[remL] += base;
                          }
                          rem[remL] -= dvsT[remL];
                      }
                      for ( ; !rem[0]; rem.shift() ) {
                      }
                  } else {
                      break;
                  }
              }
  
              // Add the 'next' digit to the result array.
              qc[qi++] = cmp ? next : ++next;
  
              // Update the remainder.
              rem[0] && cmp
                ? ( rem[remL] = dvd[dvdI] || 0 )
                : ( rem = [ dvd[dvdI] ] );
  
          } while ( ( dvdI++ < dvdL || rem[0] != null ) && s-- );
  
          // Leading zero? Do not remove if result is simply zero (qi == 1).
          if ( !qc[0] && qi != 1 ) {
  
              // There can't be more than one zero.
              --quo['e'];
              qc.shift();
          }
  
          // Round?
          if ( qi > dig ) {
              rnd( quo, DECIMAL_PLACES, base, isOdd, rem[0] != null );
          }
  
          // Overflow?
          if ( quo['e'] > MAX_EXP ) {
  
              // Infinity.
              quo['c'] = quo['e'] = null;
  
          // Underflow?
          } else if ( quo['e'] < MIN_EXP ) {
  
              // Zero.
              quo['c'] = [quo['e'] = 0];
          }
  
          return quo;
      }
  
  
      /*
       * Return a string representing the value of BigNumber n in normal or
       * exponential notation rounded to the specified decimal places or
       * significant digits.
       * Called by toString, toExponential (exp 1), toFixed, and toPrecision (exp 2).
       * d is the index (with the value in normal notation) of the digit that may be
       * rounded up.
       */
      function format( n, d, exp ) {
  
          // Initially, i is the number of decimal places required.
          var i = d - (n = new BigNumber(n))['e'],
              c = n['c'];
  
          // +-Infinity or NaN?
          if ( !c ) {
              return n['toS']();
          }
  
          // Round?
          if ( c.length > ++d ) {
              rnd( n, i, 10 );
          }
  
          // Recalculate d if toFixed as n['e'] may have changed if value rounded up.
          i = c[0] == 0 ? i + 1 : exp ? d : n['e'] + i + 1;
  
          // Append zeros?
          for ( ; c.length < i; c.push(0) ) {
          }
          i = n['e'];
  
          /*
           * toPrecision returns exponential notation if the number of significant
           * digits specified is less than the number of digits necessary to
           * represent the integer part of the value in normal notation.
           */
          return exp == 1 || exp == 2 && ( --d < i || i <= TO_EXP_NEG )
  
            // Exponential notation.
            ? ( n['s'] < 0 && c[0] ? '-' : '' ) + ( c.length > 1
              ? ( c.splice( 1, 0, '.' ), c.join('') )
              : c[0] ) + ( i < 0 ? 'e' : 'e+' ) + i
  
            // Normal notation.
            : n['toS']();
      }
  
  
      // Round if necessary.
      // Called by divide, format, setMode and sqrt.
      function rnd( x, dp, base, isOdd, r ) {
          var xc = x['c'],
              isNeg = x['s'] < 0,
              half = base / 2,
              i = x['e'] + dp + 1,
  
              // 'next' is the digit after the digit that may be rounded up.
              next = xc[i],
  
              /*
               * 'more' is whether there are digits after 'next'.
               * E.g.
               * 0.005 (e = -3) to be rounded to 0 decimal places (dp = 0) gives i = -2
               * The 'next' digit is zero, and there ARE 'more' digits after it.
               * 0.5 (e = -1) dp = 0 gives i = 0
               * The 'next' digit is 5 and there are no 'more' digits after it.
               */
              more = r || i < 0 || xc[i + 1] != null;
  
          r = ROUNDING_MODE < 4
            ? ( next != null || more ) &&
              ( ROUNDING_MODE == 0 ||
                 ROUNDING_MODE == 2 && !isNeg ||
                   ROUNDING_MODE == 3 && isNeg )
            : next > half || next == half &&
              ( ROUNDING_MODE == 4 || more ||
  
                /*
                 * isOdd is used in base conversion and refers to the least significant
                 * digit of the integer part of the value to be converted. The fraction
                 * part is rounded by this method separately from the integer part.
                 */
                ROUNDING_MODE == 6 && ( xc[i - 1] & 1 || !dp && isOdd ) ||
                  ROUNDING_MODE == 7 && !isNeg ||
                    ROUNDING_MODE == 8 && isNeg );
  
          if ( i < 1 || !xc[0] ) {
              xc.length = 0;
              xc.push(0);
  
              if ( r ) {
  
                  // 1, 0.1, 0.01, 0.001, 0.0001 etc.
                  xc[0] = 1;
                  x['e'] = -dp;
              } else {
  
                  // Zero.
                  x['e'] = 0;
              }
  
              return x;
          }
  
          // Remove any digits after the required decimal places.
          xc.length = i--;
  
          // Round up?
          if ( r ) {
  
              // Rounding up may mean the previous digit has to be rounded up and so on.
              for ( --base; ++xc[i] > base; ) {
                  xc[i] = 0;
  
                  if ( !i-- ) {
                      ++x['e'];
                      xc.unshift(1);
                  }
              }
          }
  
          // Remove trailing zeros.
          for ( i = xc.length; !xc[--i]; xc.pop() ) {
          }
  
          return x;
      }
  
  
      // Round after setting the appropriate rounding mode.
      // Handles ceil, floor and round.
      function setMode( x, dp, rm ) {
          var r = ROUNDING_MODE;
  
          ROUNDING_MODE = rm;
          x = new BigNumber(x);
          x['c'] && rnd( x, dp, 10 );
          ROUNDING_MODE = r;
  
          return x;
      }
  
  
      // PROTOTYPE/INSTANCE METHODS
  
  
      /*
       * Return a new BigNumber whose value is the absolute value of this BigNumber.
       */
      P['abs'] = P['absoluteValue'] = function () {
          var x = new BigNumber(this);
  
          if ( x['s'] < 0 ) {
              x['s'] = 1;
          }
  
          return x;
      };
  
  
      /*
       * Return a new BigNumber whose value is the value of this BigNumber
       * rounded to a whole number in the direction of Infinity.
       */
      P['ceil'] = function () {
          return setMode( this, 0, 2 );
      };
  
  
      /*
       * Return
       * 1 if the value of this BigNumber is greater than the value of BigNumber(y, b),
       * -1 if the value of this BigNumber is less than the value of BigNumber(y, b),
       * 0 if they have the same value,
       * or null if the value of either is NaN.
       */
      P['comparedTo'] = P['cmp'] = function ( y, b ) {
          var a,
              x = this,
              xc = x['c'],
              yc = ( id = -id, y = new BigNumber( y, b ) )['c'],
              i = x['s'],
              j = y['s'],
              k = x['e'],
              l = y['e'];
  
          // Either NaN?
          if ( !i || !j ) {
              return null;
          }
  
          a = xc && !xc[0], b = yc && !yc[0];
  
          // Either zero?
          if ( a || b ) {
              return a ? b ? 0 : -j : i;
          }
  
          // Signs differ?
          if ( i != j ) {
              return i;
          }
  
          // Either Infinity?
          if ( a = i < 0, b = k == l, !xc || !yc ) {
              return b ? 0 : !xc ^ a ? 1 : -1;
          }
  
          // Compare exponents.
          if ( !b ) {
              return k > l ^ a ? 1 : -1;
          }
  
          // Compare digit by digit.
          for ( i = -1,
                j = ( k = xc.length ) < ( l = yc.length ) ? k : l;
                ++i < j; ) {
  
              if ( xc[i] != yc[i] ) {
                  return xc[i] > yc[i] ^ a ? 1 : -1;
              }
          }
          // Compare lengths.
          return k == l ? 0 : k > l ^ a ? 1 : -1;
      };
  
  
      /*
       *  n / 0 = I
       *  n / N = N
       *  n / I = 0
       *  0 / n = 0
       *  0 / 0 = N
       *  0 / N = N
       *  0 / I = 0
       *  N / n = N
       *  N / 0 = N
       *  N / N = N
       *  N / I = N
       *  I / n = I
       *  I / 0 = I
       *  I / N = N
       *  I / I = N
       *
       * Return a new BigNumber whose value is the value of this BigNumber
       * divided by the value of BigNumber(y, b), rounded according to
       * DECIMAL_PLACES and ROUNDING_MODE.
       */
      P['dividedBy'] = P['div'] = function ( y, b ) {
          var xc = this['c'],
              xe = this['e'],
              xs = this['s'],
              yc = ( id = 2, y = new BigNumber( y, b ) )['c'],
              ye = y['e'],
              ys = y['s'],
              s = xs == ys ? 1 : -1;
  
          // Either NaN/Infinity/0?
          return !xe && ( !xc || !xc[0] ) || !ye && ( !yc || !yc[0] )
  
            // Either NaN?
            ? new BigNumber( !xs || !ys ||
  
              // Both 0 or both Infinity?
              ( xc ? yc && xc[0] == yc[0] : !yc )
  
                // Return NaN.
                ? NaN
  
                // x is 0 or y is Infinity?
                : xc && xc[0] == 0 || !yc
  
                  // Return +-0.
                  ? s * 0
  
                  // y is 0. Return +-Infinity.
                  : s / 0 )
  
            : divide( xc, yc, xe - ye, s, 10 );
      };
  
  
      /*
       * Return true if the value of this BigNumber is equal to the value of
       * BigNumber(n, b), otherwise returns false.
       */
      P['equals'] = P['eq'] = function ( n, b ) {
          id = 3;
          return this['cmp']( n, b ) === 0;
      };
  
  
      /*
       * Return a new BigNumber whose value is the value of this BigNumber
       * rounded to a whole number in the direction of -Infinity.
       */
      P['floor'] = function () {
          return setMode( this, 0, 3 );
      };
  
  
      /*
       * Return true if the value of this BigNumber is greater than the value of
       * BigNumber(n, b), otherwise returns false.
       */
      P['greaterThan'] = P['gt'] = function ( n, b ) {
          id = 4;
          return this['cmp']( n, b ) > 0;
      };
  
  
      /*
       * Return true if the value of this BigNumber is greater than or equal to
       * the value of BigNumber(n, b), otherwise returns false.
       */
      P['greaterThanOrEqualTo'] = P['gte'] = function ( n, b ) {
          id = 5;
          return ( b = this['cmp']( n, b ) ) == 1 || b === 0;
      };
  
  
      /*
       * Return true if the value of this BigNumber is a finite number, otherwise
       * returns false.
       */
      P['isFinite'] = P['isF'] = function () {
          return !!this['c'];
      };
  
  
      /*
       * Return true if the value of this BigNumber is NaN, otherwise returns
       * false.
       */
      P['isNaN'] = function () {
          return !this['s'];
      };
  
  
      /*
       * Return true if the value of this BigNumber is negative, otherwise
       * returns false.
       */
      P['isNegative'] = P['isNeg'] = function () {
          return this['s'] < 0;
      };
  
  
      /*
       * Return true if the value of this BigNumber is 0 or -0, otherwise returns
       * false.
       */
      P['isZero'] = P['isZ'] = function () {
          return !!this['c'] && this['c'][0] == 0;
      };
  
  
      /*
       * Return true if the value of this BigNumber is less than the value of
       * BigNumber(n, b), otherwise returns false.
       */
      P['lessThan'] = P['lt'] = function ( n, b ) {
          id = 6;
          return this['cmp']( n, b ) < 0;
      };
  
  
      /*
       * Return true if the value of this BigNumber is less than or equal to the
       * value of BigNumber(n, b), otherwise returns false.
       */
      P['lessThanOrEqualTo'] = P['lte'] = function ( n, b ) {
          id = 7;
          return ( b = this['cmp']( n, b ) ) == -1 || b === 0;
      };
  
  
      /*
       *  n - 0 = n
       *  n - N = N
       *  n - I = -I
       *  0 - n = -n
       *  0 - 0 = 0
       *  0 - N = N
       *  0 - I = -I
       *  N - n = N
       *  N - 0 = N
       *  N - N = N
       *  N - I = N
       *  I - n = I
       *  I - 0 = I
       *  I - N = N
       *  I - I = N
       *
       * Return a new BigNumber whose value is the value of this BigNumber minus
       * the value of BigNumber(y, b).
       */
      P['minus'] = function ( y, b ) {
          var d, i, j, xLTy,
              x = this,
              a = x['s'];
  
          b = ( id = 8, y = new BigNumber( y, b ) )['s'];
  
          // Either NaN?
          if ( !a || !b ) {
              return new BigNumber(NaN);
          }
  
          // Signs differ?
          if ( a != b ) {
              return y['s'] = -b, x['plus'](y);
          }
  
          var xc = x['c'],
              xe = x['e'],
              yc = y['c'],
              ye = y['e'];
  
          if ( !xe || !ye ) {
  
              // Either Infinity?
              if ( !xc || !yc ) {
                  return xc ? ( y['s'] = -b, y ) : new BigNumber( yc ? x : NaN );
              }
  
              // Either zero?
              if ( !xc[0] || !yc[0] ) {
  
                  // y is non-zero?
                  return yc[0]
                    ? ( y['s'] = -b, y )
  
                    // x is non-zero?
                    : new BigNumber( xc[0]
                      ? x
  
                      // Both are zero.
                      // IEEE 754 (2008) 6.3: n - n = -0 when rounding to -Infinity
                      : ROUNDING_MODE == 3 ? -0 : 0 );
              }
          }
  
          // Determine which is the bigger number.
          // Prepend zeros to equalise exponents.
          if ( xc = xc.slice(), a = xe - ye ) {
              d = ( xLTy = a < 0 ) ? ( a = -a, xc ) : ( ye = xe, yc );
  
              for ( d.reverse(), b = a; b--; d.push(0) ) {
              }
              d.reverse();
          } else {
  
              // Exponents equal. Check digit by digit.
              j = ( ( xLTy = xc.length < yc.length ) ? xc : yc ).length;
  
              for ( a = b = 0; b < j; b++ ) {
  
                  if ( xc[b] != yc[b] ) {
                      xLTy = xc[b] < yc[b];
                      break;
                  }
              }
          }
  
          // x < y? Point xc to the array of the bigger number.
          if ( xLTy ) {
              d = xc, xc = yc, yc = d;
              y['s'] = -y['s'];
          }
  
          /*
           * Append zeros to xc if shorter. No need to add zeros to yc if shorter
           * as subtraction only needs to start at yc.length.
           */
          if ( ( b = -( ( j = xc.length ) - yc.length ) ) > 0 ) {
  
              for ( ; b--; xc[j++] = 0 ) {
              }
          }
  
          // Subtract yc from xc.
          for ( b = yc.length; b > a; ){
  
              if ( xc[--b] < yc[b] ) {
  
                  for ( i = b; i && !xc[--i]; xc[i] = 9 ) {
                  }
                  --xc[i];
                  xc[b] += 10;
              }
              xc[b] -= yc[b];
          }
  
          // Remove trailing zeros.
          for ( ; xc[--j] == 0; xc.pop() ) {
          }
  
          // Remove leading zeros and adjust exponent accordingly.
          for ( ; xc[0] == 0; xc.shift(), --ye ) {
          }
  
          /*
           * No need to check for Infinity as +x - +y != Infinity && -x - -y != Infinity
           * when neither x or y are Infinity.
           */
  
          // Underflow?
          if ( ye < MIN_EXP || !xc[0] ) {
  
              /*
               * Following IEEE 754 (2008) 6.3,
               * n - n = +0  but  n - n = -0 when rounding towards -Infinity.
               */
              if ( !xc[0] ) {
                  y['s'] = ROUNDING_MODE == 3 ? -1 : 1;
              }
  
              // Result is zero.
              xc = [ye = 0];
          }
  
          return y['c'] = xc, y['e'] = ye, y;
      };
  
  
      /*
       *   n % 0 =  N
       *   n % N =  N
       *   0 % n =  0
       *  -0 % n = -0
       *   0 % 0 =  N
       *   0 % N =  N
       *   N % n =  N
       *   N % 0 =  N
       *   N % N =  N
       *
       * Return a new BigNumber whose value is the value of this BigNumber modulo
       * the value of BigNumber(y, b).
       */
      P['modulo'] = P['mod'] = function ( y, b ) {
          var x = this,
              xc = x['c'],
              yc = ( id = 9, y = new BigNumber( y, b ) )['c'],
              i = x['s'],
              j = y['s'];
  
          // Is x or y NaN, or y zero?
          b = !i || !j || yc && !yc[0];
  
          if ( b || xc && !xc[0] ) {
              return new BigNumber( b ? NaN : x );
          }
  
          x['s'] = y['s'] = 1;
          b = y['cmp'](x) == 1;
          x['s'] = i, y['s'] = j;
  
          return b
            ? new BigNumber(x)
            : ( i = DECIMAL_PLACES, j = ROUNDING_MODE,
              DECIMAL_PLACES = 0, ROUNDING_MODE = 1,
                x = x['div'](y),
                  DECIMAL_PLACES = i, ROUNDING_MODE = j,
                    this['minus']( x['times'](y) ) );
      };
  
  
      /*
       * Return a new BigNumber whose value is the value of this BigNumber
       * negated, i.e. multiplied by -1.
       */
      P['negated'] = P['neg'] = function () {
          var x = new BigNumber(this);
  
          return x['s'] = -x['s'] || null, x;
      };
  
  
      /*
       *  n + 0 = n
       *  n + N = N
       *  n + I = I
       *  0 + n = n
       *  0 + 0 = 0
       *  0 + N = N
       *  0 + I = I
       *  N + n = N
       *  N + 0 = N
       *  N + N = N
       *  N + I = N
       *  I + n = I
       *  I + 0 = I
       *  I + N = N
       *  I + I = I
       *
       * Return a new BigNumber whose value is the value of this BigNumber plus
       * the value of BigNumber(y, b).
       */
      P['plus'] = function ( y, b ) {
          var d,
              x = this,
              a = x['s'];
  
          b = ( id = 10, y = new BigNumber( y, b ) )['s'];
  
          // Either NaN?
          if ( !a || !b ) {
              return new BigNumber(NaN);
          }
  
          // Signs differ?
          if ( a != b ) {
              return y['s'] = -b, x['minus'](y);
          }
  
          var xe = x['e'],
              xc = x['c'],
              ye = y['e'],
              yc = y['c'];
  
          if ( !xe || !ye ) {
  
              // Either Infinity?
              if ( !xc || !yc ) {
  
                  // Return +-Infinity.
                  return new BigNumber( a / 0 );
              }
  
              // Either zero?
              if ( !xc[0] || !yc[0] ) {
  
                  // y is non-zero?
                  return yc[0]
                    ? y
  
                    // x is non-zero?
                    : new BigNumber( xc[0]
                      ? x
  
                      // Both are zero. Return zero.
                      : a * 0 );
              }
          }
  
          // Prepend zeros to equalise exponents.
          // Note: Faster to use reverse then do unshifts.
          if ( xc = xc.slice(), a = xe - ye ) {
              d = a > 0 ? ( ye = xe, yc ) : ( a = -a, xc );
  
              for ( d.reverse(); a--; d.push(0) ) {
              }
              d.reverse();
          }
  
          // Point xc to the longer array.
          if ( xc.length - yc.length < 0 ) {
              d = yc, yc = xc, xc = d;
          }
  
          /*
           * Only start adding at yc.length - 1 as the
           * further digits of xc can be left as they are.
           */
          for ( a = yc.length, b = 0; a;
               b = ( xc[--a] = xc[a] + yc[a] + b ) / 10 ^ 0, xc[a] %= 10 ) {
          }
  
          // No need to check for zero, as +x + +y != 0 && -x + -y != 0
  
          if ( b ) {
              xc.unshift(b);
  
              // Overflow? (MAX_EXP + 1 possible)
              if ( ++ye > MAX_EXP ) {
  
                  // Infinity.
                  xc = ye = null;
              }
          }
  
           // Remove trailing zeros.
          for ( a = xc.length; xc[--a] == 0; xc.pop() ) {
          }
  
          return y['c'] = xc, y['e'] = ye, y;
      };
  
  
      /*
       * Return a BigNumber whose value is the value of this BigNumber raised to
       * the power e. If e is negative round according to DECIMAL_PLACES and
       * ROUNDING_MODE.
       *
       * e {number} Integer, -MAX_POWER to MAX_POWER inclusive.
       */
      P['toPower'] = P['pow'] = function ( e ) {
  
          // e to integer, avoiding NaN or Infinity becoming 0.
          var i = e * 0 == 0 ? e | 0 : e,
              x = new BigNumber(this),
              y = new BigNumber(ONE);
  
          // Use Math.pow?
          // Pass +-Infinity for out of range exponents.
          if ( ( ( ( outOfRange = e < -MAX_POWER || e > MAX_POWER ) &&
            (i = e * 1 / 0) ) ||
  
               /*
                * Any exponent that fails the parse becomes NaN.
                *
                * Include 'e !== 0' because on Opera -0 == parseFloat(-0) is false,
                * despite -0 === parseFloat(-0) && -0 == parseFloat('-0') is true.
                */
               parse(e) != e && e !== 0 && !(i = NaN) ) &&
  
                // 'pow() exponent not an integer: {e}'
                // 'pow() exponent out of range: {e}'
                !ifExceptionsThrow( e, 'exponent', 'pow' ) ||
  
                  // Pass zero to Math.pow, as any value to the power zero is 1.
                  !i ) {
  
              // i is +-Infinity, NaN or 0.
              return new BigNumber( Math.pow( x['toS'](), i ) );
          }
  
          for ( i = i < 0 ? -i : i; ; ) {
  
              if ( i & 1 ) {
                  y = y['times'](x);
              }
              i >>= 1;
  
              if ( !i ) {
                  break;
              }
              x = x['times'](x);
          }
  
          return e < 0 ? ONE['div'](y) : y;
      };
  
  
      /*
       * Return a new BigNumber whose value is the value of this BigNumber
       * rounded to a maximum of dp decimal places using rounding mode rm, or to
       * 0 and ROUNDING_MODE respectively if omitted.
       *
       * [dp] {number} Integer, 0 to MAX inclusive.
       * [rm] {number} Integer, 0 to 8 inclusive.
       */
      P['round'] = function ( dp, rm ) {
  
          dp = dp == null || ( ( ( outOfRange = dp < 0 || dp > MAX ) ||
            parse(dp) != dp ) &&
  
              // 'round() decimal places out of range: {dp}'
              // 'round() decimal places not an integer: {dp}'
              !ifExceptionsThrow( dp, 'decimal places', 'round' ) )
                ? 0
                : dp | 0;
  
          rm = rm == null || ( ( ( outOfRange = rm < 0 || rm > 8 ) ||
  
            // Include '&& rm !== 0' because with Opera -0 == parseFloat(-0) is false.
            parse(rm) != rm && rm !== 0 ) &&
  
              // 'round() mode not an integer: {rm}'
              // 'round() mode out of range: {rm}'
              !ifExceptionsThrow( rm, 'mode', 'round' ) )
                ? ROUNDING_MODE
                : rm | 0;
  
          return setMode( this, dp, rm );
      };
  
  
      /*
       *  sqrt(-n) =  N
       *  sqrt( N) =  N
       *  sqrt(-I) =  N
       *  sqrt( I) =  I
       *  sqrt( 0) =  0
       *  sqrt(-0) = -0
       *
       * Return a new BigNumber whose value is the square root of the value of
       * this BigNumber, rounded according to DECIMAL_PLACES and ROUNDING_MODE.
       */
      P['squareRoot'] = P['sqrt'] = function () {
          var n, r, re, t,
              x = this,
              c = x['c'],
              s = x['s'],
              e = x['e'],
              dp = DECIMAL_PLACES,
              rm = ROUNDING_MODE,
              half = new BigNumber('0.5');
  
          // Negative/NaN/Infinity/zero?
          if ( s !== 1 || !c || !c[0] ) {
  
              return new BigNumber( !s || s < 0 && ( !c || c[0] )
                ? NaN
                : c ? x : 1 / 0 );
          }
  
          // Initial estimate.
          s = Math.sqrt( x['toS']() );
          ROUNDING_MODE = 1;
  
          /*
            Math.sqrt underflow/overflow?
            Pass x to Math.sqrt as integer, then adjust the exponent of the result.
           */
          if ( s == 0 || s == 1 / 0 ) {
              n = c.join('');
  
              if ( !( n.length + e & 1 ) ) {
                  n += '0';
              }
              r = new BigNumber( Math.sqrt(n) + '' );
  
              // r may still not be finite.
              if ( !r['c'] ) {
                  r['c'] = [1];
              }
              r['e'] = ( ( ( e + 1 ) / 2 ) | 0 ) - ( e < 0 || e & 1 );
          } else {
              r = new BigNumber( n = s.toString() );
          }
          re = r['e'];
          s = re + ( DECIMAL_PLACES += 4 );
  
          if ( s < 3 ) {
              s = 0;
          }
          e = s;
  
          // Newton-Raphson iteration.
          for ( ; ; ) {
              t = r;
              r = half['times']( t['plus']( x['div'](t) ) );
  
              if ( t['c'].slice( 0, s ).join('') === r['c'].slice( 0, s ).join('') ) {
                  c = r['c'];
  
                  /*
                    The exponent of r may here be one less than the final result
                    exponent (re), e.g 0.0009999 (e-4) --> 0.001 (e-3), so adjust
                    s so the rounding digits are indexed correctly.
                   */
                  s = s - ( n && r['e'] < re );
  
                  /*
                    The 4th rounding digit may be in error by -1 so if the 4 rounding
                    digits are 9999 or 4999 (i.e. approaching a rounding boundary)
                    continue the iteration.
                   */
                  if ( c[s] == 9 && c[s - 1] == 9 && c[s - 2] == 9 &&
                          ( c[s - 3] == 9 || n && c[s - 3] == 4 ) ) {
  
                      /*
                        If 9999 on first run through, check to see if rounding up
                        gives the exact result as the nines may infinitely repeat.
                       */
                      if ( n && c[s - 3] == 9 ) {
                          t = r['round']( dp, 0 );
  
                          if ( t['times'](t)['eq'](x) ) {
                              ROUNDING_MODE = rm;
                              DECIMAL_PLACES = dp;
  
                              return t;
                          }
                      }
                      DECIMAL_PLACES += 4;
                      s += 4;
                      n = '';
                  } else {
  
                      /*
                        If the rounding digits are null, 0000 or 5000, check for an
                        exact result. If not, then there are further digits so
                        increment the 1st rounding digit to ensure correct rounding.
                       */
                      if ( !c[e] && !c[e - 1] && !c[e - 2] &&
                              ( !c[e - 3] || c[e - 3] == 5 ) ) {
  
                          // Truncate to the first rounding digit.
                          if ( c.length > e - 2 ) {
                              c.length = e - 2;
                          }
  
                          if ( !r['times'](r)['eq'](x) ) {
  
                              while ( c.length < e - 3 ) {
                                  c.push(0);
                              }
                              c[e - 3]++;
                          }
                      }
                      ROUNDING_MODE = rm;
                      rnd( r, DECIMAL_PLACES = dp, 10 );
  
                      return r;
                  }
              }
          }
      };
  
  
      /*
       *  n * 0 = 0
       *  n * N = N
       *  n * I = I
       *  0 * n = 0
       *  0 * 0 = 0
       *  0 * N = N
       *  0 * I = N
       *  N * n = N
       *  N * 0 = N
       *  N * N = N
       *  N * I = N
       *  I * n = I
       *  I * 0 = N
       *  I * N = N
       *  I * I = I
       *
       * Return a new BigNumber whose value is the value of this BigNumber times
       * the value of BigNumber(y, b).
       */
      P['times'] = function ( y, b ) {
          var c,
              x = this,
              xc = x['c'],
              yc = ( id = 11, y = new BigNumber( y, b ) )['c'],
              i = x['e'],
              j = y['e'],
              a = x['s'];
  
          y['s'] = a == ( b = y['s'] ) ? 1 : -1;
  
          // Either NaN/Infinity/0?
          if ( !i && ( !xc || !xc[0] ) || !j && ( !yc || !yc[0] ) ) {
  
              // Either NaN?
              return new BigNumber( !a || !b ||
  
                // x is 0 and y is Infinity  or  y is 0 and x is Infinity?
                xc && !xc[0] && !yc || yc && !yc[0] && !xc
  
                  // Return NaN.
                  ? NaN
  
                  // Either Infinity?
                  : !xc || !yc
  
                    // Return +-Infinity.
                    ? y['s'] / 0
  
                    // x or y is 0. Return +-0.
                    : y['s'] * 0 );
          }
          y['e'] = i + j;
  
          if ( ( a = xc.length ) < ( b = yc.length ) ) {
              c = xc, xc = yc, yc = c, j = a, a = b, b = j;
          }
  
          for ( j = a + b, c = []; j--; c.push(0) ) {
          }
  
          // Multiply!
          for ( i = b - 1; i > -1; i-- ) {
  
              for ( b = 0, j = a + i;
                    j > i;
                    b = c[j] + yc[i] * xc[j - i - 1] + b,
                    c[j--] = b % 10 | 0,
                    b = b / 10 | 0 ) {
              }
  
              if ( b ) {
                  c[j] = ( c[j] + b ) % 10;
              }
          }
  
          b && ++y['e'];
  
          // Remove any leading zero.
          !c[0] && c.shift();
  
          // Remove trailing zeros.
          for ( j = c.length; !c[--j]; c.pop() ) {
          }
  
          // No zero check needed as only x * 0 == 0 etc.
  
          // Overflow?
          y['c'] = y['e'] > MAX_EXP
  
            // Infinity.
            ? ( y['e'] = null )
  
            // Underflow?
            : y['e'] < MIN_EXP
  
              // Zero.
              ? [ y['e'] = 0 ]
  
              // Neither.
              : c;
  
          return y;
      };
  
  
      /*
       * Return a string representing the value of this BigNumber in exponential
       * notation to dp fixed decimal places and rounded using ROUNDING_MODE if
       * necessary.
       *
       * [dp] {number} Integer, 0 to MAX inclusive.
       */
      P['toExponential'] = P['toE'] = function ( dp ) {
  
          return format( this,
            ( dp == null || ( ( outOfRange = dp < 0 || dp > MAX ) ||
  
              /*
               * Include '&& dp !== 0' because with Opera -0 == parseFloat(-0) is
               * false, despite -0 == parseFloat('-0') && 0 == -0 being true.
               */
              parse(dp) != dp && dp !== 0 ) &&
  
                // 'toE() decimal places not an integer: {dp}'
                // 'toE() decimal places out of range: {dp}'
                !ifExceptionsThrow( dp, 'decimal places', 'toE' ) ) && this['c']
                  ? this['c'].length - 1
                  : dp | 0, 1 );
      };
  
  
      /*
       * Return a string representing the value of this BigNumber in normal
       * notation to dp fixed decimal places and rounded using ROUNDING_MODE if
       * necessary.
       *
       * Note: as with JavaScript's number type, (-0).toFixed(0) is '0',
       * but e.g. (-0.00001).toFixed(0) is '-0'.
       *
       * [dp] {number} Integer, 0 to MAX inclusive.
       */
      P['toFixed'] = P['toF'] = function ( dp ) {
          var n, str, d,
              x = this;
  
          if ( !( dp == null || ( ( outOfRange = dp < 0 || dp > MAX ) ||
              parse(dp) != dp && dp !== 0 ) &&
  
              // 'toF() decimal places not an integer: {dp}'
              // 'toF() decimal places out of range: {dp}'
              !ifExceptionsThrow( dp, 'decimal places', 'toF' ) ) ) {
                d = x['e'] + ( dp | 0 );
          }
  
          n = TO_EXP_NEG, dp = TO_EXP_POS;
          TO_EXP_NEG = -( TO_EXP_POS = 1 / 0 );
  
          // Note: str is initially undefined.
          if ( d == str ) {
              str = x['toS']();
          } else {
              str = format( x, d );
  
              // (-0).toFixed() is '0', but (-0.1).toFixed() is '-0'.
              // (-0).toFixed(1) is '0.0', but (-0.01).toFixed(1) is '-0.0'.
              if ( x['s'] < 0 && x['c'] ) {
  
                  // As e.g. -0 toFixed(3), will wrongly be returned as -0.000 from toString.
                  if ( !x['c'][0] ) {
                      str = str.replace(/^-/, '');
  
                  // As e.g. -0.5 if rounded to -0 will cause toString to omit the minus sign.
                  } else if ( str.indexOf('-') < 0 ) {
                      str = '-' + str;
                  }
              }
          }
          TO_EXP_NEG = n, TO_EXP_POS = dp;
  
          return str;
      };
  
  
      /*
       * Return a string array representing the value of this BigNumber as a
       * simple fraction with an integer numerator and an integer denominator.
       * The denominator will be a positive non-zero value less than or equal to
       * the specified maximum denominator. If a maximum denominator is not
       * specified, the denominator will be the lowest value necessary to
       * represent the number exactly.
       *
       * [maxD] {number|string|BigNumber} Integer >= 1 and < Infinity.
       */
      P['toFraction'] = P['toFr'] = function ( maxD ) {
          var q, frac, n0, d0, d2, n, e,
              n1 = d0 = new BigNumber(ONE),
              d1 = n0 = new BigNumber('0'),
              x = this,
              xc = x['c'],
              exp = MAX_EXP,
              dp = DECIMAL_PLACES,
              rm = ROUNDING_MODE,
              d = new BigNumber(ONE);
  
          // NaN, Infinity.
          if ( !xc ) {
              return x['toS']();
          }
  
          e = d['e'] = xc.length - x['e'] - 1;
  
          // If max denominator is undefined or null...
          if ( maxD == null ||
  
               // or NaN...
               ( !( id = 12, n = new BigNumber(maxD) )['s'] ||
  
                 // or less than 1, or Infinity...
                 ( outOfRange = n['cmp'](n1) < 0 || !n['c'] ) ||
  
                   // or not an integer...
                   ( ERRORS && n['e'] < n['c'].length - 1 ) ) &&
  
                     // 'toFr() max denominator not an integer: {maxD}'
                     // 'toFr() max denominator out of range: {maxD}'
                     !ifExceptionsThrow( maxD, 'max denominator', 'toFr' ) ||
  
                       // or greater than the maxD needed to specify the value exactly...
                       ( maxD = n )['cmp'](d) > 0 ) {
  
              // d is e.g. 10, 100, 1000, 10000... , n1 is 1.
              maxD = e > 0 ? d : n1;
          }
  
          MAX_EXP = 1 / 0;
          n = new BigNumber( xc.join('') );
  
          for ( DECIMAL_PLACES = 0, ROUNDING_MODE = 1; ; )  {
              q = n['div'](d);
              d2 = d0['plus']( q['times'](d1) );
  
              if ( d2['cmp'](maxD) == 1 ) {
                  break;
              }
  
              d0 = d1, d1 = d2;
  
              n1 = n0['plus']( q['times']( d2 = n1 ) );
              n0 = d2;
  
              d = n['minus']( q['times']( d2 = d ) );
              n = d2;
          }
  
          d2 = maxD['minus'](d0)['div'](d1);
          n0 = n0['plus']( d2['times'](n1) );
          d0 = d0['plus']( d2['times'](d1) );
  
          n0['s'] = n1['s'] = x['s'];
  
          DECIMAL_PLACES = e * 2;
          ROUNDING_MODE = rm;
  
          // Determine which fraction is closer to x, n0 / d0 or n1 / d1?
          frac = n1['div'](d1)['minus'](x)['abs']()['cmp'](
            n0['div'](d0)['minus'](x)['abs']() ) < 1
            ? [ n1['toS'](), d1['toS']() ]
            : [ n0['toS'](), d0['toS']() ];
  
          return MAX_EXP = exp, DECIMAL_PLACES = dp, frac;
      };
  
  
      /*
       * Return a string representing the value of this BigNumber to sd significant
       * digits and rounded using ROUNDING_MODE if necessary.
       * If sd is less than the number of digits necessary to represent the integer
       * part of the value in normal notation, then use exponential notation.
       *
       * sd {number} Integer, 1 to MAX inclusive.
       */
      P['toPrecision'] = P['toP'] = function ( sd ) {
  
          /*
           * ERRORS true: Throw if sd not undefined, null or an integer in range.
           * ERRORS false: Ignore sd if not a number or not in range.
           * Truncate non-integers.
           */
          return sd == null || ( ( ( outOfRange = sd < 1 || sd > MAX ) ||
            parse(sd) != sd ) &&
  
              // 'toP() precision not an integer: {sd}'
              // 'toP() precision out of range: {sd}'
              !ifExceptionsThrow( sd, 'precision', 'toP' ) )
                ? this['toS']()
                : format( this, --sd | 0, 2 );
      };
  
  
      /*
       * Return a string representing the value of this BigNumber in base b, or
       * base 10 if b is omitted. If a base is specified, including base 10,
       * round according to DECIMAL_PLACES and ROUNDING_MODE.
       * If a base is not specified, and this BigNumber has a positive exponent
       * that is equal to or greater than TO_EXP_POS, or a negative exponent equal
       * to or less than TO_EXP_NEG, return exponential notation.
       *
       * [b] {number} Integer, 2 to 64 inclusive.
       */
      P['toString'] = P['toS'] = function ( b ) {
          var u, str, strL,
              x = this,
              xe = x['e'];
  
          // Infinity or NaN?
          if ( xe === null ) {
              str = x['s'] ? 'Infinity' : 'NaN';
  
          // Exponential format?
          } else if ( b === u && ( xe <= TO_EXP_NEG || xe >= TO_EXP_POS ) ) {
              return format( x, x['c'].length - 1, 1 );
          } else {
              str = x['c'].join('');
  
              // Negative exponent?
              if ( xe < 0 ) {
  
                  // Prepend zeros.
                  for ( ; ++xe; str = '0' + str ) {
                  }
                  str = '0.' + str;
  
              // Positive exponent?
              } else if ( strL = str.length, xe > 0 ) {
  
                  if ( ++xe > strL ) {
  
                      // Append zeros.
                      for ( xe -= strL; xe-- ; str += '0' ) {
                      }
                  } else if ( xe < strL ) {
                      str = str.slice( 0, xe ) + '.' + str.slice(xe);
                  }
  
              // Exponent zero.
              } else {
                  if ( u = str.charAt(0), strL > 1 ) {
                      str = u + '.' + str.slice(1);
  
                  // Avoid '-0'
                  } else if ( u == '0' ) {
                      return u;
                  }
              }
  
              if ( b != null ) {
  
                  if ( !( outOfRange = !( b >= 2 && b < 65 ) ) &&
                    ( b == (b | 0) || !ERRORS ) ) {
                      str = convert( str, b | 0, 10, x['s'] );
  
                      // Avoid '-0'
                      if ( str == '0' ) {
                          return str;
                      }
                  } else {
  
                      // 'toS() base not an integer: {b}'
                      // 'toS() base out of range: {b}'
                      ifExceptionsThrow( b, 'base', 'toS' );
                  }
              }
  
          }
  
          return x['s'] < 0 ? '-' + str : str;
      };
  
  
      /*
       * Return as toString, but do not accept a base argument.
       */
      P['valueOf'] = function () {
          return this['toS']();
      };
  
  
      // Add aliases for BigDecimal methods.
      //P['add'] = P['plus'];
      //P['subtract'] = P['minus'];
      //P['multiply'] = P['times'];
      //P['divide'] = P['div'];
      //P['remainder'] = P['mod'];
      //P['compareTo'] = P['cmp'];
      //P['negate'] = P['neg'];
  
  
      // EXPORT
  
  
      // Node and other CommonJS-like environments that support module.exports.
      if ( typeof module !== 'undefined' && module.exports ) {
          module.exports = BigNumber;
  
      //AMD.
      } else if ( typeof define == 'function' && define.amd ) {
          define( function () {
              return BigNumber;
          });
  
      //Browser.
      } else {
          global['BigNumber'] = BigNumber;
      }
  
  })( this );
  
  },{}]},{},[1])
  (1)
  });
  ;