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

Proposed by Bartosz Kosiorek
Status: Merged
Approved by: Nicholas Skaggs
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
Riccardo Padovani Approve
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.
Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Riccardo Padovani (rpadovani) wrote :

lgtm, thanks!

review: Approve
Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Needs Fixing (continuous-integration)
222. By Bartosz Kosiorek

Upgrade math.js to 2.2

223. By Bartosz Kosiorek

Upgrade math.js to 2.2.0

224. By Bartosz Kosiorek

Tune math.js for calculator purposes

Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Nicholas Skaggs (nskaggs) wrote :

Rebuilding with jenkins fixed :-)

Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
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