aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorUlrich-Matthias Schäfer <ulima.ums@googlemail.com>2017-07-06 11:07:29 +0200
committerUlrich-Matthias Schäfer <ulima.ums@googlemail.com>2017-07-06 11:07:29 +0200
commitf1bd0b48ea9cc3a499c02c524924e81eb97e9a6e (patch)
tree3f3779d3afd5126ccb7d97fd82a9f672cd677458
parent0e72ab27955ad7706157dd6fcc1ce1db091d65cf (diff)
parenta19b4f1dfe06d70775a03ec5428b0423fbb46819 (diff)
downloadsvg.js-f1bd0b48ea9cc3a499c02c524924e81eb97e9a6e.tar.gz
svg.js-f1bd0b48ea9cc3a499c02c524924e81eb97e9a6e.zip
Merge branch 'master' into 3.0.0
Conflicts (All resolved): dist/svg.js dist/svg.min.js package.json src/doc.js
-rw-r--r--.config/karma.conf.js4
-rw-r--r--.config/pretest.js4
-rw-r--r--.gitignore1
-rw-r--r--CHANGELOG.md47
-rw-r--r--dist/svg.js67
-rw-r--r--dist/svg.min.js4
-rw-r--r--spec/SpecRunner.html24
-rw-r--r--spec/fixture.svg29
-rw-r--r--spec/fixtures/fixture.css (renamed from spec/fixture.css)0
-rw-r--r--spec/fixtures/fixture.svg29
-rw-r--r--spec/lib/jasmine-2.6.0/boot.js (renamed from spec/lib/jasmine-2.5.2/boot.js)5
-rw-r--r--spec/lib/jasmine-2.6.0/console.js (renamed from spec/lib/jasmine-2.5.2/console.js)2
-rw-r--r--spec/lib/jasmine-2.6.0/jasmine-html.js (renamed from spec/lib/jasmine-2.5.2/jasmine-html.js)20
-rw-r--r--spec/lib/jasmine-2.6.0/jasmine.css (renamed from spec/lib/jasmine-2.5.2/jasmine.css)0
-rw-r--r--spec/lib/jasmine-2.6.0/jasmine.js (renamed from spec/lib/jasmine-2.5.2/jasmine.js)3542
-rw-r--r--spec/lib/jasmine-2.6.0/jasmine_favicon.png (renamed from spec/lib/jasmine-2.5.2/jasmine_favicon.png)bin1486 -> 1486 bytes
-rw-r--r--spec/spec/fx.js92
-rw-r--r--src/fx.js60
-rw-r--r--src/matrix.js2
-rw-r--r--src/textpath.js3
-rw-r--r--svg.js.d.ts22
21 files changed, 2711 insertions, 1246 deletions
diff --git a/.config/karma.conf.js b/.config/karma.conf.js
index f2bdfeb..42ceb39 100644
--- a/.config/karma.conf.js
+++ b/.config/karma.conf.js
@@ -17,12 +17,12 @@ module.exports = function(config) {
files: [
'.config/pretest.js',
{
- pattern: 'spec/fixture.css',
+ pattern: 'spec/fixtures/fixture.css',
included: false,
served: true
},
{
- pattern: 'spec/fixture.svg',
+ pattern: 'spec/fixtures/fixture.svg',
included: false,
served: true
},
diff --git a/.config/pretest.js b/.config/pretest.js
index 1ccaf89..834e8d8 100644
--- a/.config/pretest.js
+++ b/.config/pretest.js
@@ -12,9 +12,9 @@ function get(uri) {
function main() {
var style = document.createElement("style")
document.head.appendChild(style)
- style.sheet.insertRule( get('/base/spec/fixture.css'), 0 )
+ style.sheet.insertRule( get('/fixtures/fixture.css'), 0 )
- document.body.innerHTML = get('/base/spec/fixture.svg')
+ document.body.innerHTML = get('/fixtures/fixture.svg')
}
main()
diff --git a/.gitignore b/.gitignore
index 57a3831..f58d182 100644
--- a/.gitignore
+++ b/.gitignore
@@ -10,3 +10,4 @@ src/index.js
node_modules/
.vscode/
coverage/
+fonts/ \ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 60b727d..b18c88b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -44,6 +44,25 @@ The document follows the conventions described in [“Keep a CHANGELOG”](http:
- fixed a bug in clipping and masking where empty nodes persists after removal -> __TODO!__
- fixed a bug in IE11 with `mouseenter` and `mouseleave` -> __TODO!__
+## [2.6.2] - 2017-06-05
+
+### Added
+- added `width()` and `height()` methods to `SVG.FX`
+- added the intended functionality to call animate functions with multiple parameter (#671)
+
+### Changed
+- updated Jasmine from 2.5.2 to 2.6.0
+- removed the typeof check in the initialisation of SVG.Matrix
+
+### Fixed
+- fixed `SVG.FX.once` so that it add its callback on the last situation instead of the current one
+- fixed `SVG.FX.step` so that the animation doesn't stop if an afterAll callback call animate (#677)
+
+
+## [2.6.1] - 2017-04-25
+
+### Fixed
+- fixed a bug in path parser which made it stop parsing when hitting z command (#665)
## [2.6.1] - 2017-04-25
@@ -194,7 +213,7 @@ The document follows the conventions described in [“Keep a CHANGELOG”](http:
- add error callback on image loading (#508)
### Fixed
-- fixed bug when getting bbox of text elements which are not in the dom (#514)
+- fixed bug when getting bbox of text elements which are not in the dom (#514)
- fixed bug when getting bbox of element which is hidden with css (#516)
@@ -609,11 +628,15 @@ The document follows the conventions described in [“Keep a CHANGELOG”](http:
<!-- Headings above link to the releases listed here -->
+[2.6.2]: https://github.com/svgdotjs/svg.js/releases/tag/2.6.2
+[2.6.1]: https://github.com/svgdotjs/svg.js/releases/tag/2.6.1
[2.6.0]: https://github.com/svgdotjs/svg.js/releases/tag/2.6.0
+
[2.5.3]: https://github.com/svgdotjs/svg.js/releases/tag/2.5.3
[2.5.2]: https://github.com/svgdotjs/svg.js/releases/tag/2.5.2
[2.5.1]: https://github.com/svgdotjs/svg.js/releases/tag/2.5.1
[2.5.0]: https://github.com/svgdotjs/svg.js/releases/tag/2.5.0
+
[2.4.0]: https://github.com/svgdotjs/svg.js/releases/tag/2.4.0
[2.3.7]: https://github.com/svgdotjs/svg.js/releases/tag/2.3.7
@@ -645,14 +668,14 @@ The document follows the conventions described in [“Keep a CHANGELOG”](http:
[1.0.0-rc.6]: https://github.com/svgdotjs/svg.js/releases/tag/1.0.0-rc.6
[1.0.0-rc.5]: https://github.com/svgdotjs/svg.js/releases/tag/1.0.0-rc.5
[1.0.0-rc.4]: https://github.com/svgdotjs/svg.js/releases/tag/1.0.0-rc.4
-[v1.0rc3]: https://github.com/svgdotjs/svg.js/releases/tag/v1.0rc3
-[v1.0rc2]: https://github.com/svgdotjs/svg.js/releases/tag/v1.0rc2
-[v1.0rc1]: https://github.com/svgdotjs/svg.js/releases/tag/v1.0rc1
-
-[v0.38]: https://github.com/svgdotjs/svg.js/releases/tag/v0.38
-[v0.37]: https://github.com/svgdotjs/svg.js/releases/tag/v0.37
-[v0.36]: https://github.com/svgdotjs/svg.js/releases/tag/v0.36
-[v0.35]: https://github.com/svgdotjs/svg.js/releases/tag/v0.35
-[v0.34]: https://github.com/svgdotjs/svg.js/releases/tag/v0.34
-[v0.33]: https://github.com/svgdotjs/svg.js/releases/tag/v0.33
-[v0.32]: https://github.com/svgdotjs/svg.js/releases/tag/v0.32
+[v1.0rc3]: https://github.com/svgdotjs/svg.js/releases/tag/1.0rc3
+[v1.0rc2]: https://github.com/svgdotjs/svg.js/releases/tag/1.0rc2
+[v1.0rc1]: https://github.com/svgdotjs/svg.js/releases/tag/1.0rc1
+
+[v0.38]: https://github.com/svgdotjs/svg.js/releases/tag/0.38
+[v0.37]: https://github.com/svgdotjs/svg.js/releases/tag/0.37
+[v0.36]: https://github.com/svgdotjs/svg.js/releases/tag/0.36
+[v0.35]: https://github.com/svgdotjs/svg.js/releases/tag/0.35
+[v0.34]: https://github.com/svgdotjs/svg.js/releases/tag/0.34
+[v0.33]: https://github.com/svgdotjs/svg.js/releases/tag/0.33
+[v0.32]: https://github.com/svgdotjs/svg.js/releases/tag/0.32
diff --git a/dist/svg.js b/dist/svg.js
index 4430a42..9e983c8 100644
--- a/dist/svg.js
+++ b/dist/svg.js
@@ -6,7 +6,7 @@
* @copyright Wout Fierens <wout@mick-wout.com>
* @license MIT
*
-* BUILT: Tue Apr 25 2017 15:05:49 GMT+0200 (Mitteleuropäische Sommerzeit)
+* BUILT: Thu Jul 06 2017 11:05:46 GMT+0200 (Mitteleuropäische Sommerzeit)
*/;
(function(root, factory) {
/* istanbul ignore next */
@@ -1487,7 +1487,7 @@ SVG.FX = SVG.invent({
// updates all animations to the current state of the element
// this is important when one property could be changed from another property
, initAnimations: function() {
- var i, source
+ var i, j, source
var s = this.situation
if(s.init) return this
@@ -1495,12 +1495,26 @@ SVG.FX = SVG.invent({
for(i in s.animations){
source = this.target()[i]()
- // The condition is because some methods return a normal number instead
- // of a SVG.Number
- if(s.animations[i] instanceof SVG.Number)
- source = new SVG.Number(source)
+ if(!Array.isArray(source)) {
+ source = [source]
+ }
+
+ if(!Array.isArray(s.animations[i])) {
+ s.animations[i] = [s.animations[i]]
+ }
+
+ //if(s.animations[i].length > source.length) {
+ // source.concat = source.concat(s.animations[i].slice(source.length, s.animations[i].length))
+ //}
+
+ for(j = source.length; j--;) {
+ // The condition is because some methods return a normal number instead
+ // of a SVG.Number
+ if(s.animations[i][j] instanceof SVG.Number)
+ source[j] = new SVG.Number(source[j])
- s.animations[i] = source.morph(s.animations[i])
+ s.animations[i][j] = source[j].morph(s.animations[i][j])
+ }
}
for(i in s.attrs){
@@ -1836,8 +1850,12 @@ SVG.FX = SVG.invent({
if(!this.situations.length){
this.target().fire('allfinished')
- this.target().off('.fx') // there shouldnt be any binding left, but to make sure...
- this.active = false
+
+ // Recheck the length since the user may call animate in the afterAll callback
+ if(!this.situations.length){
+ this.target().off('.fx') // there shouldnt be any binding left, but to make sure...
+ this.active = false
+ }
}
// start next animation
@@ -1933,10 +1951,10 @@ SVG.FX = SVG.invent({
// adds an once-callback which is called at a specific position and never again
, once: function(pos, fn, isEased){
+ var c = this.last()
+ if(!isEased) pos = c.ease(pos)
- if(!isEased)pos = this.situation.ease(pos)
-
- this.situation.once[pos] = fn
+ c.once[pos] = fn
return this
}
@@ -2005,6 +2023,8 @@ SVG.MorphObj = SVG.invent({
create: function(from, to){
// prepare color for morphing
if(SVG.Color.isColor(to)) return new SVG.Color(from).morph(to)
+ // prepare value list for morphing
+ if(SVG.regex.delimiter.test(from)) return new SVG.Array(from).morph(to)
// prepare number for morphing
if(SVG.regex.numberAndUnit.test(to)) return new SVG.Number(from).morph(to)
@@ -2117,10 +2137,22 @@ SVG.extend(SVG.FX, {
return this
}
+ // Add animatable width
+, width: function(width) {
+ return this.add('width', new SVG.Number(width))
+ }
+ // Add animatable height
+, height: function(height) {
+ return this.add('height', new SVG.Number(height))
+ }
// Add animatable plot
-, plot: function() {
- // We use arguments here since SVG.Line's plot method can be passed 4 parameters
- return this.add('plot', arguments.length > 1 ? [].slice.call(arguments) : arguments[0])
+, plot: function(a, b, c, d) {
+ // Lines can be plotted with 4 arguments
+ if(arguments.length == 4) {
+ return this.plot([a, b, c, d])
+ }
+
+ return this.add('plot', new (this.target().morphArray)(a))
}
// Add leading method
, leading: function(value) {
@@ -2174,7 +2206,7 @@ SVG.Matrix = SVG.invent({
// merge source
for (i = abcdef.length - 1; i >= 0; --i)
- this[abcdef[i]] = source && typeof source[abcdef[i]] === 'number' ?
+ this[abcdef[i]] = source[abcdef[i]] != null ?
source[abcdef[i]] : base[abcdef[i]]
}
@@ -4373,8 +4405,9 @@ SVG.TextPath = SVG.invent({
// Add parent method
, construct: {
+ morphArray: SVG.PathArray
// Create path for text to run on
- path: function(d) {
+ , path: function(d) {
// create textPath element
var path = new SVG.TextPath
, track = this.doc().defs().path(d)
diff --git a/dist/svg.min.js b/dist/svg.min.js
index 6c6f675..3bd422d 100644
--- a/dist/svg.min.js
+++ b/dist/svg.min.js
@@ -1,2 +1,2 @@
-/*! svg.js v3.0.0 MIT*/;!function(t,e){"function"==typeof define&&define.amd?define(function(){return e(t,t.document)}):"object"==typeof exports?module.exports=t.document?e(t,t.document):function(t){return e(t,t.document)}:t.SVG=e(t,t.document)}("undefined"!=typeof window?window:this,function(t,e){function n(t){return!(t.w||t.h||t.x||t.y)}function i(t){return(e.documentElement.contains||function(t){for(;t.parentNode;)t=t.parentNode;return t==e}).call(e.documentElement,t)}function r(t,e,n,i){return n+i.replace(b.regex.dots," .")}function s(t){for(var e=t.slice(0),n=e.length;n--;)Array.isArray(e[n])&&(e[n]=s(e[n]));return e}function a(t,e){return t instanceof e}function o(t,e){return(t.matches||t.matchesSelector||t.msMatchesSelector||t.mozMatchesSelector||t.webkitMatchesSelector||t.oMatchesSelector).call(t,e)}function h(t){return t.toLowerCase().replace(/-(.)/g,function(t,e){return e.toUpperCase()})}function u(t){return t.charAt(0).toUpperCase()+t.slice(1)}function l(t){return 4==t.length?["#",t.substring(1,2),t.substring(1,2),t.substring(2,3),t.substring(2,3),t.substring(3,4),t.substring(3,4)].join(""):t}function c(t){var e=t.toString(16);return 1==e.length?"0"+e:e}function f(t,e,n){if(null==e||null==n){var i=t.bbox();null==e?e=i.width/i.height*n:null==n&&(n=i.height/i.width*e)}return{width:e,height:n}}function d(t,e,n){return{x:e*t.a+n*t.c+0,y:e*t.b+n*t.d+0}}function p(t){return{a:t[0],b:t[1],c:t[2],d:t[3],e:t[4],f:t[5]}}function x(t){return t instanceof b.Matrix||(t=new b.Matrix(t)),t}function m(t,e){t.cx=null==t.cx?e.bbox().cx:t.cx,t.cy=null==t.cy?e.bbox().cy:t.cy}function y(t){for(var e=0,n=t.length,i="";e<n;e++)i+=t[e][0],null!=t[e][1]&&(i+=t[e][1],null!=t[e][2]&&(i+=" ",i+=t[e][2],null!=t[e][3]&&(i+=" ",i+=t[e][3],i+=" ",i+=t[e][4],null!=t[e][5]&&(i+=" ",i+=t[e][5],i+=" ",i+=t[e][6],null!=t[e][7]&&(i+=" ",i+=t[e][7])))));return i+" "}function v(e){for(var n=e.childNodes.length-1;n>=0;n--)e.childNodes[n]instanceof t.SVGElement&&v(e.childNodes[n]);return e.id?b.adopt(e).id(b.eid(e.nodeName)):b.adopt(e)}function g(t){return null==t.x&&(t.x=0,t.y=0,t.width=0,t.height=0),t.w=t.width,t.h=t.height,t.x2=t.x+t.width,t.y2=t.y+t.height,t.cx=t.x+t.width/2,t.cy=t.y+t.height/2,t}function w(t){var e=(t||"").toString().match(b.regex.reference);if(e)return e[1]}var b=this.SVG=function(t){if(b.supported)return t=new b.Doc(t),b.parser.draw||b.prepare(),t};if(b.ns="http://www.w3.org/2000/svg",b.xmlns="http://www.w3.org/2000/xmlns/",b.xlink="http://www.w3.org/1999/xlink",b.svgjs="http://svgjs.com/svgjs",b.supported=function(){return!!e.createElementNS&&!!e.createElementNS(b.ns,"svg").createSVGRect}(),!b.supported)return!1;b.did=1e3,b.eid=function(t){return"Svgjs"+u(t)+b.did++},b.create=function(t){return e.createElementNS(this.ns,t)},b.extend=function(t,e){var n,i;for(t=Array.isArray(t)?t:[t],i=t.length-1;i>=0;i--)if(t[i])for(n in e)t[i].prototype[n]=e[n]},b.invent=function(t){var e="function"==typeof t.create?t.create:function(){this.constructor.call(this,b.create(t.create))};return t.inherit&&(e.prototype=new t.inherit),t.extend&&b.extend(e,t.extend),t.construct&&b.extend(t.parent||b.Container,t.construct),e},b.adopt=function(e){if(!e)return null;if(e.instance)return e.instance;var n;return n="svg"==e.nodeName?e.parentNode instanceof t.SVGElement?new b.Nested:new b.Doc:"linearGradient"==e.nodeName?new b.Gradient("linear"):"radialGradient"==e.nodeName?new b.Gradient("radial"):b[u(e.nodeName)]?new(b[u(e.nodeName)]):new b.Element(e),n.type=e.nodeName,n.node=e,e.instance=n,n instanceof b.Doc&&n.namespace().defs(),n.setData(JSON.parse(e.getAttribute("svgjs:data"))||{}),n},b.prepare=function(){var t=e.getElementsByTagName("body")[0],n=(t?new b.Doc(t):b.adopt(e.documentElement).nested()).size(2,0);b.parser={body:t||e.documentElement,draw:n.css({opacity:0,position:"absolute",left:"-100%",top:"-100%",overflow:"hidden"}).node,poly:n.polyline().node,path:n.path().node,native:b.create("svg")}},b.parser={native:b.create("svg")},e.addEventListener("DOMContentLoaded",function(){b.parser.draw||b.prepare()},!1),b.regex={numberAndUnit:/^([+-]?(\d+(\.\d*)?|\.\d+)(e[+-]?\d+)?)([a-z%]*)$/i,hex:/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i,rgb:/rgb\((\d+),(\d+),(\d+)\)/,reference:/#([a-z0-9\-_]+)/i,transforms:/\)\s*,?\s*/,whitespace:/\s/g,isHex:/^#[a-f0-9]{3,6}$/i,isRgb:/^rgb\(/,isCss:/[^:]+:[^;]+;?/,isBlank:/^(\s+)?$/,isNumber:/^[+-]?(\d+(\.\d*)?|\.\d+)(e[+-]?\d+)?$/i,isPercent:/^-?[\d\.]+%$/,isImage:/\.(jpg|jpeg|png|gif|svg)(\?[^=]+.*)?/i,delimiter:/[\s,]+/,hyphen:/([^e])\-/gi,pathLetters:/[MLHVCSQTAZ]/gi,isPathLetter:/[MLHVCSQTAZ]/i,numbersWithDots:/((\d?\.\d+(?:e[+-]?\d+)?)((?:\.\d+(?:e[+-]?\d+)?)+))+/gi,dots:/\./g},b.utils={map:function(t,e){var n,i=t.length,r=[];for(n=0;n<i;n++)r.push(e(t[n]));return r},filter:function(t,e){var n,i=t.length,r=[];for(n=0;n<i;n++)e(t[n])&&r.push(t[n]);return r},radians:function(t){return t%360*Math.PI/180},degrees:function(t){return 180*t/Math.PI%360},filterSVGElements:function(e){return this.filter(e,function(e){return e instanceof t.SVGElement})}},b.defaults={attrs:{"fill-opacity":1,"stroke-opacity":1,"stroke-width":0,"stroke-linejoin":"miter","stroke-linecap":"butt",fill:"#000000",stroke:"#000000",opacity:1,x:0,y:0,cx:0,cy:0,width:0,height:0,r:0,rx:0,ry:0,offset:0,"stop-opacity":1,"stop-color":"#000000","font-size":16,"font-family":"Helvetica, Arial, sans-serif","text-anchor":"start"}},b.Color=function(t){var e;this.r=0,this.g=0,this.b=0,t&&("string"==typeof t?b.regex.isRgb.test(t)?(e=b.regex.rgb.exec(t.replace(b.regex.whitespace,"")),this.r=parseInt(e[1]),this.g=parseInt(e[2]),this.b=parseInt(e[3])):b.regex.isHex.test(t)&&(e=b.regex.hex.exec(l(t)),this.r=parseInt(e[1],16),this.g=parseInt(e[2],16),this.b=parseInt(e[3],16)):"object"==typeof t&&(this.r=t.r,this.g=t.g,this.b=t.b))},b.extend(b.Color,{toString:function(){return this.toHex()},toHex:function(){return"#"+c(this.r)+c(this.g)+c(this.b)},toRgb:function(){return"rgb("+[this.r,this.g,this.b].join()+")"},brightness:function(){return this.r/255*.3+this.g/255*.59+this.b/255*.11},morph:function(t){return this.destination=new b.Color(t),this},at:function(t){return this.destination?(t=t<0?0:t>1?1:t,new b.Color({r:~~(this.r+(this.destination.r-this.r)*t),g:~~(this.g+(this.destination.g-this.g)*t),b:~~(this.b+(this.destination.b-this.b)*t)})):this}}),b.Color.test=function(t){return t+="",b.regex.isHex.test(t)||b.regex.isRgb.test(t)},b.Color.isRgb=function(t){return t&&"number"==typeof t.r&&"number"==typeof t.g&&"number"==typeof t.b},b.Color.isColor=function(t){return b.Color.isRgb(t)||b.Color.test(t)},b.Array=function(t,e){t=(t||[]).valueOf(),0==t.length&&e&&(t=e.valueOf()),this.value=this.parse(t)},b.extend(b.Array,{morph:function(t){if(this.destination=this.parse(t),this.value.length!=this.destination.length){for(var e=this.value[this.value.length-1],n=this.destination[this.destination.length-1];this.value.length>this.destination.length;)this.destination.push(n);for(;this.value.length<this.destination.length;)this.value.push(e)}return this},settle:function(){for(var t=0,e=this.value.length,n=[];t<e;t++)n.indexOf(this.value[t])==-1&&n.push(this.value[t]);return this.value=n},at:function(t){if(!this.destination)return this;for(var e=0,n=this.value.length,i=[];e<n;e++)i.push(this.value[e]+(this.destination[e]-this.value[e])*t);return new b.Array(i)},toString:function(){return this.value.join(" ")},valueOf:function(){return this.value},parse:function(t){return t=t.valueOf(),Array.isArray(t)?t:t.trim().split(b.regex.delimiter).map(parseFloat)},reverse:function(){return this.value.reverse(),this},clone:function(){var t=new this.constructor;return t.value=s(this.value),t}}),b.PointArray=function(t,e){b.Array.call(this,t,e||[[0,0]])},b.PointArray.prototype=new b.Array,b.PointArray.prototype.constructor=b.PointArray,b.extend(b.PointArray,{toString:function(){for(var t=0,e=this.value.length,n=[];t<e;t++)n.push(this.value[t].join(","));return n.join(" ")},toLine:function(){return{x1:this.value[0][0],y1:this.value[0][1],x2:this.value[1][0],y2:this.value[1][1]}},at:function(t){if(!this.destination)return this;for(var e=0,n=this.value.length,i=[];e<n;e++)i.push([this.value[e][0]+(this.destination[e][0]-this.value[e][0])*t,this.value[e][1]+(this.destination[e][1]-this.value[e][1])*t]);return new b.PointArray(i)},parse:function(t){var e=[];if(t=t.valueOf(),Array.isArray(t)){if(Array.isArray(t[0]))return t}else t=t.trim().split(b.regex.delimiter).map(parseFloat);t.length%2!==0&&t.pop();for(var n=0,i=t.length;n<i;n+=2)e.push([t[n],t[n+1]]);return e},move:function(t,e){var n=this.bbox();if(t-=n.x,e-=n.y,!isNaN(t)&&!isNaN(e))for(var i=this.value.length-1;i>=0;i--)this.value[i]=[this.value[i][0]+t,this.value[i][1]+e];return this},size:function(t,e){var n,i=this.bbox();for(n=this.value.length-1;n>=0;n--)i.width&&(this.value[n][0]=(this.value[n][0]-i.x)*t/i.width+i.x),i.height&&(this.value[n][1]=(this.value[n][1]-i.y)*e/i.height+i.y);return this},bbox:function(){return b.parser.poly.setAttribute("points",this.toString()),b.parser.poly.getBBox()}});for(var C={M:function(t,e,n){return e.x=n.x=t[0],e.y=n.y=t[1],["M",e.x,e.y]},L:function(t,e){return e.x=t[0],e.y=t[1],["L",t[0],t[1]]},H:function(t,e){return e.x=t[0],["H",t[0]]},V:function(t,e){return e.y=t[0],["V",t[0]]},C:function(t,e){return e.x=t[4],e.y=t[5],["C",t[0],t[1],t[2],t[3],t[4],t[5]]},S:function(t,e){return e.x=t[2],e.y=t[3],["S",t[0],t[1],t[2],t[3]]},Q:function(t,e){return e.x=t[2],e.y=t[3],["Q",t[0],t[1],t[2],t[3]]},T:function(t,e){return e.x=t[0],e.y=t[1],["T",t[0],t[1]]},Z:function(t,e,n){return e.x=n.x,e.y=n.y,["Z"]},A:function(t,e){return e.x=t[5],e.y=t[6],["A",t[0],t[1],t[2],t[3],t[4],t[5],t[6]]}},P="mlhvqtcsaz".split(""),M=0,N=P.length;M<N;++M)C[P[M]]=function(t){return function(e,n,i){if("H"==t)e[0]=e[0]+n.x;else if("V"==t)e[0]=e[0]+n.y;else if("A"==t)e[5]=e[5]+n.x,e[6]=e[6]+n.y;else for(var r=0,s=e.length;r<s;++r)e[r]=e[r]+(r%2?n.y:n.x);return C[t](e,n,i)}}(P[M].toUpperCase());b.PathArray=function(t,e){b.Array.call(this,t,e||[["M",0,0]])},b.PathArray.prototype=new b.Array,b.PathArray.prototype.constructor=b.PathArray,b.extend(b.PathArray,{toString:function(){return y(this.value)},move:function(t,e){var n=this.bbox();if(t-=n.x,e-=n.y,!isNaN(t)&&!isNaN(e))for(var i,r=this.value.length-1;r>=0;r--)i=this.value[r][0],"M"==i||"L"==i||"T"==i?(this.value[r][1]+=t,this.value[r][2]+=e):"H"==i?this.value[r][1]+=t:"V"==i?this.value[r][1]+=e:"C"==i||"S"==i||"Q"==i?(this.value[r][1]+=t,this.value[r][2]+=e,this.value[r][3]+=t,this.value[r][4]+=e,"C"==i&&(this.value[r][5]+=t,this.value[r][6]+=e)):"A"==i&&(this.value[r][6]+=t,this.value[r][7]+=e);return this},size:function(t,e){var n,i,r=this.bbox();for(n=this.value.length-1;n>=0;n--)i=this.value[n][0],"M"==i||"L"==i||"T"==i?(this.value[n][1]=(this.value[n][1]-r.x)*t/r.width+r.x,this.value[n][2]=(this.value[n][2]-r.y)*e/r.height+r.y):"H"==i?this.value[n][1]=(this.value[n][1]-r.x)*t/r.width+r.x:"V"==i?this.value[n][1]=(this.value[n][1]-r.y)*e/r.height+r.y:"C"==i||"S"==i||"Q"==i?(this.value[n][1]=(this.value[n][1]-r.x)*t/r.width+r.x,this.value[n][2]=(this.value[n][2]-r.y)*e/r.height+r.y,this.value[n][3]=(this.value[n][3]-r.x)*t/r.width+r.x,this.value[n][4]=(this.value[n][4]-r.y)*e/r.height+r.y,"C"==i&&(this.value[n][5]=(this.value[n][5]-r.x)*t/r.width+r.x,this.value[n][6]=(this.value[n][6]-r.y)*e/r.height+r.y)):"A"==i&&(this.value[n][1]=this.value[n][1]*t/r.width,this.value[n][2]=this.value[n][2]*e/r.height,this.value[n][6]=(this.value[n][6]-r.x)*t/r.width+r.x,this.value[n][7]=(this.value[n][7]-r.y)*e/r.height+r.y);return this},equalCommands:function(t){var e,n,i;for(t=new b.PathArray(t),i=this.value.length===t.value.length,e=0,n=this.value.length;i&&e<n;e++)i=this.value[e][0]===t.value[e][0];return i},morph:function(t){return t=new b.PathArray(t),this.equalCommands(t)?this.destination=t:this.destination=null,this},at:function(t){if(!this.destination)return this;var e,n,i,r,s=this.value,a=this.destination.value,o=[],h=new b.PathArray;for(e=0,n=s.length;e<n;e++){for(o[e]=[s[e][0]],i=1,r=s[e].length;i<r;i++)o[e][i]=s[e][i]+(a[e][i]-s[e][i])*t;"A"===o[e][0]&&(o[e][4]=+(0!=o[e][4]),o[e][5]=+(0!=o[e][5]))}return h.value=o,h},parse:function(t){if(t instanceof b.PathArray)return t.valueOf();var e,n,i={M:2,L:2,H:1,V:1,C:6,S:4,Q:4,T:2,A:7,Z:0};t="string"==typeof t?t.replace(b.regex.numbersWithDots,r).replace(b.regex.pathLetters," $& ").replace(b.regex.hyphen,"$1 -").trim().split(b.regex.delimiter):t.reduce(function(t,e){return[].concat.call(t,e)},[]);var n=[],s=new b.Point,a=new b.Point,o=0,h=t.length;do b.regex.isPathLetter.test(t[o])?(e=t[o],++o):"M"==e?e="L":"m"==e&&(e="l"),n.push(C[e].call(null,t.slice(o,o+=i[e.toUpperCase()]).map(parseFloat),s,a));while(h>o);return n},bbox:function(){return b.parser.path.setAttribute("d",this.toString()),b.parser.path.getBBox()}}),b.Number=b.invent({create:function(t,e){this.value=0,this.unit=e||"","number"==typeof t?this.value=isNaN(t)?0:isFinite(t)?t:t<0?-3.4e38:3.4e38:"string"==typeof t?(e=t.match(b.regex.numberAndUnit),e&&(this.value=parseFloat(e[1]),"%"==e[5]?this.value/=100:"s"==e[5]&&(this.value*=1e3),this.unit=e[5])):t instanceof b.Number&&(this.value=t.valueOf(),this.unit=t.unit)},extend:{toString:function(){return("%"==this.unit?~~(1e8*this.value)/1e6:"s"==this.unit?this.value/1e3:this.value)+this.unit},toJSON:function(){return this.toString()},valueOf:function(){return this.value},plus:function(t){return t=new b.Number(t),new b.Number(this+t,this.unit||t.unit)},minus:function(t){return t=new b.Number(t),new b.Number(this-t,this.unit||t.unit)},times:function(t){return t=new b.Number(t),new b.Number(this*t,this.unit||t.unit)},divide:function(t){return t=new b.Number(t),new b.Number(this/t,this.unit||t.unit)},to:function(t){var e=new b.Number(this);return"string"==typeof t&&(e.unit=t),e},morph:function(t){return this.destination=new b.Number(t),t.relative&&(this.destination.value+=this.value),this},at:function(t){return this.destination?new b.Number(this.destination).minus(this).times(t).plus(this):this}}}),b.Element=b.invent({create:function(t){this._event=null,this.dom={},(this.node=t)&&(this.type=t.nodeName,this.node.instance=this)},extend:{x:function(t){return this.attr("x",t)},y:function(t){return this.attr("y",t)},cx:function(t){return null==t?this.x()+this.width()/2:this.x(t-this.width()/2)},cy:function(t){return null==t?this.y()+this.height()/2:this.y(t-this.height()/2)},move:function(t,e){return this.x(t).y(e)},center:function(t,e){return this.cx(t).cy(e)},width:function(t){return this.attr("width",t)},height:function(t){return this.attr("height",t)},size:function(t,e){var n=f(this,t,e);return this.width(new b.Number(n.width)).height(new b.Number(n.height))},clone:function(t){this.writeDataToDom();var e=v(this.node.cloneNode(!0));return t?t.add(e):this.after(e),e},remove:function(){return this.parent()&&this.parent().removeElement(this),this},replace:function(t){return this.after(t).remove(),t},addTo:function(t){return t.put(this)},putIn:function(t){return t.add(this)},id:function(t){return"undefined"!=typeof t||this.node.id||(this.node.id=b.eid(this.type)),this.attr("id",t)},inside:function(t,e){var n=this.bbox();return t>n.x&&e>n.y&&t<n.x+n.width&&e<n.y+n.height},show:function(){return this.css("display","")},hide:function(){return this.css("display","none")},visible:function(){return"none"!=this.css("display")},toString:function(){return this.id()},classes:function(){var t=this.attr("class");return null==t?[]:t.trim().split(b.regex.delimiter)},hasClass:function(t){return this.classes().indexOf(t)!=-1},addClass:function(t){if(!this.hasClass(t)){var e=this.classes();e.push(t),this.attr("class",e.join(" "))}return this},removeClass:function(t){return this.hasClass(t)&&this.attr("class",this.classes().filter(function(e){return e!=t}).join(" ")),this},toggleClass:function(t){return this.hasClass(t)?this.removeClass(t):this.addClass(t)},reference:function(t){return b.get(this.attr(t))},parent:function(e){var n=this;if(!n.node.parentNode)return null;if(n=b.adopt(n.node.parentNode),!e)return n;for(;n&&n.node instanceof t.SVGElement;){if("string"==typeof e?n.matches(e):n instanceof e)return n;n=b.adopt(n.node.parentNode)}},doc:function(){return this instanceof b.Doc?this:this.parent(b.Doc)},parents:function(t){var e=[],n=this;do{if(n=n.parent(t),!n||!n.node)break;e.push(n)}while(n.parent);return e},matches:function(t){return o(this.node,t)},native:function(){return this.node},svg:function(t){var n,i;if(!(t&&this instanceof b.Parent))return this.node.outerHTML;for(n=e.createElementNS(b.ns,"svg"),n.innerHTML=t,i=n.childNodes.length;i--;)1!=n.firstChild.nodeType?n.removeChild(n.firstChild):this.node.appendChild(n.firstChild);return this},writeDataToDom:function(){return this.is(b.Parent)&&this.each(function(){this.writeDataToDom()}),this.node.removeAttribute("svgjs:data"),Object.keys(this.dom).length&&this.node.setAttribute("svgjs:data",JSON.stringify(this.dom)),this},setData:function(t){return this.dom=t,this},is:function(t){return a(this,t)}}}),b.easing={"-":function(t){return t},"<>":function(t){return-Math.cos(t*Math.PI)/2+.5},">":function(t){return Math.sin(t*Math.PI/2)},"<":function(t){return-Math.cos(t*Math.PI/2)+1}},b.morph=function(t){return function(e,n){return new b.MorphObj(e,n).at(t)}},b.Situation=b.invent({create:function(t){this.init=!1,this.reversed=!1,this.reversing=!1,this.duration=new b.Number(t.duration).valueOf(),this.delay=new b.Number(t.delay).valueOf(),this.start=+new Date+this.delay,this.finish=this.start+this.duration,this.ease=t.ease,this.loop=0,this.loops=!1,this.animations={},this.attrs={},this.styles={},this.transforms=[],this.once={}}}),b.FX=b.invent({create:function(t){this._target=t,this.situations=[],this.active=!1,this.situation=null,this.paused=!1,this.lastPos=0,this.pos=0,this.absPos=0,this._speed=1},extend:{animate:function(t,e,n){"object"==typeof t&&(e=t.ease,n=t.delay,t=t.duration);var i=new b.Situation({duration:t||1e3,delay:n||0,ease:b.easing[e||"-"]||e});return this.queue(i),this},delay:function(t){var e=new b.Situation({duration:t,delay:0,ease:b.easing["-"]});return this.queue(e)},target:function(t){return t&&t instanceof b.Element?(this._target=t,this):this._target},timeToAbsPos:function(t){return(t-this.situation.start)/(this.situation.duration/this._speed)},absPosToTime:function(t){return this.situation.duration/this._speed*t+this.situation.start},startAnimFrame:function(){this.stopAnimFrame(),this.animationFrame=t.requestAnimationFrame(function(){this.step()}.bind(this))},stopAnimFrame:function(){t.cancelAnimationFrame(this.animationFrame)},start:function(){return!this.active&&this.situation&&(this.active=!0,this.startCurrent()),this},startCurrent:function(){return this.situation.start=+new Date+this.situation.delay/this._speed,this.situation.finish=this.situation.start+this.situation.duration/this._speed,this.initAnimations().step()},queue:function(t){return("function"==typeof t||t instanceof b.Situation)&&this.situations.push(t),this.situation||(this.situation=this.situations.shift()),this},dequeue:function(){return this.stop(),this.situation=this.situations.shift(),this.situation&&(this.situation instanceof b.Situation?this.start():this.situation.call(this)),this},initAnimations:function(){var t,e,n=this.situation;if(n.init)return this;for(t in n.animations)e=this.target()[t](),n.animations[t]instanceof b.Number&&(e=new b.Number(e)),n.animations[t]=e.morph(n.animations[t]);for(t in n.attrs)n.attrs[t]=new b.MorphObj(this.target().attr(t),n.attrs[t]);for(t in n.styles)n.styles[t]=new b.MorphObj(this.target().css(t),n.styles[t]);return n.initialTransformation=this.target().matrixify(),n.init=!0,this},clearQueue:function(){return this.situations=[],this},clearCurrent:function(){return this.situation=null,this},stop:function(t,e){var n=this.active;return this.active=!1,e&&this.clearQueue(),t&&this.situation&&(!n&&this.startCurrent(),this.atEnd()),this.stopAnimFrame(),this.clearCurrent()},reset:function(){if(this.situation){var t=this.situation;this.stop(),this.situation=t,this.atStart()}return this},finish:function(){for(this.stop(!0,!1);this.dequeue().situation&&this.stop(!0,!1););return this.clearQueue().clearCurrent(),this},atStart:function(){return this.at(0,!0)},atEnd:function(){return this.situation.loops===!0&&(this.situation.loops=this.situation.loop+1),"number"==typeof this.situation.loops?this.at(this.situation.loops,!0):this.at(1,!0)},at:function(t,e){var n=this.situation.duration/this._speed;return this.absPos=t,e||(this.situation.reversed&&(this.absPos=1-this.absPos),this.absPos+=this.situation.loop),this.situation.start=+new Date-this.absPos*n,this.situation.finish=this.situation.start+n,this.step(!0)},speed:function(t){return 0===t?this.pause():t?(this._speed=t,this.at(this.absPos,!0)):this._speed},loop:function(t,e){var n=this.last();return n.loops=null==t||t,n.loop=0,e&&(n.reversing=!0),this},pause:function(){return this.paused=!0,this.stopAnimFrame(),this},play:function(){return this.paused?(this.paused=!1,this.at(this.absPos,!0)):this},reverse:function(t){var e=this.last();return"undefined"==typeof t?e.reversed=!e.reversed:e.reversed=t,this},progress:function(t){return t?this.situation.ease(this.pos):this.pos},after:function(t){var e=this.last(),n=function n(i){i.detail.situation==e&&(t.call(this,e),this.off("finished.fx",n))};return this.target().on("finished.fx",n),this._callStart()},during:function(t){var e=this.last(),n=function(n){n.detail.situation==e&&t.call(this,n.detail.pos,b.morph(n.detail.pos),n.detail.eased,e)};return this.target().off("during.fx",n).on("during.fx",n),this.after(function(){this.off("during.fx",n)}),this._callStart()},afterAll:function(t){var e=function e(n){t.call(this),this.off("allfinished.fx",e)};return this.target().off("allfinished.fx",e).on("allfinished.fx",e),this._callStart()},duringAll:function(t){var e=function(e){t.call(this,e.detail.pos,b.morph(e.detail.pos),e.detail.eased,e.detail.situation)};return this.target().off("during.fx",e).on("during.fx",e),this.afterAll(function(){this.off("during.fx",e)}),this._callStart()},last:function(){return this.situations.length?this.situations[this.situations.length-1]:this.situation},add:function(t,e,n){return this.last()[n||"animations"][t]=e,this._callStart()},step:function(t){if(t||(this.absPos=this.timeToAbsPos(+new Date)),this.situation.loops!==!1){var e,n,i;e=Math.max(this.absPos,0),n=Math.floor(e),this.situation.loops===!0||n<this.situation.loops?(this.pos=e-n,i=this.situation.loop,this.situation.loop=n):(this.absPos=this.situation.loops,this.pos=1,i=this.situation.loop-1,this.situation.loop=this.situation.loops),this.situation.reversing&&(this.situation.reversed=this.situation.reversed!=Boolean((this.situation.loop-i)%2))}else this.absPos=Math.min(this.absPos,1),this.pos=this.absPos;this.pos<0&&(this.pos=0),this.situation.reversed&&(this.pos=1-this.pos);var r=this.situation.ease(this.pos);for(var s in this.situation.once)s>this.lastPos&&s<=r&&(this.situation.once[s].call(this.target(),this.pos,r),delete this.situation.once[s]);return this.active&&this.target().fire("during",{pos:this.pos,eased:r,fx:this,situation:this.situation}),this.situation?(this.eachAt(),1==this.pos&&!this.situation.reversed||this.situation.reversed&&0==this.pos?(this.stopAnimFrame(),this.target().fire("finished",{fx:this,situation:this.situation}),this.situations.length||(this.target().fire("allfinished"),this.target().off(".fx"),this.active=!1),this.active?this.dequeue():this.clearCurrent()):!this.paused&&this.active&&this.startAnimFrame(),this.lastPos=r,this):this},eachAt:function(){var t,e,n,i=this,r=this.target(),s=this.situation;for(t in s.animations)n=[].concat(s.animations[t]).map(function(t){return"string"!=typeof t&&t.at?t.at(s.ease(i.pos),i.pos):t}),r[t].apply(r,n);for(t in s.attrs)n=[t].concat(s.attrs[t]).map(function(t){return"string"!=typeof t&&t.at?t.at(s.ease(i.pos),i.pos):t}),r.attr.apply(r,n);for(t in s.styles)n=[t].concat(s.styles[t]).map(function(t){return"string"!=typeof t&&t.at?t.at(s.ease(i.pos),i.pos):t}),r.css.apply(r,n);if(s.transforms.length){for(n=s.initialTransformation,t=0,e=s.transforms.length;t<e;t++){var a=s.transforms[t];a instanceof b.Matrix?n=a.relative?n.multiply((new b.Matrix).morph(a).at(s.ease(this.pos))):n.morph(a).at(s.ease(this.pos)):(a.relative||a.undo(n.extract()),n=n.multiply(a.at(s.ease(this.pos))))}r.matrix(n)}return this},once:function(t,e,n){return n||(t=this.situation.ease(t)),this.situation.once[t]=e,this},_callStart:function(){return setTimeout(function(){this.start()}.bind(this),0),this}},parent:b.Element,construct:{animate:function(t,e,n){return(this.fx||(this.fx=new b.FX(this))).animate(t,e,n)},delay:function(t){return(this.fx||(this.fx=new b.FX(this))).delay(t)},stop:function(t,e){return this.fx&&this.fx.stop(t,e),this},finish:function(){return this.fx&&this.fx.finish(),this},pause:function(){return this.fx&&this.fx.pause(),this},play:function(){return this.fx&&this.fx.play(),this},speed:function(t){if(this.fx){if(null==t)return this.fx.speed();this.fx.speed(t)}return this}}}),b.MorphObj=b.invent({create:function(t,e){return b.Color.isColor(e)?new b.Color(t).morph(e):b.regex.numberAndUnit.test(e)?new b.Number(t).morph(e):(this.value=t,void(this.destination=e))},extend:{at:function(t,e){return e<1?this.value:this.destination},valueOf:function(){return this.value}}}),b.extend(b.FX,{attr:function(t,e,n){if("object"==typeof t)for(var i in t)this.attr(i,t[i]);else this.add(t,e,"attrs");return this},css:function(t,e){if("object"==typeof t)for(var n in t)this.css(n,t[n]);else this.add(t,e,"styles");return this},x:function(t,e){if(this.target()instanceof b.G)return this.transform({x:t},e),this;var n=new b.Number(t);return n.relative=e,this.add("x",n)},y:function(t,e){if(this.target()instanceof b.G)return this.transform({y:t},e),this;var n=new b.Number(t);return n.relative=e,this.add("y",n)},cx:function(t){return this.add("cx",new b.Number(t))},cy:function(t){return this.add("cy",new b.Number(t))},move:function(t,e){return this.x(t).y(e)},center:function(t,e){return this.cx(t).cy(e)},size:function(t,e){if(this.target()instanceof b.Text)this.attr("font-size",t);else{var n;t&&e||(n=this.target().bbox()),t||(t=n.width/n.height*e),e||(e=n.height/n.width*t),this.add("width",new b.Number(t)).add("height",new b.Number(e))}return this},plot:function(){return this.add("plot",arguments.length>1?[].slice.call(arguments):arguments[0])},leading:function(t){return this.target().leading?this.add("leading",new b.Number(t)):this},viewbox:function(t,e,n,i){return this.target()instanceof b.Container&&this.add("viewbox",new b.Box(t,e,n,i)),this},update:function(t){if(this.target()instanceof b.Stop){if("number"==typeof t||t instanceof b.Number)return this.update({offset:arguments[0],color:arguments[1],opacity:arguments[2]});null!=t.opacity&&this.attr("stop-opacity",t.opacity),null!=t.color&&this.attr("stop-color",t.color),null!=t.offset&&this.attr("offset",t.offset)}return this}}),b.Matrix=b.invent({create:function(t){var e,n=p([1,0,0,1,0,0]);for(t=t instanceof b.Element?t.matrixify():"string"==typeof t?p(t.split(b.regex.delimiter).map(parseFloat)):6==arguments.length?p([].slice.call(arguments)):Array.isArray(t)?p(t):"object"==typeof t?t:n,e=k.length-1;e>=0;--e)this[k[e]]=t&&"number"==typeof t[k[e]]?t[k[e]]:n[k[e]]},extend:{extract:function(){var t=d(this,0,1),e=d(this,1,0),n=180/Math.PI*Math.atan2(t.y,t.x)-90;return{x:this.e,y:this.f,transformedX:(this.e*Math.cos(n*Math.PI/180)+this.f*Math.sin(n*Math.PI/180))/Math.sqrt(this.a*this.a+this.b*this.b),transformedY:(this.f*Math.cos(n*Math.PI/180)+this.e*Math.sin(-n*Math.PI/180))/Math.sqrt(this.c*this.c+this.d*this.d),skewX:-n,skewY:180/Math.PI*Math.atan2(e.y,e.x),scaleX:Math.sqrt(this.a*this.a+this.b*this.b),scaleY:Math.sqrt(this.c*this.c+this.d*this.d),rotation:n,a:this.a,b:this.b,c:this.c,d:this.d,e:this.e,f:this.f,matrix:new b.Matrix(this)}},clone:function(){return new b.Matrix(this)},morph:function(t){return this.destination=new b.Matrix(t),this},at:function(t){if(!this.destination)return this;var e=new b.Matrix({a:this.a+(this.destination.a-this.a)*t,b:this.b+(this.destination.b-this.b)*t,c:this.c+(this.destination.c-this.c)*t,d:this.d+(this.destination.d-this.d)*t,e:this.e+(this.destination.e-this.e)*t,f:this.f+(this.destination.f-this.f)*t});return e},multiply:function(t){return new b.Matrix(this.native().multiply(x(t).native()))},inverse:function(){return new b.Matrix(this.native().inverse())},translate:function(t,e){return new b.Matrix(this.native().translate(t||0,e||0))},scale:function(t,e,n,i){return 1==arguments.length?e=t:3==arguments.length&&(i=n,n=e,e=t),this.around(n,i,new b.Matrix(t,0,0,e,0,0))},rotate:function(t,e,n){return t=b.utils.radians(t),this.around(e,n,new b.Matrix(Math.cos(t),Math.sin(t),-Math.sin(t),Math.cos(t),0,0))},flip:function(t,e){return"x"==t?this.scale(-1,1,e,0):"y"==t?this.scale(1,-1,0,e):this.scale(-1,-1,t,null!=e?e:t)},skew:function(t,e,n,i){return 1==arguments.length?e=t:3==arguments.length&&(i=n,n=e,e=t),t=b.utils.radians(t),e=b.utils.radians(e),this.around(n,i,new b.Matrix(1,Math.tan(e),Math.tan(t),1,0,0))},skewX:function(t,e,n){return this.skew(t,0,e,n)},skewY:function(t,e,n){return this.skew(0,t,e,n)},around:function(t,e,n){return this.multiply(new b.Matrix(1,0,0,1,t||0,e||0)).multiply(n).multiply(new b.Matrix(1,0,0,1,-t||0,-e||0))},native:function(){for(var t=b.parser.native.createSVGMatrix(),e=k.length-1;e>=0;e--)t[k[e]]=this[k[e]];return t},toString:function(){return"matrix("+this.a+","+this.b+","+this.c+","+this.d+","+this.e+","+this.f+")"}},parent:b.Element,construct:{ctm:function(){return new b.Matrix(this.node.getCTM())},screenCTM:function(){if(this instanceof b.Nested){var t=this.rect(1,1),e=t.node.getScreenCTM();return t.remove(),new b.Matrix(e)}return new b.Matrix(this.node.getScreenCTM())}}}),b.Point=b.invent({create:function(t,e){var n,i={x:0,y:0};n=Array.isArray(t)?{x:t[0],y:t[1]}:"object"==typeof t?{x:t.x,y:t.y}:null!=t?{x:t,y:null!=e?e:t}:i,this.x=n.x,this.y=n.y},extend:{clone:function(){return new b.Point(this)},morph:function(t,e){return this.destination=new b.Point(t,e),this},at:function(t){if(!this.destination)return this;var e=new b.Point({x:this.x+(this.destination.x-this.x)*t,y:this.y+(this.destination.y-this.y)*t});return e},native:function(){var t=b.parser.native.createSVGPoint();return t.x=this.x,t.y=this.y,t},transform:function(t){return new b.Point(this.native().matrixTransform(t.native()))}}}),b.extend(b.Element,{point:function(t,e){return new b.Point(t,e).transform(this.screenCTM().inverse())}}),b.extend(b.Element,{attr:function(t,e,n){if(null==t){for(t={},e=this.node.attributes,n=e.length-1;n>=0;n--)t[e[n].nodeName]=b.regex.isNumber.test(e[n].nodeValue)?parseFloat(e[n].nodeValue):e[n].nodeValue;return t}if("object"==typeof t)for(e in t)this.attr(e,t[e]);else if(null===e)this.node.removeAttribute(t);else{if(null==e)return e=this.node.getAttribute(t),null==e?b.defaults.attrs[t]:b.regex.isNumber.test(e)?parseFloat(e):e;"fill"!=t&&"stroke"!=t||(b.regex.isImage.test(e)&&(e=this.doc().defs().image(e)),e instanceof b.Image&&(e=this.doc().defs().pattern(0,0,function(){this.add(e)}))),"number"==typeof e?e=new b.Number(e):b.Color.isColor(e)?e=new b.Color(e):Array.isArray(e)&&(e=new b.Array(e)),"leading"==t?this.leading&&this.leading(e):"string"==typeof n?this.node.setAttributeNS(n,t,e.toString()):this.node.setAttribute(t,e.toString()),!this.rebuild||"font-size"!=t&&"x"!=t||this.rebuild(t,e)}return this}}),b.extend(b.Element,{transform:function(t,e){var n,i,r=this;if("object"!=typeof t)return n=new b.Matrix(r).extract(),"string"==typeof t?n[t]:n;if(n=new b.Matrix(r),e=!!e||!!t.relative,null!=t.a)n=e?n.multiply(new b.Matrix(t)):new b.Matrix(t);else if(null!=t.rotation)m(t,r),n=e?n.rotate(t.rotation,t.cx,t.cy):n.rotate(t.rotation-n.extract().rotation,t.cx,t.cy);else if(null!=t.scale||null!=t.scaleX||null!=t.scaleY){if(m(t,r),t.scaleX=null!=t.scale?t.scale:null!=t.scaleX?t.scaleX:1,t.scaleY=null!=t.scale?t.scale:null!=t.scaleY?t.scaleY:1,
-!e){var s=n.extract();t.scaleX=1*t.scaleX/s.scaleX,t.scaleY=1*t.scaleY/s.scaleY}n=n.scale(t.scaleX,t.scaleY,t.cx,t.cy)}else if(null!=t.skew||null!=t.skewX||null!=t.skewY){if(m(t,r),t.skewX=null!=t.skew?t.skew:null!=t.skewX?t.skewX:0,t.skewY=null!=t.skew?t.skew:null!=t.skewY?t.skewY:0,!e){var s=n.extract();n=n.multiply((new b.Matrix).skew(s.skewX,s.skewY,t.cx,t.cy).inverse())}n=n.skew(t.skewX,t.skewY,t.cx,t.cy)}else t.flip?("x"==t.flip||"y"==t.flip?t.offset=null==t.offset?r.bbox()["c"+t.flip]:t.offset:null==t.offset?(i=r.bbox(),t.flip=i.cx,t.offset=i.cy):t.flip=t.offset,n=(new b.Matrix).flip(t.flip,t.offset)):null==t.x&&null==t.y||(e?n=n.translate(t.x,t.y):(null!=t.x&&(n.e=t.x),null!=t.y&&(n.f=t.y)));return this.attr("transform",n)}}),b.extend(b.FX,{transform:function(t,e){var n,i,r=this.target();return"object"!=typeof t?(n=new b.Matrix(r).extract(),"string"==typeof t?n[t]:n):(e=!!e||!!t.relative,null!=t.a?n=new b.Matrix(t):null!=t.rotation?(m(t,r),n=new b.Rotate(t.rotation,t.cx,t.cy)):null!=t.scale||null!=t.scaleX||null!=t.scaleY?(m(t,r),t.scaleX=null!=t.scale?t.scale:null!=t.scaleX?t.scaleX:1,t.scaleY=null!=t.scale?t.scale:null!=t.scaleY?t.scaleY:1,n=new b.Scale(t.scaleX,t.scaleY,t.cx,t.cy)):null!=t.skewX||null!=t.skewY?(m(t,r),t.skewX=null!=t.skewX?t.skewX:0,t.skewY=null!=t.skewY?t.skewY:0,n=new b.Skew(t.skewX,t.skewY,t.cx,t.cy)):t.flip?("x"==t.flip||"y"==t.flip?t.offset=null==t.offset?r.bbox()["c"+t.flip]:t.offset:null==t.offset?(i=r.bbox(),t.flip=i.cx,t.offset=i.cy):t.flip=t.offset,n=(new b.Matrix).flip(t.flip,t.offset)):null==t.x&&null==t.y||(n=new b.Translate(t.x,t.y)),n?(n.relative=e,this.last().transforms.push(n),this._callStart()):this)}}),b.extend(b.Element,{untransform:function(){return this.attr("transform",null)},matrixify:function(){var t=(this.attr("transform")||"").split(b.regex.transforms).slice(0,-1).map(function(t){var e=t.trim().split("(");return[e[0],e[1].split(b.regex.delimiter).map(function(t){return parseFloat(t)})]}).reduce(function(t,e){return"matrix"==e[0]?t.multiply(p(e[1])):t[e[0]].apply(t,e[1])},new b.Matrix);return t},toParent:function(t){if(this==t)return this;var e=this.screenCTM(),n=t.screenCTM().inverse();return this.addTo(t).untransform().transform(n.multiply(e)),this},toDoc:function(){return this.toParent(this.doc())}}),b.Transformation=b.invent({create:function(t,e){if(arguments.length>1&&"boolean"!=typeof e)return this.constructor.call(this,[].slice.call(arguments));if(Array.isArray(t))for(var n=0,i=this.arguments.length;n<i;++n)this[this.arguments[n]]=t[n];else if("object"==typeof t)for(var n=0,i=this.arguments.length;n<i;++n)this[this.arguments[n]]=t[this.arguments[n]];this.inversed=!1,e===!0&&(this.inversed=!0)},extend:{arguments:[],method:"",at:function(t){for(var e=[],n=0,i=this.arguments.length;n<i;++n)e.push(this[this.arguments[n]]);var r=this._undo||new b.Matrix;return r=(new b.Matrix).morph(b.Matrix.prototype[this.method].apply(r,e)).at(t),this.inversed?r.inverse():r},undo:function(t){for(var e=0,n=this.arguments.length;e<n;++e)t[this.arguments[e]]="undefined"==typeof this[this.arguments[e]]?0:t[this.arguments[e]];return t.cx=this.cx,t.cy=this.cy,this._undo=new(b[u(this.method)])(t,!0).at(1),this}}}),b.Translate=b.invent({parent:b.Matrix,inherit:b.Transformation,create:function(t,e){this.constructor.apply(this,[].slice.call(arguments))},extend:{arguments:["transformedX","transformedY"],method:"translate"}}),b.Rotate=b.invent({parent:b.Matrix,inherit:b.Transformation,create:function(t,e){this.constructor.apply(this,[].slice.call(arguments))},extend:{arguments:["rotation","cx","cy"],method:"rotate",at:function(t){var e=(new b.Matrix).rotate((new b.Number).morph(this.rotation-(this._undo?this._undo.rotation:0)).at(t),this.cx,this.cy);return this.inversed?e.inverse():e},undo:function(t){return this._undo=t,this}}}),b.Scale=b.invent({parent:b.Matrix,inherit:b.Transformation,create:function(t,e){this.constructor.apply(this,[].slice.call(arguments))},extend:{arguments:["scaleX","scaleY","cx","cy"],method:"scale"}}),b.Skew=b.invent({parent:b.Matrix,inherit:b.Transformation,create:function(t,e){this.constructor.apply(this,[].slice.call(arguments))},extend:{arguments:["skewX","skewY","cx","cy"],method:"skew"}}),b.extend(b.Element,{css:function(t,e){var n,i,r={};if(0==arguments.length)return this.node.style.cssText.split(/\s*;\s*/).filter(function(t){return!!t.length}).forEach(function(t){n=t.split(/\s*:\s*/),r[n[0]]=n[1]}),r;if(arguments.length<2){if(Array.isArray(t)){for(i=t.length;i--;)r[h(t[i])]=this.node.style[h(t[i])];return r}if("string"==typeof t)return this.node.style[h(t)];if("object"==typeof t)for(i in t)this.node.style[h(i)]=null==t[i]||b.regex.isBlank.test(t[i])?"":t[i]}return 2==arguments.length&&(this.node.style[h(t)]=null==e||b.regex.isBlank.test(e)?"":e),this}}),b.Parent=b.invent({create:function(t){this.constructor.call(this,t)},inherit:b.Element,extend:{children:function(){return b.utils.map(b.utils.filterSVGElements(this.node.childNodes),function(t){return b.adopt(t)})},add:function(t,e){return null==e?this.node.appendChild(t.node):t.node!=this.node.childNodes[e]&&this.node.insertBefore(t.node,this.node.childNodes[e]),this},put:function(t,e){return this.add(t,e),t},has:function(t){return this.index(t)>=0},index:function(t){return[].slice.call(this.node.childNodes).indexOf(t.node)},get:function(t){return b.adopt(this.node.childNodes[t])},first:function(){return this.get(0)},last:function(){return this.get(this.node.childNodes.length-1)},each:function(t,e){var n,i,r=this.children();for(n=0,i=r.length;n<i;n++)r[n]instanceof b.Element&&t.apply(r[n],[n,r]),e&&r[n]instanceof b.Container&&r[n].each(t,e);return this},removeElement:function(t){return this.node.removeChild(t.node),this},clear:function(){for(;this.node.hasChildNodes();)this.node.removeChild(this.node.lastChild);return delete this._defs,this},defs:function(){return this.doc().defs()}}}),b.extend(b.Parent,{flatten:function(t){return this instanceof b.Defs?this:(t=t||(this instanceof b.Doc?this:this.parent(b.Parent)),this.each(function(){return this instanceof b.Defs?this:this instanceof b.Parent?this.flatten(t):this.toParent(t)}),this.node.firstChild||this.remove(),this)}}),b.Container=b.invent({create:function(t){this.constructor.call(this,t)},inherit:b.Parent}),["click","dblclick","mousedown","mouseup","mouseover","mouseout","mousemove","touchstart","touchmove","touchleave","touchend","touchcancel"].forEach(function(t){b.Element.prototype[t]=function(e){return b.on(this.node,t,e),this}}),b.listeners=[],b.handlerMap=[],b.listenerId=0,b.on=function(t,e,n,i,r){var s=n.bind(i||t.instance||t),a=(b.handlerMap.indexOf(t)+1||b.handlerMap.push(t))-1,o=e.split(".")[0],h=e.split(".")[1]||"*";b.listeners[a]=b.listeners[a]||{},b.listeners[a][o]=b.listeners[a][o]||{},b.listeners[a][o][h]=b.listeners[a][o][h]||{},n._svgjsListenerId||(n._svgjsListenerId=++b.listenerId),b.listeners[a][o][h][n._svgjsListenerId]=s,t.addEventListener(o,s,r||!1)},b.off=function(t,e,n){var i=b.handlerMap.indexOf(t),r=e&&e.split(".")[0],s=e&&e.split(".")[1],a="";if(i!=-1)if(n){if("function"==typeof n&&(n=n._svgjsListenerId),!n)return;b.listeners[i][r]&&b.listeners[i][r][s||"*"]&&(t.removeEventListener(r,b.listeners[i][r][s||"*"][n],!1),delete b.listeners[i][r][s||"*"][n])}else if(s&&r){if(b.listeners[i][r]&&b.listeners[i][r][s]){for(n in b.listeners[i][r][s])b.off(t,[r,s].join("."),n);delete b.listeners[i][r][s]}}else if(s)for(e in b.listeners[i])for(a in b.listeners[i][e])s===a&&b.off(t,[e,s].join("."));else if(r){if(b.listeners[i][r]){for(a in b.listeners[i][r])b.off(t,[r,a].join("."));delete b.listeners[i][r]}}else{for(e in b.listeners[i])b.off(t,e);delete b.listeners[i],delete b.handlerMap[i]}},b.extend(b.Element,{on:function(t,e,n,i){return b.on(this.node,t,e,n,i),this},off:function(t,e){return b.off(this.node,t,e),this},fire:function(e,n){return e instanceof t.Event?this.node.dispatchEvent(e):this.node.dispatchEvent(e=new t.CustomEvent(e,{detail:n,cancelable:!0})),this._event=e,this},event:function(){return this._event}}),b.Defs=b.invent({create:"defs",inherit:b.Container}),b.G=b.invent({create:"g",inherit:b.Container,extend:{x:function(t){return null==t?this.transform("x"):this.transform({x:t-this.x()},!0)},y:function(t){return null==t?this.transform("y"):this.transform({y:t-this.y()},!0)},cx:function(t){return null==t?this.gbox().cx:this.x(t-this.gbox().width/2)},cy:function(t){return null==t?this.gbox().cy:this.y(t-this.gbox().height/2)},gbox:function(){var t=this.bbox(),e=this.transform();return t.x+=e.x,t.x2+=e.x,t.cx+=e.x,t.y+=e.y,t.y2+=e.y,t.cy+=e.y,t}},construct:{group:function(){return this.put(new b.G)}}}),b.extend(b.Element,{siblings:function(){return this.parent().children()},position:function(){return this.parent().index(this)},next:function(){return this.siblings()[this.position()+1]},previous:function(){return this.siblings()[this.position()-1]},forward:function(){var t=this.position()+1,e=this.parent();return e.removeElement(this).add(this,t),e instanceof b.Doc&&e.node.appendChild(e.defs().node),this},backward:function(){var t=this.position();return t>0&&this.parent().removeElement(this).add(this,t-1),this},front:function(){var t=this.parent();return t.node.appendChild(this.node),t instanceof b.Doc&&t.node.appendChild(t.defs().node),this},back:function(){return this.position()>0&&this.parent().removeElement(this).add(this,0),this},before:function(t){t.remove();var e=this.position();return this.parent().add(t,e),this},after:function(t){t.remove();var e=this.position();return this.parent().add(t,e+1),this}}),b.Mask=b.invent({create:"mask",inherit:b.Container,extend:{remove:function(){return this.targets().forEach(function(t){t.unmask()}),b.Element.prototype.remove.call(this)},targets:function(){return b.select('svg [mask*="'+this.id()+'"]')}},construct:{mask:function(){return this.defs().put(new b.Mask)}}}),b.extend(b.Element,{maskWith:function(t){var e=t instanceof b.Mask?t:this.parent().mask().add(t);return this.attr("mask",'url("#'+e.id()+'")')},unmask:function(){return this.attr("mask",null)},masker:function(){return this.reference("mask")}}),b.ClipPath=b.invent({create:"clipPath",inherit:b.Container,extend:{remove:function(){return this.targets().forEach(function(t){t.unclip()}),b.Element.prototype.remove.call(this)},targets:function(){return b.select('svg [clip-path*="'+this.id()+'"]')}},construct:{clip:function(){return this.defs().put(new b.ClipPath)}}}),b.extend(b.Element,{clipWith:function(t){var e=t instanceof b.ClipPath?t:this.parent().clip().add(t);return this.attr("clip-path",'url("#'+e.id()+'")')},unclip:function(){return this.attr("clip-path",null)},clipper:function(){return this.reference("clip-path")}}),b.Gradient=b.invent({create:function(t){this.constructor.call(this,b.create(t+"Gradient"))},inherit:b.Container,extend:{at:function(t,e,n){return this.put(new b.Stop).update(t,e,n)},update:function(t){return this.clear(),"function"==typeof t&&t.call(this,this),this},fill:function(){return"url(#"+this.id()+")"},toString:function(){return this.fill()},attr:function(t,e,n){return"transform"==t&&(t="gradientTransform"),b.Container.prototype.attr.call(this,t,e,n)}},construct:{gradient:function(t,e){return this.defs().gradient(t,e)}}}),b.extend([b.Gradient,b.FX],{from:function(t,e){return"radialGradient"==(this._target||this).type?this.attr({fx:new b.Number(t),fy:new b.Number(e)}):this.attr({x1:new b.Number(t),y1:new b.Number(e)})},to:function(t,e){return"radialGradient"==(this._target||this).type?this.attr({cx:new b.Number(t),cy:new b.Number(e)}):this.attr({x2:new b.Number(t),y2:new b.Number(e)})}}),b.extend(b.Defs,{gradient:function(t,e){return this.put(new b.Gradient(t)).update(e)}}),b.Stop=b.invent({create:"stop",inherit:b.Element,extend:{update:function(t){return("number"==typeof t||t instanceof b.Number)&&(t={offset:arguments[0],color:arguments[1],opacity:arguments[2]}),null!=t.opacity&&this.attr("stop-opacity",t.opacity),null!=t.color&&this.attr("stop-color",t.color),null!=t.offset&&this.attr("offset",new b.Number(t.offset)),this}}}),b.Pattern=b.invent({create:"pattern",inherit:b.Container,extend:{fill:function(){return"url(#"+this.id()+")"},update:function(t){return this.clear(),"function"==typeof t&&t.call(this,this),this},toString:function(){return this.fill()},attr:function(t,e,n){return"transform"==t&&(t="patternTransform"),b.Container.prototype.attr.call(this,t,e,n)}},construct:{pattern:function(t,e,n){return this.defs().pattern(t,e,n)}}}),b.extend(b.Defs,{pattern:function(t,e,n){return this.put(new b.Pattern).update(n).attr({x:0,y:0,width:t,height:e,patternUnits:"userSpaceOnUse"})}}),b.Doc=b.invent({create:function(t){t&&(t="string"==typeof t?e.getElementById(t):t,"svg"==t.nodeName?this.constructor.call(this,t):(this.constructor.call(this,b.create("svg")),t.appendChild(this.node),this.size("100%","100%")),this.namespace().defs())},inherit:b.Container,extend:{namespace:function(){return this.attr({xmlns:b.ns,version:"1.1"}).attr("xmlns:xlink",b.xlink,b.xmlns).attr("xmlns:svgjs",b.svgjs,b.xmlns)},defs:function(){if(!this._defs){var t;(t=this.node.getElementsByTagName("defs")[0])?this._defs=b.adopt(t):this._defs=new b.Defs,this.node.appendChild(this._defs.node)}return this._defs},parent:function(){return"#document"==this.node.parentNode.nodeName?null:this.node.parentNode},remove:function(){return this.parent()&&this.parent().removeChild(this.node),this},clear:function(){for(;this.node.hasChildNodes();)this.node.removeChild(this.node.lastChild);return delete this._defs,b.parser.draw.parentNode||this.node.appendChild(b.parser.draw),this}}}),b.Shape=b.invent({create:function(t){this.constructor.call(this,t)},inherit:b.Element}),b.Bare=b.invent({create:function(t,e){if(this.constructor.call(this,b.create(t)),e)for(var n in e.prototype)"function"==typeof e.prototype[n]&&(this[n]=e.prototype[n])},inherit:b.Element,extend:{words:function(t){for(;this.node.hasChildNodes();)this.node.removeChild(this.node.lastChild);return this.node.appendChild(e.createTextNode(t)),this}}}),b.extend(b.Parent,{element:function(t,e){return this.put(new b.Bare(t,e))}}),b.Symbol=b.invent({create:"symbol",inherit:b.Container,construct:{symbol:function(){return this.put(new b.Symbol)}}}),b.Use=b.invent({create:"use",inherit:b.Shape,extend:{element:function(t,e){return this.attr("href",(e||"")+"#"+t,b.xlink)}},construct:{use:function(t,e){return this.put(new b.Use).element(t,e)}}}),b.Rect=b.invent({create:"rect",inherit:b.Shape,construct:{rect:function(t,e){return this.put(new b.Rect).size(t,e)}}}),b.Circle=b.invent({create:"circle",inherit:b.Shape,construct:{circle:function(t){return this.put(new b.Circle).rx(new b.Number(t).divide(2)).move(0,0)}}}),b.extend([b.Circle,b.FX],{rx:function(t){return this.attr("r",t)},ry:function(t){return this.rx(t)}}),b.Ellipse=b.invent({create:"ellipse",inherit:b.Shape,construct:{ellipse:function(t,e){return this.put(new b.Ellipse).size(t,e).move(0,0)}}}),b.extend([b.Ellipse,b.Rect,b.FX],{rx:function(t){return this.attr("rx",t)},ry:function(t){return this.attr("ry",t)}}),b.extend([b.Circle,b.Ellipse],{x:function(t){return null==t?this.cx()-this.rx():this.cx(t+this.rx())},y:function(t){return null==t?this.cy()-this.ry():this.cy(t+this.ry())},cx:function(t){return null==t?this.attr("cx"):this.attr("cx",t)},cy:function(t){return null==t?this.attr("cy"):this.attr("cy",t)},width:function(t){return null==t?2*this.rx():this.rx(new b.Number(t).divide(2))},height:function(t){return null==t?2*this.ry():this.ry(new b.Number(t).divide(2))},size:function(t,e){var n=f(this,t,e);return this.rx(new b.Number(n.width).divide(2)).ry(new b.Number(n.height).divide(2))}}),b.Line=b.invent({create:"line",inherit:b.Shape,extend:{array:function(){return new b.PointArray([[this.attr("x1"),this.attr("y1")],[this.attr("x2"),this.attr("y2")]])},plot:function(t,e,n,i){return null==t?this.array():(t="undefined"!=typeof e?{x1:t,y1:e,x2:n,y2:i}:new b.PointArray(t).toLine(),this.attr(t))},move:function(t,e){return this.attr(this.array().move(t,e).toLine())},size:function(t,e){var n=f(this,t,e);return this.attr(this.array().size(n.width,n.height).toLine())}},construct:{line:function(t,e,n,i){return b.Line.prototype.plot.apply(this.put(new b.Line),null!=t?[t,e,n,i]:[0,0,0,0])}}}),b.Polyline=b.invent({create:"polyline",inherit:b.Shape,construct:{polyline:function(t){return this.put(new b.Polyline).plot(t||new b.PointArray)}}}),b.Polygon=b.invent({create:"polygon",inherit:b.Shape,construct:{polygon:function(t){return this.put(new b.Polygon).plot(t||new b.PointArray)}}}),b.extend([b.Polyline,b.Polygon],{array:function(){return this._array||(this._array=new b.PointArray(this.attr("points")))},plot:function(t){return null==t?this.array():this.clear().attr("points","string"==typeof t?t:this._array=new b.PointArray(t))},clear:function(){return delete this._array,this},move:function(t,e){return this.attr("points",this.array().move(t,e))},size:function(t,e){var n=f(this,t,e);return this.attr("points",this.array().size(n.width,n.height))}}),b.extend([b.Line,b.Polyline,b.Polygon],{morphArray:b.PointArray,x:function(t){return null==t?this.bbox().x:this.move(t,this.bbox().y)},y:function(t){return null==t?this.bbox().y:this.move(this.bbox().x,t)},width:function(t){var e=this.bbox();return null==t?e.width:this.size(t,e.height)},height:function(t){var e=this.bbox();return null==t?e.height:this.size(e.width,t)}}),b.Path=b.invent({create:"path",inherit:b.Shape,extend:{morphArray:b.PathArray,array:function(){return this._array||(this._array=new b.PathArray(this.attr("d")))},plot:function(t){return null==t?this.array():this.clear().attr("d","string"==typeof t?t:this._array=new b.PathArray(t))},clear:function(){return delete this._array,this},move:function(t,e){return this.attr("d",this.array().move(t,e))},x:function(t){return null==t?this.bbox().x:this.move(t,this.bbox().y)},y:function(t){return null==t?this.bbox().y:this.move(this.bbox().x,t)},size:function(t,e){var n=f(this,t,e);return this.attr("d",this.array().size(n.width,n.height))},width:function(t){return null==t?this.bbox().width:this.size(t,this.bbox().height)},height:function(t){return null==t?this.bbox().height:this.size(this.bbox().width,t)}},construct:{path:function(t){return this.put(new b.Path).plot(t||new b.PathArray)}}}),b.Image=b.invent({create:"image",inherit:b.Shape,extend:{load:function(e,n){if(!e)return this;var i=new t.Image;return b.on(i,"load",function(t){var r=this.parent();0==this.width()&&0==this.height()&&this.size(i.width,i.height),r instanceof b.Pattern&&0==r.width()&&0==r.height()&&r.size(this.width(),this.height()),"function"==typeof n&&n.call(this,{width:i.width,height:i.height,ratio:i.width/i.height,url:e})},this),this.attr("href",i.src=e,b.xlink)}},construct:{image:function(t,e){return this.put(new b.Image).size(0,0).load(t,e)}}}),b.Text=b.invent({create:function(){this.constructor.call(this,b.create("text")),this.dom.leading=new b.Number(1.3),this._rebuild=!0,this._build=!1,this.attr("font-family",b.defaults.attrs["font-family"])},inherit:b.Parent,extend:{x:function(t){return null==t?this.attr("x"):this.attr("x",t)},y:function(t){var e=this.attr("y"),n="number"==typeof e?e-this.bbox().y:0;return null==t?"number"==typeof e?e-n:e:this.attr("y","number"==typeof t?t+n:t)},cx:function(t){return null==t?this.bbox().cx:this.x(t-this.bbox().width/2)},cy:function(t){return null==t?this.bbox().cy:this.y(t-this.bbox().height/2)},text:function(t){if("undefined"==typeof t){for(var t="",e=this.node.childNodes,n=0,i=e.length;n<i;++n)0!=n&&3!=e[n].nodeType&&1==b.adopt(e[n]).dom.newLined&&(t+="\n"),t+=e[n].textContent;return t}if(this.clear().build(!0),"function"==typeof t)t.call(this,this);else{t=t.split("\n");for(var n=0,r=t.length;n<r;n++)this.tspan(t[n]).newLine()}return this.build(!1).rebuild()},size:function(t){return this.attr("font-size",t).rebuild()},leading:function(t){return null==t?this.dom.leading:(this.dom.leading=new b.Number(t),this.rebuild())},rebuild:function(t){if("boolean"==typeof t&&(this._rebuild=t),this._rebuild){var e=this,n=0,i=this.dom.leading*new b.Number(this.attr("font-size"));this.each(function(){this.dom.newLined&&(e.textPath()||this.attr("x",e.attr("x")),"\n"==this.text()?n+=i:(this.attr("dy",i+n),n=0))}),this.fire("rebuild")}return this},build:function(t){return this._build=!!t,this},setData:function(t){return this.dom=t,this.dom.leading=new b.Number(t.leading||1.3),this}},construct:{text:function(t){return this.put(new b.Text).text(t)},plain:function(t){return this.put(new b.Text).plain(t)}}}),b.Tspan=b.invent({create:"tspan",inherit:b.Parent,extend:{text:function(t){return null==t?this.node.textContent+(this.dom.newLined?"\n":""):("function"==typeof t?t.call(this,this):this.plain(t),this)},dx:function(t){return this.attr("dx",t)},dy:function(t){return this.attr("dy",t)},newLine:function(){var t=this.parent(b.Text);return this.dom.newLined=!0,this.dy(t.dom.leading*t.attr("font-size")).attr("x",t.x())}}}),b.extend([b.Text,b.Tspan],{plain:function(t){return this._build===!1&&this.clear(),this.node.appendChild(e.createTextNode(t)),this},tspan:function(t){var e=(this.textPath&&this.textPath()||this).node,n=new b.Tspan;return this._build===!1&&this.clear(),e.appendChild(n.node),n.text(t)},length:function(){return this.node.getComputedTextLength()}}),b.TextPath=b.invent({create:"textPath",inherit:b.Parent,parent:b.Text,construct:{path:function(t){for(var e=new b.TextPath,n=this.doc().defs().path(t);this.node.hasChildNodes();)e.node.appendChild(this.node.firstChild);return this.node.appendChild(e.node),e.attr("href","#"+n,b.xlink),this},array:function(){var t=this.track();return t?t.array():null},plot:function(t){var e=this.track(),n=null;return e&&(n=e.plot(t)),null==t?n:this},track:function(){var t=this.textPath();if(t)return t.reference("href")},textPath:function(){if(this.node.firstChild&&"textPath"==this.node.firstChild.nodeName)return b.adopt(this.node.firstChild)}}}),b.Nested=b.invent({create:function(){this.constructor.call(this,b.create("svg")),this.css("overflow","visible")},inherit:b.Container,construct:{nested:function(){return this.put(new b.Nested)}}}),b.A=b.invent({create:"a",inherit:b.Container,extend:{to:function(t){return this.attr("href",t,b.xlink)},show:function(t){return this.attr("show",t,b.xlink)},target:function(t){return this.attr("target",t)}},construct:{link:function(t){return this.put(new b.A).to(t)}}}),b.extend(b.Element,{linkTo:function(t){var e=new b.A;return"function"==typeof t?t.call(e,e):e.to(t),this.parent().put(e).put(this)}}),b.Marker=b.invent({create:"marker",inherit:b.Container,extend:{width:function(t){return this.attr("markerWidth",t)},height:function(t){return this.attr("markerHeight",t)},ref:function(t,e){return this.attr("refX",t).attr("refY",e)},update:function(t){return this.clear(),"function"==typeof t&&t.call(this,this),this},toString:function(){return"url(#"+this.id()+")"}},construct:{marker:function(t,e,n){return this.defs().marker(t,e,n)}}}),b.extend(b.Defs,{marker:function(t,e,n){return this.put(new b.Marker).size(t,e).ref(t/2,e/2).viewbox(0,0,t,e).attr("orient","auto").update(n)}}),b.extend([b.Line,b.Polyline,b.Polygon,b.Path],{marker:function(t,e,n,i){var r=["marker"];return"all"!=t&&r.push(t),r=r.join("-"),t=arguments[1]instanceof b.Marker?arguments[1]:this.doc().marker(e,n,i),this.attr(r,t)}});var A={stroke:["color","width","opacity","linecap","linejoin","miterlimit","dasharray","dashoffset"],fill:["color","opacity","rule"],prefix:function(t,e){return"color"==e?t:t+"-"+e}};["fill","stroke"].forEach(function(t){var e,n={};n[t]=function(n){if("undefined"==typeof n)return this;if("string"==typeof n||b.Color.isRgb(n)||n&&"function"==typeof n.fill)this.attr(t,n);else for(e=A[t].length-1;e>=0;e--)null!=n[A[t][e]]&&this.attr(A.prefix(t,A[t][e]),n[A[t][e]]);return this},b.extend([b.Element,b.FX],n)}),b.extend([b.Element,b.FX],{rotate:function(t,e,n){return this.transform({rotation:t,cx:e,cy:n})},skew:function(t,e,n,i){return 1==arguments.length||3==arguments.length?this.transform({skew:t,cx:e,cy:n}):this.transform({skewX:t,skewY:e,cx:n,cy:i})},scale:function(t,e,n,i){return 1==arguments.length||3==arguments.length?this.transform({scale:t,cx:e,cy:n}):this.transform({scaleX:t,scaleY:e,cx:n,cy:i})},translate:function(t,e){return this.transform({x:t,y:e})},flip:function(t,e){return e="number"==typeof t?t:e,this.transform({flip:t||"both",offset:e})},matrix:function(t){return this.attr("transform",new b.Matrix(6==arguments.length?[].slice.call(arguments):t))},opacity:function(t){return this.attr("opacity",t)},dx:function(t){return this.x(new b.Number(t).plus(this instanceof b.FX?0:this.x()),!0)},dy:function(t){return this.y(new b.Number(t).plus(this instanceof b.FX?0:this.y()),!0)},dmove:function(t,e){return this.dx(t).dy(e)}}),b.extend([b.Rect,b.Ellipse,b.Circle,b.Gradient,b.FX],{radius:function(t,e){var n=(this._target||this).type;return"radialGradient"==n||"radialGradient"==n?this.attr("r",new b.Number(t)):this.rx(t).ry(null==e?t:e)}}),b.extend(b.Path,{length:function(){return this.node.getTotalLength()},pointAt:function(t){return new b.Point(this.node.getPointAtLength(t))}}),b.extend([b.Parent,b.Text,b.Tspan,b.FX],{font:function(t,e){if("object"==typeof t)for(e in t)this.font(e,t[e]);return"leading"==t?this.leading(e):"anchor"==t?this.attr("text-anchor",e):"size"==t||"family"==t||"weight"==t||"stretch"==t||"variant"==t||"style"==t?this.attr("font-"+t,e):this.attr(t,e)}}),b.extend(b.Element,{data:function(t,e,n){if("object"==typeof t)for(e in t)this.data(e,t[e]);else if(arguments.length<2)try{return JSON.parse(this.attr("data-"+t))}catch(e){return this.attr("data-"+t)}else this.attr("data-"+t,null===e?null:n===!0||"string"==typeof e||"number"==typeof e?e:JSON.stringify(e));return this}}),b.extend(b.Element,{remember:function(t,e){if("object"==typeof arguments[0])for(var e in t)this.remember(e,t[e]);else{if(1==arguments.length)return this.memory()[t];this.memory()[t]=e}return this},forget:function(){if(0==arguments.length)this._memory={};else for(var t=arguments.length-1;t>=0;t--)delete this.memory()[arguments[t]];return this},memory:function(){return this._memory||(this._memory={})}}),b.get=function(t){var n=e.getElementById(w(t)||t);return b.adopt(n)},b.select=function(t,n){return b.utils.map((n||e).querySelectorAll(t),function(t){return b.adopt(t)})},b.$$=function(t,n){return b.utils.map((n||e).querySelectorAll(t),function(t){return b.adopt(t)})},b.$=function(t,n){return b.adopt((n||e).querySelector(t))},b.extend(b.Parent,{select:function(t){return b.select(t,this.node)}});var k="abcdef".split("");return b.Box=b.invent({create:function(t){var e=[0,0,0,0];t="string"==typeof t?t.split(b.regex.delimiter).map(parseFloat):Array.isArray(t)?t:"object"==typeof t?[null!=t.left?t.left:t.x,null!=t.top?t.top:t.y,t.width,t.height]:4==arguments.length?[].slice.call(arguments):e,this.x=t[0],this.y=t[1],this.width=t[2],this.height=t[3],g(this)},extend:{merge:function(t){var e=Math.min(this.x,t.x),n=Math.min(this.y,t.y);return new b.Box(e,n,Math.max(this.x+this.width,t.x+t.width)-e,Math.max(this.y+this.height,t.y+t.height)-n)},transform:function(t){var e=1/0,n=-(1/0),i=1/0,r=-(1/0),s=[new b.Point(this.x,this.y),new b.Point(this.x2,this.y),new b.Point(this.x,this.y2),new b.Point(this.x2,this.y2)];return s.forEach(function(s){s=s.transform(t),e=Math.min(e,s.x),n=Math.max(n,s.x),i=Math.min(i,s.y),r=Math.max(r,s.y)}),new b.Box(e,i,n-e,r-i)},addOffset:function(){return this.x+=t.pageXOffset,this.y+=t.pageYOffset,this},toString:function(){return this.x+" "+this.y+" "+this.width+" "+this.height},morph:function(t,e,n,i){return this.destination=new b.Box(t,e,n,i),this},at:function(t){return this.destination?new b.Box(this.x+(this.destination.x-this.x)*t,this.y+(this.destination.y-this.y)*t,this.width+(this.destination.width-this.width)*t,this.height+(this.destination.height-this.height)*t):this}},parent:b.Element,construct:{bbox:function(){var t;try{if(t=this.node.getBBox(),n(t)&&!i(this.node))throw new Exception("Element not in the dom")}catch(n){try{var e=this.clone(b.parser.draw.instance).show();t=e.node.getBBox(),e.remove()}catch(t){console.warn("Getting a bounding box of this element is not possible")}}return new b.Box(t)},rbox:function(t){try{var e=new b.Box(this.node.getBoundingClientRect());return t?e.transform(t.screenCTM().inverse()):e.addOffset()}catch(t){return new b.Box}}}}),b.extend([b.Doc,b.Nested,b.Symbol,b.Image,b.Pattern,b.Marker,b.ForeignObject,b.View],{viewbox:function(t,e,n,i){return null==t?new b.Box(this.attr("viewBox")):this.attr("viewBox",new b.Box(t,e,n,i))}}),b}); \ No newline at end of file
+/*! svg.js v3.0.0 MIT*/;!function(t,e){"function"==typeof define&&define.amd?define(function(){return e(t,t.document)}):"object"==typeof exports?module.exports=t.document?e(t,t.document):function(t){return e(t,t.document)}:t.SVG=e(t,t.document)}("undefined"!=typeof window?window:this,function(t,e){function i(t){return!(t.w||t.h||t.x||t.y)}function n(t){return(e.documentElement.contains||function(t){for(;t.parentNode;)t=t.parentNode;return t==e}).call(e.documentElement,t)}function r(t,e,i,n){return i+n.replace(b.regex.dots," .")}function s(t){for(var e=t.slice(0),i=e.length;i--;)Array.isArray(e[i])&&(e[i]=s(e[i]));return e}function a(t,e){return t instanceof e}function o(t,e){return(t.matches||t.matchesSelector||t.msMatchesSelector||t.mozMatchesSelector||t.webkitMatchesSelector||t.oMatchesSelector).call(t,e)}function h(t){return t.toLowerCase().replace(/-(.)/g,function(t,e){return e.toUpperCase()})}function u(t){return t.charAt(0).toUpperCase()+t.slice(1)}function l(t){return 4==t.length?["#",t.substring(1,2),t.substring(1,2),t.substring(2,3),t.substring(2,3),t.substring(3,4),t.substring(3,4)].join(""):t}function c(t){var e=t.toString(16);return 1==e.length?"0"+e:e}function f(t,e,i){if(null==e||null==i){var n=t.bbox();null==e?e=n.width/n.height*i:null==i&&(i=n.height/n.width*e)}return{width:e,height:i}}function d(t,e,i){return{x:e*t.a+i*t.c+0,y:e*t.b+i*t.d+0}}function p(t){return{a:t[0],b:t[1],c:t[2],d:t[3],e:t[4],f:t[5]}}function m(t){return t instanceof b.Matrix||(t=new b.Matrix(t)),t}function x(t,e){t.cx=null==t.cx?e.bbox().cx:t.cx,t.cy=null==t.cy?e.bbox().cy:t.cy}function y(t){for(var e=0,i=t.length,n="";e<i;e++)n+=t[e][0],null!=t[e][1]&&(n+=t[e][1],null!=t[e][2]&&(n+=" ",n+=t[e][2],null!=t[e][3]&&(n+=" ",n+=t[e][3],n+=" ",n+=t[e][4],null!=t[e][5]&&(n+=" ",n+=t[e][5],n+=" ",n+=t[e][6],null!=t[e][7]&&(n+=" ",n+=t[e][7])))));return n+" "}function v(e){for(var i=e.childNodes.length-1;i>=0;i--)e.childNodes[i]instanceof t.SVGElement&&v(e.childNodes[i]);return e.id?b.adopt(e).id(b.eid(e.nodeName)):b.adopt(e)}function g(t){return null==t.x&&(t.x=0,t.y=0,t.width=0,t.height=0),t.w=t.width,t.h=t.height,t.x2=t.x+t.width,t.y2=t.y+t.height,t.cx=t.x+t.width/2,t.cy=t.y+t.height/2,t}function w(t){var e=(t||"").toString().match(b.regex.reference);if(e)return e[1]}var b=this.SVG=function(t){if(b.supported)return t=new b.Doc(t),b.parser.draw||b.prepare(),t};if(b.ns="http://www.w3.org/2000/svg",b.xmlns="http://www.w3.org/2000/xmlns/",b.xlink="http://www.w3.org/1999/xlink",b.svgjs="http://svgjs.com/svgjs",b.supported=function(){return!!e.createElementNS&&!!e.createElementNS(b.ns,"svg").createSVGRect}(),!b.supported)return!1;b.did=1e3,b.eid=function(t){return"Svgjs"+u(t)+b.did++},b.create=function(t){return e.createElementNS(this.ns,t)},b.extend=function(t,e){var i,n;for(t=Array.isArray(t)?t:[t],n=t.length-1;n>=0;n--)if(t[n])for(i in e)t[n].prototype[i]=e[i]},b.invent=function(t){var e="function"==typeof t.create?t.create:function(){this.constructor.call(this,b.create(t.create))};return t.inherit&&(e.prototype=new t.inherit),t.extend&&b.extend(e,t.extend),t.construct&&b.extend(t.parent||b.Container,t.construct),e},b.adopt=function(e){if(!e)return null;if(e.instance)return e.instance;var i;return i="svg"==e.nodeName?e.parentNode instanceof t.SVGElement?new b.Nested:new b.Doc:"linearGradient"==e.nodeName?new b.Gradient("linear"):"radialGradient"==e.nodeName?new b.Gradient("radial"):b[u(e.nodeName)]?new(b[u(e.nodeName)]):new b.Element(e),i.type=e.nodeName,i.node=e,e.instance=i,i instanceof b.Doc&&i.namespace().defs(),i.setData(JSON.parse(e.getAttribute("svgjs:data"))||{}),i},b.prepare=function(){var t=e.getElementsByTagName("body")[0],i=(t?new b.Doc(t):b.adopt(e.documentElement).nested()).size(2,0);b.parser={body:t||e.documentElement,draw:i.css({opacity:0,position:"absolute",left:"-100%",top:"-100%",overflow:"hidden"}).node,poly:i.polyline().node,path:i.path().node,native:b.create("svg")}},b.parser={native:b.create("svg")},e.addEventListener("DOMContentLoaded",function(){b.parser.draw||b.prepare()},!1),b.regex={numberAndUnit:/^([+-]?(\d+(\.\d*)?|\.\d+)(e[+-]?\d+)?)([a-z%]*)$/i,hex:/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i,rgb:/rgb\((\d+),(\d+),(\d+)\)/,reference:/#([a-z0-9\-_]+)/i,transforms:/\)\s*,?\s*/,whitespace:/\s/g,isHex:/^#[a-f0-9]{3,6}$/i,isRgb:/^rgb\(/,isCss:/[^:]+:[^;]+;?/,isBlank:/^(\s+)?$/,isNumber:/^[+-]?(\d+(\.\d*)?|\.\d+)(e[+-]?\d+)?$/i,isPercent:/^-?[\d\.]+%$/,isImage:/\.(jpg|jpeg|png|gif|svg)(\?[^=]+.*)?/i,delimiter:/[\s,]+/,hyphen:/([^e])\-/gi,pathLetters:/[MLHVCSQTAZ]/gi,isPathLetter:/[MLHVCSQTAZ]/i,numbersWithDots:/((\d?\.\d+(?:e[+-]?\d+)?)((?:\.\d+(?:e[+-]?\d+)?)+))+/gi,dots:/\./g},b.utils={map:function(t,e){var i,n=t.length,r=[];for(i=0;i<n;i++)r.push(e(t[i]));return r},filter:function(t,e){var i,n=t.length,r=[];for(i=0;i<n;i++)e(t[i])&&r.push(t[i]);return r},radians:function(t){return t%360*Math.PI/180},degrees:function(t){return 180*t/Math.PI%360},filterSVGElements:function(e){return this.filter(e,function(e){return e instanceof t.SVGElement})}},b.defaults={attrs:{"fill-opacity":1,"stroke-opacity":1,"stroke-width":0,"stroke-linejoin":"miter","stroke-linecap":"butt",fill:"#000000",stroke:"#000000",opacity:1,x:0,y:0,cx:0,cy:0,width:0,height:0,r:0,rx:0,ry:0,offset:0,"stop-opacity":1,"stop-color":"#000000","font-size":16,"font-family":"Helvetica, Arial, sans-serif","text-anchor":"start"}},b.Color=function(t){var e;this.r=0,this.g=0,this.b=0,t&&("string"==typeof t?b.regex.isRgb.test(t)?(e=b.regex.rgb.exec(t.replace(b.regex.whitespace,"")),this.r=parseInt(e[1]),this.g=parseInt(e[2]),this.b=parseInt(e[3])):b.regex.isHex.test(t)&&(e=b.regex.hex.exec(l(t)),this.r=parseInt(e[1],16),this.g=parseInt(e[2],16),this.b=parseInt(e[3],16)):"object"==typeof t&&(this.r=t.r,this.g=t.g,this.b=t.b))},b.extend(b.Color,{toString:function(){return this.toHex()},toHex:function(){return"#"+c(this.r)+c(this.g)+c(this.b)},toRgb:function(){return"rgb("+[this.r,this.g,this.b].join()+")"},brightness:function(){return this.r/255*.3+this.g/255*.59+this.b/255*.11},morph:function(t){return this.destination=new b.Color(t),this},at:function(t){return this.destination?(t=t<0?0:t>1?1:t,new b.Color({r:~~(this.r+(this.destination.r-this.r)*t),g:~~(this.g+(this.destination.g-this.g)*t),b:~~(this.b+(this.destination.b-this.b)*t)})):this}}),b.Color.test=function(t){return t+="",b.regex.isHex.test(t)||b.regex.isRgb.test(t)},b.Color.isRgb=function(t){return t&&"number"==typeof t.r&&"number"==typeof t.g&&"number"==typeof t.b},b.Color.isColor=function(t){return b.Color.isRgb(t)||b.Color.test(t)},b.Array=function(t,e){t=(t||[]).valueOf(),0==t.length&&e&&(t=e.valueOf()),this.value=this.parse(t)},b.extend(b.Array,{morph:function(t){if(this.destination=this.parse(t),this.value.length!=this.destination.length){for(var e=this.value[this.value.length-1],i=this.destination[this.destination.length-1];this.value.length>this.destination.length;)this.destination.push(i);for(;this.value.length<this.destination.length;)this.value.push(e)}return this},settle:function(){for(var t=0,e=this.value.length,i=[];t<e;t++)-1==i.indexOf(this.value[t])&&i.push(this.value[t]);return this.value=i},at:function(t){if(!this.destination)return this;for(var e=0,i=this.value.length,n=[];e<i;e++)n.push(this.value[e]+(this.destination[e]-this.value[e])*t);return new b.Array(n)},toString:function(){return this.value.join(" ")},valueOf:function(){return this.value},parse:function(t){return t=t.valueOf(),Array.isArray(t)?t:t.trim().split(b.regex.delimiter).map(parseFloat)},reverse:function(){return this.value.reverse(),this},clone:function(){var t=new this.constructor;return t.value=s(this.value),t}}),b.PointArray=function(t,e){b.Array.call(this,t,e||[[0,0]])},b.PointArray.prototype=new b.Array,b.PointArray.prototype.constructor=b.PointArray,b.extend(b.PointArray,{toString:function(){for(var t=0,e=this.value.length,i=[];t<e;t++)i.push(this.value[t].join(","));return i.join(" ")},toLine:function(){return{x1:this.value[0][0],y1:this.value[0][1],x2:this.value[1][0],y2:this.value[1][1]}},at:function(t){if(!this.destination)return this;for(var e=0,i=this.value.length,n=[];e<i;e++)n.push([this.value[e][0]+(this.destination[e][0]-this.value[e][0])*t,this.value[e][1]+(this.destination[e][1]-this.value[e][1])*t]);return new b.PointArray(n)},parse:function(t){var e=[];if(t=t.valueOf(),Array.isArray(t)){if(Array.isArray(t[0]))return t}else t=t.trim().split(b.regex.delimiter).map(parseFloat);t.length%2!=0&&t.pop();for(var i=0,n=t.length;i<n;i+=2)e.push([t[i],t[i+1]]);return e},move:function(t,e){var i=this.bbox();if(t-=i.x,e-=i.y,!isNaN(t)&&!isNaN(e))for(var n=this.value.length-1;n>=0;n--)this.value[n]=[this.value[n][0]+t,this.value[n][1]+e];return this},size:function(t,e){var i,n=this.bbox();for(i=this.value.length-1;i>=0;i--)n.width&&(this.value[i][0]=(this.value[i][0]-n.x)*t/n.width+n.x),n.height&&(this.value[i][1]=(this.value[i][1]-n.y)*e/n.height+n.y);return this},bbox:function(){return b.parser.poly.setAttribute("points",this.toString()),b.parser.poly.getBBox()}});for(var C={M:function(t,e,i){return e.x=i.x=t[0],e.y=i.y=t[1],["M",e.x,e.y]},L:function(t,e){return e.x=t[0],e.y=t[1],["L",t[0],t[1]]},H:function(t,e){return e.x=t[0],["H",t[0]]},V:function(t,e){return e.y=t[0],["V",t[0]]},C:function(t,e){return e.x=t[4],e.y=t[5],["C",t[0],t[1],t[2],t[3],t[4],t[5]]},S:function(t,e){return e.x=t[2],e.y=t[3],["S",t[0],t[1],t[2],t[3]]},Q:function(t,e){return e.x=t[2],e.y=t[3],["Q",t[0],t[1],t[2],t[3]]},T:function(t,e){return e.x=t[0],e.y=t[1],["T",t[0],t[1]]},Z:function(t,e,i){return e.x=i.x,e.y=i.y,["Z"]},A:function(t,e){return e.x=t[5],e.y=t[6],["A",t[0],t[1],t[2],t[3],t[4],t[5],t[6]]}},N="mlhvqtcsaz".split(""),P=0,M=N.length;P<M;++P)C[N[P]]=function(t){return function(e,i,n){if("H"==t)e[0]=e[0]+i.x;else if("V"==t)e[0]=e[0]+i.y;else if("A"==t)e[5]=e[5]+i.x,e[6]=e[6]+i.y;else for(var r=0,s=e.length;r<s;++r)e[r]=e[r]+(r%2?i.y:i.x);return C[t](e,i,n)}}(N[P].toUpperCase());b.PathArray=function(t,e){b.Array.call(this,t,e||[["M",0,0]])},b.PathArray.prototype=new b.Array,b.PathArray.prototype.constructor=b.PathArray,b.extend(b.PathArray,{toString:function(){return y(this.value)},move:function(t,e){var i=this.bbox();if(t-=i.x,e-=i.y,!isNaN(t)&&!isNaN(e))for(var n,r=this.value.length-1;r>=0;r--)n=this.value[r][0],"M"==n||"L"==n||"T"==n?(this.value[r][1]+=t,this.value[r][2]+=e):"H"==n?this.value[r][1]+=t:"V"==n?this.value[r][1]+=e:"C"==n||"S"==n||"Q"==n?(this.value[r][1]+=t,this.value[r][2]+=e,this.value[r][3]+=t,this.value[r][4]+=e,"C"==n&&(this.value[r][5]+=t,this.value[r][6]+=e)):"A"==n&&(this.value[r][6]+=t,this.value[r][7]+=e);return this},size:function(t,e){var i,n,r=this.bbox();for(i=this.value.length-1;i>=0;i--)n=this.value[i][0],"M"==n||"L"==n||"T"==n?(this.value[i][1]=(this.value[i][1]-r.x)*t/r.width+r.x,this.value[i][2]=(this.value[i][2]-r.y)*e/r.height+r.y):"H"==n?this.value[i][1]=(this.value[i][1]-r.x)*t/r.width+r.x:"V"==n?this.value[i][1]=(this.value[i][1]-r.y)*e/r.height+r.y:"C"==n||"S"==n||"Q"==n?(this.value[i][1]=(this.value[i][1]-r.x)*t/r.width+r.x,this.value[i][2]=(this.value[i][2]-r.y)*e/r.height+r.y,this.value[i][3]=(this.value[i][3]-r.x)*t/r.width+r.x,this.value[i][4]=(this.value[i][4]-r.y)*e/r.height+r.y,"C"==n&&(this.value[i][5]=(this.value[i][5]-r.x)*t/r.width+r.x,this.value[i][6]=(this.value[i][6]-r.y)*e/r.height+r.y)):"A"==n&&(this.value[i][1]=this.value[i][1]*t/r.width,this.value[i][2]=this.value[i][2]*e/r.height,this.value[i][6]=(this.value[i][6]-r.x)*t/r.width+r.x,this.value[i][7]=(this.value[i][7]-r.y)*e/r.height+r.y);return this},equalCommands:function(t){var e,i,n;for(t=new b.PathArray(t),n=this.value.length===t.value.length,e=0,i=this.value.length;n&&e<i;e++)n=this.value[e][0]===t.value[e][0];return n},morph:function(t){return t=new b.PathArray(t),this.equalCommands(t)?this.destination=t:this.destination=null,this},at:function(t){if(!this.destination)return this;var e,i,n,r,s=this.value,a=this.destination.value,o=[],h=new b.PathArray;for(e=0,i=s.length;e<i;e++){for(o[e]=[s[e][0]],n=1,r=s[e].length;n<r;n++)o[e][n]=s[e][n]+(a[e][n]-s[e][n])*t;"A"===o[e][0]&&(o[e][4]=+(0!=o[e][4]),o[e][5]=+(0!=o[e][5]))}return h.value=o,h},parse:function(t){if(t instanceof b.PathArray)return t.valueOf();var e,i,n={M:2,L:2,H:1,V:1,C:6,S:4,Q:4,T:2,A:7,Z:0};t="string"==typeof t?t.replace(b.regex.numbersWithDots,r).replace(b.regex.pathLetters," $& ").replace(b.regex.hyphen,"$1 -").trim().split(b.regex.delimiter):t.reduce(function(t,e){return[].concat.call(t,e)},[]);var i=[],s=new b.Point,a=new b.Point,o=0,h=t.length;do{b.regex.isPathLetter.test(t[o])?(e=t[o],++o):"M"==e?e="L":"m"==e&&(e="l"),i.push(C[e].call(null,t.slice(o,o+=n[e.toUpperCase()]).map(parseFloat),s,a))}while(h>o);return i},bbox:function(){return b.parser.path.setAttribute("d",this.toString()),b.parser.path.getBBox()}}),b.Number=b.invent({create:function(t,e){this.value=0,this.unit=e||"","number"==typeof t?this.value=isNaN(t)?0:isFinite(t)?t:t<0?-3.4e38:3.4e38:"string"==typeof t?(e=t.match(b.regex.numberAndUnit))&&(this.value=parseFloat(e[1]),"%"==e[5]?this.value/=100:"s"==e[5]&&(this.value*=1e3),this.unit=e[5]):t instanceof b.Number&&(this.value=t.valueOf(),this.unit=t.unit)},extend:{toString:function(){return("%"==this.unit?~~(1e8*this.value)/1e6:"s"==this.unit?this.value/1e3:this.value)+this.unit},toJSON:function(){return this.toString()},valueOf:function(){return this.value},plus:function(t){return t=new b.Number(t),new b.Number(this+t,this.unit||t.unit)},minus:function(t){return t=new b.Number(t),new b.Number(this-t,this.unit||t.unit)},times:function(t){return t=new b.Number(t),new b.Number(this*t,this.unit||t.unit)},divide:function(t){return t=new b.Number(t),new b.Number(this/t,this.unit||t.unit)},to:function(t){var e=new b.Number(this);return"string"==typeof t&&(e.unit=t),e},morph:function(t){return this.destination=new b.Number(t),t.relative&&(this.destination.value+=this.value),this},at:function(t){return this.destination?new b.Number(this.destination).minus(this).times(t).plus(this):this}}}),b.Element=b.invent({create:function(t){this._event=null,this.dom={},(this.node=t)&&(this.type=t.nodeName,this.node.instance=this)},extend:{x:function(t){return this.attr("x",t)},y:function(t){return this.attr("y",t)},cx:function(t){return null==t?this.x()+this.width()/2:this.x(t-this.width()/2)},cy:function(t){return null==t?this.y()+this.height()/2:this.y(t-this.height()/2)},move:function(t,e){return this.x(t).y(e)},center:function(t,e){return this.cx(t).cy(e)},width:function(t){return this.attr("width",t)},height:function(t){return this.attr("height",t)},size:function(t,e){var i=f(this,t,e);return this.width(new b.Number(i.width)).height(new b.Number(i.height))},clone:function(t){this.writeDataToDom();var e=v(this.node.cloneNode(!0));return t?t.add(e):this.after(e),e},remove:function(){return this.parent()&&this.parent().removeElement(this),this},replace:function(t){return this.after(t).remove(),t},addTo:function(t){return t.put(this)},putIn:function(t){return t.add(this)},id:function(t){return void 0!==t||this.node.id||(this.node.id=b.eid(this.type)),this.attr("id",t)},inside:function(t,e){var i=this.bbox();return t>i.x&&e>i.y&&t<i.x+i.width&&e<i.y+i.height},show:function(){return this.css("display","")},hide:function(){return this.css("display","none")},visible:function(){return"none"!=this.css("display")},toString:function(){return this.id()},classes:function(){var t=this.attr("class");return null==t?[]:t.trim().split(b.regex.delimiter)},hasClass:function(t){return-1!=this.classes().indexOf(t)},addClass:function(t){if(!this.hasClass(t)){var e=this.classes();e.push(t),this.attr("class",e.join(" "))}return this},removeClass:function(t){return this.hasClass(t)&&this.attr("class",this.classes().filter(function(e){return e!=t}).join(" ")),this},toggleClass:function(t){return this.hasClass(t)?this.removeClass(t):this.addClass(t)},reference:function(t){return b.get(this.attr(t))},parent:function(e){var i=this;if(!i.node.parentNode)return null;if(i=b.adopt(i.node.parentNode),!e)return i;for(;i&&i.node instanceof t.SVGElement;){if("string"==typeof e?i.matches(e):i instanceof e)return i;i=b.adopt(i.node.parentNode)}},doc:function(){return this instanceof b.Doc?this:this.parent(b.Doc)},parents:function(t){var e=[],i=this;do{if(!(i=i.parent(t))||!i.node)break;e.push(i)}while(i.parent);return e},matches:function(t){return o(this.node,t)},native:function(){return this.node},svg:function(t){var i,n;if(!(t&&this instanceof b.Parent))return this.node.outerHTML;for(i=e.createElementNS(b.ns,"svg"),i.innerHTML=t,n=i.childNodes.length;n--;)1!=i.firstChild.nodeType?i.removeChild(i.firstChild):this.node.appendChild(i.firstChild);return this},writeDataToDom:function(){return this.is(b.Parent)&&this.each(function(){this.writeDataToDom()}),this.node.removeAttribute("svgjs:data"),Object.keys(this.dom).length&&this.node.setAttribute("svgjs:data",JSON.stringify(this.dom)),this},setData:function(t){return this.dom=t,this},is:function(t){return a(this,t)}}}),b.easing={"-":function(t){return t},"<>":function(t){return-Math.cos(t*Math.PI)/2+.5},">":function(t){return Math.sin(t*Math.PI/2)},"<":function(t){return 1-Math.cos(t*Math.PI/2)}},b.morph=function(t){return function(e,i){return new b.MorphObj(e,i).at(t)}},b.Situation=b.invent({create:function(t){this.init=!1,this.reversed=!1,this.reversing=!1,this.duration=new b.Number(t.duration).valueOf(),this.delay=new b.Number(t.delay).valueOf(),this.start=+new Date+this.delay,this.finish=this.start+this.duration,this.ease=t.ease,this.loop=0,this.loops=!1,this.animations={},this.attrs={},this.styles={},this.transforms=[],this.once={}}}),b.FX=b.invent({create:function(t){this._target=t,this.situations=[],this.active=!1,this.situation=null,this.paused=!1,this.lastPos=0,this.pos=0,this.absPos=0,this._speed=1},extend:{animate:function(t,e,i){"object"==typeof t&&(e=t.ease,i=t.delay,t=t.duration);var n=new b.Situation({duration:t||1e3,delay:i||0,ease:b.easing[e||"-"]||e});return this.queue(n),this},delay:function(t){var e=new b.Situation({duration:t,delay:0,ease:b.easing["-"]});return this.queue(e)},target:function(t){return t&&t instanceof b.Element?(this._target=t,this):this._target},timeToAbsPos:function(t){return(t-this.situation.start)/(this.situation.duration/this._speed)},absPosToTime:function(t){return this.situation.duration/this._speed*t+this.situation.start},startAnimFrame:function(){this.stopAnimFrame(),this.animationFrame=t.requestAnimationFrame(function(){this.step()}.bind(this))},stopAnimFrame:function(){t.cancelAnimationFrame(this.animationFrame)},start:function(){return!this.active&&this.situation&&(this.active=!0,this.startCurrent()),this},startCurrent:function(){return this.situation.start=+new Date+this.situation.delay/this._speed,this.situation.finish=this.situation.start+this.situation.duration/this._speed,this.initAnimations().step()},queue:function(t){return("function"==typeof t||t instanceof b.Situation)&&this.situations.push(t),this.situation||(this.situation=this.situations.shift()),this},dequeue:function(){return this.stop(),this.situation=this.situations.shift(),this.situation&&(this.situation instanceof b.Situation?this.start():this.situation.call(this)),this},initAnimations:function(){var t,e,i,n=this.situation;if(n.init)return this;for(t in n.animations)for(i=this.target()[t](),Array.isArray(i)||(i=[i]),Array.isArray(n.animations[t])||(n.animations[t]=[n.animations[t]]),e=i.length;e--;)n.animations[t][e]instanceof b.Number&&(i[e]=new b.Number(i[e])),n.animations[t][e]=i[e].morph(n.animations[t][e]);for(t in n.attrs)n.attrs[t]=new b.MorphObj(this.target().attr(t),n.attrs[t]);for(t in n.styles)n.styles[t]=new b.MorphObj(this.target().css(t),n.styles[t]);return n.initialTransformation=this.target().matrixify(),n.init=!0,this},clearQueue:function(){return this.situations=[],this},clearCurrent:function(){return this.situation=null,this},stop:function(t,e){var i=this.active;return this.active=!1,e&&this.clearQueue(),t&&this.situation&&(!i&&this.startCurrent(),this.atEnd()),this.stopAnimFrame(),this.clearCurrent()},reset:function(){if(this.situation){var t=this.situation;this.stop(),this.situation=t,this.atStart()}return this},finish:function(){for(this.stop(!0,!1);this.dequeue().situation&&this.stop(!0,!1););return this.clearQueue().clearCurrent(),this},atStart:function(){return this.at(0,!0)},atEnd:function(){return!0===this.situation.loops&&(this.situation.loops=this.situation.loop+1),"number"==typeof this.situation.loops?this.at(this.situation.loops,!0):this.at(1,!0)},at:function(t,e){var i=this.situation.duration/this._speed;return this.absPos=t,e||(this.situation.reversed&&(this.absPos=1-this.absPos),this.absPos+=this.situation.loop),this.situation.start=+new Date-this.absPos*i,this.situation.finish=this.situation.start+i,this.step(!0)},speed:function(t){return 0===t?this.pause():t?(this._speed=t,this.at(this.absPos,!0)):this._speed},loop:function(t,e){var i=this.last();return i.loops=null==t||t,i.loop=0,e&&(i.reversing=!0),this},pause:function(){return this.paused=!0,this.stopAnimFrame(),this},play:function(){return this.paused?(this.paused=!1,this.at(this.absPos,!0)):this},reverse:function(t){var e=this.last();return e.reversed=void 0===t?!e.reversed:t,this},progress:function(t){return t?this.situation.ease(this.pos):this.pos},after:function(t){var e=this.last(),i=function i(n){n.detail.situation==e&&(t.call(this,e),this.off("finished.fx",i))};return this.target().on("finished.fx",i),this._callStart()},during:function(t){var e=this.last(),i=function(i){i.detail.situation==e&&t.call(this,i.detail.pos,b.morph(i.detail.pos),i.detail.eased,e)};return this.target().off("during.fx",i).on("during.fx",i),this.after(function(){this.off("during.fx",i)}),this._callStart()},afterAll:function(t){var e=function e(i){t.call(this),this.off("allfinished.fx",e)};return this.target().off("allfinished.fx",e).on("allfinished.fx",e),this._callStart()},duringAll:function(t){var e=function(e){t.call(this,e.detail.pos,b.morph(e.detail.pos),e.detail.eased,e.detail.situation)};return this.target().off("during.fx",e).on("during.fx",e),this.afterAll(function(){this.off("during.fx",e)}),this._callStart()},last:function(){return this.situations.length?this.situations[this.situations.length-1]:this.situation},add:function(t,e,i){return this.last()[i||"animations"][t]=e,this._callStart()},step:function(t){if(t||(this.absPos=this.timeToAbsPos(+new Date)),!1!==this.situation.loops){var e,i,n;e=Math.max(this.absPos,0),i=Math.floor(e),!0===this.situation.loops||i<this.situation.loops?(this.pos=e-i,n=this.situation.loop,this.situation.loop=i):(this.absPos=this.situation.loops,this.pos=1,n=this.situation.loop-1,this.situation.loop=this.situation.loops),this.situation.reversing&&(this.situation.reversed=this.situation.reversed!=Boolean((this.situation.loop-n)%2))}else this.absPos=Math.min(this.absPos,1),this.pos=this.absPos;this.pos<0&&(this.pos=0),this.situation.reversed&&(this.pos=1-this.pos);var r=this.situation.ease(this.pos);for(var s in this.situation.once)s>this.lastPos&&s<=r&&(this.situation.once[s].call(this.target(),this.pos,r),delete this.situation.once[s]);return this.active&&this.target().fire("during",{pos:this.pos,eased:r,fx:this,situation:this.situation}),this.situation?(this.eachAt(),1==this.pos&&!this.situation.reversed||this.situation.reversed&&0==this.pos?(this.stopAnimFrame(),this.target().fire("finished",{fx:this,situation:this.situation}),this.situations.length||(this.target().fire("allfinished"),this.situations.length||(this.target().off(".fx"),this.active=!1)),this.active?this.dequeue():this.clearCurrent()):!this.paused&&this.active&&this.startAnimFrame(),this.lastPos=r,this):this},eachAt:function(){var t,e,i,n=this,r=this.target(),s=this.situation;for(t in s.animations)i=[].concat(s.animations[t]).map(function(t){return"string"!=typeof t&&t.at?t.at(s.ease(n.pos),n.pos):t}),r[t].apply(r,i);for(t in s.attrs)i=[t].concat(s.attrs[t]).map(function(t){return"string"!=typeof t&&t.at?t.at(s.ease(n.pos),n.pos):t}),r.attr.apply(r,i);for(t in s.styles)i=[t].concat(s.styles[t]).map(function(t){return"string"!=typeof t&&t.at?t.at(s.ease(n.pos),n.pos):t}),r.css.apply(r,i);if(s.transforms.length){for(i=s.initialTransformation,t=0,e=s.transforms.length;t<e;t++){var a=s.transforms[t];a instanceof b.Matrix?i=a.relative?i.multiply((new b.Matrix).morph(a).at(s.ease(this.pos))):i.morph(a).at(s.ease(this.pos)):(a.relative||a.undo(i.extract()),i=i.multiply(a.at(s.ease(this.pos))))}r.matrix(i)}return this},once:function(t,e,i){var n=this.last();return i||(t=n.ease(t)),n.once[t]=e,this},_callStart:function(){return setTimeout(function(){this.start()}.bind(this),0),this}},parent:b.Element,construct:{animate:function(t,e,i){return(this.fx||(this.fx=new b.FX(this))).animate(t,e,i)},delay:function(t){return(this.fx||(this.fx=new b.FX(this))).delay(t)},stop:function(t,e){return this.fx&&this.fx.stop(t,e),this},finish:function(){return this.fx&&this.fx.finish(),this},pause:function(){return this.fx&&this.fx.pause(),this},play:function(){return this.fx&&this.fx.play(),this},speed:function(t){if(this.fx){if(null==t)return this.fx.speed();this.fx.speed(t)}return this}}}),b.MorphObj=b.invent({create:function(t,e){return b.Color.isColor(e)?new b.Color(t).morph(e):b.regex.delimiter.test(t)?new b.Array(t).morph(e):b.regex.numberAndUnit.test(e)?new b.Number(t).morph(e):(this.value=t,void(this.destination=e))},extend:{at:function(t,e){return e<1?this.value:this.destination},valueOf:function(){return this.value}}}),b.extend(b.FX,{attr:function(t,e,i){if("object"==typeof t)for(var n in t)this.attr(n,t[n]);else this.add(t,e,"attrs");return this},css:function(t,e){if("object"==typeof t)for(var i in t)this.css(i,t[i]);else this.add(t,e,"styles");return this},x:function(t,e){if(this.target()instanceof b.G)return this.transform({x:t},e),this;var i=new b.Number(t);return i.relative=e,this.add("x",i)},y:function(t,e){if(this.target()instanceof b.G)return this.transform({y:t},e),this;var i=new b.Number(t);return i.relative=e,this.add("y",i)},cx:function(t){return this.add("cx",new b.Number(t))},cy:function(t){return this.add("cy",new b.Number(t))},move:function(t,e){return this.x(t).y(e)},center:function(t,e){return this.cx(t).cy(e)},size:function(t,e){if(this.target()instanceof b.Text)this.attr("font-size",t);else{var i;t&&e||(i=this.target().bbox()),t||(t=i.width/i.height*e),e||(e=i.height/i.width*t),this.add("width",new b.Number(t)).add("height",new b.Number(e))}return this},width:function(t){return this.add("width",new b.Number(t))},height:function(t){return this.add("height",new b.Number(t))},plot:function(t,e,i,n){return 4==arguments.length?this.plot([t,e,i,n]):this.add("plot",new(this.target().morphArray)(t))},leading:function(t){return this.target().leading?this.add("leading",new b.Number(t)):this},viewbox:function(t,e,i,n){return this.target()instanceof b.Container&&this.add("viewbox",new b.Box(t,e,i,n)),this},update:function(t){if(this.target()instanceof b.Stop){if("number"==typeof t||t instanceof b.Number)return this.update({offset:arguments[0],color:arguments[1],opacity:arguments[2]});null!=t.opacity&&this.attr("stop-opacity",t.opacity),null!=t.color&&this.attr("stop-color",t.color),null!=t.offset&&this.attr("offset",t.offset)}return this}}),b.Matrix=b.invent({create:function(t){var e,i=p([1,0,0,1,0,0]);for(t=t instanceof b.Element?t.matrixify():"string"==typeof t?p(t.split(b.regex.delimiter).map(parseFloat)):6==arguments.length?p([].slice.call(arguments)):Array.isArray(t)?p(t):"object"==typeof t?t:i,e=k.length-1;e>=0;--e)this[k[e]]=null!=t[k[e]]?t[k[e]]:i[k[e]]},extend:{extract:function(){var t=d(this,0,1),e=d(this,1,0),i=180/Math.PI*Math.atan2(t.y,t.x)-90;return{x:this.e,y:this.f,transformedX:(this.e*Math.cos(i*Math.PI/180)+this.f*Math.sin(i*Math.PI/180))/Math.sqrt(this.a*this.a+this.b*this.b),transformedY:(this.f*Math.cos(i*Math.PI/180)+this.e*Math.sin(-i*Math.PI/180))/Math.sqrt(this.c*this.c+this.d*this.d),skewX:-i,skewY:180/Math.PI*Math.atan2(e.y,e.x),scaleX:Math.sqrt(this.a*this.a+this.b*this.b),scaleY:Math.sqrt(this.c*this.c+this.d*this.d),rotation:i,a:this.a,b:this.b,c:this.c,d:this.d,e:this.e,f:this.f,matrix:new b.Matrix(this)}},clone:function(){return new b.Matrix(this)},morph:function(t){return this.destination=new b.Matrix(t),this},at:function(t){return this.destination?new b.Matrix({a:this.a+(this.destination.a-this.a)*t,b:this.b+(this.destination.b-this.b)*t,c:this.c+(this.destination.c-this.c)*t,d:this.d+(this.destination.d-this.d)*t,e:this.e+(this.destination.e-this.e)*t,f:this.f+(this.destination.f-this.f)*t}):this},multiply:function(t){return new b.Matrix(this.native().multiply(m(t).native()))},inverse:function(){return new b.Matrix(this.native().inverse())},translate:function(t,e){return new b.Matrix(this.native().translate(t||0,e||0))},scale:function(t,e,i,n){return 1==arguments.length?e=t:3==arguments.length&&(n=i,i=e,e=t),this.around(i,n,new b.Matrix(t,0,0,e,0,0))},rotate:function(t,e,i){return t=b.utils.radians(t),this.around(e,i,new b.Matrix(Math.cos(t),Math.sin(t),-Math.sin(t),Math.cos(t),0,0))},flip:function(t,e){return"x"==t?this.scale(-1,1,e,0):"y"==t?this.scale(1,-1,0,e):this.scale(-1,-1,t,null!=e?e:t)},skew:function(t,e,i,n){return 1==arguments.length?e=t:3==arguments.length&&(n=i,i=e,e=t),t=b.utils.radians(t),e=b.utils.radians(e),this.around(i,n,new b.Matrix(1,Math.tan(e),Math.tan(t),1,0,0))},skewX:function(t,e,i){return this.skew(t,0,e,i)},skewY:function(t,e,i){return this.skew(0,t,e,i)},around:function(t,e,i){return this.multiply(new b.Matrix(1,0,0,1,t||0,e||0)).multiply(i).multiply(new b.Matrix(1,0,0,1,-t||0,-e||0))},native:function(){for(var t=b.parser.native.createSVGMatrix(),e=k.length-1;e>=0;e--)t[k[e]]=this[k[e]];return t},toString:function(){return"matrix("+this.a+","+this.b+","+this.c+","+this.d+","+this.e+","+this.f+")"}},parent:b.Element,construct:{ctm:function(){return new b.Matrix(this.node.getCTM())},screenCTM:function(){if(this instanceof b.Nested){var t=this.rect(1,1),e=t.node.getScreenCTM();return t.remove(),new b.Matrix(e)}return new b.Matrix(this.node.getScreenCTM())}}}),b.Point=b.invent({create:function(t,e){var i,n={x:0,y:0};i=Array.isArray(t)?{x:t[0],y:t[1]}:"object"==typeof t?{x:t.x,y:t.y}:null!=t?{x:t,y:null!=e?e:t}:n,this.x=i.x,this.y=i.y},extend:{clone:function(){return new b.Point(this)},morph:function(t,e){return this.destination=new b.Point(t,e),this},at:function(t){return this.destination?new b.Point({x:this.x+(this.destination.x-this.x)*t,y:this.y+(this.destination.y-this.y)*t}):this},native:function(){var t=b.parser.native.createSVGPoint();return t.x=this.x,t.y=this.y,t},transform:function(t){return new b.Point(this.native().matrixTransform(t.native()))}}}),b.extend(b.Element,{point:function(t,e){return new b.Point(t,e).transform(this.screenCTM().inverse())}}),b.extend(b.Element,{attr:function(t,e,i){if(null==t){for(t={},e=this.node.attributes,i=e.length-1;i>=0;i--)t[e[i].nodeName]=b.regex.isNumber.test(e[i].nodeValue)?parseFloat(e[i].nodeValue):e[i].nodeValue;return t}if("object"==typeof t)for(e in t)this.attr(e,t[e]);else if(null===e)this.node.removeAttribute(t);else{if(null==e)return e=this.node.getAttribute(t),null==e?b.defaults.attrs[t]:b.regex.isNumber.test(e)?parseFloat(e):e;"fill"!=t&&"stroke"!=t||(b.regex.isImage.test(e)&&(e=this.doc().defs().image(e)),e instanceof b.Image&&(e=this.doc().defs().pattern(0,0,function(){this.add(e)}))),"number"==typeof e?e=new b.Number(e):b.Color.isColor(e)?e=new b.Color(e):Array.isArray(e)&&(e=new b.Array(e)),"leading"==t?this.leading&&this.leading(e):"string"==typeof i?this.node.setAttributeNS(i,t,e.toString()):this.node.setAttribute(t,e.toString()),!this.rebuild||"font-size"!=t&&"x"!=t||this.rebuild(t,e)}return this}}),b.extend(b.Element,{transform:function(t,e){var i,n,r=this;if("object"!=typeof t)return i=new b.Matrix(r).extract(),"string"==typeof t?i[t]:i;if(i=new b.Matrix(r),e=!!e||!!t.relative,
+null!=t.a)i=e?i.multiply(new b.Matrix(t)):new b.Matrix(t);else if(null!=t.rotation)x(t,r),i=e?i.rotate(t.rotation,t.cx,t.cy):i.rotate(t.rotation-i.extract().rotation,t.cx,t.cy);else if(null!=t.scale||null!=t.scaleX||null!=t.scaleY){if(x(t,r),t.scaleX=null!=t.scale?t.scale:null!=t.scaleX?t.scaleX:1,t.scaleY=null!=t.scale?t.scale:null!=t.scaleY?t.scaleY:1,!e){var s=i.extract();t.scaleX=1*t.scaleX/s.scaleX,t.scaleY=1*t.scaleY/s.scaleY}i=i.scale(t.scaleX,t.scaleY,t.cx,t.cy)}else if(null!=t.skew||null!=t.skewX||null!=t.skewY){if(x(t,r),t.skewX=null!=t.skew?t.skew:null!=t.skewX?t.skewX:0,t.skewY=null!=t.skew?t.skew:null!=t.skewY?t.skewY:0,!e){var s=i.extract();i=i.multiply((new b.Matrix).skew(s.skewX,s.skewY,t.cx,t.cy).inverse())}i=i.skew(t.skewX,t.skewY,t.cx,t.cy)}else t.flip?("x"==t.flip||"y"==t.flip?t.offset=null==t.offset?r.bbox()["c"+t.flip]:t.offset:null==t.offset?(n=r.bbox(),t.flip=n.cx,t.offset=n.cy):t.flip=t.offset,i=(new b.Matrix).flip(t.flip,t.offset)):null==t.x&&null==t.y||(e?i=i.translate(t.x,t.y):(null!=t.x&&(i.e=t.x),null!=t.y&&(i.f=t.y)));return this.attr("transform",i)}}),b.extend(b.FX,{transform:function(t,e){var i,n,r=this.target();return"object"!=typeof t?(i=new b.Matrix(r).extract(),"string"==typeof t?i[t]:i):(e=!!e||!!t.relative,null!=t.a?i=new b.Matrix(t):null!=t.rotation?(x(t,r),i=new b.Rotate(t.rotation,t.cx,t.cy)):null!=t.scale||null!=t.scaleX||null!=t.scaleY?(x(t,r),t.scaleX=null!=t.scale?t.scale:null!=t.scaleX?t.scaleX:1,t.scaleY=null!=t.scale?t.scale:null!=t.scaleY?t.scaleY:1,i=new b.Scale(t.scaleX,t.scaleY,t.cx,t.cy)):null!=t.skewX||null!=t.skewY?(x(t,r),t.skewX=null!=t.skewX?t.skewX:0,t.skewY=null!=t.skewY?t.skewY:0,i=new b.Skew(t.skewX,t.skewY,t.cx,t.cy)):t.flip?("x"==t.flip||"y"==t.flip?t.offset=null==t.offset?r.bbox()["c"+t.flip]:t.offset:null==t.offset?(n=r.bbox(),t.flip=n.cx,t.offset=n.cy):t.flip=t.offset,i=(new b.Matrix).flip(t.flip,t.offset)):null==t.x&&null==t.y||(i=new b.Translate(t.x,t.y)),i?(i.relative=e,this.last().transforms.push(i),this._callStart()):this)}}),b.extend(b.Element,{untransform:function(){return this.attr("transform",null)},matrixify:function(){return(this.attr("transform")||"").split(b.regex.transforms).slice(0,-1).map(function(t){var e=t.trim().split("(");return[e[0],e[1].split(b.regex.delimiter).map(function(t){return parseFloat(t)})]}).reduce(function(t,e){return"matrix"==e[0]?t.multiply(p(e[1])):t[e[0]].apply(t,e[1])},new b.Matrix)},toParent:function(t){if(this==t)return this;var e=this.screenCTM(),i=t.screenCTM().inverse();return this.addTo(t).untransform().transform(i.multiply(e)),this},toDoc:function(){return this.toParent(this.doc())}}),b.Transformation=b.invent({create:function(t,e){if(arguments.length>1&&"boolean"!=typeof e)return this.constructor.call(this,[].slice.call(arguments));if(Array.isArray(t))for(var i=0,n=this.arguments.length;i<n;++i)this[this.arguments[i]]=t[i];else if("object"==typeof t)for(var i=0,n=this.arguments.length;i<n;++i)this[this.arguments[i]]=t[this.arguments[i]];this.inversed=!1,!0===e&&(this.inversed=!0)},extend:{arguments:[],method:"",at:function(t){for(var e=[],i=0,n=this.arguments.length;i<n;++i)e.push(this[this.arguments[i]]);var r=this._undo||new b.Matrix;return r=(new b.Matrix).morph(b.Matrix.prototype[this.method].apply(r,e)).at(t),this.inversed?r.inverse():r},undo:function(t){for(var e=0,i=this.arguments.length;e<i;++e)t[this.arguments[e]]=void 0===this[this.arguments[e]]?0:t[this.arguments[e]];return t.cx=this.cx,t.cy=this.cy,this._undo=new(b[u(this.method)])(t,!0).at(1),this}}}),b.Translate=b.invent({parent:b.Matrix,inherit:b.Transformation,create:function(t,e){this.constructor.apply(this,[].slice.call(arguments))},extend:{arguments:["transformedX","transformedY"],method:"translate"}}),b.Rotate=b.invent({parent:b.Matrix,inherit:b.Transformation,create:function(t,e){this.constructor.apply(this,[].slice.call(arguments))},extend:{arguments:["rotation","cx","cy"],method:"rotate",at:function(t){var e=(new b.Matrix).rotate((new b.Number).morph(this.rotation-(this._undo?this._undo.rotation:0)).at(t),this.cx,this.cy);return this.inversed?e.inverse():e},undo:function(t){return this._undo=t,this}}}),b.Scale=b.invent({parent:b.Matrix,inherit:b.Transformation,create:function(t,e){this.constructor.apply(this,[].slice.call(arguments))},extend:{arguments:["scaleX","scaleY","cx","cy"],method:"scale"}}),b.Skew=b.invent({parent:b.Matrix,inherit:b.Transformation,create:function(t,e){this.constructor.apply(this,[].slice.call(arguments))},extend:{arguments:["skewX","skewY","cx","cy"],method:"skew"}}),b.extend(b.Element,{css:function(t,e){var i,n,r={};if(0==arguments.length)return this.node.style.cssText.split(/\s*;\s*/).filter(function(t){return!!t.length}).forEach(function(t){i=t.split(/\s*:\s*/),r[i[0]]=i[1]}),r;if(arguments.length<2){if(Array.isArray(t)){for(n=t.length;n--;)r[h(t[n])]=this.node.style[h(t[n])];return r}if("string"==typeof t)return this.node.style[h(t)];if("object"==typeof t)for(n in t)this.node.style[h(n)]=null==t[n]||b.regex.isBlank.test(t[n])?"":t[n]}return 2==arguments.length&&(this.node.style[h(t)]=null==e||b.regex.isBlank.test(e)?"":e),this}}),b.Parent=b.invent({create:function(t){this.constructor.call(this,t)},inherit:b.Element,extend:{children:function(){return b.utils.map(b.utils.filterSVGElements(this.node.childNodes),function(t){return b.adopt(t)})},add:function(t,e){return null==e?this.node.appendChild(t.node):t.node!=this.node.childNodes[e]&&this.node.insertBefore(t.node,this.node.childNodes[e]),this},put:function(t,e){return this.add(t,e),t},has:function(t){return this.index(t)>=0},index:function(t){return[].slice.call(this.node.childNodes).indexOf(t.node)},get:function(t){return b.adopt(this.node.childNodes[t])},first:function(){return this.get(0)},last:function(){return this.get(this.node.childNodes.length-1)},each:function(t,e){var i,n,r=this.children();for(i=0,n=r.length;i<n;i++)r[i]instanceof b.Element&&t.apply(r[i],[i,r]),e&&r[i]instanceof b.Container&&r[i].each(t,e);return this},removeElement:function(t){return this.node.removeChild(t.node),this},clear:function(){for(;this.node.hasChildNodes();)this.node.removeChild(this.node.lastChild);return delete this._defs,this},defs:function(){return this.doc().defs()}}}),b.extend(b.Parent,{flatten:function(t){return this instanceof b.Defs?this:(t=t||(this instanceof b.Doc?this:this.parent(b.Parent)),this.each(function(){return this instanceof b.Defs?this:this instanceof b.Parent?this.flatten(t):this.toParent(t)}),this.node.firstChild||this.remove(),this)}}),b.Container=b.invent({create:function(t){this.constructor.call(this,t)},inherit:b.Parent}),["click","dblclick","mousedown","mouseup","mouseover","mouseout","mousemove","touchstart","touchmove","touchleave","touchend","touchcancel"].forEach(function(t){b.Element.prototype[t]=function(e){return b.on(this.node,t,e),this}}),b.listeners=[],b.handlerMap=[],b.listenerId=0,b.on=function(t,e,i,n,r){var s=i.bind(n||t.instance||t),a=(b.handlerMap.indexOf(t)+1||b.handlerMap.push(t))-1,o=e.split(".")[0],h=e.split(".")[1]||"*";b.listeners[a]=b.listeners[a]||{},b.listeners[a][o]=b.listeners[a][o]||{},b.listeners[a][o][h]=b.listeners[a][o][h]||{},i._svgjsListenerId||(i._svgjsListenerId=++b.listenerId),b.listeners[a][o][h][i._svgjsListenerId]=s,t.addEventListener(o,s,r||!1)},b.off=function(t,e,i){var n=b.handlerMap.indexOf(t),r=e&&e.split(".")[0],s=e&&e.split(".")[1],a="";if(-1!=n)if(i){if("function"==typeof i&&(i=i._svgjsListenerId),!i)return;b.listeners[n][r]&&b.listeners[n][r][s||"*"]&&(t.removeEventListener(r,b.listeners[n][r][s||"*"][i],!1),delete b.listeners[n][r][s||"*"][i])}else if(s&&r){if(b.listeners[n][r]&&b.listeners[n][r][s]){for(i in b.listeners[n][r][s])b.off(t,[r,s].join("."),i);delete b.listeners[n][r][s]}}else if(s)for(e in b.listeners[n])for(a in b.listeners[n][e])s===a&&b.off(t,[e,s].join("."));else if(r){if(b.listeners[n][r]){for(a in b.listeners[n][r])b.off(t,[r,a].join("."));delete b.listeners[n][r]}}else{for(e in b.listeners[n])b.off(t,e);delete b.listeners[n],delete b.handlerMap[n]}},b.extend(b.Element,{on:function(t,e,i,n){return b.on(this.node,t,e,i,n),this},off:function(t,e){return b.off(this.node,t,e),this},fire:function(e,i){return e instanceof t.Event?this.node.dispatchEvent(e):this.node.dispatchEvent(e=new t.CustomEvent(e,{detail:i,cancelable:!0})),this._event=e,this},event:function(){return this._event}}),b.Defs=b.invent({create:"defs",inherit:b.Container}),b.G=b.invent({create:"g",inherit:b.Container,extend:{x:function(t){return null==t?this.transform("x"):this.transform({x:t-this.x()},!0)},y:function(t){return null==t?this.transform("y"):this.transform({y:t-this.y()},!0)},cx:function(t){return null==t?this.gbox().cx:this.x(t-this.gbox().width/2)},cy:function(t){return null==t?this.gbox().cy:this.y(t-this.gbox().height/2)},gbox:function(){var t=this.bbox(),e=this.transform();return t.x+=e.x,t.x2+=e.x,t.cx+=e.x,t.y+=e.y,t.y2+=e.y,t.cy+=e.y,t}},construct:{group:function(){return this.put(new b.G)}}}),b.extend(b.Element,{siblings:function(){return this.parent().children()},position:function(){return this.parent().index(this)},next:function(){return this.siblings()[this.position()+1]},previous:function(){return this.siblings()[this.position()-1]},forward:function(){var t=this.position()+1,e=this.parent();return e.removeElement(this).add(this,t),e instanceof b.Doc&&e.node.appendChild(e.defs().node),this},backward:function(){var t=this.position();return t>0&&this.parent().removeElement(this).add(this,t-1),this},front:function(){var t=this.parent();return t.node.appendChild(this.node),t instanceof b.Doc&&t.node.appendChild(t.defs().node),this},back:function(){return this.position()>0&&this.parent().removeElement(this).add(this,0),this},before:function(t){t.remove();var e=this.position();return this.parent().add(t,e),this},after:function(t){t.remove();var e=this.position();return this.parent().add(t,e+1),this}}),b.Mask=b.invent({create:"mask",inherit:b.Container,extend:{remove:function(){return this.targets().forEach(function(t){t.unmask()}),b.Element.prototype.remove.call(this)},targets:function(){return b.select('svg [mask*="'+this.id()+'"]')}},construct:{mask:function(){return this.defs().put(new b.Mask)}}}),b.extend(b.Element,{maskWith:function(t){var e=t instanceof b.Mask?t:this.parent().mask().add(t);return this.attr("mask",'url("#'+e.id()+'")')},unmask:function(){return this.attr("mask",null)},masker:function(){return this.reference("mask")}}),b.ClipPath=b.invent({create:"clipPath",inherit:b.Container,extend:{remove:function(){return this.targets().forEach(function(t){t.unclip()}),b.Element.prototype.remove.call(this)},targets:function(){return b.select('svg [clip-path*="'+this.id()+'"]')}},construct:{clip:function(){return this.defs().put(new b.ClipPath)}}}),b.extend(b.Element,{clipWith:function(t){var e=t instanceof b.ClipPath?t:this.parent().clip().add(t);return this.attr("clip-path",'url("#'+e.id()+'")')},unclip:function(){return this.attr("clip-path",null)},clipper:function(){return this.reference("clip-path")}}),b.Gradient=b.invent({create:function(t){this.constructor.call(this,b.create(t+"Gradient"))},inherit:b.Container,extend:{at:function(t,e,i){return this.put(new b.Stop).update(t,e,i)},update:function(t){return this.clear(),"function"==typeof t&&t.call(this,this),this},fill:function(){return"url(#"+this.id()+")"},toString:function(){return this.fill()},attr:function(t,e,i){return"transform"==t&&(t="gradientTransform"),b.Container.prototype.attr.call(this,t,e,i)}},construct:{gradient:function(t,e){return this.defs().gradient(t,e)}}}),b.extend([b.Gradient,b.FX],{from:function(t,e){return"radialGradient"==(this._target||this).type?this.attr({fx:new b.Number(t),fy:new b.Number(e)}):this.attr({x1:new b.Number(t),y1:new b.Number(e)})},to:function(t,e){return"radialGradient"==(this._target||this).type?this.attr({cx:new b.Number(t),cy:new b.Number(e)}):this.attr({x2:new b.Number(t),y2:new b.Number(e)})}}),b.extend(b.Defs,{gradient:function(t,e){return this.put(new b.Gradient(t)).update(e)}}),b.Stop=b.invent({create:"stop",inherit:b.Element,extend:{update:function(t){return("number"==typeof t||t instanceof b.Number)&&(t={offset:arguments[0],color:arguments[1],opacity:arguments[2]}),null!=t.opacity&&this.attr("stop-opacity",t.opacity),null!=t.color&&this.attr("stop-color",t.color),null!=t.offset&&this.attr("offset",new b.Number(t.offset)),this}}}),b.Pattern=b.invent({create:"pattern",inherit:b.Container,extend:{fill:function(){return"url(#"+this.id()+")"},update:function(t){return this.clear(),"function"==typeof t&&t.call(this,this),this},toString:function(){return this.fill()},attr:function(t,e,i){return"transform"==t&&(t="patternTransform"),b.Container.prototype.attr.call(this,t,e,i)}},construct:{pattern:function(t,e,i){return this.defs().pattern(t,e,i)}}}),b.extend(b.Defs,{pattern:function(t,e,i){return this.put(new b.Pattern).update(i).attr({x:0,y:0,width:t,height:e,patternUnits:"userSpaceOnUse"})}}),b.Doc=b.invent({create:function(t){t&&(t="string"==typeof t?e.getElementById(t):t,"svg"==t.nodeName?this.constructor.call(this,t):(this.constructor.call(this,b.create("svg")),t.appendChild(this.node),this.size("100%","100%")),this.namespace().defs())},inherit:b.Container,extend:{namespace:function(){return this.attr({xmlns:b.ns,version:"1.1"}).attr("xmlns:xlink",b.xlink,b.xmlns).attr("xmlns:svgjs",b.svgjs,b.xmlns)},defs:function(){if(!this._defs){var t;(t=this.node.getElementsByTagName("defs")[0])?this._defs=b.adopt(t):this._defs=new b.Defs,this.node.appendChild(this._defs.node)}return this._defs},parent:function(){return"#document"==this.node.parentNode.nodeName?null:this.node.parentNode},remove:function(){return this.parent()&&this.parent().removeChild(this.node),this},clear:function(){for(;this.node.hasChildNodes();)this.node.removeChild(this.node.lastChild);return delete this._defs,b.parser.draw.parentNode||this.node.appendChild(b.parser.draw),this}}}),b.Shape=b.invent({create:function(t){this.constructor.call(this,t)},inherit:b.Element}),b.Bare=b.invent({create:function(t,e){if(this.constructor.call(this,b.create(t)),e)for(var i in e.prototype)"function"==typeof e.prototype[i]&&(this[i]=e.prototype[i])},inherit:b.Element,extend:{words:function(t){for(;this.node.hasChildNodes();)this.node.removeChild(this.node.lastChild);return this.node.appendChild(e.createTextNode(t)),this}}}),b.extend(b.Parent,{element:function(t,e){return this.put(new b.Bare(t,e))}}),b.Symbol=b.invent({create:"symbol",inherit:b.Container,construct:{symbol:function(){return this.put(new b.Symbol)}}}),b.Use=b.invent({create:"use",inherit:b.Shape,extend:{element:function(t,e){return this.attr("href",(e||"")+"#"+t,b.xlink)}},construct:{use:function(t,e){return this.put(new b.Use).element(t,e)}}}),b.Rect=b.invent({create:"rect",inherit:b.Shape,construct:{rect:function(t,e){return this.put(new b.Rect).size(t,e)}}}),b.Circle=b.invent({create:"circle",inherit:b.Shape,construct:{circle:function(t){return this.put(new b.Circle).rx(new b.Number(t).divide(2)).move(0,0)}}}),b.extend([b.Circle,b.FX],{rx:function(t){return this.attr("r",t)},ry:function(t){return this.rx(t)}}),b.Ellipse=b.invent({create:"ellipse",inherit:b.Shape,construct:{ellipse:function(t,e){return this.put(new b.Ellipse).size(t,e).move(0,0)}}}),b.extend([b.Ellipse,b.Rect,b.FX],{rx:function(t){return this.attr("rx",t)},ry:function(t){return this.attr("ry",t)}}),b.extend([b.Circle,b.Ellipse],{x:function(t){return null==t?this.cx()-this.rx():this.cx(t+this.rx())},y:function(t){return null==t?this.cy()-this.ry():this.cy(t+this.ry())},cx:function(t){return null==t?this.attr("cx"):this.attr("cx",t)},cy:function(t){return null==t?this.attr("cy"):this.attr("cy",t)},width:function(t){return null==t?2*this.rx():this.rx(new b.Number(t).divide(2))},height:function(t){return null==t?2*this.ry():this.ry(new b.Number(t).divide(2))},size:function(t,e){var i=f(this,t,e);return this.rx(new b.Number(i.width).divide(2)).ry(new b.Number(i.height).divide(2))}}),b.Line=b.invent({create:"line",inherit:b.Shape,extend:{array:function(){return new b.PointArray([[this.attr("x1"),this.attr("y1")],[this.attr("x2"),this.attr("y2")]])},plot:function(t,e,i,n){return null==t?this.array():(t=void 0!==e?{x1:t,y1:e,x2:i,y2:n}:new b.PointArray(t).toLine(),this.attr(t))},move:function(t,e){return this.attr(this.array().move(t,e).toLine())},size:function(t,e){var i=f(this,t,e);return this.attr(this.array().size(i.width,i.height).toLine())}},construct:{line:function(t,e,i,n){return b.Line.prototype.plot.apply(this.put(new b.Line),null!=t?[t,e,i,n]:[0,0,0,0])}}}),b.Polyline=b.invent({create:"polyline",inherit:b.Shape,construct:{polyline:function(t){return this.put(new b.Polyline).plot(t||new b.PointArray)}}}),b.Polygon=b.invent({create:"polygon",inherit:b.Shape,construct:{polygon:function(t){return this.put(new b.Polygon).plot(t||new b.PointArray)}}}),b.extend([b.Polyline,b.Polygon],{array:function(){return this._array||(this._array=new b.PointArray(this.attr("points")))},plot:function(t){return null==t?this.array():this.clear().attr("points","string"==typeof t?t:this._array=new b.PointArray(t))},clear:function(){return delete this._array,this},move:function(t,e){return this.attr("points",this.array().move(t,e))},size:function(t,e){var i=f(this,t,e);return this.attr("points",this.array().size(i.width,i.height))}}),b.extend([b.Line,b.Polyline,b.Polygon],{morphArray:b.PointArray,x:function(t){return null==t?this.bbox().x:this.move(t,this.bbox().y)},y:function(t){return null==t?this.bbox().y:this.move(this.bbox().x,t)},width:function(t){var e=this.bbox();return null==t?e.width:this.size(t,e.height)},height:function(t){var e=this.bbox();return null==t?e.height:this.size(e.width,t)}}),b.Path=b.invent({create:"path",inherit:b.Shape,extend:{morphArray:b.PathArray,array:function(){return this._array||(this._array=new b.PathArray(this.attr("d")))},plot:function(t){return null==t?this.array():this.clear().attr("d","string"==typeof t?t:this._array=new b.PathArray(t))},clear:function(){return delete this._array,this},move:function(t,e){return this.attr("d",this.array().move(t,e))},x:function(t){return null==t?this.bbox().x:this.move(t,this.bbox().y)},y:function(t){return null==t?this.bbox().y:this.move(this.bbox().x,t)},size:function(t,e){var i=f(this,t,e);return this.attr("d",this.array().size(i.width,i.height))},width:function(t){return null==t?this.bbox().width:this.size(t,this.bbox().height)},height:function(t){return null==t?this.bbox().height:this.size(this.bbox().width,t)}},construct:{path:function(t){return this.put(new b.Path).plot(t||new b.PathArray)}}}),b.Image=b.invent({create:"image",inherit:b.Shape,extend:{load:function(e,i){if(!e)return this;var n=new t.Image;return b.on(n,"load",function(t){var r=this.parent();0==this.width()&&0==this.height()&&this.size(n.width,n.height),r instanceof b.Pattern&&0==r.width()&&0==r.height()&&r.size(this.width(),this.height()),"function"==typeof i&&i.call(this,{width:n.width,height:n.height,ratio:n.width/n.height,url:e})},this),this.attr("href",n.src=e,b.xlink)}},construct:{image:function(t,e){return this.put(new b.Image).size(0,0).load(t,e)}}}),b.Text=b.invent({create:function(){this.constructor.call(this,b.create("text")),this.dom.leading=new b.Number(1.3),this._rebuild=!0,this._build=!1,this.attr("font-family",b.defaults.attrs["font-family"])},inherit:b.Parent,extend:{x:function(t){return null==t?this.attr("x"):this.attr("x",t)},y:function(t){var e=this.attr("y"),i="number"==typeof e?e-this.bbox().y:0;return null==t?"number"==typeof e?e-i:e:this.attr("y","number"==typeof t?t+i:t)},cx:function(t){return null==t?this.bbox().cx:this.x(t-this.bbox().width/2)},cy:function(t){return null==t?this.bbox().cy:this.y(t-this.bbox().height/2)},text:function(t){if(void 0===t){for(var t="",e=this.node.childNodes,i=0,n=e.length;i<n;++i)0!=i&&3!=e[i].nodeType&&1==b.adopt(e[i]).dom.newLined&&(t+="\n"),t+=e[i].textContent;return t}if(this.clear().build(!0),"function"==typeof t)t.call(this,this);else{t=t.split("\n");for(var i=0,r=t.length;i<r;i++)this.tspan(t[i]).newLine()}return this.build(!1).rebuild()},size:function(t){return this.attr("font-size",t).rebuild()},leading:function(t){return null==t?this.dom.leading:(this.dom.leading=new b.Number(t),this.rebuild())},rebuild:function(t){if("boolean"==typeof t&&(this._rebuild=t),this._rebuild){var e=this,i=0,n=this.dom.leading*new b.Number(this.attr("font-size"));this.each(function(){this.dom.newLined&&(e.textPath()||this.attr("x",e.attr("x")),"\n"==this.text()?i+=n:(this.attr("dy",n+i),i=0))}),this.fire("rebuild")}return this},build:function(t){return this._build=!!t,this},setData:function(t){return this.dom=t,this.dom.leading=new b.Number(t.leading||1.3),this}},construct:{text:function(t){return this.put(new b.Text).text(t)},plain:function(t){return this.put(new b.Text).plain(t)}}}),b.Tspan=b.invent({create:"tspan",inherit:b.Parent,extend:{text:function(t){return null==t?this.node.textContent+(this.dom.newLined?"\n":""):("function"==typeof t?t.call(this,this):this.plain(t),this)},dx:function(t){return this.attr("dx",t)},dy:function(t){return this.attr("dy",t)},newLine:function(){var t=this.parent(b.Text);return this.dom.newLined=!0,this.dy(t.dom.leading*t.attr("font-size")).attr("x",t.x())}}}),b.extend([b.Text,b.Tspan],{plain:function(t){return!1===this._build&&this.clear(),this.node.appendChild(e.createTextNode(t)),this},tspan:function(t){var e=(this.textPath&&this.textPath()||this).node,i=new b.Tspan;return!1===this._build&&this.clear(),e.appendChild(i.node),i.text(t)},length:function(){return this.node.getComputedTextLength()}}),b.TextPath=b.invent({create:"textPath",inherit:b.Parent,parent:b.Text,construct:{morphArray:b.PathArray,path:function(t){for(var e=new b.TextPath,i=this.doc().defs().path(t);this.node.hasChildNodes();)e.node.appendChild(this.node.firstChild);return this.node.appendChild(e.node),e.attr("href","#"+i,b.xlink),this},array:function(){var t=this.track();return t?t.array():null},plot:function(t){var e=this.track(),i=null;return e&&(i=e.plot(t)),null==t?i:this},track:function(){var t=this.textPath();if(t)return t.reference("href")},textPath:function(){if(this.node.firstChild&&"textPath"==this.node.firstChild.nodeName)return b.adopt(this.node.firstChild)}}}),b.Nested=b.invent({create:function(){this.constructor.call(this,b.create("svg")),this.css("overflow","visible")},inherit:b.Container,construct:{nested:function(){return this.put(new b.Nested)}}}),b.A=b.invent({create:"a",inherit:b.Container,extend:{to:function(t){return this.attr("href",t,b.xlink)},show:function(t){return this.attr("show",t,b.xlink)},target:function(t){return this.attr("target",t)}},construct:{link:function(t){return this.put(new b.A).to(t)}}}),b.extend(b.Element,{linkTo:function(t){var e=new b.A;return"function"==typeof t?t.call(e,e):e.to(t),this.parent().put(e).put(this)}}),b.Marker=b.invent({create:"marker",inherit:b.Container,extend:{width:function(t){return this.attr("markerWidth",t)},height:function(t){return this.attr("markerHeight",t)},ref:function(t,e){return this.attr("refX",t).attr("refY",e)},update:function(t){return this.clear(),"function"==typeof t&&t.call(this,this),this},toString:function(){return"url(#"+this.id()+")"}},construct:{marker:function(t,e,i){return this.defs().marker(t,e,i)}}}),b.extend(b.Defs,{marker:function(t,e,i){return this.put(new b.Marker).size(t,e).ref(t/2,e/2).viewbox(0,0,t,e).attr("orient","auto").update(i)}}),b.extend([b.Line,b.Polyline,b.Polygon,b.Path],{marker:function(t,e,i,n){var r=["marker"];return"all"!=t&&r.push(t),r=r.join("-"),t=arguments[1]instanceof b.Marker?arguments[1]:this.doc().marker(e,i,n),this.attr(r,t)}});var A={stroke:["color","width","opacity","linecap","linejoin","miterlimit","dasharray","dashoffset"],fill:["color","opacity","rule"],prefix:function(t,e){return"color"==e?t:t+"-"+e}};["fill","stroke"].forEach(function(t){var e,i={};i[t]=function(i){if(void 0===i)return this;if("string"==typeof i||b.Color.isRgb(i)||i&&"function"==typeof i.fill)this.attr(t,i);else for(e=A[t].length-1;e>=0;e--)null!=i[A[t][e]]&&this.attr(A.prefix(t,A[t][e]),i[A[t][e]]);return this},b.extend([b.Element,b.FX],i)}),b.extend([b.Element,b.FX],{rotate:function(t,e,i){return this.transform({rotation:t,cx:e,cy:i})},skew:function(t,e,i,n){return 1==arguments.length||3==arguments.length?this.transform({skew:t,cx:e,cy:i}):this.transform({skewX:t,skewY:e,cx:i,cy:n})},scale:function(t,e,i,n){return 1==arguments.length||3==arguments.length?this.transform({scale:t,cx:e,cy:i}):this.transform({scaleX:t,scaleY:e,cx:i,cy:n})},translate:function(t,e){return this.transform({x:t,y:e})},flip:function(t,e){return e="number"==typeof t?t:e,this.transform({flip:t||"both",offset:e})},matrix:function(t){return this.attr("transform",new b.Matrix(6==arguments.length?[].slice.call(arguments):t))},opacity:function(t){return this.attr("opacity",t)},dx:function(t){return this.x(new b.Number(t).plus(this instanceof b.FX?0:this.x()),!0)},dy:function(t){return this.y(new b.Number(t).plus(this instanceof b.FX?0:this.y()),!0)},dmove:function(t,e){return this.dx(t).dy(e)}}),b.extend([b.Rect,b.Ellipse,b.Circle,b.Gradient,b.FX],{radius:function(t,e){var i=(this._target||this).type;return"radialGradient"==i||"radialGradient"==i?this.attr("r",new b.Number(t)):this.rx(t).ry(null==e?t:e)}}),b.extend(b.Path,{length:function(){return this.node.getTotalLength()},pointAt:function(t){return new b.Point(this.node.getPointAtLength(t))}}),b.extend([b.Parent,b.Text,b.Tspan,b.FX],{font:function(t,e){if("object"==typeof t)for(e in t)this.font(e,t[e]);return"leading"==t?this.leading(e):"anchor"==t?this.attr("text-anchor",e):"size"==t||"family"==t||"weight"==t||"stretch"==t||"variant"==t||"style"==t?this.attr("font-"+t,e):this.attr(t,e)}}),b.extend(b.Element,{data:function(t,e,i){if("object"==typeof t)for(e in t)this.data(e,t[e]);else if(arguments.length<2)try{return JSON.parse(this.attr("data-"+t))}catch(e){return this.attr("data-"+t)}else this.attr("data-"+t,null===e?null:!0===i||"string"==typeof e||"number"==typeof e?e:JSON.stringify(e));return this}}),b.extend(b.Element,{remember:function(t,e){if("object"==typeof arguments[0])for(var e in t)this.remember(e,t[e]);else{if(1==arguments.length)return this.memory()[t];this.memory()[t]=e}return this},forget:function(){if(0==arguments.length)this._memory={};else for(var t=arguments.length-1;t>=0;t--)delete this.memory()[arguments[t]];return this},memory:function(){return this._memory||(this._memory={})}}),b.get=function(t){var i=e.getElementById(w(t)||t);return b.adopt(i)},b.select=function(t,i){return b.utils.map((i||e).querySelectorAll(t),function(t){return b.adopt(t)})},b.$$=function(t,i){return b.utils.map((i||e).querySelectorAll(t),function(t){return b.adopt(t)})},b.$=function(t,i){return b.adopt((i||e).querySelector(t))},b.extend(b.Parent,{select:function(t){return b.select(t,this.node)}});var k="abcdef".split("");return b.Box=b.invent({create:function(t){var e=[0,0,0,0];t="string"==typeof t?t.split(b.regex.delimiter).map(parseFloat):Array.isArray(t)?t:"object"==typeof t?[null!=t.left?t.left:t.x,null!=t.top?t.top:t.y,t.width,t.height]:4==arguments.length?[].slice.call(arguments):e,this.x=t[0],this.y=t[1],this.width=t[2],this.height=t[3],g(this)},extend:{merge:function(t){var e=Math.min(this.x,t.x),i=Math.min(this.y,t.y);return new b.Box(e,i,Math.max(this.x+this.width,t.x+t.width)-e,Math.max(this.y+this.height,t.y+t.height)-i)},transform:function(t){var e=1/0,i=-1/0,n=1/0,r=-1/0;return[new b.Point(this.x,this.y),new b.Point(this.x2,this.y),new b.Point(this.x,this.y2),new b.Point(this.x2,this.y2)].forEach(function(s){s=s.transform(t),e=Math.min(e,s.x),i=Math.max(i,s.x),n=Math.min(n,s.y),r=Math.max(r,s.y)}),new b.Box(e,n,i-e,r-n)},addOffset:function(){return this.x+=t.pageXOffset,this.y+=t.pageYOffset,this},toString:function(){return this.x+" "+this.y+" "+this.width+" "+this.height},morph:function(t,e,i,n){return this.destination=new b.Box(t,e,i,n),this},at:function(t){return this.destination?new b.Box(this.x+(this.destination.x-this.x)*t,this.y+(this.destination.y-this.y)*t,this.width+(this.destination.width-this.width)*t,this.height+(this.destination.height-this.height)*t):this}},parent:b.Element,construct:{bbox:function(){var t;try{if(t=this.node.getBBox(),i(t)&&!n(this.node))throw new Exception("Element not in the dom")}catch(i){try{var e=this.clone(b.parser.draw.instance).show();t=e.node.getBBox(),e.remove()}catch(t){console.warn("Getting a bounding box of this element is not possible")}}return new b.Box(t)},rbox:function(t){try{var e=new b.Box(this.node.getBoundingClientRect());return t?e.transform(t.screenCTM().inverse()):e.addOffset()}catch(t){return new b.Box}}}}),b.extend([b.Doc,b.Nested,b.Symbol,b.Image,b.Pattern,b.Marker,b.ForeignObject,b.View],{viewbox:function(t,e,i,n){return null==t?new b.Box(this.attr("viewBox")):this.attr("viewBox",new b.Box(t,e,i,n))}}),b}); \ No newline at end of file
diff --git a/spec/SpecRunner.html b/spec/SpecRunner.html
index 0da16b0..7461bdd 100644
--- a/spec/SpecRunner.html
+++ b/spec/SpecRunner.html
@@ -2,23 +2,16 @@
<html>
<head>
<meta charset="utf-8">
- <title>Jasmine Spec Runner v2.5.2</title>
+ <title>SVG.js - Jasmine Spec Runner v2.6.0</title>
- <link rel="shortcut icon" type="image/png" href="lib/jasmine-2.5.2/jasmine_favicon.png">
- <link rel="stylesheet" href="lib/jasmine-2.5.2/jasmine.css">
+ <link rel="shortcut icon" type="image/png" href="lib/jasmine-2.6.0/jasmine_favicon.png">
+ <link rel="stylesheet" href="lib/jasmine-2.6.0/jasmine.css">
- <script src="lib/jasmine-2.5.2/jasmine.js"></script>
- <script src="lib/jasmine-2.5.2/jasmine-html.js"></script>
- <script src="lib/jasmine-2.5.2/boot.js"></script>
+ <script src="lib/jasmine-2.6.0/jasmine.js"></script>
+ <script src="lib/jasmine-2.6.0/jasmine-html.js"></script>
+ <script src="lib/jasmine-2.6.0/boot.js"></script>
- <style type="text/css" media="screen">
- #drawing {
- width: 500px;
- height: 500px;
- position: fixed;
- z-index: -1;
- }
- </style>
+ <link rel="stylesheet" href="fixtures/fixture.css">
<!-- include source files here... -->
<script src="../dist/svg.js" charset="utf-8"></script>
@@ -26,6 +19,7 @@
</head>
<body>
+
<svg height="0" width="0" id="inlineSVG">
<defs>
<linearGradient>
@@ -54,9 +48,9 @@
</g>
<polygon points="200,10 250,190 160,210" />
<polyline points="20,20 40,25 60,40 80,120 120,140 200,180" />
-
</svg>
+
<!-- include spec files here... -->
<script src="spec/adopter.js"></script>
<script src="spec/arrange.js"></script>
diff --git a/spec/fixture.svg b/spec/fixture.svg
deleted file mode 100644
index f910dc1..0000000
--- a/spec/fixture.svg
+++ /dev/null
@@ -1,29 +0,0 @@
-<svg height="0" width="0" id="inlineSVG">
- <defs>
- <linearGradient>
- <stop offset="5%" stop-color="green"/>
- <stop offset="95%" stop-color="gold"/>
- </linearGradient>
- <radialGradient>
- <stop offset="10%" stop-color="gold"/>
- <stop offset="95%" stop-color="green"/>
- </radialGradient>
- </defs>
- <desc>Some description</desc>
- <path id="lineAB" d="M 100 350 l 150 -300" stroke="red" stroke-width="3" fill="none" />
- <path id="lineBC" d="M 250 50 l 150 300" stroke="red" stroke-width="3" fill="none" />
- <path d="M 175 200 l 150 0" stroke="green" stroke-width="3" fill="none" />
- <path d="M 100 350 q 150 -300 300 0" stroke="blue" stroke-width="5" fill="none" />
- <g stroke="black" stroke-width="3" fill="black" id="pointGroup">
- <circle id="pointA" cx="100" cy="350" r="3" />
- <circle id="pointB" cx="250" cy="50" r="3" />
- <circle id="pointC" cx="400" cy="350" r="3" />
- </g>
- <g font-size="30" font="sans-serif" fill="black" stroke="none" text-anchor="middle" id="labelGroup">
- <text x="100" y="350" dx="-30">A</text>
- <text x="250" y="50" dy="-10">B</text>
- <text x="400" y="350" dx="30">C</text>
- </g>
- <polygon points="200,10 250,190 160,210" />
- <polyline points="20,20 40,25 60,40 80,120 120,140 200,180" />
-</svg> \ No newline at end of file
diff --git a/spec/fixture.css b/spec/fixtures/fixture.css
index e72e421..e72e421 100644
--- a/spec/fixture.css
+++ b/spec/fixtures/fixture.css
diff --git a/spec/fixtures/fixture.svg b/spec/fixtures/fixture.svg
new file mode 100644
index 0000000..5154267
--- /dev/null
+++ b/spec/fixtures/fixture.svg
@@ -0,0 +1,29 @@
+<svg height="0" width="0" id="inlineSVG">
+ <defs>
+ <linearGradient>
+ <stop offset="5%" stop-color="green"/>
+ <stop offset="95%" stop-color="gold"/>
+ </linearGradient>
+ <radialGradient>
+ <stop offset="10%" stop-color="gold"/>
+ <stop offset="95%" stop-color="green"/>
+ </radialGradient>
+ </defs>
+ <desc>Some description</desc>
+ <path id="lineAB" d="M 100 350 l 150 -300" stroke="red" stroke-width="3" fill="none" />
+ <path id="lineBC" d="M 250 50 l 150 300" stroke="red" stroke-width="3" fill="none" />
+ <path d="M 175 200 l 150 0" stroke="green" stroke-width="3" fill="none" />
+ <path d="M 100 350 q 150 -300 300 0" stroke="blue" stroke-width="5" fill="none" />
+ <g stroke="black" stroke-width="3" fill="black" id="pointGroup">
+ <circle id="pointA" cx="100" cy="350" r="3" />
+ <circle id="pointB" cx="250" cy="50" r="3" />
+ <circle id="pointC" cx="400" cy="350" r="3" />
+ </g>
+ <g font-size="30" font="sans-serif" fill="black" stroke="none" text-anchor="middle" id="labelGroup">
+ <text x="100" y="350" dx="-30">A</text>
+ <text x="250" y="50" dy="-10">B</text>
+ <text x="400" y="350" dx="30">C</text>
+ </g>
+ <polygon points="200,10 250,190 160,210" />
+ <polyline points="20,20 40,25 60,40 80,120 120,140 200,180" />
+</svg>
diff --git a/spec/lib/jasmine-2.5.2/boot.js b/spec/lib/jasmine-2.6.0/boot.js
index a99774d..d9b5a80 100644
--- a/spec/lib/jasmine-2.5.2/boot.js
+++ b/spec/lib/jasmine-2.6.0/boot.js
@@ -49,6 +49,8 @@
getWindowLocation: function() { return window.location; }
});
+ var filterSpecs = !!queryString.getParam("spec");
+
var catchingExceptions = queryString.getParam("catch");
env.catchExceptions(typeof catchingExceptions === "undefined" ? true : catchingExceptions);
@@ -76,7 +78,8 @@
getContainer: function() { return document.body; },
createElement: function() { return document.createElement.apply(document, arguments); },
createTextNode: function() { return document.createTextNode.apply(document, arguments); },
- timer: new jasmine.Timer()
+ timer: new jasmine.Timer(),
+ filterSpecs: filterSpecs
});
/**
diff --git a/spec/lib/jasmine-2.5.2/console.js b/spec/lib/jasmine-2.6.0/console.js
index cbc4f93..38ad952 100644
--- a/spec/lib/jasmine-2.5.2/console.js
+++ b/spec/lib/jasmine-2.6.0/console.js
@@ -1,5 +1,5 @@
/*
-Copyright (c) 2008-2016 Pivotal Labs
+Copyright (c) 2008-2017 Pivotal Labs
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
diff --git a/spec/lib/jasmine-2.5.2/jasmine-html.js b/spec/lib/jasmine-2.6.0/jasmine-html.js
index 233c982..90407cc 100644
--- a/spec/lib/jasmine-2.5.2/jasmine-html.js
+++ b/spec/lib/jasmine-2.6.0/jasmine-html.js
@@ -1,5 +1,5 @@
/*
-Copyright (c) 2008-2016 Pivotal Labs
+Copyright (c) 2008-2017 Pivotal Labs
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
@@ -43,6 +43,7 @@ jasmineRequire.HtmlReporter = function(j$) {
onThrowExpectationsClick = options.onThrowExpectationsClick || function() {},
onRandomClick = options.onRandomClick || function() {},
addToExistingQueryString = options.addToExistingQueryString || defaultQueryString,
+ filterSpecs = options.filterSpecs,
timer = options.timer || noopTimer,
results = [],
specsExecuted = 0,
@@ -263,6 +264,9 @@ jasmineRequire.HtmlReporter = function(j$) {
var specListNode;
for (var i = 0; i < resultsTree.children.length; i++) {
var resultNode = resultsTree.children[i];
+ if (filterSpecs && !hasActiveSpec(resultNode)) {
+ continue;
+ }
if (resultNode.type == 'suite') {
var suiteListNode = createDom('ul', {className: 'jasmine-suite', id: 'suite-' + resultNode.result.id},
createDom('li', {className: 'jasmine-suite-detail'},
@@ -390,6 +394,20 @@ jasmineRequire.HtmlReporter = function(j$) {
return (result.failedExpectations.length + result.passedExpectations.length) === 0 &&
result.status === 'passed';
}
+
+ function hasActiveSpec(resultNode) {
+ if (resultNode.type == 'spec' && resultNode.result.status != 'disabled') {
+ return true;
+ }
+
+ if (resultNode.type == 'suite') {
+ for (var i = 0, j = resultNode.children.length; i < j; i++) {
+ if (hasActiveSpec(resultNode.children[i])) {
+ return true;
+ }
+ }
+ }
+ }
}
return HtmlReporter;
diff --git a/spec/lib/jasmine-2.5.2/jasmine.css b/spec/lib/jasmine-2.6.0/jasmine.css
index 6319982..6319982 100644
--- a/spec/lib/jasmine-2.5.2/jasmine.css
+++ b/spec/lib/jasmine-2.6.0/jasmine.css
diff --git a/spec/lib/jasmine-2.5.2/jasmine.js b/spec/lib/jasmine-2.6.0/jasmine.js
index 7cab7e0..57b5afe 100644
--- a/spec/lib/jasmine-2.5.2/jasmine.js
+++ b/spec/lib/jasmine-2.6.0/jasmine.js
@@ -1,5 +1,5 @@
/*
-Copyright (c) 2008-2016 Pivotal Labs
+Copyright (c) 2008-2017 Pivotal Labs
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
@@ -52,6 +52,7 @@ var getJasmineRequireObj = (function (jasmineGlobal) {
j$.Anything = jRequire.Anything(j$);
j$.CallTracker = jRequire.CallTracker(j$);
j$.MockDate = jRequire.MockDate();
+ j$.getClearStack = jRequire.clearStack(j$);
j$.Clock = jRequire.Clock();
j$.DelayedFunctionScheduler = jRequire.DelayedFunctionScheduler();
j$.Env = jRequire.Env(j$);
@@ -66,6 +67,7 @@ var getJasmineRequireObj = (function (jasmineGlobal) {
j$.QueueRunner = jRequire.QueueRunner(j$);
j$.ReportDispatcher = jRequire.ReportDispatcher();
j$.Spec = jRequire.Spec(j$);
+ j$.Spy = jRequire.Spy(j$);
j$.SpyRegistry = jRequire.SpyRegistry(j$);
j$.SpyStrategy = jRequire.SpyStrategy(j$);
j$.StringMatching = jRequire.StringMatching(j$);
@@ -74,6 +76,10 @@ var getJasmineRequireObj = (function (jasmineGlobal) {
j$.TreeProcessor = jRequire.TreeProcessor();
j$.version = jRequire.version();
j$.Order = jRequire.Order();
+ j$.DiffBuilder = jRequire.DiffBuilder(j$);
+ j$.NullDiffBuilder = jRequire.NullDiffBuilder(j$);
+ j$.ObjectPath = jRequire.ObjectPath(j$);
+ j$.GlobalErrors = jRequire.GlobalErrors(j$);
j$.matchers = jRequire.requireMatchers(jRequire, j$);
@@ -91,17 +97,20 @@ getJasmineRequireObj().requireMatchers = function(jRequire, j$) {
'toBeFalsy',
'toBeGreaterThan',
'toBeGreaterThanOrEqual',
- 'toBeLessThanOrEqual',
'toBeLessThan',
+ 'toBeLessThanOrEqual',
'toBeNaN',
+ 'toBeNegativeInfinity',
'toBeNull',
+ 'toBePositiveInfinity',
'toBeTruthy',
'toBeUndefined',
'toContain',
'toEqual',
'toHaveBeenCalled',
- 'toHaveBeenCalledWith',
+ 'toHaveBeenCalledBefore',
'toHaveBeenCalledTimes',
+ 'toHaveBeenCalledWith',
'toMatch',
'toThrow',
'toThrowError'
@@ -121,14 +130,35 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
throw new Error('unimplemented method');
};
+ /**
+ * Maximum object depth the pretty printer will print to.
+ * Set this to a lower value to speed up pretty printing if you have large objects.
+ * @name jasmine.MAX_PRETTY_PRINT_DEPTH
+ */
j$.MAX_PRETTY_PRINT_DEPTH = 40;
+ /**
+ * Maximum number of array elements to display when pretty printing objects.
+ * Elements past this number will be ellipised.
+ * @name jasmine.MAX_PRETTY_PRINT_ARRAY_LENGTH
+ */
j$.MAX_PRETTY_PRINT_ARRAY_LENGTH = 100;
+ /**
+ * Default number of milliseconds Jasmine will wait for an asynchronous spec to complete.
+ * @name jasmine.DEFAULT_TIMEOUT_INTERVAL
+ */
j$.DEFAULT_TIMEOUT_INTERVAL = 5000;
j$.getGlobal = function() {
return jasmineGlobal;
};
+ /**
+ * Get the currently booted Jasmine Environment.
+ *
+ * @name jasmine.getEnv
+ * @function
+ * @return {Env}
+ */
j$.getEnv = function(options) {
var env = j$.currentEnv_ = j$.currentEnv_ || new j$.Env(options);
//jasmine. singletons in here (setTimeout blah blah).
@@ -139,6 +169,10 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
return j$.isA_('Array', value);
};
+ j$.isObject_ = function(value) {
+ return !j$.util.isUndefined(value) && value !== null && j$.isA_('Object', value);
+ };
+
j$.isString_ = function(value) {
return j$.isA_('String', value);
};
@@ -152,7 +186,11 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
};
j$.isA_ = function(typeName, value) {
- return Object.prototype.toString.apply(value) === '[object ' + typeName + ']';
+ return j$.getType_(value) === '[object ' + typeName + ']';
+ };
+
+ j$.getType_ = function(value) {
+ return Object.prototype.toString.apply(value);
};
j$.isDomNode = function(obj) {
@@ -168,59 +206,70 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
return matches ? matches[1] : '<anonymous>';
};
+ /**
+ * Get a matcher, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
+ * that will succeed if the actual value being compared is an instance of the specified class/constructor.
+ * @name jasmine.any
+ * @function
+ * @param {Constructor} clazz - The constructor to check against.
+ */
j$.any = function(clazz) {
return new j$.Any(clazz);
};
+ /**
+ * Get a matcher, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
+ * that will succeed if the actual value being compared is not `null` and not `undefined`.
+ * @name jasmine.anything
+ * @function
+ */
j$.anything = function() {
return new j$.Anything();
};
+ /**
+ * Get a matcher, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
+ * that will succeed if the actual value being compared contains at least the keys and values.
+ * @name jasmine.objectContaining
+ * @function
+ * @param {Object} sample - The subset of properties that _must_ be in the actual.
+ */
j$.objectContaining = function(sample) {
return new j$.ObjectContaining(sample);
};
+ /**
+ * Get a matcher, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
+ * that will succeed if the actual value is a `String` that matches the `RegExp` or `String`.
+ * @name jasmine.stringMatching
+ * @function
+ * @param {RegExp|String} expected
+ */
j$.stringMatching = function(expected) {
return new j$.StringMatching(expected);
};
+ /**
+ * Get a matcher, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
+ * that will succeed if the actual value is an `Array` that contains at least the elements in the sample.
+ * @name jasmine.arrayContaining
+ * @function
+ * @param {Array} sample
+ */
j$.arrayContaining = function(sample) {
return new j$.ArrayContaining(sample);
};
+ /**
+ * Create a bare {@link Spy} object. This won't be installed anywhere and will not have any implementation behind it.
+ * @name jasmine.createSpy
+ * @function
+ * @param {String} [name] - Name to give the spy. This will be displayed in failure messages.
+ * @param {Function} [originalFn] - Function to act as the real implementation.
+ * @return {Spy}
+ */
j$.createSpy = function(name, originalFn) {
-
- var spyStrategy = new j$.SpyStrategy({
- name: name,
- fn: originalFn,
- getSpy: function() { return spy; }
- }),
- callTracker = new j$.CallTracker(),
- spy = function() {
- var callData = {
- object: this,
- args: Array.prototype.slice.apply(arguments)
- };
-
- callTracker.track(callData);
- var returnValue = spyStrategy.exec.apply(this, arguments);
- callData.returnValue = returnValue;
-
- return returnValue;
- };
-
- for (var prop in originalFn) {
- if (prop === 'and' || prop === 'calls') {
- throw new Error('Jasmine spies would overwrite the \'and\' and \'calls\' properties on the object being spied upon');
- }
-
- spy[prop] = originalFn[prop];
- }
-
- spy.and = spyStrategy;
- spy.calls = callTracker;
-
- return spy;
+ return j$.Spy(name, originalFn);
};
j$.isSpy = function(putativeSpy) {
@@ -231,19 +280,44 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
putativeSpy.calls instanceof j$.CallTracker;
};
+ /**
+ * Create an object with multiple {@link Spy}s as its members.
+ * @name jasmine.createSpyObj
+ * @function
+ * @param {String} [baseName] - Base name for the spies in the object.
+ * @param {String[]|Object} methodNames - Array of method names to create spies for, or Object whose keys will be method names and values the {@link Spy#and#returnValue|returnValue}.
+ * @return {Object}
+ */
j$.createSpyObj = function(baseName, methodNames) {
- if (j$.isArray_(baseName) && j$.util.isUndefined(methodNames)) {
+ var baseNameIsCollection = j$.isObject_(baseName) || j$.isArray_(baseName);
+
+ if (baseNameIsCollection && j$.util.isUndefined(methodNames)) {
methodNames = baseName;
baseName = 'unknown';
}
- if (!j$.isArray_(methodNames) || methodNames.length === 0) {
- throw 'createSpyObj requires a non-empty array of method names to create spies for';
- }
var obj = {};
- for (var i = 0; i < methodNames.length; i++) {
- obj[methodNames[i]] = j$.createSpy(baseName + '.' + methodNames[i]);
+ var spiesWereSet = false;
+
+ if (j$.isArray_(methodNames)) {
+ for (var i = 0; i < methodNames.length; i++) {
+ obj[methodNames[i]] = j$.createSpy(baseName + '.' + methodNames[i]);
+ spiesWereSet = true;
+ }
+ } else if (j$.isObject_(methodNames)) {
+ for (var key in methodNames) {
+ if (methodNames.hasOwnProperty(key)) {
+ obj[key] = j$.createSpy(baseName + '.' + key);
+ obj[key].and.returnValue(methodNames[key]);
+ spiesWereSet = true;
+ }
+ }
}
+
+ if (!spiesWereSet) {
+ throw 'createSpyObj requires a non-empty array or object of method names to create spies for';
+ }
+
return obj;
};
};
@@ -305,6 +379,34 @@ getJasmineRequireObj().util = function() {
return cloned;
};
+ util.getPropertyDescriptor = function(obj, methodName) {
+ var descriptor,
+ proto = obj;
+
+ do {
+ descriptor = Object.getOwnPropertyDescriptor(proto, methodName);
+ proto = Object.getPrototypeOf(proto);
+ } while (!descriptor && proto);
+
+ return descriptor;
+ };
+
+ util.objectDifference = function(obj, toRemove) {
+ var diff = {};
+
+ for (var key in obj) {
+ if (util.has(obj, key) && !util.has(toRemove, key)) {
+ diff[key] = obj[key];
+ }
+ }
+
+ return diff;
+ };
+
+ util.has = function(obj, key) {
+ return Object.prototype.hasOwnProperty.call(obj, key);
+ };
+
return util;
};
@@ -513,6 +615,12 @@ getJasmineRequireObj().Order = function() {
};
getJasmineRequireObj().Env = function(j$) {
+ /**
+ * _Note:_ Do not construct this directly, Jasmine will make one during booting.
+ * @name Env
+ * @classdesc The Jasmine environment
+ * @constructor
+ */
function Env(options) {
options = options || {};
@@ -525,6 +633,7 @@ getJasmineRequireObj().Env = function(j$) {
var realSetTimeout = j$.getGlobal().setTimeout;
var realClearTimeout = j$.getGlobal().clearTimeout;
+ var clearStack = j$.getClearStack(j$.getGlobal());
this.clock = new j$.Clock(global, function () { return new j$.DelayedFunctionScheduler(); }, new j$.MockDate(global));
var runnableResources = {};
@@ -553,6 +662,8 @@ getJasmineRequireObj().Env = function(j$) {
'specDone'
]);
+ var globalErrors = new j$.GlobalErrors();
+
this.specFilter = function() {
return true;
};
@@ -668,16 +779,6 @@ getJasmineRequireObj().Env = function(j$) {
var maximumSpecCallbackDepth = 20;
var currentSpecCallbackDepth = 0;
- function clearStack(fn) {
- currentSpecCallbackDepth++;
- if (currentSpecCallbackDepth >= maximumSpecCallbackDepth) {
- currentSpecCallbackDepth = 0;
- realSetTimeout(fn, 0);
- } else {
- fn();
- }
- }
-
var catchException = function(e) {
return j$.Spec.isPendingSpecException(e) || catchExceptions;
};
@@ -710,6 +811,7 @@ getJasmineRequireObj().Env = function(j$) {
options.clearStack = options.clearStack || clearStack;
options.timeout = {setTimeout: realSetTimeout, clearTimeout: realClearTimeout};
options.fail = self.fail;
+ options.globalErrors = globalErrors;
new j$.QueueRunner(options).execute();
};
@@ -752,7 +854,7 @@ getJasmineRequireObj().Env = function(j$) {
reporter.suiteStarted(suite.result);
},
nodeComplete: function(suite, result) {
- if (!suite.disabled) {
+ if (!suite.markedPending) {
clearResourcesForRunnable(suite.id);
}
currentlyExecutingSuites.pop();
@@ -773,9 +875,11 @@ getJasmineRequireObj().Env = function(j$) {
currentlyExecutingSuites.push(topSuite);
+ globalErrors.install();
processor.execute(function() {
clearResourcesForRunnable(topSuite.id);
currentlyExecutingSuites.pop();
+ globalErrors.uninstall();
reporter.jasmineDone({
order: order,
@@ -784,6 +888,12 @@ getJasmineRequireObj().Env = function(j$) {
});
};
+ /**
+ * Add a custom reporter to the Jasmine environment.
+ * @name Env#addReporter
+ * @function
+ * @see custom_reporter
+ */
this.addReporter = function(reporterToAdd) {
reporter.addReporter(reporterToAdd);
};
@@ -811,6 +921,16 @@ getJasmineRequireObj().Env = function(j$) {
return spyRegistry.spyOn.apply(spyRegistry, arguments);
};
+ this.spyOnProperty = function() {
+ return spyRegistry.spyOnProperty.apply(spyRegistry, arguments);
+ };
+
+ var ensureIsFunction = function(fn, caller) {
+ if (!j$.isFunction_(fn)) {
+ throw new Error(caller + ' expects a function argument; received ' + j$.getType_(fn));
+ }
+ };
+
var suiteFactory = function(description) {
var suite = new j$.Suite({
env: self,
@@ -826,6 +946,7 @@ getJasmineRequireObj().Env = function(j$) {
};
this.describe = function(description, specDefinitions) {
+ ensureIsFunction(specDefinitions, 'describe');
var suite = suiteFactory(description);
if (specDefinitions.length > 0) {
throw new Error('describe does not expect any arguments');
@@ -838,6 +959,7 @@ getJasmineRequireObj().Env = function(j$) {
};
this.xdescribe = function(description, specDefinitions) {
+ ensureIsFunction(specDefinitions, 'xdescribe');
var suite = suiteFactory(description);
suite.pend();
addSpecsToSuite(suite, specDefinitions);
@@ -847,6 +969,7 @@ getJasmineRequireObj().Env = function(j$) {
var focusedRunnables = [];
this.fdescribe = function(description, specDefinitions) {
+ ensureIsFunction(specDefinitions, 'fdescribe');
var suite = suiteFactory(description);
suite.isFocused = true;
@@ -943,6 +1066,11 @@ getJasmineRequireObj().Env = function(j$) {
};
this.it = function(description, fn, timeout) {
+ // it() sometimes doesn't have a fn argument, so only check the type if
+ // it's given.
+ if (arguments.length > 1) {
+ ensureIsFunction(fn, 'it');
+ }
var spec = specFactory(description, fn, currentDeclarationSuite, timeout);
if (currentDeclarationSuite.markedPending) {
spec.pend();
@@ -951,13 +1079,19 @@ getJasmineRequireObj().Env = function(j$) {
return spec;
};
- this.xit = function() {
+ this.xit = function(description, fn, timeout) {
+ // xit(), like it(), doesn't always have a fn argument, so only check the
+ // type when needed.
+ if (arguments.length > 1) {
+ ensureIsFunction(fn, 'xit');
+ }
var spec = this.it.apply(this, arguments);
spec.pend('Temporarily disabled with xit');
return spec;
};
this.fit = function(description, fn, timeout){
+ ensureIsFunction(fn, 'fit');
var spec = specFactory(description, fn, currentDeclarationSuite, timeout);
currentDeclarationSuite.addChild(spec);
focusedRunnables.push(spec.id);
@@ -974,6 +1108,7 @@ getJasmineRequireObj().Env = function(j$) {
};
this.beforeEach = function(beforeEachFunction, timeout) {
+ ensureIsFunction(beforeEachFunction, 'beforeEach');
currentDeclarationSuite.beforeEach({
fn: beforeEachFunction,
timeout: function() { return timeout || j$.DEFAULT_TIMEOUT_INTERVAL; }
@@ -981,6 +1116,7 @@ getJasmineRequireObj().Env = function(j$) {
};
this.beforeAll = function(beforeAllFunction, timeout) {
+ ensureIsFunction(beforeAllFunction, 'beforeAll');
currentDeclarationSuite.beforeAll({
fn: beforeAllFunction,
timeout: function() { return timeout || j$.DEFAULT_TIMEOUT_INTERVAL; }
@@ -988,6 +1124,7 @@ getJasmineRequireObj().Env = function(j$) {
};
this.afterEach = function(afterEachFunction, timeout) {
+ ensureIsFunction(afterEachFunction, 'afterEach');
currentDeclarationSuite.afterEach({
fn: afterEachFunction,
timeout: function() { return timeout || j$.DEFAULT_TIMEOUT_INTERVAL; }
@@ -995,6 +1132,7 @@ getJasmineRequireObj().Env = function(j$) {
};
this.afterAll = function(afterAllFunction, timeout) {
+ ensureIsFunction(afterAllFunction, 'afterAll');
currentDeclarationSuite.afterAll({
fn: afterAllFunction,
timeout: function() { return timeout || j$.DEFAULT_TIMEOUT_INTERVAL; }
@@ -1010,10 +1148,21 @@ getJasmineRequireObj().Env = function(j$) {
};
this.fail = function(error) {
+ if (!currentRunnable()) {
+ throw new Error('\'fail\' was used when there was no current spec, this could be because an asynchronous test timed out');
+ }
+
var message = 'Failed';
if (error) {
message += ': ';
- message += error.message || error;
+ if (error.message) {
+ message += error.message;
+ } else if (jasmine.isString_(error)) {
+ message += error;
+ } else {
+ // pretty print all kind of objects. This includes arrays.
+ message += jasmine.pp(error);
+ }
}
currentRunnable().addExpectationResult(false, {
@@ -1037,6 +1186,13 @@ getJasmineRequireObj().JsApiReporter = function() {
elapsed: function(){ return 0; }
};
+ /**
+ * _Note:_ Do not construct this directly, use the global `jsApiReporter` to retrieve the instantiated object.
+ *
+ * @name jsApiReporter
+ * @classdesc Reporter added by default in `boot.js` to record results for retrieval in javascript code.
+ * @class
+ */
function JsApiReporter(options) {
var timer = options.timer || noopTimer,
status = 'loaded';
@@ -1060,6 +1216,12 @@ getJasmineRequireObj().JsApiReporter = function() {
status = 'done';
};
+ /**
+ * Get the current status for the Jasmine environment.
+ * @name jsApiReporter#status
+ * @function
+ * @return {String} - One of `loaded`, `started`, or `done`
+ */
this.status = function() {
return status;
};
@@ -1075,6 +1237,16 @@ getJasmineRequireObj().JsApiReporter = function() {
storeSuite(result);
};
+ /**
+ * Get the results for a set of suites.
+ *
+ * Retrievable in slices for easier serialization.
+ * @name jsApiReporter#suiteResults
+ * @function
+ * @param {Number} index - The position in the suites list to start from.
+ * @param {Number} length - Maximum number of suite results to return.
+ * @return {Object[]}
+ */
this.suiteResults = function(index, length) {
return suites.slice(index, index + length);
};
@@ -1084,6 +1256,12 @@ getJasmineRequireObj().JsApiReporter = function() {
suites_hash[result.id] = result;
}
+ /**
+ * Get all of the suites in a single object, with their `id` as the key.
+ * @name jsApiReporter#suites
+ * @function
+ * @return {Object}
+ */
this.suites = function() {
return suites_hash;
};
@@ -1094,14 +1272,36 @@ getJasmineRequireObj().JsApiReporter = function() {
specs.push(result);
};
+ /**
+ * Get the results for a set of specs.
+ *
+ * Retrievable in slices for easier serialization.
+ * @name jsApiReporter#specResults
+ * @function
+ * @param {Number} index - The position in the specs list to start from.
+ * @param {Number} length - Maximum number of specs results to return.
+ * @return {Object[]}
+ */
this.specResults = function(index, length) {
return specs.slice(index, index + length);
};
+ /**
+ * Get all spec results.
+ * @name jsApiReporter#specs
+ * @function
+ * @return {Object[]}
+ */
this.specs = function() {
return specs;
};
+ /**
+ * Get the number of milliseconds it took for the full Jasmine suite to run.
+ * @name jsApiReporter#executionTime
+ * @function
+ * @return {Number}
+ */
this.executionTime = function() {
return executionTime;
};
@@ -1111,8 +1311,166 @@ getJasmineRequireObj().JsApiReporter = function() {
return JsApiReporter;
};
+getJasmineRequireObj().Any = function(j$) {
+
+ function Any(expectedObject) {
+ if (typeof expectedObject === 'undefined') {
+ throw new TypeError(
+ 'jasmine.any() expects to be passed a constructor function. ' +
+ 'Please pass one or use jasmine.anything() to match any object.'
+ );
+ }
+ this.expectedObject = expectedObject;
+ }
+
+ Any.prototype.asymmetricMatch = function(other) {
+ if (this.expectedObject == String) {
+ return typeof other == 'string' || other instanceof String;
+ }
+
+ if (this.expectedObject == Number) {
+ return typeof other == 'number' || other instanceof Number;
+ }
+
+ if (this.expectedObject == Function) {
+ return typeof other == 'function' || other instanceof Function;
+ }
+
+ if (this.expectedObject == Object) {
+ return typeof other == 'object';
+ }
+
+ if (this.expectedObject == Boolean) {
+ return typeof other == 'boolean';
+ }
+
+ return other instanceof this.expectedObject;
+ };
+
+ Any.prototype.jasmineToString = function() {
+ return '<jasmine.any(' + j$.fnNameFor(this.expectedObject) + ')>';
+ };
+
+ return Any;
+};
+
+getJasmineRequireObj().Anything = function(j$) {
+
+ function Anything() {}
+
+ Anything.prototype.asymmetricMatch = function(other) {
+ return !j$.util.isUndefined(other) && other !== null;
+ };
+
+ Anything.prototype.jasmineToString = function() {
+ return '<jasmine.anything>';
+ };
+
+ return Anything;
+};
+
+getJasmineRequireObj().ArrayContaining = function(j$) {
+ function ArrayContaining(sample) {
+ this.sample = sample;
+ }
+
+ ArrayContaining.prototype.asymmetricMatch = function(other, customTesters) {
+ var className = Object.prototype.toString.call(this.sample);
+ if (className !== '[object Array]') { throw new Error('You must provide an array to arrayContaining, not \'' + this.sample + '\'.'); }
+
+ for (var i = 0; i < this.sample.length; i++) {
+ var item = this.sample[i];
+ if (!j$.matchersUtil.contains(other, item, customTesters)) {
+ return false;
+ }
+ }
+
+ return true;
+ };
+
+ ArrayContaining.prototype.jasmineToString = function () {
+ return '<jasmine.arrayContaining(' + jasmine.pp(this.sample) +')>';
+ };
+
+ return ArrayContaining;
+};
+
+getJasmineRequireObj().ObjectContaining = function(j$) {
+
+ function ObjectContaining(sample) {
+ this.sample = sample;
+ }
+
+ function getPrototype(obj) {
+ if (Object.getPrototypeOf) {
+ return Object.getPrototypeOf(obj);
+ }
+
+ if (obj.constructor.prototype == obj) {
+ return null;
+ }
+
+ return obj.constructor.prototype;
+ }
+
+ function hasProperty(obj, property) {
+ if (!obj) {
+ return false;
+ }
+
+ if (Object.prototype.hasOwnProperty.call(obj, property)) {
+ return true;
+ }
+
+ return hasProperty(getPrototype(obj), property);
+ }
+
+ ObjectContaining.prototype.asymmetricMatch = function(other, customTesters) {
+ if (typeof(this.sample) !== 'object') { throw new Error('You must provide an object to objectContaining, not \''+this.sample+'\'.'); }
+
+ for (var property in this.sample) {
+ if (!hasProperty(other, property) ||
+ !j$.matchersUtil.equals(this.sample[property], other[property], customTesters)) {
+ return false;
+ }
+ }
+
+ return true;
+ };
+
+ ObjectContaining.prototype.jasmineToString = function() {
+ return '<jasmine.objectContaining(' + j$.pp(this.sample) + ')>';
+ };
+
+ return ObjectContaining;
+};
+
+getJasmineRequireObj().StringMatching = function(j$) {
+
+ function StringMatching(expected) {
+ if (!j$.isString_(expected) && !j$.isA_('RegExp', expected)) {
+ throw new Error('Expected is not a String or a RegExp');
+ }
+
+ this.regexp = new RegExp(expected);
+ }
+
+ StringMatching.prototype.asymmetricMatch = function(other) {
+ return this.regexp.test(other);
+ };
+
+ StringMatching.prototype.jasmineToString = function() {
+ return '<jasmine.stringMatching(' + this.regexp + ')>';
+ };
+
+ return StringMatching;
+};
+
getJasmineRequireObj().CallTracker = function(j$) {
+ /**
+ * @namespace Spy#calls
+ */
function CallTracker() {
var calls = [];
var opts = {};
@@ -1137,23 +1495,54 @@ getJasmineRequireObj().CallTracker = function(j$) {
calls.push(context);
};
+ /**
+ * Check whether this spy has been invoked.
+ * @name Spy#calls#any
+ * @function
+ * @return {Boolean}
+ */
this.any = function() {
return !!calls.length;
};
+ /**
+ * Get the number of invocations of this spy.
+ * @name Spy#calls#count
+ * @function
+ * @return {Integer}
+ */
this.count = function() {
return calls.length;
};
+ /**
+ * Get the arguments that were passed to a specific invocation of this spy.
+ * @name Spy#calls#argsFor
+ * @function
+ * @param {Integer} index The 0-based invocation index.
+ * @return {Array}
+ */
this.argsFor = function(index) {
var call = calls[index];
return call ? call.args : [];
};
+ /**
+ * Get the raw calls array for this spy.
+ * @name Spy#calls#all
+ * @function
+ * @return {Spy.callData[]}
+ */
this.all = function() {
return calls;
};
+ /**
+ * Get all of the arguments for each invocation of this spy in the order they were received.
+ * @name Spy#calls#allArgs
+ * @function
+ * @return {Array}
+ */
this.allArgs = function() {
var callArgs = [];
for(var i = 0; i < calls.length; i++){
@@ -1163,18 +1552,40 @@ getJasmineRequireObj().CallTracker = function(j$) {
return callArgs;
};
+ /**
+ * Get the first invocation of this spy.
+ * @name Spy#calls#first
+ * @function
+ * @return {ObjecSpy.callData}
+ */
this.first = function() {
return calls[0];
};
+ /**
+ * Get the most recent invocation of this spy.
+ * @name Spy#calls#mostRecent
+ * @function
+ * @return {ObjecSpy.callData}
+ */
this.mostRecent = function() {
return calls[calls.length - 1];
};
+ /**
+ * Reset this spy as if it has never been called.
+ * @name Spy#calls#reset
+ * @function
+ */
this.reset = function() {
calls = [];
};
+ /**
+ * Set this spy to do a shallow clone of arguments passed to each invocation.
+ * @name Spy#calls#saveArgumentsByValue
+ * @function
+ */
this.saveArgumentsByValue = function() {
opts.cloneArgs = true;
};
@@ -1184,7 +1595,52 @@ getJasmineRequireObj().CallTracker = function(j$) {
return CallTracker;
};
+getJasmineRequireObj().clearStack = function(j$) {
+ function messageChannelImpl(global) {
+ var channel = new global.MessageChannel(),
+ head = {},
+ tail = head;
+
+ channel.port1.onmessage = function() {
+ head = head.next;
+ var task = head.task;
+ delete head.task;
+ task();
+ };
+
+ return function clearStack(fn) {
+ tail = tail.next = { task: fn };
+ channel.port2.postMessage(0);
+ };
+ }
+
+ function getClearStack(global) {
+ if (global && global.process && j$.isFunction_(global.process.nextTick)) {
+ return global.process.nextTick;
+ } else if (j$.isFunction_(global.setImmediate)) {
+ var realSetImmediate = global.setImmediate;
+ return function(fn) {
+ realSetImmediate(fn);
+ };
+ } else if (!j$.util.isUndefined(global.MessageChannel)) {
+ return messageChannelImpl(global);
+ } else {
+ var realSetTimeout = global.setTimeout;
+ return function clearStack(fn) {
+ Function.prototype.apply.apply(realSetTimeout, [global, [fn, 0]]);
+ };
+ }
+ }
+
+ return getClearStack;
+};
+
getJasmineRequireObj().Clock = function() {
+ /**
+ * _Note:_ Do not construct this directly, Jasmine will make one during booting. You can get the current clock with {@link jasmine.clock}.
+ * @class Clock
+ * @classdesc Jasmine's mock clock is used when testing time dependent code.
+ */
function Clock(global, delayedFunctionSchedulerFactory, mockDate) {
var self = this,
realTimingFunctions = {
@@ -1204,6 +1660,12 @@ getJasmineRequireObj().Clock = function() {
timer;
+ /**
+ * Install the mock clock over the built-in methods.
+ * @name Clock#install
+ * @function
+ * @return {Clock}
+ */
self.install = function() {
if(!originalTimingFunctionsIntact()) {
throw new Error('Jasmine Clock was unable to install over custom global timer functions. Is the clock already installed?');
@@ -1216,6 +1678,11 @@ getJasmineRequireObj().Clock = function() {
return self;
};
+ /**
+ * Uninstall the mock clock, returning the built-in methods to their places.
+ * @name Clock#uninstall
+ * @function
+ */
self.uninstall = function() {
delayedFunctionScheduler = null;
mockDate.uninstall();
@@ -1225,6 +1692,14 @@ getJasmineRequireObj().Clock = function() {
installed = false;
};
+ /**
+ * Execute a function with a mocked Clock
+ *
+ * The clock will be {@link Clock#install|install}ed before the function is called and {@link Clock#uninstall|uninstall}ed in a `finally` after the function completes.
+ * @name Clock#withMock
+ * @function
+ * @param {closure} Function The function to be called.
+ */
self.withMock = function(closure) {
this.install();
try {
@@ -1234,6 +1709,12 @@ getJasmineRequireObj().Clock = function() {
}
};
+ /**
+ * Instruct the installed Clock to also mock the date returned by `new Date()`
+ * @name Clock#mockDate
+ * @function
+ * @param {Date} [initialDate=now] The `Date` to provide.
+ */
self.mockDate = function(initialDate) {
mockDate.install(initialDate);
};
@@ -1266,6 +1747,12 @@ getJasmineRequireObj().Clock = function() {
return Function.prototype.call.apply(timer.clearInterval, [global, id]);
};
+ /**
+ * Tick the Clock forward, running any enqueued timeouts along the way
+ * @name Clock#tick
+ * @function
+ * @param {int} millis The number of milliseconds to tick.
+ */
self.tick = function(millis) {
if (installed) {
delayedFunctionScheduler.tick(millis, function(millis) { mockDate.tick(millis); });
@@ -1474,6 +1961,16 @@ getJasmineRequireObj().DelayedFunctionScheduler = function() {
return DelayedFunctionScheduler;
};
+getJasmineRequireObj().errors = function() {
+ function ExpectationFailed() {}
+
+ ExpectationFailed.prototype = new Error();
+ ExpectationFailed.prototype.constructor = ExpectationFailed;
+
+ return {
+ ExpectationFailed: ExpectationFailed
+ };
+};
getJasmineRequireObj().ExceptionFormatter = function() {
function ExceptionFormatter() {
this.message = function(error) {
@@ -1506,6 +2003,10 @@ getJasmineRequireObj().ExceptionFormatter = function() {
getJasmineRequireObj().Expectation = function() {
+ /**
+ * Matchers that come with Jasmine out of the box.
+ * @namespace matchers
+ */
function Expectation(options) {
this.util = options.util || { buildFailureMessage: function() {} };
this.customEqualityTesters = options.customEqualityTesters || [];
@@ -1567,6 +2068,7 @@ getJasmineRequireObj().Expectation = function() {
matcherName: name,
passed: result.pass,
message: message,
+ error: result.error,
actual: this.actual,
expected: expected // TODO: this may need to be arrayified/sliced
}
@@ -1649,6 +2151,1373 @@ getJasmineRequireObj().buildExpectationResult = function() {
return buildExpectationResult;
};
+getJasmineRequireObj().formatErrorMsg = function() {
+ function generateErrorMsg(domain, usage) {
+ var usageDefinition = usage ? '\nUsage: ' + usage : '';
+
+ return function errorMsg(msg) {
+ return domain + ' : ' + msg + usageDefinition;
+ };
+ }
+
+ return generateErrorMsg;
+};
+
+getJasmineRequireObj().GlobalErrors = function(j$) {
+ function GlobalErrors(global) {
+ var handlers = [];
+ global = global || j$.getGlobal();
+
+ var onerror = function onerror() {
+ var handler = handlers[handlers.length - 1];
+ handler.apply(null, Array.prototype.slice.call(arguments, 0));
+ };
+
+ this.uninstall = function noop() {};
+
+ this.install = function install() {
+ if (global.process && j$.isFunction_(global.process.on)) {
+ var originalHandlers = global.process.listeners('uncaughtException');
+ global.process.removeAllListeners('uncaughtException');
+ global.process.on('uncaughtException', onerror);
+
+ this.uninstall = function uninstall() {
+ global.process.removeListener('uncaughtException', onerror);
+ for (var i = 0; i < originalHandlers.length; i++) {
+ global.process.on('uncaughtException', originalHandlers[i]);
+ }
+ };
+ } else {
+ var originalHandler = global.onerror;
+ global.onerror = onerror;
+
+ this.uninstall = function uninstall() {
+ global.onerror = originalHandler;
+ };
+ }
+ };
+
+ this.pushListener = function pushListener(listener) {
+ handlers.push(listener);
+ };
+
+ this.popListener = function popListener() {
+ handlers.pop();
+ };
+ }
+
+ return GlobalErrors;
+};
+
+getJasmineRequireObj().DiffBuilder = function(j$) {
+ return function DiffBuilder() {
+ var path = new j$.ObjectPath(),
+ mismatches = [];
+
+ return {
+ record: function (actual, expected, formatter) {
+ formatter = formatter || defaultFormatter;
+ mismatches.push(formatter(actual, expected, path));
+ },
+
+ getMessage: function () {
+ return mismatches.join('\n');
+ },
+
+ withPath: function (pathComponent, block) {
+ var oldPath = path;
+ path = path.add(pathComponent);
+ block();
+ path = oldPath;
+ }
+ };
+
+ function defaultFormatter (actual, expected, path) {
+ return 'Expected ' +
+ path + (path.depth() ? ' = ' : '') +
+ j$.pp(actual) +
+ ' to equal ' +
+ j$.pp(expected) +
+ '.';
+ }
+ };
+};
+
+getJasmineRequireObj().matchersUtil = function(j$) {
+ // TODO: what to do about jasmine.pp not being inject? move to JSON.stringify? gut PrettyPrinter?
+
+ return {
+ equals: equals,
+
+ contains: function(haystack, needle, customTesters) {
+ customTesters = customTesters || [];
+
+ if ((Object.prototype.toString.apply(haystack) === '[object Set]')) {
+ return haystack.has(needle);
+ }
+
+ if ((Object.prototype.toString.apply(haystack) === '[object Array]') ||
+ (!!haystack && !haystack.indexOf))
+ {
+ for (var i = 0; i < haystack.length; i++) {
+ if (equals(haystack[i], needle, customTesters)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ return !!haystack && haystack.indexOf(needle) >= 0;
+ },
+
+ buildFailureMessage: function() {
+ var args = Array.prototype.slice.call(arguments, 0),
+ matcherName = args[0],
+ isNot = args[1],
+ actual = args[2],
+ expected = args.slice(3),
+ englishyPredicate = matcherName.replace(/[A-Z]/g, function(s) { return ' ' + s.toLowerCase(); });
+
+ var message = 'Expected ' +
+ j$.pp(actual) +
+ (isNot ? ' not ' : ' ') +
+ englishyPredicate;
+
+ if (expected.length > 0) {
+ for (var i = 0; i < expected.length; i++) {
+ if (i > 0) {
+ message += ',';
+ }
+ message += ' ' + j$.pp(expected[i]);
+ }
+ }
+
+ return message + '.';
+ }
+ };
+
+ function isAsymmetric(obj) {
+ return obj && j$.isA_('Function', obj.asymmetricMatch);
+ }
+
+ function asymmetricMatch(a, b, customTesters, diffBuilder) {
+ var asymmetricA = isAsymmetric(a),
+ asymmetricB = isAsymmetric(b),
+ result;
+
+ if (asymmetricA && asymmetricB) {
+ return undefined;
+ }
+
+ if (asymmetricA) {
+ result = a.asymmetricMatch(b, customTesters);
+ diffBuilder.record(a, b);
+ return result;
+ }
+
+ if (asymmetricB) {
+ result = b.asymmetricMatch(a, customTesters);
+ diffBuilder.record(a, b);
+ return result;
+ }
+ }
+
+ function equals(a, b, customTesters, diffBuilder) {
+ customTesters = customTesters || [];
+ diffBuilder = diffBuilder || j$.NullDiffBuilder();
+
+ return eq(a, b, [], [], customTesters, diffBuilder);
+ }
+
+ // Equality function lovingly adapted from isEqual in
+ // [Underscore](http://underscorejs.org)
+ function eq(a, b, aStack, bStack, customTesters, diffBuilder) {
+ var result = true, i;
+
+ var asymmetricResult = asymmetricMatch(a, b, customTesters, diffBuilder);
+ if (!j$.util.isUndefined(asymmetricResult)) {
+ return asymmetricResult;
+ }
+
+ for (i = 0; i < customTesters.length; i++) {
+ var customTesterResult = customTesters[i](a, b);
+ if (!j$.util.isUndefined(customTesterResult)) {
+ if (!customTesterResult) {
+ diffBuilder.record(a, b);
+ }
+ return customTesterResult;
+ }
+ }
+
+ if (a instanceof Error && b instanceof Error) {
+ result = a.message == b.message;
+ if (!result) {
+ diffBuilder.record(a, b);
+ }
+ return result;
+ }
+
+ // Identical objects are equal. `0 === -0`, but they aren't identical.
+ // See the [Harmony `egal` proposal](http://wiki.ecmascript.org/doku.php?id=harmony:egal).
+ if (a === b) {
+ result = a !== 0 || 1 / a == 1 / b;
+ if (!result) {
+ diffBuilder.record(a, b);
+ }
+ return result;
+ }
+ // A strict comparison is necessary because `null == undefined`.
+ if (a === null || b === null) {
+ result = a === b;
+ if (!result) {
+ diffBuilder.record(a, b);
+ }
+ return result;
+ }
+ var className = Object.prototype.toString.call(a);
+ if (className != Object.prototype.toString.call(b)) {
+ diffBuilder.record(a, b);
+ return false;
+ }
+ switch (className) {
+ // Strings, numbers, dates, and booleans are compared by value.
+ case '[object String]':
+ // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is
+ // equivalent to `new String("5")`.
+ result = a == String(b);
+ if (!result) {
+ diffBuilder.record(a, b);
+ }
+ return result;
+ case '[object Number]':
+ // `NaN`s are equivalent, but non-reflexive. An `egal` comparison is performed for
+ // other numeric values.
+ result = a != +a ? b != +b : (a === 0 ? 1 / a == 1 / b : a == +b);
+ if (!result) {
+ diffBuilder.record(a, b);
+ }
+ return result;
+ case '[object Date]':
+ case '[object Boolean]':
+ // Coerce dates and booleans to numeric primitive values. Dates are compared by their
+ // millisecond representations. Note that invalid dates with millisecond representations
+ // of `NaN` are not equivalent.
+ result = +a == +b;
+ if (!result) {
+ diffBuilder.record(a, b);
+ }
+ return result;
+ // RegExps are compared by their source patterns and flags.
+ case '[object RegExp]':
+ return a.source == b.source &&
+ a.global == b.global &&
+ a.multiline == b.multiline &&
+ a.ignoreCase == b.ignoreCase;
+ }
+ if (typeof a != 'object' || typeof b != 'object') {
+ diffBuilder.record(a, b);
+ return false;
+ }
+
+ var aIsDomNode = j$.isDomNode(a);
+ var bIsDomNode = j$.isDomNode(b);
+ if (aIsDomNode && bIsDomNode) {
+ // At first try to use DOM3 method isEqualNode
+ if (a.isEqualNode) {
+ result = a.isEqualNode(b);
+ if (!result) {
+ diffBuilder.record(a, b);
+ }
+ return result;
+ }
+ // IE8 doesn't support isEqualNode, try to use outerHTML && innerText
+ var aIsElement = a instanceof Element;
+ var bIsElement = b instanceof Element;
+ if (aIsElement && bIsElement) {
+ result = a.outerHTML == b.outerHTML;
+ if (!result) {
+ diffBuilder.record(a, b);
+ }
+ return result;
+ }
+ if (aIsElement || bIsElement) {
+ diffBuilder.record(a, b);
+ return false;
+ }
+ result = a.innerText == b.innerText && a.textContent == b.textContent;
+ if (!result) {
+ diffBuilder.record(a, b);
+ }
+ return result;
+ }
+ if (aIsDomNode || bIsDomNode) {
+ diffBuilder.record(a, b);
+ return false;
+ }
+
+ // Assume equality for cyclic structures. The algorithm for detecting cyclic
+ // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`.
+ var length = aStack.length;
+ while (length--) {
+ // Linear search. Performance is inversely proportional to the number of
+ // unique nested structures.
+ if (aStack[length] == a) { return bStack[length] == b; }
+ }
+ // Add the first object to the stack of traversed objects.
+ aStack.push(a);
+ bStack.push(b);
+ var size = 0;
+ // Recursively compare objects and arrays.
+ // Compare array lengths to determine if a deep comparison is necessary.
+ if (className == '[object Array]') {
+ size = a.length;
+ if (size !== b.length) {
+ diffBuilder.record(a, b);
+ return false;
+ }
+
+ for (i = 0; i < size; i++) {
+ diffBuilder.withPath(i, function() {
+ result = eq(a[i], b[i], aStack, bStack, customTesters, diffBuilder) && result;
+ });
+ }
+ if (!result) {
+ return false;
+ }
+ } else if (className == '[object Set]') {
+ if (a.size != b.size) {
+ diffBuilder.record(a, b);
+ return false;
+ }
+ var iterA = a.values(), iterB = b.values();
+ var valA, valB;
+ do {
+ valA = iterA.next();
+ valB = iterB.next();
+ if (!eq(valA.value, valB.value, aStack, bStack, customTesters, j$.NullDiffBuilder())) {
+ diffBuilder.record(a, b);
+ return false;
+ }
+ } while (!valA.done && !valB.done);
+ } else {
+
+ // Objects with different constructors are not equivalent, but `Object`s
+ // or `Array`s from different frames are.
+ var aCtor = a.constructor, bCtor = b.constructor;
+ if (aCtor !== bCtor &&
+ isFunction(aCtor) && isFunction(bCtor) &&
+ a instanceof aCtor && b instanceof bCtor &&
+ !(aCtor instanceof aCtor && bCtor instanceof bCtor)) {
+
+ diffBuilder.record(a, b, constructorsAreDifferentFormatter);
+ return false;
+ }
+ }
+
+ // Deep compare objects.
+ var aKeys = keys(a, className == '[object Array]'), key;
+ size = aKeys.length;
+
+ // Ensure that both objects contain the same number of properties before comparing deep equality.
+ if (keys(b, className == '[object Array]').length !== size) {
+ diffBuilder.record(a, b, objectKeysAreDifferentFormatter);
+ return false;
+ }
+
+ for (i = 0; i < size; i++) {
+ key = aKeys[i];
+ // Deep compare each member
+ if (!j$.util.has(b, key)) {
+ diffBuilder.record(a, b, objectKeysAreDifferentFormatter);
+ result = false;
+ continue;
+ }
+
+ diffBuilder.withPath(key, function() {
+ if(!eq(a[key], b[key], aStack, bStack, customTesters, diffBuilder)) {
+ result = false;
+ }
+ });
+ }
+
+ if (!result) {
+ return false;
+ }
+
+ // Remove the first object from the stack of traversed objects.
+ aStack.pop();
+ bStack.pop();
+
+ return result;
+ }
+
+ function keys(obj, isArray) {
+ var allKeys = Object.keys ? Object.keys(obj) :
+ (function(o) {
+ var keys = [];
+ for (var key in o) {
+ if (j$.util.has(o, key)) {
+ keys.push(key);
+ }
+ }
+ return keys;
+ })(obj);
+
+ if (!isArray) {
+ return allKeys;
+ }
+
+ if (allKeys.length === 0) {
+ return allKeys;
+ }
+
+ var extraKeys = [];
+ for (var i in allKeys) {
+ if (!allKeys[i].match(/^[0-9]+$/)) {
+ extraKeys.push(allKeys[i]);
+ }
+ }
+
+ return extraKeys;
+ }
+
+ function has(obj, key) {
+ return Object.prototype.hasOwnProperty.call(obj, key);
+ }
+
+ function isFunction(obj) {
+ return typeof obj === 'function';
+ }
+
+ function objectKeysAreDifferentFormatter(actual, expected, path) {
+ var missingProperties = j$.util.objectDifference(expected, actual),
+ extraProperties = j$.util.objectDifference(actual, expected),
+ missingPropertiesMessage = formatKeyValuePairs(missingProperties),
+ extraPropertiesMessage = formatKeyValuePairs(extraProperties),
+ messages = [];
+
+ if (!path.depth()) {
+ path = 'object';
+ }
+
+ if (missingPropertiesMessage.length) {
+ messages.push('Expected ' + path + ' to have properties' + missingPropertiesMessage);
+ }
+
+ if (extraPropertiesMessage.length) {
+ messages.push('Expected ' + path + ' not to have properties' + extraPropertiesMessage);
+ }
+
+ return messages.join('\n');
+ }
+
+ function constructorsAreDifferentFormatter(actual, expected, path) {
+ if (!path.depth()) {
+ path = 'object';
+ }
+
+ return 'Expected ' +
+ path + ' to be a kind of ' +
+ j$.fnNameFor(expected.constructor) +
+ ', but was ' + j$.pp(actual) + '.';
+ }
+
+ function formatKeyValuePairs(obj) {
+ var formatted = '';
+ for (var key in obj) {
+ formatted += '\n ' + key + ': ' + j$.pp(obj[key]);
+ }
+ return formatted;
+ }
+};
+
+getJasmineRequireObj().NullDiffBuilder = function(j$) {
+ return function() {
+ return {
+ withPath: function(_, block) {
+ block();
+ },
+ record: function() {}
+ };
+ };
+};
+
+getJasmineRequireObj().ObjectPath = function(j$) {
+ function ObjectPath(components) {
+ this.components = components || [];
+ }
+
+ ObjectPath.prototype.toString = function() {
+ if (this.components.length) {
+ return '$' + map(this.components, formatPropertyAccess).join('');
+ } else {
+ return '';
+ }
+ };
+
+ ObjectPath.prototype.add = function(component) {
+ return new ObjectPath(this.components.concat([component]));
+ };
+
+ ObjectPath.prototype.depth = function() {
+ return this.components.length;
+ };
+
+ function formatPropertyAccess(prop) {
+ if (typeof prop === 'number') {
+ return '[' + prop + ']';
+ }
+
+ if (isValidIdentifier(prop)) {
+ return '.' + prop;
+ }
+
+ return '[\'' + prop + '\']';
+ }
+
+ function map(array, fn) {
+ var results = [];
+ for (var i = 0; i < array.length; i++) {
+ results.push(fn(array[i]));
+ }
+ return results;
+ }
+
+ function isValidIdentifier(string) {
+ return /^[A-Za-z\$_][A-Za-z0-9\$_]*$/.test(string);
+ }
+
+ return ObjectPath;
+};
+
+getJasmineRequireObj().toBe = function() {
+ /**
+ * {@link expect} the actual value to be `===` to the expected value.
+ * @function
+ * @name matchers#toBe
+ * @param {Object} expected - The expected value to compare against.
+ * @example
+ * expect(thing).toBe(realThing);
+ */
+ function toBe() {
+ return {
+ compare: function(actual, expected) {
+ return {
+ pass: actual === expected
+ };
+ }
+ };
+ }
+
+ return toBe;
+};
+
+getJasmineRequireObj().toBeCloseTo = function() {
+ /**
+ * {@link expect} the actual value to be within a specified precision of the expected value.
+ * @function
+ * @name matchers#toBeCloseTo
+ * @param {Object} expected - The expected value to compare against.
+ * @param {Number} [precision=2] - The number of decimal points to check.
+ * @example
+ * expect(number).toBeCloseTo(42.2, 3);
+ */
+ function toBeCloseTo() {
+ return {
+ compare: function(actual, expected, precision) {
+ if (precision !== 0) {
+ precision = precision || 2;
+ }
+
+ return {
+ pass: Math.abs(expected - actual) < (Math.pow(10, -precision) / 2)
+ };
+ }
+ };
+ }
+
+ return toBeCloseTo;
+};
+
+getJasmineRequireObj().toBeDefined = function() {
+ /**
+ * {@link expect} the actual value to be defined. (Not `undefined`)
+ * @function
+ * @name matchers#toBeDefined
+ * @example
+ * expect(result).toBeDefined();
+ */
+ function toBeDefined() {
+ return {
+ compare: function(actual) {
+ return {
+ pass: (void 0 !== actual)
+ };
+ }
+ };
+ }
+
+ return toBeDefined;
+};
+
+getJasmineRequireObj().toBeFalsy = function() {
+ /**
+ * {@link expect} the actual value to be falsy
+ * @function
+ * @name matchers#toBeFalsy
+ * @example
+ * expect(result).toBeFalsy();
+ */
+ function toBeFalsy() {
+ return {
+ compare: function(actual) {
+ return {
+ pass: !!!actual
+ };
+ }
+ };
+ }
+
+ return toBeFalsy;
+};
+
+getJasmineRequireObj().toBeGreaterThan = function() {
+ /**
+ * {@link expect} the actual value to be greater than the expected value.
+ * @function
+ * @name matchers#toBeGreaterThan
+ * @param {Number} expected - The value to compare against.
+ * @example
+ * expect(result).toBeGreaterThan(3);
+ */
+ function toBeGreaterThan() {
+ return {
+ compare: function(actual, expected) {
+ return {
+ pass: actual > expected
+ };
+ }
+ };
+ }
+
+ return toBeGreaterThan;
+};
+
+
+getJasmineRequireObj().toBeGreaterThanOrEqual = function() {
+ /**
+ * {@link expect} the actual value to be greater than or equal to the expected value.
+ * @function
+ * @name matchers#toBeGreaterThanOrEqual
+ * @param {Number} expected - The expected value to compare against.
+ * @example
+ * expect(result).toBeGreaterThanOrEqual(25);
+ */
+ function toBeGreaterThanOrEqual() {
+ return {
+ compare: function(actual, expected) {
+ return {
+ pass: actual >= expected
+ };
+ }
+ };
+ }
+
+ return toBeGreaterThanOrEqual;
+};
+
+getJasmineRequireObj().toBeLessThan = function() {
+ /**
+ * {@link expect} the actual value to be less than the expected value.
+ * @function
+ * @name matchers#toBeLessThan
+ * @param {Number} expected - The expected value to compare against.
+ * @example
+ * expect(result).toBeLessThan(0);
+ */
+ function toBeLessThan() {
+ return {
+
+ compare: function(actual, expected) {
+ return {
+ pass: actual < expected
+ };
+ }
+ };
+ }
+
+ return toBeLessThan;
+};
+
+getJasmineRequireObj().toBeLessThanOrEqual = function() {
+ /**
+ * {@link expect} the actual value to be less than or equal to the expected value.
+ * @function
+ * @name matchers#toBeLessThanOrEqual
+ * @param {Number} expected - The expected value to compare against.
+ * @example
+ * expect(result).toBeLessThanOrEqual(123);
+ */
+ function toBeLessThanOrEqual() {
+ return {
+
+ compare: function(actual, expected) {
+ return {
+ pass: actual <= expected
+ };
+ }
+ };
+ }
+
+ return toBeLessThanOrEqual;
+};
+
+getJasmineRequireObj().toBeNaN = function(j$) {
+ /**
+ * {@link expect} the actual value to be `NaN` (Not a Number).
+ * @function
+ * @name matchers#toBeNaN
+ * @example
+ * expect(thing).toBeNaN();
+ */
+ function toBeNaN() {
+ return {
+ compare: function(actual) {
+ var result = {
+ pass: (actual !== actual)
+ };
+
+ if (result.pass) {
+ result.message = 'Expected actual not to be NaN.';
+ } else {
+ result.message = function() { return 'Expected ' + j$.pp(actual) + ' to be NaN.'; };
+ }
+
+ return result;
+ }
+ };
+ }
+
+ return toBeNaN;
+};
+
+getJasmineRequireObj().toBeNegativeInfinity = function(j$) {
+ /**
+ * {@link expect} the actual value to be `-Infinity` (-infinity).
+ * @function
+ * @name matchers#toBeNegativeInfinity
+ * @example
+ * expect(thing).toBeNegativeInfinity();
+ */
+ function toBeNegativeInfinity() {
+ return {
+ compare: function(actual) {
+ var result = {
+ pass: (actual === Number.NEGATIVE_INFINITY)
+ };
+
+ if (result.pass) {
+ result.message = 'Expected actual to be -Infinity.';
+ } else {
+ result.message = function() { return 'Expected ' + j$.pp(actual) + ' not to be -Infinity.'; };
+ }
+
+ return result;
+ }
+ };
+ }
+
+ return toBeNegativeInfinity;
+};
+
+getJasmineRequireObj().toBeNull = function() {
+ /**
+ * {@link expect} the actual value to be `null`.
+ * @function
+ * @name matchers#toBeNull
+ * @example
+ * expect(result).toBeNull();
+ */
+ function toBeNull() {
+ return {
+ compare: function(actual) {
+ return {
+ pass: actual === null
+ };
+ }
+ };
+ }
+
+ return toBeNull;
+};
+
+getJasmineRequireObj().toBePositiveInfinity = function(j$) {
+ /**
+ * {@link expect} the actual value to be `Infinity` (infinity).
+ * @function
+ * @name matchers#toBePositiveInfinity
+ * @example
+ * expect(thing).toBePositiveInfinity();
+ */
+ function toBePositiveInfinity() {
+ return {
+ compare: function(actual) {
+ var result = {
+ pass: (actual === Number.POSITIVE_INFINITY)
+ };
+
+ if (result.pass) {
+ result.message = 'Expected actual to be Infinity.';
+ } else {
+ result.message = function() { return 'Expected ' + j$.pp(actual) + ' not to be Infinity.'; };
+ }
+
+ return result;
+ }
+ };
+ }
+
+ return toBePositiveInfinity;
+};
+
+getJasmineRequireObj().toBeTruthy = function() {
+ /**
+ * {@link expect} the actual value to be truthy.
+ * @function
+ * @name matchers#toBeTruthy
+ * @example
+ * expect(thing).toBeTruthy();
+ */
+ function toBeTruthy() {
+ return {
+ compare: function(actual) {
+ return {
+ pass: !!actual
+ };
+ }
+ };
+ }
+
+ return toBeTruthy;
+};
+
+getJasmineRequireObj().toBeUndefined = function() {
+ /**
+ * {@link expect} the actual value to be `undefined`.
+ * @function
+ * @name matchers#toBeUndefined
+ * @example
+ * expect(result).toBeUndefined():
+ */
+ function toBeUndefined() {
+ return {
+ compare: function(actual) {
+ return {
+ pass: void 0 === actual
+ };
+ }
+ };
+ }
+
+ return toBeUndefined;
+};
+
+getJasmineRequireObj().toContain = function() {
+ /**
+ * {@link expect} the actual value to contain a specific value.
+ * @function
+ * @name matchers#toContain
+ * @param {Object} expected - The value to look for.
+ * @example
+ * expect(array).toContain(anElement);
+ * expect(string).toContain(substring);
+ */
+ function toContain(util, customEqualityTesters) {
+ customEqualityTesters = customEqualityTesters || [];
+
+ return {
+ compare: function(actual, expected) {
+
+ return {
+ pass: util.contains(actual, expected, customEqualityTesters)
+ };
+ }
+ };
+ }
+
+ return toContain;
+};
+
+getJasmineRequireObj().toEqual = function(j$) {
+ /**
+ * {@link expect} the actual value to be equal to the expected, using deep equality comparison.
+ * @function
+ * @name matchers#toEqual
+ * @param {Object} expected - Expected value
+ * @example
+ * expect(bigObject).toEqual({"foo": ['bar', 'baz']});
+ */
+ function toEqual(util, customEqualityTesters) {
+ customEqualityTesters = customEqualityTesters || [];
+
+ return {
+ compare: function(actual, expected) {
+ var result = {
+ pass: false
+ },
+ diffBuilder = j$.DiffBuilder();
+
+ result.pass = util.equals(actual, expected, customEqualityTesters, diffBuilder);
+
+ // TODO: only set error message if test fails
+ result.message = diffBuilder.getMessage();
+
+ return result;
+ }
+ };
+ }
+
+ return toEqual;
+};
+
+getJasmineRequireObj().toHaveBeenCalled = function(j$) {
+
+ var getErrorMsg = j$.formatErrorMsg('<toHaveBeenCalled>', 'expect(<spyObj>).toHaveBeenCalled()');
+
+ /**
+ * {@link expect} the actual (a {@link Spy}) to have been called.
+ * @function
+ * @name matchers#toHaveBeenCalled
+ * @example
+ * expect(mySpy).toHaveBeenCalled();
+ * expect(mySpy).not.toHaveBeenCalled();
+ */
+ function toHaveBeenCalled() {
+ return {
+ compare: function(actual) {
+ var result = {};
+
+ if (!j$.isSpy(actual)) {
+ throw new Error(getErrorMsg('Expected a spy, but got ' + j$.pp(actual) + '.'));
+ }
+
+ if (arguments.length > 1) {
+ throw new Error(getErrorMsg('Does not take arguments, use toHaveBeenCalledWith'));
+ }
+
+ result.pass = actual.calls.any();
+
+ result.message = result.pass ?
+ 'Expected spy ' + actual.and.identity() + ' not to have been called.' :
+ 'Expected spy ' + actual.and.identity() + ' to have been called.';
+
+ return result;
+ }
+ };
+ }
+
+ return toHaveBeenCalled;
+};
+
+getJasmineRequireObj().toHaveBeenCalledBefore = function(j$) {
+
+ var getErrorMsg = j$.formatErrorMsg('<toHaveBeenCalledBefore>', 'expect(<spyObj>).toHaveBeenCalledBefore(<spyObj>)');
+
+ /**
+ * {@link expect} the actual value (a {@link Spy}) to have been called before another {@link Spy}.
+ * @function
+ * @name matchers#toHaveBeenCalledBefore
+ * @param {Spy} expected - {@link Spy} that should have been called after the `actual` {@link Spy}.
+ * @example
+ * expect(mySpy).toHaveBeenCalledBefore(otherSpy);
+ */
+ function toHaveBeenCalledBefore() {
+ return {
+ compare: function(firstSpy, latterSpy) {
+ if (!j$.isSpy(firstSpy)) {
+ throw new Error(getErrorMsg('Expected a spy, but got ' + j$.pp(firstSpy) + '.'));
+ }
+ if (!j$.isSpy(latterSpy)) {
+ throw new Error(getErrorMsg('Expected a spy, but got ' + j$.pp(latterSpy) + '.'));
+ }
+
+ var result = { pass: false };
+
+ if (!firstSpy.calls.count()) {
+ result.message = 'Expected spy ' + firstSpy.and.identity() + ' to have been called.';
+ return result;
+ }
+ if (!latterSpy.calls.count()) {
+ result.message = 'Expected spy ' + latterSpy.and.identity() + ' to have been called.';
+ return result;
+ }
+
+ var latest1stSpyCall = firstSpy.calls.mostRecent().invocationOrder;
+ var first2ndSpyCall = latterSpy.calls.first().invocationOrder;
+
+ result.pass = latest1stSpyCall < first2ndSpyCall;
+
+ if (result.pass) {
+ result.message = 'Expected spy ' + firstSpy.and.identity() + ' to not have been called before spy ' + latterSpy.and.identity() + ', but it was';
+ } else {
+ var first1stSpyCall = firstSpy.calls.first().invocationOrder;
+ var latest2ndSpyCall = latterSpy.calls.mostRecent().invocationOrder;
+
+ if(first1stSpyCall < first2ndSpyCall) {
+ result.message = 'Expected latest call to spy ' + firstSpy.and.identity() + ' to have been called before first call to spy ' + latterSpy.and.identity() + ' (no interleaved calls)';
+ } else if (latest2ndSpyCall > latest1stSpyCall) {
+ result.message = 'Expected first call to spy ' + latterSpy.and.identity() + ' to have been called after latest call to spy ' + firstSpy.and.identity() + ' (no interleaved calls)';
+ } else {
+ result.message = 'Expected spy ' + firstSpy.and.identity() + ' to have been called before spy ' + latterSpy.and.identity();
+ }
+ }
+
+ return result;
+ }
+ };
+ }
+
+ return toHaveBeenCalledBefore;
+};
+
+getJasmineRequireObj().toHaveBeenCalledTimes = function(j$) {
+
+ var getErrorMsg = j$.formatErrorMsg('<toHaveBeenCalledTimes>', 'expect(<spyObj>).toHaveBeenCalledTimes(<Number>)');
+
+ /**
+ * {@link expect} the actual (a {@link Spy}) to have been called the specified number of times.
+ * @function
+ * @name matchers#toHaveBeenCalledTimes
+ * @param {Number} expected - The number of invocations to look for.
+ * @example
+ * expect(mySpy).toHaveBeenCalledTimes(3);
+ */
+ function toHaveBeenCalledTimes() {
+ return {
+ compare: function(actual, expected) {
+ if (!j$.isSpy(actual)) {
+ throw new Error(getErrorMsg('Expected a spy, but got ' + j$.pp(actual) + '.'));
+ }
+
+ var args = Array.prototype.slice.call(arguments, 0),
+ result = { pass: false };
+
+ if (!j$.isNumber_(expected)){
+ throw new Error(getErrorMsg('The expected times failed is a required argument and must be a number.'));
+ }
+
+ actual = args[0];
+ var calls = actual.calls.count();
+ var timesMessage = expected === 1 ? 'once' : expected + ' times';
+ result.pass = calls === expected;
+ result.message = result.pass ?
+ 'Expected spy ' + actual.and.identity() + ' not to have been called ' + timesMessage + '. It was called ' + calls + ' times.' :
+ 'Expected spy ' + actual.and.identity() + ' to have been called ' + timesMessage + '. It was called ' + calls + ' times.';
+ return result;
+ }
+ };
+ }
+
+ return toHaveBeenCalledTimes;
+};
+
+getJasmineRequireObj().toHaveBeenCalledWith = function(j$) {
+
+ var getErrorMsg = j$.formatErrorMsg('<toHaveBeenCalledWith>', 'expect(<spyObj>).toHaveBeenCalledWith(...arguments)');
+
+ /**
+ * {@link expect} the actual (a {@link Spy}) to have been called with particular arguments at least once.
+ * @function
+ * @name matchers#toHaveBeenCalledWith
+ * @param {...Object} - The arguments to look for
+ * @example
+ * expect(mySpy).toHaveBeenCalledWith('foo', 'bar', 2);
+ */
+ function toHaveBeenCalledWith(util, customEqualityTesters) {
+ return {
+ compare: function() {
+ var args = Array.prototype.slice.call(arguments, 0),
+ actual = args[0],
+ expectedArgs = args.slice(1),
+ result = { pass: false };
+
+ if (!j$.isSpy(actual)) {
+ throw new Error(getErrorMsg('Expected a spy, but got ' + j$.pp(actual) + '.'));
+ }
+
+ if (!actual.calls.any()) {
+ result.message = function() { return 'Expected spy ' + actual.and.identity() + ' to have been called with ' + j$.pp(expectedArgs) + ' but it was never called.'; };
+ return result;
+ }
+
+ if (util.contains(actual.calls.allArgs(), expectedArgs, customEqualityTesters)) {
+ result.pass = true;
+ result.message = function() { return 'Expected spy ' + actual.and.identity() + ' not to have been called with ' + j$.pp(expectedArgs) + ' but it was.'; };
+ } else {
+ result.message = function() { return 'Expected spy ' + actual.and.identity() + ' to have been called with ' + j$.pp(expectedArgs) + ' but actual calls were ' + j$.pp(actual.calls.allArgs()).replace(/^\[ | \]$/g, '') + '.'; };
+ }
+
+ return result;
+ }
+ };
+ }
+
+ return toHaveBeenCalledWith;
+};
+
+getJasmineRequireObj().toMatch = function(j$) {
+
+ var getErrorMsg = j$.formatErrorMsg('<toMatch>', 'expect(<expectation>).toMatch(<string> || <regexp>)');
+
+ /**
+ * {@link expect} the actual value to match a regular expression
+ * @function
+ * @name matchers#toMatch
+ * @param {RegExp|String} expected - Value to look for in the string.
+ * @example
+ * expect("my string").toMatch(/string$/);
+ * expect("other string").toMatch("her");
+ */
+ function toMatch() {
+ return {
+ compare: function(actual, expected) {
+ if (!j$.isString_(expected) && !j$.isA_('RegExp', expected)) {
+ throw new Error(getErrorMsg('Expected is not a String or a RegExp'));
+ }
+
+ var regexp = new RegExp(expected);
+
+ return {
+ pass: regexp.test(actual)
+ };
+ }
+ };
+ }
+
+ return toMatch;
+};
+
+getJasmineRequireObj().toThrow = function(j$) {
+
+ var getErrorMsg = j$.formatErrorMsg('<toThrow>', 'expect(function() {<expectation>}).toThrow()');
+
+ /**
+ * {@link expect} a function to `throw` something.
+ * @function
+ * @name matchers#toThrow
+ * @param {Object} [expected] - Value that should be thrown. If not provided, simply the fact that something was thrown will be checked.
+ * @example
+ * expect(function() { return 'things'; }).toThrow('foo');
+ * expect(function() { return 'stuff'; }).toThrow();
+ */
+ function toThrow(util) {
+ return {
+ compare: function(actual, expected) {
+ var result = { pass: false },
+ threw = false,
+ thrown;
+
+ if (typeof actual != 'function') {
+ throw new Error(getErrorMsg('Actual is not a Function'));
+ }
+
+ try {
+ actual();
+ } catch (e) {
+ threw = true;
+ thrown = e;
+ }
+
+ if (!threw) {
+ result.message = 'Expected function to throw an exception.';
+ return result;
+ }
+
+ if (arguments.length == 1) {
+ result.pass = true;
+ result.message = function() { return 'Expected function not to throw, but it threw ' + j$.pp(thrown) + '.'; };
+
+ return result;
+ }
+
+ if (util.equals(thrown, expected)) {
+ result.pass = true;
+ result.message = function() { return 'Expected function not to throw ' + j$.pp(expected) + '.'; };
+ } else {
+ result.message = function() { return 'Expected function to throw ' + j$.pp(expected) + ', but it threw ' + j$.pp(thrown) + '.'; };
+ }
+
+ return result;
+ }
+ };
+ }
+
+ return toThrow;
+};
+
+getJasmineRequireObj().toThrowError = function(j$) {
+
+ var getErrorMsg = j$.formatErrorMsg('<toThrowError>', 'expect(function() {<expectation>}).toThrowError(<ErrorConstructor>, <message>)');
+
+ /**
+ * {@link expect} a function to `throw` an `Error`.
+ * @function
+ * @name matchers#toThrowError
+ * @param {Error} [expected] - `Error` constructor the object that was thrown needs to be an instance of. If not provided, `Error` will be used.
+ * @param {RegExp|String} [message] - The message that should be set on the thrown `Error`
+ * @example
+ * expect(function() { return 'things'; }).toThrowError(MyCustomError, 'message');
+ * expect(function() { return 'things'; }).toThrowError(MyCustomError, /bar/);
+ * expect(function() { return 'stuff'; }).toThrowError(MyCustomError);
+ * expect(function() { return 'other'; }).toThrowError(/foo/);
+ * expect(function() { return 'other'; }).toThrowError();
+ */
+ function toThrowError () {
+ return {
+ compare: function(actual) {
+ var threw = false,
+ pass = {pass: true},
+ fail = {pass: false},
+ thrown;
+
+ if (typeof actual != 'function') {
+ throw new Error(getErrorMsg('Actual is not a Function'));
+ }
+
+ var errorMatcher = getMatcher.apply(null, arguments);
+
+ try {
+ actual();
+ } catch (e) {
+ threw = true;
+ thrown = e;
+ }
+
+ if (!threw) {
+ fail.message = 'Expected function to throw an Error.';
+ return fail;
+ }
+
+ // Get Error constructor of thrown
+ if (!isErrorObject(thrown)) {
+ fail.message = function() { return 'Expected function to throw an Error, but it threw ' + j$.pp(thrown) + '.'; };
+ return fail;
+ }
+
+ if (errorMatcher.hasNoSpecifics()) {
+ pass.message = 'Expected function not to throw an Error, but it threw ' + j$.fnNameFor(thrown) + '.';
+ return pass;
+ }
+
+ if (errorMatcher.matches(thrown)) {
+ pass.message = function() {
+ return 'Expected function not to throw ' + errorMatcher.errorTypeDescription + errorMatcher.messageDescription() + '.';
+ };
+ return pass;
+ } else {
+ fail.message = function() {
+ return 'Expected function to throw ' + errorMatcher.errorTypeDescription + errorMatcher.messageDescription() +
+ ', but it threw ' + errorMatcher.thrownDescription(thrown) + '.';
+ };
+ return fail;
+ }
+ }
+ };
+
+ function getMatcher() {
+ var expected = null,
+ errorType = null;
+
+ if (arguments.length == 2) {
+ expected = arguments[1];
+ if (isAnErrorType(expected)) {
+ errorType = expected;
+ expected = null;
+ }
+ } else if (arguments.length > 2) {
+ errorType = arguments[1];
+ expected = arguments[2];
+ if (!isAnErrorType(errorType)) {
+ throw new Error(getErrorMsg('Expected error type is not an Error.'));
+ }
+ }
+
+ if (expected && !isStringOrRegExp(expected)) {
+ if (errorType) {
+ throw new Error(getErrorMsg('Expected error message is not a string or RegExp.'));
+ } else {
+ throw new Error(getErrorMsg('Expected is not an Error, string, or RegExp.'));
+ }
+ }
+
+ function messageMatch(message) {
+ if (typeof expected == 'string') {
+ return expected == message;
+ } else {
+ return expected.test(message);
+ }
+ }
+
+ return {
+ errorTypeDescription: errorType ? j$.fnNameFor(errorType) : 'an exception',
+ thrownDescription: function(thrown) {
+ var thrownName = errorType ? j$.fnNameFor(thrown.constructor) : 'an exception',
+ thrownMessage = '';
+
+ if (expected) {
+ thrownMessage = ' with message ' + j$.pp(thrown.message);
+ }
+
+ return thrownName + thrownMessage;
+ },
+ messageDescription: function() {
+ if (expected === null) {
+ return '';
+ } else if (expected instanceof RegExp) {
+ return ' with a message matching ' + j$.pp(expected);
+ } else {
+ return ' with message ' + j$.pp(expected);
+ }
+ },
+ hasNoSpecifics: function() {
+ return expected === null && errorType === null;
+ },
+ matches: function(error) {
+ return (errorType === null || error instanceof errorType) &&
+ (expected === null || messageMatch(error.message));
+ }
+ };
+ }
+
+ function isStringOrRegExp(potential) {
+ return potential instanceof RegExp || (typeof potential == 'string');
+ }
+
+ function isAnErrorType(type) {
+ if (typeof type !== 'function') {
+ return false;
+ }
+
+ var Surrogate = function() {};
+ Surrogate.prototype = type.prototype;
+ return isErrorObject(new Surrogate());
+ }
+
+ function isErrorObject(thrown) {
+ if (thrown instanceof Error) {
+ return true;
+ }
+ if (thrown && thrown.constructor && thrown.constructor.constructor &&
+ (thrown instanceof (thrown.constructor.constructor('return this')()).Error)) {
+ return true;
+ }
+ return false;
+ }
+ }
+
+ return toThrowError;
+};
+
getJasmineRequireObj().MockDate = function() {
function MockDate(global) {
var self = this;
@@ -1739,6 +3608,12 @@ getJasmineRequireObj().pp = function(j$) {
this.seen = [];
}
+ function hasCustomToString(value) {
+ // value.toString !== Object.prototype.toString if value has no custom toString but is from another context (e.g.
+ // iframe, web worker)
+ return value.toString !== Object.prototype.toString && (value.toString() !== Object.prototype.toString.call(value));
+ }
+
PrettyPrinter.prototype.format = function(value) {
this.ppNestLevel_++;
try {
@@ -1764,7 +3639,9 @@ getJasmineRequireObj().pp = function(j$) {
this.emitScalar('HTMLNode');
} else if (value instanceof Date) {
this.emitScalar('Date(' + value + ')');
- } else if (value.toString && typeof value === 'object' && !(value instanceof Array) && value.toString !== Object.prototype.toString) {
+ } else if (value.toString && value.toString() == '[object Set]') {
+ this.emitSet(value);
+ } else if (value.toString && typeof value === 'object' && !j$.isArray_(value) && hasCustomToString(value)) {
this.emitScalar(value.toString());
} else if (j$.util.arrayContains(this.seen, value)) {
this.emitScalar('<circular reference: ' + (j$.isArray_(value) ? 'Array' : 'Object') + '>');
@@ -1793,6 +3670,7 @@ getJasmineRequireObj().pp = function(j$) {
};
PrettyPrinter.prototype.emitArray = j$.unimplementedMethod_;
+ PrettyPrinter.prototype.emitSet = j$.unimplementedMethod_;
PrettyPrinter.prototype.emitObject = j$.unimplementedMethod_;
PrettyPrinter.prototype.emitScalar = j$.unimplementedMethod_;
PrettyPrinter.prototype.emitString = j$.unimplementedMethod_;
@@ -1849,8 +3727,34 @@ getJasmineRequireObj().pp = function(j$) {
this.append(' ]');
};
+ StringPrettyPrinter.prototype.emitSet = function(set) {
+ if (this.ppNestLevel_ > j$.MAX_PRETTY_PRINT_DEPTH) {
+ this.append('Set');
+ return;
+ }
+ this.append('Set( ');
+ var size = Math.min(set.size, j$.MAX_PRETTY_PRINT_ARRAY_LENGTH);
+ var iter = set.values();
+ for (var i = 0; i < size; i++) {
+ if (i > 0) {
+ this.append(', ');
+ }
+ this.format(iter.next().value);
+ }
+ if (set.size > size){
+ this.append(', ...');
+ }
+ this.append(' )');
+ };
+
StringPrettyPrinter.prototype.emitObject = function(obj) {
- var constructorName = obj.constructor ? j$.fnNameFor(obj.constructor) : 'null';
+ var ctor = obj.constructor,
+ constructorName;
+
+ constructorName = typeof ctor === 'function' && obj instanceof ctor ?
+ j$.fnNameFor(obj.constructor) :
+ 'null';
+
this.append(constructorName);
if (this.ppNestLevel_ > j$.MAX_PRETTY_PRINT_DEPTH) {
@@ -1917,6 +3821,7 @@ getJasmineRequireObj().QueueRunner = function(j$) {
this.userContext = attrs.userContext || {};
this.timeout = attrs.timeout || {setTimeout: setTimeout, clearTimeout: clearTimeout};
this.fail = attrs.fail || function() {};
+ this.globalErrors = attrs.globalErrors || { pushListener: function() {}, popListener: function() {} };
}
QueueRunner.prototype.execute = function() {
@@ -1939,11 +3844,7 @@ getJasmineRequireObj().QueueRunner = function(j$) {
}
}
- var runnerDone = iterativeIndex >= length;
-
- if (runnerDone) {
- this.clearStack(this.onComplete);
- }
+ this.clearStack(this.onComplete);
function attemptSync(queueableFn) {
try {
@@ -1957,8 +3858,13 @@ getJasmineRequireObj().QueueRunner = function(j$) {
var clearTimeout = function () {
Function.prototype.apply.apply(self.timeout.clearTimeout, [j$.getGlobal(), [timeoutId]]);
},
+ handleError = function(error) {
+ onException(error);
+ next();
+ },
next = once(function () {
clearTimeout(timeoutId);
+ self.globalErrors.popListener(handleError);
self.run(queueableFns, iterativeIndex + 1);
}),
timeoutId;
@@ -1968,6 +3874,8 @@ getJasmineRequireObj().QueueRunner = function(j$) {
next();
};
+ self.globalErrors.pushListener(handleError);
+
if (queueableFn.timeout) {
timeoutId = Function.prototype.apply.apply(self.timeout.setTimeout, [j$.getGlobal(), [function() {
var error = new Error('Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.');
@@ -2049,6 +3957,337 @@ getJasmineRequireObj().ReportDispatcher = function() {
};
+getJasmineRequireObj().interface = function(jasmine, env) {
+ var jasmineInterface = {
+ /**
+ * Create a group of specs (often called a suite).
+ *
+ * Calls to `describe` can be nested within other calls to compose your suite as a tree.
+ * @name describe
+ * @function
+ * @global
+ * @param {String} description Textual description of the group
+ * @param {Function} specDefinitions Function for Jasmine to invoke that will define inner suites a specs
+ */
+ describe: function(description, specDefinitions) {
+ return env.describe(description, specDefinitions);
+ },
+
+ /**
+ * A temporarily disabled [`describe`]{@link describe}
+ *
+ * Specs within an `xdescribe` will be marked pending and not executed
+ * @name xdescribe
+ * @function
+ * @global
+ * @param {String} description Textual description of the group
+ * @param {Function} specDefinitions Function for Jasmine to invoke that will define inner suites a specs
+ */
+ xdescribe: function(description, specDefinitions) {
+ return env.xdescribe(description, specDefinitions);
+ },
+
+ /**
+ * A focused [`describe`]{@link describe}
+ *
+ * If suites or specs are focused, only those that are focused will be executed
+ * @see fit
+ * @name fdescribe
+ * @function
+ * @global
+ * @param {String} description Textual description of the group
+ * @param {Function} specDefinitions Function for Jasmine to invoke that will define inner suites a specs
+ */
+ fdescribe: function(description, specDefinitions) {
+ return env.fdescribe(description, specDefinitions);
+ },
+
+ /**
+ * Define a single spec. A spec should contain one or more {@link expect|expectations} that test the state of the code.
+ *
+ * A spec whose expectations all succeed will be passing and a spec with any failures will fail.
+ * @name it
+ * @function
+ * @global
+ * @param {String} description Textual description of what this spec is checking
+ * @param {Function} [testFunction] Function that contains the code of your test. If not provided the test will be `pending`.
+ * @param {Int} [timeout={@link jasmine.DEFAULT_TIMEOUT_INTERVAL}] Custom timeout for an async spec.
+ */
+ it: function() {
+ return env.it.apply(env, arguments);
+ },
+
+ /**
+ * A temporarily disabled [`it`]{@link it}
+ *
+ * The spec will report as `pending` and will not be executed.
+ * @name xit
+ * @function
+ * @global
+ * @param {String} description Textual description of what this spec is checking.
+ * @param {Function} [testFunction] Function that contains the code of your test. Will not be executed.
+ */
+ xit: function() {
+ return env.xit.apply(env, arguments);
+ },
+
+ /**
+ * A focused [`it`]{@link it}
+ *
+ * If suites or specs are focused, only those that are focused will be executed.
+ * @name fit
+ * @function
+ * @global
+ * @param {String} description Textual description of what this spec is checking.
+ * @param {Function} testFunction Function that contains the code of your test.
+ * @param {Int} [timeout={@link jasmine.DEFAULT_TIMEOUT_INTERVAL}] Custom timeout for an async spec.
+ */
+ fit: function() {
+ return env.fit.apply(env, arguments);
+ },
+
+ /**
+ * Run some shared setup before each of the specs in the {@link describe} in which it is called.
+ * @name beforeEach
+ * @function
+ * @global
+ * @param {Function} [function] Function that contains the code to setup your specs.
+ * @param {Int} [timeout={@link jasmine.DEFAULT_TIMEOUT_INTERVAL}] Custom timeout for an async beforeEach.
+ */
+ beforeEach: function() {
+ return env.beforeEach.apply(env, arguments);
+ },
+
+ /**
+ * Run some shared teardown after each of the specs in the {@link describe} in which it is called.
+ * @name afterEach
+ * @function
+ * @global
+ * @param {Function} [function] Function that contains the code to teardown your specs.
+ * @param {Int} [timeout={@link jasmine.DEFAULT_TIMEOUT_INTERVAL}] Custom timeout for an async afterEach.
+ */
+ afterEach: function() {
+ return env.afterEach.apply(env, arguments);
+ },
+
+ /**
+ * Run some shared setup once before all of the specs in the {@link describe} are run.
+ *
+ * _Note:_ Be careful, sharing the setup from a beforeAll makes it easy to accidentally leak state between your specs so that they erroneously pass or fail.
+ * @name beforeAll
+ * @function
+ * @global
+ * @param {Function} [function] Function that contains the code to setup your specs.
+ * @param {Int} [timeout={@link jasmine.DEFAULT_TIMEOUT_INTERVAL}] Custom timeout for an async beforeAll.
+ */
+ beforeAll: function() {
+ return env.beforeAll.apply(env, arguments);
+ },
+
+ /**
+ * Run some shared teardown once before all of the specs in the {@link describe} are run.
+ *
+ * _Note:_ Be careful, sharing the teardown from a afterAll makes it easy to accidentally leak state between your specs so that they erroneously pass or fail.
+ * @name afterAll
+ * @function
+ * @global
+ * @param {Function} [function] Function that contains the code to teardown your specs.
+ * @param {Int} [timeout={@link jasmine.DEFAULT_TIMEOUT_INTERVAL}] Custom timeout for an async afterAll.
+ */
+ afterAll: function() {
+ return env.afterAll.apply(env, arguments);
+ },
+
+ /**
+ * Create an expectation for a spec.
+ * @name expect
+ * @function
+ * @global
+ * @param {Object} actual - Actual computed value to test expectations against.
+ * @return {matchers}
+ */
+ expect: function(actual) {
+ return env.expect(actual);
+ },
+
+ /**
+ * Mark a spec as pending, expectation results will be ignored.
+ * @name pending
+ * @function
+ * @global
+ * @param {String} [message] - Reason the spec is pending.
+ */
+ pending: function() {
+ return env.pending.apply(env, arguments);
+ },
+
+ /**
+ * Explicitly mark a spec as failed.
+ * @name fail
+ * @function
+ * @global
+ * @param {String|Error} [error] - Reason for the failure.
+ */
+ fail: function() {
+ return env.fail.apply(env, arguments);
+ },
+
+ /**
+ * Install a spy onto an existing object.
+ * @name spyOn
+ * @function
+ * @global
+ * @param {Object} obj - The object upon which to install the {@link Spy}.
+ * @param {String} methodName - The name of the method to replace with a {@link Spy}.
+ * @returns {Spy}
+ */
+ spyOn: function(obj, methodName) {
+ return env.spyOn(obj, methodName);
+ },
+
+ /**
+ * Install a spy on a property onto an existing object.
+ * @name spyOnProperty
+ * @function
+ * @global
+ * @param {Object} obj - The object upon which to install the {@link Spy}
+ * @param {String} propertyName - The name of the property to replace with a {@link Spy}.
+ * @param {String} [accessType=get] - The access type (get|set) of the property to {@link Spy} on.
+ * @returns {Spy}
+ */
+ spyOnProperty: function(obj, methodName, accessType) {
+ return env.spyOnProperty(obj, methodName, accessType);
+ },
+
+ jsApiReporter: new jasmine.JsApiReporter({
+ timer: new jasmine.Timer()
+ }),
+
+ /**
+ * @namespace jasmine
+ */
+ jasmine: jasmine
+ };
+
+ /**
+ * Add a custom equality tester for the current scope of specs.
+ *
+ * _Note:_ This is only callable from within a {@link beforeEach}, {@link it}, or {@link beforeAll}.
+ * @name jasmine.addCustomEqualityTester
+ * @function
+ * @param {Function} tester - A function which takes two arguments to compare and returns a `true` or `false` comparison result if it knows how to compare them, and `undefined` otherwise.
+ * @see custom_equality
+ */
+ jasmine.addCustomEqualityTester = function(tester) {
+ env.addCustomEqualityTester(tester);
+ };
+
+ /**
+ * Add custom matchers for the current scope of specs.
+ *
+ * _Note:_ This is only callable from within a {@link beforeEach}, {@link it}, or {@link beforeAll}.
+ * @name jasmine.addMatchers
+ * @function
+ * @param {Object} matchers - Keys from this object will be the new matcher names.
+ * @see custom_matcher
+ */
+ jasmine.addMatchers = function(matchers) {
+ return env.addMatchers(matchers);
+ };
+
+ /**
+ * Get the currently booted mock {Clock} for this Jasmine environment.
+ * @name jasmine.clock
+ * @function
+ * @returns {Clock}
+ */
+ jasmine.clock = function() {
+ return env.clock;
+ };
+
+ return jasmineInterface;
+};
+
+getJasmineRequireObj().Spy = function (j$) {
+
+ var nextOrder = (function() {
+ var order = 0;
+
+ return function() {
+ return order++;
+ };
+ })();
+
+ /**
+ * _Note:_ Do not construct this directly, use {@link spyOn}, {@link spyOnProperty}, {@link jasmine.createSpy}, or {@link jasmine.createSpyObj}
+ * @constructor
+ * @name Spy
+ */
+ function Spy(name, originalFn) {
+ var args = buildArgs(),
+ /*`eval` is the only option to preserve both this and context:
+ - former is needed to work as expected with methods,
+ - latter is needed to access real spy function and allows to reduce eval'ed code to absolute minimum
+ More explanation here (look at comments): http://www.bennadel.com/blog/1909-javascript-function-constructor-does-not-create-a-closure.htm
+ */
+ /* jshint evil: true */
+ wrapper = eval('(0, function (' + args + ') { return spy.apply(this, Array.prototype.slice.call(arguments)); })'),
+ /* jshint evil: false */
+ spyStrategy = new j$.SpyStrategy({
+ name: name,
+ fn: originalFn,
+ getSpy: function () {
+ return wrapper;
+ }
+ }),
+ callTracker = new j$.CallTracker(),
+ spy = function () {
+ /**
+ * @name Spy.callData
+ * @property {object} object - `this` context for the invocation.
+ * @property {number} invocationOrder - Order of the invocation.
+ * @property {Array} args - The arguments passed for this invocation.
+ */
+ var callData = {
+ object: this,
+ invocationOrder: nextOrder(),
+ args: Array.prototype.slice.apply(arguments)
+ };
+
+ callTracker.track(callData);
+ var returnValue = spyStrategy.exec.apply(this, arguments);
+ callData.returnValue = returnValue;
+
+ return returnValue;
+ };
+
+ function buildArgs() {
+ var args = [];
+
+ while (originalFn instanceof Function && args.length < originalFn.length) {
+ args.push('arg' + args.length);
+ }
+
+ return args.join(', ');
+ }
+
+ for (var prop in originalFn) {
+ if (prop === 'and' || prop === 'calls') {
+ throw new Error('Jasmine spies would overwrite the \'and\' and \'calls\' properties on the object being spied upon');
+ }
+
+ wrapper[prop] = originalFn[prop];
+ }
+
+ wrapper.and = spyStrategy;
+ wrapper.calls = callTracker;
+
+ return wrapper;
+ }
+
+ return Spy;
+};
+
getJasmineRequireObj().SpyRegistry = function(j$) {
var getErrorMsg = j$.formatErrorMsg('<spyOn>', 'spyOn(<object>, <methodName>)');
@@ -2063,11 +4302,11 @@ getJasmineRequireObj().SpyRegistry = function(j$) {
this.spyOn = function(obj, methodName) {
- if (j$.util.isUndefined(obj)) {
+ if (j$.util.isUndefined(obj) || obj === null) {
throw new Error(getErrorMsg('could not find an object to spy upon for ' + methodName + '()'));
}
- if (j$.util.isUndefined(methodName)) {
+ if (j$.util.isUndefined(methodName) || methodName === null) {
throw new Error(getErrorMsg('No method name supplied'));
}
@@ -2119,6 +4358,66 @@ getJasmineRequireObj().SpyRegistry = function(j$) {
return spiedMethod;
};
+ this.spyOnProperty = function (obj, propertyName, accessType) {
+ accessType = accessType || 'get';
+
+ if (j$.util.isUndefined(obj)) {
+ throw new Error('spyOn could not find an object to spy upon for ' + propertyName + '');
+ }
+
+ if (j$.util.isUndefined(propertyName)) {
+ throw new Error('No property name supplied');
+ }
+
+ var descriptor;
+ try {
+ descriptor = j$.util.getPropertyDescriptor(obj, propertyName);
+ } catch(e) {
+ // IE 8 doesn't support `definePropery` on non-DOM nodes
+ }
+
+ if (!descriptor) {
+ throw new Error(propertyName + ' property does not exist');
+ }
+
+ if (!descriptor.configurable) {
+ throw new Error(propertyName + ' is not declared configurable');
+ }
+
+ if(!descriptor[accessType]) {
+ throw new Error('Property ' + propertyName + ' does not have access type ' + accessType);
+ }
+
+ if (j$.isSpy(descriptor[accessType])) {
+ //TODO?: should this return the current spy? Downside: may cause user confusion about spy state
+ throw new Error(propertyName + ' has already been spied upon');
+ }
+
+ var originalDescriptor = j$.util.clone(descriptor),
+ spy = j$.createSpy(propertyName, descriptor[accessType]),
+ restoreStrategy;
+
+ if (Object.prototype.hasOwnProperty.call(obj, propertyName)) {
+ restoreStrategy = function() {
+ Object.defineProperty(obj, propertyName, originalDescriptor);
+ };
+ } else {
+ restoreStrategy = function() {
+ delete obj[propertyName];
+ };
+ }
+
+ currentSpies().push({
+ restoreObjectToOriginalState: restoreStrategy
+ });
+
+ descriptor[accessType] = spy;
+
+ Object.defineProperty(obj, propertyName, descriptor);
+
+ return spy;
+ };
+
this.clearSpies = function() {
var spies = currentSpies();
for (var i = spies.length - 1; i >= 0; i--) {
@@ -2133,6 +4432,9 @@ getJasmineRequireObj().SpyRegistry = function(j$) {
getJasmineRequireObj().SpyStrategy = function(j$) {
+ /**
+ * @namespace Spy#and
+ */
function SpyStrategy(options) {
options = options || {};
@@ -2141,19 +4443,41 @@ getJasmineRequireObj().SpyStrategy = function(j$) {
getSpy = options.getSpy || function() {},
plan = function() {};
+ /**
+ * Return the identifying information for the spy.
+ * @name Spy#and#identity
+ * @function
+ * @returns {String}
+ */
this.identity = function() {
return identity;
};
+ /**
+ * Execute the current spy strategy.
+ * @name Spy#and#exec
+ * @function
+ */
this.exec = function() {
return plan.apply(this, arguments);
};
+ /**
+ * Tell the spy to call through to the real implementation when invoked.
+ * @name Spy#and#callThrough
+ * @function
+ */
this.callThrough = function() {
plan = originalFn;
return getSpy();
};
+ /**
+ * Tell the spy to return the value when invoked.
+ * @name Spy#and#returnValue
+ * @function
+ * @param {*} value The value to return.
+ */
this.returnValue = function(value) {
plan = function() {
return value;
@@ -2161,6 +4485,12 @@ getJasmineRequireObj().SpyStrategy = function(j$) {
return getSpy();
};
+ /**
+ * Tell the spy to return one of the specified values (sequentially) each time the spy is invoked.
+ * @name Spy#and#returnValues
+ * @function
+ * @param {...*} values - Values to be returned on subsequent calls to the spy.
+ */
this.returnValues = function() {
var values = Array.prototype.slice.call(arguments);
plan = function () {
@@ -2169,6 +4499,12 @@ getJasmineRequireObj().SpyStrategy = function(j$) {
return getSpy();
};
+ /**
+ * Tell the spy to throw an error when invoked.
+ * @name Spy#and#throwError
+ * @function
+ * @param {Error|String} something Thing to throw
+ */
this.throwError = function(something) {
var error = (something instanceof Error) ? something : new Error(something);
plan = function() {
@@ -2177,6 +4513,12 @@ getJasmineRequireObj().SpyStrategy = function(j$) {
return getSpy();
};
+ /**
+ * Tell the spy to call a fake implementation when invoked.
+ * @name Spy#and#callFake
+ * @function
+ * @param {Function} fn The function to invoke with the passed parameters.
+ */
this.callFake = function(fn) {
if(!j$.isFunction_(fn)) {
throw new Error('Argument passed to callFake should be a function, got ' + fn);
@@ -2185,6 +4527,11 @@ getJasmineRequireObj().SpyStrategy = function(j$) {
return getSpy();
};
+ /**
+ * Tell the spy to do nothing when invoked. This is the default.
+ * @name Spy#and#stub
+ * @function
+ */
this.stub = function(fn) {
plan = function() {};
return getSpy();
@@ -2208,7 +4555,6 @@ getJasmineRequireObj().Suite = function(j$) {
this.afterFns = [];
this.beforeAllFns = [];
this.afterAllFns = [];
- this.disabled = false;
this.children = [];
@@ -2234,11 +4580,7 @@ getJasmineRequireObj().Suite = function(j$) {
return fullName.join(' ');
};
- Suite.prototype.disable = function() {
- this.disabled = true;
- };
-
- Suite.prototype.pend = function(message) {
+ Suite.prototype.pend = function() {
this.markedPending = true;
};
@@ -2255,7 +4597,7 @@ getJasmineRequireObj().Suite = function(j$) {
};
Suite.prototype.afterAll = function(fn) {
- this.afterAllFns.push(fn);
+ this.afterAllFns.unshift(fn);
};
Suite.prototype.addChild = function(child) {
@@ -2263,10 +4605,6 @@ getJasmineRequireObj().Suite = function(j$) {
};
Suite.prototype.status = function() {
- if (this.disabled) {
- return 'disabled';
- }
-
if (this.markedPending) {
return 'pending';
}
@@ -2279,7 +4617,7 @@ getJasmineRequireObj().Suite = function(j$) {
};
Suite.prototype.isExecutable = function() {
- return !this.disabled;
+ return !this.markedPending;
};
Suite.prototype.canBeReentered = function() {
@@ -2600,1056 +4938,6 @@ getJasmineRequireObj().TreeProcessor = function() {
return TreeProcessor;
};
-getJasmineRequireObj().Any = function(j$) {
-
- function Any(expectedObject) {
- if (typeof expectedObject === 'undefined') {
- throw new TypeError(
- 'jasmine.any() expects to be passed a constructor function. ' +
- 'Please pass one or use jasmine.anything() to match any object.'
- );
- }
- this.expectedObject = expectedObject;
- }
-
- Any.prototype.asymmetricMatch = function(other) {
- if (this.expectedObject == String) {
- return typeof other == 'string' || other instanceof String;
- }
-
- if (this.expectedObject == Number) {
- return typeof other == 'number' || other instanceof Number;
- }
-
- if (this.expectedObject == Function) {
- return typeof other == 'function' || other instanceof Function;
- }
-
- if (this.expectedObject == Object) {
- return typeof other == 'object';
- }
-
- if (this.expectedObject == Boolean) {
- return typeof other == 'boolean';
- }
-
- return other instanceof this.expectedObject;
- };
-
- Any.prototype.jasmineToString = function() {
- return '<jasmine.any(' + j$.fnNameFor(this.expectedObject) + ')>';
- };
-
- return Any;
-};
-
-getJasmineRequireObj().Anything = function(j$) {
-
- function Anything() {}
-
- Anything.prototype.asymmetricMatch = function(other) {
- return !j$.util.isUndefined(other) && other !== null;
- };
-
- Anything.prototype.jasmineToString = function() {
- return '<jasmine.anything>';
- };
-
- return Anything;
-};
-
-getJasmineRequireObj().ArrayContaining = function(j$) {
- function ArrayContaining(sample) {
- this.sample = sample;
- }
-
- ArrayContaining.prototype.asymmetricMatch = function(other) {
- var className = Object.prototype.toString.call(this.sample);
- if (className !== '[object Array]') { throw new Error('You must provide an array to arrayContaining, not \'' + this.sample + '\'.'); }
-
- for (var i = 0; i < this.sample.length; i++) {
- var item = this.sample[i];
- if (!j$.matchersUtil.contains(other, item)) {
- return false;
- }
- }
-
- return true;
- };
-
- ArrayContaining.prototype.jasmineToString = function () {
- return '<jasmine.arrayContaining(' + jasmine.pp(this.sample) +')>';
- };
-
- return ArrayContaining;
-};
-
-getJasmineRequireObj().ObjectContaining = function(j$) {
-
- function ObjectContaining(sample) {
- this.sample = sample;
- }
-
- function getPrototype(obj) {
- if (Object.getPrototypeOf) {
- return Object.getPrototypeOf(obj);
- }
-
- if (obj.constructor.prototype == obj) {
- return null;
- }
-
- return obj.constructor.prototype;
- }
-
- function hasProperty(obj, property) {
- if (!obj) {
- return false;
- }
-
- if (Object.prototype.hasOwnProperty.call(obj, property)) {
- return true;
- }
-
- return hasProperty(getPrototype(obj), property);
- }
-
- ObjectContaining.prototype.asymmetricMatch = function(other) {
- if (typeof(this.sample) !== 'object') { throw new Error('You must provide an object to objectContaining, not \''+this.sample+'\'.'); }
-
- for (var property in this.sample) {
- if (!hasProperty(other, property) ||
- !j$.matchersUtil.equals(this.sample[property], other[property])) {
- return false;
- }
- }
-
- return true;
- };
-
- ObjectContaining.prototype.jasmineToString = function() {
- return '<jasmine.objectContaining(' + j$.pp(this.sample) + ')>';
- };
-
- return ObjectContaining;
-};
-
-getJasmineRequireObj().StringMatching = function(j$) {
-
- function StringMatching(expected) {
- if (!j$.isString_(expected) && !j$.isA_('RegExp', expected)) {
- throw new Error('Expected is not a String or a RegExp');
- }
-
- this.regexp = new RegExp(expected);
- }
-
- StringMatching.prototype.asymmetricMatch = function(other) {
- return this.regexp.test(other);
- };
-
- StringMatching.prototype.jasmineToString = function() {
- return '<jasmine.stringMatching(' + this.regexp + ')>';
- };
-
- return StringMatching;
-};
-
-getJasmineRequireObj().errors = function() {
- function ExpectationFailed() {}
-
- ExpectationFailed.prototype = new Error();
- ExpectationFailed.prototype.constructor = ExpectationFailed;
-
- return {
- ExpectationFailed: ExpectationFailed
- };
-};
-getJasmineRequireObj().formatErrorMsg = function() {
- function generateErrorMsg(domain, usage) {
- var usageDefinition = usage ? '\nUsage: ' + usage : '';
-
- return function errorMsg(msg) {
- return domain + ' : ' + msg + usageDefinition;
- };
- }
-
- return generateErrorMsg;
-};
-
-getJasmineRequireObj().matchersUtil = function(j$) {
- // TODO: what to do about jasmine.pp not being inject? move to JSON.stringify? gut PrettyPrinter?
-
- return {
- equals: function(a, b, customTesters) {
- customTesters = customTesters || [];
-
- return eq(a, b, [], [], customTesters);
- },
-
- contains: function(haystack, needle, customTesters) {
- customTesters = customTesters || [];
-
- if ((Object.prototype.toString.apply(haystack) === '[object Array]') ||
- (!!haystack && !haystack.indexOf))
- {
- for (var i = 0; i < haystack.length; i++) {
- if (eq(haystack[i], needle, [], [], customTesters)) {
- return true;
- }
- }
- return false;
- }
-
- return !!haystack && haystack.indexOf(needle) >= 0;
- },
-
- buildFailureMessage: function() {
- var args = Array.prototype.slice.call(arguments, 0),
- matcherName = args[0],
- isNot = args[1],
- actual = args[2],
- expected = args.slice(3),
- englishyPredicate = matcherName.replace(/[A-Z]/g, function(s) { return ' ' + s.toLowerCase(); });
-
- var message = 'Expected ' +
- j$.pp(actual) +
- (isNot ? ' not ' : ' ') +
- englishyPredicate;
-
- if (expected.length > 0) {
- for (var i = 0; i < expected.length; i++) {
- if (i > 0) {
- message += ',';
- }
- message += ' ' + j$.pp(expected[i]);
- }
- }
-
- return message + '.';
- }
- };
-
- function isAsymmetric(obj) {
- return obj && j$.isA_('Function', obj.asymmetricMatch);
- }
-
- function asymmetricMatch(a, b) {
- var asymmetricA = isAsymmetric(a),
- asymmetricB = isAsymmetric(b);
-
- if (asymmetricA && asymmetricB) {
- return undefined;
- }
-
- if (asymmetricA) {
- return a.asymmetricMatch(b);
- }
-
- if (asymmetricB) {
- return b.asymmetricMatch(a);
- }
- }
-
- // Equality function lovingly adapted from isEqual in
- // [Underscore](http://underscorejs.org)
- function eq(a, b, aStack, bStack, customTesters) {
- var result = true;
-
- var asymmetricResult = asymmetricMatch(a, b);
- if (!j$.util.isUndefined(asymmetricResult)) {
- return asymmetricResult;
- }
-
- for (var i = 0; i < customTesters.length; i++) {
- var customTesterResult = customTesters[i](a, b);
- if (!j$.util.isUndefined(customTesterResult)) {
- return customTesterResult;
- }
- }
-
- if (a instanceof Error && b instanceof Error) {
- return a.message == b.message;
- }
-
- // Identical objects are equal. `0 === -0`, but they aren't identical.
- // See the [Harmony `egal` proposal](http://wiki.ecmascript.org/doku.php?id=harmony:egal).
- if (a === b) { return a !== 0 || 1 / a == 1 / b; }
- // A strict comparison is necessary because `null == undefined`.
- if (a === null || b === null) { return a === b; }
- var className = Object.prototype.toString.call(a);
- if (className != Object.prototype.toString.call(b)) { return false; }
- switch (className) {
- // Strings, numbers, dates, and booleans are compared by value.
- case '[object String]':
- // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is
- // equivalent to `new String("5")`.
- return a == String(b);
- case '[object Number]':
- // `NaN`s are equivalent, but non-reflexive. An `egal` comparison is performed for
- // other numeric values.
- return a != +a ? b != +b : (a === 0 ? 1 / a == 1 / b : a == +b);
- case '[object Date]':
- case '[object Boolean]':
- // Coerce dates and booleans to numeric primitive values. Dates are compared by their
- // millisecond representations. Note that invalid dates with millisecond representations
- // of `NaN` are not equivalent.
- return +a == +b;
- // RegExps are compared by their source patterns and flags.
- case '[object RegExp]':
- return a.source == b.source &&
- a.global == b.global &&
- a.multiline == b.multiline &&
- a.ignoreCase == b.ignoreCase;
- }
- if (typeof a != 'object' || typeof b != 'object') { return false; }
-
- var aIsDomNode = j$.isDomNode(a);
- var bIsDomNode = j$.isDomNode(b);
- if (aIsDomNode && bIsDomNode) {
- // At first try to use DOM3 method isEqualNode
- if (a.isEqualNode) {
- return a.isEqualNode(b);
- }
- // IE8 doesn't support isEqualNode, try to use outerHTML && innerText
- var aIsElement = a instanceof Element;
- var bIsElement = b instanceof Element;
- if (aIsElement && bIsElement) {
- return a.outerHTML == b.outerHTML;
- }
- if (aIsElement || bIsElement) {
- return false;
- }
- return a.innerText == b.innerText && a.textContent == b.textContent;
- }
- if (aIsDomNode || bIsDomNode) {
- return false;
- }
-
- // Assume equality for cyclic structures. The algorithm for detecting cyclic
- // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`.
- var length = aStack.length;
- while (length--) {
- // Linear search. Performance is inversely proportional to the number of
- // unique nested structures.
- if (aStack[length] == a) { return bStack[length] == b; }
- }
- // Add the first object to the stack of traversed objects.
- aStack.push(a);
- bStack.push(b);
- var size = 0;
- // Recursively compare objects and arrays.
- // Compare array lengths to determine if a deep comparison is necessary.
- if (className == '[object Array]') {
- size = a.length;
- if (size !== b.length) {
- return false;
- }
-
- while (size--) {
- result = eq(a[size], b[size], aStack, bStack, customTesters);
- if (!result) {
- return false;
- }
- }
- } else {
-
- // Objects with different constructors are not equivalent, but `Object`s
- // or `Array`s from different frames are.
- var aCtor = a.constructor, bCtor = b.constructor;
- if (aCtor !== bCtor && !(isObjectConstructor(aCtor) &&
- isObjectConstructor(bCtor))) {
- return false;
- }
- }
-
- // Deep compare objects.
- var aKeys = keys(a, className == '[object Array]'), key;
- size = aKeys.length;
-
- // Ensure that both objects contain the same number of properties before comparing deep equality.
- if (keys(b, className == '[object Array]').length !== size) { return false; }
-
- while (size--) {
- key = aKeys[size];
- // Deep compare each member
- result = has(b, key) && eq(a[key], b[key], aStack, bStack, customTesters);
-
- if (!result) {
- return false;
- }
- }
- // Remove the first object from the stack of traversed objects.
- aStack.pop();
- bStack.pop();
-
- return result;
-
- function keys(obj, isArray) {
- var allKeys = Object.keys ? Object.keys(obj) :
- (function(o) {
- var keys = [];
- for (var key in o) {
- if (has(o, key)) {
- keys.push(key);
- }
- }
- return keys;
- })(obj);
-
- if (!isArray) {
- return allKeys;
- }
-
- var extraKeys = [];
- if (allKeys.length === 0) {
- return allKeys;
- }
-
- for (var x = 0; x < allKeys.length; x++) {
- if (!allKeys[x].match(/^[0-9]+$/)) {
- extraKeys.push(allKeys[x]);
- }
- }
-
- return extraKeys;
- }
- }
-
- function has(obj, key) {
- return Object.prototype.hasOwnProperty.call(obj, key);
- }
-
- function isFunction(obj) {
- return typeof obj === 'function';
- }
-
- function isObjectConstructor(ctor) {
- // aCtor instanceof aCtor is true for the Object and Function
- // constructors (since a constructor is-a Function and a function is-a
- // Object). We don't just compare ctor === Object because the constructor
- // might come from a different frame with different globals.
- return isFunction(ctor) && ctor instanceof ctor;
- }
-};
-
-getJasmineRequireObj().toBe = function() {
- function toBe() {
- return {
- compare: function(actual, expected) {
- return {
- pass: actual === expected
- };
- }
- };
- }
-
- return toBe;
-};
-
-getJasmineRequireObj().toBeCloseTo = function() {
-
- function toBeCloseTo() {
- return {
- compare: function(actual, expected, precision) {
- if (precision !== 0) {
- precision = precision || 2;
- }
-
- return {
- pass: Math.abs(expected - actual) < (Math.pow(10, -precision) / 2)
- };
- }
- };
- }
-
- return toBeCloseTo;
-};
-
-getJasmineRequireObj().toBeDefined = function() {
- function toBeDefined() {
- return {
- compare: function(actual) {
- return {
- pass: (void 0 !== actual)
- };
- }
- };
- }
-
- return toBeDefined;
-};
-
-getJasmineRequireObj().toBeFalsy = function() {
- function toBeFalsy() {
- return {
- compare: function(actual) {
- return {
- pass: !!!actual
- };
- }
- };
- }
-
- return toBeFalsy;
-};
-
-getJasmineRequireObj().toBeGreaterThan = function() {
-
- function toBeGreaterThan() {
- return {
- compare: function(actual, expected) {
- return {
- pass: actual > expected
- };
- }
- };
- }
-
- return toBeGreaterThan;
-};
-
-
-getJasmineRequireObj().toBeGreaterThanOrEqual = function() {
-
- function toBeGreaterThanOrEqual() {
- return {
- compare: function(actual, expected) {
- return {
- pass: actual >= expected
- };
- }
- };
- }
-
- return toBeGreaterThanOrEqual;
-};
-
-getJasmineRequireObj().toBeLessThan = function() {
- function toBeLessThan() {
- return {
-
- compare: function(actual, expected) {
- return {
- pass: actual < expected
- };
- }
- };
- }
-
- return toBeLessThan;
-};
-getJasmineRequireObj().toBeLessThanOrEqual = function() {
- function toBeLessThanOrEqual() {
- return {
-
- compare: function(actual, expected) {
- return {
- pass: actual <= expected
- };
- }
- };
- }
-
- return toBeLessThanOrEqual;
-};
-
-getJasmineRequireObj().toBeNaN = function(j$) {
-
- function toBeNaN() {
- return {
- compare: function(actual) {
- var result = {
- pass: (actual !== actual)
- };
-
- if (result.pass) {
- result.message = 'Expected actual not to be NaN.';
- } else {
- result.message = function() { return 'Expected ' + j$.pp(actual) + ' to be NaN.'; };
- }
-
- return result;
- }
- };
- }
-
- return toBeNaN;
-};
-
-getJasmineRequireObj().toBeNull = function() {
-
- function toBeNull() {
- return {
- compare: function(actual) {
- return {
- pass: actual === null
- };
- }
- };
- }
-
- return toBeNull;
-};
-
-getJasmineRequireObj().toBeTruthy = function() {
-
- function toBeTruthy() {
- return {
- compare: function(actual) {
- return {
- pass: !!actual
- };
- }
- };
- }
-
- return toBeTruthy;
-};
-
-getJasmineRequireObj().toBeUndefined = function() {
-
- function toBeUndefined() {
- return {
- compare: function(actual) {
- return {
- pass: void 0 === actual
- };
- }
- };
- }
-
- return toBeUndefined;
-};
-
-getJasmineRequireObj().toContain = function() {
- function toContain(util, customEqualityTesters) {
- customEqualityTesters = customEqualityTesters || [];
-
- return {
- compare: function(actual, expected) {
-
- return {
- pass: util.contains(actual, expected, customEqualityTesters)
- };
- }
- };
- }
-
- return toContain;
-};
-
-getJasmineRequireObj().toEqual = function() {
-
- function toEqual(util, customEqualityTesters) {
- customEqualityTesters = customEqualityTesters || [];
-
- return {
- compare: function(actual, expected) {
- var result = {
- pass: false
- };
-
- result.pass = util.equals(actual, expected, customEqualityTesters);
-
- return result;
- }
- };
- }
-
- return toEqual;
-};
-
-getJasmineRequireObj().toHaveBeenCalled = function(j$) {
-
- var getErrorMsg = j$.formatErrorMsg('<toHaveBeenCalled>', 'expect(<spyObj>).toHaveBeenCalled()');
-
- function toHaveBeenCalled() {
- return {
- compare: function(actual) {
- var result = {};
-
- if (!j$.isSpy(actual)) {
- throw new Error(getErrorMsg('Expected a spy, but got ' + j$.pp(actual) + '.'));
- }
-
- if (arguments.length > 1) {
- throw new Error(getErrorMsg('Does not take arguments, use toHaveBeenCalledWith'));
- }
-
- result.pass = actual.calls.any();
-
- result.message = result.pass ?
- 'Expected spy ' + actual.and.identity() + ' not to have been called.' :
- 'Expected spy ' + actual.and.identity() + ' to have been called.';
-
- return result;
- }
- };
- }
-
- return toHaveBeenCalled;
-};
-
-getJasmineRequireObj().toHaveBeenCalledTimes = function(j$) {
-
- var getErrorMsg = j$.formatErrorMsg('<toHaveBeenCalledTimes>', 'expect(<spyObj>).toHaveBeenCalledTimes(<Number>)');
-
- function toHaveBeenCalledTimes() {
- return {
- compare: function(actual, expected) {
- if (!j$.isSpy(actual)) {
- throw new Error(getErrorMsg('Expected a spy, but got ' + j$.pp(actual) + '.'));
- }
-
- var args = Array.prototype.slice.call(arguments, 0),
- result = { pass: false };
-
- if (!j$.isNumber_(expected)){
- throw new Error(getErrorMsg('The expected times failed is a required argument and must be a number.'));
- }
-
- actual = args[0];
- var calls = actual.calls.count();
- var timesMessage = expected === 1 ? 'once' : expected + ' times';
- result.pass = calls === expected;
- result.message = result.pass ?
- 'Expected spy ' + actual.and.identity() + ' not to have been called ' + timesMessage + '. It was called ' + calls + ' times.' :
- 'Expected spy ' + actual.and.identity() + ' to have been called ' + timesMessage + '. It was called ' + calls + ' times.';
- return result;
- }
- };
- }
-
- return toHaveBeenCalledTimes;
-};
-
-getJasmineRequireObj().toHaveBeenCalledWith = function(j$) {
-
- var getErrorMsg = j$.formatErrorMsg('<toHaveBeenCalledWith>', 'expect(<spyObj>).toHaveBeenCalledWith(...arguments)');
-
- function toHaveBeenCalledWith(util, customEqualityTesters) {
- return {
- compare: function() {
- var args = Array.prototype.slice.call(arguments, 0),
- actual = args[0],
- expectedArgs = args.slice(1),
- result = { pass: false };
-
- if (!j$.isSpy(actual)) {
- throw new Error(getErrorMsg('Expected a spy, but got ' + j$.pp(actual) + '.'));
- }
-
- if (!actual.calls.any()) {
- result.message = function() { return 'Expected spy ' + actual.and.identity() + ' to have been called with ' + j$.pp(expectedArgs) + ' but it was never called.'; };
- return result;
- }
-
- if (util.contains(actual.calls.allArgs(), expectedArgs, customEqualityTesters)) {
- result.pass = true;
- result.message = function() { return 'Expected spy ' + actual.and.identity() + ' not to have been called with ' + j$.pp(expectedArgs) + ' but it was.'; };
- } else {
- result.message = function() { return 'Expected spy ' + actual.and.identity() + ' to have been called with ' + j$.pp(expectedArgs) + ' but actual calls were ' + j$.pp(actual.calls.allArgs()).replace(/^\[ | \]$/g, '') + '.'; };
- }
-
- return result;
- }
- };
- }
-
- return toHaveBeenCalledWith;
-};
-
-getJasmineRequireObj().toMatch = function(j$) {
-
- var getErrorMsg = j$.formatErrorMsg('<toMatch>', 'expect(<expectation>).toMatch(<string> || <regexp>)');
-
- function toMatch() {
- return {
- compare: function(actual, expected) {
- if (!j$.isString_(expected) && !j$.isA_('RegExp', expected)) {
- throw new Error(getErrorMsg('Expected is not a String or a RegExp'));
- }
-
- var regexp = new RegExp(expected);
-
- return {
- pass: regexp.test(actual)
- };
- }
- };
- }
-
- return toMatch;
-};
-
-getJasmineRequireObj().toThrow = function(j$) {
-
- var getErrorMsg = j$.formatErrorMsg('<toThrow>', 'expect(function() {<expectation>}).toThrow()');
-
- function toThrow(util) {
- return {
- compare: function(actual, expected) {
- var result = { pass: false },
- threw = false,
- thrown;
-
- if (typeof actual != 'function') {
- throw new Error(getErrorMsg('Actual is not a Function'));
- }
-
- try {
- actual();
- } catch (e) {
- threw = true;
- thrown = e;
- }
-
- if (!threw) {
- result.message = 'Expected function to throw an exception.';
- return result;
- }
-
- if (arguments.length == 1) {
- result.pass = true;
- result.message = function() { return 'Expected function not to throw, but it threw ' + j$.pp(thrown) + '.'; };
-
- return result;
- }
-
- if (util.equals(thrown, expected)) {
- result.pass = true;
- result.message = function() { return 'Expected function not to throw ' + j$.pp(expected) + '.'; };
- } else {
- result.message = function() { return 'Expected function to throw ' + j$.pp(expected) + ', but it threw ' + j$.pp(thrown) + '.'; };
- }
-
- return result;
- }
- };
- }
-
- return toThrow;
-};
-
-getJasmineRequireObj().toThrowError = function(j$) {
-
- var getErrorMsg = j$.formatErrorMsg('<toThrowError>', 'expect(function() {<expectation>}).toThrowError(<ErrorConstructor>, <message>)');
-
- function toThrowError () {
- return {
- compare: function(actual) {
- var threw = false,
- pass = {pass: true},
- fail = {pass: false},
- thrown;
-
- if (typeof actual != 'function') {
- throw new Error(getErrorMsg('Actual is not a Function'));
- }
-
- var errorMatcher = getMatcher.apply(null, arguments);
-
- try {
- actual();
- } catch (e) {
- threw = true;
- thrown = e;
- }
-
- if (!threw) {
- fail.message = 'Expected function to throw an Error.';
- return fail;
- }
-
- if (!(thrown instanceof Error)) {
- fail.message = function() { return 'Expected function to throw an Error, but it threw ' + j$.pp(thrown) + '.'; };
- return fail;
- }
-
- if (errorMatcher.hasNoSpecifics()) {
- pass.message = 'Expected function not to throw an Error, but it threw ' + j$.fnNameFor(thrown) + '.';
- return pass;
- }
-
- if (errorMatcher.matches(thrown)) {
- pass.message = function() {
- return 'Expected function not to throw ' + errorMatcher.errorTypeDescription + errorMatcher.messageDescription() + '.';
- };
- return pass;
- } else {
- fail.message = function() {
- return 'Expected function to throw ' + errorMatcher.errorTypeDescription + errorMatcher.messageDescription() +
- ', but it threw ' + errorMatcher.thrownDescription(thrown) + '.';
- };
- return fail;
- }
- }
- };
-
- function getMatcher() {
- var expected = null,
- errorType = null;
-
- if (arguments.length == 2) {
- expected = arguments[1];
- if (isAnErrorType(expected)) {
- errorType = expected;
- expected = null;
- }
- } else if (arguments.length > 2) {
- errorType = arguments[1];
- expected = arguments[2];
- if (!isAnErrorType(errorType)) {
- throw new Error(getErrorMsg('Expected error type is not an Error.'));
- }
- }
-
- if (expected && !isStringOrRegExp(expected)) {
- if (errorType) {
- throw new Error(getErrorMsg('Expected error message is not a string or RegExp.'));
- } else {
- throw new Error(getErrorMsg('Expected is not an Error, string, or RegExp.'));
- }
- }
-
- function messageMatch(message) {
- if (typeof expected == 'string') {
- return expected == message;
- } else {
- return expected.test(message);
- }
- }
-
- return {
- errorTypeDescription: errorType ? j$.fnNameFor(errorType) : 'an exception',
- thrownDescription: function(thrown) {
- var thrownName = errorType ? j$.fnNameFor(thrown.constructor) : 'an exception',
- thrownMessage = '';
-
- if (expected) {
- thrownMessage = ' with message ' + j$.pp(thrown.message);
- }
-
- return thrownName + thrownMessage;
- },
- messageDescription: function() {
- if (expected === null) {
- return '';
- } else if (expected instanceof RegExp) {
- return ' with a message matching ' + j$.pp(expected);
- } else {
- return ' with message ' + j$.pp(expected);
- }
- },
- hasNoSpecifics: function() {
- return expected === null && errorType === null;
- },
- matches: function(error) {
- return (errorType === null || error instanceof errorType) &&
- (expected === null || messageMatch(error.message));
- }
- };
- }
-
- function isStringOrRegExp(potential) {
- return potential instanceof RegExp || (typeof potential == 'string');
- }
-
- function isAnErrorType(type) {
- if (typeof type !== 'function') {
- return false;
- }
-
- var Surrogate = function() {};
- Surrogate.prototype = type.prototype;
- return (new Surrogate()) instanceof Error;
- }
- }
-
- return toThrowError;
-};
-
-getJasmineRequireObj().interface = function(jasmine, env) {
- var jasmineInterface = {
- describe: function(description, specDefinitions) {
- return env.describe(description, specDefinitions);
- },
-
- xdescribe: function(description, specDefinitions) {
- return env.xdescribe(description, specDefinitions);
- },
-
- fdescribe: function(description, specDefinitions) {
- return env.fdescribe(description, specDefinitions);
- },
-
- it: function() {
- return env.it.apply(env, arguments);
- },
-
- xit: function() {
- return env.xit.apply(env, arguments);
- },
-
- fit: function() {
- return env.fit.apply(env, arguments);
- },
-
- beforeEach: function() {
- return env.beforeEach.apply(env, arguments);
- },
-
- afterEach: function() {
- return env.afterEach.apply(env, arguments);
- },
-
- beforeAll: function() {
- return env.beforeAll.apply(env, arguments);
- },
-
- afterAll: function() {
- return env.afterAll.apply(env, arguments);
- },
-
- expect: function(actual) {
- return env.expect(actual);
- },
-
- pending: function() {
- return env.pending.apply(env, arguments);
- },
-
- fail: function() {
- return env.fail.apply(env, arguments);
- },
-
- spyOn: function(obj, methodName) {
- return env.spyOn(obj, methodName);
- },
-
- jsApiReporter: new jasmine.JsApiReporter({
- timer: new jasmine.Timer()
- }),
-
- jasmine: jasmine
- };
-
- jasmine.addCustomEqualityTester = function(tester) {
- env.addCustomEqualityTester(tester);
- };
-
- jasmine.addMatchers = function(matchers) {
- return env.addMatchers(matchers);
- };
-
- jasmine.clock = function() {
- return env.clock;
- };
-
- return jasmineInterface;
-};
-
getJasmineRequireObj().version = function() {
- return '2.5.2';
+ return '2.6.0';
};
diff --git a/spec/lib/jasmine-2.5.2/jasmine_favicon.png b/spec/lib/jasmine-2.6.0/jasmine_favicon.png
index 3b84583..3b84583 100644
--- a/spec/lib/jasmine-2.5.2/jasmine_favicon.png
+++ b/spec/lib/jasmine-2.6.0/jasmine_favicon.png
Binary files differ
diff --git a/spec/spec/fx.js b/spec/spec/fx.js
index e7aad57..4a54229 100644
--- a/spec/spec/fx.js
+++ b/spec/spec/fx.js
@@ -1227,6 +1227,15 @@ describe('FX', function() {
fx.step()
expect(called).toBe(true)
})
+
+ it('adds the callback on the last situation', function () {
+ var callback = function () {}
+
+ fx.animate(500).animate(500).once(0.5, callback)
+ expect(fx.situation.once['0.5']).toBeUndefined()
+ expect(fx.situations[0].once['0.5']).toBeUndefined()
+ expect(fx.situations[1].once['0.5']).toBe(callback)
+ })
})
@@ -1666,18 +1675,35 @@ describe('FX', function() {
expect(fx.pos).toBe(1) // It should end not reversed, which mean the position is expected to be 1
// ((9-1)-6) is even, the -1 is because we do not want reversed to be toggled after the last loop
})
+ })
- it('should not throw an error when stop is called in a during callback', function () {
- fx.move(100,100).start()
- fx.during(function () {this.stop()})
- expect(fx.step.bind(fx)).not.toThrow()
- })
- it('should not throw an error when finish is called in a during callback', function () {
- fx.move(100,100).start()
- fx.during(function () {this.finish()})
- expect(fx.step.bind(fx)).not.toThrow()
- })
+ it('should not throw an error when stop is called in a during callback', function () {
+ fx.move(100,100).start()
+ fx.during(function () {this.stop()})
+ expect(fx.step.bind(fx)).not.toThrow()
+ })
+
+ it('should not throw an error when finish is called in a during callback', function () {
+ fx.move(100,100).start()
+ fx.during(function () {this.finish()})
+ expect(fx.step.bind(fx)).not.toThrow()
+ })
+
+ it('should not set active to false if the afterAll callback add situations to the situations queue', function () {
+ fx.afterAll(function(){this.animate(500).move(0,0)})
+
+ jasmine.clock().tick(500)
+ fx.step()
+ expect(fx.active).toBe(true)
+ expect(fx.situation).not.toBeNull()
+ expect(fx.situations.length).toBe(0)
+
+ jasmine.clock().tick(500)
+ fx.step()
+ expect(fx.active).toBe(false)
+ expect(fx.situation).toBeNull()
+ expect(fx.situations.length).toBe(0)
})
})
@@ -2531,6 +2557,48 @@ describe('FX', function() {
})
})
+ describe('width()', function() {
+ it('should set width with add()', function() {
+ spyOn(fx, 'add').and.callThrough()
+ fx.width(20)
+ expect(fx.add).toHaveBeenCalledWith('width', jasmine.objectContaining({value:20}))
+ })
+
+ it('should animate the width attribute', function() {
+ fx.width(200)
+ expect(rect.width()).toBe(100)
+
+ jasmine.clock().tick(250)
+ fx.step()
+ expect(rect.width()).toBe(150)
+
+ jasmine.clock().tick(250)
+ fx.step()
+ expect(rect.width()).toBe(200)
+ })
+ })
+
+ describe('height()', function() {
+ it('should set height with add()', function() {
+ spyOn(fx, 'add').and.callThrough()
+ fx.height(20)
+ expect(fx.add).toHaveBeenCalledWith('height', jasmine.objectContaining({value:20}))
+ })
+
+ it('should animate the height attribute', function() {
+ fx.height(200)
+ expect(rect.height()).toBe(100)
+
+ jasmine.clock().tick(250)
+ fx.step()
+ expect(rect.height()).toBe(150)
+
+ jasmine.clock().tick(250)
+ fx.step()
+ expect(rect.height()).toBe(200)
+ })
+ })
+
describe('plot()', function() {
it('should call add with plot as method', function() {
var polyline = draw.polyline('10 10 20 20 30 10 50 20')
@@ -2538,7 +2606,7 @@ describe('FX', function() {
spyOn(fx, 'add')
fx.plot('5 5 30 29 40 19 12 30')
- expect(fx.add).toHaveBeenCalledWith('plot', '5 5 30 29 40 19 12 30')
+ expect(fx.add).toHaveBeenCalledWith('plot', new SVG.PointArray('5 5 30 29 40 19 12 30'))
})
it('also accept parameter list', function() {
@@ -2547,7 +2615,7 @@ describe('FX', function() {
spyOn(fx, 'add')
fx.plot(5, 5, 10, 10)
- expect(fx.add).toHaveBeenCalledWith('plot', [5, 5, 10, 10])
+ expect(fx.add).toHaveBeenCalledWith('plot', new SVG.PointArray([5, 5, 10, 10]))
})
})
diff --git a/src/fx.js b/src/fx.js
index b2b5d29..46276ed 100644
--- a/src/fx.js
+++ b/src/fx.js
@@ -214,7 +214,7 @@ SVG.FX = SVG.invent({
// updates all animations to the current state of the element
// this is important when one property could be changed from another property
, initAnimations: function() {
- var i, source
+ var i, j, source
var s = this.situation
if(s.init) return this
@@ -222,12 +222,26 @@ SVG.FX = SVG.invent({
for(i in s.animations){
source = this.target()[i]()
- // The condition is because some methods return a normal number instead
- // of a SVG.Number
- if(s.animations[i] instanceof SVG.Number)
- source = new SVG.Number(source)
+ if(!Array.isArray(source)) {
+ source = [source]
+ }
+
+ if(!Array.isArray(s.animations[i])) {
+ s.animations[i] = [s.animations[i]]
+ }
+
+ //if(s.animations[i].length > source.length) {
+ // source.concat = source.concat(s.animations[i].slice(source.length, s.animations[i].length))
+ //}
- s.animations[i] = source.morph(s.animations[i])
+ for(j = source.length; j--;) {
+ // The condition is because some methods return a normal number instead
+ // of a SVG.Number
+ if(s.animations[i][j] instanceof SVG.Number)
+ source[j] = new SVG.Number(source[j])
+
+ s.animations[i][j] = source[j].morph(s.animations[i][j])
+ }
}
for(i in s.attrs){
@@ -563,8 +577,12 @@ SVG.FX = SVG.invent({
if(!this.situations.length){
this.target().fire('allfinished')
- this.target().off('.fx') // there shouldnt be any binding left, but to make sure...
- this.active = false
+
+ // Recheck the length since the user may call animate in the afterAll callback
+ if(!this.situations.length){
+ this.target().off('.fx') // there shouldnt be any binding left, but to make sure...
+ this.active = false
+ }
}
// start next animation
@@ -660,10 +678,10 @@ SVG.FX = SVG.invent({
// adds an once-callback which is called at a specific position and never again
, once: function(pos, fn, isEased){
+ var c = this.last()
+ if(!isEased) pos = c.ease(pos)
- if(!isEased)pos = this.situation.ease(pos)
-
- this.situation.once[pos] = fn
+ c.once[pos] = fn
return this
}
@@ -732,6 +750,8 @@ SVG.MorphObj = SVG.invent({
create: function(from, to){
// prepare color for morphing
if(SVG.Color.isColor(to)) return new SVG.Color(from).morph(to)
+ // prepare value list for morphing
+ if(SVG.regex.delimiter.test(from)) return new SVG.Array(from).morph(to)
// prepare number for morphing
if(SVG.regex.numberAndUnit.test(to)) return new SVG.Number(from).morph(to)
@@ -844,10 +864,22 @@ SVG.extend(SVG.FX, {
return this
}
+ // Add animatable width
+, width: function(width) {
+ return this.add('width', new SVG.Number(width))
+ }
+ // Add animatable height
+, height: function(height) {
+ return this.add('height', new SVG.Number(height))
+ }
// Add animatable plot
-, plot: function() {
- // We use arguments here since SVG.Line's plot method can be passed 4 parameters
- return this.add('plot', arguments.length > 1 ? [].slice.call(arguments) : arguments[0])
+, plot: function(a, b, c, d) {
+ // Lines can be plotted with 4 arguments
+ if(arguments.length == 4) {
+ return this.plot([a, b, c, d])
+ }
+
+ return this.add('plot', new (this.target().morphArray)(a))
}
// Add leading method
, leading: function(value) {
diff --git a/src/matrix.js b/src/matrix.js
index 7b8ced9..449f8b6 100644
--- a/src/matrix.js
+++ b/src/matrix.js
@@ -17,7 +17,7 @@ SVG.Matrix = SVG.invent({
// merge source
for (i = abcdef.length - 1; i >= 0; --i)
- this[abcdef[i]] = source && typeof source[abcdef[i]] === 'number' ?
+ this[abcdef[i]] = source[abcdef[i]] != null ?
source[abcdef[i]] : base[abcdef[i]]
}
diff --git a/src/textpath.js b/src/textpath.js
index 4750310..18e2149 100644
--- a/src/textpath.js
+++ b/src/textpath.js
@@ -10,8 +10,9 @@ SVG.TextPath = SVG.invent({
// Add parent method
, construct: {
+ morphArray: SVG.PathArray
// Create path for text to run on
- path: function(d) {
+ , path: function(d) {
// create textPath element
var path = new SVG.TextPath
, track = this.doc().defs().path(d)
diff --git a/svg.js.d.ts b/svg.js.d.ts
index ec803bd..f87f831 100644
--- a/svg.js.d.ts
+++ b/svg.js.d.ts
@@ -62,6 +62,7 @@ declare namespace svgjs {
// attr.js
interface Element {
+ attr(): object;
attr(name: string): any;
attr(obj: Object): this;
attr(name: string, value: any, namespace?: string): this;
@@ -215,7 +216,7 @@ declare namespace svgjs {
namespace(): this;
defs(): Defs;
parent(): HTMLElement;
- spof(spof): this;
+ spof(): this;
remove(): this;
}
interface Library { Doc: Doc; }
@@ -363,7 +364,7 @@ declare namespace svgjs {
at(opts: StopProperties): Stop;
update(block?: Function): this;
fill(): string;
- fill(...any): never;
+ fill(...params: any[]): never;
toString(): string;
from(x: number, y: number): this;
to(x: number, y: number): this;
@@ -392,7 +393,7 @@ declare namespace svgjs {
to(): string;
show(target: string): this;
show(): string;
- show(...any): never;
+ show(...params: any[]): never;
target(target: string): this;
target(): string;
}
@@ -637,7 +638,7 @@ declare namespace svgjs {
export interface Pattern extends Container {
new (): Pattern;
fill(): string;
- fill(...any): never;
+ fill(...rest: any[]): never;
update(block: (pattern: Pattern) => void): this;
toString(): string;
}
@@ -712,6 +713,7 @@ declare namespace svgjs {
// rect.js
export interface Rect extends Shape {
new (): Rect;
+ radius(x: number, y?: number): this;
}
interface Library { Rect: Rect; }
interface Container {
@@ -821,9 +823,9 @@ declare namespace svgjs {
}
interface FontData {
family?: string;
- size?: number;
+ size?: NumberAlias;
anchor?: string;
- leading?: string;
+ leading?: NumberAlias;
weight?: string;
style?: string
}
@@ -842,8 +844,9 @@ declare namespace svgjs {
text(text: string): this;
text(block: (text: Text) => void): this;
size(fontSize: NumberAlias): this;
- leading(leading: number): this;
- lines(): number;
+ leading(): number;
+ leading(leading: NumberAlias): this;
+ lines(): Set;
rebuild(enabled: boolean): this;
build(enabled: boolean): this;
plain(text: string): this;
@@ -913,7 +916,7 @@ declare namespace svgjs {
f?: number;
}
export interface Transformation {
- new (...Transform): Transformation;
+ new (...transform: Transform[]): Transformation;
new (source: Transform, inversed?: boolean): Transformation;
at(pos: number): Matrix;
undo(transform: Transform): this
@@ -986,6 +989,7 @@ declare namespace svgjs {
attr(name: string, value: any, namespace?: string): Animation;
attr(obj: Object): Animation;
attr(name: string): any;
+ attr(): object;
viewbox(x: number, y: number, w: number, h: number): Animation;