Merge lp:~gang65/ubuntu-calculator-app/ubuntu-calculator-app-mathjs-2-upgrade into lp:ubuntu-calculator-app

Proposed by Bartosz Kosiorek on 2015-08-14
Status: Merged
Approved by: Nicholas Skaggs on 2015-09-14
Approved revision: 224
Merged at revision: 224
Proposed branch: lp:~gang65/ubuntu-calculator-app/ubuntu-calculator-app-mathjs-2-upgrade
Merge into: lp:ubuntu-calculator-app
Diff against target: 73137 lines (+42283/-28666)
2 files modified
app/engine/math.js (+42280/-28664)
debian/changelog (+3/-2)
To merge this branch: bzr merge lp:~gang65/ubuntu-calculator-app/ubuntu-calculator-app-mathjs-2-upgrade
Reviewer Review Type Date Requested Status
Ubuntu Phone Apps Jenkins Bot continuous-integration Approve on 2015-09-14
Riccardo Padovani 2015-08-14 Approve on 2015-08-30
Review via email: mp+268046@code.launchpad.net

Commit Message

Upgrade math.js to 2.1.1 to improve performance (LP: #1484851)

Description of the Change

Upgrade math.js to 2.1.1 to improve performance (LP: #1484851)

To post a comment you must log in.
Riccardo Padovani (rpadovani) wrote :

lgtm, thanks!

review: Approve
222. By Bartosz Kosiorek on 2015-08-30

Upgrade math.js to 2.2

223. By Bartosz Kosiorek on 2015-08-30

Upgrade math.js to 2.2.0

224. By Bartosz Kosiorek on 2015-08-30

Tune math.js for calculator purposes

Nicholas Skaggs (nskaggs) wrote :

Rebuilding with jenkins fixed :-)

review: Approve (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'app/engine/math.js'
2--- app/engine/math.js 2015-04-29 19:37:47 +0000
3+++ app/engine/math.js 2015-08-30 23:10:49 +0000
4@@ -14,8 +14,8 @@
5 * It features real and complex numbers, units, matrices, a large set of
6 * mathematical functions, and a flexible expression parser.
7 *
8- * @version 1.5.2
9- * @date 2015-04-09
10+ * @version 2.2.0
11+ * @date 2015-08-30
12 *
13 * @license
14 * Copyright (C) 2013-2015 Jos de Jong <wjosdejong@gmail.com>
15@@ -35,7 +35,8 @@
16
17 (function webpackUniversalModuleDefinition(root, factory) {
18 // UCA: we delete all exports, we don't need them, and we keep only our var
19- mathJs = factory();})(this, function() {
20+ mathJs = factory();
21+})(this, function() {
22 return /******/ (function(modules) { // webpackBootstrap
23 /******/ // The module cache
24 /******/ var installedModules = {};
25@@ -82,42 +83,117 @@
26 /* 0 */
27 /***/ function(module, exports, __webpack_require__) {
28
29- module.exports = __webpack_require__(1);
30-
31-
32-/***/ },
33-/* 1 */
34-/***/ function(module, exports, __webpack_require__) {
35-
36- 'use strict';
37-
38- var object = __webpack_require__(2);
39- var digits = __webpack_require__(3).digits;
40+ var core = __webpack_require__(1);
41
42 /**
43- * math.js factory function.
44+ * math.js factory function. Creates a new instance of math.js
45 *
46 * @param {Object} [config] Available configuration options:
47- * {String} matrix
48+ * {number} epsilon
49+ * Minimum relative difference between two
50+ * compared values, used by all comparison functions.
51+ * {string} matrix
52 * A string 'matrix' (default) or 'array'.
53- * {String} number
54- * A string 'number' (default) or 'bignumber'
55- * {Number} precision
56+ * {string} number
57+ * A string 'number' (default), 'bignumber', or
58+ * 'fraction'
59+ * {number} precision
60 * The number of significant digits for BigNumbers.
61 * Not applicable for Numbers.
62+ * {boolean} predictable
63+ * Predictable output type of functions. When true,
64+ * output type depends only on the input types. When
65+ * false (default), output type can vary depending
66+ * on input values. For example `math.sqrt(-2)`
67+ * returns `NaN` when predictable is false, and
68+ * returns `complex('2i')` when true.
69 */
70 function create (config) {
71+ // create a new math.js instance
72+ var math = core.create(config);
73+ math.create = create;
74+
75+ // import data types, functions, constants, expression parser, etc.
76+ math.import(__webpack_require__(13));
77+
78+ return math;
79+ }
80+
81+ // return a new instance of math.js
82+ module.exports = create();
83+
84+
85+/***/ },
86+/* 1 */
87+/***/ function(module, exports, __webpack_require__) {
88+
89+ module.exports = __webpack_require__(2);
90+
91+/***/ },
92+/* 2 */
93+/***/ function(module, exports, __webpack_require__) {
94+
95+ var isFactory = __webpack_require__(5).isFactory;
96+ var deepExtend = __webpack_require__(5).deepExtend;
97+ var typedFactory = __webpack_require__(6);
98+ var emitter = __webpack_require__(3);
99+
100+ var importFactory = __webpack_require__(10);
101+ var configFactory = __webpack_require__(12);
102+
103+ /**
104+ * Math.js core. Creates a new, empty math.js instance
105+ * @param {Object} [options] Available options:
106+ * {number} epsilon
107+ * Minimum relative difference between two
108+ * compared values, used by all comparison functions.
109+ * {string} matrix
110+ * A string 'matrix' (default) or 'array'.
111+ * {string} number
112+ * A string 'number' (default), 'bignumber', or 'fraction'
113+ * {number} precision
114+ * The number of significant digits for BigNumbers.
115+ * Not applicable for Numbers.
116+ * {boolean} predictable
117+ * Predictable output type of functions. When true,
118+ * output type depends only on the input types. When
119+ * false (default), output type can vary depending
120+ * on input values. For example `math.sqrt(-2)`
121+ * returns `NaN` when predictable is false, and
122+ * returns `complex('2i')` when true.
123+ * @returns {Object} Returns a bare-bone math.js instance containing
124+ * functions:
125+ * - `import` to add new functions
126+ * - `config` to change configuration
127+ * - `on`, `off`, `once`, `emit` for events
128+ */
129+ exports.create = function create (options) {
130 // simple test for ES5 support
131 if (typeof Object.create !== 'function') {
132 throw new Error('ES5 not supported by this JavaScript engine. ' +
133- 'Please load the es5-shim and es5-sham library for compatibility.');
134+ 'Please load the es5-shim and es5-sham library for compatibility.');
135 }
136
137- // create namespace
138- var math = {};
139+ // cached factories and instances
140+ var factories = [];
141+ var instances = [];
142+
143+ // create a namespace for the mathjs instance, and attach emitter functions
144+ var math = emitter.mixin({});
145+ math.type = {};
146+ math.expression = {
147+ transform: Object.create(math)
148+ };
149+
150+ // create a new typed instance
151+ math.typed = typedFactory.create(math.type);
152
153 // create configuration options. These are private
154 var _config = {
155+ // minimum relative difference between two compared values,
156+ // used by all comparison functions
157+ epsilon: 1e-14,
158+
159 // type of default matrix output. Choose 'matrix' (default) or 'array'
160 matrix: 'matrix',
161
162@@ -127,391 +203,161 @@
163 // number of significant digits in BigNumbers
164 precision: 64,
165
166- // minimum relative difference between two compared values,
167- // used by all comparison functions
168- epsilon: 1e-14
169+ // predictable output type of functions. When true, output type depends only
170+ // on the input types. When false (default), output type can vary depending
171+ // on input values. For example `math.sqrt(-2)` returns `NaN` when
172+ // predictable is false, and returns `complex('2i')` when true.
173+ predictable: false
174 };
175
176+ if (options) {
177+ // merge options
178+ deepExtend(_config, options);
179+ }
180+
181 /**
182- * Set configuration options for math.js, and get current options
183- * @param {Object} [options] Available options:
184- * {String} matrix
185- * A string 'matrix' (default) or 'array'.
186- * {String} number
187- * A string 'number' (default) or 'bignumber'
188- * {Number} precision
189- * The number of significant digits for BigNumbers.
190- * Not applicable for Numbers.
191- * @return {Object} Returns the current configuration
192+ * Load a function or data type from a factory.
193+ * If the function or data type already exists, the existing instance is
194+ * returned.
195+ * @param {{type: string, name: string, factory: Function}} factory
196+ * @returns {*}
197 */
198- math.config = function(options) {
199- if (options) {
200- // merge options
201- object.deepExtend(_config, options);
202-
203- if (options.precision) {
204- math.type.BigNumber.config({
205- precision: options.precision
206- });
207- }
208-
209- // reload the constants (they depend on option number and precision)
210- // this must be done after math.type.BigNumber.config is applied
211- __webpack_require__(4)(math, _config);
212-
213- // TODO: remove deprecated setting some day (deprecated since version 0.17.0)
214- if (options.number && options.number.defaultType) {
215- throw new Error('setting `number.defaultType` is deprecated. Use `number` instead.');
216- }
217-
218- // TODO: remove deprecated setting some day (deprecated since version 0.17.0)
219- if (options.number && options.number.precision) {
220- throw new Error('setting `number.precision` is deprecated. Use `precision` instead.');
221- }
222-
223- // TODO: remove deprecated setting some day (deprecated since version 0.17.0)
224- if (options.matrix && options.matrix.defaultType) {
225- throw new Error('setting `matrix.defaultType` is deprecated. Use `matrix` instead.');
226- }
227-
228- // TODO: remove deprecated setting some day (deprecated since version 0.15.0)
229- if (options.matrix && options.matrix['default']) {
230- throw new Error('setting `matrix.default` is deprecated. Use `matrix` instead.');
231- }
232-
233- // TODO: remove deprecated setting some day (deprecated since version 0.20.0)
234- if (options.decimals) {
235- throw new Error('setting `decimals` is deprecated. Use `precision` instead.');
236- }
237+ function load (factory) {
238+ if (!isFactory(factory)) {
239+ throw new Error('Factory object with properties `type`, `name`, and `factory` expected');
240 }
241
242- // return a clone of the settings
243- return object.clone(_config);
244- };
245-
246- /**
247- * math.js factory function. Creates a new instance of math.js
248- *
249- * @param {Object} [config] Available configuration options:
250- * {String} matrix
251- * A string 'matrix' (default) or 'array'.
252- * {String} number
253- * A string 'number' (default) or 'bignumber'
254- * {Number} precision
255- * The number of significant digits for BigNumbers.
256- * Not applicable for Numbers.
257- */
258- math.create = create;
259-
260- // create a new BigNumber factory for this instance of math.js
261- var BigNumber = __webpack_require__(5).constructor();
262-
263- /**
264- * Get a JSON representation of a BigNumber containing
265- * type information
266- * @returns {Object} Returns a JSON object structured as:
267- * `{"mathjs": "BigNumber", "value": "0.2"}`
268- */
269- BigNumber.prototype.toJSON = function () {
270- return {
271- mathjs: 'BigNumber',
272- value: this.toString()
273- };
274- };
275-
276- /**
277- * Instantiate a BigNumber from a JSON object
278- * @param {Object} json a JSON object structured as:
279- * `{"mathjs": "BigNumber", "value": "0.2"}`
280- * @return {BigNumber}
281- */
282- BigNumber.fromJSON = function (json) {
283- return new BigNumber(json.value);
284- };
285-
286- // extend BigNumber with a function clone
287- if (typeof BigNumber.prototype.clone !== 'function') {
288- /**
289- * Clone a bignumber
290- * @return {BigNumber} clone
291- */
292- BigNumber.prototype.clone = function() {
293- return this; // just return itself (a BigNumber is immutable)
294- };
295- }
296-
297- // extend BigNumber with a function convert
298- if (typeof BigNumber.convert !== 'function') {
299- /**
300- * Try to convert a Number in to a BigNumber.
301- * If the number has 15 or mor significant digits, the Number cannot be
302- * converted to BigNumber and will return the original number.
303- * @param {Number} number
304- * @return {BigNumber | Number} bignumber
305- */
306- BigNumber.convert = function(number) {
307- if (digits(number) > 15) {
308- return number;
309+ var index = factories.indexOf(factory);
310+ var instance;
311+ if (index === -1) {
312+ // doesn't yet exist
313+ if (factory.math === true) {
314+ // pass with math namespace
315+ instance = factory.factory(math.type, _config, load, math.typed, math);
316 }
317 else {
318- return new BigNumber(number);
319+ instance = factory.factory(math.type, _config, load, math.typed);
320 }
321- };
322- }
323- else {
324- throw new Error('Cannot add function convert to BigNumber: function already exists');
325- }
326-
327- // errors
328- math.error = __webpack_require__(6);
329-
330- // types (Matrix, Complex, Unit, ...)
331- math.type = {};
332- math.type.Complex = __webpack_require__(7);
333- math.type.Range = __webpack_require__(8);
334- math.type.Index = __webpack_require__(9);
335- math.type.Matrix = __webpack_require__(10)(_config);
336- math.type.Unit = __webpack_require__(11);
337- math.type.Help = __webpack_require__(12);
338- math.type.ResultSet = __webpack_require__(13);
339- math.type.BigNumber = BigNumber;
340-
341- math.collection = __webpack_require__(14)(math, _config);
342-
343- // matrix storage formats
344- math.type.CcsMatrix = __webpack_require__(15)(math, _config);
345- math.type.CrsMatrix = __webpack_require__(16)(math, _config);
346- math.type.DenseMatrix = __webpack_require__(17)(math, _config);
347-
348- // matrix storage format registry
349- math.type.Matrix._storage.ccs = math.type.CcsMatrix;
350- math.type.Matrix._storage.crs = math.type.CrsMatrix;
351- math.type.Matrix._storage.dense = math.type.DenseMatrix;
352- math.type.Matrix._storage['default'] = math.type.DenseMatrix;
353-
354- // expression (parse, Parser, nodes, docs)
355- math.expression = {};
356- math.expression.node = __webpack_require__(18);
357- math.expression.parse = __webpack_require__(19)(math, _config);
358- math.expression.Parser = __webpack_require__(20)(math, _config);
359- math.expression.docs = __webpack_require__(21);
360-
361- // serialization utilities
362- math.json = {
363- reviver: __webpack_require__(22)(math, _config)
364- };
365-
366- // functions - construction (must be defined before the rest of functions)
367- __webpack_require__(34)(math, _config);
368- __webpack_require__(35)(math, _config);
369- __webpack_require__(36)(math, _config);
370- __webpack_require__(37)(math, _config);
371- __webpack_require__(38)(math, _config);
372- __webpack_require__(39)(math, _config);
373- __webpack_require__(40)(math, _config);
374- __webpack_require__(41)(math, _config);
375- __webpack_require__(42)(math, _config);
376- __webpack_require__(43)(math, _config);
377-
378- // expression parser
379- __webpack_require__(44)(math, _config);
380- __webpack_require__(45)(math, _config);
381- __webpack_require__(46)(math, _config);
382- __webpack_require__(47)(math, _config);
383-
384- // functions - arithmetic
385- __webpack_require__(48)(math, _config);
386- __webpack_require__(49)(math, _config);
387- __webpack_require__(50)(math, _config);
388- __webpack_require__(51)(math, _config);
389- __webpack_require__(52)(math, _config);
390- __webpack_require__(53)(math, _config);
391- __webpack_require__(54)(math, _config);
392- __webpack_require__(55)(math, _config);
393- __webpack_require__(56)(math, _config);
394- __webpack_require__(57)(math, _config);
395- __webpack_require__(58)(math, _config);
396- __webpack_require__(59)(math, _config);
397- __webpack_require__(60)(math, _config);
398- __webpack_require__(61)(math, _config);
399- __webpack_require__(62)(math, _config);
400- __webpack_require__(63)(math, _config);
401- __webpack_require__(64)(math, _config);
402- __webpack_require__(65)(math, _config);
403- __webpack_require__(66)(math, _config);
404- __webpack_require__(67)(math, _config);
405- __webpack_require__(68)(math, _config);
406- __webpack_require__(69)(math, _config);
407- __webpack_require__(70)(math, _config);
408- __webpack_require__(71)(math, _config);
409- __webpack_require__(72)(math, _config);
410- __webpack_require__(73)(math, _config);
411- __webpack_require__(74)(math, _config);
412- __webpack_require__(75)(math, _config);
413- __webpack_require__(76)(math, _config);
414-
415- // functions - bitwise
416- __webpack_require__(77)(math, _config);
417- __webpack_require__(78)(math, _config);
418- __webpack_require__(79)(math, _config);
419- __webpack_require__(80)(math, _config);
420- __webpack_require__(81)(math, _config);
421- __webpack_require__(82)(math, _config);
422- __webpack_require__(83)(math, _config);
423-
424- // functions - complex
425- __webpack_require__(84)(math, _config);
426- __webpack_require__(85)(math, _config);
427- __webpack_require__(86)(math, _config);
428- __webpack_require__(87)(math, _config);
429-
430- // functions - logical
431- __webpack_require__(88)(math, _config);
432- __webpack_require__(89)(math, _config);
433- __webpack_require__(90)(math, _config);
434- __webpack_require__(91)(math, _config);
435-
436- // functions - matrix
437- __webpack_require__(92)(math, _config);
438- __webpack_require__(93)(math, _config);
439- __webpack_require__(94)(math, _config);
440- __webpack_require__(95)(math, _config);
441- __webpack_require__(96)(math, _config);
442- __webpack_require__(97)(math, _config);
443- __webpack_require__(98)(math, _config);
444- __webpack_require__(99)(math, _config);
445- __webpack_require__(100)(math, _config);
446- __webpack_require__(101)(math, _config);
447- __webpack_require__(102)(math, _config);
448- __webpack_require__(103)(math, _config);
449- __webpack_require__(104)(math, _config);
450- __webpack_require__(105)(math, _config);
451- __webpack_require__(106)(math, _config);
452- __webpack_require__(107)(math, _config);
453- __webpack_require__(108)(math, _config);
454-
455- // functions - probability
456- //require('./function/probability/distribution')(math, _config); // TODO: rethink math.distribution
457- __webpack_require__(109)(math, _config);
458- __webpack_require__(110)(math, _config);
459- __webpack_require__(111)(math, _config);
460- __webpack_require__(112)(math, _config);
461- __webpack_require__(113)(math, _config);
462- __webpack_require__(114)(math, _config);
463- __webpack_require__(115)(math, _config);
464-
465- // functions - relational
466- __webpack_require__(116)(math, _config);
467- __webpack_require__(117)(math, _config);
468- __webpack_require__(118)(math, _config);
469- __webpack_require__(119)(math, _config);
470- __webpack_require__(120)(math, _config);
471- __webpack_require__(121)(math, _config);
472- __webpack_require__(122)(math, _config);
473- __webpack_require__(123)(math, _config);
474-
475- // functions - statistics
476- __webpack_require__(124)(math, _config);
477- __webpack_require__(125)(math, _config);
478- __webpack_require__(126)(math, _config);
479- __webpack_require__(127)(math, _config);
480- __webpack_require__(128)(math, _config);
481- __webpack_require__(129)(math, _config);
482- __webpack_require__(130)(math, _config);
483- __webpack_require__(131)(math, _config);
484-
485- // functions - trigonometry
486- __webpack_require__(132)(math, _config);
487- __webpack_require__(133)(math, _config);
488- __webpack_require__(134)(math, _config);
489- __webpack_require__(135)(math, _config);
490- __webpack_require__(136)(math, _config);
491- __webpack_require__(137)(math, _config);
492- __webpack_require__(138)(math, _config);
493- __webpack_require__(139)(math, _config);
494- __webpack_require__(140)(math, _config);
495- __webpack_require__(141)(math, _config);
496- __webpack_require__(142)(math, _config);
497- __webpack_require__(143)(math, _config);
498- __webpack_require__(144)(math, _config);
499- __webpack_require__(145)(math, _config);
500- __webpack_require__(146)(math, _config);
501- __webpack_require__(147)(math, _config);
502- __webpack_require__(148)(math, _config);
503- __webpack_require__(149)(math, _config);
504- __webpack_require__(150)(math, _config);
505- __webpack_require__(151)(math, _config);
506- __webpack_require__(152)(math, _config);
507- __webpack_require__(153)(math, _config);
508- __webpack_require__(154)(math, _config);
509- __webpack_require__(155)(math, _config);
510- __webpack_require__(156)(math, _config);
511-
512- // functions - units
513- __webpack_require__(157)(math, _config);
514-
515- // functions - utils
516- __webpack_require__(158)(math, _config);
517- __webpack_require__(159)(math, _config);
518- __webpack_require__(160)(math, _config);
519- __webpack_require__(161)(math, _config);
520- __webpack_require__(162)(math, _config);
521- __webpack_require__(163)(math, _config);
522- __webpack_require__(164)(math, _config);
523- __webpack_require__(165)(math, _config);
524- __webpack_require__(166)(math, _config);
525-
526- // TODO: deprecated since version 0.25.0, remove some day.
527- math.ifElse = function () {
528- throw new Error('Function ifElse is deprecated. Use the conditional operator instead.');
529- };
530-
531- // constants
532- __webpack_require__(4)(math, _config);
533-
534- // attach transform functions (for converting one-based indices to zero-based)
535- math.expression.transform = {
536- concat: __webpack_require__(23)(math, _config),
537- filter: __webpack_require__(24)(math, _config),
538- forEach:__webpack_require__(25)(math, _config),
539- index: __webpack_require__(26)(math, _config),
540- map: __webpack_require__(27)(math, _config),
541- max: __webpack_require__(28)(math, _config),
542- mean: __webpack_require__(29)(math, _config),
543- min: __webpack_require__(30)(math, _config),
544- range: __webpack_require__(31)(math, _config),
545- subset: __webpack_require__(32)(math, _config)
546- };
547-
548- // selector (we initialize after all functions are loaded)
549- math.chaining = {};
550- math.chaining.Chain = __webpack_require__(33)(math, _config);
551- math.chaining.Selector = math.chaining.Chain; // TODO: deprecate in v2.0
552-
553- // apply provided configuration options
554- math.config(_config); // apply the default options
555- math.config(config); // apply custom options
556-
557- // return the new instance
558+
559+ // append to the cache
560+ factories.push(factory);
561+ instances.push(instance);
562+ }
563+ else {
564+ // already existing function, return the cached instance
565+ instance = instances[index];
566+ }
567+
568+ return instance;
569+ }
570+
571+ // load the import and config functions
572+ math['import'] = load(importFactory);
573+ math['config'] = load(configFactory);
574+
575 return math;
576- }
577-
578- // create a default instance of math.js
579- var math = create();
580-
581- if (typeof window !== 'undefined') {
582- window.mathjs = math; // TODO: deprecate the mathjs namespace some day (replaced with 'math' since version 0.25.0)
583- }
584-
585- // export the default instance
586- module.exports = math;
587-
588+ };
589
590
591 /***/ },
592-/* 2 */
593+/* 3 */
594 /***/ function(module, exports, __webpack_require__) {
595
596+ var Emitter = __webpack_require__(4);
597+
598+ /**
599+ * Extend given object with emitter functions `on`, `off`, `once`, `emit`
600+ * @param {Object} obj
601+ * @return {Object} obj
602+ */
603+ exports.mixin = function (obj) {
604+ // create event emitter
605+ var emitter = new Emitter();
606+
607+ // bind methods to obj (we don't want to expose the emitter.e Array...)
608+ obj.on = emitter.on.bind(emitter);
609+ obj.off = emitter.off.bind(emitter);
610+ obj.once = emitter.once.bind(emitter);
611+ obj.emit = emitter.emit.bind(emitter);
612+
613+ return obj;
614+ };
615+
616+
617+/***/ },
618+/* 4 */
619+/***/ function(module, exports) {
620+
621+ function E () {
622+ // Keep this empty so it's easier to inherit from
623+ // (via https://github.com/lipsmack from https://github.com/scottcorgan/tiny-emitter/issues/3)
624+ }
625+
626+ E.prototype = {
627+ on: function (name, callback, ctx) {
628+ var e = this.e || (this.e = {});
629+
630+ (e[name] || (e[name] = [])).push({
631+ fn: callback,
632+ ctx: ctx
633+ });
634+
635+ return this;
636+ },
637+
638+ once: function (name, callback, ctx) {
639+ var self = this;
640+ var fn = function () {
641+ self.off(name, fn);
642+ callback.apply(ctx, arguments);
643+ };
644+
645+ return this.on(name, fn, ctx);
646+ },
647+
648+ emit: function (name) {
649+ var data = [].slice.call(arguments, 1);
650+ var evtArr = ((this.e || (this.e = {}))[name] || []).slice();
651+ var i = 0;
652+ var len = evtArr.length;
653+
654+ for (i; i < len; i++) {
655+ evtArr[i].fn.apply(evtArr[i].ctx, data);
656+ }
657+
658+ return this;
659+ },
660+
661+ off: function (name, callback) {
662+ var e = this.e || (this.e = {});
663+ var evts = e[name];
664+ var liveEvents = [];
665+
666+ if (evts && callback) {
667+ for (var i = 0, len = evts.length; i < len; i++) {
668+ if (evts[i].fn !== callback) liveEvents.push(evts[i]);
669+ }
670+ }
671+
672+ // Remove event from queue to prevent memory leak
673+ // Suggested by https://github.com/lazd
674+ // Ref: https://github.com/scottcorgan/tiny-emitter/commit/c6ebfaa9bc973b33d110a84a307742b7cf94c953#commitcomment-5024910
675+
676+ (liveEvents.length)
677+ ? e[name] = liveEvents
678+ : delete e[name];
679+
680+ return this;
681+ }
682+ };
683+
684+ module.exports = E;
685+
686+
687+/***/ },
688+/* 5 */
689+/***/ function(module, exports) {
690+
691 'use strict';
692
693 /**
694@@ -546,10 +392,11 @@
695 });
696 }
697
698- if (x instanceof Number) return new Number(x.valueOf());
699- if (x instanceof String) return new String(x.valueOf());
700- if (x instanceof Boolean) return new Boolean(x.valueOf());
701- if (x instanceof Date) return new Date(x.valueOf());
702+ if (x instanceof Number) return new Number(x.valueOf());
703+ if (x instanceof String) return new String(x.valueOf());
704+ if (x instanceof Boolean) return new Boolean(x.valueOf());
705+ if (x instanceof Date) return new Date(x.valueOf());
706+ if (x && x.isBigNumber === true) return x; // bignumbers are immutable
707 if (x instanceof RegExp) throw new TypeError('Cannot clone ' + x); // TODO: clone a RegExp
708
709 // object
710@@ -667,7 +514,7 @@
711 // test needed for broken IE8 implementation
712 try {
713 if (Object.defineProperty) {
714- Object.defineProperty({}, 'x', {});
715+ Object.defineProperty({}, 'x', { get: function () {} });
716 return true;
717 }
718 } catch (e) {}
719@@ -682,7 +529,7 @@
720 * of the properties value.
721 * @param {Object} object Object where to add the property
722 * @param {string} prop Property name
723- * @param {function} fn Function returning the property value. Called
724+ * @param {Function} fn Function returning the property value. Called
725 * without arguments.
726 */
727 exports.lazy = function (object, prop, fn) {
728@@ -701,7 +548,10 @@
729 set: function (value) {
730 _value = value;
731 _uninitialized = false;
732- }
733+ },
734+
735+ configurable: true,
736+ enumerable: true
737 });
738 }
739 else {
740@@ -710,37 +560,1553 @@
741 }
742 };
743
744-
745-/***/ },
746-/* 3 */
747-/***/ function(module, exports, __webpack_require__) {
748-
749- 'use strict';
750-
751- var NumberFormatter = __webpack_require__(167);
752-
753- /**
754- * Test whether value is a Number
755+ /**
756+ * Traverse a path into an object.
757+ * When a namespace is missing, it will be created
758+ * @param {Object} object
759+ * @param {string} path A dot separated string like 'name.space'
760+ * @return {Object} Returns the object at the end of the path
761+ */
762+ exports.traverse = function(object, path) {
763+ var obj = object;
764+
765+ if (path) {
766+ var names = path.split('.');
767+ for (var i = 0; i < names.length; i++) {
768+ var name = names[i];
769+ if (!(name in obj)) {
770+ obj[name] = {};
771+ }
772+ obj = obj[name];
773+ }
774+ }
775+
776+ return obj;
777+ };
778+
779+ /**
780+ * Test whether an object is a factory. a factory has fields:
781+ *
782+ * - factory: function (type: Object, config: Object, load: function, typed: function [, math: Object]) (required)
783+ * - name: string (optional)
784+ * - path: string A dot separated path (optional)
785+ * - math: boolean If true (false by default), the math namespace is passed
786+ * as fifth argument of the factory function
787+ *
788+ * @param {*} object
789+ * @returns {boolean}
790+ */
791+ exports.isFactory = function (object) {
792+ return object && typeof object.factory === 'function';
793+ };
794+
795+
796+/***/ },
797+/* 6 */
798+/***/ function(module, exports, __webpack_require__) {
799+
800+ var typedFunction = __webpack_require__(7);
801+ var digits = __webpack_require__(8).digits;
802+
803+ // returns a new instance of typed-function
804+ var createTyped = function () {
805+ // initially, return the original instance of typed-function
806+ // consecutively, return a new instance from typed.create.
807+ createTyped = typedFunction.create;
808+ return typedFunction;
809+ };
810+
811+ /**
812+ * Factory function for creating a new typed instance
813+ * @param {Object} type Object with data types like Complex and BigNumber
814+ * @returns {Function}
815+ */
816+ exports.create = function create(type) {
817+ // TODO: typed-function must be able to silently ignore signatures with unknown data types
818+
819+ // get a new instance of typed-function
820+ var typed = createTyped();
821+
822+ // define all types. The order of the types determines in which order function
823+ // arguments are type-checked (so for performance it's important to put the
824+ // most used types first).
825+ typed.types = [
826+ { name: 'number', test: function (x) { return typeof x === 'number'; } },
827+ { name: 'Complex', test: function (x) { return x && x.isComplex; } },
828+ { name: 'BigNumber', test: function (x) { return x && x.isBigNumber; } },
829+ { name: 'Fraction', test: function (x) { return x && x.isFraction; } },
830+ { name: 'Unit', test: function (x) { return x && x.isUnit; } },
831+ { name: 'string', test: function (x) { return typeof x === 'string'; } },
832+ { name: 'Array', test: Array.isArray },
833+ { name: 'Matrix', test: function (x) { return x && x.isMatrix; } },
834+ { name: 'DenseMatrix', test: function (x) { return x && x.isDenseMatrix; } },
835+ { name: 'SparseMatrix', test: function (x) { return x && x.isSparseMatrix; } },
836+ { name: 'ImmutableDenseMatrix', test: function (x) { return x && x.isImmutableDenseMatrix; } },
837+ { name: 'Range', test: function (x) { return x && x.isRange; } },
838+ { name: 'Index', test: function (x) { return x && x.isIndex; } },
839+ { name: 'boolean', test: function (x) { return typeof x === 'boolean'; } },
840+ { name: 'ResultSet', test: function (x) { return x && x.isResultSet; } },
841+ { name: 'Help', test: function (x) { return x && x.isHelp; } },
842+ { name: 'function', test: function (x) { return typeof x === 'function';} },
843+ { name: 'Date', test: function (x) { return x instanceof Date; } },
844+ { name: 'RegExp', test: function (x) { return x instanceof RegExp; } },
845+ { name: 'Object', test: function (x) { return typeof x === 'object'; } },
846+ { name: 'null', test: function (x) { return x === null; } },
847+ { name: 'undefined', test: function (x) { return x === undefined; } }
848+ ];
849+
850+ // TODO: add conversion from BigNumber to number?
851+ typed.conversions = [
852+ {
853+ from: 'number',
854+ to: 'BigNumber',
855+ convert: function (x) {
856+ // note: conversion from number to BigNumber can fail if x has >15 digits
857+ if (digits(x) > 15) {
858+ throw new TypeError('Cannot implicitly convert a number with >15 significant digits to BigNumber ' +
859+ '(value: ' + x + '). ' +
860+ 'Use function bignumber(x) to convert to BigNumber.');
861+ }
862+ return new type.BigNumber(x);
863+ }
864+ }, {
865+ from: 'number',
866+ to: 'Complex',
867+ convert: function (x) {
868+ return new type.Complex(x, 0);
869+ }
870+ }, {
871+ from: 'number',
872+ to: 'string',
873+ convert: function (x) {
874+ return x + '';
875+ }
876+ }, {
877+ from: 'BigNumber',
878+ to: 'Complex',
879+ convert: function (x) {
880+ return new type.Complex(x.toNumber(), 0);
881+ }
882+ }, {
883+ from: 'number',
884+ to: 'Fraction',
885+ convert: function (x) {
886+ if (digits(x) > 15) {
887+ throw new TypeError('Cannot implicitly convert a number with >15 significant digits to Fraction ' +
888+ '(value: ' + x + '). ' +
889+ 'Use function fraction(x) to convert to Fraction.');
890+ }
891+ return new type.Fraction(x);
892+ }
893+ }, {
894+ from: 'string',
895+ to: 'number',
896+ convert: function (x) {
897+ var n = Number(x);
898+ if (isNaN(n)) {
899+ throw new Error('Cannot convert "' + x + '" to a number');
900+ }
901+ return n;
902+ }
903+ }, {
904+ from: 'boolean',
905+ to: 'number',
906+ convert: function (x) {
907+ return +x;
908+ }
909+ }, {
910+ from: 'boolean',
911+ to: 'BigNumber',
912+ convert: function (x) {
913+ return new type.BigNumber(+x);
914+ }
915+ }, {
916+ from: 'boolean',
917+ to: 'string',
918+ convert: function (x) {
919+ return +x;
920+ }
921+ }, {
922+ from: 'null',
923+ to: 'number',
924+ convert: function () {
925+ return 0;
926+ }
927+ }, {
928+ from: 'null',
929+ to: 'string',
930+ convert: function () {
931+ return 'null';
932+ }
933+ }, {
934+ from: 'null',
935+ to: 'BigNumber',
936+ convert: function () {
937+ return new type.BigNumber(0);
938+ }
939+ }, {
940+ from: 'Array',
941+ to: 'Matrix',
942+ convert: function (array) {
943+ // TODO: how to decide on the right type of matrix to create?
944+ return new type.DenseMatrix(array);
945+ }
946+ }, {
947+ from: 'Matrix',
948+ to: 'Array',
949+ convert: function (matrix) {
950+ return matrix.valueOf();
951+ }
952+ }
953+ ];
954+
955+ return typed;
956+ };
957+
958+
959+/***/ },
960+/* 7 */
961+/***/ function(module, exports, __webpack_require__) {
962+
963+ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;/**
964+ * typed-function
965+ *
966+ * Type checking for JavaScript functions
967+ *
968+ * https://github.com/josdejong/typed-function
969+ */
970+ 'use strict';
971+
972+ (function (factory) {
973+ if (true) {
974+ // AMD. Register as an anonymous module.
975+ !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_FACTORY__ = (factory), __WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ? (__WEBPACK_AMD_DEFINE_FACTORY__.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__)) : __WEBPACK_AMD_DEFINE_FACTORY__), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
976+ } else if (typeof exports === 'object') {
977+ // OldNode. Does not work with strict CommonJS, but
978+ // only CommonJS-like environments that support module.exports,
979+ // like OldNode.
980+ module.exports = factory();
981+ } else {
982+ // Browser globals (root is window)
983+ window.typed = factory();
984+ }
985+ }(function () {
986+ // factory function to create a new instance of typed-function
987+ // TODO: allow passing configuration, types, tests via the factory function
988+ function create() {
989+ /**
990+ * Get a type test function for a specific data type
991+ * @param {string} name Name of a data type like 'number' or 'string'
992+ * @returns {Function(obj: *) : boolean} Returns a type testing function.
993+ * Throws an error for an unknown type.
994+ */
995+ function getTypeTest(name) {
996+ var test;
997+ for (var i = 0; i < typed.types.length; i++) {
998+ var entry = typed.types[i];
999+ if (entry.name === name) {
1000+ test = entry.test;
1001+ break;
1002+ }
1003+ }
1004+
1005+ if (!test) {
1006+ var hint;
1007+ for (i = 0; i < typed.types.length; i++) {
1008+ entry = typed.types[i];
1009+ if (entry.name.toLowerCase() == name.toLowerCase()) {
1010+ hint = entry.name;
1011+ break;
1012+ }
1013+ }
1014+
1015+ throw new Error('Unknown type "' + name + '"' +
1016+ (hint ? ('. Did you mean "' + hint + '"?') : ''));
1017+ }
1018+ return test;
1019+ }
1020+
1021+ /**
1022+ * Retrieve the function name from a set of functions, and check
1023+ * whether the name of all functions match (if given)
1024+ * @param {Array.<function>} fns
1025+ */
1026+ function getName (fns) {
1027+ var name = '';
1028+
1029+ for (var i = 0; i < fns.length; i++) {
1030+ var fn = fns[i];
1031+
1032+ // merge function name
1033+ if (fn.name != '') {
1034+ if (name == '') {
1035+ name = fn.name;
1036+ }
1037+ else if (name != fn.name) {
1038+ var err = new Error('Function names do not match (expected: ' + name + ', actual: ' + fn.name + ')');
1039+ err.data = {
1040+ actual: fn.name,
1041+ expected: name
1042+ };
1043+ throw err;
1044+ }
1045+ }
1046+ }
1047+
1048+ return name;
1049+ }
1050+
1051+ /**
1052+ * Create an ArgumentsError. Creates messages like:
1053+ *
1054+ * Unexpected type of argument (expected: ..., actual: ..., index: ...)
1055+ * Too few arguments (expected: ..., index: ...)
1056+ * Too many arguments (expected: ..., actual: ...)
1057+ *
1058+ * @param {String} fn Function name
1059+ * @param {number} argCount Number of arguments
1060+ * @param {Number} index Current argument index
1061+ * @param {*} actual Current argument
1062+ * @param {string} [expected] An optional, comma separated string with
1063+ * expected types on given index
1064+ * @extends Error
1065+ */
1066+ function createError(fn, argCount, index, actual, expected) {
1067+ var actualType = getTypeOf(actual);
1068+ var _expected = expected ? expected.split(',') : null;
1069+ var _fn = (fn || 'unnamed');
1070+ var anyType = _expected && contains(_expected, 'any');
1071+ var message;
1072+ var data = {
1073+ fn: fn,
1074+ index: index,
1075+ actual: actual,
1076+ expected: _expected
1077+ };
1078+
1079+ if (_expected) {
1080+ if (argCount > index && !anyType) {
1081+ // unexpected type
1082+ message = 'Unexpected type of argument in function ' + _fn +
1083+ ' (expected: ' + _expected.join(' or ') + ', actual: ' + actualType + ', index: ' + index + ')';
1084+ }
1085+ else {
1086+ // too few arguments
1087+ message = 'Too few arguments in function ' + _fn +
1088+ ' (expected: ' + _expected.join(' or ') + ', index: ' + index + ')';
1089+ }
1090+ }
1091+ else {
1092+ // too many arguments
1093+ message = 'Too many arguments in function ' + _fn +
1094+ ' (expected: ' + index + ', actual: ' + argCount + ')'
1095+ }
1096+
1097+ var err = new TypeError(message);
1098+ err.data = data;
1099+ return err;
1100+ }
1101+
1102+ /**
1103+ * Collection with function references (local shortcuts to functions)
1104+ * @constructor
1105+ * @param {string} [name='refs'] Optional name for the refs, used to generate
1106+ * JavaScript code
1107+ */
1108+ function Refs(name) {
1109+ this.name = name || 'refs';
1110+ this.categories = {};
1111+ }
1112+
1113+ /**
1114+ * Add a function reference.
1115+ * @param {Function} fn
1116+ * @param {string} [category='fn'] A function category, like 'fn' or 'signature'
1117+ * @returns {string} Returns the function name, for example 'fn0' or 'signature2'
1118+ */
1119+ Refs.prototype.add = function (fn, category) {
1120+ var cat = category || 'fn';
1121+ if (!this.categories[cat]) this.categories[cat] = [];
1122+
1123+ var index = this.categories[cat].indexOf(fn);
1124+ if (index == -1) {
1125+ index = this.categories[cat].length;
1126+ this.categories[cat].push(fn);
1127+ }
1128+
1129+ return cat + index;
1130+ };
1131+
1132+ /**
1133+ * Create code lines for all function references
1134+ * @returns {string} Returns the code containing all function references
1135+ */
1136+ Refs.prototype.toCode = function () {
1137+ var code = [];
1138+ var path = this.name + '.categories';
1139+ var categories = this.categories;
1140+
1141+ for (var cat in categories) {
1142+ if (categories.hasOwnProperty(cat)) {
1143+ var category = categories[cat];
1144+
1145+ for (var i = 0; i < category.length; i++) {
1146+ code.push('var ' + cat + i + ' = ' + path + '[\'' + cat + '\'][' + i + '];');
1147+ }
1148+ }
1149+ }
1150+
1151+ return code.join('\n');
1152+ };
1153+
1154+ /**
1155+ * A function parameter
1156+ * @param {string | string[] | Param} types A parameter type like 'string',
1157+ * 'number | boolean'
1158+ * @param {boolean} [varArgs=false] Variable arguments if true
1159+ * @constructor
1160+ */
1161+ function Param(types, varArgs) {
1162+ // parse the types, can be a string with types separated by pipe characters |
1163+ if (typeof types === 'string') {
1164+ // parse variable arguments operator (ellipses '...number')
1165+ var _types = types.trim();
1166+ var _varArgs = _types.substr(0, 3) === '...';
1167+ if (_varArgs) {
1168+ _types = _types.substr(3);
1169+ }
1170+ if (_types === '') {
1171+ this.types = ['any'];
1172+ }
1173+ else {
1174+ this.types = _types.split('|');
1175+ for (var i = 0; i < this.types.length; i++) {
1176+ this.types[i] = this.types[i].trim();
1177+ }
1178+ }
1179+ }
1180+ else if (Array.isArray(types)) {
1181+ this.types = types;
1182+ }
1183+ else if (types instanceof Param) {
1184+ return types.clone();
1185+ }
1186+ else {
1187+ throw new Error('String or Array expected');
1188+ }
1189+
1190+ // can hold a type to which to convert when handling this parameter
1191+ this.conversions = [];
1192+ // TODO: implement better API for conversions, be able to add conversions via constructor (support a new type Object?)
1193+
1194+ // variable arguments
1195+ this.varArgs = _varArgs || varArgs || false;
1196+
1197+ // check for any type arguments
1198+ this.anyType = this.types.indexOf('any') !== -1;
1199+ }
1200+
1201+ /**
1202+ * Order Params
1203+ * any type ('any') will be ordered last, and object as second last (as other
1204+ * types may be an object as well, like Array).
1205+ *
1206+ * @param {Param} a
1207+ * @param {Param} b
1208+ * @returns {number} Returns 1 if a > b, -1 if a < b, and else 0.
1209+ */
1210+ Param.compare = function (a, b) {
1211+ // TODO: simplify parameter comparison, it's a mess
1212+ if (a.anyType) return 1;
1213+ if (b.anyType) return -1;
1214+
1215+ if (contains(a.types, 'Object')) return 1;
1216+ if (contains(b.types, 'Object')) return -1;
1217+
1218+ if (a.hasConversions()) {
1219+ if (b.hasConversions()) {
1220+ var i, ac, bc;
1221+
1222+ for (i = 0; i < a.conversions.length; i++) {
1223+ if (a.conversions[i] !== undefined) {
1224+ ac = a.conversions[i];
1225+ break;
1226+ }
1227+ }
1228+
1229+ for (i = 0; i < b.conversions.length; i++) {
1230+ if (b.conversions[i] !== undefined) {
1231+ bc = b.conversions[i];
1232+ break;
1233+ }
1234+ }
1235+
1236+ return typed.conversions.indexOf(ac) - typed.conversions.indexOf(bc);
1237+ }
1238+ else {
1239+ return 1;
1240+ }
1241+ }
1242+ else {
1243+ if (b.hasConversions()) {
1244+ return -1;
1245+ }
1246+ else {
1247+ // both params have no conversions
1248+ var ai, bi;
1249+
1250+ for (i = 0; i < typed.types.length; i++) {
1251+ if (typed.types[i].name === a.types[0]) {
1252+ ai = i;
1253+ break;
1254+ }
1255+ }
1256+
1257+ for (i = 0; i < typed.types.length; i++) {
1258+ if (typed.types[i].name === b.types[0]) {
1259+ bi = i;
1260+ break;
1261+ }
1262+ }
1263+
1264+ return ai - bi;
1265+ }
1266+ }
1267+ };
1268+
1269+ /**
1270+ * Test whether this parameters types overlap an other parameters types.
1271+ * @param {Param} other
1272+ * @return {boolean} Returns true when there are conflicting types
1273+ */
1274+ Param.prototype.overlapping = function (other) {
1275+ for (var i = 0; i < this.types.length; i++) {
1276+ if (contains(other.types, this.types[i])) {
1277+ return true;
1278+ }
1279+ }
1280+ return false;
1281+ };
1282+
1283+ /**
1284+ * Create a clone of this param
1285+ * @returns {Param} Returns a cloned version of this param
1286+ */
1287+ Param.prototype.clone = function () {
1288+ var param = new Param(this.types.slice(), this.varArgs);
1289+ param.conversions = this.conversions.slice();
1290+ return param;
1291+ };
1292+
1293+ /**
1294+ * Test whether this parameter contains conversions
1295+ * @returns {boolean} Returns true if the parameter contains one or
1296+ * multiple conversions.
1297+ */
1298+ Param.prototype.hasConversions = function () {
1299+ return this.conversions.length > 0;
1300+ };
1301+
1302+ /**
1303+ * Tests whether this parameters contains any of the provided types
1304+ * @param {Object} types A Map with types, like {'number': true}
1305+ * @returns {boolean} Returns true when the parameter contains any
1306+ * of the provided types
1307+ */
1308+ Param.prototype.contains = function (types) {
1309+ for (var i = 0; i < this.types.length; i++) {
1310+ if (types[this.types[i]]) {
1311+ return true;
1312+ }
1313+ }
1314+ return false;
1315+ };
1316+
1317+ /**
1318+ * Return a string representation of this params types, like 'string' or
1319+ * 'number | boolean' or '...number'
1320+ * @param {boolean} [toConversion] If true, the returned types string
1321+ * contains the types where the parameter
1322+ * will convert to. If false (default)
1323+ * the "from" types are returned
1324+ * @returns {string}
1325+ */
1326+ Param.prototype.toString = function (toConversion) {
1327+ var types = [];
1328+ var keys = {};
1329+
1330+ for (var i = 0; i < this.types.length; i++) {
1331+ var conversion = this.conversions[i];
1332+ var type = toConversion && conversion ? conversion.to : this.types[i];
1333+ if (!(type in keys)) {
1334+ keys[type] = true;
1335+ types.push(type);
1336+ }
1337+ }
1338+
1339+ return (this.varArgs ? '...' : '') + types.join('|');
1340+ };
1341+
1342+ /**
1343+ * A function signature
1344+ * @param {string | string[] | Param[]} params
1345+ * Array with the type(s) of each parameter,
1346+ * or a comma separated string with types
1347+ * @param {Function} fn The actual function
1348+ * @constructor
1349+ */
1350+ function Signature(params, fn) {
1351+ var _params;
1352+ if (typeof params === 'string') {
1353+ _params = (params !== '') ? params.split(',') : [];
1354+ }
1355+ else if (Array.isArray(params)) {
1356+ _params = params;
1357+ }
1358+ else {
1359+ throw new Error('string or Array expected');
1360+ }
1361+
1362+ this.params = new Array(_params.length);
1363+ for (var i = 0; i < _params.length; i++) {
1364+ var param = new Param(_params[i]);
1365+ this.params[i] = param;
1366+ if (i === _params.length - 1) {
1367+ // the last argument
1368+ this.varArgs = param.varArgs;
1369+ }
1370+ else {
1371+ // non-last argument
1372+ if (param.varArgs) {
1373+ throw new SyntaxError('Unexpected variable arguments operator "..."');
1374+ }
1375+ }
1376+ }
1377+
1378+ this.fn = fn;
1379+ }
1380+
1381+ /**
1382+ * Create a clone of this signature
1383+ * @returns {Signature} Returns a cloned version of this signature
1384+ */
1385+ Signature.prototype.clone = function () {
1386+ return new Signature(this.params.slice(), this.fn);
1387+ };
1388+
1389+ /**
1390+ * Expand a signature: split params with union types in separate signatures
1391+ * For example split a Signature "string | number" into two signatures.
1392+ * @return {Signature[]} Returns an array with signatures (at least one)
1393+ */
1394+ Signature.prototype.expand = function () {
1395+ var signatures = [];
1396+
1397+ function recurse(signature, path) {
1398+ if (path.length < signature.params.length) {
1399+ var i, newParam, conversion;
1400+
1401+ var param = signature.params[path.length];
1402+ if (param.varArgs) {
1403+ // a variable argument. do not split the types in the parameter
1404+ newParam = param.clone();
1405+
1406+ // add conversions to the parameter
1407+ // recurse for all conversions
1408+ for (i = 0; i < typed.conversions.length; i++) {
1409+ conversion = typed.conversions[i];
1410+ if (!contains(param.types, conversion.from) && contains(param.types, conversion.to)) {
1411+ var j = newParam.types.length;
1412+ newParam.types[j] = conversion.from;
1413+ newParam.conversions[j] = conversion;
1414+ }
1415+ }
1416+
1417+ recurse(signature, path.concat(newParam));
1418+ }
1419+ else {
1420+ // split each type in the parameter
1421+ for (i = 0; i < param.types.length; i++) {
1422+ recurse(signature, path.concat(new Param(param.types[i])));
1423+ }
1424+
1425+ // recurse for all conversions
1426+ for (i = 0; i < typed.conversions.length; i++) {
1427+ conversion = typed.conversions[i];
1428+ if (!contains(param.types, conversion.from) && contains(param.types, conversion.to)) {
1429+ newParam = new Param(conversion.from);
1430+ newParam.conversions[0] = conversion;
1431+ recurse(signature, path.concat(newParam));
1432+ }
1433+ }
1434+ }
1435+ }
1436+ else {
1437+ signatures.push(new Signature(path, signature.fn));
1438+ }
1439+ }
1440+
1441+ recurse(this, []);
1442+
1443+ return signatures;
1444+ };
1445+
1446+ /**
1447+ * Compare two signatures.
1448+ *
1449+ * When two params are equal and contain conversions, they will be sorted
1450+ * by lowest index of the first conversions.
1451+ *
1452+ * @param {Signature} a
1453+ * @param {Signature} b
1454+ * @returns {number} Returns 1 if a > b, -1 if a < b, and else 0.
1455+ */
1456+ Signature.compare = function (a, b) {
1457+ if (a.params.length > b.params.length) return 1;
1458+ if (a.params.length < b.params.length) return -1;
1459+
1460+ // count the number of conversions
1461+ var i;
1462+ var len = a.params.length; // a and b have equal amount of params
1463+ var ac = 0;
1464+ var bc = 0;
1465+ for (i = 0; i < len; i++) {
1466+ if (a.params[i].hasConversions()) ac++;
1467+ if (b.params[i].hasConversions()) bc++;
1468+ }
1469+
1470+ if (ac > bc) return 1;
1471+ if (ac < bc) return -1;
1472+
1473+ // compare the order per parameter
1474+ for (i = 0; i < a.params.length; i++) {
1475+ var cmp = Param.compare(a.params[i], b.params[i]);
1476+ if (cmp !== 0) {
1477+ return cmp;
1478+ }
1479+ }
1480+
1481+ return 0;
1482+ };
1483+
1484+ /**
1485+ * Test whether any of the signatures parameters has conversions
1486+ * @return {boolean} Returns true when any of the parameters contains
1487+ * conversions.
1488+ */
1489+ Signature.prototype.hasConversions = function () {
1490+ for (var i = 0; i < this.params.length; i++) {
1491+ if (this.params[i].hasConversions()) {
1492+ return true;
1493+ }
1494+ }
1495+ return false;
1496+ };
1497+
1498+ /**
1499+ * Test whether this signature should be ignored.
1500+ * Checks whether any of the parameters contains a type listed in
1501+ * typed.ignore
1502+ * @return {boolean} Returns true when the signature should be ignored
1503+ */
1504+ Signature.prototype.ignore = function () {
1505+ // create a map with ignored types
1506+ var types = {};
1507+ for (var i = 0; i < typed.ignore.length; i++) {
1508+ types[typed.ignore[i]] = true;
1509+ }
1510+
1511+ // test whether any of the parameters contains this type
1512+ for (i = 0; i < this.params.length; i++) {
1513+ if (this.params[i].contains(types)) {
1514+ return true;
1515+ }
1516+ }
1517+
1518+ return false;
1519+ };
1520+
1521+ /**
1522+ * Generate the code to invoke this signature
1523+ * @param {Refs} refs
1524+ * @param {string} prefix
1525+ * @returns {string} Returns code
1526+ */
1527+ Signature.prototype.toCode = function (refs, prefix) {
1528+ var code = [];
1529+
1530+ var args = new Array(this.params.length);
1531+ for (var i = 0; i < this.params.length; i++) {
1532+ var param = this.params[i];
1533+ var conversion = param.conversions[0];
1534+ if (param.varArgs) {
1535+ args[i] = 'varArgs';
1536+ }
1537+ else if (conversion) {
1538+ args[i] = refs.add(conversion.convert, 'convert') + '(arg' + i + ')';
1539+ }
1540+ else {
1541+ args[i] = 'arg' + i;
1542+ }
1543+ }
1544+
1545+ var ref = this.fn ? refs.add(this.fn, 'signature') : undefined;
1546+ if (ref) {
1547+ return prefix + 'return ' + ref + '(' + args.join(', ') + '); // signature: ' + this.params.join(', ');
1548+ }
1549+
1550+ return code.join('\n');
1551+ };
1552+
1553+ /**
1554+ * Return a string representation of the signature
1555+ * @returns {string}
1556+ */
1557+ Signature.prototype.toString = function () {
1558+ return this.params.join(', ');
1559+ };
1560+
1561+ /**
1562+ * A group of signatures with the same parameter on given index
1563+ * @param {Param[]} path
1564+ * @param {Signature} [signature]
1565+ * @param {Node[]} childs
1566+ * @constructor
1567+ */
1568+ function Node(path, signature, childs) {
1569+ this.path = path || [];
1570+ this.param = path[path.length - 1] || null;
1571+ this.signature = signature || null;
1572+ this.childs = childs || [];
1573+ }
1574+
1575+ /**
1576+ * Generate code for this group of signatures
1577+ * @param {Refs} refs
1578+ * @param {string} prefix
1579+ * @param {Node | undefined} [anyType] Sibling of this node with any type parameter
1580+ * @returns {string} Returns the code as string
1581+ */
1582+ Node.prototype.toCode = function (refs, prefix, anyType) {
1583+ // TODO: split this function in multiple functions, it's too large
1584+ var code = [];
1585+
1586+ if (this.param) {
1587+ var index = this.path.length - 1;
1588+ var conversion = this.param.conversions[0];
1589+ var comment = '// type: ' + (conversion ?
1590+ (conversion.from + ' (convert to ' + conversion.to + ')') :
1591+ this.param);
1592+
1593+ // non-root node (path is non-empty)
1594+ if (this.param.varArgs) {
1595+ if (this.param.anyType) {
1596+ // variable arguments with any type
1597+ code.push(prefix + 'if (arguments.length > ' + index + ') {');
1598+ code.push(prefix + ' var varArgs = [];');
1599+ code.push(prefix + ' for (var i = ' + index + '; i < arguments.length; i++) {');
1600+ code.push(prefix + ' varArgs.push(arguments[i]);');
1601+ code.push(prefix + ' }');
1602+ code.push(this.signature.toCode(refs, prefix + ' '));
1603+ code.push(prefix + '}');
1604+ }
1605+ else {
1606+ // variable arguments with a fixed type
1607+ var getTests = function (types, arg) {
1608+ var tests = [];
1609+ for (var i = 0; i < types.length; i++) {
1610+ tests[i] = refs.add(getTypeTest(types[i]), 'test') + '(' + arg + ')';
1611+ }
1612+ return tests.join(' || ');
1613+ }.bind(this);
1614+
1615+ var allTypes = this.param.types;
1616+ var exactTypes = [];
1617+ for (var i = 0; i < allTypes.length; i++) {
1618+ if (this.param.conversions[i] === undefined) {
1619+ exactTypes.push(allTypes[i]);
1620+ }
1621+ }
1622+
1623+ code.push(prefix + 'if (' + getTests(allTypes, 'arg' + index) + ') { ' + comment);
1624+ code.push(prefix + ' var varArgs = [arg' + index + '];');
1625+ code.push(prefix + ' for (var i = ' + (index + 1) + '; i < arguments.length; i++) {');
1626+ code.push(prefix + ' if (' + getTests(exactTypes, 'arguments[i]') + ') {');
1627+ code.push(prefix + ' varArgs.push(arguments[i]);');
1628+
1629+ for (var i = 0; i < allTypes.length; i++) {
1630+ var conversion_i = this.param.conversions[i];
1631+ if (conversion_i) {
1632+ var test = refs.add(getTypeTest(allTypes[i]), 'test');
1633+ var convert = refs.add(conversion_i.convert, 'convert');
1634+ code.push(prefix + ' }');
1635+ code.push(prefix + ' else if (' + test + '(arguments[i])) {');
1636+ code.push(prefix + ' varArgs.push(' + convert + '(arguments[i]));');
1637+ }
1638+ }
1639+ code.push(prefix + ' } else {');
1640+ code.push(prefix + ' throw createError(name, arguments.length, i, arguments[i], \'' + exactTypes.join(',') + '\');');
1641+ code.push(prefix + ' }');
1642+ code.push(prefix + ' }');
1643+ code.push(this.signature.toCode(refs, prefix + ' '));
1644+ code.push(prefix + '}');
1645+ }
1646+ }
1647+ else {
1648+ if (this.param.anyType) {
1649+ // any type
1650+ code.push(prefix + '// type: any');
1651+ code.push(this._innerCode(refs, prefix, anyType));
1652+ }
1653+ else {
1654+ // regular type
1655+ var type = this.param.types[0];
1656+ var test = type !== 'any' ? refs.add(getTypeTest(type), 'test') : null;
1657+
1658+ code.push(prefix + 'if (' + test + '(arg' + index + ')) { ' + comment);
1659+ code.push(this._innerCode(refs, prefix + ' ', anyType));
1660+ code.push(prefix + '}');
1661+ }
1662+ }
1663+ }
1664+ else {
1665+ // root node (path is empty)
1666+ code.push(this._innerCode(refs, prefix, anyType));
1667+ }
1668+
1669+ return code.join('\n');
1670+ };
1671+
1672+ /**
1673+ * Generate inner code for this group of signatures.
1674+ * This is a helper function of Node.prototype.toCode
1675+ * @param {Refs} refs
1676+ * @param {string} prefix
1677+ * @param {Node | undefined} [anyType] Sibling of this node with any type parameter
1678+ * @returns {string} Returns the inner code as string
1679+ * @private
1680+ */
1681+ Node.prototype._innerCode = function (refs, prefix, anyType) {
1682+ var code = [];
1683+ var i;
1684+
1685+ if (this.signature) {
1686+ code.push(prefix + 'if (arguments.length === ' + this.path.length + ') {');
1687+ code.push(this.signature.toCode(refs, prefix + ' '));
1688+ code.push(prefix + '}');
1689+ }
1690+
1691+ var nextAnyType;
1692+ for (i = 0; i < this.childs.length; i++) {
1693+ if (this.childs[i].param.anyType) {
1694+ nextAnyType = this.childs[i];
1695+ break;
1696+ }
1697+ }
1698+
1699+ for (i = 0; i < this.childs.length; i++) {
1700+ code.push(this.childs[i].toCode(refs, prefix, nextAnyType));
1701+ }
1702+
1703+ if (anyType && !this.param.anyType) {
1704+ code.push(anyType.toCode(refs, prefix, nextAnyType));
1705+ }
1706+
1707+ var exceptions = this._exceptions(refs, prefix);
1708+ if (exceptions) {
1709+ code.push(exceptions);
1710+ }
1711+
1712+ return code.join('\n');
1713+ };
1714+
1715+ /**
1716+ * Generate code to throw exceptions
1717+ * @param {Refs} refs
1718+ * @param {string} prefix
1719+ * @returns {string} Returns the inner code as string
1720+ * @private
1721+ */
1722+ Node.prototype._exceptions = function (refs, prefix) {
1723+ var index = this.path.length;
1724+
1725+ if (this.childs.length === 0) {
1726+ // TODO: can this condition be simplified? (we have a fall-through here)
1727+ return [
1728+ prefix + 'if (arguments.length > ' + index + ') {',
1729+ prefix + ' throw createError(name, arguments.length, ' + index + ', arguments[' + index + ']);',
1730+ prefix + '}'
1731+ ].join('\n');
1732+ }
1733+ else {
1734+ var keys = {};
1735+ var types = [];
1736+
1737+ for (var i = 0; i < this.childs.length; i++) {
1738+ var node = this.childs[i];
1739+ if (node.param) {
1740+ for (var j = 0; j < node.param.types.length; j++) {
1741+ var type = node.param.types[j];
1742+ if (!(type in keys) && !node.param.conversions[j]) {
1743+ keys[type] = true;
1744+ types.push(type);
1745+ }
1746+ }
1747+ }
1748+ }
1749+
1750+ return prefix + 'throw createError(name, arguments.length, ' + index + ', arguments[' + index + '], \'' + types.join(',') + '\');';
1751+ }
1752+ };
1753+
1754+ /**
1755+ * Split all raw signatures into an array with expanded Signatures
1756+ * @param {Object.<string, Function>} rawSignatures
1757+ * @return {Signature[]} Returns an array with expanded signatures
1758+ */
1759+ function parseSignatures(rawSignatures) {
1760+ // FIXME: need to have deterministic ordering of signatures, do not create via object
1761+ var signature;
1762+ var keys = {};
1763+ var signatures = [];
1764+ var i;
1765+
1766+ for (var types in rawSignatures) {
1767+ if (rawSignatures.hasOwnProperty(types)) {
1768+ var fn = rawSignatures[types];
1769+ signature = new Signature(types, fn);
1770+
1771+ if (signature.ignore()) {
1772+ continue;
1773+ }
1774+
1775+ var expanded = signature.expand();
1776+
1777+ for (i = 0; i < expanded.length; i++) {
1778+ var signature_i = expanded[i];
1779+ var key = signature_i.toString();
1780+ var existing = keys[key];
1781+ if (!existing) {
1782+ keys[key] = signature_i;
1783+ }
1784+ else {
1785+ var cmp = Signature.compare(signature_i, existing);
1786+ if (cmp < 0) {
1787+ // override if sorted first
1788+ keys[key] = signature_i;
1789+ }
1790+ else if (cmp === 0) {
1791+ throw new Error('Signature "' + key + '" is defined twice');
1792+ }
1793+ // else: just ignore
1794+ }
1795+ }
1796+ }
1797+ }
1798+
1799+ // convert from map to array
1800+ for (key in keys) {
1801+ if (keys.hasOwnProperty(key)) {
1802+ signatures.push(keys[key]);
1803+ }
1804+ }
1805+
1806+ // order the signatures
1807+ signatures.sort(function (a, b) {
1808+ return Signature.compare(a, b);
1809+ });
1810+
1811+ // filter redundant conversions from signatures with varArgs
1812+ // TODO: simplify this loop or move it to a separate function
1813+ for (i = 0; i < signatures.length; i++) {
1814+ signature = signatures[i];
1815+
1816+ if (signature.varArgs) {
1817+ var index = signature.params.length - 1;
1818+ var param = signature.params[index];
1819+
1820+ var t = 0;
1821+ while (t < param.types.length) {
1822+ if (param.conversions[t]) {
1823+ var type = param.types[t];
1824+
1825+ for (var j = 0; j < signatures.length; j++) {
1826+ var other = signatures[j];
1827+ var p = other.params[index];
1828+
1829+ if (other !== signature &&
1830+ p &&
1831+ contains(p.types, type) && !p.conversions[index]) {
1832+ // this (conversion) type already exists, remove it
1833+ param.types.splice(t, 1);
1834+ param.conversions.splice(t, 1);
1835+ t--;
1836+ break;
1837+ }
1838+ }
1839+ }
1840+ t++;
1841+ }
1842+ }
1843+ }
1844+
1845+ return signatures;
1846+ }
1847+
1848+ /**
1849+ * create a map with normalized signatures as key and the function as value
1850+ * @param {Signature[]} signatures An array with split signatures
1851+ * @return {Object.<string, Function>} Returns a map with normalized
1852+ * signatures as key, and the function
1853+ * as value.
1854+ */
1855+ function mapSignatures(signatures) {
1856+ var normalized = {};
1857+
1858+ for (var i = 0; i < signatures.length; i++) {
1859+ var signature = signatures[i];
1860+ if (signature.fn && !signature.hasConversions()) {
1861+ var params = signature.params.join(',');
1862+ normalized[params] = signature.fn;
1863+ }
1864+ }
1865+
1866+ return normalized;
1867+ }
1868+
1869+ /**
1870+ * Parse signatures recursively in a node tree.
1871+ * @param {Signature[]} signatures Array with expanded signatures
1872+ * @param {Param[]} path Traversed path of parameter types
1873+ * @return {Node} Returns a node tree
1874+ */
1875+ function parseTree(signatures, path) {
1876+ var i, signature;
1877+ var index = path.length;
1878+ var nodeSignature;
1879+
1880+ var filtered = [];
1881+ for (i = 0; i < signatures.length; i++) {
1882+ signature = signatures[i];
1883+
1884+ // filter the first signature with the correct number of params
1885+ if (signature.params.length === index && !nodeSignature) {
1886+ nodeSignature = signature;
1887+ }
1888+
1889+ if (signature.params[index] != undefined) {
1890+ filtered.push(signature);
1891+ }
1892+ }
1893+
1894+ // sort the filtered signatures by param
1895+ filtered.sort(function (a, b) {
1896+ return Param.compare(a.params[index], b.params[index]);
1897+ });
1898+
1899+ // recurse over the signatures
1900+ var entries = [];
1901+ for (i = 0; i < filtered.length; i++) {
1902+ signature = filtered[i];
1903+ // group signatures with the same param at current index
1904+ var param = signature.params[index];
1905+
1906+ // TODO: replace the next filter loop
1907+ var existing = entries.filter(function (entry) {
1908+ return entry.param.overlapping(param);
1909+ })[0];
1910+
1911+ //var existing;
1912+ //for (var j = 0; j < entries.length; j++) {
1913+ // if (entries[j].param.overlapping(param)) {
1914+ // existing = entries[j];
1915+ // break;
1916+ // }
1917+ //}
1918+
1919+ if (existing) {
1920+ if (existing.param.varArgs) {
1921+ throw new Error('Conflicting types "' + existing.param + '" and "' + param + '"');
1922+ }
1923+ existing.signatures.push(signature);
1924+ }
1925+ else {
1926+ entries.push({
1927+ param: param,
1928+ signatures: [signature]
1929+ });
1930+ }
1931+ }
1932+
1933+ // parse the childs
1934+ var childs = new Array(entries.length);
1935+ for (i = 0; i < entries.length; i++) {
1936+ var entry = entries[i];
1937+ childs[i] = parseTree(entry.signatures, path.concat(entry.param))
1938+ }
1939+
1940+ return new Node(path, nodeSignature, childs);
1941+ }
1942+
1943+ /**
1944+ * Generate an array like ['arg0', 'arg1', 'arg2']
1945+ * @param {number} count Number of arguments to generate
1946+ * @returns {Array} Returns an array with argument names
1947+ */
1948+ function getArgs(count) {
1949+ // create an array with all argument names
1950+ var args = [];
1951+ for (var i = 0; i < count; i++) {
1952+ args[i] = 'arg' + i;
1953+ }
1954+
1955+ return args;
1956+ }
1957+
1958+ /**
1959+ * Compose a function from sub-functions each handling a single type signature.
1960+ * Signatures:
1961+ * typed(signature: string, fn: function)
1962+ * typed(name: string, signature: string, fn: function)
1963+ * typed(signatures: Object.<string, function>)
1964+ * typed(name: string, signatures: Object.<string, function>)
1965+ *
1966+ * @param {string | null} name
1967+ * @param {Object.<string, Function>} signatures
1968+ * @return {Function} Returns the typed function
1969+ * @private
1970+ */
1971+ function _typed(name, signatures) {
1972+ var refs = new Refs();
1973+
1974+ // parse signatures, expand them
1975+ var _signatures = parseSignatures(signatures);
1976+ if (_signatures.length == 0) {
1977+ throw new Error('No signatures provided');
1978+ }
1979+
1980+ // parse signatures into a node tree
1981+ var node = parseTree(_signatures, []);
1982+
1983+ //var util = require('util');
1984+ //console.log('ROOT');
1985+ //console.log(util.inspect(node, { depth: null }));
1986+
1987+ // generate code for the typed function
1988+ var code = [];
1989+ var _name = name || '';
1990+ var _args = getArgs(maxParams(_signatures));
1991+ code.push('function ' + _name + '(' + _args.join(', ') + ') {');
1992+ code.push(' "use strict";');
1993+ code.push(' var name = \'' + _name + '\';');
1994+ code.push(node.toCode(refs, ' '));
1995+ code.push('}');
1996+
1997+ // generate body for the factory function
1998+ var body = [
1999+ refs.toCode(),
2000+ 'return ' + code.join('\n')
2001+ ].join('\n');
2002+
2003+ // evaluate the JavaScript code and attach function references
2004+ var factory = (new Function(refs.name, 'createError', body));
2005+ var fn = factory(refs, createError);
2006+
2007+ //console.log('FN\n' + fn.toString()); // TODO: cleanup
2008+
2009+ // attach the signatures with sub-functions to the constructed function
2010+ fn.signatures = mapSignatures(_signatures);
2011+
2012+ return fn;
2013+ }
2014+
2015+ /**
2016+ * Calculate the maximum number of parameters in givens signatures
2017+ * @param {Signature[]} signatures
2018+ * @returns {number} The maximum number of parameters
2019+ */
2020+ function maxParams(signatures) {
2021+ var max = 0;
2022+
2023+ for (var i = 0; i < signatures.length; i++) {
2024+ var len = signatures[i].params.length;
2025+ if (len > max) {
2026+ max = len;
2027+ }
2028+ }
2029+
2030+ return max;
2031+ }
2032+
2033+ /**
2034+ * Get the type of a value
2035+ * @param {*} x
2036+ * @returns {string} Returns a string with the type of value
2037+ */
2038+ function getTypeOf(x) {
2039+ var obj;
2040+
2041+ for (var i = 0; i < typed.types.length; i++) {
2042+ var entry = typed.types[i];
2043+
2044+ if (entry.name === 'Object') {
2045+ // Array and Date are also Object, so test for Object afterwards
2046+ obj = entry;
2047+ }
2048+ else {
2049+ if (entry.test(x)) return entry.name;
2050+ }
2051+ }
2052+
2053+ // at last, test whether an object
2054+ if (obj && obj.test(x)) return obj.name;
2055+
2056+ return 'unknown';
2057+ }
2058+
2059+ /**
2060+ * Test whether an array contains some entry
2061+ * @param {Array} array
2062+ * @param {*} entry
2063+ * @return {boolean} Returns true if array contains entry, false if not.
2064+ */
2065+ function contains(array, entry) {
2066+ return array.indexOf(entry) !== -1;
2067+ }
2068+
2069+ // data type tests
2070+ var types = [
2071+ { name: 'number', test: function (x) { return typeof x === 'number' } },
2072+ { name: 'string', test: function (x) { return typeof x === 'string' } },
2073+ { name: 'boolean', test: function (x) { return typeof x === 'boolean' } },
2074+ { name: 'Function', test: function (x) { return typeof x === 'function'} },
2075+ { name: 'Array', test: Array.isArray },
2076+ { name: 'Date', test: function (x) { return x instanceof Date } },
2077+ { name: 'RegExp', test: function (x) { return x instanceof RegExp } },
2078+ { name: 'Object', test: function (x) { return typeof x === 'object' } },
2079+ { name: 'null', test: function (x) { return x === null } },
2080+ { name: 'undefined', test: function (x) { return x === undefined } }
2081+ ];
2082+
2083+ // configuration
2084+ var config = {};
2085+
2086+ // type conversions. Order is important
2087+ var conversions = [];
2088+
2089+ // types to be ignored
2090+ var ignore = [];
2091+
2092+ // temporary object for holding types and conversions, for constructing
2093+ // the `typed` function itself
2094+ // TODO: find a more elegant solution for this
2095+ var typed = {
2096+ config: config,
2097+ types: types,
2098+ conversions: conversions,
2099+ ignore: ignore
2100+ };
2101+
2102+ /**
2103+ * Construct the typed function itself with various signatures
2104+ *
2105+ * Signatures:
2106+ *
2107+ * typed(signatures: Object.<string, function>)
2108+ * typed(name: string, signatures: Object.<string, function>)
2109+ */
2110+ typed = _typed('typed', {
2111+ 'Object': function (signatures) {
2112+ var fns = [];
2113+ for (var signature in signatures) {
2114+ if (signatures.hasOwnProperty(signature)) {
2115+ fns.push(signatures[signature]);
2116+ }
2117+ }
2118+ var name = getName(fns);
2119+
2120+ return _typed(name, signatures);
2121+ },
2122+ 'string, Object': _typed,
2123+ // TODO: add a signature 'Array.<function>'
2124+ '...Function': function (fns) {
2125+ var err;
2126+ var name = getName(fns);
2127+ var signatures = {};
2128+
2129+ for (var i = 0; i < fns.length; i++) {
2130+ var fn = fns[i];
2131+
2132+ // test whether this is a typed-function
2133+ if (!(typeof fn.signatures === 'object')) {
2134+ err = new TypeError('Function is no typed-function (index: ' + i + ')');
2135+ err.data = {index: i};
2136+ throw err;
2137+ }
2138+
2139+ // merge the signatures
2140+ for (var signature in fn.signatures) {
2141+ if (fn.signatures.hasOwnProperty(signature)) {
2142+ if (signatures.hasOwnProperty(signature)) {
2143+ if (fn.signatures[signature] !== signatures[signature]) {
2144+ err = new Error('Signature "' + signature + '" is defined twice');
2145+ err.data = {signature: signature};
2146+ throw err;
2147+ }
2148+ // else: both signatures point to the same function, that's fine
2149+ }
2150+ else {
2151+ signatures[signature] = fn.signatures[signature];
2152+ }
2153+ }
2154+ }
2155+ }
2156+
2157+ return _typed(name, signatures);
2158+ }
2159+ });
2160+
2161+ /**
2162+ * Find a specific signature from a (composed) typed function, for
2163+ * example:
2164+ *
2165+ * typed.find(fn, ['number', 'string'])
2166+ * typed.find(fn, 'number, string')
2167+ *
2168+ * Function find only only works for exact matches.
2169+ *
2170+ * @param {Function} fn A typed-function
2171+ * @param {string | string[]} signature Signature to be found, can be
2172+ * an array or a comma separated string.
2173+ * @return {Function} Returns the matching signature, or
2174+ * throws an errror when no signature
2175+ * is found.
2176+ */
2177+ function find (fn, signature) {
2178+ if (!fn.signatures) {
2179+ throw new TypeError('Function is no typed-function');
2180+ }
2181+
2182+ // normalize input
2183+ var arr;
2184+ if (typeof signature === 'string') {
2185+ arr = signature.split(',');
2186+ for (var i = 0; i < arr.length; i++) {
2187+ arr[i] = arr[i].trim();
2188+ }
2189+ }
2190+ else if (Array.isArray(signature)) {
2191+ arr = signature;
2192+ }
2193+ else {
2194+ throw new TypeError('String array or a comma separated string expected');
2195+ }
2196+
2197+ var str = arr.join(',');
2198+
2199+ // find an exact match
2200+ var match = fn.signatures[str];
2201+ if (match) {
2202+ return match;
2203+ }
2204+
2205+ // TODO: extend find to match non-exact signatures
2206+
2207+ throw new TypeError('Signature not found (signature: ' + (fn.name || 'unnamed') + '(' + arr.join(', ') + '))');
2208+ }
2209+
2210+ /**
2211+ * Convert a given value to another data type.
2212+ * @param {*} value
2213+ * @param {string} type
2214+ */
2215+ function convert (value, type) {
2216+ var from = getTypeOf(value);
2217+
2218+ // check conversion is needed
2219+ if (type === from) {
2220+ return value;
2221+ }
2222+
2223+ for (var i = 0; i < typed.conversions.length; i++) {
2224+ var conversion = typed.conversions[i];
2225+ if (conversion.from === from && conversion.to === type) {
2226+ return conversion.convert(value);
2227+ }
2228+ }
2229+
2230+ throw new Error('Cannot convert from ' + from + ' to ' + type);
2231+ }
2232+
2233+ // attach types and conversions to the final `typed` function
2234+ typed.config = config;
2235+ typed.types = types;
2236+ typed.conversions = conversions;
2237+ typed.ignore = ignore;
2238+ typed.create = create;
2239+ typed.find = find;
2240+ typed.convert = convert;
2241+
2242+ // add a type
2243+ typed.addType = function (type) {
2244+ if (!type || typeof type.name !== 'string' || typeof type.test !== 'function') {
2245+ throw new TypeError('Object with properties {name: string, test: function} expected');
2246+ }
2247+
2248+ typed.types.push(type);
2249+ };
2250+
2251+ // add a conversion
2252+ typed.addConversion = function (conversion) {
2253+ if (!conversion
2254+ || typeof conversion.from !== 'string'
2255+ || typeof conversion.to !== 'string'
2256+ || typeof conversion.convert !== 'function') {
2257+ throw new TypeError('Object with properties {from: string, to: string, convert: function} expected');
2258+ }
2259+
2260+ typed.conversions.push(conversion);
2261+ };
2262+
2263+ return typed;
2264+ }
2265+
2266+ return create();
2267+ }));
2268+
2269+
2270+/***/ },
2271+/* 8 */
2272+/***/ function(module, exports, __webpack_require__) {
2273+
2274+ 'use strict';
2275+
2276+ var NumberFormatter = __webpack_require__(9);
2277+
2278+ /**
2279+ * Test whether value is a number
2280 * @param {*} value
2281- * @return {Boolean} isNumber
2282+ * @return {boolean} isNumber
2283 */
2284 exports.isNumber = function(value) {
2285- return (value instanceof Number) || (typeof value == 'number');
2286+ return typeof value === 'number';
2287 };
2288
2289 /**
2290 * Check if a number is integer
2291- * @param {Number | Boolean} value
2292- * @return {Boolean} isInteger
2293+ * @param {number | boolean} value
2294+ * @return {boolean} isInteger
2295 */
2296 exports.isInteger = function(value) {
2297- return (value == Math.round(value));
2298+ return isFinite(value)
2299+ ? (value == Math.round(value))
2300+ : false;
2301 // Note: we use ==, not ===, as we can have Booleans as well
2302 };
2303
2304 /**
2305 * Calculate the sign of a number
2306- * @param {Number} x
2307+ * @param {number} x
2308 * @returns {*}
2309 */
2310 exports.sign = function(x) {
2311@@ -767,9 +2133,9 @@
2312 *
2313 * Where:
2314 *
2315- * {Number} value The value to be formatted
2316+ * {number} value The value to be formatted
2317 * {Object} options An object with formatting options. Available options:
2318- * {String} notation
2319+ * {string} notation
2320 * Number notation. Choose from:
2321 * 'fixed' Always use regular number notation.
2322 * For example '123.40' and '14000000'
2323@@ -782,7 +2148,7 @@
2324 * Lower bound is included, upper bound
2325 * is excluded.
2326 * For example '123.4' and '1.4e7'.
2327- * {Number} precision A number between 0 and 16 to round
2328+ * {number} precision A number between 0 and 16 to round
2329 * the digits of the number.
2330 * In case of notations 'exponential' and
2331 * 'auto', `precision` defines the total
2332@@ -793,7 +2159,7 @@
2333 * significant digits after the decimal
2334 * point, and is 0 by default.
2335 * {Object} exponential An object containing two parameters,
2336- * {Number} lower and {Number} upper,
2337+ * {number} lower and {number} upper,
2338 * used by notation 'auto' to determine
2339 * when to return exponential notation.
2340 * Default values are `lower=1e-3` and
2341@@ -815,9 +2181,9 @@
2342 * format(2.3, {notation: 'fixed', precision: 2}); // '2.30'
2343 * format(52.8, {notation: 'exponential'}); // '5.28e+1'
2344 *
2345- * @param {Number} value
2346- * @param {Object | Function | Number} [options]
2347- * @return {String} str The formatted value
2348+ * @param {number} value
2349+ * @param {Object | Function | number} [options]
2350+ * @return {string} str The formatted value
2351 */
2352 exports.format = function(value, options) {
2353 if (typeof options === 'function') {
2354@@ -882,8 +2248,8 @@
2355
2356 /**
2357 * Format a number in exponential notation. Like '1.23e+5', '2.3e+0', '3.500e-3'
2358- * @param {Number} value
2359- * @param {Number} [precision] Number of digits in formatted output.
2360+ * @param {number} value
2361+ * @param {number} [precision] Number of digits in formatted output.
2362 * If not provided, the maximum available digits
2363 * is used.
2364 * @returns {string} str
2365@@ -894,8 +2260,8 @@
2366
2367 /**
2368 * Format a number with fixed notation.
2369- * @param {Number} value
2370- * @param {Number} [precision=0] Optional number of decimals after the
2371+ * @param {number} value
2372+ * @param {number} [precision=0] Optional number of decimals after the
2373 * decimal point. Zero by default.
2374 */
2375 exports.toFixed = function(value, precision) {
2376@@ -904,8 +2270,8 @@
2377
2378 /**
2379 * Format a number with a certain precision
2380- * @param {Number} value
2381- * @param {Number} [precision=undefined] Optional number of digits.
2382+ * @param {number} value
2383+ * @param {number} [precision=undefined] Optional number of digits.
2384 * @param {{lower: number, upper: number}} [options] By default:
2385 * lower = 1e-3 (excl)
2386 * upper = 1e+5 (incl)
2387@@ -923,8 +2289,8 @@
2388 * 0.0034 returns 2
2389 * 120.5e+30 returns 4
2390 *
2391- * @param {Number} value
2392- * @return {Number} digits Number of significant digits
2393+ * @param {number} value
2394+ * @return {number} digits Number of significant digits
2395 */
2396 exports.digits = function(value) {
2397 return value
2398@@ -941,9 +2307,9 @@
2399
2400 /**
2401 * Compares two floating point numbers.
2402- * @param {Number} x First value to compare
2403- * @param {Number} y Second value to compare
2404- * @param {Number} [epsilon] The maximum relative difference between x and y
2405+ * @param {number} x First value to compare
2406+ * @param {number} y Second value to compare
2407+ * @param {number} [epsilon] The maximum relative difference between x and y
2408 * If epsilon is undefined or null, the function will
2409 * test whether x and y are exactly equal.
2410 * @return {boolean} whether the two numbers are equal
2411@@ -977,1167 +2343,216 @@
2412
2413
2414 /***/ },
2415-/* 4 */
2416-/***/ function(module, exports, __webpack_require__) {
2417-
2418- 'use strict';
2419-
2420- module.exports = function (math, config) {
2421- var object = __webpack_require__(2);
2422- var bignumber = __webpack_require__(168);
2423- var Complex = __webpack_require__(7);
2424- var BigNumber = math.type.BigNumber;
2425-
2426- math['true'] = true;
2427- math['false'] = false;
2428- math['null'] = null;
2429- math['uninitialized'] = __webpack_require__(169).UNINITIALIZED;
2430-
2431- if (config.number === 'bignumber') {
2432- math['Infinity'] = new BigNumber(Infinity);
2433- math['NaN'] = new BigNumber(NaN);
2434-
2435- object.lazy(math, 'pi', function () {return bignumber.pi(config.precision)});
2436- object.lazy(math, 'tau', function () {return bignumber.tau(config.precision)});
2437- object.lazy(math, 'e', function () {return bignumber.e(config.precision)});
2438- object.lazy(math, 'phi', function () {return bignumber.phi(config.precision)}); // golden ratio, (1+sqrt(5))/2
2439-
2440- // uppercase constants (for compatibility with built-in Math)
2441- object.lazy(math, 'E', function () {return math.e;});
2442- object.lazy(math, 'LN2', function () {return new BigNumber(2).ln();});
2443- object.lazy(math, 'LN10', function () {return new BigNumber(10).ln()});
2444- object.lazy(math, 'LOG2E', function () {return new BigNumber(1).div(new BigNumber(2).ln());});
2445- object.lazy(math, 'LOG10E', function () {return new BigNumber(1).div(new BigNumber(10).ln())});
2446- object.lazy(math, 'PI', function () {return math.pi});
2447- object.lazy(math, 'SQRT1_2', function () {return new BigNumber('0.5').sqrt()});
2448- object.lazy(math, 'SQRT2', function () {return new BigNumber(2).sqrt()});
2449- }
2450- else {
2451- math['Infinity'] = Infinity;
2452- math['NaN'] = NaN;
2453-
2454- math.pi = Math.PI;
2455- math.tau = Math.PI * 2;
2456- math.e = Math.E;
2457- math.phi = 1.61803398874989484820458683436563811772030917980576286213545; // golden ratio, (1+sqrt(5))/2
2458-
2459- // uppercase constants (for compatibility with built-in Math)
2460- math.E = math.e;
2461- math.LN2 = Math.LN2;
2462- math.LN10 = Math.LN10;
2463- math.LOG2E = Math.LOG2E;
2464- math.LOG10E = Math.LOG10E;
2465- math.PI = math.pi;
2466- math.SQRT1_2 = Math.SQRT1_2;
2467- math.SQRT2 = Math.SQRT2;
2468- }
2469-
2470- // complex i
2471- math.i = new Complex(0, 1);
2472-
2473- // meta information
2474- math.version = __webpack_require__(170);
2475- };
2476-
2477-
2478-/***/ },
2479-/* 5 */
2480-/***/ function(module, exports, __webpack_require__) {
2481-
2482- var BigNumber = __webpack_require__(340);
2483-
2484- // FIXME: replace all require('decimal.js') with require('./BigNumber').
2485-
2486- module.exports = BigNumber;
2487-
2488-
2489-/***/ },
2490-/* 6 */
2491-/***/ function(module, exports, __webpack_require__) {
2492-
2493- 'use strict';
2494-
2495- exports.ArgumentsError = __webpack_require__(171);
2496- exports.DimensionError = __webpack_require__(172);
2497- exports.IndexError = __webpack_require__(173);
2498- exports.UnsupportedTypeError = __webpack_require__(174);
2499-
2500- // TODO: implement an InvalidValueError?
2501-
2502-
2503-/***/ },
2504-/* 7 */
2505-/***/ function(module, exports, __webpack_require__) {
2506-
2507- 'use strict';
2508-
2509- var util = __webpack_require__(175),
2510- Unit = __webpack_require__(11),
2511- number = util.number,
2512-
2513- isNumber = util.number.isNumber,
2514- isUnit = Unit.isUnit,
2515- isString = util.string.isString;
2516-
2517- /**
2518- * @constructor Complex
2519- *
2520- * A complex value can be constructed in the following ways:
2521- * var a = new Complex();
2522- * var b = new Complex(re, im);
2523- * var c = Complex.parse(str);
2524- *
2525- * Example usage:
2526- * var a = new Complex(3, -4); // 3 - 4i
2527- * a.re = 5; // a = 5 - 4i
2528- * var i = a.im; // -4;
2529- * var b = Complex.parse('2 + 6i'); // 2 + 6i
2530- * var c = new Complex(); // 0 + 0i
2531- * var d = math.add(a, b); // 5 + 2i
2532- *
2533- * @param {Number} re The real part of the complex value
2534- * @param {Number} [im] The imaginary part of the complex value
2535- */
2536- function Complex(re, im) {
2537- if (!(this instanceof Complex)) {
2538- throw new SyntaxError('Constructor must be called with the new operator');
2539- }
2540-
2541- switch (arguments.length) {
2542- case 0:
2543- this.re = 0;
2544- this.im = 0;
2545- break;
2546-
2547- case 1:
2548- var arg = arguments[0];
2549- if (typeof arg === 'object') {
2550- if('re' in arg && 'im' in arg) {
2551- var construct = new Complex(arg.re, arg.im); // pass on input validation
2552- this.re = construct.re;
2553- this.im = construct.im;
2554- break;
2555- } else if ('r' in arg && 'phi' in arg) {
2556- var construct = Complex.fromPolar(arg.r, arg.phi);
2557- this.re = construct.re;
2558- this.im = construct.im;
2559- break;
2560- }
2561- }
2562- throw new SyntaxError('Object with the re and im or r and phi properties expected.');
2563-
2564- case 2:
2565- if (!isNumber(re) || !isNumber(im)) {
2566- throw new TypeError('Two numbers expected in Complex constructor');
2567- }
2568- this.re = re;
2569- this.im = im;
2570- break;
2571-
2572- default:
2573- throw new SyntaxError('One, two or three arguments expected in Complex constructor');
2574- }
2575- }
2576-
2577- /**
2578- * Test whether value is a Complex value
2579- * @param {*} value
2580- * @return {Boolean} isComplex
2581- */
2582- Complex.isComplex = function (value) {
2583- return (value instanceof Complex);
2584- };
2585-
2586- // private variables and functions for the parser
2587- var text, index, c;
2588-
2589- function skipWhitespace() {
2590- while (c == ' ' || c == '\t') {
2591- next();
2592- }
2593- }
2594-
2595- function isDigitDot (c) {
2596- return ((c >= '0' && c <= '9') || c == '.');
2597- }
2598-
2599- function isDigit (c) {
2600- return ((c >= '0' && c <= '9'));
2601- }
2602-
2603- function next() {
2604- index++;
2605- c = text.charAt(index);
2606- }
2607-
2608- function revert(oldIndex) {
2609- index = oldIndex;
2610- c = text.charAt(index);
2611- }
2612-
2613- function parseNumber () {
2614- var number = '';
2615- var oldIndex;
2616- oldIndex = index;
2617-
2618- if (c == '+') {
2619- next();
2620- }
2621- else if (c == '-') {
2622- number += c;
2623- next();
2624- }
2625-
2626- if (!isDigitDot(c)) {
2627- // a + or - must be followed by a digit
2628- revert(oldIndex);
2629- return null;
2630- }
2631-
2632- // get number, can have a single dot
2633- if (c == '.') {
2634- number += c;
2635- next();
2636- if (!isDigit(c)) {
2637- // this is no legal number, it is just a dot
2638- revert(oldIndex);
2639- return null;
2640- }
2641- }
2642- else {
2643- while (isDigit(c)) {
2644- number += c;
2645- next();
2646- }
2647- if (c == '.') {
2648- number += c;
2649- next();
2650- }
2651- }
2652- while (isDigit(c)) {
2653- number += c;
2654- next();
2655- }
2656-
2657- // check for exponential notation like "2.3e-4" or "1.23e50"
2658- if (c == 'E' || c == 'e') {
2659- number += c;
2660- next();
2661-
2662- if (c == '+' || c == '-') {
2663- number += c;
2664- next();
2665- }
2666-
2667- // Scientific notation MUST be followed by an exponent
2668- if (!isDigit(c)) {
2669- // this is no legal number, exponent is missing.
2670- revert(oldIndex);
2671- return null;
2672- }
2673-
2674- while (isDigit(c)) {
2675- number += c;
2676- next();
2677- }
2678- }
2679-
2680- return number;
2681- }
2682-
2683- function parseComplex () {
2684- // check for 'i', '-i', '+i'
2685- var cnext = text.charAt(index + 1);
2686- if (c == 'I' || c == 'i') {
2687- next();
2688- return '1';
2689- }
2690- else if ((c == '+' || c == '-') && (cnext == 'I' || cnext == 'i')) {
2691- var number = (c == '+') ? '1' : '-1';
2692- next();
2693- next();
2694- return number;
2695- }
2696-
2697- return null;
2698- }
2699-
2700- /**
2701- * Parse a complex number from a string. For example Complex.parse("2 + 3i")
2702- * will return a Complex value where re = 2, im = 3.
2703- * Returns null if provided string does not contain a valid complex number.
2704- * @param {String} str
2705- * @returns {Complex | null} complex
2706- */
2707- Complex.parse = function (str) {
2708- text = str;
2709- index = -1;
2710- c = '';
2711-
2712- if (!isString(text)) {
2713- return null;
2714- }
2715-
2716- next();
2717- skipWhitespace();
2718- var first = parseNumber();
2719- if (first) {
2720- if (c == 'I' || c == 'i') {
2721- // pure imaginary number
2722- next();
2723- skipWhitespace();
2724- if (c) {
2725- // garbage at the end. not good.
2726- return null;
2727- }
2728-
2729- return new Complex(0, Number(first));
2730- }
2731- else {
2732- // complex and real part
2733- skipWhitespace();
2734- var separator = c;
2735- if (separator != '+' && separator != '-') {
2736- // pure real number
2737- skipWhitespace();
2738- if (c) {
2739- // garbage at the end. not good.
2740- return null;
2741- }
2742-
2743- return new Complex(Number(first), 0);
2744- }
2745- else {
2746- // complex and real part
2747- next();
2748- skipWhitespace();
2749- var second = parseNumber();
2750- if (second) {
2751- if (c != 'I' && c != 'i') {
2752- // 'i' missing at the end of the complex number
2753- return null;
2754- }
2755- next();
2756- }
2757- else {
2758- second = parseComplex();
2759- if (!second) {
2760- // imaginary number missing after separator
2761- return null;
2762- }
2763- }
2764-
2765- if (separator == '-') {
2766- if (second[0] == '-') {
2767- second = '+' + second.substring(1);
2768- }
2769- else {
2770- second = '-' + second;
2771- }
2772- }
2773-
2774- next();
2775- skipWhitespace();
2776- if (c) {
2777- // garbage at the end. not good.
2778- return null;
2779- }
2780-
2781- return new Complex(Number(first), Number(second));
2782- }
2783- }
2784- }
2785- else {
2786- // check for 'i', '-i', '+i'
2787- first = parseComplex();
2788- if (first) {
2789- skipWhitespace();
2790- if (c) {
2791- // garbage at the end. not good.
2792- return null;
2793- }
2794-
2795- return new Complex(0, Number(first));
2796- }
2797- }
2798-
2799- return null;
2800- };
2801-
2802- /**
2803- * Create a complex number from polar coordinates
2804- *
2805- * Usage:
2806- *
2807- * Complex.fromPolar(r: Number, phi: Number) : Complex
2808- * Complex.fromPolar({r: Number, phi: Number}) : Complex
2809- *
2810- * @param {*} args...
2811- * @return {Complex}
2812- */
2813- Complex.fromPolar = function (args) {
2814- switch (arguments.length) {
2815- case 1:
2816- var arg = arguments[0];
2817- if(typeof arg === 'object') {
2818- return Complex.fromPolar(arg.r, arg.phi);
2819- }
2820- throw new TypeError('Input has to be an object with r and phi keys.');
2821-
2822- case 2:
2823- var r = arguments[0],
2824- phi = arguments[1];
2825- if(isNumber(r)) {
2826- if (isUnit(phi) && phi.hasBase(Unit.BASE_UNITS.ANGLE)) {
2827- // convert unit to a number in radians
2828- phi = phi.toNumber('rad');
2829- }
2830-
2831- if(isNumber(phi)) {
2832- return new Complex(r * Math.cos(phi), r * Math.sin(phi));
2833- }
2834-
2835- throw new TypeError('Phi is not a number nor an angle unit.');
2836- } else {
2837- throw new TypeError('Radius r is not a number.');
2838- }
2839-
2840- default:
2841- throw new SyntaxError('Wrong number of arguments in function fromPolar');
2842- }
2843- };
2844-
2845- /*
2846- * Return the value of the complex number in polar notation
2847- * The angle phi will be set in the interval of [-pi, pi].
2848- * @return {{r: number, phi: number}} Returns and object with properties r and phi.
2849- */
2850- Complex.prototype.toPolar = function() {
2851- return {
2852- r: Math.sqrt(this.re * this.re + this.im * this.im),
2853- phi: Math.atan2(this.im, this.re)
2854- };
2855- };
2856-
2857- /**
2858- * Create a copy of the complex value
2859- * @return {Complex} clone
2860- */
2861- Complex.prototype.clone = function () {
2862- return new Complex(this.re, this.im);
2863- };
2864-
2865- /**
2866- * Test whether this complex number equals an other complex value.
2867- * Two complex numbers are equal when both their real and imaginary parts
2868- * are equal.
2869- * @param {Complex} other
2870- * @return {boolean} isEqual
2871- */
2872- Complex.prototype.equals = function (other) {
2873- return (this.re === other.re) && (this.im === other.im);
2874- };
2875-
2876- /**
2877- * Get a string representation of the complex number,
2878- * with optional formatting options.
2879- * @param {Object | Number | Function} [options] Formatting options. See
2880- * lib/util/number:format for a
2881- * description of the available
2882- * options.
2883- * @return {String} str
2884- */
2885- Complex.prototype.format = function (options) {
2886- var str = '';
2887- var im = this.im;
2888- var re = this.re;
2889- var strRe = number.format(this.re, options);
2890- var strIm = number.format(this.im, options);
2891-
2892- // round either re or im when smaller than the configured precision
2893- var precision = isNumber(options) ? options : options ? options.precision : null;
2894- if (precision !== null) {
2895- var epsilon = Math.pow(10, -precision);
2896- if (Math.abs(re / im) < epsilon) {re = 0;}
2897- if (Math.abs(im / re) < epsilon) {im = 0;}
2898- }
2899-
2900- if (im == 0) {
2901- // real value
2902- str = strRe;
2903- }
2904- else if (re == 0) {
2905- // purely complex value
2906- if (im == 1) {
2907- str = 'i';
2908- }
2909- else if (im == -1) {
2910- str = '-i';
2911- }
2912- else {
2913- str = strIm + 'i';
2914- }
2915- }
2916- else {
2917- // complex value
2918- if (im > 0) {
2919- if (im == 1) {
2920- str = strRe + ' + i';
2921- }
2922- else {
2923- str = strRe + ' + ' + strIm + 'i';
2924- }
2925- }
2926- else {
2927- if (im == -1) {
2928- str = strRe + ' - i';
2929- }
2930- else {
2931- str = strRe + ' - ' + strIm.substring(1) + 'i';
2932- }
2933- }
2934- }
2935-
2936- return str;
2937- };
2938-
2939- /**
2940- * Get a string representation of the complex number.
2941- * @return {String} str
2942- */
2943- Complex.prototype.toString = function () {
2944- return this.format();
2945- };
2946-
2947- /**
2948- * Get a JSON representation of the complex number
2949- * @returns {Object} Returns a JSON object structured as:
2950- * `{"mathjs": "Complex", "re": 2, "im": 3}`
2951- */
2952- Complex.prototype.toJSON = function () {
2953- return {
2954- mathjs: 'Complex',
2955- re: this.re,
2956- im: this.im
2957- };
2958- };
2959-
2960- /**
2961- * Create a Complex number from a JSON object
2962- * @param {Object} json A JSON Object structured as
2963- * {"mathjs": "Complex", "re": 2, "im": 3}
2964- * All properties are optional, default values
2965- * for `re` and `im` are 0.
2966- * @return {Complex} Returns a new Complex number
2967- */
2968- Complex.fromJSON = function (json) {
2969- return new Complex(json);
2970- };
2971-
2972- /**
2973- * Returns a string representation of the complex number.
2974- * @return {String} str
2975- */
2976- Complex.prototype.valueOf = Complex.prototype.toString;
2977-
2978- // exports
2979- module.exports = Complex;
2980-
2981-
2982-/***/ },
2983-/* 8 */
2984-/***/ function(module, exports, __webpack_require__) {
2985-
2986- 'use strict';
2987-
2988- var util = __webpack_require__(175);
2989-
2990- var number = util.number;
2991- var string = util.string;
2992- var array = util.array;
2993-
2994- /**
2995- * @constructor Range
2996- * Create a range. A range has a start, step, and end, and contains functions
2997- * to iterate over the range.
2998- *
2999- * A range can be constructed as:
3000- * var range = new Range(start, end);
3001- * var range = new Range(start, end, step);
3002- *
3003- * To get the result of the range:
3004- * range.forEach(function (x) {
3005- * console.log(x);
3006- * });
3007- * range.map(function (x) {
3008- * return math.sin(x);
3009- * });
3010- * range.toArray();
3011- *
3012- * Example usage:
3013- * var c = new Range(2, 6); // 2:1:5
3014- * c.toArray(); // [2, 3, 4, 5]
3015- * var d = new Range(2, -3, -1); // 2:-1:-2
3016- * d.toArray(); // [2, 1, 0, -1, -2]
3017- *
3018- * @param {Number} start included lower bound
3019- * @param {Number} end excluded upper bound
3020- * @param {Number} [step] step size, default value is 1
3021- */
3022- function Range(start, end, step) {
3023- if (!(this instanceof Range)) {
3024- throw new SyntaxError('Constructor must be called with the new operator');
3025- }
3026-
3027- if (start != null && !number.isNumber(start)) {
3028- throw new TypeError('Parameter start must be a number');
3029- }
3030- if (end != null && !number.isNumber(end)) {
3031- throw new TypeError('Parameter end must be a number');
3032- }
3033- if (step != null && !number.isNumber(step)) {
3034- throw new TypeError('Parameter step must be a number');
3035- }
3036-
3037- this.start = (start != null) ? parseFloat(start) : 0;
3038- this.end = (end != null) ? parseFloat(end) : 0;
3039- this.step = (step != null) ? parseFloat(step) : 1;
3040- }
3041-
3042- /**
3043- * Parse a string into a range,
3044- * The string contains the start, optional step, and end, separated by a colon.
3045- * If the string does not contain a valid range, null is returned.
3046- * For example str='0:2:11'.
3047- * @param {String} str
3048- * @return {Range | null} range
3049- */
3050- Range.parse = function (str) {
3051- if (!string.isString(str)) {
3052- return null;
3053- }
3054-
3055- var args = str.split(':');
3056- var nums = args.map(function (arg) {
3057- return parseFloat(arg);
3058- });
3059-
3060- var invalid = nums.some(function (num) {
3061- return isNaN(num);
3062- });
3063- if(invalid) {
3064- return null;
3065- }
3066-
3067- switch (nums.length) {
3068- case 2: return new Range(nums[0], nums[1]);
3069- case 3: return new Range(nums[0], nums[2], nums[1]);
3070- default: return null;
3071- }
3072- };
3073-
3074- /**
3075- * Create a clone of the range
3076- * @return {Range} clone
3077- */
3078- Range.prototype.clone = function () {
3079- return new Range(this.start, this.end, this.step);
3080- };
3081-
3082- /**
3083- * Test whether an object is a Range
3084- * @param {*} object
3085- * @return {Boolean} isRange
3086- */
3087- Range.isRange = function (object) {
3088- return (object instanceof Range);
3089- };
3090-
3091- /**
3092- * Retrieve the size of the range.
3093- * Returns an array containing one number, the number of elements in the range.
3094- * @returns {Number[]} size
3095- */
3096- Range.prototype.size = function () {
3097- var len = 0,
3098- start = this.start,
3099- step = this.step,
3100- end = this.end,
3101- diff = end - start;
3102-
3103- if (number.sign(step) == number.sign(diff)) {
3104- len = Math.ceil((diff) / step);
3105- }
3106- else if (diff == 0) {
3107- len = 0;
3108- }
3109-
3110- if (isNaN(len)) {
3111- len = 0;
3112- }
3113- return [len];
3114- };
3115-
3116- /**
3117- * Calculate the minimum value in the range
3118- * @return {Number | undefined} min
3119- */
3120- Range.prototype.min = function () {
3121- var size = this.size()[0];
3122-
3123- if (size > 0) {
3124- if (this.step > 0) {
3125- // positive step
3126- return this.start;
3127- }
3128- else {
3129- // negative step
3130- return this.start + (size - 1) * this.step;
3131- }
3132- }
3133- else {
3134- return undefined;
3135- }
3136- };
3137-
3138- /**
3139- * Calculate the maximum value in the range
3140- * @return {Number | undefined} max
3141- */
3142- Range.prototype.max = function () {
3143- var size = this.size()[0];
3144-
3145- if (size > 0) {
3146- if (this.step > 0) {
3147- // positive step
3148- return this.start + (size - 1) * this.step;
3149- }
3150- else {
3151- // negative step
3152- return this.start;
3153- }
3154- }
3155- else {
3156- return undefined;
3157- }
3158- };
3159-
3160-
3161- /**
3162- * Execute a callback function for each value in the range.
3163- * @param {function} callback The callback method is invoked with three
3164- * parameters: the value of the element, the index
3165- * of the element, and the Matrix being traversed.
3166- */
3167- Range.prototype.forEach = function (callback) {
3168- var x = this.start;
3169- var step = this.step;
3170- var end = this.end;
3171- var i = 0;
3172-
3173- if (step > 0) {
3174- while (x < end) {
3175- callback(x, i, this);
3176- x += step;
3177- i++;
3178- }
3179- }
3180- else if (step < 0) {
3181- while (x > end) {
3182- callback(x, i, this);
3183- x += step;
3184- i++;
3185- }
3186- }
3187- };
3188-
3189- /**
3190- * Execute a callback function for each value in the Range, and return the
3191- * results as an array
3192- * @param {function} callback The callback method is invoked with three
3193- * parameters: the value of the element, the index
3194- * of the element, and the Matrix being traversed.
3195- * @returns {Array} array
3196- */
3197- Range.prototype.map = function (callback) {
3198- var array = [];
3199- this.forEach(function (value, index, obj) {
3200- array[index] = callback(value, index, obj);
3201- });
3202- return array;
3203- };
3204-
3205- /**
3206- * Create an Array with a copy of the Ranges data
3207- * @returns {Array} array
3208- */
3209- Range.prototype.toArray = function () {
3210- var array = [];
3211- this.forEach(function (value, index) {
3212- array[index] = value;
3213- });
3214- return array;
3215- };
3216-
3217- /**
3218- * Get the primitive value of the Range, a one dimensional array
3219- * @returns {Array} array
3220- */
3221- Range.prototype.valueOf = function () {
3222- // TODO: implement a caching mechanism for range.valueOf()
3223- return this.toArray();
3224- };
3225-
3226- /**
3227- * Get a string representation of the range, with optional formatting options.
3228- * Output is formatted as 'start:step:end', for example '2:6' or '0:0.2:11'
3229- * @param {Object | Number | Function} [options] Formatting options. See
3230- * lib/util/number:format for a
3231- * description of the available
3232- * options.
3233- * @returns {String} str
3234- */
3235- Range.prototype.format = function (options) {
3236- var str = number.format(this.start, options);
3237-
3238- if (this.step != 1) {
3239- str += ':' + number.format(this.step, options);
3240- }
3241- str += ':' + number.format(this.end, options);
3242- return str;
3243- };
3244-
3245- /**
3246- * Get a string representation of the range.
3247- * @returns {String}
3248- */
3249- Range.prototype.toString = function () {
3250- return this.format();
3251- };
3252-
3253- /**
3254- * Get a JSON representation of the range
3255- * @returns {Object} Returns a JSON object structured as:
3256- * `{"mathjs": "Range", "start": 2, "end": 4, "step": 1}`
3257- */
3258- Range.prototype.toJSON = function () {
3259- return {
3260- mathjs: 'Range',
3261- start: this.start,
3262- end: this.end,
3263- step: this.step
3264- };
3265- };
3266-
3267- /**
3268- * Instantiate a Range from a JSON object
3269- * @param {Object} json A JSON object structured as:
3270- * `{"mathjs": "Range", "start": 2, "end": 4, "step": 1}`
3271- * @return {Range}
3272- */
3273- Range.fromJSON = function (json) {
3274- return new Range(json.start, json.end, json.step);
3275- };
3276-
3277- // exports
3278- module.exports = Range;
3279-
3280-
3281-/***/ },
3282 /* 9 */
3283-/***/ function(module, exports, __webpack_require__) {
3284+/***/ function(module, exports) {
3285
3286 'use strict';
3287
3288- var util = __webpack_require__(175),
3289-
3290- Range = __webpack_require__(8),
3291-
3292- number = util.number,
3293-
3294- isNumber = number.isNumber,
3295- isInteger = number.isInteger,
3296- isArray = Array.isArray;
3297-
3298- /**
3299- * @Constructor Index
3300- * Create an index. An Index can store ranges having start, step, and end
3301- * for multiple dimensions.
3302- * Matrix.get, Matrix.set, and math.subset accept an Index as input.
3303- *
3304- * Usage:
3305- * var index = new Index(range1, range2, ...);
3306- *
3307- * Where each range can be any of:
3308- * An array [start, end]
3309- * An array [start, end, step]
3310- * A number
3311- * An instance of Range
3312- *
3313- * The parameters start, end, and step must be integer numbers.
3314- *
3315- * @param {...*} ranges
3316- */
3317- function Index(ranges) {
3318- if (!(this instanceof Index)) {
3319- throw new SyntaxError('Constructor must be called with the new operator');
3320- }
3321-
3322- this._ranges = [];
3323- this._isScalar = true;
3324-
3325- for (var i = 0, ii = arguments.length; i < ii; i++) {
3326- var arg = arguments[i];
3327-
3328- if (arg instanceof Range) {
3329- this._ranges.push(arg);
3330- this._isScalar = false;
3331- }
3332- else if (isArray(arg)) {
3333- this._ranges.push(_createRange(arg));
3334- this._isScalar = false;
3335- }
3336- else if (isNumber(arg)) {
3337- this._ranges.push(_createRange([arg, arg + 1]));
3338- }
3339- // TODO: implement support for wildcard '*'
3340- else {
3341- var primitive = arg.valueOf(); // for example turn a Matrix into an Array
3342- if (isArray(primitive)) {
3343- this._ranges.push(_createRange(primitive));
3344- this._isScalar = false;
3345- }
3346- else {
3347- throw new TypeError('Ranges must be an Array, Number, or Range');
3348- }
3349- }
3350- }
3351- }
3352-
3353- /**
3354- * Parse an argument into a range and validate the range
3355- * @param {Array} arg An array with [start: Number, end: Number] and
3356- * optional a third element step:Number
3357- * @return {Range} range
3358- * @private
3359- */
3360- function _createRange(arg) {
3361- // TODO: make function _createRange simpler/faster
3362-
3363- // test whether all arguments are integers
3364- var num = arg.length;
3365- for (var i = 0; i < num; i++) {
3366- if (!isNumber(arg[i]) || !isInteger(arg[i])) {
3367- throw new TypeError('Index parameters must be integer numbers');
3368- }
3369- }
3370-
3371- switch (arg.length) {
3372- case 2:
3373- return new Range(arg[0], arg[1]); // start, end
3374- case 3:
3375- return new Range(arg[0], arg[1], arg[2]); // start, end, step
3376- default:
3377- // TODO: improve error message
3378- throw new SyntaxError('Wrong number of arguments in Index (2 or 3 expected)');
3379- }
3380- }
3381-
3382- /**
3383- * Create a clone of the index
3384- * @return {Index} clone
3385- */
3386- Index.prototype.clone = function () {
3387- var index = new Index();
3388- index._ranges = util.object.clone(this._ranges);
3389- index._isScalar = this._isScalar;
3390- return index;
3391- };
3392-
3393- /**
3394- * Test whether an object is an Index
3395- * @param {*} object
3396- * @return {Boolean} isIndex
3397- */
3398- Index.isIndex = function (object) {
3399- return (object instanceof Index);
3400- };
3401-
3402- /**
3403- * Create an index from an array with ranges/numbers
3404- * @param {Array.<Array | Number>} ranges
3405- * @return {Index} index
3406- * @private
3407- */
3408- Index.create = function (ranges) {
3409- var index = new Index();
3410- Index.apply(index, ranges);
3411- return index;
3412- };
3413-
3414- /**
3415- * Retrieve the size of the index, the number of elements for each dimension.
3416- * @returns {Number[]} size
3417- */
3418- Index.prototype.size = function () {
3419- var size = [];
3420-
3421- for (var i = 0, ii = this._ranges.length; i < ii; i++) {
3422- var range = this._ranges[i];
3423-
3424- size[i] = range.size()[0];
3425- }
3426-
3427- return size;
3428- };
3429-
3430- /**
3431- * Get the maximum value for each of the indexes ranges.
3432- * @returns {Number[]} max
3433- */
3434- Index.prototype.max = function () {
3435- var values = [];
3436-
3437- for (var i = 0, ii = this._ranges.length; i < ii; i++) {
3438- var range = this._ranges[i];
3439- values[i] = range.max();
3440- }
3441-
3442- return values;
3443- };
3444-
3445- /**
3446- * Get the minimum value for each of the indexes ranges.
3447- * @returns {Number[]} min
3448- */
3449- Index.prototype.min = function () {
3450- var values = [];
3451-
3452- for (var i = 0, ii = this._ranges.length; i < ii; i++) {
3453- var range = this._ranges[i];
3454-
3455- values[i] = range.min();
3456- }
3457-
3458- return values;
3459- };
3460-
3461- /**
3462- * Loop over each of the ranges of the index
3463- * @param {function} callback Called for each range with a Range as first
3464- * argument, the dimension as second, and the
3465- * index object as third.
3466- */
3467- Index.prototype.forEach = function (callback) {
3468- for (var i = 0, ii = this._ranges.length; i < ii; i++) {
3469- callback(this._ranges[i], i, this);
3470- }
3471- };
3472-
3473- /**
3474- * Retrieve the range for a given dimension number from the index
3475- * @param {Number} dim Number of the dimension
3476- * @returns {Range | null} range
3477- */
3478- Index.prototype.range = function(dim) {
3479- return this._ranges[dim] || null;
3480- };
3481-
3482- /**
3483- * Test whether this index contains only a single value.
3484- *
3485- * This is the case when the index is created with only scalar values as ranges,
3486- * not for ranges resolving into a single value.
3487- * @return {boolean} isScalar
3488- */
3489- Index.prototype.isScalar = function () {
3490- return this._isScalar;
3491- };
3492-
3493- /**
3494- * Expand the Index into an array.
3495- * For example new Index([0,3], [2,7]) returns [[0,1,2], [2,3,4,5,6]]
3496- * @returns {Array} array
3497- */
3498- Index.prototype.toArray = function () {
3499- var array = [];
3500- for (var i = 0, ii = this._ranges.length; i < ii; i++) {
3501- var range = this._ranges[i],
3502- row = [],
3503- x = range.start,
3504- end = range.end,
3505- step = range.step;
3506-
3507- if (step > 0) {
3508- while (x < end) {
3509- row.push(x);
3510- x += step;
3511- }
3512- }
3513- else if (step < 0) {
3514- while (x > end) {
3515- row.push(x);
3516- x += step;
3517- }
3518- }
3519-
3520- array.push(row);
3521- }
3522-
3523- return array;
3524- };
3525-
3526- /**
3527- * Get the primitive value of the Index, a two dimensional array.
3528- * Equivalent to Index.toArray().
3529- * @returns {Array} array
3530- */
3531- Index.prototype.valueOf = Index.prototype.toArray;
3532-
3533- /**
3534- * Get the string representation of the index, for example '[2:6]' or '[0:2:10, 4:7]'
3535- * @returns {String} str
3536- */
3537- Index.prototype.toString = function () {
3538- var strings = [];
3539-
3540- for (var i = 0, ii = this._ranges.length; i < ii; i++) {
3541- var range = this._ranges[i];
3542- var str = number.format(range.start);
3543- if (range.step != 1) {
3544- str += ':' + number.format(range.step);
3545- }
3546- str += ':' + number.format(range.end);
3547- strings.push(str);
3548- }
3549-
3550- return '[' + strings.join(', ') + ']';
3551- };
3552-
3553- /**
3554- * Get a JSON representation of the Index
3555- * @returns {Object} Returns a JSON object structured as:
3556- * `{"mathjs": "Index", "ranges": [{"mathjs": "Range", start: 0, end: 10, step:1}, ...]}`
3557- */
3558- Index.prototype.toJSON = function () {
3559- return {
3560- mathjs: 'Index',
3561- ranges: this._ranges
3562- };
3563- };
3564-
3565- /**
3566- * Instantiate an Index from a JSON object
3567- * @param {Object} json A JSON object structured as:
3568- * `{"mathjs": "Index", "ranges": [{"mathjs": "Range", start: 0, end: 10, step:1}, ...]}`
3569- * @return {Index}
3570- */
3571- Index.fromJSON = function (json) {
3572- return Index.create(json.ranges);
3573- };
3574-
3575- // exports
3576- module.exports = Index;
3577+ /**
3578+ * Format a number using methods toPrecision, toFixed, toExponential.
3579+ * @param {number | string} value
3580+ * @constructor
3581+ */
3582+ function NumberFormatter (value) {
3583+ // parse the input value
3584+ var match = String(value).toLowerCase().match(/^0*?(-?)(\d+\.?\d*)(e([+-]?\d+))?$/);
3585+ if (!match) {
3586+ throw new SyntaxError('Invalid number');
3587+ }
3588+
3589+ var sign = match[1];
3590+ var coefficients = match[2];
3591+ var exponent = parseFloat(match[4] || '0');
3592+
3593+ var dot = coefficients.indexOf('.');
3594+ exponent += (dot !== -1) ? (dot - 1) : (coefficients.length - 1);
3595+
3596+ this.sign = sign;
3597+ this.coefficients = coefficients
3598+ .replace('.', '') // remove the dot (must be removed before removing leading zeros)
3599+ .replace(/^0*/, function (zeros) {
3600+ // remove leading zeros, add their count to the exponent
3601+ exponent -= zeros.length;
3602+ return '';
3603+ })
3604+ .replace(/0*$/, '') // remove trailing zeros
3605+ .split('')
3606+ .map(function (d) {
3607+ return parseInt(d);
3608+ });
3609+
3610+ if (this.coefficients.length === 0) {
3611+ this.coefficients.push(0);
3612+ exponent++;
3613+ }
3614+
3615+ this.exponent = exponent;
3616+ }
3617+
3618+ /**
3619+ * Format a number with fixed notation.
3620+ * @param {number} [precision=0] Optional number of decimals after the
3621+ * decimal point. Zero by default.
3622+ */
3623+ NumberFormatter.prototype.toFixed = function (precision) {
3624+ var rounded = this.roundDigits(this.exponent + 1 + (precision || 0));
3625+ var c = rounded.coefficients;
3626+ var p = rounded.exponent + 1; // exponent may have changed
3627+
3628+ // append zeros if needed
3629+ var pp = p + (precision || 0);
3630+ if (c.length < pp) {
3631+ c = c.concat(zeros(pp - c.length));
3632+ }
3633+
3634+ // prepend zeros if needed
3635+ if (p < 0) {
3636+ c = zeros(-p + 1).concat(c);
3637+ p = 1;
3638+ }
3639+
3640+ // insert a dot if needed
3641+ if (precision) {
3642+ c.splice(p, 0, (p === 0) ? '0.' : '.');
3643+ }
3644+
3645+ return this.sign + c.join('');
3646+ };
3647+
3648+ /**
3649+ * Format a number in exponential notation. Like '1.23e+5', '2.3e+0', '3.500e-3'
3650+ * @param {number} [precision] Number of digits in formatted output.
3651+ * If not provided, the maximum available digits
3652+ * is used.
3653+ */
3654+ NumberFormatter.prototype.toExponential = function (precision) {
3655+ // round if needed, else create a clone
3656+ var rounded = precision ? this.roundDigits(precision) : this.clone();
3657+ var c = rounded.coefficients;
3658+ var e = rounded.exponent;
3659+
3660+ // append zeros if needed
3661+ if (c.length < precision) {
3662+ c = c.concat(zeros(precision - c.length));
3663+ }
3664+
3665+ // format as `C.CCCe+EEE` or `C.CCCe-EEE`
3666+ var first = c.shift();
3667+ return this.sign + first + (c.length > 0 ? ('.' + c.join('')) : '') +
3668+ 'e' + (e >= 0 ? '+' : '') + e;
3669+ };
3670+
3671+ /**
3672+ * Format a number with a certain precision
3673+ * @param {number} [precision=undefined] Optional number of digits.
3674+ * @param {{lower: number | undefined, upper: number | undefined}} [options]
3675+ * By default:
3676+ * lower = 1e-3 (excl)
3677+ * upper = 1e+5 (incl)
3678+ * @return {string}
3679+ */
3680+ NumberFormatter.prototype.toPrecision = function(precision, options) {
3681+ // determine lower and upper bound for exponential notation.
3682+ var lower = (options && options.lower !== undefined) ? options.lower : 1e-3;
3683+ var upper = (options && options.upper !== undefined) ? options.upper : 1e+5;
3684+
3685+ var abs = Math.abs(Math.pow(10, this.exponent));
3686+ if (abs < lower || abs >= upper) {
3687+ // exponential notation
3688+ return this.toExponential(precision);
3689+ }
3690+ else {
3691+ var rounded = precision ? this.roundDigits(precision) : this.clone();
3692+ var c = rounded.coefficients;
3693+ var e = rounded.exponent;
3694+
3695+ // append trailing zeros
3696+ if (c.length < precision) {
3697+ c = c.concat(zeros(precision - c.length));
3698+ }
3699+
3700+ // append trailing zeros
3701+ // TODO: simplify the next statement
3702+ c = c.concat(zeros(e - c.length + 1 +
3703+ (c.length < precision ? precision - c.length : 0)));
3704+
3705+ // prepend zeros
3706+ c = zeros(-e).concat(c);
3707+
3708+ var dot = e > 0 ? e : 0;
3709+ if (dot < c.length - 1) {
3710+ c.splice(dot + 1, 0, '.');
3711+ }
3712+
3713+ return this.sign + c.join('');
3714+ }
3715+ };
3716+
3717+ /**
3718+ * Crete a clone of the NumberFormatter
3719+ * @return {NumberFormatter} Returns a clone of the NumberFormatter
3720+ */
3721+ NumberFormatter.prototype.clone = function () {
3722+ var clone = new NumberFormatter('0');
3723+ clone.sign = this.sign;
3724+ clone.coefficients = this.coefficients.slice(0);
3725+ clone.exponent = this.exponent;
3726+ return clone;
3727+ };
3728+
3729+ /**
3730+ * Round the number of digits of a number *
3731+ * @param {number} precision A positive integer
3732+ * @return {NumberFormatter} Returns a new NumberFormatter with the rounded
3733+ * digits
3734+ */
3735+ NumberFormatter.prototype.roundDigits = function (precision) {
3736+ var rounded = this.clone();
3737+ var c = rounded.coefficients;
3738+
3739+ // prepend zeros if needed
3740+ while (precision <= 0) {
3741+ c.unshift(0);
3742+ rounded.exponent++;
3743+ precision++;
3744+ }
3745+
3746+ if (c.length > precision) {
3747+ var removed = c.splice(precision);
3748+
3749+ if (removed[0] >= 5) {
3750+ var i = precision - 1;
3751+ c[i]++;
3752+ while (c[i] === 10) {
3753+ c.pop();
3754+ if (i === 0) {
3755+ c.unshift(0);
3756+ rounded.exponent++;
3757+ i++;
3758+ }
3759+ i--;
3760+ c[i]++;
3761+ }
3762+ }
3763+ }
3764+
3765+ return rounded;
3766+ };
3767+
3768+ /**
3769+ * Create an array filled with zeros.
3770+ * @param {number} length
3771+ * @return {Array}
3772+ */
3773+ function zeros(length) {
3774+ var arr = [];
3775+ for (var i = 0; i < length; i++) {
3776+ arr.push(0);
3777+ }
3778+ return arr;
3779+ }
3780+
3781+ module.exports = NumberFormatter;
3782
3783
3784 /***/ },
3785@@ -2146,1166 +2561,300 @@
3786
3787 'use strict';
3788
3789- var string = __webpack_require__(176),
3790-
3791- isString = string.isString;
3792-
3793- module.exports = function (config) {
3794-
3795+ var lazy = __webpack_require__(5).lazy;
3796+ var isFactory = __webpack_require__(5).isFactory;
3797+ var traverse = __webpack_require__(5).traverse;
3798+ var extend = __webpack_require__(5).extend;
3799+ var ArgumentsError = __webpack_require__(11);
3800+
3801+ function factory (type, config, load, typed, math) {
3802 /**
3803- * @constructor Matrix
3804- *
3805- * A Matrix is a wrapper around an Array. A matrix can hold a multi dimensional
3806- * array. A matrix can be constructed as:
3807- * var matrix = math.matrix(data)
3808- *
3809- * Matrix contains the functions to resize, get and set values, get the size,
3810- * clone the matrix and to convert the matrix to a vector, array, or scalar.
3811- * Furthermore, one can iterate over the matrix using map and forEach.
3812- * The internal Array of the Matrix can be accessed using the function valueOf.
3813- *
3814- * Example usage:
3815- * var matrix = math.matrix([[1, 2], [3, 4]]);
3816- * matix.size(); // [2, 2]
3817- * matrix.resize([3, 2], 5);
3818- * matrix.valueOf(); // [[1, 2], [3, 4], [5, 5]]
3819- * matrix.subset([1,2]) // 3 (indexes are zero-based)
3820- *
3821+ * Import functions from an object or a module
3822+ *
3823+ * Syntax:
3824+ *
3825+ * math.import(object)
3826+ * math.import(object, options)
3827+ *
3828+ * Where:
3829+ *
3830+ * - `object: Object`
3831+ * An object with functions to be imported.
3832+ * - `options: Object` An object with import options. Available options:
3833+ * - `override: boolean`
3834+ * If true, existing functions will be overwritten. False by default.
3835+ * - `silent: boolean`
3836+ * If true, the function will not throw errors on duplicates or invalid
3837+ * types. False by default.
3838+ * - `wrap: boolean`
3839+ * If true, the functions will be wrapped in a wrapper function
3840+ * which converts data types like Matrix to primitive data types like Array.
3841+ * The wrapper is needed when extending math.js with libraries which do not
3842+ * support these data type. False by default.
3843+ *
3844+ * Examples:
3845+ *
3846+ * // define new functions and variables
3847+ * math.import({
3848+ * myvalue: 42,
3849+ * hello: function (name) {
3850+ * return 'hello, ' + name + '!';
3851+ * }
3852+ * });
3853+ *
3854+ * // use the imported function and variable
3855+ * math.myvalue * 2; // 84
3856+ * math.hello('user'); // 'hello, user!'
3857+ *
3858+ * // import the npm module 'numbers'
3859+ * // (must be installed first with `npm install numbers`)
3860+ * math.import(require('numbers'), {wrap: true});
3861+ *
3862+ * math.fibonacci(7); // returns 13
3863+ *
3864+ * @param {Object | Array} object Object with functions to be imported.
3865+ * @param {Object} [options] Import options.
3866 */
3867- function Matrix() {
3868- if (!(this instanceof Matrix)) {
3869- throw new SyntaxError('Constructor must be called with the new operator');
3870+ function math_import(object, options) {
3871+ var num = arguments.length;
3872+ if (num != 1 && num != 2) {
3873+ throw new ArgumentsError('import', num, 1, 2);
3874+ }
3875+
3876+ if (!options) {
3877+ options = {};
3878+ }
3879+
3880+ if (isFactory(object)) {
3881+ _importFactory(object, options);
3882+ }
3883+ else if (Array.isArray(object)) {
3884+ object.forEach(function (entry) {
3885+ math_import(entry, options);
3886+ });
3887+ }
3888+ else if (typeof object === 'object') {
3889+ // a map with functions
3890+ for (var name in object) {
3891+ if (object.hasOwnProperty(name)) {
3892+ var value = object[name];
3893+ if (isSupportedType(value)) {
3894+ _import(name, value, options);
3895+ }
3896+ else if (isFactory(object)) {
3897+ _importFactory(object, options);
3898+ }
3899+ else {
3900+ math_import(value, options);
3901+ }
3902+ }
3903+ }
3904+ }
3905+ else {
3906+ if (!options.silent) {
3907+ throw new TypeError('Factory, Object, or Array expected');
3908+ }
3909 }
3910 }
3911
3912 /**
3913- * Test whether an object is a Matrix
3914- * @param {*} object
3915- * @return {Boolean} isMatrix
3916- */
3917- Matrix.isMatrix = function (object) {
3918- return (object instanceof Matrix);
3919- };
3920-
3921- /**
3922- * Get the Matrix storage constructor for the given format.
3923- *
3924- * @param {string} format The Matrix storage format.
3925- *
3926- * @return {Function} The Matrix storage constructor.
3927- */
3928- Matrix.storage = function (format) {
3929- // check storage format is a string
3930- if (!isString(format)) {
3931- throw new TypeError('format must be a string value');
3932- }
3933-
3934- // get storage format constructor
3935- var constructor = Matrix._storage[format];
3936- if (!constructor) {
3937- throw new SyntaxError('Unsupported matrix storage format: ' + format);
3938- }
3939-
3940- // return storage constructor
3941- return constructor;
3942- };
3943-
3944- // a map with all constructors for all storage types
3945- Matrix._storage = {};
3946-
3947- /**
3948- * Get the storage format used by the matrix.
3949- *
3950- * Usage:
3951- * var format = matrix.storage() // retrieve storage format
3952- *
3953- * @return {string} The storage format.
3954- */
3955- Matrix.prototype.storage = function () {
3956- // must be implemented by each of the Matrix implementations
3957- throw new Error('Cannot invoke storage on a Matrix interface');
3958- };
3959-
3960- /**
3961- * Get a subset of the matrix, or replace a subset of the matrix.
3962- *
3963- * Usage:
3964- * var subset = matrix.subset(index) // retrieve subset
3965- * var value = matrix.subset(index, replacement) // replace subset
3966- *
3967- * @param {Index} index
3968- * @param {Array | Matrix | *} [replacement]
3969- * @param {*} [defaultValue=0] Default value, filled in on new entries when
3970- * the matrix is resized. If not provided,
3971- * new matrix elements will be filled with zeros.
3972- */
3973- Matrix.prototype.subset = function (index, replacement, defaultValue) {
3974- // must be implemented by each of the Matrix implementations
3975- throw new Error('Cannot invoke subset on a Matrix interface');
3976- };
3977-
3978- /**
3979- * Get a single element from the matrix.
3980- * @param {Number[]} index Zero-based index
3981- * @return {*} value
3982- */
3983- Matrix.prototype.get = function (index) {
3984- // must be implemented by each of the Matrix implementations
3985- throw new Error('Cannot invoke get on a Matrix interface');
3986- };
3987-
3988- /**
3989- * Replace a single element in the matrix.
3990- * @param {Number[]} index Zero-based index
3991+ * Add a property to the math namespace and create a chain proxy for it.
3992+ * @param {string} name
3993 * @param {*} value
3994- * @param {*} [defaultValue] Default value, filled in on new entries when
3995- * the matrix is resized. If not provided,
3996- * new matrix elements will be left undefined.
3997- * @return {Matrix} self
3998- */
3999- Matrix.prototype.set = function (index, value, defaultValue) {
4000- // must be implemented by each of the Matrix implementations
4001- throw new Error('Cannot invoke set on a Matrix interface');
4002- };
4003-
4004- /**
4005- * Resize the matrix to the given size. Returns a copy of the matrix when
4006- * `copy=true`, otherwise return the matrix itself (resize in place).
4007- *
4008- * @param {Number[]} size The new size the matrix should have.
4009- * @param {*} [defaultValue=0] Default value, filled in on new entries.
4010- * If not provided, the matrix elements will
4011- * be filled with zeros.
4012- * @param {boolean} [copy] Return a resized copy of the matrix
4013- *
4014- * @return {Matrix} The resized matrix
4015- */
4016- Matrix.prototype.resize = function (size, defaultValue) {
4017- // must be implemented by each of the Matrix implementations
4018- throw new Error('Cannot invoke resize on a Matrix interface');
4019- };
4020-
4021- /**
4022- * Create a clone of the matrix
4023- * @return {Matrix} clone
4024- */
4025- Matrix.prototype.clone = function () {
4026- // must be implemented by each of the Matrix implementations
4027- throw new Error('Cannot invoke clone on a Matrix interface');
4028- };
4029-
4030- /**
4031- * Retrieve the size of the matrix.
4032- * @returns {Number[]} size
4033- */
4034- Matrix.prototype.size = function() {
4035- // must be implemented by each of the Matrix implementations
4036- throw new Error('Cannot invoke size on a Matrix interface');
4037- };
4038-
4039- /**
4040- * Create a new matrix with the results of the callback function executed on
4041- * each entry of the matrix.
4042- * @param {function} callback The callback function is invoked with three
4043- * parameters: the value of the element, the index
4044- * of the element, and the Matrix being traversed.
4045- * @param {boolean} [skipZeros] Invoke callback function for non-zero values only.
4046- *
4047- * @return {Matrix} matrix
4048- */
4049- Matrix.prototype.map = function (callback, skipZeros) {
4050- // must be implemented by each of the Matrix implementations
4051- throw new Error('Cannot invoke map on a Matrix interface');
4052- };
4053-
4054- /**
4055- * Execute a callback function on each entry of the matrix.
4056- * @param {function} callback The callback function is invoked with three
4057- * parameters: the value of the element, the index
4058- * of the element, and the Matrix being traversed.
4059- */
4060- Matrix.prototype.forEach = function (callback) {
4061- // must be implemented by each of the Matrix implementations
4062- throw new Error('Cannot invoke forEach on a Matrix interface');
4063- };
4064-
4065- /**
4066- * Create an Array with a copy of the data of the Matrix
4067- * @returns {Array} array
4068- */
4069- Matrix.prototype.toArray = function () {
4070- // must be implemented by each of the Matrix implementations
4071- throw new Error('Cannot invoke toArray on a Matrix interface');
4072- };
4073-
4074- /**
4075- * Get the primitive value of the Matrix: a multidimensional array
4076- * @returns {Array} array
4077- */
4078- Matrix.prototype.valueOf = function () {
4079- // must be implemented by each of the Matrix implementations
4080- throw new Error('Cannot invoke valueOf on a Matrix interface');
4081- };
4082-
4083- /**
4084- * Get a string representation of the matrix, with optional formatting options.
4085- * @param {Object | Number | Function} [options] Formatting options. See
4086- * lib/util/number:format for a
4087- * description of the available
4088- * options.
4089- * @returns {String} str
4090- */
4091- Matrix.prototype.format = function (options) {
4092- // must be implemented by each of the Matrix implementations
4093- throw new Error('Cannot invoke format on a Matrix interface');
4094- };
4095-
4096- /**
4097- * Get a string representation of the matrix
4098- * @returns {String} str
4099- */
4100- Matrix.prototype.toString = function () {
4101- // must be implemented by each of the Matrix implementations
4102- throw new Error('Cannot invoke toString on a Matrix interface');
4103- };
4104-
4105- /**
4106- * Calculates the transpose of the matrix
4107- * @returns {Matrix}
4108- */
4109- Matrix.prototype.transpose = function () {
4110- // must be implemented by each of the Matrix implementations
4111- throw new Error('Cannot invoke transpose on a Matrix interface');
4112- };
4113-
4114- /**
4115- * Calculate the trace of a matrix: the sum of the elements on the main
4116- * diagonal of a square matrix.
4117- *
4118- * See also:
4119- *
4120- * diagonal
4121- *
4122- * @returns {Number} The matrix trace
4123- */
4124- Matrix.prototype.trace = function () {
4125- // must be implemented by each of the Matrix implementations
4126- throw new Error('Cannot invoke transpose on a Matrix interface');
4127- };
4128-
4129- /**
4130- * Multiply the matrix values times the argument.
4131- *
4132- * @param {Number | BigNumber | Boolean | Complex | Unit | Array | Matrix | null} Value to multiply.
4133- *
4134- * @return {Number | BigNumber | Complex | Unit | Matrix}
4135- */
4136- Matrix.prototype.multiply = function (value) {
4137- // must be implemented by each of the Matrix implementations
4138- throw new Error('Cannot invoke multiply on a Matrix interface');
4139- };
4140-
4141- // exports
4142- return Matrix;
4143- };
4144+ * @param {Object} options See import for a description of the options
4145+ * @private
4146+ */
4147+ function _import(name, value, options) {
4148+ if (options.wrap && typeof value === 'function') {
4149+ // create a wrapper around the function
4150+ value = _wrap(value);
4151+ }
4152+
4153+ if (isTypedFunction(math[name]) && isTypedFunction(value)) {
4154+ // merge two typed functions
4155+ if (options.override) {
4156+ value = typed(extend({}, math[name].signatures, value.signatures));
4157+ }
4158+ else {
4159+ value = typed(math[name], value);
4160+ }
4161+
4162+ math[name] = value;
4163+ _importTransform(name, value);
4164+ math.emit('import', name, function resolver() {
4165+ return value;
4166+ });
4167+ return;
4168+ }
4169+
4170+ if (math[name] === undefined || options.override) {
4171+ math[name] = value;
4172+ _importTransform(name, value);
4173+ math.emit('import', name, function resolver() {
4174+ return value;
4175+ });
4176+ return;
4177+ }
4178+
4179+ if (!options.silent) {
4180+ throw new Error('Cannot import "' + name + '": already exists');
4181+ }
4182+ }
4183+
4184+ function _importTransform (name, value) {
4185+ if (value && typeof value.transform === 'function') {
4186+ math.expression.transform[name] = value.transform;
4187+ }
4188+ }
4189+
4190+ /**
4191+ * Create a wrapper a round an function which converts the arguments
4192+ * to their primitive values (like convert a Matrix to Array)
4193+ * @param {Function} fn
4194+ * @return {Function} Returns the wrapped function
4195+ * @private
4196+ */
4197+ function _wrap (fn) {
4198+ var wrapper = function wrapper () {
4199+ var args = [];
4200+ for (var i = 0, len = arguments.length; i < len; i++) {
4201+ var arg = arguments[i];
4202+ args[i] = arg && arg.valueOf();
4203+ }
4204+ return fn.apply(math, args);
4205+ };
4206+
4207+ if (fn.transform) {
4208+ wrapper.transform = fn.transform;
4209+ }
4210+
4211+ return wrapper;
4212+ }
4213+
4214+ /**
4215+ * Import an instance of a factory into math.js
4216+ * @param {{factory: Function, name: string, path: string, math: boolean}} factory
4217+ * @param {Object} options See import for a description of the options
4218+ * @private
4219+ */
4220+ function _importFactory(factory, options) {
4221+ if (typeof factory.name === 'string') {
4222+ var name = factory.name;
4223+ var namespace = factory.path ? traverse(math, factory.path) : math;
4224+ var existing = namespace.hasOwnProperty(name) ? namespace[name] : undefined;
4225+
4226+ var resolver = function () {
4227+ var instance = load(factory);
4228+
4229+ if (isTypedFunction(existing) && isTypedFunction(instance)) {
4230+ // merge two typed functions
4231+ if (options.override) {
4232+ instance = typed(extend({}, existing.signatures, instance.signatures));
4233+ }
4234+ else {
4235+ instance = typed(existing, instance);
4236+ }
4237+
4238+ return instance;
4239+ }
4240+
4241+ if (existing === undefined || options.override) {
4242+ return instance;
4243+ }
4244+
4245+ if (!options.silent) {
4246+ throw new Error('Cannot import "' + name + '": already exists');
4247+ }
4248+ };
4249+
4250+ if (factory.lazy !== false) {
4251+ lazy(namespace, name, resolver);
4252+ }
4253+ else {
4254+ namespace[name] = resolver();
4255+ }
4256+
4257+ math.emit('import', name, resolver, factory.path);
4258+ }
4259+ else {
4260+ // unnamed factory.
4261+ // no lazy loading
4262+ load(factory);
4263+ }
4264+ }
4265+
4266+ /**
4267+ * Check whether given object is a type which can be imported
4268+ * @param {Function | number | string | boolean | null | Unit | Complex} object
4269+ * @return {boolean}
4270+ * @private
4271+ */
4272+ function isSupportedType(object) {
4273+ return typeof object == 'function'
4274+ || typeof object === 'number'
4275+ || typeof object === 'string'
4276+ || typeof object === 'boolean'
4277+ || object === null
4278+ || (object && object.isUnit === true)
4279+ || (object && object.isComplex === true)
4280+ }
4281+
4282+ /**
4283+ * Test whether a given thing is a typed-function
4284+ * @param {*} fn
4285+ * @return {boolean} Returns true when `fn` is a typed-function
4286+ */
4287+ function isTypedFunction (fn) {
4288+ return typeof fn === 'function' && typeof fn.signatures === 'object';
4289+ }
4290+
4291+ return math_import;
4292+ }
4293+
4294+ exports.math = true; // request access to the math namespace as 5th argument of the factory function
4295+ exports.name = 'import';
4296+ exports.factory = factory;
4297+ exports.lazy = true;
4298+
4299
4300 /***/ },
4301 /* 11 */
4302-/***/ function(module, exports, __webpack_require__) {
4303+/***/ function(module, exports) {
4304
4305 'use strict';
4306
4307- var util = __webpack_require__(175),
4308-
4309- number = util.number,
4310- string = util.string,
4311- isNumber = util.number.isNumber,
4312- isString = util.string.isString;
4313-
4314- /**
4315- * @constructor Unit
4316- *
4317- * A unit can be constructed in the following ways:
4318- * var a = new Unit(value, name);
4319- * var b = new Unit(null, name);
4320- * var c = Unit.parse(str);
4321- *
4322- * Example usage:
4323- * var a = new Unit(5, 'cm'); // 50 mm
4324- * var b = Unit.parse('23 kg'); // 23 kg
4325- * var c = math.in(a, new Unit(null, 'm'); // 0.05 m
4326- *
4327- * @param {Number} [value] A value like 5.2
4328- * @param {String} [name] A unit name like "cm" or "inch". Can include a prefix
4329- */
4330- function Unit(value, name) {
4331- if (!(this instanceof Unit)) {
4332- throw new Error('Constructor must be called with the new operator');
4333- }
4334-
4335- if (value != undefined && !isNumber(value)) {
4336- throw new TypeError('First parameter in Unit constructor must be a number');
4337- }
4338- if (name != undefined && (!isString(name) || name == '')) {
4339- throw new TypeError('Second parameter in Unit constructor must be a string');
4340- }
4341-
4342- if (name != undefined) {
4343- // find the unit and prefix from the string
4344- var res = _findUnit(name);
4345- if (!res) {
4346- throw new SyntaxError('Unknown unit "' + name + '"');
4347- }
4348- this.unit = res.unit;
4349- this.prefix = res.prefix;
4350- }
4351- else {
4352- this.unit = UNIT_NONE;
4353- this.prefix = PREFIX_NONE; // link to a list with supported prefixes
4354- }
4355-
4356- this.value = (value != undefined) ? this._normalize(value) : null;
4357- this.fixPrefix = false; // if true, function format will not search for the
4358- // best prefix but leave it as initially provided.
4359- // fixPrefix is set true by the method Unit.to
4360- }
4361-
4362- // private variables and functions for the Unit parser
4363- var text, index, c;
4364-
4365- function skipWhitespace() {
4366- while (c == ' ' || c == '\t') {
4367- next();
4368- }
4369- }
4370-
4371- function isDigitDot (c) {
4372- return ((c >= '0' && c <= '9') || c == '.');
4373- }
4374-
4375- function isDigit (c) {
4376- return ((c >= '0' && c <= '9'));
4377- }
4378-
4379- function next() {
4380- index++;
4381- c = text.charAt(index);
4382- }
4383-
4384- function revert(oldIndex) {
4385- index = oldIndex;
4386- c = text.charAt(index);
4387- }
4388-
4389- function parseNumber () {
4390- var number = '';
4391- var oldIndex;
4392- oldIndex = index;
4393-
4394- if (c == '+') {
4395- next();
4396- }
4397- else if (c == '-') {
4398- number += c;
4399- next();
4400- }
4401-
4402- if (!isDigitDot(c)) {
4403- // a + or - must be followed by a digit
4404- revert(oldIndex);
4405- return null;
4406- }
4407-
4408- // get number, can have a single dot
4409- if (c == '.') {
4410- number += c;
4411- next();
4412- if (!isDigit(c)) {
4413- // this is no legal number, it is just a dot
4414- revert(oldIndex);
4415- return null;
4416- }
4417- }
4418- else {
4419- while (isDigit(c)) {
4420- number += c;
4421- next();
4422- }
4423- if (c == '.') {
4424- number += c;
4425- next();
4426- }
4427- }
4428- while (isDigit(c)) {
4429- number += c;
4430- next();
4431- }
4432-
4433- // check for exponential notation like "2.3e-4" or "1.23e50"
4434- if (c == 'E' || c == 'e') {
4435- number += c;
4436- next();
4437-
4438- if (c == '+' || c == '-') {
4439- number += c;
4440- next();
4441- }
4442-
4443- // Scientific notation MUST be followed by an exponent
4444- if (!isDigit(c)) {
4445- // this is no legal number, exponent is missing.
4446- revert(oldIndex);
4447- return null;
4448- }
4449-
4450- while (isDigit(c)) {
4451- number += c;
4452- next();
4453- }
4454- }
4455-
4456- return number;
4457- }
4458-
4459- function parseUnit() {
4460- var unitName = '';
4461-
4462- skipWhitespace();
4463- while (c && c != ' ' && c != '\t') {
4464- unitName += c;
4465- next();
4466- }
4467-
4468- return unitName || null;
4469- }
4470-
4471- /**
4472- * Parse a string into a unit. Returns null if the provided string does not
4473- * contain a valid unit.
4474- * @param {String} str A string like "5.2 inch", "4e2 kg"
4475- * @return {Unit | null} unit
4476- */
4477- Unit.parse = function(str) {
4478- text = str;
4479- index = -1;
4480- c = '';
4481-
4482- if (!isString(text)) {
4483- return null;
4484- }
4485-
4486- next();
4487- skipWhitespace();
4488- var value = parseNumber();
4489- var name;
4490- if (value) {
4491- name = parseUnit();
4492-
4493- next();
4494- skipWhitespace();
4495- if (c) {
4496- // garbage at the end. not good.
4497- return null;
4498- }
4499-
4500- if (value && name) {
4501- try {
4502- // constructor will throw an error when unit is not found
4503- return new Unit(Number(value), name);
4504- }
4505- catch (err) {}
4506- }
4507- }
4508- else {
4509- name = parseUnit();
4510-
4511- next();
4512- skipWhitespace();
4513- if (c) {
4514- // garbage at the end. not good.
4515- return null;
4516- }
4517-
4518- if (name) {
4519- try {
4520- // constructor will throw an error when unit is not found
4521- return new Unit(null, name);
4522- }
4523- catch (err) {}
4524- }
4525- }
4526-
4527- return null;
4528- };
4529-
4530- /**
4531- * Test whether value is of type Unit
4532- * @param {*} value
4533- * @return {Boolean} isUnit
4534- */
4535- Unit.isUnit = function(value) {
4536- return (value instanceof Unit);
4537- };
4538-
4539- /**
4540- * create a copy of this unit
4541- * @return {Unit} clone
4542- */
4543- Unit.prototype.clone = function () {
4544- var clone = new Unit();
4545-
4546- for (var p in this) {
4547- if (this.hasOwnProperty(p)) {
4548- clone[p] = this[p];
4549- }
4550- }
4551-
4552- return clone;
4553- };
4554-
4555- /**
4556- * Normalize a value, based on its currently set unit
4557- * @param {Number} value
4558- * @return {Number} normalized value
4559- * @private
4560- */
4561- Unit.prototype._normalize = function(value) {
4562- return (value + this.unit.offset) * this.unit.value * this.prefix.value;
4563- };
4564-
4565- /**
4566- * Denormalize a value, based on its currently set unit
4567- * @param {Number} value
4568- * @param {Number} [prefixValue] Optional prefix value to be used
4569- * @return {Number} denormalized value
4570- * @private
4571- */
4572- Unit.prototype._denormalize = function (value, prefixValue) {
4573- if (prefixValue == undefined) {
4574- return value / this.unit.value / this.prefix.value - this.unit.offset;
4575- }
4576- else {
4577- return value / this.unit.value / prefixValue - this.unit.offset;
4578- }
4579- };
4580-
4581- /**
4582- * Find a unit from a string
4583- * @param {String} str A string like 'cm' or 'inch'
4584- * @returns {Object | null} result When found, an object with fields unit and
4585- * prefix is returned. Else, null is returned.
4586- * @private
4587- */
4588- function _findUnit(str) {
4589- for (var name in UNITS) {
4590- if (UNITS.hasOwnProperty(name)) {
4591- if (string.endsWith(str, name) ) {
4592- var unit = UNITS[name];
4593- var prefixLen = (str.length - name.length);
4594- var prefixName = str.substring(0, prefixLen);
4595- var prefix = unit.prefixes[prefixName];
4596- if (prefix !== undefined) {
4597- // store unit, prefix, and value
4598- return {
4599- unit: unit,
4600- prefix: prefix
4601- };
4602- }
4603- }
4604- }
4605- }
4606-
4607- return null;
4608- }
4609-
4610- /**
4611- * Test if the given expression is a unit.
4612- * The unit can have a prefix but cannot have a value.
4613- * @param {String} name A string to be tested whether it is a value less unit.
4614- * The unit can have prefix, like "cm"
4615- * @return {Boolean} true if the given string is a unit
4616- */
4617- Unit.isValuelessUnit = function (name) {
4618- return (_findUnit(name) != null);
4619- };
4620-
4621- /**
4622- * check if this unit has given base unit
4623- * @param {BASE_UNITS | undefined} base
4624- */
4625- Unit.prototype.hasBase = function(base) {
4626- return (this.unit.base === base);
4627- };
4628-
4629- /**
4630- * Check if this unit has a base equal to another base
4631- * @param {Unit} other
4632- * @return {Boolean} true if equal base
4633- */
4634- Unit.prototype.equalBase = function(other) {
4635- return (this.unit.base === other.unit.base);
4636- };
4637-
4638- /**
4639- * Check if this unit equals another unit
4640- * @param {Unit} other
4641- * @return {Boolean} true if both units are equal
4642- */
4643- Unit.prototype.equals = function(other) {
4644- return (this.equalBase(other) && this.value == other.value);
4645- };
4646-
4647- /**
4648- * Create a clone of this unit with a representation
4649- * @param {String | Unit} valuelessUnit A unit without value. Can have prefix, like "cm"
4650- * @returns {Unit} unit having fixed, specified unit
4651- */
4652- Unit.prototype.to = function (valuelessUnit) {
4653- var other;
4654- var value = this.value == null ? this._normalize(1) : this.value;
4655- if (isString(valuelessUnit)) {
4656- other = new Unit(null, valuelessUnit);
4657-
4658- if (!this.equalBase(other)) {
4659- throw new Error('Units do not match');
4660- }
4661-
4662- other.value = value;
4663- other.fixPrefix = true;
4664- return other;
4665- }
4666- else if (valuelessUnit instanceof Unit) {
4667- if (!this.equalBase(valuelessUnit)) {
4668- throw new Error('Units do not match');
4669- }
4670- if (valuelessUnit.value !== null) {
4671- throw new Error('Cannot convert to a unit with a value');
4672- }
4673-
4674- other = valuelessUnit.clone();
4675- other.value = value;
4676- other.fixPrefix = true;
4677- return other;
4678- }
4679- else {
4680- throw new Error('String or Unit expected as parameter');
4681- }
4682- };
4683-
4684- /**
4685- * Return the value of the unit when represented with given valueless unit
4686- * @param {String | Unit} valuelessUnit For example 'cm' or 'inch'
4687- * @return {Number} value
4688- */
4689- Unit.prototype.toNumber = function (valuelessUnit) {
4690- var other = this.to(valuelessUnit);
4691- return other._denormalize(other.value, other.prefix.value);
4692- };
4693-
4694-
4695- /**
4696- * Get a string representation of the unit.
4697- * @return {String}
4698- */
4699- Unit.prototype.toString = function() {
4700- return this.format();
4701- };
4702-
4703- /**
4704- * Get a JSON representation of the unit
4705- * @returns {Object} Returns a JSON object structured as:
4706- * `{"mathjs": "Unit", "value": 2, "unit": "cm", "fixPrefix": false}`
4707- */
4708- Unit.prototype.toJSON = function () {
4709- return {
4710- mathjs: 'Unit',
4711- value: this._denormalize(this.value),
4712- unit: this.prefix.name + this.unit.name,
4713- fixPrefix: this.fixPrefix
4714- };
4715- };
4716-
4717- /**
4718- * Instantiate a Unit from a JSON object
4719- * @param {Object} json A JSON object structured as:
4720- * `{"mathjs": "Unit", "value": 2, "unit": "cm", "fixPrefix": false}`
4721- * @return {Unit}
4722- */
4723- Unit.fromJSON = function (json) {
4724- var unit = new Unit(json.value, json.unit);
4725- unit.fixPrefix = json.fixPrefix || false;
4726- return unit;
4727- };
4728-
4729- /**
4730- * Returns the string representation of the unit.
4731- * @return {String}
4732- */
4733- Unit.prototype.valueOf = Unit.prototype.toString;
4734-
4735- /**
4736- * Get a string representation of the Unit, with optional formatting options.
4737- * @param {Object | Number | Function} [options] Formatting options. See
4738- * lib/util/number:format for a
4739- * description of the available
4740- * options.
4741- * @return {String}
4742- */
4743- Unit.prototype.format = function(options) {
4744- var value,
4745- str;
4746-
4747- if (this.value !== null && !this.fixPrefix) {
4748- var bestPrefix = this._bestPrefix();
4749- value = this._denormalize(this.value, bestPrefix.value);
4750- str = number.format(value, options) + ' ';
4751- str += bestPrefix.name + this.unit.name;
4752- }
4753- else {
4754- value = this._denormalize(this.value);
4755- str = (this.value !== null) ? (number.format(value, options) + ' ') : '';
4756- str += this.prefix.name + this.unit.name;
4757- }
4758-
4759- return str;
4760- };
4761-
4762- /**
4763- * Calculate the best prefix using current value.
4764- * @returns {Object} prefix
4765- * @private
4766- */
4767- Unit.prototype._bestPrefix = function () {
4768- // find the best prefix value (resulting in the value of which
4769- // the absolute value of the log10 is closest to zero,
4770- // though with a little offset of 1.2 for nicer values: you get a
4771- // sequence 1mm 100mm 500mm 0.6m 1m 10m 100m 500m 0.6km 1km ...
4772- var absValue = Math.abs(this.value / this.unit.value);
4773- var bestPrefix = PREFIX_NONE;
4774- var bestDiff = Math.abs(
4775- Math.log(absValue / bestPrefix.value) / Math.LN10 - 1.2);
4776-
4777- var prefixes = this.unit.prefixes;
4778- for (var p in prefixes) {
4779- if (prefixes.hasOwnProperty(p)) {
4780- var prefix = prefixes[p];
4781- if (prefix.scientific) {
4782- var diff = Math.abs(
4783- Math.log(absValue / prefix.value) / Math.LN10 - 1.2);
4784-
4785- if (diff < bestDiff) {
4786- bestPrefix = prefix;
4787- bestDiff = diff;
4788- }
4789- }
4790- }
4791- }
4792-
4793- return bestPrefix;
4794- };
4795-
4796- var PREFIXES = {
4797- NONE: {
4798- '': {name: '', value: 1, scientific: true}
4799- },
4800- SHORT: {
4801- '': {name: '', value: 1, scientific: true},
4802-
4803- 'da': {name: 'da', value: 1e1, scientific: false},
4804- 'h': {name: 'h', value: 1e2, scientific: false},
4805- 'k': {name: 'k', value: 1e3, scientific: true},
4806- 'M': {name: 'M', value: 1e6, scientific: true},
4807- 'G': {name: 'G', value: 1e9, scientific: true},
4808- 'T': {name: 'T', value: 1e12, scientific: true},
4809- 'P': {name: 'P', value: 1e15, scientific: true},
4810- 'E': {name: 'E', value: 1e18, scientific: true},
4811- 'Z': {name: 'Z', value: 1e21, scientific: true},
4812- 'Y': {name: 'Y', value: 1e24, scientific: true},
4813-
4814- 'd': {name: 'd', value: 1e-1, scientific: false},
4815- 'c': {name: 'c', value: 1e-2, scientific: false},
4816- 'm': {name: 'm', value: 1e-3, scientific: true},
4817- 'u': {name: 'u', value: 1e-6, scientific: true},
4818- 'n': {name: 'n', value: 1e-9, scientific: true},
4819- 'p': {name: 'p', value: 1e-12, scientific: true},
4820- 'f': {name: 'f', value: 1e-15, scientific: true},
4821- 'a': {name: 'a', value: 1e-18, scientific: true},
4822- 'z': {name: 'z', value: 1e-21, scientific: true},
4823- 'y': {name: 'y', value: 1e-24, scientific: true}
4824- },
4825- LONG: {
4826- '': {name: '', value: 1, scientific: true},
4827-
4828- 'deca': {name: 'deca', value: 1e1, scientific: false},
4829- 'hecto': {name: 'hecto', value: 1e2, scientific: false},
4830- 'kilo': {name: 'kilo', value: 1e3, scientific: true},
4831- 'mega': {name: 'mega', value: 1e6, scientific: true},
4832- 'giga': {name: 'giga', value: 1e9, scientific: true},
4833- 'tera': {name: 'tera', value: 1e12, scientific: true},
4834- 'peta': {name: 'peta', value: 1e15, scientific: true},
4835- 'exa': {name: 'exa', value: 1e18, scientific: true},
4836- 'zetta': {name: 'zetta', value: 1e21, scientific: true},
4837- 'yotta': {name: 'yotta', value: 1e24, scientific: true},
4838-
4839- 'deci': {name: 'deci', value: 1e-1, scientific: false},
4840- 'centi': {name: 'centi', value: 1e-2, scientific: false},
4841- 'milli': {name: 'milli', value: 1e-3, scientific: true},
4842- 'micro': {name: 'micro', value: 1e-6, scientific: true},
4843- 'nano': {name: 'nano', value: 1e-9, scientific: true},
4844- 'pico': {name: 'pico', value: 1e-12, scientific: true},
4845- 'femto': {name: 'femto', value: 1e-15, scientific: true},
4846- 'atto': {name: 'atto', value: 1e-18, scientific: true},
4847- 'zepto': {name: 'zepto', value: 1e-21, scientific: true},
4848- 'yocto': {name: 'yocto', value: 1e-24, scientific: true}
4849- },
4850- SQUARED: {
4851- '': {name: '', value: 1, scientific: true},
4852-
4853- 'da': {name: 'da', value: 1e2, scientific: false},
4854- 'h': {name: 'h', value: 1e4, scientific: false},
4855- 'k': {name: 'k', value: 1e6, scientific: true},
4856- 'M': {name: 'M', value: 1e12, scientific: true},
4857- 'G': {name: 'G', value: 1e18, scientific: true},
4858- 'T': {name: 'T', value: 1e24, scientific: true},
4859- 'P': {name: 'P', value: 1e30, scientific: true},
4860- 'E': {name: 'E', value: 1e36, scientific: true},
4861- 'Z': {name: 'Z', value: 1e42, scientific: true},
4862- 'Y': {name: 'Y', value: 1e48, scientific: true},
4863-
4864- 'd': {name: 'd', value: 1e-2, scientific: false},
4865- 'c': {name: 'c', value: 1e-4, scientific: false},
4866- 'm': {name: 'm', value: 1e-6, scientific: true},
4867- 'u': {name: 'u', value: 1e-12, scientific: true},
4868- 'n': {name: 'n', value: 1e-18, scientific: true},
4869- 'p': {name: 'p', value: 1e-24, scientific: true},
4870- 'f': {name: 'f', value: 1e-30, scientific: true},
4871- 'a': {name: 'a', value: 1e-36, scientific: true},
4872- 'z': {name: 'z', value: 1e-42, scientific: true},
4873- 'y': {name: 'y', value: 1e-42, scientific: true}
4874- },
4875- CUBIC: {
4876- '': {name: '', value: 1, scientific: true},
4877-
4878- 'da': {name: 'da', value: 1e3, scientific: false},
4879- 'h': {name: 'h', value: 1e6, scientific: false},
4880- 'k': {name: 'k', value: 1e9, scientific: true},
4881- 'M': {name: 'M', value: 1e18, scientific: true},
4882- 'G': {name: 'G', value: 1e27, scientific: true},
4883- 'T': {name: 'T', value: 1e36, scientific: true},
4884- 'P': {name: 'P', value: 1e45, scientific: true},
4885- 'E': {name: 'E', value: 1e54, scientific: true},
4886- 'Z': {name: 'Z', value: 1e63, scientific: true},
4887- 'Y': {name: 'Y', value: 1e72, scientific: true},
4888-
4889- 'd': {name: 'd', value: 1e-3, scientific: false},
4890- 'c': {name: 'c', value: 1e-6, scientific: false},
4891- 'm': {name: 'm', value: 1e-9, scientific: true},
4892- 'u': {name: 'u', value: 1e-18, scientific: true},
4893- 'n': {name: 'n', value: 1e-27, scientific: true},
4894- 'p': {name: 'p', value: 1e-36, scientific: true},
4895- 'f': {name: 'f', value: 1e-45, scientific: true},
4896- 'a': {name: 'a', value: 1e-54, scientific: true},
4897- 'z': {name: 'z', value: 1e-63, scientific: true},
4898- 'y': {name: 'y', value: 1e-72, scientific: true}
4899- },
4900- BINARY_SHORT: {
4901- '': {name: '', value: 1, scientific: true},
4902- 'k': {name: 'k', value: 1e3, scientific: true},
4903- 'M': {name: 'M', value: 1e6, scientific: true},
4904- 'G': {name: 'G', value: 1e9, scientific: true},
4905- 'T': {name: 'T', value: 1e12, scientific: true},
4906- 'P': {name: 'P', value: 1e15, scientific: true},
4907- 'E': {name: 'E', value: 1e18, scientific: true},
4908- 'Z': {name: 'Z', value: 1e21, scientific: true},
4909- 'Y': {name: 'Y', value: 1e24, scientific: true},
4910-
4911- 'Ki': {name: 'Ki', value: 1024, scientific: true},
4912- 'Mi': {name: 'Mi', value: Math.pow(1024, 2), scientific: true},
4913- 'Gi': {name: 'Gi', value: Math.pow(1024, 3), scientific: true},
4914- 'Ti': {name: 'Ti', value: Math.pow(1024, 4), scientific: true},
4915- 'Pi': {name: 'Pi', value: Math.pow(1024, 5), scientific: true},
4916- 'Ei': {name: 'Ei', value: Math.pow(1024, 6), scientific: true},
4917- 'Zi': {name: 'Zi', value: Math.pow(1024, 7), scientific: true},
4918- 'Yi': {name: 'Yi', value: Math.pow(1024, 8), scientific: true}
4919- },
4920- BINARY_LONG: {
4921- '': {name: '', value: 1, scientific: true},
4922- 'kilo': {name: 'kilo', value: 1e3, scientific: true},
4923- 'mega': {name: 'mega', value: 1e6, scientific: true},
4924- 'giga': {name: 'giga', value: 1e9, scientific: true},
4925- 'tera': {name: 'tera', value: 1e12, scientific: true},
4926- 'peta': {name: 'peta', value: 1e15, scientific: true},
4927- 'exa': {name: 'exa', value: 1e18, scientific: true},
4928- 'zetta': {name: 'zetta', value: 1e21, scientific: true},
4929- 'yotta': {name: 'yotta', value: 1e24, scientific: true},
4930-
4931- 'kibi': {name: 'kibi', value: 1024, scientific: true},
4932- 'mebi': {name: 'mebi', value: Math.pow(1024, 2), scientific: true},
4933- 'gibi': {name: 'gibi', value: Math.pow(1024, 3), scientific: true},
4934- 'tebi': {name: 'tebi', value: Math.pow(1024, 4), scientific: true},
4935- 'pebi': {name: 'pebi', value: Math.pow(1024, 5), scientific: true},
4936- 'exi': {name: 'exi', value: Math.pow(1024, 6), scientific: true},
4937- 'zebi': {name: 'zebi', value: Math.pow(1024, 7), scientific: true},
4938- 'yobi': {name: 'yobi', value: Math.pow(1024, 8), scientific: true}
4939- }
4940- };
4941-
4942- var PREFIX_NONE = {name: '', value: 1, scientific: true};
4943-
4944- var BASE_UNITS = {
4945- NONE: {},
4946-
4947- LENGTH: {}, // meter
4948- MASS: {}, // kilogram
4949- TIME: {}, // second
4950- CURRENT: {}, // ampere
4951- TEMPERATURE: {}, // kelvin
4952- LUMINOUS_INTENSITY: {}, // candela
4953- AMOUNT_OF_SUBSTANCE: {}, // mole
4954-
4955- FORCE: {}, // Newton
4956- SURFACE: {}, // m2
4957- VOLUME: {}, // m3
4958- ANGLE: {}, // rad
4959- BIT: {} // bit (digital)
4960- };
4961-
4962- var BASE_UNIT_NONE = {};
4963-
4964- var UNIT_NONE = {name: '', base: BASE_UNIT_NONE, value: 1, offset: 0};
4965-
4966- var UNITS = {
4967- // length
4968- meter: {name: 'meter', base: BASE_UNITS.LENGTH, prefixes: PREFIXES.LONG, value: 1, offset: 0},
4969- inch: {name: 'inch', base: BASE_UNITS.LENGTH, prefixes: PREFIXES.NONE, value: 0.0254, offset: 0},
4970- foot: {name: 'foot', base: BASE_UNITS.LENGTH, prefixes: PREFIXES.NONE, value: 0.3048, offset: 0},
4971- yard: {name: 'yard', base: BASE_UNITS.LENGTH, prefixes: PREFIXES.NONE, value: 0.9144, offset: 0},
4972- mile: {name: 'mile', base: BASE_UNITS.LENGTH, prefixes: PREFIXES.NONE, value: 1609.344, offset: 0},
4973- link: {name: 'link', base: BASE_UNITS.LENGTH, prefixes: PREFIXES.NONE, value: 0.201168, offset: 0},
4974- rod: {name: 'rod', base: BASE_UNITS.LENGTH, prefixes: PREFIXES.NONE, value: 5.029210, offset: 0},
4975- chain: {name: 'chain', base: BASE_UNITS.LENGTH, prefixes: PREFIXES.NONE, value: 20.1168, offset: 0},
4976- angstrom: {name: 'angstrom', base: BASE_UNITS.LENGTH, prefixes: PREFIXES.NONE, value: 1e-10, offset: 0},
4977-
4978- m: {name: 'm', base: BASE_UNITS.LENGTH, prefixes: PREFIXES.SHORT, value: 1, offset: 0},
4979- 'in': {name: 'in', base: BASE_UNITS.LENGTH, prefixes: PREFIXES.NONE, value: 0.0254, offset: 0},
4980- ft: {name: 'ft', base: BASE_UNITS.LENGTH, prefixes: PREFIXES.NONE, value: 0.3048, offset: 0},
4981- yd: {name: 'yd', base: BASE_UNITS.LENGTH, prefixes: PREFIXES.NONE, value: 0.9144, offset: 0},
4982- mi: {name: 'mi', base: BASE_UNITS.LENGTH, prefixes: PREFIXES.NONE, value: 1609.344, offset: 0},
4983- li: {name: 'li', base: BASE_UNITS.LENGTH, prefixes: PREFIXES.NONE, value: 0.201168, offset: 0},
4984- rd: {name: 'rd', base: BASE_UNITS.LENGTH, prefixes: PREFIXES.NONE, value: 5.029210, offset: 0},
4985- ch: {name: 'ch', base: BASE_UNITS.LENGTH, prefixes: PREFIXES.NONE, value: 20.1168, offset: 0},
4986- mil: {name: 'mil', base: BASE_UNITS.LENGTH, prefixes: PREFIXES.NONE, value: 0.0000254, offset: 0}, // 1/1000 inch
4987-
4988- // Surface
4989- m2: {name: 'm2', base: BASE_UNITS.SURFACE, prefixes: PREFIXES.SQUARED, value: 1, offset: 0},
4990- sqin: {name: 'sqin', base: BASE_UNITS.SURFACE, prefixes: PREFIXES.NONE, value: 0.00064516, offset: 0}, // 645.16 mm2
4991- sqft: {name: 'sqft', base: BASE_UNITS.SURFACE, prefixes: PREFIXES.NONE, value: 0.09290304, offset: 0}, // 0.09290304 m2
4992- sqyd: {name: 'sqyd', base: BASE_UNITS.SURFACE, prefixes: PREFIXES.NONE, value: 0.83612736, offset: 0}, // 0.83612736 m2
4993- sqmi: {name: 'sqmi', base: BASE_UNITS.SURFACE, prefixes: PREFIXES.NONE, value: 2589988.110336, offset: 0}, // 2.589988110336 km2
4994- sqrd: {name: 'sqrd', base: BASE_UNITS.SURFACE, prefixes: PREFIXES.NONE, value: 25.29295, offset: 0}, // 25.29295 m2
4995- sqch: {name: 'sqch', base: BASE_UNITS.SURFACE, prefixes: PREFIXES.NONE, value: 404.6873, offset: 0}, // 404.6873 m2
4996- sqmil: {name: 'sqmil', base: BASE_UNITS.SURFACE, prefixes: PREFIXES.NONE, value: 6.4516e-10, offset: 0}, // 6.4516 * 10^-10 m2
4997-
4998- // Volume
4999- m3: {name: 'm3', base: BASE_UNITS.VOLUME, prefixes: PREFIXES.CUBIC, value: 1, offset: 0},
5000- L: {name: 'L', base: BASE_UNITS.VOLUME, prefixes: PREFIXES.SHORT, value: 0.001, offset: 0}, // litre
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches