From b88691d1f3acc3698bb60c7b8823242977f9ac8a Mon Sep 17 00:00:00 2001 From: jfh Date: Sun, 13 Sep 2020 23:56:45 +0200 Subject: [PATCH] fix issue with the snapshot --- badges/coverage-badge.svg | 2 +- cypress.json | 16 +- .../ui/__snapshots__/scenario.js.snap | 273 ++++++++++++++++-- cypress/integration/ui/scenario.js | 7 +- .../extensions/ext-closepath/ext-closepath.js | 10 +- .../ext-closepath/ext-closepath.js.map | 2 +- .../ext-server_moinsave.js | 10 +- .../ext-server_moinsave.js.map | 2 +- .../ext-server_opensave.js | 10 +- .../ext-server_opensave.js.map | 2 +- dist/editor/index.js | 66 ++--- dist/editor/index.js.map | 2 +- .../extensions/ext-closepath/ext-closepath.js | 10 +- .../ext-server_moinsave.js | 10 +- .../ext-server_opensave.js | 10 +- dist/editor/system/index.js | 68 ++--- dist/editor/xdomain-index.js | 66 ++--- dist/editor/xdomain-index.js.map | 2 +- package.json | 2 +- 19 files changed, 369 insertions(+), 201 deletions(-) diff --git a/badges/coverage-badge.svg b/badges/coverage-badge.svg index 75a99de5..3af32e51 100644 --- a/badges/coverage-badge.svg +++ b/badges/coverage-badge.svg @@ -1 +1 @@ -Statements 50.85%Statements 50.85%Branches 40.85%Branches 40.85%Lines 51.98%Lines 51.98%Functions 55.1%Functions 55.1% +Statements 50.84%Statements 50.84%Branches 40.85%Branches 40.85%Lines 51.96%Lines 51.96%Functions 55.04%Functions 55.04% diff --git a/cypress.json b/cypress.json index c7dd025e..e76775b3 100644 --- a/cypress.json +++ b/cypress.json @@ -5,15 +5,13 @@ "reporterOptions": { "configFile": "mocha-multi-reporters.json" }, - "ignoreTestFiles": [ - "**/__snapshots__/*", - "**/__image_snapshots__/*" - ], - "defaultCommandTimeout": 10000, + "ignoreTestFiles": ["**/__snapshots__/*", "**/__image_snapshots__/*"], + "defaultCommandTimeout": 10000, "pageLoadTimeout": 120000, "cypress-plugin-snapshots": { - "autoCleanUp": true, - "prettier": false, - "updateSnapshots": false + "autoCleanUp": true, + "prettier": true, + "updateSnapshots": false, + "diffLines": 5 } -} \ No newline at end of file +} diff --git a/cypress/integration/ui/__snapshots__/scenario.js.snap b/cypress/integration/ui/__snapshots__/scenario.js.snap index 7be0291e..d5d1ca50 100644 --- a/cypress/integration/ui/__snapshots__/scenario.js.snap +++ b/cypress/integration/ui/__snapshots__/scenario.js.snap @@ -1,51 +1,260 @@ exports[`use various parts of svg-edit > check tool_source #0`] = ` - - - Layer 1 - - + + + Layer 1 + + `; exports[`use various parts of svg-edit > check tool_text #0`] = ` - - - Layer 1 - - B - + + + Layer 1 + + + B + + `; exports[`use various parts of svg-edit > check tool_clone #0`] = ` - - - Layer 1 - - B - B - + + + Layer 1 + + + B + + + B + + `; exports[`use various parts of svg-edit > check tool_italic #0`] = ` - - - Layer 1 - - B - B - + + + Layer 1 + + + B + + + B + + `; exports[`use various parts of svg-edit > check tool_bold #0`] = ` - - - Layer 1 - - B - B - + + + Layer 1 + + + B + + + B + + `; diff --git a/cypress/integration/ui/scenario.js b/cypress/integration/ui/scenario.js index 8418cabe..2ca77a23 100644 --- a/cypress/integration/ui/scenario.js +++ b/cypress/integration/ui/scenario.js @@ -3,9 +3,10 @@ import { } from '../../support/ui-test-helper.js'; const testSnapshot = () => { - cy.get('#tool_source').click({force: true}); - cy.get('#svg_source_textarea').invoke('val').toMatchSnapshot(); - cy.get('#tool_source_save').click({force: true}); + // cy.get('#tool_source').click({force: true}); + // cy.get('#svg_source_textarea').invoke('val').toMatchSnapshot(); + // cy.get('#tool_source_save').click({force: true}); + cy.get('#svgcontent').toMatchSnapshot(); }; describe('use various parts of svg-edit', function () { diff --git a/dist/editor/extensions/ext-closepath/ext-closepath.js b/dist/editor/extensions/ext-closepath/ext-closepath.js index 176c219c..5cc4a086 100644 --- a/dist/editor/extensions/ext-closepath/ext-closepath.js +++ b/dist/editor/extensions/ext-closepath/ext-closepath.js @@ -1,2 +1,10 @@ -var t="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{};function createCommonjsModule(t,e,n){return t(n={path:e,exports:{},require:function(t,e){return function commonjsRequire(){throw new Error("Dynamic requires are not currently supported by @rollup/plugin-commonjs")}(null==e&&n.path)}},n.exports),n.exports}var check=function(t){return t&&t.Math==Math&&t},e=check("object"==typeof globalThis&&globalThis)||check("object"==typeof window&&window)||check("object"==typeof self&&self)||check("object"==typeof t&&t)||Function("return this")(),fails=function(t){try{return!!t()}catch(t){return!0}},n=!fails((function(){return 7!=Object.defineProperty({},1,{get:function(){return 7}})[1]})),r={}.propertyIsEnumerable,i=Object.getOwnPropertyDescriptor,o={f:i&&!r.call({1:2},1)?function propertyIsEnumerable(t){var e=i(this,t);return!!e&&e.enumerable}:r},createPropertyDescriptor=function(t,e){return{enumerable:!(1&t),configurable:!(2&t),writable:!(4&t),value:e}},a={}.toString,classofRaw=function(t){return a.call(t).slice(8,-1)},s="".split,u=fails((function(){return!Object("z").propertyIsEnumerable(0)}))?function(t){return"String"==classofRaw(t)?s.call(t,""):Object(t)}:Object,requireObjectCoercible=function(t){if(null==t)throw TypeError("Can't call method on "+t);return t},toIndexedObject=function(t){return u(requireObjectCoercible(t))},isObject=function(t){return"object"==typeof t?null!==t:"function"==typeof t},toPrimitive=function(t,e){if(!isObject(t))return t;var n,r;if(e&&"function"==typeof(n=t.toString)&&!isObject(r=n.call(t)))return r;if("function"==typeof(n=t.valueOf)&&!isObject(r=n.call(t)))return r;if(!e&&"function"==typeof(n=t.toString)&&!isObject(r=n.call(t)))return r;throw TypeError("Can't convert object to primitive value")},c={}.hasOwnProperty,has=function(t,e){return c.call(t,e)},h=e.document,l=isObject(h)&&isObject(h.createElement),documentCreateElement=function(t){return l?h.createElement(t):{}},_=!n&&!fails((function(){return 7!=Object.defineProperty(documentCreateElement("div"),"a",{get:function(){return 7}}).a})),f=Object.getOwnPropertyDescriptor,g={f:n?f:function getOwnPropertyDescriptor(t,e){if(t=toIndexedObject(t),e=toPrimitive(e,!0),_)try{return f(t,e)}catch(t){}if(has(t,e))return createPropertyDescriptor(!o.f.call(t,e),t[e])}},anObject=function(t){if(!isObject(t))throw TypeError(String(t)+" is not an object");return t},S=Object.defineProperty,p={f:n?S:function defineProperty(t,e,n){if(anObject(t),e=toPrimitive(e,!0),anObject(n),_)try{return S(t,e,n)}catch(t){}if("get"in n||"set"in n)throw TypeError("Accessors not supported");return"value"in n&&(t[e]=n.value),t}},y=n?function(t,e,n){return p.f(t,e,createPropertyDescriptor(1,n))}:function(t,e,n){return t[e]=n,t},setGlobal=function(t,n){try{y(e,t,n)}catch(r){e[t]=n}return n},v=e["__core-js_shared__"]||setGlobal("__core-js_shared__",{}),d=Function.toString;"function"!=typeof v.inspectSource&&(v.inspectSource=function(t){return d.call(t)});var m,P,b,A=v.inspectSource,C=e.WeakMap,G="function"==typeof C&&/native code/.test(A(C)),V=createCommonjsModule((function(t){(t.exports=function(t,e){return v[t]||(v[t]=void 0!==e?e:{})})("versions",[]).push({version:"3.6.5",mode:"global",copyright:"© 2020 Denis Pushkarev (zloirock.ru)"})})),x=0,E=Math.random(),uid=function(t){return"Symbol("+String(void 0===t?"":t)+")_"+(++x+E).toString(36)},T=V("keys"),sharedKey=function(t){return T[t]||(T[t]=uid(t))},w={},O=e.WeakMap;if(G){var L=new O,R=L.get,I=L.has,k=L.set;m=function(t,e){return k.call(L,t,e),e},P=function(t){return R.call(L,t)||{}},b=function(t){return I.call(L,t)}}else{var j=sharedKey("state");w[j]=!0,m=function(t,e){return y(t,j,e),e},P=function(t){return has(t,j)?t[j]:{}},b=function(t){return has(t,j)}}var H,N,M={set:m,get:P,has:b,enforce:function(t){return b(t)?P(t):m(t,{})},getterFor:function(t){return function(e){var n;if(!isObject(e)||(n=P(e)).type!==t)throw TypeError("Incompatible receiver, "+t+" required");return n}}},U=createCommonjsModule((function(t){var n=M.get,r=M.enforce,i=String(String).split("String");(t.exports=function(t,n,o,a){var s=!!a&&!!a.unsafe,u=!!a&&!!a.enumerable,c=!!a&&!!a.noTargetGet;"function"==typeof o&&("string"!=typeof n||has(o,"name")||y(o,"name",n),r(o).source=i.join("string"==typeof n?n:"")),t!==e?(s?!c&&t[n]&&(u=!0):delete t[n],u?t[n]=o:y(t,n,o)):u?t[n]=o:setGlobal(n,o)})(Function.prototype,"toString",(function toString(){return"function"==typeof this&&n(this).source||A(this)}))})),B=e,aFunction=function(t){return"function"==typeof t?t:void 0},getBuiltIn=function(t,n){return arguments.length<2?aFunction(B[t])||aFunction(e[t]):B[t]&&B[t][n]||e[t]&&e[t][n]},Q=Math.ceil,D=Math.floor,toInteger=function(t){return isNaN(t=+t)?0:(t>0?D:Q)(t)},z=Math.min,toLength=function(t){return t>0?z(toInteger(t),9007199254740991):0},W=Math.max,q=Math.min,toAbsoluteIndex=function(t,e){var n=toInteger(t);return n<0?W(n+e,0):q(n,e)},createMethod=function(t){return function(e,n,r){var i,o=toIndexedObject(e),a=toLength(o.length),s=toAbsoluteIndex(r,a);if(t&&n!=n){for(;a>s;)if((i=o[s++])!=i)return!0}else for(;a>s;s++)if((t||s in o)&&o[s]===n)return t||s||0;return!t&&-1}},K={includes:createMethod(!0),indexOf:createMethod(!1)}.indexOf,objectKeysInternal=function(t,e){var n,r=toIndexedObject(t),i=0,o=[];for(n in r)!has(w,n)&&has(r,n)&&o.push(n);for(;e.length>i;)has(r,n=e[i++])&&(~K(o,n)||o.push(n));return o},Z=["constructor","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","toLocaleString","toString","valueOf"],Y=Z.concat("length","prototype"),$={f:Object.getOwnPropertyNames||function getOwnPropertyNames(t){return objectKeysInternal(t,Y)}},J={f:Object.getOwnPropertySymbols},X=getBuiltIn("Reflect","ownKeys")||function ownKeys(t){var e=$.f(anObject(t)),n=J.f;return n?e.concat(n(t)):e},copyConstructorProperties=function(t,e){for(var n=X(e),r=p.f,i=g.f,o=0;ov;v++)if((a||v in S)&&(f=p(_=S[v],v,g),t))if(e)m[v]=f;else if(f)switch(t){case 3:return!0;case 5:return _;case 6:return v;case 2:gt.call(m,_)}else if(i)return!1;return o?-1:r||i?i:m}},St={forEach:createMethod$1(0),map:createMethod$1(1),filter:createMethod$1(2),some:createMethod$1(3),every:createMethod$1(4),find:createMethod$1(5),findIndex:createMethod$1(6)},pt=getBuiltIn("navigator","userAgent")||"",yt=e.process,vt=yt&&yt.versions,dt=vt&&vt.v8;dt?N=(H=dt.split("."))[0]+H[1]:pt&&(!(H=pt.match(/Edge\/(\d+)/))||H[1]>=74)&&(H=pt.match(/Chrome\/(\d+)/))&&(N=H[1]);var mt=N&&+N,Pt=wellKnownSymbol("species"),arrayMethodHasSpeciesSupport=function(t){return mt>=51||!fails((function(){var e=[];return(e.constructor={})[Pt]=function(){return{foo:1}},1!==e[t](Boolean).foo}))},bt=Object.defineProperty,At={},thrower=function(t){throw t},arrayMethodUsesToLength=function(t,e){if(has(At,t))return At[t];e||(e={});var r=[][t],i=!!has(e,"ACCESSORS")&&e.ACCESSORS,o=has(e,0)?e[0]:thrower,a=has(e,1)?e[1]:void 0;return At[t]=!!r&&!fails((function(){if(i&&!n)return!0;var t={length:-1};i?bt(t,1,{enumerable:!0,get:thrower}):t[1]=1,r.call(t,o,a)}))},Ct=St.map,Gt=arrayMethodHasSpeciesSupport("map"),Vt=arrayMethodUsesToLength("map");_export({target:"Array",proto:!0,forced:!Gt||!Vt},{map:function map(t){return Ct(this,t,arguments.length>1?arguments[1]:void 0)}});var xt=p.f,Et=Function.prototype,Tt=Et.toString,wt=/^\s*function ([^ (]*)/;n&&!("name"in Et)&&xt(Et,"name",{configurable:!0,get:function(){try{return Tt.call(this).match(wt)[1]}catch(t){return""}}});var Ot=Object.keys||function keys(t){return objectKeysInternal(t,Z)},Lt=Object.assign,Rt=Object.defineProperty,It=!Lt||fails((function(){if(n&&1!==Lt({b:1},Lt(Rt({},"a",{enumerable:!0,get:function(){Rt(this,"b",{value:3,enumerable:!1})}}),{b:2})).b)return!0;var t={},e={},r=Symbol(),i="abcdefghijklmnopqrst";return t[r]=7,i.split("").forEach((function(t){e[t]=t})),7!=Lt({},t)[r]||Ot(Lt({},e)).join("")!=i}))?function assign(t,e){for(var r=toObject(t),i=arguments.length,a=1,s=J.f,c=o.f;i>a;)for(var h,l=u(arguments[a++]),_=s?Ot(l).concat(s(l)):Ot(l),f=_.length,g=0;f>g;)h=_[g++],n&&!c.call(l,h)||(r[h]=l[h]);return r}:Lt;_export({target:"Object",stat:!0,forced:Object.assign!==It},{assign:It});var kt={};kt[wellKnownSymbol("toStringTag")]="z";var jt="[object z]"===String(kt),Ht=wellKnownSymbol("toStringTag"),Nt="Arguments"==classofRaw(function(){return arguments}()),Mt=jt?classofRaw:function(t){var e,n,r;return void 0===t?"Undefined":null===t?"Null":"string"==typeof(n=function(t,e){try{return t[e]}catch(t){}}(e=Object(t),Ht))?n:Nt?classofRaw(e):"Object"==(r=classofRaw(e))&&"function"==typeof e.callee?"Arguments":r},Ft=jt?{}.toString:function toString(){return"[object "+Mt(this)+"]"};jt||U(Object.prototype,"toString",Ft,{unsafe:!0});var Ut=e.Promise,Bt=p.f,Qt=wellKnownSymbol("toStringTag"),setToStringTag=function(t,e,n){t&&!has(t=n?t:t.prototype,Qt)&&Bt(t,Qt,{configurable:!0,value:e})},Dt=wellKnownSymbol("species"),zt={},Wt=wellKnownSymbol("iterator"),qt=Array.prototype,Kt=wellKnownSymbol("iterator"),callWithSafeIterationClosing=function(t,e,n,r){try{return r?e(anObject(n)[0],n[1]):e(n)}catch(e){var i=t.return;throw void 0!==i&&anObject(i.call(t)),e}},Zt=createCommonjsModule((function(t){var Result=function(t,e){this.stopped=t,this.result=e};(t.exports=function(t,e,n,r,i){var o,a,s,u,c,h,l,_,f=functionBindContext(e,n,r?2:1);if(i)o=t;else{if("function"!=typeof(a=function(t){if(null!=t)return t[Kt]||t["@@iterator"]||zt[Mt(t)]}(t)))throw TypeError("Target is not iterable");if(void 0!==(_=a)&&(zt.Array===_||qt[Wt]===_)){for(s=0,u=toLength(t.length);u>s;s++)if((c=r?f(anObject(l=t[s])[0],l[1]):f(t[s]))&&c instanceof Result)return c;return new Result(!1)}o=a.call(t)}for(h=o.next;!(l=h.call(o)).done;)if("object"==typeof(c=callWithSafeIterationClosing(o,f,l.value,r))&&c&&c instanceof Result)return c;return new Result(!1)}).stop=function(t){return new Result(!0,t)}})),Yt=wellKnownSymbol("iterator"),$t=!1;try{var Jt=0,Xt={next:function(){return{done:!!Jt++}},return:function(){$t=!0}};Xt[Yt]=function(){return this},Array.from(Xt,(function(){throw 2}))}catch(t){}var te,ee,ne,re=wellKnownSymbol("species"),ie=getBuiltIn("document","documentElement"),oe=/(iphone|ipod|ipad).*applewebkit/i.test(pt),ae=e.location,se=e.setImmediate,ue=e.clearImmediate,ce=e.process,he=e.MessageChannel,le=e.Dispatch,_e=0,fe={},run=function(t){if(fe.hasOwnProperty(t)){var e=fe[t];delete fe[t],e()}},runner=function(t){return function(){run(t)}},listener=function(t){run(t.data)},post=function(t){e.postMessage(t+"",ae.protocol+"//"+ae.host)};se&&ue||(se=function setImmediate(t){for(var e=[],n=1;arguments.length>n;)e.push(arguments[n++]);return fe[++_e]=function(){("function"==typeof t?t:Function(t)).apply(void 0,e)},te(_e),_e},ue=function clearImmediate(t){delete fe[t]},"process"==classofRaw(ce)?te=function(t){ce.nextTick(runner(t))}:le&&le.now?te=function(t){le.now(runner(t))}:he&&!oe?(ne=(ee=new he).port2,ee.port1.onmessage=listener,te=functionBindContext(ne.postMessage,ne,1)):!e.addEventListener||"function"!=typeof postMessage||e.importScripts||fails(post)||"file:"===ae.protocol?te="onreadystatechange"in documentCreateElement("script")?function(t){ie.appendChild(documentCreateElement("script")).onreadystatechange=function(){ie.removeChild(this),run(t)}}:function(t){setTimeout(runner(t),0)}:(te=post,e.addEventListener("message",listener,!1)));var ge,Se,pe,ye,ve,de,me,Pe,be={set:se,clear:ue},Ae=g.f,Ce=be.set,Ge=e.MutationObserver||e.WebKitMutationObserver,Ve=e.process,xe=e.Promise,Ee="process"==classofRaw(Ve),Te=Ae(e,"queueMicrotask"),we=Te&&Te.value;we||(ge=function(){var t,e;for(Ee&&(t=Ve.domain)&&t.exit();Se;){e=Se.fn,Se=Se.next;try{e()}catch(t){throw Se?ye():pe=void 0,t}}pe=void 0,t&&t.enter()},Ee?ye=function(){Ve.nextTick(ge)}:Ge&&!oe?(ve=!0,de=document.createTextNode(""),new Ge(ge).observe(de,{characterData:!0}),ye=function(){de.data=ve=!ve}):xe&&xe.resolve?(me=xe.resolve(void 0),Pe=me.then,ye=function(){Pe.call(me,ge)}):ye=function(){Ce.call(e,ge)});var Oe,Le,Re,Ie,ke=we||function(t){var e={fn:t,next:void 0};pe&&(pe.next=e),Se||(Se=e,ye()),pe=e},PromiseCapability=function(t){var e,n;this.promise=new t((function(t,r){if(void 0!==e||void 0!==n)throw TypeError("Bad Promise constructor");e=t,n=r})),this.resolve=aFunction$1(e),this.reject=aFunction$1(n)},je={f:function(t){return new PromiseCapability(t)}},promiseResolve=function(t,e){if(anObject(t),isObject(e)&&e.constructor===t)return e;var n=je.f(t);return(0,n.resolve)(e),n.promise},perform=function(t){try{return{error:!1,value:t()}}catch(t){return{error:!0,value:t}}},He=be.set,Ne=wellKnownSymbol("species"),Me="Promise",Fe=M.get,Ue=M.set,Be=M.getterFor(Me),Qe=Ut,De=e.TypeError,ze=e.document,We=e.process,qe=getBuiltIn("fetch"),Ke=je.f,Ze=Ke,Ye="process"==classofRaw(We),$e=!!(ze&&ze.createEvent&&e.dispatchEvent),Je=ot(Me,(function(){if(!(A(Qe)!==String(Qe))){if(66===mt)return!0;if(!Ye&&"function"!=typeof PromiseRejectionEvent)return!0}if(mt>=51&&/native code/.test(Qe))return!1;var t=Qe.resolve(1),FakePromise=function(t){t((function(){}),(function(){}))};return(t.constructor={})[Ne]=FakePromise,!(t.then((function(){}))instanceof FakePromise)})),Xe=Je||!function(t,e){if(!e&&!$t)return!1;var n=!1;try{var r={};r[Yt]=function(){return{next:function(){return{done:n=!0}}}},t(r)}catch(t){}return n}((function(t){Qe.all(t).catch((function(){}))})),isThenable=function(t){var e;return!(!isObject(t)||"function"!=typeof(e=t.then))&&e},notify$1=function(t,e,n){if(!e.notified){e.notified=!0;var r=e.reactions;ke((function(){for(var i=e.value,o=1==e.state,a=0;r.length>a;){var s,u,c,h=r[a++],l=o?h.ok:h.fail,_=h.resolve,f=h.reject,g=h.domain;try{l?(o||(2===e.rejection&&onHandleUnhandled(t,e),e.rejection=1),!0===l?s=i:(g&&g.enter(),s=l(i),g&&(g.exit(),c=!0)),s===h.promise?f(De("Promise-chain cycle")):(u=isThenable(s))?u.call(s,_,f):_(s)):f(i)}catch(t){g&&!c&&g.exit(),f(t)}}e.reactions=[],e.notified=!1,n&&!e.rejection&&onUnhandled(t,e)}))}},dispatchEvent=function(t,n,r){var i,o;$e?((i=ze.createEvent("Event")).promise=n,i.reason=r,i.initEvent(t,!1,!0),e.dispatchEvent(i)):i={promise:n,reason:r},(o=e["on"+t])?o(i):"unhandledrejection"===t&&function(t,n){var r=e.console;r&&r.error&&(1===arguments.length?r.error(t):r.error(t,n))}("Unhandled promise rejection",r)},onUnhandled=function(t,n){He.call(e,(function(){var e,r=n.value;if(isUnhandled(n)&&(e=perform((function(){Ye?We.emit("unhandledRejection",r,t):dispatchEvent("unhandledrejection",t,r)})),n.rejection=Ye||isUnhandled(n)?2:1,e.error))throw e.value}))},isUnhandled=function(t){return 1!==t.rejection&&!t.parent},onHandleUnhandled=function(t,n){He.call(e,(function(){Ye?We.emit("rejectionHandled",t):dispatchEvent("rejectionhandled",t,n.value)}))},bind=function(t,e,n,r){return function(i){t(e,n,i,r)}},internalReject=function(t,e,n,r){e.done||(e.done=!0,r&&(e=r),e.value=n,e.state=2,notify$1(t,e,!0))},internalResolve=function(t,e,n,r){if(!e.done){e.done=!0,r&&(e=r);try{if(t===n)throw De("Promise can't be resolved itself");var i=isThenable(n);i?ke((function(){var r={done:!1};try{i.call(n,bind(internalResolve,t,r,e),bind(internalReject,t,r,e))}catch(n){internalReject(t,r,n,e)}})):(e.value=n,e.state=1,notify$1(t,e,!1))}catch(n){internalReject(t,{done:!1},n,e)}}};Je&&(Qe=function Promise(t){!function(t,e,n){if(!(t instanceof e))throw TypeError("Incorrect "+(n?n+" ":"")+"invocation")}(this,Qe,Me),aFunction$1(t),Oe.call(this);var e=Fe(this);try{t(bind(internalResolve,this,e),bind(internalReject,this,e))}catch(t){internalReject(this,e,t)}},(Oe=function Promise(t){Ue(this,{type:Me,done:!1,notified:!1,parent:!1,reactions:[],rejection:!1,state:0,value:void 0})}).prototype=function(t,e,n){for(var r in e)U(t,r,e[r],n);return t}(Qe.prototype,{then:function then(t,e){var n,r,i,o=Be(this),a=Ke((n=Qe,void 0===(i=anObject(this).constructor)||null==(r=anObject(i)[re])?n:aFunction$1(r)));return a.ok="function"!=typeof t||t,a.fail="function"==typeof e&&e,a.domain=Ye?We.domain:void 0,o.parent=!0,o.reactions.push(a),0!=o.state&¬ify$1(this,o,!1),a.promise},catch:function(t){return this.then(void 0,t)}}),Le=function(){var t=new Oe,e=Fe(t);this.promise=t,this.resolve=bind(internalResolve,t,e),this.reject=bind(internalReject,t,e)},je.f=Ke=function(t){return t===Qe||t===Re?new Le(t):Ze(t)},"function"==typeof Ut&&(Ie=Ut.prototype.then,U(Ut.prototype,"then",(function then(t,e){var n=this;return new Qe((function(t,e){Ie.call(n,t,e)})).then(t,e)}),{unsafe:!0}),"function"==typeof qe&&_export({global:!0,enumerable:!0,forced:!0},{fetch:function fetch(t){return promiseResolve(Qe,qe.apply(e,arguments))}}))),_export({global:!0,wrap:!0,forced:Je},{Promise:Qe}),setToStringTag(Qe,Me,!1),function(t){var e=getBuiltIn(t),r=p.f;n&&e&&!e[Dt]&&r(e,Dt,{configurable:!0,get:function(){return this}})}(Me),Re=getBuiltIn(Me),_export({target:Me,stat:!0,forced:Je},{reject:function reject(t){var e=Ke(this);return e.reject.call(void 0,t),e.promise}}),_export({target:Me,stat:!0,forced:Je},{resolve:function resolve(t){return promiseResolve(this,t)}}),_export({target:Me,stat:!0,forced:Xe},{all:function all(t){var e=this,n=Ke(e),r=n.resolve,i=n.reject,o=perform((function(){var n=aFunction$1(e.resolve),o=[],a=0,s=1;Zt(t,(function(t){var u=a++,c=!1;o.push(void 0),s++,n.call(e,t).then((function(t){c||(c=!0,o[u]=t,--s||r(o))}),i)})),--s||r(o)}));return o.error&&i(o.value),n.promise},race:function race(t){var e=this,n=Ke(e),r=n.reject,i=perform((function(){var i=aFunction$1(e.resolve);Zt(t,(function(t){i.call(e,t).then(n.resolve,r)}))}));return i.error&&r(i.value),n.promise}});var tn,en=n?Object.defineProperties:function defineProperties(t,e){anObject(t);for(var n,r=Ot(e),i=r.length,o=0;i>o;)p.f(t,n=r[o++],e[n]);return t},nn=sharedKey("IE_PROTO"),EmptyConstructor=function(){},scriptTag=function(t){return"\\d{1,3})\\)$/,\n example: ['rgb(123, 234, 45)', 'rgb(255,234,245)'],\n process (_, ...bits) {\n return bits.map((b) => Number.parseInt(b));\n }\n },\n {\n re: /^(\\w{2})(\\w{2})(\\w{2})$/,\n // re: /^(?\\w{2})(?\\w{2})(?\\w{2})$/,\n example: ['#00ff00', '336699'],\n process (_, ...bits) {\n return bits.map((b) => Number.parseInt(b, 16));\n }\n },\n {\n re: /^(\\w)(\\w)(\\w)$/,\n // re: /^(?\\w{1})(?\\w{1})(?\\w{1})$/,\n example: ['#fb0', 'f0f'],\n process (_, ...bits) {\n return bits.map((b) => Number.parseInt(b + b, 16));\n }\n }\n];\n\n/**\n * A class to parse color values.\n */\nexport default class RGBColor {\n /**\n * @param {string} colorString\n */\n constructor (colorString) {\n this.ok = false;\n\n // strip any leading #\n if (colorString.charAt(0) === '#') { // remove # if any\n colorString = colorString.substr(1, 6);\n }\n\n colorString = colorString.replace(/ /g, '');\n colorString = colorString.toLowerCase();\n\n // before getting into regexps, try simple matches\n // and overwrite the input\n if (colorString in simpleColors) {\n colorString = simpleColors[colorString];\n }\n // end of simple type-in colors\n\n // search through the definitions to find a match\n\n colorDefs.forEach(({re, process: processor}) => {\n const bits = re.exec(colorString);\n if (bits) {\n const [r, g, b] = processor(...bits);\n Object.assign(this, {r, g, b});\n this.ok = true;\n }\n });\n\n // validate/cleanup values\n this.r = (this.r < 0 || isNaN(this.r)) ? 0 : ((this.r > 255) ? 255 : this.r);\n this.g = (this.g < 0 || isNaN(this.g)) ? 0 : ((this.g > 255) ? 255 : this.g);\n this.b = (this.b < 0 || isNaN(this.b)) ? 0 : ((this.b > 255) ? 255 : this.b);\n }\n\n // some getters\n /**\n * @returns {string}\n */\n toRGB () {\n return 'rgb(' + this.r + ', ' + this.g + ', ' + this.b + ')';\n }\n\n /**\n * @returns {string}\n */\n toHex () {\n let r = this.r.toString(16);\n let g = this.g.toString(16);\n let b = this.b.toString(16);\n if (r.length === 1) { r = '0' + r; }\n if (g.length === 1) { g = '0' + g; }\n if (b.length === 1) { b = '0' + b; }\n return '#' + r + g + b;\n }\n\n /**\n * Offers a bulleted list of help.\n * @returns {HTMLUListElement}\n */\n static getHelpXML () {\n const examples = [\n // add regexps\n ...colorDefs.flatMap(({example}) => {\n return example;\n }),\n // add type-in colors\n ...Object.keys(simpleColors)\n ];\n\n const xml = document.createElement('ul');\n xml.setAttribute('id', 'rgbcolor-examples');\n\n xml.append(...examples.map((example) => {\n try {\n const listItem = document.createElement('li');\n const listColor = new RGBColor(example);\n const exampleDiv = document.createElement('div');\n exampleDiv.style.cssText = `\n margin: 3px;\n border: 1px solid black;\n background: ${listColor.toHex()};\n color: ${listColor.toHex()};`;\n exampleDiv.append('test');\n const listItemValue = ` ${example} -> ${listColor.toRGB()} -> ${listColor.toHex()}`;\n listItem.append(exampleDiv, listItemValue);\n return listItem;\n } catch (e) {\n return '';\n }\n }));\n return xml;\n }\n}\n","function _typeof(obj) {\n \"@babel/helpers - typeof\";\n\n if (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\") {\n _typeof = function (obj) {\n return typeof obj;\n };\n } else {\n _typeof = function (obj) {\n return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj;\n };\n }\n\n return _typeof(obj);\n}\n\nfunction _classCallCheck(instance, Constructor) {\n if (!(instance instanceof Constructor)) {\n throw new TypeError(\"Cannot call a class as a function\");\n }\n}\n\n/* eslint-disable no-bitwise, unicorn/prefer-query-selector */\n\n/**\n* StackBlur - a fast almost Gaussian Blur For Canvas\n*\n* In case you find this class useful - especially in commercial projects -\n* I am not totally unhappy for a small donation to my PayPal account\n* mario@quasimondo.de\n*\n* Or support me on flattr:\n* {@link https://flattr.com/thing/72791/StackBlur-a-fast-almost-Gaussian-Blur-Effect-for-CanvasJavascript}.\n*\n* @module StackBlur\n* @author Mario Klingemann\n* Contact: mario@quasimondo.com\n* Website: {@link http://www.quasimondo.com/StackBlurForCanvas/StackBlurDemo.html}\n* Twitter: @quasimondo\n*\n* @copyright (c) 2010 Mario Klingemann\n*\n* Permission is hereby granted, free of charge, to any person\n* obtaining a copy of this software and associated documentation\n* files (the \"Software\"), to deal in the Software without\n* restriction, including without limitation the rights to use,\n* copy, modify, merge, publish, distribute, sublicense, and/or sell\n* copies of the Software, and to permit persons to whom the\n* Software is furnished to do so, subject to the following\n* conditions:\n*\n* The above copyright notice and this permission notice shall be\n* included in all copies or substantial portions of the Software.\n*\n* THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES\n* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\n* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT\n* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR\n* OTHER DEALINGS IN THE SOFTWARE.\n*/\n\n/* eslint-disable max-len */\nvar mulTable = [512, 512, 456, 512, 328, 456, 335, 512, 405, 328, 271, 456, 388, 335, 292, 512, 454, 405, 364, 328, 298, 271, 496, 456, 420, 388, 360, 335, 312, 292, 273, 512, 482, 454, 428, 405, 383, 364, 345, 328, 312, 298, 284, 271, 259, 496, 475, 456, 437, 420, 404, 388, 374, 360, 347, 335, 323, 312, 302, 292, 282, 273, 265, 512, 497, 482, 468, 454, 441, 428, 417, 405, 394, 383, 373, 364, 354, 345, 337, 328, 320, 312, 305, 298, 291, 284, 278, 271, 265, 259, 507, 496, 485, 475, 465, 456, 446, 437, 428, 420, 412, 404, 396, 388, 381, 374, 367, 360, 354, 347, 341, 335, 329, 323, 318, 312, 307, 302, 297, 292, 287, 282, 278, 273, 269, 265, 261, 512, 505, 497, 489, 482, 475, 468, 461, 454, 447, 441, 435, 428, 422, 417, 411, 405, 399, 394, 389, 383, 378, 373, 368, 364, 359, 354, 350, 345, 341, 337, 332, 328, 324, 320, 316, 312, 309, 305, 301, 298, 294, 291, 287, 284, 281, 278, 274, 271, 268, 265, 262, 259, 257, 507, 501, 496, 491, 485, 480, 475, 470, 465, 460, 456, 451, 446, 442, 437, 433, 428, 424, 420, 416, 412, 408, 404, 400, 396, 392, 388, 385, 381, 377, 374, 370, 367, 363, 360, 357, 354, 350, 347, 344, 341, 338, 335, 332, 329, 326, 323, 320, 318, 315, 312, 310, 307, 304, 302, 299, 297, 294, 292, 289, 287, 285, 282, 280, 278, 275, 273, 271, 269, 267, 265, 263, 261, 259];\nvar shgTable = [9, 11, 12, 13, 13, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24];\n/* eslint-enable max-len */\n\n/**\n * @param {string|HTMLImageElement} img\n * @param {string|HTMLCanvasElement} canvas\n * @param {Float} radius\n * @param {boolean} blurAlphaChannel\n * @returns {undefined}\n */\n\nfunction processImage(img, canvas, radius, blurAlphaChannel) {\n if (typeof img === 'string') {\n img = document.getElementById(img);\n }\n\n if (!img || !('naturalWidth' in img)) {\n return;\n }\n\n var w = img.naturalWidth;\n var h = img.naturalHeight;\n\n if (typeof canvas === 'string') {\n canvas = document.getElementById(canvas);\n }\n\n if (!canvas || !('getContext' in canvas)) {\n return;\n }\n\n canvas.style.width = w + 'px';\n canvas.style.height = h + 'px';\n canvas.width = w;\n canvas.height = h;\n var context = canvas.getContext('2d');\n context.clearRect(0, 0, w, h);\n context.drawImage(img, 0, 0);\n\n if (isNaN(radius) || radius < 1) {\n return;\n }\n\n if (blurAlphaChannel) {\n processCanvasRGBA(canvas, 0, 0, w, h, radius);\n } else {\n processCanvasRGB(canvas, 0, 0, w, h, radius);\n }\n}\n/**\n * @param {string|HTMLCanvasElement} canvas\n * @param {Integer} topX\n * @param {Integer} topY\n * @param {Integer} width\n * @param {Integer} height\n * @throws {Error|TypeError}\n * @returns {ImageData} See {@link https://html.spec.whatwg.org/multipage/canvas.html#imagedata}\n */\n\n\nfunction getImageDataFromCanvas(canvas, topX, topY, width, height) {\n if (typeof canvas === 'string') {\n canvas = document.getElementById(canvas);\n }\n\n if (!canvas || _typeof(canvas) !== 'object' || !('getContext' in canvas)) {\n throw new TypeError('Expecting canvas with `getContext` method ' + 'in processCanvasRGB(A) calls!');\n }\n\n var context = canvas.getContext('2d');\n\n try {\n return context.getImageData(topX, topY, width, height);\n } catch (e) {\n throw new Error('unable to access image data: ' + e);\n }\n}\n/**\n * @param {HTMLCanvasElement} canvas\n * @param {Integer} topX\n * @param {Integer} topY\n * @param {Integer} width\n * @param {Integer} height\n * @param {Float} radius\n * @returns {undefined}\n */\n\n\nfunction processCanvasRGBA(canvas, topX, topY, width, height, radius) {\n if (isNaN(radius) || radius < 1) {\n return;\n }\n\n radius |= 0;\n var imageData = getImageDataFromCanvas(canvas, topX, topY, width, height);\n imageData = processImageDataRGBA(imageData, topX, topY, width, height, radius);\n canvas.getContext('2d').putImageData(imageData, topX, topY);\n}\n/**\n * @param {ImageData} imageData\n * @param {Integer} topX\n * @param {Integer} topY\n * @param {Integer} width\n * @param {Integer} height\n * @param {Float} radius\n * @returns {ImageData}\n */\n\n\nfunction processImageDataRGBA(imageData, topX, topY, width, height, radius) {\n var pixels = imageData.data;\n var x, y, i, p, yp, yi, yw, rSum, gSum, bSum, aSum, rOutSum, gOutSum, bOutSum, aOutSum, rInSum, gInSum, bInSum, aInSum, pr, pg, pb, pa, rbs;\n var div = 2 * radius + 1; // const w4 = width << 2;\n\n var widthMinus1 = width - 1;\n var heightMinus1 = height - 1;\n var radiusPlus1 = radius + 1;\n var sumFactor = radiusPlus1 * (radiusPlus1 + 1) / 2;\n var stackStart = new BlurStack();\n var stack = stackStart;\n var stackEnd;\n\n for (i = 1; i < div; i++) {\n stack = stack.next = new BlurStack();\n\n if (i === radiusPlus1) {\n stackEnd = stack;\n }\n }\n\n stack.next = stackStart;\n var stackIn = null;\n var stackOut = null;\n yw = yi = 0;\n var mulSum = mulTable[radius];\n var shgSum = shgTable[radius];\n\n for (y = 0; y < height; y++) {\n rInSum = gInSum = bInSum = aInSum = rSum = gSum = bSum = aSum = 0;\n rOutSum = radiusPlus1 * (pr = pixels[yi]);\n gOutSum = radiusPlus1 * (pg = pixels[yi + 1]);\n bOutSum = radiusPlus1 * (pb = pixels[yi + 2]);\n aOutSum = radiusPlus1 * (pa = pixels[yi + 3]);\n rSum += sumFactor * pr;\n gSum += sumFactor * pg;\n bSum += sumFactor * pb;\n aSum += sumFactor * pa;\n stack = stackStart;\n\n for (i = 0; i < radiusPlus1; i++) {\n stack.r = pr;\n stack.g = pg;\n stack.b = pb;\n stack.a = pa;\n stack = stack.next;\n }\n\n for (i = 1; i < radiusPlus1; i++) {\n p = yi + ((widthMinus1 < i ? widthMinus1 : i) << 2);\n rSum += (stack.r = pr = pixels[p]) * (rbs = radiusPlus1 - i);\n gSum += (stack.g = pg = pixels[p + 1]) * rbs;\n bSum += (stack.b = pb = pixels[p + 2]) * rbs;\n aSum += (stack.a = pa = pixels[p + 3]) * rbs;\n rInSum += pr;\n gInSum += pg;\n bInSum += pb;\n aInSum += pa;\n stack = stack.next;\n }\n\n stackIn = stackStart;\n stackOut = stackEnd;\n\n for (x = 0; x < width; x++) {\n pixels[yi + 3] = pa = aSum * mulSum >> shgSum;\n\n if (pa !== 0) {\n pa = 255 / pa;\n pixels[yi] = (rSum * mulSum >> shgSum) * pa;\n pixels[yi + 1] = (gSum * mulSum >> shgSum) * pa;\n pixels[yi + 2] = (bSum * mulSum >> shgSum) * pa;\n } else {\n pixels[yi] = pixels[yi + 1] = pixels[yi + 2] = 0;\n }\n\n rSum -= rOutSum;\n gSum -= gOutSum;\n bSum -= bOutSum;\n aSum -= aOutSum;\n rOutSum -= stackIn.r;\n gOutSum -= stackIn.g;\n bOutSum -= stackIn.b;\n aOutSum -= stackIn.a;\n p = yw + ((p = x + radius + 1) < widthMinus1 ? p : widthMinus1) << 2;\n rInSum += stackIn.r = pixels[p];\n gInSum += stackIn.g = pixels[p + 1];\n bInSum += stackIn.b = pixels[p + 2];\n aInSum += stackIn.a = pixels[p + 3];\n rSum += rInSum;\n gSum += gInSum;\n bSum += bInSum;\n aSum += aInSum;\n stackIn = stackIn.next;\n rOutSum += pr = stackOut.r;\n gOutSum += pg = stackOut.g;\n bOutSum += pb = stackOut.b;\n aOutSum += pa = stackOut.a;\n rInSum -= pr;\n gInSum -= pg;\n bInSum -= pb;\n aInSum -= pa;\n stackOut = stackOut.next;\n yi += 4;\n }\n\n yw += width;\n }\n\n for (x = 0; x < width; x++) {\n gInSum = bInSum = aInSum = rInSum = gSum = bSum = aSum = rSum = 0;\n yi = x << 2;\n rOutSum = radiusPlus1 * (pr = pixels[yi]);\n gOutSum = radiusPlus1 * (pg = pixels[yi + 1]);\n bOutSum = radiusPlus1 * (pb = pixels[yi + 2]);\n aOutSum = radiusPlus1 * (pa = pixels[yi + 3]);\n rSum += sumFactor * pr;\n gSum += sumFactor * pg;\n bSum += sumFactor * pb;\n aSum += sumFactor * pa;\n stack = stackStart;\n\n for (i = 0; i < radiusPlus1; i++) {\n stack.r = pr;\n stack.g = pg;\n stack.b = pb;\n stack.a = pa;\n stack = stack.next;\n }\n\n yp = width;\n\n for (i = 1; i <= radius; i++) {\n yi = yp + x << 2;\n rSum += (stack.r = pr = pixels[yi]) * (rbs = radiusPlus1 - i);\n gSum += (stack.g = pg = pixels[yi + 1]) * rbs;\n bSum += (stack.b = pb = pixels[yi + 2]) * rbs;\n aSum += (stack.a = pa = pixels[yi + 3]) * rbs;\n rInSum += pr;\n gInSum += pg;\n bInSum += pb;\n aInSum += pa;\n stack = stack.next;\n\n if (i < heightMinus1) {\n yp += width;\n }\n }\n\n yi = x;\n stackIn = stackStart;\n stackOut = stackEnd;\n\n for (y = 0; y < height; y++) {\n p = yi << 2;\n pixels[p + 3] = pa = aSum * mulSum >> shgSum;\n\n if (pa > 0) {\n pa = 255 / pa;\n pixels[p] = (rSum * mulSum >> shgSum) * pa;\n pixels[p + 1] = (gSum * mulSum >> shgSum) * pa;\n pixels[p + 2] = (bSum * mulSum >> shgSum) * pa;\n } else {\n pixels[p] = pixels[p + 1] = pixels[p + 2] = 0;\n }\n\n rSum -= rOutSum;\n gSum -= gOutSum;\n bSum -= bOutSum;\n aSum -= aOutSum;\n rOutSum -= stackIn.r;\n gOutSum -= stackIn.g;\n bOutSum -= stackIn.b;\n aOutSum -= stackIn.a;\n p = x + ((p = y + radiusPlus1) < heightMinus1 ? p : heightMinus1) * width << 2;\n rSum += rInSum += stackIn.r = pixels[p];\n gSum += gInSum += stackIn.g = pixels[p + 1];\n bSum += bInSum += stackIn.b = pixels[p + 2];\n aSum += aInSum += stackIn.a = pixels[p + 3];\n stackIn = stackIn.next;\n rOutSum += pr = stackOut.r;\n gOutSum += pg = stackOut.g;\n bOutSum += pb = stackOut.b;\n aOutSum += pa = stackOut.a;\n rInSum -= pr;\n gInSum -= pg;\n bInSum -= pb;\n aInSum -= pa;\n stackOut = stackOut.next;\n yi += width;\n }\n }\n\n return imageData;\n}\n/**\n * @param {HTMLCanvasElement} canvas\n * @param {Integer} topX\n * @param {Integer} topY\n * @param {Integer} width\n * @param {Integer} height\n * @param {Float} radius\n * @returns {undefined}\n */\n\n\nfunction processCanvasRGB(canvas, topX, topY, width, height, radius) {\n if (isNaN(radius) || radius < 1) {\n return;\n }\n\n radius |= 0;\n var imageData = getImageDataFromCanvas(canvas, topX, topY, width, height);\n imageData = processImageDataRGB(imageData, topX, topY, width, height, radius);\n canvas.getContext('2d').putImageData(imageData, topX, topY);\n}\n/**\n * @param {ImageData} imageData\n * @param {Integer} topX\n * @param {Integer} topY\n * @param {Integer} width\n * @param {Integer} height\n * @param {Float} radius\n * @returns {ImageData}\n */\n\n\nfunction processImageDataRGB(imageData, topX, topY, width, height, radius) {\n var pixels = imageData.data;\n var x, y, i, p, yp, yi, yw, rSum, gSum, bSum, rOutSum, gOutSum, bOutSum, rInSum, gInSum, bInSum, pr, pg, pb, rbs;\n var div = 2 * radius + 1; // const w4 = width << 2;\n\n var widthMinus1 = width - 1;\n var heightMinus1 = height - 1;\n var radiusPlus1 = radius + 1;\n var sumFactor = radiusPlus1 * (radiusPlus1 + 1) / 2;\n var stackStart = new BlurStack();\n var stack = stackStart;\n var stackEnd;\n\n for (i = 1; i < div; i++) {\n stack = stack.next = new BlurStack();\n\n if (i === radiusPlus1) {\n stackEnd = stack;\n }\n }\n\n stack.next = stackStart;\n var stackIn = null;\n var stackOut = null;\n yw = yi = 0;\n var mulSum = mulTable[radius];\n var shgSum = shgTable[radius];\n\n for (y = 0; y < height; y++) {\n rInSum = gInSum = bInSum = rSum = gSum = bSum = 0;\n rOutSum = radiusPlus1 * (pr = pixels[yi]);\n gOutSum = radiusPlus1 * (pg = pixels[yi + 1]);\n bOutSum = radiusPlus1 * (pb = pixels[yi + 2]);\n rSum += sumFactor * pr;\n gSum += sumFactor * pg;\n bSum += sumFactor * pb;\n stack = stackStart;\n\n for (i = 0; i < radiusPlus1; i++) {\n stack.r = pr;\n stack.g = pg;\n stack.b = pb;\n stack = stack.next;\n }\n\n for (i = 1; i < radiusPlus1; i++) {\n p = yi + ((widthMinus1 < i ? widthMinus1 : i) << 2);\n rSum += (stack.r = pr = pixels[p]) * (rbs = radiusPlus1 - i);\n gSum += (stack.g = pg = pixels[p + 1]) * rbs;\n bSum += (stack.b = pb = pixels[p + 2]) * rbs;\n rInSum += pr;\n gInSum += pg;\n bInSum += pb;\n stack = stack.next;\n }\n\n stackIn = stackStart;\n stackOut = stackEnd;\n\n for (x = 0; x < width; x++) {\n pixels[yi] = rSum * mulSum >> shgSum;\n pixels[yi + 1] = gSum * mulSum >> shgSum;\n pixels[yi + 2] = bSum * mulSum >> shgSum;\n rSum -= rOutSum;\n gSum -= gOutSum;\n bSum -= bOutSum;\n rOutSum -= stackIn.r;\n gOutSum -= stackIn.g;\n bOutSum -= stackIn.b;\n p = yw + ((p = x + radius + 1) < widthMinus1 ? p : widthMinus1) << 2;\n rInSum += stackIn.r = pixels[p];\n gInSum += stackIn.g = pixels[p + 1];\n bInSum += stackIn.b = pixels[p + 2];\n rSum += rInSum;\n gSum += gInSum;\n bSum += bInSum;\n stackIn = stackIn.next;\n rOutSum += pr = stackOut.r;\n gOutSum += pg = stackOut.g;\n bOutSum += pb = stackOut.b;\n rInSum -= pr;\n gInSum -= pg;\n bInSum -= pb;\n stackOut = stackOut.next;\n yi += 4;\n }\n\n yw += width;\n }\n\n for (x = 0; x < width; x++) {\n gInSum = bInSum = rInSum = gSum = bSum = rSum = 0;\n yi = x << 2;\n rOutSum = radiusPlus1 * (pr = pixels[yi]);\n gOutSum = radiusPlus1 * (pg = pixels[yi + 1]);\n bOutSum = radiusPlus1 * (pb = pixels[yi + 2]);\n rSum += sumFactor * pr;\n gSum += sumFactor * pg;\n bSum += sumFactor * pb;\n stack = stackStart;\n\n for (i = 0; i < radiusPlus1; i++) {\n stack.r = pr;\n stack.g = pg;\n stack.b = pb;\n stack = stack.next;\n }\n\n yp = width;\n\n for (i = 1; i <= radius; i++) {\n yi = yp + x << 2;\n rSum += (stack.r = pr = pixels[yi]) * (rbs = radiusPlus1 - i);\n gSum += (stack.g = pg = pixels[yi + 1]) * rbs;\n bSum += (stack.b = pb = pixels[yi + 2]) * rbs;\n rInSum += pr;\n gInSum += pg;\n bInSum += pb;\n stack = stack.next;\n\n if (i < heightMinus1) {\n yp += width;\n }\n }\n\n yi = x;\n stackIn = stackStart;\n stackOut = stackEnd;\n\n for (y = 0; y < height; y++) {\n p = yi << 2;\n pixels[p] = rSum * mulSum >> shgSum;\n pixels[p + 1] = gSum * mulSum >> shgSum;\n pixels[p + 2] = bSum * mulSum >> shgSum;\n rSum -= rOutSum;\n gSum -= gOutSum;\n bSum -= bOutSum;\n rOutSum -= stackIn.r;\n gOutSum -= stackIn.g;\n bOutSum -= stackIn.b;\n p = x + ((p = y + radiusPlus1) < heightMinus1 ? p : heightMinus1) * width << 2;\n rSum += rInSum += stackIn.r = pixels[p];\n gSum += gInSum += stackIn.g = pixels[p + 1];\n bSum += bInSum += stackIn.b = pixels[p + 2];\n stackIn = stackIn.next;\n rOutSum += pr = stackOut.r;\n gOutSum += pg = stackOut.g;\n bOutSum += pb = stackOut.b;\n rInSum -= pr;\n gInSum -= pg;\n bInSum -= pb;\n stackOut = stackOut.next;\n yi += width;\n }\n }\n\n return imageData;\n}\n/**\n *\n */\n\n\nvar BlurStack =\n/**\n * Set properties.\n */\nfunction BlurStack() {\n _classCallCheck(this, BlurStack);\n\n this.r = 0;\n this.g = 0;\n this.b = 0;\n this.a = 0;\n this.next = null;\n};\n\nexport { BlurStack, processCanvasRGB as canvasRGB, processCanvasRGBA as canvasRGBA, processImage as image, processImageDataRGB as imageDataRGB, processImageDataRGBA as imageDataRGBA };\n","/* eslint-disable new-cap, class-methods-use-this, jsdoc/require-jsdoc */\n// Todo: Compare with latest canvg (add any improvements of ours) and add full JSDocs (denoting links to standard APIs and which are custom): https://github.com/canvg/canvg\n/**\n * Javascript SVG parser and renderer on Canvas.\n * @file canvg.js\n * @module canvg\n * @license MIT\n * @author Gabe Lerner \n * @see https://github.com/canvg/canvg\n */\n\nimport RGBColor from './rgbcolor.js';\nimport {canvasRGBA} from '../../external/stackblur-canvas/dist/stackblur-es.js';\n\n/**\n * Whether a value is `null` or `undefined`.\n * @param {any} val\n * @returns {boolean}\n */\nconst isNullish = (val) => {\n return val === null || val === undefined;\n};\n\n/**\n* @callback module:canvg.ForceRedraw\n* @returns {boolean}\n*/\n\n/**\n* @typedef {PlainObject} module:canvg.CanvgOptions\n* @property {boolean} ignoreMouse true => ignore mouse events\n* @property {boolean} ignoreAnimation true => ignore animations\n* @property {boolean} ignoreDimensions true => does not try to resize canvas\n* @property {boolean} ignoreClear true => does not clear canvas\n* @property {Integer} offsetX int => draws at a x offset\n* @property {Integer} offsetY int => draws at a y offset\n* @property {Integer} scaleWidth int => scales horizontally to width\n* @property {Integer} scaleHeight int => scales vertically to height\n* @property {module:canvg.ForceRedraw} forceRedraw function => will call the function on every frame, if it returns true, will redraw\n* @property {boolean} log Adds log function\n* @property {boolean} useCORS Whether to set CORS `crossOrigin` for the image to `Anonymous`\n*/\n\n/**\n* If called with no arguments, it will replace all `` elements on the page\n* with `` elements.\n* @function module:canvg.canvg\n* @param {HTMLCanvasElement|string} target canvas element or the id of a canvas element\n* @param {string|XMLDocument} s - svg string, url to svg file, or xml document\n* @param {module:canvg.CanvgOptions} [opts] Optional hash of options\n* @returns {Promise} All the function after the first render is completed with dom\n*/\nexport const canvg = function (target, s, opts) {\n // no parameters\n if (isNullish(target) && isNullish(s) && isNullish(opts)) {\n const svgTags = document.querySelectorAll('svg');\n return Promise.all([...svgTags].map((svgTag) => {\n const c = document.createElement('canvas');\n c.width = svgTag.clientWidth;\n c.height = svgTag.clientHeight;\n svgTag.before(c);\n svgTag.remove();\n const div = document.createElement('div');\n div.append(svgTag);\n return canvg(c, div.innerHTML);\n }));\n }\n\n if (typeof target === 'string') {\n target = document.getElementById(target);\n }\n\n // store class on canvas\n if (!isNullish(target.svg)) target.svg.stop();\n const svg = build(opts || {});\n // on i.e. 8 for flash canvas, we can't assign the property so check for it\n if (!(target.childNodes.length === 1 && target.childNodes[0].nodeName === 'OBJECT')) {\n target.svg = svg;\n }\n\n const ctx = target.getContext('2d');\n if (typeof s.documentElement !== 'undefined') {\n // load from xml doc\n return svg.loadXmlDoc(ctx, s);\n }\n if (s.substr(0, 1) === '<') {\n // load from xml string\n return svg.loadXml(ctx, s);\n }\n // load from url\n return svg.load(ctx, s);\n};\n\n/* eslint-disable jsdoc/check-types */\n/**\n* @param {module:canvg.CanvgOptions} opts\n* @returns {object}\n* @todo Flesh out exactly what object is returned here (after updating to latest and reincluding our changes here and those of StackBlur)\n*/\nfunction build (opts) {\n /* eslint-enable jsdoc/check-types */\n const svg = {opts};\n\n svg.FRAMERATE = 30;\n svg.MAX_VIRTUAL_PIXELS = 30000;\n\n svg.log = function (msg) { /* */ };\n if (svg.opts.log === true && typeof console !== 'undefined') {\n svg.log = function (msg) { console.log(msg); }; // eslint-disable-line no-console\n }\n\n // globals\n svg.init = function (ctx) {\n let uniqueId = 0;\n svg.UniqueId = function () {\n uniqueId++;\n return 'canvg' + uniqueId;\n };\n svg.Definitions = {};\n svg.Styles = {};\n svg.Animations = [];\n svg.Images = [];\n svg.ctx = ctx;\n svg.ViewPort = {\n viewPorts: [],\n Clear () { this.viewPorts = []; },\n SetCurrent (width, height) { this.viewPorts.push({width, height}); },\n RemoveCurrent () { this.viewPorts.pop(); },\n Current () { return this.viewPorts[this.viewPorts.length - 1]; },\n width () { return this.Current().width; },\n height () { return this.Current().height; },\n ComputeSize (d) {\n if (!isNullish(d) && typeof d === 'number') return d;\n if (d === 'x') return this.width();\n if (d === 'y') return this.height();\n return Math.sqrt(\n (this.width() ** 2) + (this.height() ** 2)\n ) / Math.sqrt(2);\n }\n };\n };\n svg.init();\n\n // images loaded\n svg.ImagesLoaded = function () {\n return svg.Images.every((img) => img.loaded);\n };\n\n // trim\n svg.trim = function (s) {\n return s.replace(/^\\s+|\\s+$/g, '');\n };\n\n // compress spaces\n svg.compressSpaces = function (s) {\n return s.replace(/\\s+/gm, ' ');\n };\n\n // ajax\n // Todo: Replace with `fetch` and polyfill\n svg.ajax = function (url, asynch) {\n const AJAX = window.XMLHttpRequest\n ? new XMLHttpRequest()\n : new window.ActiveXObject('Microsoft.XMLHTTP');\n if (asynch) {\n return new Promise((resolve, reject) => { // eslint-disable-line promise/avoid-new\n const req = AJAX.open('GET', url, true);\n req.addEventListener('load', () => {\n resolve(AJAX.responseText);\n });\n AJAX.send(null);\n });\n }\n\n AJAX.open('GET', url, false);\n AJAX.send(null);\n return AJAX.responseText;\n };\n\n // parse xml\n svg.parseXml = function (xml) {\n if (window.DOMParser) {\n const parser = new DOMParser();\n return parser.parseFromString(xml, 'text/xml');\n }\n xml = xml.replace(/]*>/, '');\n const xmlDoc = new window.ActiveXObject('Microsoft.XMLDOM');\n xmlDoc.async = 'false';\n xmlDoc.loadXML(xml);\n return xmlDoc;\n };\n\n // text extensions\n // get the text baseline\n const textBaselineMapping = {\n baseline: 'alphabetic',\n 'before-edge': 'top',\n 'text-before-edge': 'top',\n middle: 'middle',\n central: 'middle',\n 'after-edge': 'bottom',\n 'text-after-edge': 'bottom',\n ideographic: 'ideographic',\n alphabetic: 'alphabetic',\n hanging: 'hanging',\n mathematical: 'alphabetic'\n };\n\n svg.Property = class Property {\n constructor (name, value) {\n this.name = name;\n this.value = value;\n }\n\n getValue () {\n return this.value;\n }\n\n hasValue () {\n return (!isNullish(this.value) && this.value !== '');\n }\n\n // return the numerical value of the property\n numValue () {\n if (!this.hasValue()) return 0;\n\n let n = Number.parseFloat(this.value);\n if (String(this.value).endsWith('%')) {\n n /= 100.0;\n }\n return n;\n }\n\n valueOrDefault (def) {\n if (this.hasValue()) return this.value;\n return def;\n }\n\n numValueOrDefault (def) {\n if (this.hasValue()) return this.numValue();\n return def;\n }\n\n // color extensions\n // augment the current color value with the opacity\n addOpacity (opacityProp) {\n let newValue = this.value;\n if (!isNullish(opacityProp.value) && opacityProp.value !== '' && typeof this.value === 'string') { // can only add opacity to colors, not patterns\n const color = new RGBColor(this.value);\n if (color.ok) {\n newValue = 'rgba(' + color.r + ', ' + color.g + ', ' + color.b + ', ' + opacityProp.numValue() + ')';\n }\n }\n return new svg.Property(this.name, newValue);\n }\n\n // definition extensions\n // get the definition from the definitions table\n getDefinition () {\n let name = this.value.match(/#([^)'\"]+)/);\n if (name) { name = name[1]; }\n if (!name) { name = this.value; }\n return svg.Definitions[name];\n }\n\n isUrlDefinition () {\n return this.value.startsWith('url(');\n }\n\n getFillStyleDefinition (e, opacityProp) {\n let def = this.getDefinition();\n\n // gradient\n if (!isNullish(def) && def.createGradient) {\n return def.createGradient(svg.ctx, e, opacityProp);\n }\n\n // pattern\n if (!isNullish(def) && def.createPattern) {\n if (def.getHrefAttribute().hasValue()) {\n const pt = def.attribute('patternTransform');\n def = def.getHrefAttribute().getDefinition();\n if (pt.hasValue()) { def.attribute('patternTransform', true).value = pt.value; }\n }\n return def.createPattern(svg.ctx, e);\n }\n\n return null;\n }\n\n // length extensions\n getDPI (viewPort) {\n return 96.0; // TODO: compute?\n }\n\n getEM (viewPort) {\n let em = 12;\n\n const fontSize = new svg.Property('fontSize', svg.Font.Parse(svg.ctx.font).fontSize);\n if (fontSize.hasValue()) em = fontSize.toPixels(viewPort);\n\n return em;\n }\n\n getUnits () {\n return String(this.value).replace(/[\\d.-]/g, '');\n }\n\n // get the length as pixels\n toPixels (viewPort, processPercent) {\n if (!this.hasValue()) return 0;\n const s = String(this.value);\n if (s.endsWith('em')) return this.numValue() * this.getEM(viewPort);\n if (s.endsWith('ex')) return this.numValue() * this.getEM(viewPort) / 2.0;\n if (s.endsWith('px')) return this.numValue();\n if (s.endsWith('pt')) return this.numValue() * this.getDPI(viewPort) * (1.0 / 72.0);\n if (s.endsWith('pc')) return this.numValue() * 15;\n if (s.endsWith('cm')) return this.numValue() * this.getDPI(viewPort) / 2.54;\n if (s.endsWith('mm')) return this.numValue() * this.getDPI(viewPort) / 25.4;\n if (s.endsWith('in')) return this.numValue() * this.getDPI(viewPort);\n if (s.endsWith('%')) return this.numValue() * svg.ViewPort.ComputeSize(viewPort);\n const n = this.numValue();\n if (processPercent && n < 1.0) return n * svg.ViewPort.ComputeSize(viewPort);\n return n;\n }\n\n // time extensions\n // get the time as milliseconds\n toMilliseconds () {\n if (!this.hasValue()) return 0;\n const s = String(this.value);\n if (s.endsWith('ms')) return this.numValue();\n if (s.endsWith('s')) return this.numValue() * 1000;\n return this.numValue();\n }\n\n // angle extensions\n // get the angle as radians\n toRadians () {\n if (!this.hasValue()) return 0;\n const s = String(this.value);\n if (s.endsWith('deg')) return this.numValue() * (Math.PI / 180.0);\n if (s.endsWith('grad')) return this.numValue() * (Math.PI / 200.0);\n if (s.endsWith('rad')) return this.numValue();\n return this.numValue() * (Math.PI / 180.0);\n }\n\n toTextBaseline () {\n if (!this.hasValue()) return null;\n return textBaselineMapping[this.value];\n }\n };\n\n // fonts\n svg.Font = {\n Styles: 'normal|italic|oblique|inherit',\n Variants: 'normal|small-caps|inherit',\n Weights: 'normal|bold|bolder|lighter|100|200|300|400|500|600|700|800|900|inherit',\n\n CreateFont (fontStyle, fontVariant, fontWeight, fontSize, fontFamily, inherit) {\n const f = !isNullish(inherit) ? this.Parse(inherit) : this.CreateFont('', '', '', '', '', svg.ctx.font);\n return {\n fontFamily: fontFamily || f.fontFamily,\n fontSize: fontSize || f.fontSize,\n fontStyle: fontStyle || f.fontStyle,\n fontWeight: fontWeight || f.fontWeight,\n fontVariant: fontVariant || f.fontVariant,\n toString () {\n return [\n this.fontStyle, this.fontVariant, this.fontWeight,\n this.fontSize, this.fontFamily\n ].join(' ');\n }\n };\n },\n\n Parse (s) {\n const f = {};\n const ds = svg.trim(svg.compressSpaces(s || '')).split(' ');\n const set = {\n fontSize: false, fontStyle: false, fontWeight: false, fontVariant: false\n };\n let ff = '';\n ds.forEach((d) => {\n if (!set.fontStyle && this.Styles.includes(d)) {\n if (d !== 'inherit') {\n f.fontStyle = d;\n }\n set.fontStyle = true;\n } else if (!set.fontVariant && this.Variants.includes(d)) {\n if (d !== 'inherit') {\n f.fontVariant = d;\n }\n set.fontStyle = set.fontVariant = true;\n } else if (!set.fontWeight && this.Weights.includes(d)) {\n if (d !== 'inherit') {\n f.fontWeight = d;\n }\n set.fontStyle = set.fontVariant = set.fontWeight = true;\n } else if (!set.fontSize) {\n if (d !== 'inherit') {\n f.fontSize = d.split('/')[0];\n }\n set.fontStyle = set.fontVariant = set.fontWeight = set.fontSize = true;\n } else if (d !== 'inherit') {\n ff += d;\n }\n });\n if (ff !== '') { f.fontFamily = ff; }\n return f;\n }\n };\n\n // points and paths\n svg.ToNumberArray = function (s) {\n const a = svg.trim(svg.compressSpaces((s || '').replace(/,/g, ' '))).split(' ');\n return a.map((_a) => Number.parseFloat(_a));\n };\n svg.Point = class {\n constructor (x, y) {\n this.x = x;\n this.y = y;\n }\n\n angleTo (p) {\n return Math.atan2(p.y - this.y, p.x - this.x);\n }\n\n applyTransform (v) {\n const xp = this.x * v[0] + this.y * v[2] + v[4];\n const yp = this.x * v[1] + this.y * v[3] + v[5];\n this.x = xp;\n this.y = yp;\n }\n };\n\n svg.CreatePoint = function (s) {\n const a = svg.ToNumberArray(s);\n return new svg.Point(a[0], a[1]);\n };\n svg.CreatePath = function (s) {\n const a = svg.ToNumberArray(s);\n const path = [];\n for (let i = 0; i < a.length; i += 2) {\n path.push(new svg.Point(a[i], a[i + 1]));\n }\n return path;\n };\n\n // bounding box\n svg.BoundingBox = class {\n constructor (x1, y1, x2, y2) { // pass in initial points if you want\n this.x1 = Number.NaN;\n this.y1 = Number.NaN;\n this.x2 = Number.NaN;\n this.y2 = Number.NaN;\n this.addPoint(x1, y1);\n this.addPoint(x2, y2);\n }\n\n x () { return this.x1; }\n y () { return this.y1; }\n width () { return this.x2 - this.x1; }\n height () { return this.y2 - this.y1; }\n\n addPoint (x, y) {\n if (!isNullish(x)) {\n if (isNaN(this.x1) || isNaN(this.x2)) {\n this.x1 = x;\n this.x2 = x;\n }\n if (x < this.x1) this.x1 = x;\n if (x > this.x2) this.x2 = x;\n }\n\n if (!isNullish(y)) {\n if (isNaN(this.y1) || isNaN(this.y2)) {\n this.y1 = y;\n this.y2 = y;\n }\n if (y < this.y1) this.y1 = y;\n if (y > this.y2) this.y2 = y;\n }\n }\n addX (x) { this.addPoint(x, null); }\n addY (y) { this.addPoint(null, y); }\n\n addBoundingBox (bb) {\n this.addPoint(bb.x1, bb.y1);\n this.addPoint(bb.x2, bb.y2);\n }\n\n addQuadraticCurve (p0x, p0y, p1x, p1y, p2x, p2y) {\n const cp1x = p0x + 2 / 3 * (p1x - p0x); // CP1 = QP0 + 2/3 *(QP1-QP0)\n const cp1y = p0y + 2 / 3 * (p1y - p0y); // CP1 = QP0 + 2/3 *(QP1-QP0)\n const cp2x = cp1x + 1 / 3 * (p2x - p0x); // CP2 = CP1 + 1/3 *(QP2-QP0)\n const cp2y = cp1y + 1 / 3 * (p2y - p0y); // CP2 = CP1 + 1/3 *(QP2-QP0)\n this.addBezierCurve(p0x, p0y, cp1x, cp2x, cp1y, cp2y, p2x, p2y);\n }\n\n addBezierCurve (p0x, p0y, p1x, p1y, p2x, p2y, p3x, p3y) {\n // from http://blog.hackers-cafe.net/2009/06/how-to-calculate-bezier-curves-bounding.html\n const p0 = [p0x, p0y], p1 = [p1x, p1y], p2 = [p2x, p2y], p3 = [p3x, p3y];\n this.addPoint(p0[0], p0[1]);\n this.addPoint(p3[0], p3[1]);\n\n for (let i = 0; i <= 1; i++) {\n const f = function (t) {\n return ((1 - t) ** 3) * p0[i] +\n 3 * ((1 - t) ** 2) * t * p1[i] +\n 3 * (1 - t) * (t ** 2) * p2[i] +\n (t ** 3) * p3[i];\n };\n\n const b = 6 * p0[i] - 12 * p1[i] + 6 * p2[i];\n const a = -3 * p0[i] + 9 * p1[i] - 9 * p2[i] + 3 * p3[i];\n const c = 3 * p1[i] - 3 * p0[i];\n\n if (a === 0) {\n if (b === 0) continue;\n const t = -c / b;\n if (t > 0 && t < 1) {\n if (i === 0) this.addX(f(t));\n if (i === 1) this.addY(f(t));\n }\n continue;\n }\n\n const b2ac = (b ** 2) - 4 * c * a;\n if (b2ac < 0) continue;\n const t1 = (-b + Math.sqrt(b2ac)) / (2 * a);\n if (t1 > 0 && t1 < 1) {\n if (i === 0) this.addX(f(t1));\n if (i === 1) this.addY(f(t1));\n }\n const t2 = (-b - Math.sqrt(b2ac)) / (2 * a);\n if (t2 > 0 && t2 < 1) {\n if (i === 0) this.addX(f(t2));\n if (i === 1) this.addY(f(t2));\n }\n }\n }\n\n isPointInBox (x, y) {\n return (this.x1 <= x && x <= this.x2 && this.y1 <= y && y <= this.y2);\n }\n };\n\n // transforms\n svg.Transform = class {\n constructor (v) {\n this.Type = {\n translate: class {\n constructor (s) {\n this.p = svg.CreatePoint(s);\n this.apply = function (ctx) {\n ctx.translate(this.p.x || 0.0, this.p.y || 0.0);\n };\n this.unapply = function (ctx) {\n ctx.translate(-1.0 * this.p.x || 0.0, -1.0 * this.p.y || 0.0);\n };\n this.applyToPoint = function (p) {\n p.applyTransform([1, 0, 0, 1, this.p.x || 0.0, this.p.y || 0.0]);\n };\n }\n },\n rotate: class {\n constructor (s) {\n const a = svg.ToNumberArray(s);\n this.angle = new svg.Property('angle', a[0]);\n this.cx = a[1] || 0;\n this.cy = a[2] || 0;\n this.apply = function (ctx) {\n ctx.translate(this.cx, this.cy);\n ctx.rotate(this.angle.toRadians());\n ctx.translate(-this.cx, -this.cy);\n };\n this.unapply = function (ctx) {\n ctx.translate(this.cx, this.cy);\n ctx.rotate(-1.0 * this.angle.toRadians());\n ctx.translate(-this.cx, -this.cy);\n };\n this.applyToPoint = function (p) {\n const _a = this.angle.toRadians();\n p.applyTransform([1, 0, 0, 1, this.p.x || 0.0, this.p.y || 0.0]);\n p.applyTransform([Math.cos(_a), Math.sin(_a), -Math.sin(_a), Math.cos(_a), 0, 0]);\n p.applyTransform([1, 0, 0, 1, -this.p.x || 0.0, -this.p.y || 0.0]);\n };\n }\n },\n scale: class {\n constructor (s) {\n this.p = svg.CreatePoint(s);\n this.apply = function (ctx) {\n ctx.scale(this.p.x || 1.0, this.p.y || this.p.x || 1.0);\n };\n this.unapply = function (ctx) {\n ctx.scale(1.0 / this.p.x || 1.0, 1.0 / this.p.y || this.p.x || 1.0);\n };\n this.applyToPoint = function (p) {\n p.applyTransform([this.p.x || 0.0, 0, 0, this.p.y || 0.0, 0, 0]);\n };\n }\n },\n matrix: class {\n constructor (s) {\n this.m = svg.ToNumberArray(s);\n this.apply = function (ctx) {\n ctx.transform(this.m[0], this.m[1], this.m[2], this.m[3], this.m[4], this.m[5]);\n };\n this.applyToPoint = function (p) {\n p.applyTransform(this.m);\n };\n }\n }\n };\n Object.assign(this.Type, {\n SkewBase: class extends this.Type.matrix {\n constructor (s) {\n super(s);\n this.angle = new svg.Property('angle', s);\n }\n }\n });\n Object.assign(this.Type, {\n skewX: class extends this.Type.SkewBase {\n constructor (s) {\n super(s);\n this.m = [1, 0, Math.tan(this.angle.toRadians()), 1, 0, 0];\n }\n },\n skewY: class extends this.Type.SkewBase {\n constructor (s) {\n super(s);\n this.m = [1, Math.tan(this.angle.toRadians()), 0, 1, 0, 0];\n }\n }\n });\n\n const data = svg.trim(svg.compressSpaces(v)).replace(\n /\\)([a-zA-Z])/g, ') $1'\n ).replace(/\\)(\\s?,\\s?)/g, ') ').split(/\\s(?=[a-z])/);\n this.transforms = data.map((d) => {\n const type = svg.trim(d.split('(')[0]);\n const s = d.split('(')[1].replace(')', '');\n const transform = new this.Type[type](s);\n transform.type = type;\n return transform;\n });\n }\n\n apply (ctx) {\n this.transforms.forEach((transform) => {\n transform.apply(ctx);\n });\n }\n\n unapply (ctx) {\n for (let i = this.transforms.length - 1; i >= 0; i--) {\n this.transforms[i].unapply(ctx);\n }\n }\n\n applyToPoint (p) {\n this.transforms.forEach((transform) => {\n transform.applyToPoint(p);\n });\n }\n };\n\n // aspect ratio\n svg.AspectRatio = function (ctx, aspectRatio, width, desiredWidth, height, desiredHeight, minX, minY, refX, refY) {\n // aspect ratio - https://www.w3.org/TR/SVG/coords.html#PreserveAspectRatioAttribute\n aspectRatio = svg.compressSpaces(aspectRatio);\n aspectRatio = aspectRatio.replace(/^defer\\s/, ''); // ignore defer\n const align = aspectRatio.split(' ')[0] || 'xMidYMid';\n const meetOrSlice = aspectRatio.split(' ')[1] || 'meet';\n\n // calculate scale\n const scaleX = width / desiredWidth;\n const scaleY = height / desiredHeight;\n const scaleMin = Math.min(scaleX, scaleY);\n const scaleMax = Math.max(scaleX, scaleY);\n if (meetOrSlice === 'meet') { desiredWidth *= scaleMin; desiredHeight *= scaleMin; }\n if (meetOrSlice === 'slice') { desiredWidth *= scaleMax; desiredHeight *= scaleMax; }\n\n refX = new svg.Property('refX', refX);\n refY = new svg.Property('refY', refY);\n if (refX.hasValue() && refY.hasValue()) {\n ctx.translate(-scaleMin * refX.toPixels('x'), -scaleMin * refY.toPixels('y'));\n } else {\n // align\n if (align.startsWith('xMid') &&\n ((meetOrSlice === 'meet' && scaleMin === scaleY) || (meetOrSlice === 'slice' && scaleMax === scaleY))) {\n ctx.translate(width / 2.0 - desiredWidth / 2.0, 0);\n }\n if (align.endsWith('YMid') &&\n ((meetOrSlice === 'meet' && scaleMin === scaleX) || (meetOrSlice === 'slice' && scaleMax === scaleX))) {\n ctx.translate(0, height / 2.0 - desiredHeight / 2.0);\n }\n if (align.startsWith('xMax') &&\n ((meetOrSlice === 'meet' && scaleMin === scaleY) || (meetOrSlice === 'slice' && scaleMax === scaleY))) {\n ctx.translate(width - desiredWidth, 0);\n }\n if (align.endsWith('YMax') &&\n ((meetOrSlice === 'meet' && scaleMin === scaleX) ||\n (meetOrSlice === 'slice' && scaleMax === scaleX)\n )\n ) {\n ctx.translate(0, height - desiredHeight);\n }\n }\n\n // scale\n if (align === 'none') ctx.scale(scaleX, scaleY);\n else if (meetOrSlice === 'meet') ctx.scale(scaleMin, scaleMin);\n else if (meetOrSlice === 'slice') ctx.scale(scaleMax, scaleMax);\n\n // translate\n ctx.translate(isNullish(minX) ? 0 : -minX, isNullish(minY) ? 0 : -minY);\n };\n\n // elements\n svg.Element = {};\n\n svg.EmptyProperty = new svg.Property('EMPTY', '');\n\n svg.Element.ElementBase = class {\n constructor (node) {\n // Argument from inheriting class\n this.captureTextNodes = arguments[1]; // eslint-disable-line prefer-rest-params\n this.attributes = {};\n this.styles = {};\n this.children = [];\n if (!isNullish(node) && node.nodeType === 1) { // ELEMENT_NODE\n // add children\n [...node.childNodes].forEach((childNode) => {\n if (childNode.nodeType === 1) {\n this.addChild(childNode, true); // ELEMENT_NODE\n }\n if (this.captureTextNodes && (\n childNode.nodeType === 3 || childNode.nodeType === 4\n )) {\n const text = childNode.nodeValue || childNode.text || '';\n if (svg.trim(svg.compressSpaces(text)) !== '') {\n this.addChild(new svg.Element.tspan(childNode), false); // TEXT_NODE\n }\n }\n });\n\n // add attributes\n [...node.attributes].forEach(({nodeName, nodeValue}) => {\n this.attributes[nodeName] = new svg.Property(\n nodeName,\n nodeValue\n );\n });\n // add tag styles\n let styles = svg.Styles[node.nodeName];\n if (!isNullish(styles)) {\n Object.entries(styles).forEach(([name, styleValue]) => {\n this.styles[name] = styleValue;\n });\n }\n\n // add class styles\n if (this.attribute('class').hasValue()) {\n const classes = svg.compressSpaces(this.attribute('class').value).split(' ');\n classes.forEach((clss) => {\n styles = svg.Styles['.' + clss];\n if (!isNullish(styles)) {\n Object.entries(styles).forEach(([name, styleValue]) => {\n this.styles[name] = styleValue;\n });\n }\n styles = svg.Styles[node.nodeName + '.' + clss];\n if (!isNullish(styles)) {\n Object.entries(styles).forEach(([name, styleValue]) => {\n this.styles[name] = styleValue;\n });\n }\n });\n }\n\n // add id styles\n if (this.attribute('id').hasValue()) {\n const _styles = svg.Styles['#' + this.attribute('id').value];\n if (!isNullish(_styles)) {\n Object.entries(_styles).forEach(([name, styleValue]) => {\n this.styles[name] = styleValue;\n });\n }\n }\n\n // add inline styles\n if (this.attribute('style').hasValue()) {\n const _styles = this.attribute('style').value.split(';');\n _styles.forEach((style) => {\n if (svg.trim(style) !== '') {\n let {name, value} = style.split(':');\n name = svg.trim(name);\n value = svg.trim(value);\n this.styles[name] = new svg.Property(name, value);\n }\n });\n }\n\n // add id\n if (this.attribute('id').hasValue()) {\n if (isNullish(svg.Definitions[this.attribute('id').value])) {\n svg.Definitions[this.attribute('id').value] = this;\n }\n }\n }\n }\n\n // get or create attribute\n attribute (name, createIfNotExists) {\n let a = this.attributes[name];\n if (!isNullish(a)) return a;\n\n if (createIfNotExists === true) { a = new svg.Property(name, ''); this.attributes[name] = a; }\n return a || svg.EmptyProperty;\n }\n\n getHrefAttribute () {\n for (const a in this.attributes) {\n if (a.endsWith(':href')) {\n return this.attributes[a];\n }\n }\n return svg.EmptyProperty;\n }\n\n // get or create style, crawls up node tree\n style (name, createIfNotExists, skipAncestors) {\n let s = this.styles[name];\n if (!isNullish(s)) return s;\n\n const a = this.attribute(name);\n if (!isNullish(a) && a.hasValue()) {\n this.styles[name] = a; // move up to me to cache\n return a;\n }\n\n if (skipAncestors !== true) {\n const p = this.parent;\n if (!isNullish(p)) {\n const ps = p.style(name);\n if (!isNullish(ps) && ps.hasValue()) {\n return ps;\n }\n }\n }\n\n if (createIfNotExists === true) { s = new svg.Property(name, ''); this.styles[name] = s; }\n return s || svg.EmptyProperty;\n }\n\n // base render\n render (ctx) {\n // don't render display=none\n if (this.style('display').value === 'none') return;\n\n // don't render visibility=hidden\n if (this.style('visibility').value === 'hidden') return;\n\n ctx.save();\n if (this.attribute('mask').hasValue()) { // mask\n const mask = this.attribute('mask').getDefinition();\n if (!isNullish(mask)) mask.apply(ctx, this);\n } else if (this.style('filter').hasValue()) { // filter\n const filter = this.style('filter').getDefinition();\n if (!isNullish(filter)) filter.apply(ctx, this);\n } else {\n this.setContext(ctx);\n this.renderChildren(ctx);\n this.clearContext(ctx);\n }\n ctx.restore();\n }\n\n // base set context\n setContext (ctx) {\n // OVERRIDE ME!\n }\n\n // base clear context\n clearContext (ctx) {\n // OVERRIDE ME!\n }\n\n // base render children\n renderChildren (ctx) {\n this.children.forEach((child) => {\n child.render(ctx);\n });\n }\n\n addChild (childNode, create) {\n const child = create\n ? svg.CreateElement(childNode)\n : childNode;\n child.parent = this;\n if (child.type !== 'title') { this.children.push(child); }\n }\n };\n\n svg.Element.RenderedElementBase = class extends svg.Element.ElementBase {\n setContext (ctx) {\n // fill\n if (this.style('fill').isUrlDefinition()) {\n const fs = this.style('fill').getFillStyleDefinition(this, this.style('fill-opacity'));\n if (!isNullish(fs)) ctx.fillStyle = fs;\n } else if (this.style('fill').hasValue()) {\n const fillStyle = this.style('fill');\n if (fillStyle.value === 'currentColor') fillStyle.value = this.style('color').value;\n ctx.fillStyle = (fillStyle.value === 'none' ? 'rgba(0,0,0,0)' : fillStyle.value);\n }\n if (this.style('fill-opacity').hasValue()) {\n let fillStyle = new svg.Property('fill', ctx.fillStyle);\n fillStyle = fillStyle.addOpacity(this.style('fill-opacity'));\n ctx.fillStyle = fillStyle.value;\n }\n\n // stroke\n if (this.style('stroke').isUrlDefinition()) {\n const fs = this.style('stroke').getFillStyleDefinition(this, this.style('stroke-opacity'));\n if (!isNullish(fs)) ctx.strokeStyle = fs;\n } else if (this.style('stroke').hasValue()) {\n const strokeStyle = this.style('stroke');\n if (strokeStyle.value === 'currentColor') strokeStyle.value = this.style('color').value;\n ctx.strokeStyle = (strokeStyle.value === 'none' ? 'rgba(0,0,0,0)' : strokeStyle.value);\n }\n if (this.style('stroke-opacity').hasValue()) {\n let strokeStyle = new svg.Property('stroke', ctx.strokeStyle);\n strokeStyle = strokeStyle.addOpacity(this.style('stroke-opacity'));\n ctx.strokeStyle = strokeStyle.value;\n }\n if (this.style('stroke-width').hasValue()) {\n const newLineWidth = this.style('stroke-width').toPixels();\n ctx.lineWidth = newLineWidth === 0 ? 0.001 : newLineWidth; // browsers don't respect 0\n }\n if (this.style('stroke-linecap').hasValue()) ctx.lineCap = this.style('stroke-linecap').value;\n if (this.style('stroke-linejoin').hasValue()) ctx.lineJoin = this.style('stroke-linejoin').value;\n if (this.style('stroke-miterlimit').hasValue()) ctx.miterLimit = this.style('stroke-miterlimit').value;\n if (this.style('stroke-dasharray').hasValue() && this.style('stroke-dasharray').value !== 'none') {\n const gaps = svg.ToNumberArray(this.style('stroke-dasharray').value);\n if (typeof ctx.setLineDash !== 'undefined') {\n ctx.setLineDash(gaps);\n } else if (typeof ctx.webkitLineDash !== 'undefined') {\n ctx.webkitLineDash = gaps;\n } else if (typeof ctx.mozDash !== 'undefined' && !(gaps.length === 1 && gaps[0] === 0)) {\n ctx.mozDash = gaps;\n }\n\n const offset = this.style('stroke-dashoffset').numValueOrDefault(1);\n if (typeof ctx.lineDashOffset !== 'undefined') {\n ctx.lineDashOffset = offset;\n } else if (typeof ctx.webkitLineDashOffset !== 'undefined') {\n ctx.webkitLineDashOffset = offset;\n } else if (typeof ctx.mozDashOffset !== 'undefined') {\n ctx.mozDashOffset = offset;\n }\n }\n\n // font\n if (typeof ctx.font !== 'undefined') {\n ctx.font = svg.Font.CreateFont(\n this.style('font-style').value,\n this.style('font-variant').value,\n this.style('font-weight').value,\n this.style('font-size').hasValue() ? this.style('font-size').toPixels() + 'px' : '',\n this.style('font-family').value\n ).toString();\n }\n\n // transform\n if (this.attribute('transform').hasValue()) {\n const transform = new svg.Transform(this.attribute('transform').value);\n transform.apply(ctx);\n }\n\n // clip\n if (this.style('clip-path', false, true).hasValue()) {\n const clip = this.style('clip-path', false, true).getDefinition();\n if (!isNullish(clip)) clip.apply(ctx);\n }\n\n // opacity\n if (this.style('opacity').hasValue()) {\n ctx.globalAlpha = this.style('opacity').numValue();\n }\n }\n };\n\n svg.Element.PathElementBase = class extends svg.Element.RenderedElementBase {\n path (ctx) {\n if (!isNullish(ctx)) ctx.beginPath();\n return new svg.BoundingBox();\n }\n\n renderChildren (ctx) {\n this.path(ctx);\n svg.Mouse.checkPath(this, ctx);\n if (ctx.fillStyle !== '') {\n if (this.style('fill-rule').valueOrDefault('inherit') !== 'inherit') {\n ctx.fill(this.style('fill-rule').value);\n } else {\n ctx.fill();\n }\n }\n if (ctx.strokeStyle !== '') ctx.stroke();\n\n const markers = this.getMarkers();\n if (!isNullish(markers)) {\n if (this.style('marker-start').isUrlDefinition()) {\n const marker = this.style('marker-start').getDefinition();\n marker.render(ctx, markers[0][0], markers[0][1]);\n }\n if (this.style('marker-mid').isUrlDefinition()) {\n const marker = this.style('marker-mid').getDefinition();\n for (let i = 1; i < markers.length - 1; i++) {\n marker.render(ctx, markers[i][0], markers[i][1]);\n }\n }\n if (this.style('marker-end').isUrlDefinition()) {\n const marker = this.style('marker-end').getDefinition();\n marker.render(ctx, markers[markers.length - 1][0], markers[markers.length - 1][1]);\n }\n }\n }\n\n getBoundingBox () {\n return this.path();\n }\n\n getMarkers () {\n return null;\n }\n };\n\n // svg element\n svg.Element.svg = class extends svg.Element.RenderedElementBase {\n clearContext (ctx) {\n super.clearContext(ctx);\n svg.ViewPort.RemoveCurrent();\n }\n\n setContext (ctx) {\n // initial values and defaults\n ctx.strokeStyle = 'rgba(0,0,0,0)';\n ctx.lineCap = 'butt';\n ctx.lineJoin = 'miter';\n ctx.miterLimit = 4;\n if (typeof ctx.font !== 'undefined' && typeof window.getComputedStyle !== 'undefined') {\n ctx.font = window.getComputedStyle(ctx.canvas).getPropertyValue('font');\n }\n\n super.setContext(ctx);\n\n // create new view port\n if (!this.attribute('x').hasValue()) this.attribute('x', true).value = 0;\n if (!this.attribute('y').hasValue()) this.attribute('y', true).value = 0;\n ctx.translate(this.attribute('x').toPixels('x'), this.attribute('y').toPixels('y'));\n\n let width = svg.ViewPort.width();\n let height = svg.ViewPort.height();\n\n if (!this.attribute('width').hasValue()) this.attribute('width', true).value = '100%';\n if (!this.attribute('height').hasValue()) this.attribute('height', true).value = '100%';\n if (typeof this.root === 'undefined') {\n width = this.attribute('width').toPixels('x');\n height = this.attribute('height').toPixels('y');\n\n let x = 0;\n let y = 0;\n if (this.attribute('refX').hasValue() && this.attribute('refY').hasValue()) {\n x = -this.attribute('refX').toPixels('x');\n y = -this.attribute('refY').toPixels('y');\n }\n\n if (this.attribute('overflow').valueOrDefault('hidden') !== 'visible') {\n ctx.beginPath();\n ctx.moveTo(x, y);\n ctx.lineTo(width, y);\n ctx.lineTo(width, height);\n ctx.lineTo(x, height);\n ctx.closePath();\n ctx.clip();\n }\n }\n svg.ViewPort.SetCurrent(width, height);\n\n // viewbox\n if (this.attribute('viewBox').hasValue()) {\n const viewBox = svg.ToNumberArray(this.attribute('viewBox').value);\n const minX = viewBox[0];\n const minY = viewBox[1];\n width = viewBox[2];\n height = viewBox[3];\n\n svg.AspectRatio(\n ctx,\n this.attribute('preserveAspectRatio').value,\n svg.ViewPort.width(),\n width,\n svg.ViewPort.height(),\n height,\n minX,\n minY,\n this.attribute('refX').value,\n this.attribute('refY').value\n );\n\n svg.ViewPort.RemoveCurrent();\n svg.ViewPort.SetCurrent(viewBox[2], viewBox[3]);\n }\n }\n };\n\n // rect element\n svg.Element.rect = class extends svg.Element.PathElementBase {\n path (ctx) {\n const x = this.attribute('x').toPixels('x');\n const y = this.attribute('y').toPixels('y');\n const width = this.attribute('width').toPixels('x');\n const height = this.attribute('height').toPixels('y');\n let rx = this.attribute('rx').toPixels('x');\n let ry = this.attribute('ry').toPixels('y');\n if (this.attribute('rx').hasValue() && !this.attribute('ry').hasValue()) ry = rx;\n if (this.attribute('ry').hasValue() && !this.attribute('rx').hasValue()) rx = ry;\n rx = Math.min(rx, width / 2.0);\n ry = Math.min(ry, height / 2.0);\n if (!isNullish(ctx)) {\n ctx.beginPath();\n ctx.moveTo(x + rx, y);\n ctx.lineTo(x + width - rx, y);\n ctx.quadraticCurveTo(x + width, y, x + width, y + ry);\n ctx.lineTo(x + width, y + height - ry);\n ctx.quadraticCurveTo(x + width, y + height, x + width - rx, y + height);\n ctx.lineTo(x + rx, y + height);\n ctx.quadraticCurveTo(x, y + height, x, y + height - ry);\n ctx.lineTo(x, y + ry);\n ctx.quadraticCurveTo(x, y, x + rx, y);\n ctx.closePath();\n }\n\n return new svg.BoundingBox(x, y, x + width, y + height);\n }\n };\n\n // circle element\n svg.Element.circle = class extends svg.Element.PathElementBase {\n path (ctx) {\n const cx = this.attribute('cx').toPixels('x');\n const cy = this.attribute('cy').toPixels('y');\n const r = this.attribute('r').toPixels();\n\n if (!isNullish(ctx)) {\n ctx.beginPath();\n ctx.arc(cx, cy, r, 0, Math.PI * 2, true);\n ctx.closePath();\n }\n\n return new svg.BoundingBox(cx - r, cy - r, cx + r, cy + r);\n }\n };\n\n // ellipse element\n const KAPPA = 4 * ((Math.sqrt(2) - 1) / 3);\n svg.Element.ellipse = class extends svg.Element.PathElementBase {\n path (ctx) {\n const rx = this.attribute('rx').toPixels('x');\n const ry = this.attribute('ry').toPixels('y');\n const cx = this.attribute('cx').toPixels('x');\n const cy = this.attribute('cy').toPixels('y');\n\n if (!isNullish(ctx)) {\n ctx.beginPath();\n ctx.moveTo(cx, cy - ry);\n ctx.bezierCurveTo(cx + (KAPPA * rx), cy - ry, cx + rx, cy - (KAPPA * ry), cx + rx, cy);\n ctx.bezierCurveTo(cx + rx, cy + (KAPPA * ry), cx + (KAPPA * rx), cy + ry, cx, cy + ry);\n ctx.bezierCurveTo(cx - (KAPPA * rx), cy + ry, cx - rx, cy + (KAPPA * ry), cx - rx, cy);\n ctx.bezierCurveTo(cx - rx, cy - (KAPPA * ry), cx - (KAPPA * rx), cy - ry, cx, cy - ry);\n ctx.closePath();\n }\n\n return new svg.BoundingBox(cx - rx, cy - ry, cx + rx, cy + ry);\n }\n };\n\n // line element\n svg.Element.line = class extends svg.Element.PathElementBase {\n getPoints () {\n return [\n new svg.Point(this.attribute('x1').toPixels('x'), this.attribute('y1').toPixels('y')),\n new svg.Point(this.attribute('x2').toPixels('x'), this.attribute('y2').toPixels('y'))\n ];\n }\n\n path (ctx) {\n const points = this.getPoints();\n\n if (!isNullish(ctx)) {\n ctx.beginPath();\n ctx.moveTo(points[0].x, points[0].y);\n ctx.lineTo(points[1].x, points[1].y);\n }\n\n return new svg.BoundingBox(points[0].x, points[0].y, points[1].x, points[1].y);\n }\n\n getMarkers () {\n const points = this.getPoints();\n const a = points[0].angleTo(points[1]);\n return [[points[0], a], [points[1], a]];\n }\n };\n\n // polyline element\n svg.Element.polyline = class extends svg.Element.PathElementBase {\n constructor (node) {\n super(node);\n\n this.points = svg.CreatePath(this.attribute('points').value);\n }\n path (ctx) {\n const {x, y} = this.points[0];\n const bb = new svg.BoundingBox(x, y);\n if (!isNullish(ctx)) {\n ctx.beginPath();\n ctx.moveTo(x, y);\n }\n for (let i = 1; i < this.points.length; i++) {\n const {x: _x, y: _y} = this.points[i];\n bb.addPoint(_x, _y);\n if (!isNullish(ctx)) ctx.lineTo(_x, _y);\n }\n return bb;\n }\n\n getMarkers () {\n const markers = [];\n for (let i = 0; i < this.points.length - 1; i++) {\n markers.push([this.points[i], this.points[i].angleTo(this.points[i + 1])]);\n }\n markers.push([this.points[this.points.length - 1], markers[markers.length - 1][1]]);\n return markers;\n }\n };\n\n // polygon element\n svg.Element.polygon = class extends svg.Element.polyline {\n path (ctx) {\n const bb = super.path(ctx);\n if (!isNullish(ctx)) {\n ctx.lineTo(this.points[0].x, this.points[0].y);\n ctx.closePath();\n }\n return bb;\n }\n };\n\n // path element\n svg.Element.path = class extends svg.Element.PathElementBase {\n constructor (node) {\n super(node);\n\n let d = this.attribute('d').value\n // TODO: convert to real lexer based on https://www.w3.org/TR/SVG11/paths.html#PathDataBNF\n .replace(/,/gm, ' ') // get rid of all commas\n .replace(/([MmZzLlHhVvCcSsQqTtAa])([MmZzLlHhVvCcSsQqTtAa])/gm, '$1 $2') // separate commands from commands\n .replace(/([MmZzLlHhVvCcSsQqTtAa])([MmZzLlHhVvCcSsQqTtAa])/gm, '$1 $2') // separate commands from commands\n .replace(/([MmZzLlHhVvCcSsQqTtAa])(\\S)/gm, '$1 $2') // separate commands from points\n .replace(/(\\S)([MmZzLlHhVvCcSsQqTtAa])/gm, '$1 $2') // separate commands from points\n .replace(/(\\d)([+-])/gm, '$1 $2') // separate digits when no comma\n .replace(/(\\.\\d*)(\\.)/gm, '$1 $2') // separate digits when no comma\n .replace(/([Aa](\\s+\\d+)(\\s+\\d+)(\\s+\\d+))\\s+([01])\\s*([01])/gm, '$1 $5 $6 '); // shorthand elliptical arc path syntax\n d = svg.compressSpaces(d); // compress multiple spaces\n d = svg.trim(d);\n this.PathParser = {\n tokens: d.split(' '),\n\n reset () {\n this.i = -1;\n this.command = '';\n this.previousCommand = '';\n this.start = new svg.Point(0, 0);\n this.control = new svg.Point(0, 0);\n this.current = new svg.Point(0, 0);\n this.points = [];\n this.angles = [];\n },\n\n isEnd () {\n return this.i >= this.tokens.length - 1;\n },\n\n isCommandOrEnd () {\n if (this.isEnd()) return true;\n return !isNullish(this.tokens[this.i + 1].match(/^[A-Za-z]$/));\n },\n\n isRelativeCommand () {\n switch (this.command) {\n case 'm':\n case 'l':\n case 'h':\n case 'v':\n case 'c':\n case 's':\n case 'q':\n case 't':\n case 'a':\n case 'z':\n return true;\n }\n return false;\n },\n\n getToken () {\n this.i++;\n return this.tokens[this.i];\n },\n\n getScalar () {\n return Number.parseFloat(this.getToken());\n },\n\n nextCommand () {\n this.previousCommand = this.command;\n this.command = this.getToken();\n },\n\n getPoint () {\n const p = new svg.Point(this.getScalar(), this.getScalar());\n return this.makeAbsolute(p);\n },\n\n getAsControlPoint () {\n const p = this.getPoint();\n this.control = p;\n return p;\n },\n\n getAsCurrentPoint () {\n const p = this.getPoint();\n this.current = p;\n return p;\n },\n\n getReflectedControlPoint () {\n if (this.previousCommand.toLowerCase() !== 'c' &&\n this.previousCommand.toLowerCase() !== 's' &&\n this.previousCommand.toLowerCase() !== 'q' &&\n this.previousCommand.toLowerCase() !== 't') {\n return this.current;\n }\n\n // reflect point\n const p = new svg.Point(2 * this.current.x - this.control.x, 2 * this.current.y - this.control.y);\n return p;\n },\n\n makeAbsolute (p) {\n if (this.isRelativeCommand()) {\n p.x += this.current.x;\n p.y += this.current.y;\n }\n return p;\n },\n\n addMarker (p, from, priorTo) {\n // if the last angle isn't filled in because we didn't have this point yet ...\n if (!isNullish(priorTo) && this.angles.length > 0 && isNullish(this.angles[this.angles.length - 1])) {\n this.angles[this.angles.length - 1] = this.points[this.points.length - 1].angleTo(priorTo);\n }\n this.addMarkerAngle(p, isNullish(from) ? null : from.angleTo(p));\n },\n\n addMarkerAngle (p, a) {\n this.points.push(p);\n this.angles.push(a);\n },\n\n getMarkerPoints () { return this.points; },\n getMarkerAngles () {\n for (let i = 0; i < this.angles.length; i++) {\n if (isNullish(this.angles[i])) {\n for (let j = i + 1; j < this.angles.length; j++) {\n if (!isNullish(this.angles[j])) {\n this.angles[i] = this.angles[j];\n break;\n }\n }\n }\n }\n return this.angles;\n }\n };\n }\n\n path (ctx) {\n const pp = this.PathParser;\n pp.reset();\n\n const bb = new svg.BoundingBox();\n if (!isNullish(ctx)) ctx.beginPath();\n while (!pp.isEnd()) {\n pp.nextCommand();\n switch (pp.command) {\n case 'M':\n case 'm': {\n const p = pp.getAsCurrentPoint();\n pp.addMarker(p);\n bb.addPoint(p.x, p.y);\n if (!isNullish(ctx)) ctx.moveTo(p.x, p.y);\n pp.start = pp.current;\n while (!pp.isCommandOrEnd()) {\n const _p = pp.getAsCurrentPoint();\n pp.addMarker(_p, pp.start);\n bb.addPoint(_p.x, _p.y);\n if (!isNullish(ctx)) ctx.lineTo(_p.x, _p.y);\n }\n break;\n } case 'L':\n case 'l':\n while (!pp.isCommandOrEnd()) {\n const c = pp.current;\n const p = pp.getAsCurrentPoint();\n pp.addMarker(p, c);\n bb.addPoint(p.x, p.y);\n if (!isNullish(ctx)) ctx.lineTo(p.x, p.y);\n }\n break;\n case 'H':\n case 'h':\n while (!pp.isCommandOrEnd()) {\n const newP = new svg.Point((pp.isRelativeCommand() ? pp.current.x : 0) + pp.getScalar(), pp.current.y);\n pp.addMarker(newP, pp.current);\n pp.current = newP;\n bb.addPoint(pp.current.x, pp.current.y);\n if (!isNullish(ctx)) ctx.lineTo(pp.current.x, pp.current.y);\n }\n break;\n case 'V':\n case 'v':\n while (!pp.isCommandOrEnd()) {\n const newP = new svg.Point(pp.current.x, (pp.isRelativeCommand() ? pp.current.y : 0) + pp.getScalar());\n pp.addMarker(newP, pp.current);\n pp.current = newP;\n bb.addPoint(pp.current.x, pp.current.y);\n if (!isNullish(ctx)) ctx.lineTo(pp.current.x, pp.current.y);\n }\n break;\n case 'C':\n case 'c':\n while (!pp.isCommandOrEnd()) {\n const curr = pp.current;\n const p1 = pp.getPoint();\n const cntrl = pp.getAsControlPoint();\n const cp = pp.getAsCurrentPoint();\n pp.addMarker(cp, cntrl, p1);\n bb.addBezierCurve(curr.x, curr.y, p1.x, p1.y, cntrl.x, cntrl.y, cp.x, cp.y);\n if (!isNullish(ctx)) ctx.bezierCurveTo(p1.x, p1.y, cntrl.x, cntrl.y, cp.x, cp.y);\n }\n break;\n case 'S':\n case 's':\n while (!pp.isCommandOrEnd()) {\n const curr = pp.current;\n const p1 = pp.getReflectedControlPoint();\n const cntrl = pp.getAsControlPoint();\n const cp = pp.getAsCurrentPoint();\n pp.addMarker(cp, cntrl, p1);\n bb.addBezierCurve(curr.x, curr.y, p1.x, p1.y, cntrl.x, cntrl.y, cp.x, cp.y);\n if (!isNullish(ctx)) ctx.bezierCurveTo(p1.x, p1.y, cntrl.x, cntrl.y, cp.x, cp.y);\n }\n break;\n case 'Q':\n case 'q':\n while (!pp.isCommandOrEnd()) {\n const curr = pp.current;\n const cntrl = pp.getAsControlPoint();\n const cp = pp.getAsCurrentPoint();\n pp.addMarker(cp, cntrl, cntrl);\n bb.addQuadraticCurve(curr.x, curr.y, cntrl.x, cntrl.y, cp.x, cp.y);\n if (!isNullish(ctx)) ctx.quadraticCurveTo(cntrl.x, cntrl.y, cp.x, cp.y);\n }\n break;\n case 'T':\n case 't':\n while (!pp.isCommandOrEnd()) {\n const curr = pp.current;\n const cntrl = pp.getReflectedControlPoint();\n pp.control = cntrl;\n const cp = pp.getAsCurrentPoint();\n pp.addMarker(cp, cntrl, cntrl);\n bb.addQuadraticCurve(curr.x, curr.y, cntrl.x, cntrl.y, cp.x, cp.y);\n if (!isNullish(ctx)) ctx.quadraticCurveTo(cntrl.x, cntrl.y, cp.x, cp.y);\n }\n break;\n case 'A':\n case 'a':\n while (!pp.isCommandOrEnd()) {\n const curr = pp.current;\n let rx = pp.getScalar();\n let ry = pp.getScalar();\n const xAxisRotation = pp.getScalar() * (Math.PI / 180.0);\n const largeArcFlag = pp.getScalar();\n const sweepFlag = pp.getScalar();\n const cp = pp.getAsCurrentPoint();\n\n // Conversion from endpoint to center parameterization\n // https://www.w3.org/TR/SVG11/implnote.html#ArcConversionEndpointToCenter\n\n // x1', y1'\n const currp = new svg.Point(\n Math.cos(xAxisRotation) * (curr.x - cp.x) / 2.0 + Math.sin(xAxisRotation) * (curr.y - cp.y) / 2.0,\n -Math.sin(xAxisRotation) * (curr.x - cp.x) / 2.0 + Math.cos(xAxisRotation) * (curr.y - cp.y) / 2.0\n );\n // adjust radii\n const l = (currp.x ** 2) / (rx ** 2) + (currp.y ** 2) / (ry ** 2);\n if (l > 1) {\n rx *= Math.sqrt(l);\n ry *= Math.sqrt(l);\n }\n // cx', cy'\n let s = (largeArcFlag === sweepFlag ? -1 : 1) * Math.sqrt(\n (((rx ** 2) * (ry ** 2)) - ((rx ** 2) * (currp.y ** 2)) - ((ry ** 2) * (currp.x ** 2))) /\n ((rx ** 2) * (currp.y ** 2) + (ry ** 2) * (currp.x ** 2))\n );\n if (isNaN(s)) s = 0;\n const cpp = new svg.Point(s * rx * currp.y / ry, s * -ry * currp.x / rx);\n // cx, cy\n const centp = new svg.Point(\n (curr.x + cp.x) / 2.0 + Math.cos(xAxisRotation) * cpp.x - Math.sin(xAxisRotation) * cpp.y,\n (curr.y + cp.y) / 2.0 + Math.sin(xAxisRotation) * cpp.x + Math.cos(xAxisRotation) * cpp.y\n );\n // vector magnitude\n const m = function (v) {\n return Math.sqrt((v[0] ** 2) + (v[1] ** 2));\n };\n // ratio between two vectors\n const r = function (u, v) {\n return (u[0] * v[0] + u[1] * v[1]) / (m(u) * m(v));\n };\n // angle between two vectors\n const a = function (u, v) {\n return (u[0] * v[1] < u[1] * v[0] ? -1 : 1) * Math.acos(r(u, v));\n };\n // initial angle\n const a1 = a([1, 0], [(currp.x - cpp.x) / rx, (currp.y - cpp.y) / ry]);\n // angle delta\n const u = [(currp.x - cpp.x) / rx, (currp.y - cpp.y) / ry];\n const v = [(-currp.x - cpp.x) / rx, (-currp.y - cpp.y) / ry];\n let ad = a(u, v);\n if (r(u, v) <= -1) ad = Math.PI;\n if (r(u, v) >= 1) ad = 0;\n\n // for markers\n const dir = 1 - sweepFlag ? 1.0 : -1.0;\n const ah = a1 + dir * (ad / 2.0);\n const halfWay = new svg.Point(\n centp.x + rx * Math.cos(ah),\n centp.y + ry * Math.sin(ah)\n );\n pp.addMarkerAngle(halfWay, ah - dir * Math.PI / 2);\n pp.addMarkerAngle(cp, ah - dir * Math.PI);\n\n bb.addPoint(cp.x, cp.y); // TODO: this is too naive, make it better\n if (!isNullish(ctx)) {\n const _r = rx > ry ? rx : ry;\n const sx = rx > ry ? 1 : rx / ry;\n const sy = rx > ry ? ry / rx : 1;\n\n ctx.translate(centp.x, centp.y);\n ctx.rotate(xAxisRotation);\n ctx.scale(sx, sy);\n ctx.arc(0, 0, _r, a1, a1 + ad, 1 - sweepFlag);\n ctx.scale(1 / sx, 1 / sy);\n ctx.rotate(-xAxisRotation);\n ctx.translate(-centp.x, -centp.y);\n }\n }\n break;\n case 'Z':\n case 'z':\n if (!isNullish(ctx)) ctx.closePath();\n pp.current = pp.start;\n }\n }\n\n return bb;\n }\n\n getMarkers () {\n const points = this.PathParser.getMarkerPoints();\n const angles = this.PathParser.getMarkerAngles();\n\n const markers = points.map((point, i) => {\n return [point, angles[i]];\n });\n return markers;\n }\n };\n\n // pattern element\n svg.Element.pattern = class extends svg.Element.ElementBase {\n createPattern (ctx, element) {\n const width = this.attribute('width').toPixels('x', true);\n const height = this.attribute('height').toPixels('y', true);\n\n // render me using a temporary svg element\n const tempSvg = new svg.Element.svg();\n tempSvg.attributes.viewBox = new svg.Property('viewBox', this.attribute('viewBox').value);\n tempSvg.attributes.width = new svg.Property('width', width + 'px');\n tempSvg.attributes.height = new svg.Property('height', height + 'px');\n tempSvg.attributes.transform = new svg.Property('transform', this.attribute('patternTransform').value);\n tempSvg.children = this.children;\n\n const c = document.createElement('canvas');\n c.width = width;\n c.height = height;\n const cctx = c.getContext('2d');\n if (this.attribute('x').hasValue() && this.attribute('y').hasValue()) {\n cctx.translate(this.attribute('x').toPixels('x', true), this.attribute('y').toPixels('y', true));\n }\n // render 3x3 grid so when we transform there's no white space on edges\n for (let x = -1; x <= 1; x++) {\n for (let y = -1; y <= 1; y++) {\n cctx.save();\n cctx.translate(x * c.width, y * c.height);\n tempSvg.render(cctx);\n cctx.restore();\n }\n }\n const pattern = ctx.createPattern(c, 'repeat');\n return pattern;\n }\n };\n\n // marker element\n svg.Element.marker = class extends svg.Element.ElementBase {\n render (ctx, point, angle) {\n ctx.translate(point.x, point.y);\n if (this.attribute('orient').valueOrDefault('auto') === 'auto') ctx.rotate(angle);\n if (this.attribute('markerUnits').valueOrDefault('strokeWidth') === 'strokeWidth') ctx.scale(ctx.lineWidth, ctx.lineWidth);\n ctx.save();\n\n // render me using a temporary svg element\n const tempSvg = new svg.Element.svg();\n tempSvg.attributes.viewBox = new svg.Property(\n 'viewBox', this.attribute('viewBox').value\n );\n tempSvg.attributes.refX = new svg.Property(\n 'refX', this.attribute('refX').value\n );\n tempSvg.attributes.refY = new svg.Property(\n 'refY', this.attribute('refY').value\n );\n tempSvg.attributes.width = new svg.Property(\n 'width', this.attribute('markerWidth').value\n );\n tempSvg.attributes.height = new svg.Property(\n 'height', this.attribute('markerHeight').value\n );\n tempSvg.attributes.fill = new svg.Property(\n 'fill', this.attribute('fill').valueOrDefault('black')\n );\n tempSvg.attributes.stroke = new svg.Property(\n 'stroke', this.attribute('stroke').valueOrDefault('none')\n );\n tempSvg.children = this.children;\n tempSvg.render(ctx);\n\n ctx.restore();\n if (this.attribute('markerUnits').valueOrDefault('strokeWidth') ===\n 'strokeWidth'\n ) ctx.scale(1 / ctx.lineWidth, 1 / ctx.lineWidth);\n if (this.attribute('orient').valueOrDefault('auto') === 'auto') {\n ctx.rotate(-angle);\n }\n ctx.translate(-point.x, -point.y);\n }\n };\n\n // definitions element\n svg.Element.defs = class extends svg.Element.ElementBase {\n render (ctx) {\n // NOOP\n }\n };\n\n // base for gradients\n svg.Element.GradientBase = class extends svg.Element.ElementBase {\n constructor (node) {\n super(node);\n\n this.gradientUnits = this.attribute('gradientUnits').valueOrDefault('objectBoundingBox');\n\n this.stops = [];\n this.children.forEach((child) => {\n if (child.type === 'stop') {\n this.stops.push(child);\n }\n });\n }\n\n getGradient () {\n // OVERRIDE ME!\n }\n\n createGradient (ctx, element, parentOpacityProp) {\n const stopsContainer = this.getHrefAttribute().hasValue()\n ? this.getHrefAttribute().getDefinition()\n : this;\n\n const addParentOpacity = function (color) {\n if (parentOpacityProp.hasValue()) {\n const p = new svg.Property('color', color);\n return p.addOpacity(parentOpacityProp).value;\n }\n return color;\n };\n\n const g = this.getGradient(ctx, element);\n if (isNullish(g)) return addParentOpacity(stopsContainer.stops[stopsContainer.stops.length - 1].color);\n stopsContainer.stops.forEach(({offset, color}) => {\n g.addColorStop(offset, addParentOpacity(color));\n });\n\n if (this.attribute('gradientTransform').hasValue()) {\n // render as transformed pattern on temporary canvas\n const rootView = svg.ViewPort.viewPorts[0];\n\n const rect = new svg.Element.rect();\n rect.attributes.x = new svg.Property('x', -svg.MAX_VIRTUAL_PIXELS / 3.0);\n rect.attributes.y = new svg.Property('y', -svg.MAX_VIRTUAL_PIXELS / 3.0);\n rect.attributes.width = new svg.Property('width', svg.MAX_VIRTUAL_PIXELS);\n rect.attributes.height = new svg.Property('height', svg.MAX_VIRTUAL_PIXELS);\n\n const group = new svg.Element.g();\n group.attributes.transform = new svg.Property('transform', this.attribute('gradientTransform').value);\n group.children = [rect];\n\n const tempSvg = new svg.Element.svg();\n tempSvg.attributes.x = new svg.Property('x', 0);\n tempSvg.attributes.y = new svg.Property('y', 0);\n tempSvg.attributes.width = new svg.Property('width', rootView.width);\n tempSvg.attributes.height = new svg.Property('height', rootView.height);\n tempSvg.children = [group];\n\n const c = document.createElement('canvas');\n c.width = rootView.width;\n c.height = rootView.height;\n const tempCtx = c.getContext('2d');\n tempCtx.fillStyle = g;\n tempSvg.render(tempCtx);\n return tempCtx.createPattern(c, 'no-repeat');\n }\n\n return g;\n }\n };\n\n // linear gradient element\n svg.Element.linearGradient = class extends svg.Element.GradientBase {\n getGradient (ctx, element) {\n const useBB = this.gradientUnits === 'objectBoundingBox' && element.getBoundingBox;\n const bb = useBB\n ? element.getBoundingBox()\n : null;\n\n if (!this.attribute('x1').hasValue() &&\n !this.attribute('y1').hasValue() &&\n !this.attribute('x2').hasValue() &&\n !this.attribute('y2').hasValue()\n ) {\n this.attribute('x1', true).value = 0;\n this.attribute('y1', true).value = 0;\n this.attribute('x2', true).value = 1;\n this.attribute('y2', true).value = 0;\n }\n\n const x1 = (useBB\n ? bb.x() + bb.width() * this.attribute('x1').numValue()\n : this.attribute('x1').toPixels('x'));\n const y1 = (useBB\n ? bb.y() + bb.height() * this.attribute('y1').numValue()\n : this.attribute('y1').toPixels('y'));\n const x2 = (useBB\n ? bb.x() + bb.width() * this.attribute('x2').numValue()\n : this.attribute('x2').toPixels('x'));\n const y2 = (useBB\n ? bb.y() + bb.height() * this.attribute('y2').numValue()\n : this.attribute('y2').toPixels('y'));\n\n if (x1 === x2 && y1 === y2) return null;\n return ctx.createLinearGradient(x1, y1, x2, y2);\n }\n };\n\n // radial gradient element\n svg.Element.radialGradient = class extends svg.Element.GradientBase {\n getGradient (ctx, element) {\n const useBB = this.gradientUnits === 'objectBoundingBox' && element.getBoundingBox;\n const bb = useBB ? element.getBoundingBox() : null;\n\n if (!this.attribute('cx').hasValue()) this.attribute('cx', true).value = '50%';\n if (!this.attribute('cy').hasValue()) this.attribute('cy', true).value = '50%';\n if (!this.attribute('r').hasValue()) this.attribute('r', true).value = '50%';\n\n const cx = (useBB\n ? bb.x() + bb.width() * this.attribute('cx').numValue()\n : this.attribute('cx').toPixels('x'));\n const cy = (useBB\n ? bb.y() + bb.height() * this.attribute('cy').numValue()\n : this.attribute('cy').toPixels('y'));\n\n let fx = cx;\n let fy = cy;\n if (this.attribute('fx').hasValue()) {\n fx = (useBB\n ? bb.x() + bb.width() * this.attribute('fx').numValue()\n : this.attribute('fx').toPixels('x'));\n }\n if (this.attribute('fy').hasValue()) {\n fy = (useBB\n ? bb.y() + bb.height() * this.attribute('fy').numValue()\n : this.attribute('fy').toPixels('y'));\n }\n\n const r = (useBB\n ? (bb.width() + bb.height()) / 2.0 * this.attribute('r').numValue()\n : this.attribute('r').toPixels());\n\n return ctx.createRadialGradient(fx, fy, 0, cx, cy, r);\n }\n };\n\n // gradient stop element\n svg.Element.stop = class extends svg.Element.ElementBase {\n constructor (node) {\n super(node);\n\n this.offset = this.attribute('offset').numValue();\n if (this.offset < 0) this.offset = 0;\n if (this.offset > 1) this.offset = 1;\n\n let stopColor = this.style('stop-color');\n if (this.style('stop-opacity').hasValue()) {\n stopColor = stopColor.addOpacity(this.style('stop-opacity'));\n }\n this.color = stopColor.value;\n }\n };\n\n // animation base element\n svg.Element.AnimateBase = class extends svg.Element.ElementBase {\n constructor (node) {\n super(node);\n\n svg.Animations.push(this);\n\n this.duration = 0.0;\n this.begin = this.attribute('begin').toMilliseconds();\n this.maxDuration = this.begin + this.attribute('dur').toMilliseconds();\n\n this.initialValue = null;\n this.initialUnits = '';\n this.removed = false;\n\n this.from = this.attribute('from');\n this.to = this.attribute('to');\n this.values = this.attribute('values');\n if (this.values.hasValue()) this.values.value = this.values.value.split(';');\n }\n\n getProperty () {\n const attributeType = this.attribute('attributeType').value;\n const attributeName = this.attribute('attributeName').value;\n\n if (attributeType === 'CSS') {\n return this.parent.style(attributeName, true);\n }\n return this.parent.attribute(attributeName, true);\n }\n\n calcValue () {\n // OVERRIDE ME!\n return '';\n }\n\n update (delta) {\n // set initial value\n if (isNullish(this.initialValue)) {\n this.initialValue = this.getProperty().value;\n this.initialUnits = this.getProperty().getUnits();\n }\n\n // if we're past the end time\n if (this.duration > this.maxDuration) {\n // loop for indefinitely repeating animations\n if (this.attribute('repeatCount').value === 'indefinite' ||\n this.attribute('repeatDur').value === 'indefinite') {\n this.duration = 0.0;\n } else if (this.attribute('fill').valueOrDefault('remove') === 'freeze' && !this.frozen) {\n this.frozen = true;\n this.parent.animationFrozen = true;\n this.parent.animationFrozenValue = this.getProperty().value;\n } else if (this.attribute('fill').valueOrDefault('remove') === 'remove' && !this.removed) {\n this.removed = true;\n this.getProperty().value = this.parent.animationFrozen ? this.parent.animationFrozenValue : this.initialValue;\n return true;\n }\n return false;\n }\n this.duration += delta;\n\n // if we're past the begin time\n let updated = false;\n if (this.begin < this.duration) {\n let newValue = this.calcValue(); // tween\n\n if (this.attribute('type').hasValue()) {\n // for transform, etc.\n const type = this.attribute('type').value;\n newValue = type + '(' + newValue + ')';\n }\n\n this.getProperty().value = newValue;\n updated = true;\n }\n\n return updated;\n }\n\n // fraction of duration we've covered\n progress () {\n const ret = {progress: (this.duration - this.begin) / (this.maxDuration - this.begin)};\n if (this.values.hasValue()) {\n const p = ret.progress * (this.values.value.length - 1);\n const lb = Math.floor(p), ub = Math.ceil(p);\n ret.from = new svg.Property('from', Number.parseFloat(this.values.value[lb]));\n ret.to = new svg.Property('to', Number.parseFloat(this.values.value[ub]));\n ret.progress = (p - lb) / (ub - lb);\n } else {\n ret.from = this.from;\n ret.to = this.to;\n }\n return ret;\n }\n };\n\n // animate element\n svg.Element.animate = class extends svg.Element.AnimateBase {\n calcValue () {\n const p = this.progress();\n\n // tween value linearly\n const newValue = p.from.numValue() + (p.to.numValue() - p.from.numValue()) * p.progress;\n return newValue + this.initialUnits;\n }\n };\n\n // animate color element\n svg.Element.animateColor = class extends svg.Element.AnimateBase {\n calcValue () {\n const p = this.progress();\n const from = new RGBColor(p.from.value);\n const to = new RGBColor(p.to.value);\n\n if (from.ok && to.ok) {\n // tween color linearly\n const r = from.r + (to.r - from.r) * p.progress;\n const g = from.g + (to.g - from.g) * p.progress;\n const b = from.b + (to.b - from.b) * p.progress;\n return 'rgb(' + Number.parseInt(r) + ',' + Number.parseInt(g) + ',' + Number.parseInt(b) + ')';\n }\n return this.attribute('from').value;\n }\n };\n\n // animate transform element\n svg.Element.animateTransform = class extends svg.Element.animate {\n calcValue () {\n const p = this.progress();\n\n // tween value linearly\n const from = svg.ToNumberArray(p.from.value);\n const to = svg.ToNumberArray(p.to.value);\n let newValue = '';\n from.forEach((fr, i) => {\n newValue += fr + (to[i] - fr) * p.progress + ' ';\n });\n return newValue;\n }\n };\n\n // font element\n svg.Element.font = class extends svg.Element.ElementBase {\n constructor (node) {\n super(node);\n\n this.horizAdvX = this.attribute('horiz-adv-x').numValue();\n\n this.isRTL = false;\n this.isArabic = false;\n this.fontFace = null;\n this.missingGlyph = null;\n this.glyphs = [];\n this.children.forEach((child) => {\n if (child.type === 'font-face') {\n this.fontFace = child;\n if (child.style('font-family').hasValue()) {\n svg.Definitions[child.style('font-family').value] = this;\n }\n } else if (child.type === 'missing-glyph') {\n this.missingGlyph = child;\n } else if (child.type === 'glyph') {\n if (child.arabicForm !== '') {\n this.isRTL = true;\n this.isArabic = true;\n if (typeof this.glyphs[child.unicode] === 'undefined') {\n this.glyphs[child.unicode] = [];\n }\n this.glyphs[child.unicode][child.arabicForm] = child;\n } else {\n this.glyphs[child.unicode] = child;\n }\n }\n });\n }\n };\n\n // font-face element\n svg.Element.fontface = class extends svg.Element.ElementBase {\n constructor (node) {\n super(node);\n\n this.ascent = this.attribute('ascent').value;\n this.descent = this.attribute('descent').value;\n this.unitsPerEm = this.attribute('units-per-em').numValue();\n }\n };\n\n // missing-glyph element\n svg.Element.missingglyph = class extends svg.Element.path {\n constructor (node) {\n super(node);\n\n this.horizAdvX = 0;\n }\n };\n\n // glyph element\n svg.Element.glyph = class extends svg.Element.path {\n constructor (node) {\n super(node);\n\n this.horizAdvX = this.attribute('horiz-adv-x').numValue();\n this.unicode = this.attribute('unicode').value;\n this.arabicForm = this.attribute('arabic-form').value;\n }\n };\n\n // text element\n svg.Element.text = class extends svg.Element.RenderedElementBase {\n constructor (node) {\n super(node, true);\n }\n\n setContext (ctx) {\n super.setContext(ctx);\n\n let textBaseline = this.style('dominant-baseline').toTextBaseline();\n if (isNullish(textBaseline)) textBaseline = this.style('alignment-baseline').toTextBaseline();\n if (!isNullish(textBaseline)) ctx.textBaseline = textBaseline;\n }\n\n getBoundingBox () {\n const x = this.attribute('x').toPixels('x');\n const y = this.attribute('y').toPixels('y');\n const fontSize = this.parent.style('font-size').numValueOrDefault(svg.Font.Parse(svg.ctx.font).fontSize);\n return new svg.BoundingBox(x, y - fontSize, x + Math.floor(fontSize * 2.0 / 3.0) * this.children[0].getText().length, y);\n }\n\n renderChildren (ctx) {\n this.x = this.attribute('x').toPixels('x');\n this.y = this.attribute('y').toPixels('y');\n this.x += this.getAnchorDelta(ctx, this, 0);\n this.children.forEach((child, i) => {\n this.renderChild(ctx, this, i);\n });\n }\n\n getAnchorDelta (ctx, parent, startI) {\n const textAnchor = this.style('text-anchor').valueOrDefault('start');\n if (textAnchor !== 'start') {\n let width = 0;\n for (let i = startI; i < parent.children.length; i++) {\n const child = parent.children[i];\n if (i > startI && child.attribute('x').hasValue()) break; // new group\n width += child.measureTextRecursive(ctx);\n }\n return -1 * (textAnchor === 'end' ? width : width / 2.0);\n }\n return 0;\n }\n\n renderChild (ctx, parent, i) {\n const child = parent.children[i];\n if (child.attribute('x').hasValue()) {\n child.x = child.attribute('x').toPixels('x') + this.getAnchorDelta(ctx, parent, i);\n if (child.attribute('dx').hasValue()) child.x += child.attribute('dx').toPixels('x');\n } else {\n if (this.attribute('dx').hasValue()) this.x += this.attribute('dx').toPixels('x');\n if (child.attribute('dx').hasValue()) this.x += child.attribute('dx').toPixels('x');\n child.x = this.x;\n }\n this.x = child.x + child.measureText(ctx);\n\n if (child.attribute('y').hasValue()) {\n child.y = child.attribute('y').toPixels('y');\n if (child.attribute('dy').hasValue()) child.y += child.attribute('dy').toPixels('y');\n } else {\n if (this.attribute('dy').hasValue()) this.y += this.attribute('dy').toPixels('y');\n if (child.attribute('dy').hasValue()) this.y += child.attribute('dy').toPixels('y');\n child.y = this.y;\n }\n this.y = child.y;\n\n child.render(ctx);\n\n for (let j = 0; j < child.children.length; j++) {\n this.renderChild(ctx, child, j);\n }\n }\n };\n\n // text base\n svg.Element.TextElementBase = class extends svg.Element.RenderedElementBase {\n getGlyph (font, text, i) {\n const c = text[i];\n let glyph = null;\n if (font.isArabic) {\n let arabicForm = 'isolated';\n if ((i === 0 || text[i - 1] === ' ') && i < text.length - 2 && text[i + 1] !== ' ') arabicForm = 'terminal';\n if (i > 0 && text[i - 1] !== ' ' && i < text.length - 2 && text[i + 1] !== ' ') arabicForm = 'medial';\n if (i > 0 && text[i - 1] !== ' ' && (i === text.length - 1 || text[i + 1] === ' ')) arabicForm = 'initial';\n if (typeof font.glyphs[c] !== 'undefined') {\n glyph = font.glyphs[c][arabicForm];\n if (isNullish(glyph) && font.glyphs[c].type === 'glyph') glyph = font.glyphs[c];\n }\n } else {\n glyph = font.glyphs[c];\n }\n if (isNullish(glyph)) glyph = font.missingGlyph;\n return glyph;\n }\n\n renderChildren (ctx) {\n const customFont = this.parent.style('font-family').getDefinition();\n if (!isNullish(customFont)) {\n const fontSize = this.parent.style('font-size').numValueOrDefault(svg.Font.Parse(svg.ctx.font).fontSize);\n const fontStyle = this.parent.style('font-style').valueOrDefault(svg.Font.Parse(svg.ctx.font).fontStyle);\n let text = this.getText();\n if (customFont.isRTL) text = text.split('').reverse().join('');\n\n const dx = svg.ToNumberArray(this.parent.attribute('dx').value);\n for (let i = 0; i < text.length; i++) {\n const glyph = this.getGlyph(customFont, text, i);\n const scale = fontSize / customFont.fontFace.unitsPerEm;\n ctx.translate(this.x, this.y);\n ctx.scale(scale, -scale);\n const lw = ctx.lineWidth;\n ctx.lineWidth = ctx.lineWidth * customFont.fontFace.unitsPerEm / fontSize;\n if (fontStyle === 'italic') ctx.transform(1, 0, 0.4, 1, 0, 0);\n glyph.render(ctx);\n if (fontStyle === 'italic') ctx.transform(1, 0, -0.4, 1, 0, 0);\n ctx.lineWidth = lw;\n ctx.scale(1 / scale, -1 / scale);\n ctx.translate(-this.x, -this.y);\n\n this.x += fontSize * (glyph.horizAdvX || customFont.horizAdvX) / customFont.fontFace.unitsPerEm;\n if (typeof dx[i] !== 'undefined' && !isNaN(dx[i])) {\n this.x += dx[i];\n }\n }\n return;\n }\n\n if (ctx.fillStyle !== '') ctx.fillText(svg.compressSpaces(this.getText()), this.x, this.y);\n if (ctx.strokeStyle !== '') ctx.strokeText(svg.compressSpaces(this.getText()), this.x, this.y);\n }\n\n getText () {\n // OVERRIDE ME\n }\n\n measureTextRecursive (ctx) {\n let width = this.measureText(ctx);\n this.children.forEach((child) => {\n width += child.measureTextRecursive(ctx);\n });\n return width;\n }\n\n measureText (ctx) {\n const customFont = this.parent.style('font-family').getDefinition();\n if (!isNullish(customFont)) {\n const fontSize = this.parent.style('font-size').numValueOrDefault(svg.Font.Parse(svg.ctx.font).fontSize);\n let measure = 0;\n let text = this.getText();\n if (customFont.isRTL) text = text.split('').reverse().join('');\n const dx = svg.ToNumberArray(this.parent.attribute('dx').value);\n for (let i = 0; i < text.length; i++) {\n const glyph = this.getGlyph(customFont, text, i);\n measure += (glyph.horizAdvX || customFont.horizAdvX) * fontSize / customFont.fontFace.unitsPerEm;\n if (typeof dx[i] !== 'undefined' && !isNaN(dx[i])) {\n measure += dx[i];\n }\n }\n return measure;\n }\n\n const textToMeasure = svg.compressSpaces(this.getText());\n if (!ctx.measureText) return textToMeasure.length * 10;\n\n ctx.save();\n this.setContext(ctx);\n const {width} = ctx.measureText(textToMeasure);\n ctx.restore();\n return width;\n }\n };\n\n // tspan\n svg.Element.tspan = class extends svg.Element.TextElementBase {\n constructor (node) {\n super(node, true);\n\n this.text = node.nodeValue || node.text || '';\n }\n getText () {\n return this.text;\n }\n };\n\n // tref\n svg.Element.tref = class extends svg.Element.TextElementBase {\n getText () {\n const element = this.getHrefAttribute().getDefinition();\n if (!isNullish(element)) return element.children[0].getText();\n return undefined;\n }\n };\n\n // a element\n svg.Element.a = class extends svg.Element.TextElementBase {\n constructor (node) {\n super(node);\n\n this.hasText = true;\n [...node.childNodes].forEach((childNode) => {\n if (childNode.nodeType !== 3) {\n this.hasText = false;\n }\n });\n // this might contain text\n this.text = this.hasText ? node.childNodes[0].nodeValue : '';\n }\n\n getText () {\n return this.text;\n }\n\n renderChildren (ctx) {\n if (this.hasText) {\n // render as text element\n super.renderChildren(ctx);\n const fontSize = new svg.Property(\n 'fontSize', svg.Font.Parse(svg.ctx.font).fontSize\n );\n svg.Mouse.checkBoundingBox(\n this, new svg.BoundingBox(\n this.x,\n this.y - fontSize.toPixels('y'),\n this.x + this.measureText(ctx),\n this.y\n )\n );\n } else {\n // render as temporary group\n const g = new svg.Element.g();\n g.children = this.children;\n g.parent = this;\n g.render(ctx);\n }\n }\n\n onclick () {\n window.open(this.getHrefAttribute().value);\n }\n\n onmousemove () {\n svg.ctx.canvas.style.cursor = 'pointer';\n }\n };\n\n // image element\n svg.Element.image = class extends svg.Element.RenderedElementBase {\n constructor (node) {\n super(node);\n\n const href = this.getHrefAttribute().value;\n if (href === '') {\n return;\n }\n this._isSvg = href.match(/\\.svg$/);\n\n svg.Images.push(this);\n this.loaded = false;\n if (!this._isSvg) {\n this.img = document.createElement('img');\n if (svg.opts.useCORS === true) {\n this.img.crossOrigin = 'Anonymous';\n }\n this.img.addEventListener('load', () => {\n this.loaded = true;\n });\n this.img.addEventListener('error', () => {\n svg.log('ERROR: image \"' + href + '\" not found');\n this.loaded = true;\n });\n this.img.src = href;\n } else {\n svg.ajax(href, true).then((img) => { // eslint-disable-line promise/prefer-await-to-then, promise/always-return\n this.img = img;\n this.loaded = true;\n }).catch((err) => { // eslint-disable-line promise/prefer-await-to-callbacks\n this.erred = true;\n console.error('Ajax error for canvg', err); // eslint-disable-line no-console\n });\n }\n }\n renderChildren (ctx) {\n const x = this.attribute('x').toPixels('x');\n const y = this.attribute('y').toPixels('y');\n\n const width = this.attribute('width').toPixels('x');\n const height = this.attribute('height').toPixels('y');\n if (width === 0 || height === 0) return;\n\n ctx.save();\n if (this._isSvg) {\n ctx.drawSvg(this.img, x, y, width, height);\n } else {\n ctx.translate(x, y);\n svg.AspectRatio(\n ctx,\n this.attribute('preserveAspectRatio').value,\n width,\n this.img.width,\n height,\n this.img.height,\n 0,\n 0\n );\n ctx.drawImage(this.img, 0, 0);\n }\n ctx.restore();\n }\n\n getBoundingBox () {\n const x = this.attribute('x').toPixels('x');\n const y = this.attribute('y').toPixels('y');\n const width = this.attribute('width').toPixels('x');\n const height = this.attribute('height').toPixels('y');\n return new svg.BoundingBox(x, y, x + width, y + height);\n }\n };\n\n // group element\n svg.Element.g = class extends svg.Element.RenderedElementBase {\n getBoundingBox () {\n const bb = new svg.BoundingBox();\n this.children.forEach((child) => {\n bb.addBoundingBox(child.getBoundingBox());\n });\n return bb;\n }\n };\n\n // symbol element\n svg.Element.symbol = class extends svg.Element.RenderedElementBase {\n render (ctx) {\n // NO RENDER\n }\n };\n\n // style element\n svg.Element.style = class extends svg.Element.ElementBase {\n constructor (node) {\n super(node);\n\n // text, or spaces then CDATA\n let css = '';\n [...node.childNodes].forEach(({nodeValue}) => {\n css += nodeValue;\n });\n // remove comments\n css = css.replace(/(\\/\\*([^*]|[\\r\\n]|(\\*+([^*/]|[\\r\\n])))*\\*+\\/)|(^\\s*\\/\\/.*)/gm, ''); // eslint-disable-line unicorn/no-unsafe-regex\n // replace whitespace\n css = svg.compressSpaces(css);\n const cssDefs = css.split('}');\n cssDefs.forEach((cssDef) => {\n if (svg.trim(cssDef) !== '') {\n let [cssClasses, cssProps] = cssDef.split('{');\n cssClasses = cssClasses.split(',');\n cssProps = cssProps.split(';');\n cssClasses.forEach((cssClass) => {\n cssClass = svg.trim(cssClass);\n if (cssClass !== '') {\n const props = {};\n cssProps.forEach((cssProp) => {\n const prop = cssProp.indexOf(':');\n const name = cssProp.substr(0, prop);\n const value = cssProp.substr(prop + 1, cssProp.length - prop);\n if (!isNullish(name) && !isNullish(value)) {\n props[svg.trim(name)] = new svg.Property(svg.trim(name), svg.trim(value));\n }\n });\n svg.Styles[cssClass] = props;\n if (cssClass === '@font-face') {\n const fontFamily = props['font-family'].value.replace(/\"/g, '');\n const srcs = props.src.value.split(',');\n srcs.forEach((src) => {\n if (src.includes('format(\"svg\")')) {\n const urlStart = src.indexOf('url');\n const urlEnd = src.indexOf(')', urlStart);\n const url = src.substr(urlStart + 5, urlEnd - urlStart - 6);\n // Can this ajax safely be converted to async?\n const doc = svg.parseXml(svg.ajax(url));\n const fonts = doc.getElementsByTagName('font');\n [...fonts].forEach((font) => {\n font = svg.CreateElement(font);\n svg.Definitions[fontFamily] = font;\n });\n }\n });\n }\n }\n });\n }\n });\n }\n };\n\n // use element\n svg.Element.use = class extends svg.Element.RenderedElementBase {\n constructor (node) {\n super(node);\n\n this._el = this.getHrefAttribute().getDefinition();\n }\n\n setContext (ctx) {\n super.setContext(ctx);\n if (this.attribute('x').hasValue()) ctx.translate(this.attribute('x').toPixels('x'), 0);\n if (this.attribute('y').hasValue()) ctx.translate(0, this.attribute('y').toPixels('y'));\n }\n\n path (ctx) {\n const {_el: element} = this;\n if (!isNullish(element)) element.path(ctx);\n }\n\n getBoundingBox () {\n const {_el: element} = this;\n if (!isNullish(element)) return element.getBoundingBox();\n return undefined;\n }\n\n renderChildren (ctx) {\n const {_el: element} = this;\n if (!isNullish(element)) {\n let tempSvg = element;\n if (element.type === 'symbol') {\n // render me using a temporary svg element in symbol cases\n // (https://www.w3.org/TR/SVG/struct.html#UseElement)\n tempSvg = new svg.Element.svg();\n tempSvg.type = 'svg';\n tempSvg.attributes.viewBox = new svg.Property(\n 'viewBox', element.attribute('viewBox').value\n );\n tempSvg.attributes.preserveAspectRatio = new svg.Property(\n 'preserveAspectRatio', element.attribute('preserveAspectRatio').value\n );\n tempSvg.attributes.overflow = new svg.Property(\n 'overflow', element.attribute('overflow').value\n );\n tempSvg.children = element.children;\n }\n if (tempSvg.type === 'svg') {\n // if symbol or svg, inherit width/height from me\n if (this.attribute('width').hasValue()) {\n tempSvg.attributes.width = new svg.Property(\n 'width', this.attribute('width').value\n );\n }\n if (this.attribute('height').hasValue()) {\n tempSvg.attributes.height = new svg.Property(\n 'height', this.attribute('height').value\n );\n }\n }\n const oldParent = tempSvg.parent;\n tempSvg.parent = null;\n tempSvg.render(ctx);\n tempSvg.parent = oldParent;\n }\n }\n };\n\n // mask element\n svg.Element.mask = class extends svg.Element.ElementBase {\n apply (ctx, element) {\n // render as temp svg\n let x = this.attribute('x').toPixels('x');\n let y = this.attribute('y').toPixels('y');\n let width = this.attribute('width').toPixels('x');\n let height = this.attribute('height').toPixels('y');\n\n if (width === 0 && height === 0) {\n const bb = new svg.BoundingBox();\n this.children.forEach((child) => {\n bb.addBoundingBox(child.getBoundingBox());\n });\n x = Math.floor(bb.x1);\n y = Math.floor(bb.y1);\n width = Math.floor(bb.width());\n height = Math.floor(bb.height());\n }\n\n // temporarily remove mask to avoid recursion\n const mask = element.attribute('mask').value;\n element.attribute('mask').value = '';\n\n const cMask = document.createElement('canvas');\n cMask.width = x + width;\n cMask.height = y + height;\n const maskCtx = cMask.getContext('2d');\n this.renderChildren(maskCtx);\n\n const c = document.createElement('canvas');\n c.width = x + width;\n c.height = y + height;\n const tempCtx = c.getContext('2d');\n element.render(tempCtx);\n tempCtx.globalCompositeOperation = 'destination-in';\n tempCtx.fillStyle = maskCtx.createPattern(cMask, 'no-repeat');\n tempCtx.fillRect(0, 0, x + width, y + height);\n\n ctx.fillStyle = tempCtx.createPattern(c, 'no-repeat');\n ctx.fillRect(0, 0, x + width, y + height);\n\n // reassign mask\n element.attribute('mask').value = mask;\n }\n\n render (ctx) {\n // NO RENDER\n }\n };\n\n // clip element\n svg.Element.clipPath = class extends svg.Element.ElementBase {\n apply (ctx) {\n this.children.forEach((child) => {\n if (typeof child.path !== 'undefined') {\n let transform = null;\n if (child.attribute('transform').hasValue()) {\n transform = new svg.Transform(child.attribute('transform').value);\n transform.apply(ctx);\n }\n child.path(ctx);\n ctx.clip();\n if (transform) { transform.unapply(ctx); }\n }\n });\n }\n render (ctx) {\n // NO RENDER\n }\n };\n\n // filters\n svg.Element.filter = class extends svg.Element.ElementBase {\n apply (ctx, element) {\n // render as temp svg\n const bb = element.getBoundingBox();\n const x = Math.floor(bb.x1);\n const y = Math.floor(bb.y1);\n const width = Math.floor(bb.width());\n const height = Math.floor(bb.height());\n\n // temporarily remove filter to avoid recursion\n const filter = element.style('filter').value;\n element.style('filter').value = '';\n\n let px = 0, py = 0;\n this.children.forEach((child) => {\n const efd = child.extraFilterDistance || 0;\n px = Math.max(px, efd);\n py = Math.max(py, efd);\n });\n\n const c = document.createElement('canvas');\n c.width = width + 2 * px;\n c.height = height + 2 * py;\n const tempCtx = c.getContext('2d');\n tempCtx.translate(-x + px, -y + py);\n element.render(tempCtx);\n\n // apply filters\n this.children.forEach((child) => {\n child.apply(tempCtx, 0, 0, width + 2 * px, height + 2 * py);\n });\n\n // render on me\n ctx.drawImage(c, 0, 0, width + 2 * px, height + 2 * py, x - px, y - py, width + 2 * px, height + 2 * py);\n\n // reassign filter\n element.style('filter', true).value = filter;\n }\n\n render (ctx) {\n // NO RENDER\n }\n };\n\n svg.Element.feMorphology = class extends svg.Element.ElementBase {\n apply (ctx, x, y, width, height) {\n // TODO: implement\n }\n };\n\n svg.Element.feComposite = class extends svg.Element.ElementBase {\n apply (ctx, x, y, width, height) {\n // TODO: implement\n }\n };\n\n /**\n * @param {Uint8ClampedArray} img\n * @param {Integer} x\n * @param {Integer} y\n * @param {Float} width\n * @param {Float} height\n * @param {Integer} rgba\n * @returns {Integer}\n */\n function imGet (img, x, y, width, height, rgba) {\n return img[y * width * 4 + x * 4 + rgba];\n }\n\n /**\n * @param {Uint8ClampedArray} img\n * @param {Integer} x\n * @param {Integer} y\n * @param {Float} width\n * @param {Float} height\n * @param {Integer} rgba\n * @param {Float} val\n * @returns {void}\n */\n function imSet (img, x, y, width, height, rgba, val) {\n img[y * width * 4 + x * 4 + rgba] = val;\n }\n\n svg.Element.feColorMatrix = class extends svg.Element.ElementBase {\n constructor (node) {\n super(node);\n\n let matrix = svg.ToNumberArray(this.attribute('values').value);\n switch (this.attribute('type').valueOrDefault('matrix')) { // https://www.w3.org/TR/SVG/filters.html#feColorMatrixElement\n case 'saturate': {\n const s = matrix[0];\n matrix = [\n 0.213 + 0.787 * s, 0.715 - 0.715 * s, 0.072 - 0.072 * s, 0, 0,\n 0.213 - 0.213 * s, 0.715 + 0.285 * s, 0.072 - 0.072 * s, 0, 0,\n 0.213 - 0.213 * s, 0.715 - 0.715 * s, 0.072 + 0.928 * s, 0, 0,\n 0, 0, 0, 1, 0,\n 0, 0, 0, 0, 1\n ];\n break;\n } case 'hueRotate': {\n const a = matrix[0] * Math.PI / 180.0;\n const c = function (m1, m2, m3) {\n return m1 + Math.cos(a) * m2 + Math.sin(a) * m3;\n };\n matrix = [\n c(0.213, 0.787, -0.213), c(0.715, -0.715, -0.715), c(0.072, -0.072, 0.928), 0, 0,\n c(0.213, -0.213, 0.143), c(0.715, 0.285, 0.140), c(0.072, -0.072, -0.283), 0, 0,\n c(0.213, -0.213, -0.787), c(0.715, -0.715, 0.715), c(0.072, 0.928, 0.072), 0, 0,\n 0, 0, 0, 1, 0,\n 0, 0, 0, 0, 1\n ];\n break;\n } case 'luminanceToAlpha':\n matrix = [\n 0, 0, 0, 0, 0,\n 0, 0, 0, 0, 0,\n 0, 0, 0, 0, 0,\n 0.2125, 0.7154, 0.0721, 0, 0,\n 0, 0, 0, 0, 1\n ];\n break;\n }\n this.matrix = matrix;\n\n this._m = (i, v) => {\n const mi = matrix[i];\n return mi * (mi < 0 ? v - 255 : v);\n };\n }\n apply (ctx, x, y, width, height) {\n const {_m: m} = this;\n // assuming x==0 && y==0 for now\n const srcData = ctx.getImageData(0, 0, width, height);\n for (let _y = 0; _y < height; _y++) {\n for (let _x = 0; _x < width; _x++) {\n const r = imGet(srcData.data, _x, _y, width, height, 0);\n const g = imGet(srcData.data, _x, _y, width, height, 1);\n const b = imGet(srcData.data, _x, _y, width, height, 2);\n const a = imGet(srcData.data, _x, _y, width, height, 3);\n imSet(srcData.data, _x, _y, width, height, 0, m(0, r) + m(1, g) + m(2, b) + m(3, a) + m(4, 1));\n imSet(srcData.data, _x, _y, width, height, 1, m(5, r) + m(6, g) + m(7, b) + m(8, a) + m(9, 1));\n imSet(srcData.data, _x, _y, width, height, 2, m(10, r) + m(11, g) + m(12, b) + m(13, a) + m(14, 1));\n imSet(srcData.data, _x, _y, width, height, 3, m(15, r) + m(16, g) + m(17, b) + m(18, a) + m(19, 1));\n }\n }\n ctx.clearRect(0, 0, width, height);\n ctx.putImageData(srcData, 0, 0);\n }\n };\n\n svg.Element.feGaussianBlur = class extends svg.Element.ElementBase {\n constructor (node) {\n super(node);\n\n this.blurRadius = Math.floor(this.attribute('stdDeviation').numValue());\n this.extraFilterDistance = this.blurRadius;\n }\n\n apply (ctx, x, y, width, height) {\n // Todo: This might not be a problem anymore with out `instanceof` fix\n // StackBlur requires canvas be on document\n ctx.canvas.id = svg.UniqueId();\n ctx.canvas.style.display = 'none';\n document.body.append(ctx.canvas);\n canvasRGBA(ctx.canvas, x, y, width, height, this.blurRadius);\n ctx.canvas.remove();\n }\n };\n\n // title element, do nothing\n svg.Element.title = class extends svg.Element.ElementBase {\n constructor (node) {\n super();\n }\n };\n\n // desc element, do nothing\n svg.Element.desc = class extends svg.Element.ElementBase {\n constructor (node) {\n super();\n }\n };\n\n svg.Element.MISSING = class extends svg.Element.ElementBase {\n constructor (node) {\n super();\n svg.log('ERROR: Element \\'' + node.nodeName + '\\' not yet implemented.');\n }\n };\n\n // element factory\n svg.CreateElement = function (node) {\n const className = node.nodeName\n .replace(/^[^:]+:/, '') // remove namespace\n .replace(/-/g, ''); // remove dashes\n let e;\n if (typeof svg.Element[className] !== 'undefined') {\n e = new svg.Element[className](node);\n } else {\n e = new svg.Element.MISSING(node);\n }\n\n e.type = node.nodeName;\n return e;\n };\n\n // load from url\n svg.load = async function (ctx, url) {\n const dom = await svg.ajax(url, true);\n return svg.loadXml(ctx, dom);\n };\n\n // load from xml\n svg.loadXml = function (ctx, xml) {\n return svg.loadXmlDoc(ctx, svg.parseXml(xml));\n };\n\n svg.loadXmlDoc = function (ctx, dom) {\n let res;\n svg.init(ctx);\n\n const mapXY = function (p) {\n let e = ctx.canvas;\n while (e) {\n p.x -= e.offsetLeft;\n p.y -= e.offsetTop;\n e = e.offsetParent;\n }\n if (window.scrollX) p.x += window.scrollX;\n if (window.scrollY) p.y += window.scrollY;\n return p;\n };\n\n // bind mouse\n if (svg.opts.ignoreMouse !== true) {\n ctx.canvas.addEventListener('click', function (e) {\n const args = !isNullish(e)\n ? [e.clientX, e.clientY]\n : [event.clientX, event.clientY]; // eslint-disable-line no-restricted-globals\n const {x, y} = mapXY(new svg.Point(...args));\n svg.Mouse.onclick(x, y);\n });\n ctx.canvas.addEventListener('mousemove', function (e) {\n const args = !isNullish(e)\n ? [e.clientX, e.clientY]\n : [event.clientX, event.clientY]; // eslint-disable-line no-restricted-globals\n const {x, y} = mapXY(new svg.Point(...args));\n svg.Mouse.onmousemove(x, y);\n });\n }\n\n const e = svg.CreateElement(dom.documentElement);\n e.root = true;\n\n // render loop\n let isFirstRender = true;\n const draw = function (resolve) {\n svg.ViewPort.Clear();\n if (ctx.canvas.parentNode) {\n svg.ViewPort.SetCurrent(\n ctx.canvas.parentNode.clientWidth,\n ctx.canvas.parentNode.clientHeight\n );\n }\n\n if (svg.opts.ignoreDimensions !== true) {\n // set canvas size\n if (e.style('width').hasValue()) {\n ctx.canvas.width = e.style('width').toPixels('x');\n ctx.canvas.style.width = ctx.canvas.width + 'px';\n }\n if (e.style('height').hasValue()) {\n ctx.canvas.height = e.style('height').toPixels('y');\n ctx.canvas.style.height = ctx.canvas.height + 'px';\n }\n }\n let cWidth = ctx.canvas.clientWidth || ctx.canvas.width;\n let cHeight = ctx.canvas.clientHeight || ctx.canvas.height;\n if (svg.opts.ignoreDimensions === true &&\n e.style('width').hasValue() && e.style('height').hasValue()\n ) {\n cWidth = e.style('width').toPixels('x');\n cHeight = e.style('height').toPixels('y');\n }\n svg.ViewPort.SetCurrent(cWidth, cHeight);\n\n if (!isNullish(svg.opts.offsetX)) {\n e.attribute('x', true).value = svg.opts.offsetX;\n }\n if (!isNullish(svg.opts.offsetY)) {\n e.attribute('y', true).value = svg.opts.offsetY;\n }\n if (!isNullish(svg.opts.scaleWidth) || !isNullish(svg.opts.scaleHeight)) {\n const viewBox = svg.ToNumberArray(e.attribute('viewBox').value);\n let xRatio = null, yRatio = null;\n\n if (!isNullish(svg.opts.scaleWidth)) {\n if (e.attribute('width').hasValue()) {\n xRatio = e.attribute('width').toPixels('x') / svg.opts.scaleWidth;\n } else if (!isNaN(viewBox[2])) {\n xRatio = viewBox[2] / svg.opts.scaleWidth;\n }\n }\n\n if (!isNullish(svg.opts.scaleHeight)) {\n if (e.attribute('height').hasValue()) {\n yRatio = e.attribute('height').toPixels('y') / svg.opts.scaleHeight;\n } else if (!isNaN(viewBox[3])) {\n yRatio = viewBox[3] / svg.opts.scaleHeight;\n }\n }\n\n if (isNullish(xRatio)) { xRatio = yRatio; }\n if (isNullish(yRatio)) { yRatio = xRatio; }\n\n e.attribute('width', true).value = svg.opts.scaleWidth;\n e.attribute('height', true).value = svg.opts.scaleHeight;\n e.attribute('viewBox', true).value = '0 0 ' + (cWidth * xRatio) + ' ' + (cHeight * yRatio);\n e.attribute('preserveAspectRatio', true).value = 'none';\n }\n\n // clear and render\n if (svg.opts.ignoreClear !== true) {\n ctx.clearRect(0, 0, cWidth, cHeight);\n }\n e.render(ctx);\n if (isFirstRender) {\n isFirstRender = false;\n resolve(dom);\n }\n };\n\n let waitingForImages = true;\n svg.intervalID = setInterval(function () {\n let needUpdate = false;\n\n if (waitingForImages && svg.ImagesLoaded()) {\n waitingForImages = false;\n needUpdate = true;\n }\n\n // need update from mouse events?\n if (svg.opts.ignoreMouse !== true) {\n needUpdate = needUpdate || svg.Mouse.hasEvents();\n }\n\n // need update from animations?\n if (svg.opts.ignoreAnimation !== true) {\n svg.Animations.forEach((animation) => {\n const needAnimationUpdate = animation.update(1000 / svg.FRAMERATE);\n needUpdate = needUpdate || needAnimationUpdate;\n });\n }\n\n // need update from redraw?\n if (typeof svg.opts.forceRedraw === 'function') {\n if (svg.opts.forceRedraw() === true) {\n needUpdate = true;\n }\n }\n\n // render if needed\n if (needUpdate) {\n draw(res);\n svg.Mouse.runEvents(); // run and clear our events\n }\n }, 1000 / svg.FRAMERATE);\n // Todo: Replace with an image loading Promise utility?\n // eslint-disable-next-line promise/avoid-new\n return new Promise((resolve, reject) => {\n if (svg.ImagesLoaded()) {\n waitingForImages = false;\n draw(resolve);\n return;\n }\n res = resolve;\n });\n };\n\n svg.stop = () => {\n if (svg.intervalID) {\n clearInterval(svg.intervalID);\n }\n };\n\n svg.Mouse = {\n events: [],\n hasEvents () { return this.events.length !== 0; },\n\n onclick (x, y) {\n this.events.push({\n type: 'onclick', x, y,\n run (e) { if (e.onclick) e.onclick(); }\n });\n },\n\n onmousemove (x, y) {\n this.events.push({\n type: 'onmousemove', x, y,\n run (e) { if (e.onmousemove) e.onmousemove(); }\n });\n },\n\n eventElements: [],\n\n checkPath (element, ctx) {\n this.events.forEach(({x, y}, i) => {\n if (ctx.isPointInPath && ctx.isPointInPath(x, y)) {\n this.eventElements[i] = element;\n }\n });\n },\n\n checkBoundingBox (element, bb) {\n this.events.forEach(({x, y}, i) => {\n if (bb.isPointInBox(x, y)) {\n this.eventElements[i] = element;\n }\n });\n },\n\n runEvents () {\n svg.ctx.canvas.style.cursor = '';\n\n this.events.forEach((e, i) => {\n let element = this.eventElements[i];\n while (element) {\n e.run(element);\n element = element.parent;\n }\n });\n\n // done running, clear\n this.events = [];\n this.eventElements = [];\n }\n };\n\n return svg;\n}\n\nif (typeof CanvasRenderingContext2D !== 'undefined') {\n CanvasRenderingContext2D.prototype.drawSvg = function (s, dx, dy, dw, dh) {\n canvg(this.canvas, s, {\n ignoreMouse: true,\n ignoreAnimation: true,\n ignoreDimensions: true,\n ignoreClear: true,\n offsetX: dx,\n offsetY: dy,\n scaleWidth: dw,\n scaleHeight: dh\n });\n };\n}\n","/**\n * @file ext-server_moinsave.js\n *\n * @license (MIT OR GPL-2.0-or-later)\n *\n * @copyright 2010 Alexis Deveria, 2011 MoinMoin:ReimarBauer\n * adopted for moinmoins item storage. It sends in one post png and svg data\n * (I agree to dual license my work to additional GPLv2 or later)\n */\nimport {canvg} from '../../../external/canvg/canvg.js';\n\nconst loadExtensionTranslation = async function (lang) {\n let translationModule;\n try {\n // eslint-disable-next-line node/no-unsupported-features/es-syntax\n translationModule = await import(`./locale/${lang}.js`);\n } catch (_error) {\n // eslint-disable-next-line no-console\n console.error(`Missing translation (${lang}) - using 'en'`);\n // eslint-disable-next-line node/no-unsupported-features/es-syntax\n translationModule = await import(`./locale/en.js`);\n }\n return translationModule.default;\n};\n\nexport default {\n name: 'server_moinsave',\n async init ({$, encode64, importLocale}) {\n const svgEditor = this;\n const strings = await loadExtensionTranslation(svgEditor.curPrefs.lang);\n const svgCanvas = svgEditor.canvas;\n const saveSvgAction = '/+modify';\n\n // Create upload target (hidden iframe)\n // Hiding by size instead of display to avoid FF console errors\n // with `getBBox` in browser.js `supportsPathBBox_`)\n /* const target = */ $(\n `\\d{1,3})\\)$/,\n example: ['rgb(123, 234, 45)', 'rgb(255,234,245)'],\n process (_, ...bits) {\n return bits.map((b) => Number.parseInt(b));\n }\n },\n {\n re: /^(\\w{2})(\\w{2})(\\w{2})$/,\n // re: /^(?\\w{2})(?\\w{2})(?\\w{2})$/,\n example: ['#00ff00', '336699'],\n process (_, ...bits) {\n return bits.map((b) => Number.parseInt(b, 16));\n }\n },\n {\n re: /^(\\w)(\\w)(\\w)$/,\n // re: /^(?\\w{1})(?\\w{1})(?\\w{1})$/,\n example: ['#fb0', 'f0f'],\n process (_, ...bits) {\n return bits.map((b) => Number.parseInt(b + b, 16));\n }\n }\n];\n\n/**\n * A class to parse color values.\n */\nexport default class RGBColor {\n /**\n * @param {string} colorString\n */\n constructor (colorString) {\n this.ok = false;\n\n // strip any leading #\n if (colorString.charAt(0) === '#') { // remove # if any\n colorString = colorString.substr(1, 6);\n }\n\n colorString = colorString.replace(/ /g, '');\n colorString = colorString.toLowerCase();\n\n // before getting into regexps, try simple matches\n // and overwrite the input\n if (colorString in simpleColors) {\n colorString = simpleColors[colorString];\n }\n // end of simple type-in colors\n\n // search through the definitions to find a match\n\n colorDefs.forEach(({re, process: processor}) => {\n const bits = re.exec(colorString);\n if (bits) {\n const [r, g, b] = processor(...bits);\n Object.assign(this, {r, g, b});\n this.ok = true;\n }\n });\n\n // validate/cleanup values\n this.r = (this.r < 0 || isNaN(this.r)) ? 0 : ((this.r > 255) ? 255 : this.r);\n this.g = (this.g < 0 || isNaN(this.g)) ? 0 : ((this.g > 255) ? 255 : this.g);\n this.b = (this.b < 0 || isNaN(this.b)) ? 0 : ((this.b > 255) ? 255 : this.b);\n }\n\n // some getters\n /**\n * @returns {string}\n */\n toRGB () {\n return 'rgb(' + this.r + ', ' + this.g + ', ' + this.b + ')';\n }\n\n /**\n * @returns {string}\n */\n toHex () {\n let r = this.r.toString(16);\n let g = this.g.toString(16);\n let b = this.b.toString(16);\n if (r.length === 1) { r = '0' + r; }\n if (g.length === 1) { g = '0' + g; }\n if (b.length === 1) { b = '0' + b; }\n return '#' + r + g + b;\n }\n\n /**\n * Offers a bulleted list of help.\n * @returns {HTMLUListElement}\n */\n static getHelpXML () {\n const examples = [\n // add regexps\n ...colorDefs.flatMap(({example}) => {\n return example;\n }),\n // add type-in colors\n ...Object.keys(simpleColors)\n ];\n\n const xml = document.createElement('ul');\n xml.setAttribute('id', 'rgbcolor-examples');\n\n xml.append(...examples.map((example) => {\n try {\n const listItem = document.createElement('li');\n const listColor = new RGBColor(example);\n const exampleDiv = document.createElement('div');\n exampleDiv.style.cssText = `\n margin: 3px;\n border: 1px solid black;\n background: ${listColor.toHex()};\n color: ${listColor.toHex()};`;\n exampleDiv.append('test');\n const listItemValue = ` ${example} -> ${listColor.toRGB()} -> ${listColor.toHex()}`;\n listItem.append(exampleDiv, listItemValue);\n return listItem;\n } catch (e) {\n return '';\n }\n }));\n return xml;\n }\n}\n","function _typeof(obj) {\n \"@babel/helpers - typeof\";\n\n if (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\") {\n _typeof = function (obj) {\n return typeof obj;\n };\n } else {\n _typeof = function (obj) {\n return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj;\n };\n }\n\n return _typeof(obj);\n}\n\nfunction _classCallCheck(instance, Constructor) {\n if (!(instance instanceof Constructor)) {\n throw new TypeError(\"Cannot call a class as a function\");\n }\n}\n\n/* eslint-disable no-bitwise, unicorn/prefer-query-selector */\n\n/**\n* StackBlur - a fast almost Gaussian Blur For Canvas\n*\n* In case you find this class useful - especially in commercial projects -\n* I am not totally unhappy for a small donation to my PayPal account\n* mario@quasimondo.de\n*\n* Or support me on flattr:\n* {@link https://flattr.com/thing/72791/StackBlur-a-fast-almost-Gaussian-Blur-Effect-for-CanvasJavascript}.\n*\n* @module StackBlur\n* @author Mario Klingemann\n* Contact: mario@quasimondo.com\n* Website: {@link http://www.quasimondo.com/StackBlurForCanvas/StackBlurDemo.html}\n* Twitter: @quasimondo\n*\n* @copyright (c) 2010 Mario Klingemann\n*\n* Permission is hereby granted, free of charge, to any person\n* obtaining a copy of this software and associated documentation\n* files (the \"Software\"), to deal in the Software without\n* restriction, including without limitation the rights to use,\n* copy, modify, merge, publish, distribute, sublicense, and/or sell\n* copies of the Software, and to permit persons to whom the\n* Software is furnished to do so, subject to the following\n* conditions:\n*\n* The above copyright notice and this permission notice shall be\n* included in all copies or substantial portions of the Software.\n*\n* THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES\n* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\n* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT\n* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR\n* OTHER DEALINGS IN THE SOFTWARE.\n*/\n\n/* eslint-disable max-len */\nvar mulTable = [512, 512, 456, 512, 328, 456, 335, 512, 405, 328, 271, 456, 388, 335, 292, 512, 454, 405, 364, 328, 298, 271, 496, 456, 420, 388, 360, 335, 312, 292, 273, 512, 482, 454, 428, 405, 383, 364, 345, 328, 312, 298, 284, 271, 259, 496, 475, 456, 437, 420, 404, 388, 374, 360, 347, 335, 323, 312, 302, 292, 282, 273, 265, 512, 497, 482, 468, 454, 441, 428, 417, 405, 394, 383, 373, 364, 354, 345, 337, 328, 320, 312, 305, 298, 291, 284, 278, 271, 265, 259, 507, 496, 485, 475, 465, 456, 446, 437, 428, 420, 412, 404, 396, 388, 381, 374, 367, 360, 354, 347, 341, 335, 329, 323, 318, 312, 307, 302, 297, 292, 287, 282, 278, 273, 269, 265, 261, 512, 505, 497, 489, 482, 475, 468, 461, 454, 447, 441, 435, 428, 422, 417, 411, 405, 399, 394, 389, 383, 378, 373, 368, 364, 359, 354, 350, 345, 341, 337, 332, 328, 324, 320, 316, 312, 309, 305, 301, 298, 294, 291, 287, 284, 281, 278, 274, 271, 268, 265, 262, 259, 257, 507, 501, 496, 491, 485, 480, 475, 470, 465, 460, 456, 451, 446, 442, 437, 433, 428, 424, 420, 416, 412, 408, 404, 400, 396, 392, 388, 385, 381, 377, 374, 370, 367, 363, 360, 357, 354, 350, 347, 344, 341, 338, 335, 332, 329, 326, 323, 320, 318, 315, 312, 310, 307, 304, 302, 299, 297, 294, 292, 289, 287, 285, 282, 280, 278, 275, 273, 271, 269, 267, 265, 263, 261, 259];\nvar shgTable = [9, 11, 12, 13, 13, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24];\n/* eslint-enable max-len */\n\n/**\n * @param {string|HTMLImageElement} img\n * @param {string|HTMLCanvasElement} canvas\n * @param {Float} radius\n * @param {boolean} blurAlphaChannel\n * @returns {undefined}\n */\n\nfunction processImage(img, canvas, radius, blurAlphaChannel) {\n if (typeof img === 'string') {\n img = document.getElementById(img);\n }\n\n if (!img || !('naturalWidth' in img)) {\n return;\n }\n\n var w = img.naturalWidth;\n var h = img.naturalHeight;\n\n if (typeof canvas === 'string') {\n canvas = document.getElementById(canvas);\n }\n\n if (!canvas || !('getContext' in canvas)) {\n return;\n }\n\n canvas.style.width = w + 'px';\n canvas.style.height = h + 'px';\n canvas.width = w;\n canvas.height = h;\n var context = canvas.getContext('2d');\n context.clearRect(0, 0, w, h);\n context.drawImage(img, 0, 0);\n\n if (isNaN(radius) || radius < 1) {\n return;\n }\n\n if (blurAlphaChannel) {\n processCanvasRGBA(canvas, 0, 0, w, h, radius);\n } else {\n processCanvasRGB(canvas, 0, 0, w, h, radius);\n }\n}\n/**\n * @param {string|HTMLCanvasElement} canvas\n * @param {Integer} topX\n * @param {Integer} topY\n * @param {Integer} width\n * @param {Integer} height\n * @throws {Error|TypeError}\n * @returns {ImageData} See {@link https://html.spec.whatwg.org/multipage/canvas.html#imagedata}\n */\n\n\nfunction getImageDataFromCanvas(canvas, topX, topY, width, height) {\n if (typeof canvas === 'string') {\n canvas = document.getElementById(canvas);\n }\n\n if (!canvas || _typeof(canvas) !== 'object' || !('getContext' in canvas)) {\n throw new TypeError('Expecting canvas with `getContext` method ' + 'in processCanvasRGB(A) calls!');\n }\n\n var context = canvas.getContext('2d');\n\n try {\n return context.getImageData(topX, topY, width, height);\n } catch (e) {\n throw new Error('unable to access image data: ' + e);\n }\n}\n/**\n * @param {HTMLCanvasElement} canvas\n * @param {Integer} topX\n * @param {Integer} topY\n * @param {Integer} width\n * @param {Integer} height\n * @param {Float} radius\n * @returns {undefined}\n */\n\n\nfunction processCanvasRGBA(canvas, topX, topY, width, height, radius) {\n if (isNaN(radius) || radius < 1) {\n return;\n }\n\n radius |= 0;\n var imageData = getImageDataFromCanvas(canvas, topX, topY, width, height);\n imageData = processImageDataRGBA(imageData, topX, topY, width, height, radius);\n canvas.getContext('2d').putImageData(imageData, topX, topY);\n}\n/**\n * @param {ImageData} imageData\n * @param {Integer} topX\n * @param {Integer} topY\n * @param {Integer} width\n * @param {Integer} height\n * @param {Float} radius\n * @returns {ImageData}\n */\n\n\nfunction processImageDataRGBA(imageData, topX, topY, width, height, radius) {\n var pixels = imageData.data;\n var x, y, i, p, yp, yi, yw, rSum, gSum, bSum, aSum, rOutSum, gOutSum, bOutSum, aOutSum, rInSum, gInSum, bInSum, aInSum, pr, pg, pb, pa, rbs;\n var div = 2 * radius + 1; // const w4 = width << 2;\n\n var widthMinus1 = width - 1;\n var heightMinus1 = height - 1;\n var radiusPlus1 = radius + 1;\n var sumFactor = radiusPlus1 * (radiusPlus1 + 1) / 2;\n var stackStart = new BlurStack();\n var stack = stackStart;\n var stackEnd;\n\n for (i = 1; i < div; i++) {\n stack = stack.next = new BlurStack();\n\n if (i === radiusPlus1) {\n stackEnd = stack;\n }\n }\n\n stack.next = stackStart;\n var stackIn = null;\n var stackOut = null;\n yw = yi = 0;\n var mulSum = mulTable[radius];\n var shgSum = shgTable[radius];\n\n for (y = 0; y < height; y++) {\n rInSum = gInSum = bInSum = aInSum = rSum = gSum = bSum = aSum = 0;\n rOutSum = radiusPlus1 * (pr = pixels[yi]);\n gOutSum = radiusPlus1 * (pg = pixels[yi + 1]);\n bOutSum = radiusPlus1 * (pb = pixels[yi + 2]);\n aOutSum = radiusPlus1 * (pa = pixels[yi + 3]);\n rSum += sumFactor * pr;\n gSum += sumFactor * pg;\n bSum += sumFactor * pb;\n aSum += sumFactor * pa;\n stack = stackStart;\n\n for (i = 0; i < radiusPlus1; i++) {\n stack.r = pr;\n stack.g = pg;\n stack.b = pb;\n stack.a = pa;\n stack = stack.next;\n }\n\n for (i = 1; i < radiusPlus1; i++) {\n p = yi + ((widthMinus1 < i ? widthMinus1 : i) << 2);\n rSum += (stack.r = pr = pixels[p]) * (rbs = radiusPlus1 - i);\n gSum += (stack.g = pg = pixels[p + 1]) * rbs;\n bSum += (stack.b = pb = pixels[p + 2]) * rbs;\n aSum += (stack.a = pa = pixels[p + 3]) * rbs;\n rInSum += pr;\n gInSum += pg;\n bInSum += pb;\n aInSum += pa;\n stack = stack.next;\n }\n\n stackIn = stackStart;\n stackOut = stackEnd;\n\n for (x = 0; x < width; x++) {\n pixels[yi + 3] = pa = aSum * mulSum >> shgSum;\n\n if (pa !== 0) {\n pa = 255 / pa;\n pixels[yi] = (rSum * mulSum >> shgSum) * pa;\n pixels[yi + 1] = (gSum * mulSum >> shgSum) * pa;\n pixels[yi + 2] = (bSum * mulSum >> shgSum) * pa;\n } else {\n pixels[yi] = pixels[yi + 1] = pixels[yi + 2] = 0;\n }\n\n rSum -= rOutSum;\n gSum -= gOutSum;\n bSum -= bOutSum;\n aSum -= aOutSum;\n rOutSum -= stackIn.r;\n gOutSum -= stackIn.g;\n bOutSum -= stackIn.b;\n aOutSum -= stackIn.a;\n p = yw + ((p = x + radius + 1) < widthMinus1 ? p : widthMinus1) << 2;\n rInSum += stackIn.r = pixels[p];\n gInSum += stackIn.g = pixels[p + 1];\n bInSum += stackIn.b = pixels[p + 2];\n aInSum += stackIn.a = pixels[p + 3];\n rSum += rInSum;\n gSum += gInSum;\n bSum += bInSum;\n aSum += aInSum;\n stackIn = stackIn.next;\n rOutSum += pr = stackOut.r;\n gOutSum += pg = stackOut.g;\n bOutSum += pb = stackOut.b;\n aOutSum += pa = stackOut.a;\n rInSum -= pr;\n gInSum -= pg;\n bInSum -= pb;\n aInSum -= pa;\n stackOut = stackOut.next;\n yi += 4;\n }\n\n yw += width;\n }\n\n for (x = 0; x < width; x++) {\n gInSum = bInSum = aInSum = rInSum = gSum = bSum = aSum = rSum = 0;\n yi = x << 2;\n rOutSum = radiusPlus1 * (pr = pixels[yi]);\n gOutSum = radiusPlus1 * (pg = pixels[yi + 1]);\n bOutSum = radiusPlus1 * (pb = pixels[yi + 2]);\n aOutSum = radiusPlus1 * (pa = pixels[yi + 3]);\n rSum += sumFactor * pr;\n gSum += sumFactor * pg;\n bSum += sumFactor * pb;\n aSum += sumFactor * pa;\n stack = stackStart;\n\n for (i = 0; i < radiusPlus1; i++) {\n stack.r = pr;\n stack.g = pg;\n stack.b = pb;\n stack.a = pa;\n stack = stack.next;\n }\n\n yp = width;\n\n for (i = 1; i <= radius; i++) {\n yi = yp + x << 2;\n rSum += (stack.r = pr = pixels[yi]) * (rbs = radiusPlus1 - i);\n gSum += (stack.g = pg = pixels[yi + 1]) * rbs;\n bSum += (stack.b = pb = pixels[yi + 2]) * rbs;\n aSum += (stack.a = pa = pixels[yi + 3]) * rbs;\n rInSum += pr;\n gInSum += pg;\n bInSum += pb;\n aInSum += pa;\n stack = stack.next;\n\n if (i < heightMinus1) {\n yp += width;\n }\n }\n\n yi = x;\n stackIn = stackStart;\n stackOut = stackEnd;\n\n for (y = 0; y < height; y++) {\n p = yi << 2;\n pixels[p + 3] = pa = aSum * mulSum >> shgSum;\n\n if (pa > 0) {\n pa = 255 / pa;\n pixels[p] = (rSum * mulSum >> shgSum) * pa;\n pixels[p + 1] = (gSum * mulSum >> shgSum) * pa;\n pixels[p + 2] = (bSum * mulSum >> shgSum) * pa;\n } else {\n pixels[p] = pixels[p + 1] = pixels[p + 2] = 0;\n }\n\n rSum -= rOutSum;\n gSum -= gOutSum;\n bSum -= bOutSum;\n aSum -= aOutSum;\n rOutSum -= stackIn.r;\n gOutSum -= stackIn.g;\n bOutSum -= stackIn.b;\n aOutSum -= stackIn.a;\n p = x + ((p = y + radiusPlus1) < heightMinus1 ? p : heightMinus1) * width << 2;\n rSum += rInSum += stackIn.r = pixels[p];\n gSum += gInSum += stackIn.g = pixels[p + 1];\n bSum += bInSum += stackIn.b = pixels[p + 2];\n aSum += aInSum += stackIn.a = pixels[p + 3];\n stackIn = stackIn.next;\n rOutSum += pr = stackOut.r;\n gOutSum += pg = stackOut.g;\n bOutSum += pb = stackOut.b;\n aOutSum += pa = stackOut.a;\n rInSum -= pr;\n gInSum -= pg;\n bInSum -= pb;\n aInSum -= pa;\n stackOut = stackOut.next;\n yi += width;\n }\n }\n\n return imageData;\n}\n/**\n * @param {HTMLCanvasElement} canvas\n * @param {Integer} topX\n * @param {Integer} topY\n * @param {Integer} width\n * @param {Integer} height\n * @param {Float} radius\n * @returns {undefined}\n */\n\n\nfunction processCanvasRGB(canvas, topX, topY, width, height, radius) {\n if (isNaN(radius) || radius < 1) {\n return;\n }\n\n radius |= 0;\n var imageData = getImageDataFromCanvas(canvas, topX, topY, width, height);\n imageData = processImageDataRGB(imageData, topX, topY, width, height, radius);\n canvas.getContext('2d').putImageData(imageData, topX, topY);\n}\n/**\n * @param {ImageData} imageData\n * @param {Integer} topX\n * @param {Integer} topY\n * @param {Integer} width\n * @param {Integer} height\n * @param {Float} radius\n * @returns {ImageData}\n */\n\n\nfunction processImageDataRGB(imageData, topX, topY, width, height, radius) {\n var pixels = imageData.data;\n var x, y, i, p, yp, yi, yw, rSum, gSum, bSum, rOutSum, gOutSum, bOutSum, rInSum, gInSum, bInSum, pr, pg, pb, rbs;\n var div = 2 * radius + 1; // const w4 = width << 2;\n\n var widthMinus1 = width - 1;\n var heightMinus1 = height - 1;\n var radiusPlus1 = radius + 1;\n var sumFactor = radiusPlus1 * (radiusPlus1 + 1) / 2;\n var stackStart = new BlurStack();\n var stack = stackStart;\n var stackEnd;\n\n for (i = 1; i < div; i++) {\n stack = stack.next = new BlurStack();\n\n if (i === radiusPlus1) {\n stackEnd = stack;\n }\n }\n\n stack.next = stackStart;\n var stackIn = null;\n var stackOut = null;\n yw = yi = 0;\n var mulSum = mulTable[radius];\n var shgSum = shgTable[radius];\n\n for (y = 0; y < height; y++) {\n rInSum = gInSum = bInSum = rSum = gSum = bSum = 0;\n rOutSum = radiusPlus1 * (pr = pixels[yi]);\n gOutSum = radiusPlus1 * (pg = pixels[yi + 1]);\n bOutSum = radiusPlus1 * (pb = pixels[yi + 2]);\n rSum += sumFactor * pr;\n gSum += sumFactor * pg;\n bSum += sumFactor * pb;\n stack = stackStart;\n\n for (i = 0; i < radiusPlus1; i++) {\n stack.r = pr;\n stack.g = pg;\n stack.b = pb;\n stack = stack.next;\n }\n\n for (i = 1; i < radiusPlus1; i++) {\n p = yi + ((widthMinus1 < i ? widthMinus1 : i) << 2);\n rSum += (stack.r = pr = pixels[p]) * (rbs = radiusPlus1 - i);\n gSum += (stack.g = pg = pixels[p + 1]) * rbs;\n bSum += (stack.b = pb = pixels[p + 2]) * rbs;\n rInSum += pr;\n gInSum += pg;\n bInSum += pb;\n stack = stack.next;\n }\n\n stackIn = stackStart;\n stackOut = stackEnd;\n\n for (x = 0; x < width; x++) {\n pixels[yi] = rSum * mulSum >> shgSum;\n pixels[yi + 1] = gSum * mulSum >> shgSum;\n pixels[yi + 2] = bSum * mulSum >> shgSum;\n rSum -= rOutSum;\n gSum -= gOutSum;\n bSum -= bOutSum;\n rOutSum -= stackIn.r;\n gOutSum -= stackIn.g;\n bOutSum -= stackIn.b;\n p = yw + ((p = x + radius + 1) < widthMinus1 ? p : widthMinus1) << 2;\n rInSum += stackIn.r = pixels[p];\n gInSum += stackIn.g = pixels[p + 1];\n bInSum += stackIn.b = pixels[p + 2];\n rSum += rInSum;\n gSum += gInSum;\n bSum += bInSum;\n stackIn = stackIn.next;\n rOutSum += pr = stackOut.r;\n gOutSum += pg = stackOut.g;\n bOutSum += pb = stackOut.b;\n rInSum -= pr;\n gInSum -= pg;\n bInSum -= pb;\n stackOut = stackOut.next;\n yi += 4;\n }\n\n yw += width;\n }\n\n for (x = 0; x < width; x++) {\n gInSum = bInSum = rInSum = gSum = bSum = rSum = 0;\n yi = x << 2;\n rOutSum = radiusPlus1 * (pr = pixels[yi]);\n gOutSum = radiusPlus1 * (pg = pixels[yi + 1]);\n bOutSum = radiusPlus1 * (pb = pixels[yi + 2]);\n rSum += sumFactor * pr;\n gSum += sumFactor * pg;\n bSum += sumFactor * pb;\n stack = stackStart;\n\n for (i = 0; i < radiusPlus1; i++) {\n stack.r = pr;\n stack.g = pg;\n stack.b = pb;\n stack = stack.next;\n }\n\n yp = width;\n\n for (i = 1; i <= radius; i++) {\n yi = yp + x << 2;\n rSum += (stack.r = pr = pixels[yi]) * (rbs = radiusPlus1 - i);\n gSum += (stack.g = pg = pixels[yi + 1]) * rbs;\n bSum += (stack.b = pb = pixels[yi + 2]) * rbs;\n rInSum += pr;\n gInSum += pg;\n bInSum += pb;\n stack = stack.next;\n\n if (i < heightMinus1) {\n yp += width;\n }\n }\n\n yi = x;\n stackIn = stackStart;\n stackOut = stackEnd;\n\n for (y = 0; y < height; y++) {\n p = yi << 2;\n pixels[p] = rSum * mulSum >> shgSum;\n pixels[p + 1] = gSum * mulSum >> shgSum;\n pixels[p + 2] = bSum * mulSum >> shgSum;\n rSum -= rOutSum;\n gSum -= gOutSum;\n bSum -= bOutSum;\n rOutSum -= stackIn.r;\n gOutSum -= stackIn.g;\n bOutSum -= stackIn.b;\n p = x + ((p = y + radiusPlus1) < heightMinus1 ? p : heightMinus1) * width << 2;\n rSum += rInSum += stackIn.r = pixels[p];\n gSum += gInSum += stackIn.g = pixels[p + 1];\n bSum += bInSum += stackIn.b = pixels[p + 2];\n stackIn = stackIn.next;\n rOutSum += pr = stackOut.r;\n gOutSum += pg = stackOut.g;\n bOutSum += pb = stackOut.b;\n rInSum -= pr;\n gInSum -= pg;\n bInSum -= pb;\n stackOut = stackOut.next;\n yi += width;\n }\n }\n\n return imageData;\n}\n/**\n *\n */\n\n\nvar BlurStack =\n/**\n * Set properties.\n */\nfunction BlurStack() {\n _classCallCheck(this, BlurStack);\n\n this.r = 0;\n this.g = 0;\n this.b = 0;\n this.a = 0;\n this.next = null;\n};\n\nexport { BlurStack, processCanvasRGB as canvasRGB, processCanvasRGBA as canvasRGBA, processImage as image, processImageDataRGB as imageDataRGB, processImageDataRGBA as imageDataRGBA };\n","/* eslint-disable new-cap, class-methods-use-this, jsdoc/require-jsdoc */\n// Todo: Compare with latest canvg (add any improvements of ours) and add full JSDocs (denoting links to standard APIs and which are custom): https://github.com/canvg/canvg\n/**\n * Javascript SVG parser and renderer on Canvas.\n * @file canvg.js\n * @module canvg\n * @license MIT\n * @author Gabe Lerner \n * @see https://github.com/canvg/canvg\n */\n\nimport RGBColor from './rgbcolor.js';\nimport {canvasRGBA} from '../../external/stackblur-canvas/dist/stackblur-es.js';\n\n/**\n * Whether a value is `null` or `undefined`.\n * @param {any} val\n * @returns {boolean}\n */\nconst isNullish = (val) => {\n return val === null || val === undefined;\n};\n\n/**\n* @callback module:canvg.ForceRedraw\n* @returns {boolean}\n*/\n\n/**\n* @typedef {PlainObject} module:canvg.CanvgOptions\n* @property {boolean} ignoreMouse true => ignore mouse events\n* @property {boolean} ignoreAnimation true => ignore animations\n* @property {boolean} ignoreDimensions true => does not try to resize canvas\n* @property {boolean} ignoreClear true => does not clear canvas\n* @property {Integer} offsetX int => draws at a x offset\n* @property {Integer} offsetY int => draws at a y offset\n* @property {Integer} scaleWidth int => scales horizontally to width\n* @property {Integer} scaleHeight int => scales vertically to height\n* @property {module:canvg.ForceRedraw} forceRedraw function => will call the function on every frame, if it returns true, will redraw\n* @property {boolean} log Adds log function\n* @property {boolean} useCORS Whether to set CORS `crossOrigin` for the image to `Anonymous`\n*/\n\n/**\n* If called with no arguments, it will replace all `` elements on the page\n* with `` elements.\n* @function module:canvg.canvg\n* @param {HTMLCanvasElement|string} target canvas element or the id of a canvas element\n* @param {string|XMLDocument} s - svg string, url to svg file, or xml document\n* @param {module:canvg.CanvgOptions} [opts] Optional hash of options\n* @returns {Promise} All the function after the first render is completed with dom\n*/\nexport const canvg = function (target, s, opts) {\n // no parameters\n if (isNullish(target) && isNullish(s) && isNullish(opts)) {\n const svgTags = document.querySelectorAll('svg');\n return Promise.all([...svgTags].map((svgTag) => {\n const c = document.createElement('canvas');\n c.width = svgTag.clientWidth;\n c.height = svgTag.clientHeight;\n svgTag.before(c);\n svgTag.remove();\n const div = document.createElement('div');\n div.append(svgTag);\n return canvg(c, div.innerHTML);\n }));\n }\n\n if (typeof target === 'string') {\n target = document.getElementById(target);\n }\n\n // store class on canvas\n if (!isNullish(target.svg)) target.svg.stop();\n const svg = build(opts || {});\n // on i.e. 8 for flash canvas, we can't assign the property so check for it\n if (!(target.childNodes.length === 1 && target.childNodes[0].nodeName === 'OBJECT')) {\n target.svg = svg;\n }\n\n const ctx = target.getContext('2d');\n if (typeof s.documentElement !== 'undefined') {\n // load from xml doc\n return svg.loadXmlDoc(ctx, s);\n }\n if (s.substr(0, 1) === '<') {\n // load from xml string\n return svg.loadXml(ctx, s);\n }\n // load from url\n return svg.load(ctx, s);\n};\n\n/* eslint-disable jsdoc/check-types */\n/**\n* @param {module:canvg.CanvgOptions} opts\n* @returns {object}\n* @todo Flesh out exactly what object is returned here (after updating to latest and reincluding our changes here and those of StackBlur)\n*/\nfunction build (opts) {\n /* eslint-enable jsdoc/check-types */\n const svg = {opts};\n\n svg.FRAMERATE = 30;\n svg.MAX_VIRTUAL_PIXELS = 30000;\n\n svg.log = function (msg) { /* */ };\n if (svg.opts.log === true && typeof console !== 'undefined') {\n svg.log = function (msg) { console.log(msg); }; // eslint-disable-line no-console\n }\n\n // globals\n svg.init = function (ctx) {\n let uniqueId = 0;\n svg.UniqueId = function () {\n uniqueId++;\n return 'canvg' + uniqueId;\n };\n svg.Definitions = {};\n svg.Styles = {};\n svg.Animations = [];\n svg.Images = [];\n svg.ctx = ctx;\n svg.ViewPort = {\n viewPorts: [],\n Clear () { this.viewPorts = []; },\n SetCurrent (width, height) { this.viewPorts.push({width, height}); },\n RemoveCurrent () { this.viewPorts.pop(); },\n Current () { return this.viewPorts[this.viewPorts.length - 1]; },\n width () { return this.Current().width; },\n height () { return this.Current().height; },\n ComputeSize (d) {\n if (!isNullish(d) && typeof d === 'number') return d;\n if (d === 'x') return this.width();\n if (d === 'y') return this.height();\n return Math.sqrt(\n (this.width() ** 2) + (this.height() ** 2)\n ) / Math.sqrt(2);\n }\n };\n };\n svg.init();\n\n // images loaded\n svg.ImagesLoaded = function () {\n return svg.Images.every((img) => img.loaded);\n };\n\n // trim\n svg.trim = function (s) {\n return s.replace(/^\\s+|\\s+$/g, '');\n };\n\n // compress spaces\n svg.compressSpaces = function (s) {\n return s.replace(/\\s+/gm, ' ');\n };\n\n // ajax\n // Todo: Replace with `fetch` and polyfill\n svg.ajax = function (url, asynch) {\n const AJAX = window.XMLHttpRequest\n ? new XMLHttpRequest()\n : new window.ActiveXObject('Microsoft.XMLHTTP');\n if (asynch) {\n return new Promise((resolve, reject) => { // eslint-disable-line promise/avoid-new\n const req = AJAX.open('GET', url, true);\n req.addEventListener('load', () => {\n resolve(AJAX.responseText);\n });\n AJAX.send(null);\n });\n }\n\n AJAX.open('GET', url, false);\n AJAX.send(null);\n return AJAX.responseText;\n };\n\n // parse xml\n svg.parseXml = function (xml) {\n if (window.DOMParser) {\n const parser = new DOMParser();\n return parser.parseFromString(xml, 'text/xml');\n }\n xml = xml.replace(/]*>/, '');\n const xmlDoc = new window.ActiveXObject('Microsoft.XMLDOM');\n xmlDoc.async = 'false';\n xmlDoc.loadXML(xml);\n return xmlDoc;\n };\n\n // text extensions\n // get the text baseline\n const textBaselineMapping = {\n baseline: 'alphabetic',\n 'before-edge': 'top',\n 'text-before-edge': 'top',\n middle: 'middle',\n central: 'middle',\n 'after-edge': 'bottom',\n 'text-after-edge': 'bottom',\n ideographic: 'ideographic',\n alphabetic: 'alphabetic',\n hanging: 'hanging',\n mathematical: 'alphabetic'\n };\n\n svg.Property = class Property {\n constructor (name, value) {\n this.name = name;\n this.value = value;\n }\n\n getValue () {\n return this.value;\n }\n\n hasValue () {\n return (!isNullish(this.value) && this.value !== '');\n }\n\n // return the numerical value of the property\n numValue () {\n if (!this.hasValue()) return 0;\n\n let n = Number.parseFloat(this.value);\n if (String(this.value).endsWith('%')) {\n n /= 100.0;\n }\n return n;\n }\n\n valueOrDefault (def) {\n if (this.hasValue()) return this.value;\n return def;\n }\n\n numValueOrDefault (def) {\n if (this.hasValue()) return this.numValue();\n return def;\n }\n\n // color extensions\n // augment the current color value with the opacity\n addOpacity (opacityProp) {\n let newValue = this.value;\n if (!isNullish(opacityProp.value) && opacityProp.value !== '' && typeof this.value === 'string') { // can only add opacity to colors, not patterns\n const color = new RGBColor(this.value);\n if (color.ok) {\n newValue = 'rgba(' + color.r + ', ' + color.g + ', ' + color.b + ', ' + opacityProp.numValue() + ')';\n }\n }\n return new svg.Property(this.name, newValue);\n }\n\n // definition extensions\n // get the definition from the definitions table\n getDefinition () {\n let name = this.value.match(/#([^)'\"]+)/);\n if (name) { name = name[1]; }\n if (!name) { name = this.value; }\n return svg.Definitions[name];\n }\n\n isUrlDefinition () {\n return this.value.startsWith('url(');\n }\n\n getFillStyleDefinition (e, opacityProp) {\n let def = this.getDefinition();\n\n // gradient\n if (!isNullish(def) && def.createGradient) {\n return def.createGradient(svg.ctx, e, opacityProp);\n }\n\n // pattern\n if (!isNullish(def) && def.createPattern) {\n if (def.getHrefAttribute().hasValue()) {\n const pt = def.attribute('patternTransform');\n def = def.getHrefAttribute().getDefinition();\n if (pt.hasValue()) { def.attribute('patternTransform', true).value = pt.value; }\n }\n return def.createPattern(svg.ctx, e);\n }\n\n return null;\n }\n\n // length extensions\n getDPI (viewPort) {\n return 96.0; // TODO: compute?\n }\n\n getEM (viewPort) {\n let em = 12;\n\n const fontSize = new svg.Property('fontSize', svg.Font.Parse(svg.ctx.font).fontSize);\n if (fontSize.hasValue()) em = fontSize.toPixels(viewPort);\n\n return em;\n }\n\n getUnits () {\n return String(this.value).replace(/[\\d.-]/g, '');\n }\n\n // get the length as pixels\n toPixels (viewPort, processPercent) {\n if (!this.hasValue()) return 0;\n const s = String(this.value);\n if (s.endsWith('em')) return this.numValue() * this.getEM(viewPort);\n if (s.endsWith('ex')) return this.numValue() * this.getEM(viewPort) / 2.0;\n if (s.endsWith('px')) return this.numValue();\n if (s.endsWith('pt')) return this.numValue() * this.getDPI(viewPort) * (1.0 / 72.0);\n if (s.endsWith('pc')) return this.numValue() * 15;\n if (s.endsWith('cm')) return this.numValue() * this.getDPI(viewPort) / 2.54;\n if (s.endsWith('mm')) return this.numValue() * this.getDPI(viewPort) / 25.4;\n if (s.endsWith('in')) return this.numValue() * this.getDPI(viewPort);\n if (s.endsWith('%')) return this.numValue() * svg.ViewPort.ComputeSize(viewPort);\n const n = this.numValue();\n if (processPercent && n < 1.0) return n * svg.ViewPort.ComputeSize(viewPort);\n return n;\n }\n\n // time extensions\n // get the time as milliseconds\n toMilliseconds () {\n if (!this.hasValue()) return 0;\n const s = String(this.value);\n if (s.endsWith('ms')) return this.numValue();\n if (s.endsWith('s')) return this.numValue() * 1000;\n return this.numValue();\n }\n\n // angle extensions\n // get the angle as radians\n toRadians () {\n if (!this.hasValue()) return 0;\n const s = String(this.value);\n if (s.endsWith('deg')) return this.numValue() * (Math.PI / 180.0);\n if (s.endsWith('grad')) return this.numValue() * (Math.PI / 200.0);\n if (s.endsWith('rad')) return this.numValue();\n return this.numValue() * (Math.PI / 180.0);\n }\n\n toTextBaseline () {\n if (!this.hasValue()) return null;\n return textBaselineMapping[this.value];\n }\n };\n\n // fonts\n svg.Font = {\n Styles: 'normal|italic|oblique|inherit',\n Variants: 'normal|small-caps|inherit',\n Weights: 'normal|bold|bolder|lighter|100|200|300|400|500|600|700|800|900|inherit',\n\n CreateFont (fontStyle, fontVariant, fontWeight, fontSize, fontFamily, inherit) {\n const f = !isNullish(inherit) ? this.Parse(inherit) : this.CreateFont('', '', '', '', '', svg.ctx.font);\n return {\n fontFamily: fontFamily || f.fontFamily,\n fontSize: fontSize || f.fontSize,\n fontStyle: fontStyle || f.fontStyle,\n fontWeight: fontWeight || f.fontWeight,\n fontVariant: fontVariant || f.fontVariant,\n toString () {\n return [\n this.fontStyle, this.fontVariant, this.fontWeight,\n this.fontSize, this.fontFamily\n ].join(' ');\n }\n };\n },\n\n Parse (s) {\n const f = {};\n const ds = svg.trim(svg.compressSpaces(s || '')).split(' ');\n const set = {\n fontSize: false, fontStyle: false, fontWeight: false, fontVariant: false\n };\n let ff = '';\n ds.forEach((d) => {\n if (!set.fontStyle && this.Styles.includes(d)) {\n if (d !== 'inherit') {\n f.fontStyle = d;\n }\n set.fontStyle = true;\n } else if (!set.fontVariant && this.Variants.includes(d)) {\n if (d !== 'inherit') {\n f.fontVariant = d;\n }\n set.fontStyle = set.fontVariant = true;\n } else if (!set.fontWeight && this.Weights.includes(d)) {\n if (d !== 'inherit') {\n f.fontWeight = d;\n }\n set.fontStyle = set.fontVariant = set.fontWeight = true;\n } else if (!set.fontSize) {\n if (d !== 'inherit') {\n f.fontSize = d.split('/')[0];\n }\n set.fontStyle = set.fontVariant = set.fontWeight = set.fontSize = true;\n } else if (d !== 'inherit') {\n ff += d;\n }\n });\n if (ff !== '') { f.fontFamily = ff; }\n return f;\n }\n };\n\n // points and paths\n svg.ToNumberArray = function (s) {\n const a = svg.trim(svg.compressSpaces((s || '').replace(/,/g, ' '))).split(' ');\n return a.map((_a) => Number.parseFloat(_a));\n };\n svg.Point = class {\n constructor (x, y) {\n this.x = x;\n this.y = y;\n }\n\n angleTo (p) {\n return Math.atan2(p.y - this.y, p.x - this.x);\n }\n\n applyTransform (v) {\n const xp = this.x * v[0] + this.y * v[2] + v[4];\n const yp = this.x * v[1] + this.y * v[3] + v[5];\n this.x = xp;\n this.y = yp;\n }\n };\n\n svg.CreatePoint = function (s) {\n const a = svg.ToNumberArray(s);\n return new svg.Point(a[0], a[1]);\n };\n svg.CreatePath = function (s) {\n const a = svg.ToNumberArray(s);\n const path = [];\n for (let i = 0; i < a.length; i += 2) {\n path.push(new svg.Point(a[i], a[i + 1]));\n }\n return path;\n };\n\n // bounding box\n svg.BoundingBox = class {\n constructor (x1, y1, x2, y2) { // pass in initial points if you want\n this.x1 = Number.NaN;\n this.y1 = Number.NaN;\n this.x2 = Number.NaN;\n this.y2 = Number.NaN;\n this.addPoint(x1, y1);\n this.addPoint(x2, y2);\n }\n\n x () { return this.x1; }\n y () { return this.y1; }\n width () { return this.x2 - this.x1; }\n height () { return this.y2 - this.y1; }\n\n addPoint (x, y) {\n if (!isNullish(x)) {\n if (isNaN(this.x1) || isNaN(this.x2)) {\n this.x1 = x;\n this.x2 = x;\n }\n if (x < this.x1) this.x1 = x;\n if (x > this.x2) this.x2 = x;\n }\n\n if (!isNullish(y)) {\n if (isNaN(this.y1) || isNaN(this.y2)) {\n this.y1 = y;\n this.y2 = y;\n }\n if (y < this.y1) this.y1 = y;\n if (y > this.y2) this.y2 = y;\n }\n }\n addX (x) { this.addPoint(x, null); }\n addY (y) { this.addPoint(null, y); }\n\n addBoundingBox (bb) {\n this.addPoint(bb.x1, bb.y1);\n this.addPoint(bb.x2, bb.y2);\n }\n\n addQuadraticCurve (p0x, p0y, p1x, p1y, p2x, p2y) {\n const cp1x = p0x + 2 / 3 * (p1x - p0x); // CP1 = QP0 + 2/3 *(QP1-QP0)\n const cp1y = p0y + 2 / 3 * (p1y - p0y); // CP1 = QP0 + 2/3 *(QP1-QP0)\n const cp2x = cp1x + 1 / 3 * (p2x - p0x); // CP2 = CP1 + 1/3 *(QP2-QP0)\n const cp2y = cp1y + 1 / 3 * (p2y - p0y); // CP2 = CP1 + 1/3 *(QP2-QP0)\n this.addBezierCurve(p0x, p0y, cp1x, cp2x, cp1y, cp2y, p2x, p2y);\n }\n\n addBezierCurve (p0x, p0y, p1x, p1y, p2x, p2y, p3x, p3y) {\n // from http://blog.hackers-cafe.net/2009/06/how-to-calculate-bezier-curves-bounding.html\n const p0 = [p0x, p0y], p1 = [p1x, p1y], p2 = [p2x, p2y], p3 = [p3x, p3y];\n this.addPoint(p0[0], p0[1]);\n this.addPoint(p3[0], p3[1]);\n\n for (let i = 0; i <= 1; i++) {\n const f = function (t) {\n return ((1 - t) ** 3) * p0[i] +\n 3 * ((1 - t) ** 2) * t * p1[i] +\n 3 * (1 - t) * (t ** 2) * p2[i] +\n (t ** 3) * p3[i];\n };\n\n const b = 6 * p0[i] - 12 * p1[i] + 6 * p2[i];\n const a = -3 * p0[i] + 9 * p1[i] - 9 * p2[i] + 3 * p3[i];\n const c = 3 * p1[i] - 3 * p0[i];\n\n if (a === 0) {\n if (b === 0) continue;\n const t = -c / b;\n if (t > 0 && t < 1) {\n if (i === 0) this.addX(f(t));\n if (i === 1) this.addY(f(t));\n }\n continue;\n }\n\n const b2ac = (b ** 2) - 4 * c * a;\n if (b2ac < 0) continue;\n const t1 = (-b + Math.sqrt(b2ac)) / (2 * a);\n if (t1 > 0 && t1 < 1) {\n if (i === 0) this.addX(f(t1));\n if (i === 1) this.addY(f(t1));\n }\n const t2 = (-b - Math.sqrt(b2ac)) / (2 * a);\n if (t2 > 0 && t2 < 1) {\n if (i === 0) this.addX(f(t2));\n if (i === 1) this.addY(f(t2));\n }\n }\n }\n\n isPointInBox (x, y) {\n return (this.x1 <= x && x <= this.x2 && this.y1 <= y && y <= this.y2);\n }\n };\n\n // transforms\n svg.Transform = class {\n constructor (v) {\n this.Type = {\n translate: class {\n constructor (s) {\n this.p = svg.CreatePoint(s);\n this.apply = function (ctx) {\n ctx.translate(this.p.x || 0.0, this.p.y || 0.0);\n };\n this.unapply = function (ctx) {\n ctx.translate(-1.0 * this.p.x || 0.0, -1.0 * this.p.y || 0.0);\n };\n this.applyToPoint = function (p) {\n p.applyTransform([1, 0, 0, 1, this.p.x || 0.0, this.p.y || 0.0]);\n };\n }\n },\n rotate: class {\n constructor (s) {\n const a = svg.ToNumberArray(s);\n this.angle = new svg.Property('angle', a[0]);\n this.cx = a[1] || 0;\n this.cy = a[2] || 0;\n this.apply = function (ctx) {\n ctx.translate(this.cx, this.cy);\n ctx.rotate(this.angle.toRadians());\n ctx.translate(-this.cx, -this.cy);\n };\n this.unapply = function (ctx) {\n ctx.translate(this.cx, this.cy);\n ctx.rotate(-1.0 * this.angle.toRadians());\n ctx.translate(-this.cx, -this.cy);\n };\n this.applyToPoint = function (p) {\n const _a = this.angle.toRadians();\n p.applyTransform([1, 0, 0, 1, this.p.x || 0.0, this.p.y || 0.0]);\n p.applyTransform([Math.cos(_a), Math.sin(_a), -Math.sin(_a), Math.cos(_a), 0, 0]);\n p.applyTransform([1, 0, 0, 1, -this.p.x || 0.0, -this.p.y || 0.0]);\n };\n }\n },\n scale: class {\n constructor (s) {\n this.p = svg.CreatePoint(s);\n this.apply = function (ctx) {\n ctx.scale(this.p.x || 1.0, this.p.y || this.p.x || 1.0);\n };\n this.unapply = function (ctx) {\n ctx.scale(1.0 / this.p.x || 1.0, 1.0 / this.p.y || this.p.x || 1.0);\n };\n this.applyToPoint = function (p) {\n p.applyTransform([this.p.x || 0.0, 0, 0, this.p.y || 0.0, 0, 0]);\n };\n }\n },\n matrix: class {\n constructor (s) {\n this.m = svg.ToNumberArray(s);\n this.apply = function (ctx) {\n ctx.transform(this.m[0], this.m[1], this.m[2], this.m[3], this.m[4], this.m[5]);\n };\n this.applyToPoint = function (p) {\n p.applyTransform(this.m);\n };\n }\n }\n };\n Object.assign(this.Type, {\n SkewBase: class extends this.Type.matrix {\n constructor (s) {\n super(s);\n this.angle = new svg.Property('angle', s);\n }\n }\n });\n Object.assign(this.Type, {\n skewX: class extends this.Type.SkewBase {\n constructor (s) {\n super(s);\n this.m = [1, 0, Math.tan(this.angle.toRadians()), 1, 0, 0];\n }\n },\n skewY: class extends this.Type.SkewBase {\n constructor (s) {\n super(s);\n this.m = [1, Math.tan(this.angle.toRadians()), 0, 1, 0, 0];\n }\n }\n });\n\n const data = svg.trim(svg.compressSpaces(v)).replace(\n /\\)([a-zA-Z])/g, ') $1'\n ).replace(/\\)(\\s?,\\s?)/g, ') ').split(/\\s(?=[a-z])/);\n this.transforms = data.map((d) => {\n const type = svg.trim(d.split('(')[0]);\n const s = d.split('(')[1].replace(')', '');\n const transform = new this.Type[type](s);\n transform.type = type;\n return transform;\n });\n }\n\n apply (ctx) {\n this.transforms.forEach((transform) => {\n transform.apply(ctx);\n });\n }\n\n unapply (ctx) {\n for (let i = this.transforms.length - 1; i >= 0; i--) {\n this.transforms[i].unapply(ctx);\n }\n }\n\n applyToPoint (p) {\n this.transforms.forEach((transform) => {\n transform.applyToPoint(p);\n });\n }\n };\n\n // aspect ratio\n svg.AspectRatio = function (ctx, aspectRatio, width, desiredWidth, height, desiredHeight, minX, minY, refX, refY) {\n // aspect ratio - https://www.w3.org/TR/SVG/coords.html#PreserveAspectRatioAttribute\n aspectRatio = svg.compressSpaces(aspectRatio);\n aspectRatio = aspectRatio.replace(/^defer\\s/, ''); // ignore defer\n const align = aspectRatio.split(' ')[0] || 'xMidYMid';\n const meetOrSlice = aspectRatio.split(' ')[1] || 'meet';\n\n // calculate scale\n const scaleX = width / desiredWidth;\n const scaleY = height / desiredHeight;\n const scaleMin = Math.min(scaleX, scaleY);\n const scaleMax = Math.max(scaleX, scaleY);\n if (meetOrSlice === 'meet') { desiredWidth *= scaleMin; desiredHeight *= scaleMin; }\n if (meetOrSlice === 'slice') { desiredWidth *= scaleMax; desiredHeight *= scaleMax; }\n\n refX = new svg.Property('refX', refX);\n refY = new svg.Property('refY', refY);\n if (refX.hasValue() && refY.hasValue()) {\n ctx.translate(-scaleMin * refX.toPixels('x'), -scaleMin * refY.toPixels('y'));\n } else {\n // align\n if (align.startsWith('xMid') &&\n ((meetOrSlice === 'meet' && scaleMin === scaleY) || (meetOrSlice === 'slice' && scaleMax === scaleY))) {\n ctx.translate(width / 2.0 - desiredWidth / 2.0, 0);\n }\n if (align.endsWith('YMid') &&\n ((meetOrSlice === 'meet' && scaleMin === scaleX) || (meetOrSlice === 'slice' && scaleMax === scaleX))) {\n ctx.translate(0, height / 2.0 - desiredHeight / 2.0);\n }\n if (align.startsWith('xMax') &&\n ((meetOrSlice === 'meet' && scaleMin === scaleY) || (meetOrSlice === 'slice' && scaleMax === scaleY))) {\n ctx.translate(width - desiredWidth, 0);\n }\n if (align.endsWith('YMax') &&\n ((meetOrSlice === 'meet' && scaleMin === scaleX) ||\n (meetOrSlice === 'slice' && scaleMax === scaleX)\n )\n ) {\n ctx.translate(0, height - desiredHeight);\n }\n }\n\n // scale\n if (align === 'none') ctx.scale(scaleX, scaleY);\n else if (meetOrSlice === 'meet') ctx.scale(scaleMin, scaleMin);\n else if (meetOrSlice === 'slice') ctx.scale(scaleMax, scaleMax);\n\n // translate\n ctx.translate(isNullish(minX) ? 0 : -minX, isNullish(minY) ? 0 : -minY);\n };\n\n // elements\n svg.Element = {};\n\n svg.EmptyProperty = new svg.Property('EMPTY', '');\n\n svg.Element.ElementBase = class {\n constructor (node) {\n // Argument from inheriting class\n this.captureTextNodes = arguments[1]; // eslint-disable-line prefer-rest-params\n this.attributes = {};\n this.styles = {};\n this.children = [];\n if (!isNullish(node) && node.nodeType === 1) { // ELEMENT_NODE\n // add children\n [...node.childNodes].forEach((childNode) => {\n if (childNode.nodeType === 1) {\n this.addChild(childNode, true); // ELEMENT_NODE\n }\n if (this.captureTextNodes && (\n childNode.nodeType === 3 || childNode.nodeType === 4\n )) {\n const text = childNode.nodeValue || childNode.text || '';\n if (svg.trim(svg.compressSpaces(text)) !== '') {\n this.addChild(new svg.Element.tspan(childNode), false); // TEXT_NODE\n }\n }\n });\n\n // add attributes\n [...node.attributes].forEach(({nodeName, nodeValue}) => {\n this.attributes[nodeName] = new svg.Property(\n nodeName,\n nodeValue\n );\n });\n // add tag styles\n let styles = svg.Styles[node.nodeName];\n if (!isNullish(styles)) {\n Object.entries(styles).forEach(([name, styleValue]) => {\n this.styles[name] = styleValue;\n });\n }\n\n // add class styles\n if (this.attribute('class').hasValue()) {\n const classes = svg.compressSpaces(this.attribute('class').value).split(' ');\n classes.forEach((clss) => {\n styles = svg.Styles['.' + clss];\n if (!isNullish(styles)) {\n Object.entries(styles).forEach(([name, styleValue]) => {\n this.styles[name] = styleValue;\n });\n }\n styles = svg.Styles[node.nodeName + '.' + clss];\n if (!isNullish(styles)) {\n Object.entries(styles).forEach(([name, styleValue]) => {\n this.styles[name] = styleValue;\n });\n }\n });\n }\n\n // add id styles\n if (this.attribute('id').hasValue()) {\n const _styles = svg.Styles['#' + this.attribute('id').value];\n if (!isNullish(_styles)) {\n Object.entries(_styles).forEach(([name, styleValue]) => {\n this.styles[name] = styleValue;\n });\n }\n }\n\n // add inline styles\n if (this.attribute('style').hasValue()) {\n const _styles = this.attribute('style').value.split(';');\n _styles.forEach((style) => {\n if (svg.trim(style) !== '') {\n let {name, value} = style.split(':');\n name = svg.trim(name);\n value = svg.trim(value);\n this.styles[name] = new svg.Property(name, value);\n }\n });\n }\n\n // add id\n if (this.attribute('id').hasValue()) {\n if (isNullish(svg.Definitions[this.attribute('id').value])) {\n svg.Definitions[this.attribute('id').value] = this;\n }\n }\n }\n }\n\n // get or create attribute\n attribute (name, createIfNotExists) {\n let a = this.attributes[name];\n if (!isNullish(a)) return a;\n\n if (createIfNotExists === true) { a = new svg.Property(name, ''); this.attributes[name] = a; }\n return a || svg.EmptyProperty;\n }\n\n getHrefAttribute () {\n for (const a in this.attributes) {\n if (a.endsWith(':href')) {\n return this.attributes[a];\n }\n }\n return svg.EmptyProperty;\n }\n\n // get or create style, crawls up node tree\n style (name, createIfNotExists, skipAncestors) {\n let s = this.styles[name];\n if (!isNullish(s)) return s;\n\n const a = this.attribute(name);\n if (!isNullish(a) && a.hasValue()) {\n this.styles[name] = a; // move up to me to cache\n return a;\n }\n\n if (skipAncestors !== true) {\n const p = this.parent;\n if (!isNullish(p)) {\n const ps = p.style(name);\n if (!isNullish(ps) && ps.hasValue()) {\n return ps;\n }\n }\n }\n\n if (createIfNotExists === true) { s = new svg.Property(name, ''); this.styles[name] = s; }\n return s || svg.EmptyProperty;\n }\n\n // base render\n render (ctx) {\n // don't render display=none\n if (this.style('display').value === 'none') return;\n\n // don't render visibility=hidden\n if (this.style('visibility').value === 'hidden') return;\n\n ctx.save();\n if (this.attribute('mask').hasValue()) { // mask\n const mask = this.attribute('mask').getDefinition();\n if (!isNullish(mask)) mask.apply(ctx, this);\n } else if (this.style('filter').hasValue()) { // filter\n const filter = this.style('filter').getDefinition();\n if (!isNullish(filter)) filter.apply(ctx, this);\n } else {\n this.setContext(ctx);\n this.renderChildren(ctx);\n this.clearContext(ctx);\n }\n ctx.restore();\n }\n\n // base set context\n setContext (ctx) {\n // OVERRIDE ME!\n }\n\n // base clear context\n clearContext (ctx) {\n // OVERRIDE ME!\n }\n\n // base render children\n renderChildren (ctx) {\n this.children.forEach((child) => {\n child.render(ctx);\n });\n }\n\n addChild (childNode, create) {\n const child = create\n ? svg.CreateElement(childNode)\n : childNode;\n child.parent = this;\n if (child.type !== 'title') { this.children.push(child); }\n }\n };\n\n svg.Element.RenderedElementBase = class extends svg.Element.ElementBase {\n setContext (ctx) {\n // fill\n if (this.style('fill').isUrlDefinition()) {\n const fs = this.style('fill').getFillStyleDefinition(this, this.style('fill-opacity'));\n if (!isNullish(fs)) ctx.fillStyle = fs;\n } else if (this.style('fill').hasValue()) {\n const fillStyle = this.style('fill');\n if (fillStyle.value === 'currentColor') fillStyle.value = this.style('color').value;\n ctx.fillStyle = (fillStyle.value === 'none' ? 'rgba(0,0,0,0)' : fillStyle.value);\n }\n if (this.style('fill-opacity').hasValue()) {\n let fillStyle = new svg.Property('fill', ctx.fillStyle);\n fillStyle = fillStyle.addOpacity(this.style('fill-opacity'));\n ctx.fillStyle = fillStyle.value;\n }\n\n // stroke\n if (this.style('stroke').isUrlDefinition()) {\n const fs = this.style('stroke').getFillStyleDefinition(this, this.style('stroke-opacity'));\n if (!isNullish(fs)) ctx.strokeStyle = fs;\n } else if (this.style('stroke').hasValue()) {\n const strokeStyle = this.style('stroke');\n if (strokeStyle.value === 'currentColor') strokeStyle.value = this.style('color').value;\n ctx.strokeStyle = (strokeStyle.value === 'none' ? 'rgba(0,0,0,0)' : strokeStyle.value);\n }\n if (this.style('stroke-opacity').hasValue()) {\n let strokeStyle = new svg.Property('stroke', ctx.strokeStyle);\n strokeStyle = strokeStyle.addOpacity(this.style('stroke-opacity'));\n ctx.strokeStyle = strokeStyle.value;\n }\n if (this.style('stroke-width').hasValue()) {\n const newLineWidth = this.style('stroke-width').toPixels();\n ctx.lineWidth = newLineWidth === 0 ? 0.001 : newLineWidth; // browsers don't respect 0\n }\n if (this.style('stroke-linecap').hasValue()) ctx.lineCap = this.style('stroke-linecap').value;\n if (this.style('stroke-linejoin').hasValue()) ctx.lineJoin = this.style('stroke-linejoin').value;\n if (this.style('stroke-miterlimit').hasValue()) ctx.miterLimit = this.style('stroke-miterlimit').value;\n if (this.style('stroke-dasharray').hasValue() && this.style('stroke-dasharray').value !== 'none') {\n const gaps = svg.ToNumberArray(this.style('stroke-dasharray').value);\n if (typeof ctx.setLineDash !== 'undefined') {\n ctx.setLineDash(gaps);\n } else if (typeof ctx.webkitLineDash !== 'undefined') {\n ctx.webkitLineDash = gaps;\n } else if (typeof ctx.mozDash !== 'undefined' && !(gaps.length === 1 && gaps[0] === 0)) {\n ctx.mozDash = gaps;\n }\n\n const offset = this.style('stroke-dashoffset').numValueOrDefault(1);\n if (typeof ctx.lineDashOffset !== 'undefined') {\n ctx.lineDashOffset = offset;\n } else if (typeof ctx.webkitLineDashOffset !== 'undefined') {\n ctx.webkitLineDashOffset = offset;\n } else if (typeof ctx.mozDashOffset !== 'undefined') {\n ctx.mozDashOffset = offset;\n }\n }\n\n // font\n if (typeof ctx.font !== 'undefined') {\n ctx.font = svg.Font.CreateFont(\n this.style('font-style').value,\n this.style('font-variant').value,\n this.style('font-weight').value,\n this.style('font-size').hasValue() ? this.style('font-size').toPixels() + 'px' : '',\n this.style('font-family').value\n ).toString();\n }\n\n // transform\n if (this.attribute('transform').hasValue()) {\n const transform = new svg.Transform(this.attribute('transform').value);\n transform.apply(ctx);\n }\n\n // clip\n if (this.style('clip-path', false, true).hasValue()) {\n const clip = this.style('clip-path', false, true).getDefinition();\n if (!isNullish(clip)) clip.apply(ctx);\n }\n\n // opacity\n if (this.style('opacity').hasValue()) {\n ctx.globalAlpha = this.style('opacity').numValue();\n }\n }\n };\n\n svg.Element.PathElementBase = class extends svg.Element.RenderedElementBase {\n path (ctx) {\n if (!isNullish(ctx)) ctx.beginPath();\n return new svg.BoundingBox();\n }\n\n renderChildren (ctx) {\n this.path(ctx);\n svg.Mouse.checkPath(this, ctx);\n if (ctx.fillStyle !== '') {\n if (this.style('fill-rule').valueOrDefault('inherit') !== 'inherit') {\n ctx.fill(this.style('fill-rule').value);\n } else {\n ctx.fill();\n }\n }\n if (ctx.strokeStyle !== '') ctx.stroke();\n\n const markers = this.getMarkers();\n if (!isNullish(markers)) {\n if (this.style('marker-start').isUrlDefinition()) {\n const marker = this.style('marker-start').getDefinition();\n marker.render(ctx, markers[0][0], markers[0][1]);\n }\n if (this.style('marker-mid').isUrlDefinition()) {\n const marker = this.style('marker-mid').getDefinition();\n for (let i = 1; i < markers.length - 1; i++) {\n marker.render(ctx, markers[i][0], markers[i][1]);\n }\n }\n if (this.style('marker-end').isUrlDefinition()) {\n const marker = this.style('marker-end').getDefinition();\n marker.render(ctx, markers[markers.length - 1][0], markers[markers.length - 1][1]);\n }\n }\n }\n\n getBoundingBox () {\n return this.path();\n }\n\n getMarkers () {\n return null;\n }\n };\n\n // svg element\n svg.Element.svg = class extends svg.Element.RenderedElementBase {\n clearContext (ctx) {\n super.clearContext(ctx);\n svg.ViewPort.RemoveCurrent();\n }\n\n setContext (ctx) {\n // initial values and defaults\n ctx.strokeStyle = 'rgba(0,0,0,0)';\n ctx.lineCap = 'butt';\n ctx.lineJoin = 'miter';\n ctx.miterLimit = 4;\n if (typeof ctx.font !== 'undefined' && typeof window.getComputedStyle !== 'undefined') {\n ctx.font = window.getComputedStyle(ctx.canvas).getPropertyValue('font');\n }\n\n super.setContext(ctx);\n\n // create new view port\n if (!this.attribute('x').hasValue()) this.attribute('x', true).value = 0;\n if (!this.attribute('y').hasValue()) this.attribute('y', true).value = 0;\n ctx.translate(this.attribute('x').toPixels('x'), this.attribute('y').toPixels('y'));\n\n let width = svg.ViewPort.width();\n let height = svg.ViewPort.height();\n\n if (!this.attribute('width').hasValue()) this.attribute('width', true).value = '100%';\n if (!this.attribute('height').hasValue()) this.attribute('height', true).value = '100%';\n if (typeof this.root === 'undefined') {\n width = this.attribute('width').toPixels('x');\n height = this.attribute('height').toPixels('y');\n\n let x = 0;\n let y = 0;\n if (this.attribute('refX').hasValue() && this.attribute('refY').hasValue()) {\n x = -this.attribute('refX').toPixels('x');\n y = -this.attribute('refY').toPixels('y');\n }\n\n if (this.attribute('overflow').valueOrDefault('hidden') !== 'visible') {\n ctx.beginPath();\n ctx.moveTo(x, y);\n ctx.lineTo(width, y);\n ctx.lineTo(width, height);\n ctx.lineTo(x, height);\n ctx.closePath();\n ctx.clip();\n }\n }\n svg.ViewPort.SetCurrent(width, height);\n\n // viewbox\n if (this.attribute('viewBox').hasValue()) {\n const viewBox = svg.ToNumberArray(this.attribute('viewBox').value);\n const minX = viewBox[0];\n const minY = viewBox[1];\n width = viewBox[2];\n height = viewBox[3];\n\n svg.AspectRatio(\n ctx,\n this.attribute('preserveAspectRatio').value,\n svg.ViewPort.width(),\n width,\n svg.ViewPort.height(),\n height,\n minX,\n minY,\n this.attribute('refX').value,\n this.attribute('refY').value\n );\n\n svg.ViewPort.RemoveCurrent();\n svg.ViewPort.SetCurrent(viewBox[2], viewBox[3]);\n }\n }\n };\n\n // rect element\n svg.Element.rect = class extends svg.Element.PathElementBase {\n path (ctx) {\n const x = this.attribute('x').toPixels('x');\n const y = this.attribute('y').toPixels('y');\n const width = this.attribute('width').toPixels('x');\n const height = this.attribute('height').toPixels('y');\n let rx = this.attribute('rx').toPixels('x');\n let ry = this.attribute('ry').toPixels('y');\n if (this.attribute('rx').hasValue() && !this.attribute('ry').hasValue()) ry = rx;\n if (this.attribute('ry').hasValue() && !this.attribute('rx').hasValue()) rx = ry;\n rx = Math.min(rx, width / 2.0);\n ry = Math.min(ry, height / 2.0);\n if (!isNullish(ctx)) {\n ctx.beginPath();\n ctx.moveTo(x + rx, y);\n ctx.lineTo(x + width - rx, y);\n ctx.quadraticCurveTo(x + width, y, x + width, y + ry);\n ctx.lineTo(x + width, y + height - ry);\n ctx.quadraticCurveTo(x + width, y + height, x + width - rx, y + height);\n ctx.lineTo(x + rx, y + height);\n ctx.quadraticCurveTo(x, y + height, x, y + height - ry);\n ctx.lineTo(x, y + ry);\n ctx.quadraticCurveTo(x, y, x + rx, y);\n ctx.closePath();\n }\n\n return new svg.BoundingBox(x, y, x + width, y + height);\n }\n };\n\n // circle element\n svg.Element.circle = class extends svg.Element.PathElementBase {\n path (ctx) {\n const cx = this.attribute('cx').toPixels('x');\n const cy = this.attribute('cy').toPixels('y');\n const r = this.attribute('r').toPixels();\n\n if (!isNullish(ctx)) {\n ctx.beginPath();\n ctx.arc(cx, cy, r, 0, Math.PI * 2, true);\n ctx.closePath();\n }\n\n return new svg.BoundingBox(cx - r, cy - r, cx + r, cy + r);\n }\n };\n\n // ellipse element\n const KAPPA = 4 * ((Math.sqrt(2) - 1) / 3);\n svg.Element.ellipse = class extends svg.Element.PathElementBase {\n path (ctx) {\n const rx = this.attribute('rx').toPixels('x');\n const ry = this.attribute('ry').toPixels('y');\n const cx = this.attribute('cx').toPixels('x');\n const cy = this.attribute('cy').toPixels('y');\n\n if (!isNullish(ctx)) {\n ctx.beginPath();\n ctx.moveTo(cx, cy - ry);\n ctx.bezierCurveTo(cx + (KAPPA * rx), cy - ry, cx + rx, cy - (KAPPA * ry), cx + rx, cy);\n ctx.bezierCurveTo(cx + rx, cy + (KAPPA * ry), cx + (KAPPA * rx), cy + ry, cx, cy + ry);\n ctx.bezierCurveTo(cx - (KAPPA * rx), cy + ry, cx - rx, cy + (KAPPA * ry), cx - rx, cy);\n ctx.bezierCurveTo(cx - rx, cy - (KAPPA * ry), cx - (KAPPA * rx), cy - ry, cx, cy - ry);\n ctx.closePath();\n }\n\n return new svg.BoundingBox(cx - rx, cy - ry, cx + rx, cy + ry);\n }\n };\n\n // line element\n svg.Element.line = class extends svg.Element.PathElementBase {\n getPoints () {\n return [\n new svg.Point(this.attribute('x1').toPixels('x'), this.attribute('y1').toPixels('y')),\n new svg.Point(this.attribute('x2').toPixels('x'), this.attribute('y2').toPixels('y'))\n ];\n }\n\n path (ctx) {\n const points = this.getPoints();\n\n if (!isNullish(ctx)) {\n ctx.beginPath();\n ctx.moveTo(points[0].x, points[0].y);\n ctx.lineTo(points[1].x, points[1].y);\n }\n\n return new svg.BoundingBox(points[0].x, points[0].y, points[1].x, points[1].y);\n }\n\n getMarkers () {\n const points = this.getPoints();\n const a = points[0].angleTo(points[1]);\n return [[points[0], a], [points[1], a]];\n }\n };\n\n // polyline element\n svg.Element.polyline = class extends svg.Element.PathElementBase {\n constructor (node) {\n super(node);\n\n this.points = svg.CreatePath(this.attribute('points').value);\n }\n path (ctx) {\n const {x, y} = this.points[0];\n const bb = new svg.BoundingBox(x, y);\n if (!isNullish(ctx)) {\n ctx.beginPath();\n ctx.moveTo(x, y);\n }\n for (let i = 1; i < this.points.length; i++) {\n const {x: _x, y: _y} = this.points[i];\n bb.addPoint(_x, _y);\n if (!isNullish(ctx)) ctx.lineTo(_x, _y);\n }\n return bb;\n }\n\n getMarkers () {\n const markers = [];\n for (let i = 0; i < this.points.length - 1; i++) {\n markers.push([this.points[i], this.points[i].angleTo(this.points[i + 1])]);\n }\n markers.push([this.points[this.points.length - 1], markers[markers.length - 1][1]]);\n return markers;\n }\n };\n\n // polygon element\n svg.Element.polygon = class extends svg.Element.polyline {\n path (ctx) {\n const bb = super.path(ctx);\n if (!isNullish(ctx)) {\n ctx.lineTo(this.points[0].x, this.points[0].y);\n ctx.closePath();\n }\n return bb;\n }\n };\n\n // path element\n svg.Element.path = class extends svg.Element.PathElementBase {\n constructor (node) {\n super(node);\n\n let d = this.attribute('d').value\n // TODO: convert to real lexer based on https://www.w3.org/TR/SVG11/paths.html#PathDataBNF\n .replace(/,/gm, ' ') // get rid of all commas\n .replace(/([MmZzLlHhVvCcSsQqTtAa])([MmZzLlHhVvCcSsQqTtAa])/gm, '$1 $2') // separate commands from commands\n .replace(/([MmZzLlHhVvCcSsQqTtAa])([MmZzLlHhVvCcSsQqTtAa])/gm, '$1 $2') // separate commands from commands\n .replace(/([MmZzLlHhVvCcSsQqTtAa])(\\S)/gm, '$1 $2') // separate commands from points\n .replace(/(\\S)([MmZzLlHhVvCcSsQqTtAa])/gm, '$1 $2') // separate commands from points\n .replace(/(\\d)([+-])/gm, '$1 $2') // separate digits when no comma\n .replace(/(\\.\\d*)(\\.)/gm, '$1 $2') // separate digits when no comma\n .replace(/([Aa](\\s+\\d+)(\\s+\\d+)(\\s+\\d+))\\s+([01])\\s*([01])/gm, '$1 $5 $6 '); // shorthand elliptical arc path syntax\n d = svg.compressSpaces(d); // compress multiple spaces\n d = svg.trim(d);\n this.PathParser = {\n tokens: d.split(' '),\n\n reset () {\n this.i = -1;\n this.command = '';\n this.previousCommand = '';\n this.start = new svg.Point(0, 0);\n this.control = new svg.Point(0, 0);\n this.current = new svg.Point(0, 0);\n this.points = [];\n this.angles = [];\n },\n\n isEnd () {\n return this.i >= this.tokens.length - 1;\n },\n\n isCommandOrEnd () {\n if (this.isEnd()) return true;\n return !isNullish(this.tokens[this.i + 1].match(/^[A-Za-z]$/));\n },\n\n isRelativeCommand () {\n switch (this.command) {\n case 'm':\n case 'l':\n case 'h':\n case 'v':\n case 'c':\n case 's':\n case 'q':\n case 't':\n case 'a':\n case 'z':\n return true;\n }\n return false;\n },\n\n getToken () {\n this.i++;\n return this.tokens[this.i];\n },\n\n getScalar () {\n return Number.parseFloat(this.getToken());\n },\n\n nextCommand () {\n this.previousCommand = this.command;\n this.command = this.getToken();\n },\n\n getPoint () {\n const p = new svg.Point(this.getScalar(), this.getScalar());\n return this.makeAbsolute(p);\n },\n\n getAsControlPoint () {\n const p = this.getPoint();\n this.control = p;\n return p;\n },\n\n getAsCurrentPoint () {\n const p = this.getPoint();\n this.current = p;\n return p;\n },\n\n getReflectedControlPoint () {\n if (this.previousCommand.toLowerCase() !== 'c' &&\n this.previousCommand.toLowerCase() !== 's' &&\n this.previousCommand.toLowerCase() !== 'q' &&\n this.previousCommand.toLowerCase() !== 't') {\n return this.current;\n }\n\n // reflect point\n const p = new svg.Point(2 * this.current.x - this.control.x, 2 * this.current.y - this.control.y);\n return p;\n },\n\n makeAbsolute (p) {\n if (this.isRelativeCommand()) {\n p.x += this.current.x;\n p.y += this.current.y;\n }\n return p;\n },\n\n addMarker (p, from, priorTo) {\n // if the last angle isn't filled in because we didn't have this point yet ...\n if (!isNullish(priorTo) && this.angles.length > 0 && isNullish(this.angles[this.angles.length - 1])) {\n this.angles[this.angles.length - 1] = this.points[this.points.length - 1].angleTo(priorTo);\n }\n this.addMarkerAngle(p, isNullish(from) ? null : from.angleTo(p));\n },\n\n addMarkerAngle (p, a) {\n this.points.push(p);\n this.angles.push(a);\n },\n\n getMarkerPoints () { return this.points; },\n getMarkerAngles () {\n for (let i = 0; i < this.angles.length; i++) {\n if (isNullish(this.angles[i])) {\n for (let j = i + 1; j < this.angles.length; j++) {\n if (!isNullish(this.angles[j])) {\n this.angles[i] = this.angles[j];\n break;\n }\n }\n }\n }\n return this.angles;\n }\n };\n }\n\n path (ctx) {\n const pp = this.PathParser;\n pp.reset();\n\n const bb = new svg.BoundingBox();\n if (!isNullish(ctx)) ctx.beginPath();\n while (!pp.isEnd()) {\n pp.nextCommand();\n switch (pp.command) {\n case 'M':\n case 'm': {\n const p = pp.getAsCurrentPoint();\n pp.addMarker(p);\n bb.addPoint(p.x, p.y);\n if (!isNullish(ctx)) ctx.moveTo(p.x, p.y);\n pp.start = pp.current;\n while (!pp.isCommandOrEnd()) {\n const _p = pp.getAsCurrentPoint();\n pp.addMarker(_p, pp.start);\n bb.addPoint(_p.x, _p.y);\n if (!isNullish(ctx)) ctx.lineTo(_p.x, _p.y);\n }\n break;\n } case 'L':\n case 'l':\n while (!pp.isCommandOrEnd()) {\n const c = pp.current;\n const p = pp.getAsCurrentPoint();\n pp.addMarker(p, c);\n bb.addPoint(p.x, p.y);\n if (!isNullish(ctx)) ctx.lineTo(p.x, p.y);\n }\n break;\n case 'H':\n case 'h':\n while (!pp.isCommandOrEnd()) {\n const newP = new svg.Point((pp.isRelativeCommand() ? pp.current.x : 0) + pp.getScalar(), pp.current.y);\n pp.addMarker(newP, pp.current);\n pp.current = newP;\n bb.addPoint(pp.current.x, pp.current.y);\n if (!isNullish(ctx)) ctx.lineTo(pp.current.x, pp.current.y);\n }\n break;\n case 'V':\n case 'v':\n while (!pp.isCommandOrEnd()) {\n const newP = new svg.Point(pp.current.x, (pp.isRelativeCommand() ? pp.current.y : 0) + pp.getScalar());\n pp.addMarker(newP, pp.current);\n pp.current = newP;\n bb.addPoint(pp.current.x, pp.current.y);\n if (!isNullish(ctx)) ctx.lineTo(pp.current.x, pp.current.y);\n }\n break;\n case 'C':\n case 'c':\n while (!pp.isCommandOrEnd()) {\n const curr = pp.current;\n const p1 = pp.getPoint();\n const cntrl = pp.getAsControlPoint();\n const cp = pp.getAsCurrentPoint();\n pp.addMarker(cp, cntrl, p1);\n bb.addBezierCurve(curr.x, curr.y, p1.x, p1.y, cntrl.x, cntrl.y, cp.x, cp.y);\n if (!isNullish(ctx)) ctx.bezierCurveTo(p1.x, p1.y, cntrl.x, cntrl.y, cp.x, cp.y);\n }\n break;\n case 'S':\n case 's':\n while (!pp.isCommandOrEnd()) {\n const curr = pp.current;\n const p1 = pp.getReflectedControlPoint();\n const cntrl = pp.getAsControlPoint();\n const cp = pp.getAsCurrentPoint();\n pp.addMarker(cp, cntrl, p1);\n bb.addBezierCurve(curr.x, curr.y, p1.x, p1.y, cntrl.x, cntrl.y, cp.x, cp.y);\n if (!isNullish(ctx)) ctx.bezierCurveTo(p1.x, p1.y, cntrl.x, cntrl.y, cp.x, cp.y);\n }\n break;\n case 'Q':\n case 'q':\n while (!pp.isCommandOrEnd()) {\n const curr = pp.current;\n const cntrl = pp.getAsControlPoint();\n const cp = pp.getAsCurrentPoint();\n pp.addMarker(cp, cntrl, cntrl);\n bb.addQuadraticCurve(curr.x, curr.y, cntrl.x, cntrl.y, cp.x, cp.y);\n if (!isNullish(ctx)) ctx.quadraticCurveTo(cntrl.x, cntrl.y, cp.x, cp.y);\n }\n break;\n case 'T':\n case 't':\n while (!pp.isCommandOrEnd()) {\n const curr = pp.current;\n const cntrl = pp.getReflectedControlPoint();\n pp.control = cntrl;\n const cp = pp.getAsCurrentPoint();\n pp.addMarker(cp, cntrl, cntrl);\n bb.addQuadraticCurve(curr.x, curr.y, cntrl.x, cntrl.y, cp.x, cp.y);\n if (!isNullish(ctx)) ctx.quadraticCurveTo(cntrl.x, cntrl.y, cp.x, cp.y);\n }\n break;\n case 'A':\n case 'a':\n while (!pp.isCommandOrEnd()) {\n const curr = pp.current;\n let rx = pp.getScalar();\n let ry = pp.getScalar();\n const xAxisRotation = pp.getScalar() * (Math.PI / 180.0);\n const largeArcFlag = pp.getScalar();\n const sweepFlag = pp.getScalar();\n const cp = pp.getAsCurrentPoint();\n\n // Conversion from endpoint to center parameterization\n // https://www.w3.org/TR/SVG11/implnote.html#ArcConversionEndpointToCenter\n\n // x1', y1'\n const currp = new svg.Point(\n Math.cos(xAxisRotation) * (curr.x - cp.x) / 2.0 + Math.sin(xAxisRotation) * (curr.y - cp.y) / 2.0,\n -Math.sin(xAxisRotation) * (curr.x - cp.x) / 2.0 + Math.cos(xAxisRotation) * (curr.y - cp.y) / 2.0\n );\n // adjust radii\n const l = (currp.x ** 2) / (rx ** 2) + (currp.y ** 2) / (ry ** 2);\n if (l > 1) {\n rx *= Math.sqrt(l);\n ry *= Math.sqrt(l);\n }\n // cx', cy'\n let s = (largeArcFlag === sweepFlag ? -1 : 1) * Math.sqrt(\n (((rx ** 2) * (ry ** 2)) - ((rx ** 2) * (currp.y ** 2)) - ((ry ** 2) * (currp.x ** 2))) /\n ((rx ** 2) * (currp.y ** 2) + (ry ** 2) * (currp.x ** 2))\n );\n if (isNaN(s)) s = 0;\n const cpp = new svg.Point(s * rx * currp.y / ry, s * -ry * currp.x / rx);\n // cx, cy\n const centp = new svg.Point(\n (curr.x + cp.x) / 2.0 + Math.cos(xAxisRotation) * cpp.x - Math.sin(xAxisRotation) * cpp.y,\n (curr.y + cp.y) / 2.0 + Math.sin(xAxisRotation) * cpp.x + Math.cos(xAxisRotation) * cpp.y\n );\n // vector magnitude\n const m = function (v) {\n return Math.sqrt((v[0] ** 2) + (v[1] ** 2));\n };\n // ratio between two vectors\n const r = function (u, v) {\n return (u[0] * v[0] + u[1] * v[1]) / (m(u) * m(v));\n };\n // angle between two vectors\n const a = function (u, v) {\n return (u[0] * v[1] < u[1] * v[0] ? -1 : 1) * Math.acos(r(u, v));\n };\n // initial angle\n const a1 = a([1, 0], [(currp.x - cpp.x) / rx, (currp.y - cpp.y) / ry]);\n // angle delta\n const u = [(currp.x - cpp.x) / rx, (currp.y - cpp.y) / ry];\n const v = [(-currp.x - cpp.x) / rx, (-currp.y - cpp.y) / ry];\n let ad = a(u, v);\n if (r(u, v) <= -1) ad = Math.PI;\n if (r(u, v) >= 1) ad = 0;\n\n // for markers\n const dir = 1 - sweepFlag ? 1.0 : -1.0;\n const ah = a1 + dir * (ad / 2.0);\n const halfWay = new svg.Point(\n centp.x + rx * Math.cos(ah),\n centp.y + ry * Math.sin(ah)\n );\n pp.addMarkerAngle(halfWay, ah - dir * Math.PI / 2);\n pp.addMarkerAngle(cp, ah - dir * Math.PI);\n\n bb.addPoint(cp.x, cp.y); // TODO: this is too naive, make it better\n if (!isNullish(ctx)) {\n const _r = rx > ry ? rx : ry;\n const sx = rx > ry ? 1 : rx / ry;\n const sy = rx > ry ? ry / rx : 1;\n\n ctx.translate(centp.x, centp.y);\n ctx.rotate(xAxisRotation);\n ctx.scale(sx, sy);\n ctx.arc(0, 0, _r, a1, a1 + ad, 1 - sweepFlag);\n ctx.scale(1 / sx, 1 / sy);\n ctx.rotate(-xAxisRotation);\n ctx.translate(-centp.x, -centp.y);\n }\n }\n break;\n case 'Z':\n case 'z':\n if (!isNullish(ctx)) ctx.closePath();\n pp.current = pp.start;\n }\n }\n\n return bb;\n }\n\n getMarkers () {\n const points = this.PathParser.getMarkerPoints();\n const angles = this.PathParser.getMarkerAngles();\n\n const markers = points.map((point, i) => {\n return [point, angles[i]];\n });\n return markers;\n }\n };\n\n // pattern element\n svg.Element.pattern = class extends svg.Element.ElementBase {\n createPattern (ctx, element) {\n const width = this.attribute('width').toPixels('x', true);\n const height = this.attribute('height').toPixels('y', true);\n\n // render me using a temporary svg element\n const tempSvg = new svg.Element.svg();\n tempSvg.attributes.viewBox = new svg.Property('viewBox', this.attribute('viewBox').value);\n tempSvg.attributes.width = new svg.Property('width', width + 'px');\n tempSvg.attributes.height = new svg.Property('height', height + 'px');\n tempSvg.attributes.transform = new svg.Property('transform', this.attribute('patternTransform').value);\n tempSvg.children = this.children;\n\n const c = document.createElement('canvas');\n c.width = width;\n c.height = height;\n const cctx = c.getContext('2d');\n if (this.attribute('x').hasValue() && this.attribute('y').hasValue()) {\n cctx.translate(this.attribute('x').toPixels('x', true), this.attribute('y').toPixels('y', true));\n }\n // render 3x3 grid so when we transform there's no white space on edges\n for (let x = -1; x <= 1; x++) {\n for (let y = -1; y <= 1; y++) {\n cctx.save();\n cctx.translate(x * c.width, y * c.height);\n tempSvg.render(cctx);\n cctx.restore();\n }\n }\n const pattern = ctx.createPattern(c, 'repeat');\n return pattern;\n }\n };\n\n // marker element\n svg.Element.marker = class extends svg.Element.ElementBase {\n render (ctx, point, angle) {\n ctx.translate(point.x, point.y);\n if (this.attribute('orient').valueOrDefault('auto') === 'auto') ctx.rotate(angle);\n if (this.attribute('markerUnits').valueOrDefault('strokeWidth') === 'strokeWidth') ctx.scale(ctx.lineWidth, ctx.lineWidth);\n ctx.save();\n\n // render me using a temporary svg element\n const tempSvg = new svg.Element.svg();\n tempSvg.attributes.viewBox = new svg.Property(\n 'viewBox', this.attribute('viewBox').value\n );\n tempSvg.attributes.refX = new svg.Property(\n 'refX', this.attribute('refX').value\n );\n tempSvg.attributes.refY = new svg.Property(\n 'refY', this.attribute('refY').value\n );\n tempSvg.attributes.width = new svg.Property(\n 'width', this.attribute('markerWidth').value\n );\n tempSvg.attributes.height = new svg.Property(\n 'height', this.attribute('markerHeight').value\n );\n tempSvg.attributes.fill = new svg.Property(\n 'fill', this.attribute('fill').valueOrDefault('black')\n );\n tempSvg.attributes.stroke = new svg.Property(\n 'stroke', this.attribute('stroke').valueOrDefault('none')\n );\n tempSvg.children = this.children;\n tempSvg.render(ctx);\n\n ctx.restore();\n if (this.attribute('markerUnits').valueOrDefault('strokeWidth') ===\n 'strokeWidth'\n ) ctx.scale(1 / ctx.lineWidth, 1 / ctx.lineWidth);\n if (this.attribute('orient').valueOrDefault('auto') === 'auto') {\n ctx.rotate(-angle);\n }\n ctx.translate(-point.x, -point.y);\n }\n };\n\n // definitions element\n svg.Element.defs = class extends svg.Element.ElementBase {\n render (ctx) {\n // NOOP\n }\n };\n\n // base for gradients\n svg.Element.GradientBase = class extends svg.Element.ElementBase {\n constructor (node) {\n super(node);\n\n this.gradientUnits = this.attribute('gradientUnits').valueOrDefault('objectBoundingBox');\n\n this.stops = [];\n this.children.forEach((child) => {\n if (child.type === 'stop') {\n this.stops.push(child);\n }\n });\n }\n\n getGradient () {\n // OVERRIDE ME!\n }\n\n createGradient (ctx, element, parentOpacityProp) {\n const stopsContainer = this.getHrefAttribute().hasValue()\n ? this.getHrefAttribute().getDefinition()\n : this;\n\n const addParentOpacity = function (color) {\n if (parentOpacityProp.hasValue()) {\n const p = new svg.Property('color', color);\n return p.addOpacity(parentOpacityProp).value;\n }\n return color;\n };\n\n const g = this.getGradient(ctx, element);\n if (isNullish(g)) return addParentOpacity(stopsContainer.stops[stopsContainer.stops.length - 1].color);\n stopsContainer.stops.forEach(({offset, color}) => {\n g.addColorStop(offset, addParentOpacity(color));\n });\n\n if (this.attribute('gradientTransform').hasValue()) {\n // render as transformed pattern on temporary canvas\n const rootView = svg.ViewPort.viewPorts[0];\n\n const rect = new svg.Element.rect();\n rect.attributes.x = new svg.Property('x', -svg.MAX_VIRTUAL_PIXELS / 3.0);\n rect.attributes.y = new svg.Property('y', -svg.MAX_VIRTUAL_PIXELS / 3.0);\n rect.attributes.width = new svg.Property('width', svg.MAX_VIRTUAL_PIXELS);\n rect.attributes.height = new svg.Property('height', svg.MAX_VIRTUAL_PIXELS);\n\n const group = new svg.Element.g();\n group.attributes.transform = new svg.Property('transform', this.attribute('gradientTransform').value);\n group.children = [rect];\n\n const tempSvg = new svg.Element.svg();\n tempSvg.attributes.x = new svg.Property('x', 0);\n tempSvg.attributes.y = new svg.Property('y', 0);\n tempSvg.attributes.width = new svg.Property('width', rootView.width);\n tempSvg.attributes.height = new svg.Property('height', rootView.height);\n tempSvg.children = [group];\n\n const c = document.createElement('canvas');\n c.width = rootView.width;\n c.height = rootView.height;\n const tempCtx = c.getContext('2d');\n tempCtx.fillStyle = g;\n tempSvg.render(tempCtx);\n return tempCtx.createPattern(c, 'no-repeat');\n }\n\n return g;\n }\n };\n\n // linear gradient element\n svg.Element.linearGradient = class extends svg.Element.GradientBase {\n getGradient (ctx, element) {\n const useBB = this.gradientUnits === 'objectBoundingBox' && element.getBoundingBox;\n const bb = useBB\n ? element.getBoundingBox()\n : null;\n\n if (!this.attribute('x1').hasValue() &&\n !this.attribute('y1').hasValue() &&\n !this.attribute('x2').hasValue() &&\n !this.attribute('y2').hasValue()\n ) {\n this.attribute('x1', true).value = 0;\n this.attribute('y1', true).value = 0;\n this.attribute('x2', true).value = 1;\n this.attribute('y2', true).value = 0;\n }\n\n const x1 = (useBB\n ? bb.x() + bb.width() * this.attribute('x1').numValue()\n : this.attribute('x1').toPixels('x'));\n const y1 = (useBB\n ? bb.y() + bb.height() * this.attribute('y1').numValue()\n : this.attribute('y1').toPixels('y'));\n const x2 = (useBB\n ? bb.x() + bb.width() * this.attribute('x2').numValue()\n : this.attribute('x2').toPixels('x'));\n const y2 = (useBB\n ? bb.y() + bb.height() * this.attribute('y2').numValue()\n : this.attribute('y2').toPixels('y'));\n\n if (x1 === x2 && y1 === y2) return null;\n return ctx.createLinearGradient(x1, y1, x2, y2);\n }\n };\n\n // radial gradient element\n svg.Element.radialGradient = class extends svg.Element.GradientBase {\n getGradient (ctx, element) {\n const useBB = this.gradientUnits === 'objectBoundingBox' && element.getBoundingBox;\n const bb = useBB ? element.getBoundingBox() : null;\n\n if (!this.attribute('cx').hasValue()) this.attribute('cx', true).value = '50%';\n if (!this.attribute('cy').hasValue()) this.attribute('cy', true).value = '50%';\n if (!this.attribute('r').hasValue()) this.attribute('r', true).value = '50%';\n\n const cx = (useBB\n ? bb.x() + bb.width() * this.attribute('cx').numValue()\n : this.attribute('cx').toPixels('x'));\n const cy = (useBB\n ? bb.y() + bb.height() * this.attribute('cy').numValue()\n : this.attribute('cy').toPixels('y'));\n\n let fx = cx;\n let fy = cy;\n if (this.attribute('fx').hasValue()) {\n fx = (useBB\n ? bb.x() + bb.width() * this.attribute('fx').numValue()\n : this.attribute('fx').toPixels('x'));\n }\n if (this.attribute('fy').hasValue()) {\n fy = (useBB\n ? bb.y() + bb.height() * this.attribute('fy').numValue()\n : this.attribute('fy').toPixels('y'));\n }\n\n const r = (useBB\n ? (bb.width() + bb.height()) / 2.0 * this.attribute('r').numValue()\n : this.attribute('r').toPixels());\n\n return ctx.createRadialGradient(fx, fy, 0, cx, cy, r);\n }\n };\n\n // gradient stop element\n svg.Element.stop = class extends svg.Element.ElementBase {\n constructor (node) {\n super(node);\n\n this.offset = this.attribute('offset').numValue();\n if (this.offset < 0) this.offset = 0;\n if (this.offset > 1) this.offset = 1;\n\n let stopColor = this.style('stop-color');\n if (this.style('stop-opacity').hasValue()) {\n stopColor = stopColor.addOpacity(this.style('stop-opacity'));\n }\n this.color = stopColor.value;\n }\n };\n\n // animation base element\n svg.Element.AnimateBase = class extends svg.Element.ElementBase {\n constructor (node) {\n super(node);\n\n svg.Animations.push(this);\n\n this.duration = 0.0;\n this.begin = this.attribute('begin').toMilliseconds();\n this.maxDuration = this.begin + this.attribute('dur').toMilliseconds();\n\n this.initialValue = null;\n this.initialUnits = '';\n this.removed = false;\n\n this.from = this.attribute('from');\n this.to = this.attribute('to');\n this.values = this.attribute('values');\n if (this.values.hasValue()) this.values.value = this.values.value.split(';');\n }\n\n getProperty () {\n const attributeType = this.attribute('attributeType').value;\n const attributeName = this.attribute('attributeName').value;\n\n if (attributeType === 'CSS') {\n return this.parent.style(attributeName, true);\n }\n return this.parent.attribute(attributeName, true);\n }\n\n calcValue () {\n // OVERRIDE ME!\n return '';\n }\n\n update (delta) {\n // set initial value\n if (isNullish(this.initialValue)) {\n this.initialValue = this.getProperty().value;\n this.initialUnits = this.getProperty().getUnits();\n }\n\n // if we're past the end time\n if (this.duration > this.maxDuration) {\n // loop for indefinitely repeating animations\n if (this.attribute('repeatCount').value === 'indefinite' ||\n this.attribute('repeatDur').value === 'indefinite') {\n this.duration = 0.0;\n } else if (this.attribute('fill').valueOrDefault('remove') === 'freeze' && !this.frozen) {\n this.frozen = true;\n this.parent.animationFrozen = true;\n this.parent.animationFrozenValue = this.getProperty().value;\n } else if (this.attribute('fill').valueOrDefault('remove') === 'remove' && !this.removed) {\n this.removed = true;\n this.getProperty().value = this.parent.animationFrozen ? this.parent.animationFrozenValue : this.initialValue;\n return true;\n }\n return false;\n }\n this.duration += delta;\n\n // if we're past the begin time\n let updated = false;\n if (this.begin < this.duration) {\n let newValue = this.calcValue(); // tween\n\n if (this.attribute('type').hasValue()) {\n // for transform, etc.\n const type = this.attribute('type').value;\n newValue = type + '(' + newValue + ')';\n }\n\n this.getProperty().value = newValue;\n updated = true;\n }\n\n return updated;\n }\n\n // fraction of duration we've covered\n progress () {\n const ret = {progress: (this.duration - this.begin) / (this.maxDuration - this.begin)};\n if (this.values.hasValue()) {\n const p = ret.progress * (this.values.value.length - 1);\n const lb = Math.floor(p), ub = Math.ceil(p);\n ret.from = new svg.Property('from', Number.parseFloat(this.values.value[lb]));\n ret.to = new svg.Property('to', Number.parseFloat(this.values.value[ub]));\n ret.progress = (p - lb) / (ub - lb);\n } else {\n ret.from = this.from;\n ret.to = this.to;\n }\n return ret;\n }\n };\n\n // animate element\n svg.Element.animate = class extends svg.Element.AnimateBase {\n calcValue () {\n const p = this.progress();\n\n // tween value linearly\n const newValue = p.from.numValue() + (p.to.numValue() - p.from.numValue()) * p.progress;\n return newValue + this.initialUnits;\n }\n };\n\n // animate color element\n svg.Element.animateColor = class extends svg.Element.AnimateBase {\n calcValue () {\n const p = this.progress();\n const from = new RGBColor(p.from.value);\n const to = new RGBColor(p.to.value);\n\n if (from.ok && to.ok) {\n // tween color linearly\n const r = from.r + (to.r - from.r) * p.progress;\n const g = from.g + (to.g - from.g) * p.progress;\n const b = from.b + (to.b - from.b) * p.progress;\n return 'rgb(' + Number.parseInt(r) + ',' + Number.parseInt(g) + ',' + Number.parseInt(b) + ')';\n }\n return this.attribute('from').value;\n }\n };\n\n // animate transform element\n svg.Element.animateTransform = class extends svg.Element.animate {\n calcValue () {\n const p = this.progress();\n\n // tween value linearly\n const from = svg.ToNumberArray(p.from.value);\n const to = svg.ToNumberArray(p.to.value);\n let newValue = '';\n from.forEach((fr, i) => {\n newValue += fr + (to[i] - fr) * p.progress + ' ';\n });\n return newValue;\n }\n };\n\n // font element\n svg.Element.font = class extends svg.Element.ElementBase {\n constructor (node) {\n super(node);\n\n this.horizAdvX = this.attribute('horiz-adv-x').numValue();\n\n this.isRTL = false;\n this.isArabic = false;\n this.fontFace = null;\n this.missingGlyph = null;\n this.glyphs = [];\n this.children.forEach((child) => {\n if (child.type === 'font-face') {\n this.fontFace = child;\n if (child.style('font-family').hasValue()) {\n svg.Definitions[child.style('font-family').value] = this;\n }\n } else if (child.type === 'missing-glyph') {\n this.missingGlyph = child;\n } else if (child.type === 'glyph') {\n if (child.arabicForm !== '') {\n this.isRTL = true;\n this.isArabic = true;\n if (typeof this.glyphs[child.unicode] === 'undefined') {\n this.glyphs[child.unicode] = [];\n }\n this.glyphs[child.unicode][child.arabicForm] = child;\n } else {\n this.glyphs[child.unicode] = child;\n }\n }\n });\n }\n };\n\n // font-face element\n svg.Element.fontface = class extends svg.Element.ElementBase {\n constructor (node) {\n super(node);\n\n this.ascent = this.attribute('ascent').value;\n this.descent = this.attribute('descent').value;\n this.unitsPerEm = this.attribute('units-per-em').numValue();\n }\n };\n\n // missing-glyph element\n svg.Element.missingglyph = class extends svg.Element.path {\n constructor (node) {\n super(node);\n\n this.horizAdvX = 0;\n }\n };\n\n // glyph element\n svg.Element.glyph = class extends svg.Element.path {\n constructor (node) {\n super(node);\n\n this.horizAdvX = this.attribute('horiz-adv-x').numValue();\n this.unicode = this.attribute('unicode').value;\n this.arabicForm = this.attribute('arabic-form').value;\n }\n };\n\n // text element\n svg.Element.text = class extends svg.Element.RenderedElementBase {\n constructor (node) {\n super(node, true);\n }\n\n setContext (ctx) {\n super.setContext(ctx);\n\n let textBaseline = this.style('dominant-baseline').toTextBaseline();\n if (isNullish(textBaseline)) textBaseline = this.style('alignment-baseline').toTextBaseline();\n if (!isNullish(textBaseline)) ctx.textBaseline = textBaseline;\n }\n\n getBoundingBox () {\n const x = this.attribute('x').toPixels('x');\n const y = this.attribute('y').toPixels('y');\n const fontSize = this.parent.style('font-size').numValueOrDefault(svg.Font.Parse(svg.ctx.font).fontSize);\n return new svg.BoundingBox(x, y - fontSize, x + Math.floor(fontSize * 2.0 / 3.0) * this.children[0].getText().length, y);\n }\n\n renderChildren (ctx) {\n this.x = this.attribute('x').toPixels('x');\n this.y = this.attribute('y').toPixels('y');\n this.x += this.getAnchorDelta(ctx, this, 0);\n this.children.forEach((child, i) => {\n this.renderChild(ctx, this, i);\n });\n }\n\n getAnchorDelta (ctx, parent, startI) {\n const textAnchor = this.style('text-anchor').valueOrDefault('start');\n if (textAnchor !== 'start') {\n let width = 0;\n for (let i = startI; i < parent.children.length; i++) {\n const child = parent.children[i];\n if (i > startI && child.attribute('x').hasValue()) break; // new group\n width += child.measureTextRecursive(ctx);\n }\n return -1 * (textAnchor === 'end' ? width : width / 2.0);\n }\n return 0;\n }\n\n renderChild (ctx, parent, i) {\n const child = parent.children[i];\n if (child.attribute('x').hasValue()) {\n child.x = child.attribute('x').toPixels('x') + this.getAnchorDelta(ctx, parent, i);\n if (child.attribute('dx').hasValue()) child.x += child.attribute('dx').toPixels('x');\n } else {\n if (this.attribute('dx').hasValue()) this.x += this.attribute('dx').toPixels('x');\n if (child.attribute('dx').hasValue()) this.x += child.attribute('dx').toPixels('x');\n child.x = this.x;\n }\n this.x = child.x + child.measureText(ctx);\n\n if (child.attribute('y').hasValue()) {\n child.y = child.attribute('y').toPixels('y');\n if (child.attribute('dy').hasValue()) child.y += child.attribute('dy').toPixels('y');\n } else {\n if (this.attribute('dy').hasValue()) this.y += this.attribute('dy').toPixels('y');\n if (child.attribute('dy').hasValue()) this.y += child.attribute('dy').toPixels('y');\n child.y = this.y;\n }\n this.y = child.y;\n\n child.render(ctx);\n\n for (let j = 0; j < child.children.length; j++) {\n this.renderChild(ctx, child, j);\n }\n }\n };\n\n // text base\n svg.Element.TextElementBase = class extends svg.Element.RenderedElementBase {\n getGlyph (font, text, i) {\n const c = text[i];\n let glyph = null;\n if (font.isArabic) {\n let arabicForm = 'isolated';\n if ((i === 0 || text[i - 1] === ' ') && i < text.length - 2 && text[i + 1] !== ' ') arabicForm = 'terminal';\n if (i > 0 && text[i - 1] !== ' ' && i < text.length - 2 && text[i + 1] !== ' ') arabicForm = 'medial';\n if (i > 0 && text[i - 1] !== ' ' && (i === text.length - 1 || text[i + 1] === ' ')) arabicForm = 'initial';\n if (typeof font.glyphs[c] !== 'undefined') {\n glyph = font.glyphs[c][arabicForm];\n if (isNullish(glyph) && font.glyphs[c].type === 'glyph') glyph = font.glyphs[c];\n }\n } else {\n glyph = font.glyphs[c];\n }\n if (isNullish(glyph)) glyph = font.missingGlyph;\n return glyph;\n }\n\n renderChildren (ctx) {\n const customFont = this.parent.style('font-family').getDefinition();\n if (!isNullish(customFont)) {\n const fontSize = this.parent.style('font-size').numValueOrDefault(svg.Font.Parse(svg.ctx.font).fontSize);\n const fontStyle = this.parent.style('font-style').valueOrDefault(svg.Font.Parse(svg.ctx.font).fontStyle);\n let text = this.getText();\n if (customFont.isRTL) text = text.split('').reverse().join('');\n\n const dx = svg.ToNumberArray(this.parent.attribute('dx').value);\n for (let i = 0; i < text.length; i++) {\n const glyph = this.getGlyph(customFont, text, i);\n const scale = fontSize / customFont.fontFace.unitsPerEm;\n ctx.translate(this.x, this.y);\n ctx.scale(scale, -scale);\n const lw = ctx.lineWidth;\n ctx.lineWidth = ctx.lineWidth * customFont.fontFace.unitsPerEm / fontSize;\n if (fontStyle === 'italic') ctx.transform(1, 0, 0.4, 1, 0, 0);\n glyph.render(ctx);\n if (fontStyle === 'italic') ctx.transform(1, 0, -0.4, 1, 0, 0);\n ctx.lineWidth = lw;\n ctx.scale(1 / scale, -1 / scale);\n ctx.translate(-this.x, -this.y);\n\n this.x += fontSize * (glyph.horizAdvX || customFont.horizAdvX) / customFont.fontFace.unitsPerEm;\n if (typeof dx[i] !== 'undefined' && !isNaN(dx[i])) {\n this.x += dx[i];\n }\n }\n return;\n }\n\n if (ctx.fillStyle !== '') ctx.fillText(svg.compressSpaces(this.getText()), this.x, this.y);\n if (ctx.strokeStyle !== '') ctx.strokeText(svg.compressSpaces(this.getText()), this.x, this.y);\n }\n\n getText () {\n // OVERRIDE ME\n }\n\n measureTextRecursive (ctx) {\n let width = this.measureText(ctx);\n this.children.forEach((child) => {\n width += child.measureTextRecursive(ctx);\n });\n return width;\n }\n\n measureText (ctx) {\n const customFont = this.parent.style('font-family').getDefinition();\n if (!isNullish(customFont)) {\n const fontSize = this.parent.style('font-size').numValueOrDefault(svg.Font.Parse(svg.ctx.font).fontSize);\n let measure = 0;\n let text = this.getText();\n if (customFont.isRTL) text = text.split('').reverse().join('');\n const dx = svg.ToNumberArray(this.parent.attribute('dx').value);\n for (let i = 0; i < text.length; i++) {\n const glyph = this.getGlyph(customFont, text, i);\n measure += (glyph.horizAdvX || customFont.horizAdvX) * fontSize / customFont.fontFace.unitsPerEm;\n if (typeof dx[i] !== 'undefined' && !isNaN(dx[i])) {\n measure += dx[i];\n }\n }\n return measure;\n }\n\n const textToMeasure = svg.compressSpaces(this.getText());\n if (!ctx.measureText) return textToMeasure.length * 10;\n\n ctx.save();\n this.setContext(ctx);\n const {width} = ctx.measureText(textToMeasure);\n ctx.restore();\n return width;\n }\n };\n\n // tspan\n svg.Element.tspan = class extends svg.Element.TextElementBase {\n constructor (node) {\n super(node, true);\n\n this.text = node.nodeValue || node.text || '';\n }\n getText () {\n return this.text;\n }\n };\n\n // tref\n svg.Element.tref = class extends svg.Element.TextElementBase {\n getText () {\n const element = this.getHrefAttribute().getDefinition();\n if (!isNullish(element)) return element.children[0].getText();\n return undefined;\n }\n };\n\n // a element\n svg.Element.a = class extends svg.Element.TextElementBase {\n constructor (node) {\n super(node);\n\n this.hasText = true;\n [...node.childNodes].forEach((childNode) => {\n if (childNode.nodeType !== 3) {\n this.hasText = false;\n }\n });\n // this might contain text\n this.text = this.hasText ? node.childNodes[0].nodeValue : '';\n }\n\n getText () {\n return this.text;\n }\n\n renderChildren (ctx) {\n if (this.hasText) {\n // render as text element\n super.renderChildren(ctx);\n const fontSize = new svg.Property(\n 'fontSize', svg.Font.Parse(svg.ctx.font).fontSize\n );\n svg.Mouse.checkBoundingBox(\n this, new svg.BoundingBox(\n this.x,\n this.y - fontSize.toPixels('y'),\n this.x + this.measureText(ctx),\n this.y\n )\n );\n } else {\n // render as temporary group\n const g = new svg.Element.g();\n g.children = this.children;\n g.parent = this;\n g.render(ctx);\n }\n }\n\n onclick () {\n window.open(this.getHrefAttribute().value);\n }\n\n onmousemove () {\n svg.ctx.canvas.style.cursor = 'pointer';\n }\n };\n\n // image element\n svg.Element.image = class extends svg.Element.RenderedElementBase {\n constructor (node) {\n super(node);\n\n const href = this.getHrefAttribute().value;\n if (href === '') {\n return;\n }\n this._isSvg = href.match(/\\.svg$/);\n\n svg.Images.push(this);\n this.loaded = false;\n if (!this._isSvg) {\n this.img = document.createElement('img');\n if (svg.opts.useCORS === true) {\n this.img.crossOrigin = 'Anonymous';\n }\n this.img.addEventListener('load', () => {\n this.loaded = true;\n });\n this.img.addEventListener('error', () => {\n svg.log('ERROR: image \"' + href + '\" not found');\n this.loaded = true;\n });\n this.img.src = href;\n } else {\n svg.ajax(href, true).then((img) => { // eslint-disable-line promise/prefer-await-to-then, promise/always-return\n this.img = img;\n this.loaded = true;\n }).catch((err) => { // eslint-disable-line promise/prefer-await-to-callbacks\n this.erred = true;\n console.error('Ajax error for canvg', err); // eslint-disable-line no-console\n });\n }\n }\n renderChildren (ctx) {\n const x = this.attribute('x').toPixels('x');\n const y = this.attribute('y').toPixels('y');\n\n const width = this.attribute('width').toPixels('x');\n const height = this.attribute('height').toPixels('y');\n if (width === 0 || height === 0) return;\n\n ctx.save();\n if (this._isSvg) {\n ctx.drawSvg(this.img, x, y, width, height);\n } else {\n ctx.translate(x, y);\n svg.AspectRatio(\n ctx,\n this.attribute('preserveAspectRatio').value,\n width,\n this.img.width,\n height,\n this.img.height,\n 0,\n 0\n );\n ctx.drawImage(this.img, 0, 0);\n }\n ctx.restore();\n }\n\n getBoundingBox () {\n const x = this.attribute('x').toPixels('x');\n const y = this.attribute('y').toPixels('y');\n const width = this.attribute('width').toPixels('x');\n const height = this.attribute('height').toPixels('y');\n return new svg.BoundingBox(x, y, x + width, y + height);\n }\n };\n\n // group element\n svg.Element.g = class extends svg.Element.RenderedElementBase {\n getBoundingBox () {\n const bb = new svg.BoundingBox();\n this.children.forEach((child) => {\n bb.addBoundingBox(child.getBoundingBox());\n });\n return bb;\n }\n };\n\n // symbol element\n svg.Element.symbol = class extends svg.Element.RenderedElementBase {\n render (ctx) {\n // NO RENDER\n }\n };\n\n // style element\n svg.Element.style = class extends svg.Element.ElementBase {\n constructor (node) {\n super(node);\n\n // text, or spaces then CDATA\n let css = '';\n [...node.childNodes].forEach(({nodeValue}) => {\n css += nodeValue;\n });\n // remove comments\n css = css.replace(/(\\/\\*([^*]|[\\r\\n]|(\\*+([^*/]|[\\r\\n])))*\\*+\\/)|(^\\s*\\/\\/.*)/gm, ''); // eslint-disable-line unicorn/no-unsafe-regex\n // replace whitespace\n css = svg.compressSpaces(css);\n const cssDefs = css.split('}');\n cssDefs.forEach((cssDef) => {\n if (svg.trim(cssDef) !== '') {\n let [cssClasses, cssProps] = cssDef.split('{');\n cssClasses = cssClasses.split(',');\n cssProps = cssProps.split(';');\n cssClasses.forEach((cssClass) => {\n cssClass = svg.trim(cssClass);\n if (cssClass !== '') {\n const props = {};\n cssProps.forEach((cssProp) => {\n const prop = cssProp.indexOf(':');\n const name = cssProp.substr(0, prop);\n const value = cssProp.substr(prop + 1, cssProp.length - prop);\n if (!isNullish(name) && !isNullish(value)) {\n props[svg.trim(name)] = new svg.Property(svg.trim(name), svg.trim(value));\n }\n });\n svg.Styles[cssClass] = props;\n if (cssClass === '@font-face') {\n const fontFamily = props['font-family'].value.replace(/\"/g, '');\n const srcs = props.src.value.split(',');\n srcs.forEach((src) => {\n if (src.includes('format(\"svg\")')) {\n const urlStart = src.indexOf('url');\n const urlEnd = src.indexOf(')', urlStart);\n const url = src.substr(urlStart + 5, urlEnd - urlStart - 6);\n // Can this ajax safely be converted to async?\n const doc = svg.parseXml(svg.ajax(url));\n const fonts = doc.getElementsByTagName('font');\n [...fonts].forEach((font) => {\n font = svg.CreateElement(font);\n svg.Definitions[fontFamily] = font;\n });\n }\n });\n }\n }\n });\n }\n });\n }\n };\n\n // use element\n svg.Element.use = class extends svg.Element.RenderedElementBase {\n constructor (node) {\n super(node);\n\n this._el = this.getHrefAttribute().getDefinition();\n }\n\n setContext (ctx) {\n super.setContext(ctx);\n if (this.attribute('x').hasValue()) ctx.translate(this.attribute('x').toPixels('x'), 0);\n if (this.attribute('y').hasValue()) ctx.translate(0, this.attribute('y').toPixels('y'));\n }\n\n path (ctx) {\n const {_el: element} = this;\n if (!isNullish(element)) element.path(ctx);\n }\n\n getBoundingBox () {\n const {_el: element} = this;\n if (!isNullish(element)) return element.getBoundingBox();\n return undefined;\n }\n\n renderChildren (ctx) {\n const {_el: element} = this;\n if (!isNullish(element)) {\n let tempSvg = element;\n if (element.type === 'symbol') {\n // render me using a temporary svg element in symbol cases\n // (https://www.w3.org/TR/SVG/struct.html#UseElement)\n tempSvg = new svg.Element.svg();\n tempSvg.type = 'svg';\n tempSvg.attributes.viewBox = new svg.Property(\n 'viewBox', element.attribute('viewBox').value\n );\n tempSvg.attributes.preserveAspectRatio = new svg.Property(\n 'preserveAspectRatio', element.attribute('preserveAspectRatio').value\n );\n tempSvg.attributes.overflow = new svg.Property(\n 'overflow', element.attribute('overflow').value\n );\n tempSvg.children = element.children;\n }\n if (tempSvg.type === 'svg') {\n // if symbol or svg, inherit width/height from me\n if (this.attribute('width').hasValue()) {\n tempSvg.attributes.width = new svg.Property(\n 'width', this.attribute('width').value\n );\n }\n if (this.attribute('height').hasValue()) {\n tempSvg.attributes.height = new svg.Property(\n 'height', this.attribute('height').value\n );\n }\n }\n const oldParent = tempSvg.parent;\n tempSvg.parent = null;\n tempSvg.render(ctx);\n tempSvg.parent = oldParent;\n }\n }\n };\n\n // mask element\n svg.Element.mask = class extends svg.Element.ElementBase {\n apply (ctx, element) {\n // render as temp svg\n let x = this.attribute('x').toPixels('x');\n let y = this.attribute('y').toPixels('y');\n let width = this.attribute('width').toPixels('x');\n let height = this.attribute('height').toPixels('y');\n\n if (width === 0 && height === 0) {\n const bb = new svg.BoundingBox();\n this.children.forEach((child) => {\n bb.addBoundingBox(child.getBoundingBox());\n });\n x = Math.floor(bb.x1);\n y = Math.floor(bb.y1);\n width = Math.floor(bb.width());\n height = Math.floor(bb.height());\n }\n\n // temporarily remove mask to avoid recursion\n const mask = element.attribute('mask').value;\n element.attribute('mask').value = '';\n\n const cMask = document.createElement('canvas');\n cMask.width = x + width;\n cMask.height = y + height;\n const maskCtx = cMask.getContext('2d');\n this.renderChildren(maskCtx);\n\n const c = document.createElement('canvas');\n c.width = x + width;\n c.height = y + height;\n const tempCtx = c.getContext('2d');\n element.render(tempCtx);\n tempCtx.globalCompositeOperation = 'destination-in';\n tempCtx.fillStyle = maskCtx.createPattern(cMask, 'no-repeat');\n tempCtx.fillRect(0, 0, x + width, y + height);\n\n ctx.fillStyle = tempCtx.createPattern(c, 'no-repeat');\n ctx.fillRect(0, 0, x + width, y + height);\n\n // reassign mask\n element.attribute('mask').value = mask;\n }\n\n render (ctx) {\n // NO RENDER\n }\n };\n\n // clip element\n svg.Element.clipPath = class extends svg.Element.ElementBase {\n apply (ctx) {\n this.children.forEach((child) => {\n if (typeof child.path !== 'undefined') {\n let transform = null;\n if (child.attribute('transform').hasValue()) {\n transform = new svg.Transform(child.attribute('transform').value);\n transform.apply(ctx);\n }\n child.path(ctx);\n ctx.clip();\n if (transform) { transform.unapply(ctx); }\n }\n });\n }\n render (ctx) {\n // NO RENDER\n }\n };\n\n // filters\n svg.Element.filter = class extends svg.Element.ElementBase {\n apply (ctx, element) {\n // render as temp svg\n const bb = element.getBoundingBox();\n const x = Math.floor(bb.x1);\n const y = Math.floor(bb.y1);\n const width = Math.floor(bb.width());\n const height = Math.floor(bb.height());\n\n // temporarily remove filter to avoid recursion\n const filter = element.style('filter').value;\n element.style('filter').value = '';\n\n let px = 0, py = 0;\n this.children.forEach((child) => {\n const efd = child.extraFilterDistance || 0;\n px = Math.max(px, efd);\n py = Math.max(py, efd);\n });\n\n const c = document.createElement('canvas');\n c.width = width + 2 * px;\n c.height = height + 2 * py;\n const tempCtx = c.getContext('2d');\n tempCtx.translate(-x + px, -y + py);\n element.render(tempCtx);\n\n // apply filters\n this.children.forEach((child) => {\n child.apply(tempCtx, 0, 0, width + 2 * px, height + 2 * py);\n });\n\n // render on me\n ctx.drawImage(c, 0, 0, width + 2 * px, height + 2 * py, x - px, y - py, width + 2 * px, height + 2 * py);\n\n // reassign filter\n element.style('filter', true).value = filter;\n }\n\n render (ctx) {\n // NO RENDER\n }\n };\n\n svg.Element.feMorphology = class extends svg.Element.ElementBase {\n apply (ctx, x, y, width, height) {\n // TODO: implement\n }\n };\n\n svg.Element.feComposite = class extends svg.Element.ElementBase {\n apply (ctx, x, y, width, height) {\n // TODO: implement\n }\n };\n\n /**\n * @param {Uint8ClampedArray} img\n * @param {Integer} x\n * @param {Integer} y\n * @param {Float} width\n * @param {Float} height\n * @param {Integer} rgba\n * @returns {Integer}\n */\n function imGet (img, x, y, width, height, rgba) {\n return img[y * width * 4 + x * 4 + rgba];\n }\n\n /**\n * @param {Uint8ClampedArray} img\n * @param {Integer} x\n * @param {Integer} y\n * @param {Float} width\n * @param {Float} height\n * @param {Integer} rgba\n * @param {Float} val\n * @returns {void}\n */\n function imSet (img, x, y, width, height, rgba, val) {\n img[y * width * 4 + x * 4 + rgba] = val;\n }\n\n svg.Element.feColorMatrix = class extends svg.Element.ElementBase {\n constructor (node) {\n super(node);\n\n let matrix = svg.ToNumberArray(this.attribute('values').value);\n switch (this.attribute('type').valueOrDefault('matrix')) { // https://www.w3.org/TR/SVG/filters.html#feColorMatrixElement\n case 'saturate': {\n const s = matrix[0];\n matrix = [\n 0.213 + 0.787 * s, 0.715 - 0.715 * s, 0.072 - 0.072 * s, 0, 0,\n 0.213 - 0.213 * s, 0.715 + 0.285 * s, 0.072 - 0.072 * s, 0, 0,\n 0.213 - 0.213 * s, 0.715 - 0.715 * s, 0.072 + 0.928 * s, 0, 0,\n 0, 0, 0, 1, 0,\n 0, 0, 0, 0, 1\n ];\n break;\n } case 'hueRotate': {\n const a = matrix[0] * Math.PI / 180.0;\n const c = function (m1, m2, m3) {\n return m1 + Math.cos(a) * m2 + Math.sin(a) * m3;\n };\n matrix = [\n c(0.213, 0.787, -0.213), c(0.715, -0.715, -0.715), c(0.072, -0.072, 0.928), 0, 0,\n c(0.213, -0.213, 0.143), c(0.715, 0.285, 0.140), c(0.072, -0.072, -0.283), 0, 0,\n c(0.213, -0.213, -0.787), c(0.715, -0.715, 0.715), c(0.072, 0.928, 0.072), 0, 0,\n 0, 0, 0, 1, 0,\n 0, 0, 0, 0, 1\n ];\n break;\n } case 'luminanceToAlpha':\n matrix = [\n 0, 0, 0, 0, 0,\n 0, 0, 0, 0, 0,\n 0, 0, 0, 0, 0,\n 0.2125, 0.7154, 0.0721, 0, 0,\n 0, 0, 0, 0, 1\n ];\n break;\n }\n this.matrix = matrix;\n\n this._m = (i, v) => {\n const mi = matrix[i];\n return mi * (mi < 0 ? v - 255 : v);\n };\n }\n apply (ctx, x, y, width, height) {\n const {_m: m} = this;\n // assuming x==0 && y==0 for now\n const srcData = ctx.getImageData(0, 0, width, height);\n for (let _y = 0; _y < height; _y++) {\n for (let _x = 0; _x < width; _x++) {\n const r = imGet(srcData.data, _x, _y, width, height, 0);\n const g = imGet(srcData.data, _x, _y, width, height, 1);\n const b = imGet(srcData.data, _x, _y, width, height, 2);\n const a = imGet(srcData.data, _x, _y, width, height, 3);\n imSet(srcData.data, _x, _y, width, height, 0, m(0, r) + m(1, g) + m(2, b) + m(3, a) + m(4, 1));\n imSet(srcData.data, _x, _y, width, height, 1, m(5, r) + m(6, g) + m(7, b) + m(8, a) + m(9, 1));\n imSet(srcData.data, _x, _y, width, height, 2, m(10, r) + m(11, g) + m(12, b) + m(13, a) + m(14, 1));\n imSet(srcData.data, _x, _y, width, height, 3, m(15, r) + m(16, g) + m(17, b) + m(18, a) + m(19, 1));\n }\n }\n ctx.clearRect(0, 0, width, height);\n ctx.putImageData(srcData, 0, 0);\n }\n };\n\n svg.Element.feGaussianBlur = class extends svg.Element.ElementBase {\n constructor (node) {\n super(node);\n\n this.blurRadius = Math.floor(this.attribute('stdDeviation').numValue());\n this.extraFilterDistance = this.blurRadius;\n }\n\n apply (ctx, x, y, width, height) {\n // Todo: This might not be a problem anymore with out `instanceof` fix\n // StackBlur requires canvas be on document\n ctx.canvas.id = svg.UniqueId();\n ctx.canvas.style.display = 'none';\n document.body.append(ctx.canvas);\n canvasRGBA(ctx.canvas, x, y, width, height, this.blurRadius);\n ctx.canvas.remove();\n }\n };\n\n // title element, do nothing\n svg.Element.title = class extends svg.Element.ElementBase {\n constructor (node) {\n super();\n }\n };\n\n // desc element, do nothing\n svg.Element.desc = class extends svg.Element.ElementBase {\n constructor (node) {\n super();\n }\n };\n\n svg.Element.MISSING = class extends svg.Element.ElementBase {\n constructor (node) {\n super();\n svg.log('ERROR: Element \\'' + node.nodeName + '\\' not yet implemented.');\n }\n };\n\n // element factory\n svg.CreateElement = function (node) {\n const className = node.nodeName\n .replace(/^[^:]+:/, '') // remove namespace\n .replace(/-/g, ''); // remove dashes\n let e;\n if (typeof svg.Element[className] !== 'undefined') {\n e = new svg.Element[className](node);\n } else {\n e = new svg.Element.MISSING(node);\n }\n\n e.type = node.nodeName;\n return e;\n };\n\n // load from url\n svg.load = async function (ctx, url) {\n const dom = await svg.ajax(url, true);\n return svg.loadXml(ctx, dom);\n };\n\n // load from xml\n svg.loadXml = function (ctx, xml) {\n return svg.loadXmlDoc(ctx, svg.parseXml(xml));\n };\n\n svg.loadXmlDoc = function (ctx, dom) {\n let res;\n svg.init(ctx);\n\n const mapXY = function (p) {\n let e = ctx.canvas;\n while (e) {\n p.x -= e.offsetLeft;\n p.y -= e.offsetTop;\n e = e.offsetParent;\n }\n if (window.scrollX) p.x += window.scrollX;\n if (window.scrollY) p.y += window.scrollY;\n return p;\n };\n\n // bind mouse\n if (svg.opts.ignoreMouse !== true) {\n ctx.canvas.addEventListener('click', function (e) {\n const args = !isNullish(e)\n ? [e.clientX, e.clientY]\n : [event.clientX, event.clientY]; // eslint-disable-line no-restricted-globals\n const {x, y} = mapXY(new svg.Point(...args));\n svg.Mouse.onclick(x, y);\n });\n ctx.canvas.addEventListener('mousemove', function (e) {\n const args = !isNullish(e)\n ? [e.clientX, e.clientY]\n : [event.clientX, event.clientY]; // eslint-disable-line no-restricted-globals\n const {x, y} = mapXY(new svg.Point(...args));\n svg.Mouse.onmousemove(x, y);\n });\n }\n\n const e = svg.CreateElement(dom.documentElement);\n e.root = true;\n\n // render loop\n let isFirstRender = true;\n const draw = function (resolve) {\n svg.ViewPort.Clear();\n if (ctx.canvas.parentNode) {\n svg.ViewPort.SetCurrent(\n ctx.canvas.parentNode.clientWidth,\n ctx.canvas.parentNode.clientHeight\n );\n }\n\n if (svg.opts.ignoreDimensions !== true) {\n // set canvas size\n if (e.style('width').hasValue()) {\n ctx.canvas.width = e.style('width').toPixels('x');\n ctx.canvas.style.width = ctx.canvas.width + 'px';\n }\n if (e.style('height').hasValue()) {\n ctx.canvas.height = e.style('height').toPixels('y');\n ctx.canvas.style.height = ctx.canvas.height + 'px';\n }\n }\n let cWidth = ctx.canvas.clientWidth || ctx.canvas.width;\n let cHeight = ctx.canvas.clientHeight || ctx.canvas.height;\n if (svg.opts.ignoreDimensions === true &&\n e.style('width').hasValue() && e.style('height').hasValue()\n ) {\n cWidth = e.style('width').toPixels('x');\n cHeight = e.style('height').toPixels('y');\n }\n svg.ViewPort.SetCurrent(cWidth, cHeight);\n\n if (!isNullish(svg.opts.offsetX)) {\n e.attribute('x', true).value = svg.opts.offsetX;\n }\n if (!isNullish(svg.opts.offsetY)) {\n e.attribute('y', true).value = svg.opts.offsetY;\n }\n if (!isNullish(svg.opts.scaleWidth) || !isNullish(svg.opts.scaleHeight)) {\n const viewBox = svg.ToNumberArray(e.attribute('viewBox').value);\n let xRatio = null, yRatio = null;\n\n if (!isNullish(svg.opts.scaleWidth)) {\n if (e.attribute('width').hasValue()) {\n xRatio = e.attribute('width').toPixels('x') / svg.opts.scaleWidth;\n } else if (!isNaN(viewBox[2])) {\n xRatio = viewBox[2] / svg.opts.scaleWidth;\n }\n }\n\n if (!isNullish(svg.opts.scaleHeight)) {\n if (e.attribute('height').hasValue()) {\n yRatio = e.attribute('height').toPixels('y') / svg.opts.scaleHeight;\n } else if (!isNaN(viewBox[3])) {\n yRatio = viewBox[3] / svg.opts.scaleHeight;\n }\n }\n\n if (isNullish(xRatio)) { xRatio = yRatio; }\n if (isNullish(yRatio)) { yRatio = xRatio; }\n\n e.attribute('width', true).value = svg.opts.scaleWidth;\n e.attribute('height', true).value = svg.opts.scaleHeight;\n e.attribute('viewBox', true).value = '0 0 ' + (cWidth * xRatio) + ' ' + (cHeight * yRatio);\n e.attribute('preserveAspectRatio', true).value = 'none';\n }\n\n // clear and render\n if (svg.opts.ignoreClear !== true) {\n ctx.clearRect(0, 0, cWidth, cHeight);\n }\n e.render(ctx);\n if (isFirstRender) {\n isFirstRender = false;\n resolve(dom);\n }\n };\n\n let waitingForImages = true;\n svg.intervalID = setInterval(function () {\n let needUpdate = false;\n\n if (waitingForImages && svg.ImagesLoaded()) {\n waitingForImages = false;\n needUpdate = true;\n }\n\n // need update from mouse events?\n if (svg.opts.ignoreMouse !== true) {\n needUpdate = needUpdate || svg.Mouse.hasEvents();\n }\n\n // need update from animations?\n if (svg.opts.ignoreAnimation !== true) {\n svg.Animations.forEach((animation) => {\n const needAnimationUpdate = animation.update(1000 / svg.FRAMERATE);\n needUpdate = needUpdate || needAnimationUpdate;\n });\n }\n\n // need update from redraw?\n if (typeof svg.opts.forceRedraw === 'function') {\n if (svg.opts.forceRedraw() === true) {\n needUpdate = true;\n }\n }\n\n // render if needed\n if (needUpdate) {\n draw(res);\n svg.Mouse.runEvents(); // run and clear our events\n }\n }, 1000 / svg.FRAMERATE);\n // Todo: Replace with an image loading Promise utility?\n // eslint-disable-next-line promise/avoid-new\n return new Promise((resolve, reject) => {\n if (svg.ImagesLoaded()) {\n waitingForImages = false;\n draw(resolve);\n return;\n }\n res = resolve;\n });\n };\n\n svg.stop = () => {\n if (svg.intervalID) {\n clearInterval(svg.intervalID);\n }\n };\n\n svg.Mouse = {\n events: [],\n hasEvents () { return this.events.length !== 0; },\n\n onclick (x, y) {\n this.events.push({\n type: 'onclick', x, y,\n run (e) { if (e.onclick) e.onclick(); }\n });\n },\n\n onmousemove (x, y) {\n this.events.push({\n type: 'onmousemove', x, y,\n run (e) { if (e.onmousemove) e.onmousemove(); }\n });\n },\n\n eventElements: [],\n\n checkPath (element, ctx) {\n this.events.forEach(({x, y}, i) => {\n if (ctx.isPointInPath && ctx.isPointInPath(x, y)) {\n this.eventElements[i] = element;\n }\n });\n },\n\n checkBoundingBox (element, bb) {\n this.events.forEach(({x, y}, i) => {\n if (bb.isPointInBox(x, y)) {\n this.eventElements[i] = element;\n }\n });\n },\n\n runEvents () {\n svg.ctx.canvas.style.cursor = '';\n\n this.events.forEach((e, i) => {\n let element = this.eventElements[i];\n while (element) {\n e.run(element);\n element = element.parent;\n }\n });\n\n // done running, clear\n this.events = [];\n this.eventElements = [];\n }\n };\n\n return svg;\n}\n\nif (typeof CanvasRenderingContext2D !== 'undefined') {\n CanvasRenderingContext2D.prototype.drawSvg = function (s, dx, dy, dw, dh) {\n canvg(this.canvas, s, {\n ignoreMouse: true,\n ignoreAnimation: true,\n ignoreDimensions: true,\n ignoreClear: true,\n offsetX: dx,\n offsetY: dy,\n scaleWidth: dw,\n scaleHeight: dh\n });\n };\n}\n","/**\n * @file ext-server_opensave.js\n *\n * @license MIT\n *\n * @copyright 2010 Alexis Deveria\n *\n */\nimport {canvg} from '../../../external/canvg/canvg.js';\n\nconst loadExtensionTranslation = async function (lang) {\n let translationModule;\n try {\n // eslint-disable-next-line node/no-unsupported-features/es-syntax\n translationModule = await import(`./locale/${lang}.js`);\n } catch (_error) {\n // eslint-disable-next-line no-console\n console.error(`Missing translation (${lang}) - using 'en'`);\n // eslint-disable-next-line node/no-unsupported-features/es-syntax\n translationModule = await import(`./locale/en.js`);\n }\n return translationModule.default;\n};\n\nexport default {\n name: 'server_opensave',\n async init ({$, decode64, encode64}) {\n const svgEditor = this;\n const strings = await loadExtensionTranslation(svgEditor.curPrefs.lang);\n const {\n curConfig: {\n extPath,\n avoidClientSide, // Deprecated\n avoidClientSideDownload, avoidClientSideOpen\n },\n canvas: svgCanvas\n } = svgEditor;\n\n /**\n *\n * @returns {string}\n */\n function getFileNameFromTitle () {\n const title = svgCanvas.getDocumentTitle();\n // We convert (to underscore) only those disallowed Win7 file name characters\n return title.trim().replace(/[/\\\\:*?\"<>|]/g, '_');\n }\n /**\n * Escapes XML predefined entities for quoted attributes.\n * @param {string} str\n * @returns {string}\n */\n function xhtmlEscape (str) {\n return str.replace(/&(?!amp;)/g, '&').replace(/\"/g, '"').replace(/')[0].download === '';\n let a;\n if (support) {\n a = $('hidden').attr({\n download: (filename || 'image') + suffix,\n href: uri\n }).css('display', 'none').appendTo('body');\n a[0].click();\n return true;\n }\n return false;\n }\n const\n saveSvgAction = extPath + 'filesave.php',\n saveImgAction = extPath + 'filesave.php';\n // Create upload target (hidden iframe)\n\n let cancelled = false;\n\n // Hiding by size instead of display to avoid FF console errors\n // with `getBBox` in browser.js `supportsPathBBox_`)\n $(\n `SVG-edit "],{type:"text/html"});return FA(er)}(),IA=function text2xml(er){var tr,rr;er.includes("0?tr=tr[0]:(tr=er.ownerDocument.createElementNS(Yu.SVG,"defs"),er.firstChild?er.insertBefore(tr,er.firstChild.nextSibling):er.append(tr)),tr},jA=function getPathBBox(er){for(var tr=er.pathSegList,rr=tr.numberOfItems,nr=[[],[]],ar=tr.getItem(0),ir=[ar.x,ar.y],or=function getCalc(er,tr,rr,nr){return function(ar){return 1-Math.pow(ar,3)*ir[er]+3-Math.pow(ar,2)*ar*tr[er]+3*(1-ar)*Math.pow(ar,2)*rr[er]+Math.pow(ar,3)*nr[er]}},sr=0;sr0&&_r<1&&nr[hr].push(pr(_r));var vr=(-Ar-Math.sqrt(mr))/(2*fr);vr>0&&vr<1&&nr[hr].push(pr(vr))}}else{if(0===Ar)continue;var yr=-gr/Ar;yr>0&&yr<1&&nr[hr].push(pr(yr))}}ir=dr}else nr[0].push(lr.x),nr[1].push(lr.y)}var br=Math.min.apply(null,nr[0]),wr=Math.max.apply(null,nr[0])-br,kr=Math.min.apply(null,nr[1]);return{x:br,y:kr,width:wr,height:Math.max.apply(null,nr[1])-kr}};function groupBBFix(er){if(function supportsHVLineContainerBBox(){return vd}())try{return er.getBBox()}catch(er){}var tr,rr,nr=wA.data(er,"ref"),ar=null;nr?(rr=wA(nr).children().clone().attr("visibility","hidden"),wA(EA).append(rr),ar=rr.filter("line, path")):ar=wA(er).find("line, path");var ir=!1;if(ar.length)if(ar.each((function(){var er=this.getBBox();er.width&&er.height||(ir=!0)})),ir){var or=nr?rr:wA(er).children();tr=WA(or)}else tr=er.getBBox();else tr=er.getBBox();return nr&&rr.remove(),tr}var HA=function getBBox(er){var tr=er||SA.geSelectedElements()[0];if(1!==er.nodeType)return null;var rr=tr.nodeName,nr=null;switch(rr){case"text":""===tr.textContent?(tr.textContent="a",nr=tr.getBBox(),tr.textContent=""):tr.getBBox&&(nr=tr.getBBox());break;case"path":!function supportsPathBBox(){return _d}()?nr=jA(tr):tr.getBBox&&(nr=tr.getBBox());break;case"g":case"a":nr=groupBBFix(tr);break;default:if("use"===rr&&(nr=groupBBFix(tr)),"use"===rr||"foreignObject"===rr&&wd()){if(nr||(nr=tr.getBBox()),!wd()){var ar=nr,ir=ar.x,or=ar.y;nr={width:ar.width,height:ar.height,x:ir+Number.parseFloat(tr.getAttribute("x")||0),y:or+Number.parseFloat(tr.getAttribute("y")||0)}}}else if(xA.includes(rr))if(tr)try{nr=tr.getBBox()}catch(er){var sr=tr.getExtentOfChar(0),lr=tr.getComputedTextLength();nr={x:sr.x,y:sr.y,width:lr,height:sr.height}}else{var cr=wA(tr).closest("foreignObject");cr.length&&cr[0].getBBox&&(nr=cr[0].getBBox())}}return nr&&(nr=function bboxToObj(er){return{x:er.x,y:er.y,width:er.width,height:er.height}}(nr)),nr},GA=function getPathDFromSegments(er){var tr="";return wA.each(er,(function(er,rr){var nr=_slicedToArray(rr,2),ar=nr[0],ir=nr[1];tr+=ar;for(var or=0;or-.001&&rr<.001||rr<-89.99||rr>89.99)}(ir,or)){if(["ellipse","path","line","polyline","polygon"].includes(er.tagName))nr=sr=KA(er,tr,rr);else if("rect"===er.tagName){var lr=er.getAttribute("rx"),cr=er.getAttribute("ry");(lr||cr)&&(nr=sr=KA(er,tr,rr))}}if(!sr){var ur=_A(ar).matrix;nr=mA(nr.x,nr.y,nr.width,nr.height,ur).aabox}}return nr};function getStrokeOffsetForBBox(er){var tr=er.getAttribute("stroke-width");return isNaN(tr)||"none"===er.getAttribute("stroke")?0:tr/2}var WA=function getStrokedBBox(er,tr,rr){if(!er||!er.length)return!1;var nr;if(wA.each(er,(function(){nr||this.parentNode&&(nr=qA(this,tr,rr))})),void 0===nr)return null;var ar=nr.x+nr.width,ir=nr.y+nr.height,or=nr.x,sr=nr.y;if(1===er.length){var lr=getStrokeOffsetForBBox(er[0]);or-=lr,sr-=lr,ar+=lr,ir+=lr}else wA.each(er,(function(er,nr){var lr=qA(nr,tr,rr);if(lr){var cr=getStrokeOffsetForBBox(nr);or=Math.min(or,lr.x-cr),sr=Math.min(sr,lr.y-cr),1===nr.nodeType&&(ar=Math.max(ar,lr.x+lr.width+cr),ir=Math.max(ir,lr.y+lr.height+cr))}}));return nr.x=or,nr.y=sr,nr.width=ar-or,nr.height=ir-sr,nr},XA=function getVisibleElements(er){er||(er=wA(SA.getSVGContent()).children());var tr=[];return wA(er).children().each((function(er,rr){rr.getBBox&&tr.push(rr)})),tr.reverse()},YA=function getStrokedBBoxDefaultVisible(er){return er||(er=XA()),WA(er,SA.addSVGElementFromJson,SA.pathActions)},JA=function getRotationAngleFromTransformList(er,tr){if(!er)return 0;for(var rr=er.numberOfItems,nr=0;nr");var tr=er.shortcut||"";sf("#cmenu_canvas").append("
  • "+er.label+""+tr+"
  • ")}(er)}))},uf={true:!0,false:!1,null:null};_export({target:"Array",proto:!0},{fill:Od}),addToUnscopables("fill");var df=[],hf=df.sort,pf=fails((function(){df.sort(void 0)})),Af=fails((function(){df.sort(null)})),ff=arrayMethodIsStrict("sort");_export({target:"Array",proto:!0,forced:pf||!Af||!ff},{sort:function sort(er){return void 0===er?hf.call(toObject(this)):hf.call(toObject(this),aFunction$1(er))}}),_export({target:"Object",stat:!0,forced:Object.assign!==Gl},{assign:Gl});var gf="undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{},mf=ah.ArrayBuffer,_f=tr.ArrayBuffer;_export({global:!0,forced:_f!==mf},{ArrayBuffer:mf}),setSpecies("ArrayBuffer"),_export({global:!0,forced:!Fd},{DataView:ah.DataView});var vf=Math.floor;_export({target:"Number",stat:!0},{isInteger:function isInteger(er){return!isObject(er)&&isFinite(er)&&vf(er)===er}}),_export({target:"Number",stat:!0},{MAX_SAFE_INTEGER:9007199254740991});var yf=Ar.f,bf=fails((function(){yf(1)}));_export({target:"Object",stat:!0,forced:!rr||bf,sham:!rr},{getOwnPropertyDescriptor:function getOwnPropertyDescriptor(er,tr){return yf(toIndexedObject(er),tr)}});var wf=cu.f,kf=fails((function(){return!Object.getOwnPropertyNames(1)}));_export({target:"Object",stat:!0,forced:kf},{getOwnPropertyNames:wf}),_export({global:!0,forced:parseFloat!=$i},{parseFloat:$i}),_export({global:!0,forced:parseInt!=ro},{parseInt:ro}),rr&&("g"!=/./g.flags||Ls.UNSUPPORTED_Y)&&gr.f(RegExp.prototype,"flags",{configurable:!0,get:regexpFlags});var xf=Qi.trim;_export({target:"String",proto:!0,forced:function(er){return fails((function(){return!!Ui[er]()||"​…᠎"!="​…᠎"[er]()||Ui[er].name!==er}))}("trim")},{trim:function trim(){return xf(this)}});var Sf=/"/g,createHtml=function(er,tr,rr,nr){var ar=String(requireObjectCoercible(er)),ir="<"+tr;return""!==rr&&(ir+=" "+rr+'="'+String(nr).replace(Sf,""")+'"'),ir+">"+ar+""},stringHtmlForced=function(er){return fails((function(){var tr=""[er]('"');return tr!==tr.toLowerCase()||tr.split('"').length>3}))};_export({target:"String",proto:!0,forced:stringHtmlForced("link")},{link:function link(er){return createHtml(this,"a","href",er)}}),Ph("Float32",(function(er){return function Float32Array(tr,rr,nr){return er(this,tr,rr,nr)}})),Ph("Float64",(function(er){return function Float64Array(tr,rr,nr){return er(this,tr,rr,nr)}})),Ph("Int8",(function(er){return function Int8Array(tr,rr,nr){return er(this,tr,rr,nr)}})),Ph("Int16",(function(er){return function Int16Array(tr,rr,nr){return er(this,tr,rr,nr)}})),Ph("Int32",(function(er){return function Int32Array(tr,rr,nr){return er(this,tr,rr,nr)}})),Ph("Uint8",(function(er){return function Uint8ClampedArray(tr,rr,nr){return er(this,tr,rr,nr)}}),!0),Ph("Uint16",(function(er){return function Uint16Array(tr,rr,nr){return er(this,tr,rr,nr)}})),Ph("Uint32",(function(er){return function Uint32Array(tr,rr,nr){return er(this,tr,rr,nr)}})); +function jQueryPluginSVG(er){var tr=er.fn.attr;return er.fn.attr=function(er,rr){var nr=this.length;if(!nr)return tr.call(this,er,rr);for(var ar=0;ar=0)return this._xforms[er];var tr=new Error("DOMException with code=INDEX_SIZE_ERR");throw tr.code=1,tr}},{key:"insertItemBefore",value:function insertItemBefore(er,tr){var rr=null;if(tr>=0)if(tr=0&&(this._removeFromOtherLists(er),this._xforms[tr]=er,rr=er,this._list._update()),rr}},{key:"removeItem",value:function removeItem(er){if(er=0){var tr,rr=this._xforms[er],nr=new Array(this.numberOfItems-1);for(tr=0;tr1?arguments[1]:void 0)}});var Ap=document.createElementNS(Ju.SVG,"svg"),pp=function transformPoint(er,tr,rr){return{x:rr.a*er+rr.c*tr+rr.e,y:rr.b*er+rr.d*tr+rr.f}},gp=function isIdentity(er){return 1===er.a&&0===er.b&&0===er.c&&1===er.d&&0===er.e&&0===er.f},fp=function matrixMultiply(){for(var er=arguments.length,tr=new Array(er),rr=0;rr(rr=Number.parseInt(rr))){var nr=rr;rr=tr,tr=nr}for(var ar=Ap.createSVGMatrix(),ir=tr;ir<=rr;++ir){var or=ir>=0&&irer.x&&tr.yer.y},kp=jQueryPluginSVG(jQuery),xp="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",Sp="a,circle,ellipse,foreignObject,g,image,line,path,polygon,polyline,rect,svg,text,tspan,use,clipPath".split(","),Cp=null,Bp=null,Ep=null,Np=null,Lp=function dropXMLInternalSubset(er){return er.replace(/()/,"$1$2")},Tp=function toXml(er){return er.replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'")};function encode64(er){if(er=Pp(er),window.btoa)return window.btoa(er);var tr=new Array(4*Math.floor((er.length+2)/3)),rr=0,nr=0;do{var ar=er.charCodeAt(rr++),ir=er.charCodeAt(rr++),or=er.charCodeAt(rr++),sr=ar>>2,lr=(3&ar)<<4|ir>>4,cr=(15&ir)<<2|or>>6,ur=63∨Number.isNaN(ir)?(cr=64,ur=64):Number.isNaN(or)&&(ur=64),tr[nr++]=xp.charAt(sr),tr[nr++]=xp.charAt(lr),tr[nr++]=xp.charAt(cr),tr[nr++]=xp.charAt(ur)}while(rr>4,lr=(15&ar)<<4|ir>>2,cr=(3&ir)<<6|or;tr+=String.fromCharCode(sr),64!==ir&&(tr+=String.fromCharCode(lr)),64!==or&&(tr+=String.fromCharCode(cr))}while(rrSVG-edit "],{type:"text/html"});return Fp(er)}(),Rp=function text2xml(er){var tr,rr;er.includes("0?tr=tr[0]:(tr=er.ownerDocument.createElementNS(Ju.SVG,"defs"),er.firstChild?er.insertBefore(tr,er.firstChild.nextSibling):er.append(tr)),tr},Hp=function getPathBBox(er){for(var tr=er.pathSegList,rr=tr.numberOfItems,nr=[[],[]],ar=tr.getItem(0),ir=[ar.x,ar.y],or=function getCalc(er,tr,rr,nr){return function(ar){return 1-Math.pow(ar,3)*ir[er]+3-Math.pow(ar,2)*ar*tr[er]+3*(1-ar)*Math.pow(ar,2)*rr[er]+Math.pow(ar,3)*nr[er]}},sr=0;sr0&&_r<1&&nr[hr].push(Ar(_r));var vr=(-pr-Math.sqrt(mr))/(2*gr);vr>0&&vr<1&&nr[hr].push(Ar(vr))}}else{if(0===pr)continue;var yr=-fr/pr;yr>0&&yr<1&&nr[hr].push(Ar(yr))}}ir=dr}else nr[0].push(lr.x),nr[1].push(lr.y)}var br=Math.min.apply(null,nr[0]),wr=Math.max.apply(null,nr[0])-br,kr=Math.min.apply(null,nr[1]);return{x:br,y:kr,width:wr,height:Math.max.apply(null,nr[1])-kr}};function groupBBFix(er){if(function supportsHVLineContainerBBox(){return yd}())try{return er.getBBox()}catch(er){}var tr,rr,nr=kp.data(er,"ref"),ar=null;nr?(rr=kp(nr).children().clone().attr("visibility","hidden"),kp(Np).append(rr),ar=rr.filter("line, path")):ar=kp(er).find("line, path");var ir=!1;if(ar.length)if(ar.each((function(){var er=this.getBBox();er.width&&er.height||(ir=!0)})),ir){var or=nr?rr:kp(er).children();tr=Xp(or)}else tr=er.getBBox();else tr=er.getBBox();return nr&&rr.remove(),tr}var Gp=function getBBox(er){var tr=er||Cp.geSelectedElements()[0];if(1!==er.nodeType)return null;var rr=tr.nodeName,nr=null;switch(rr){case"text":""===tr.textContent?(tr.textContent="a",nr=tr.getBBox(),tr.textContent=""):tr.getBBox&&(nr=tr.getBBox());break;case"path":!function supportsPathBBox(){return vd}()?nr=Hp(tr):tr.getBBox&&(nr=tr.getBBox());break;case"g":case"a":nr=groupBBFix(tr);break;default:if("use"===rr&&(nr=groupBBFix(tr)),"use"===rr||"foreignObject"===rr&&kd()){if(nr||(nr=tr.getBBox()),!kd()){var ar=nr,ir=ar.x,or=ar.y;nr={width:ar.width,height:ar.height,x:ir+Number.parseFloat(tr.getAttribute("x")||0),y:or+Number.parseFloat(tr.getAttribute("y")||0)}}}else if(Sp.includes(rr))if(tr)try{nr=tr.getBBox()}catch(er){var sr=tr.getExtentOfChar(0),lr=tr.getComputedTextLength();nr={x:sr.x,y:sr.y,width:lr,height:sr.height}}else{var cr=kp(tr).closest("foreignObject");cr.length&&cr[0].getBBox&&(nr=cr[0].getBBox())}}return nr&&(nr=function bboxToObj(er){return{x:er.x,y:er.y,width:er.width,height:er.height}}(nr)),nr},zp=function getPathDFromSegments(er){var tr="";return kp.each(er,(function(er,rr){var nr=_slicedToArray(rr,2),ar=nr[0],ir=nr[1];tr+=ar;for(var or=0;or-.001&&rr<.001||rr<-89.99||rr>89.99)}(ir,or)){if(["ellipse","path","line","polyline","polygon"].includes(er.tagName))nr=sr=qp(er,tr,rr);else if("rect"===er.tagName){var lr=er.getAttribute("rx"),cr=er.getAttribute("ry");(lr||cr)&&(nr=sr=qp(er,tr,rr))}}if(!sr){var ur=vp(ar).matrix;nr=_p(nr.x,nr.y,nr.width,nr.height,ur).aabox}}return nr};function getStrokeOffsetForBBox(er){var tr=er.getAttribute("stroke-width");return isNaN(tr)||"none"===er.getAttribute("stroke")?0:tr/2}var Xp=function getStrokedBBox(er,tr,rr){if(!er||!er.length)return!1;var nr;if(kp.each(er,(function(){nr||this.parentNode&&(nr=Wp(this,tr,rr))})),void 0===nr)return null;var ar=nr.x+nr.width,ir=nr.y+nr.height,or=nr.x,sr=nr.y;if(1===er.length){var lr=getStrokeOffsetForBBox(er[0]);or-=lr,sr-=lr,ar+=lr,ir+=lr}else kp.each(er,(function(er,nr){var lr=Wp(nr,tr,rr);if(lr){var cr=getStrokeOffsetForBBox(nr);or=Math.min(or,lr.x-cr),sr=Math.min(sr,lr.y-cr),1===nr.nodeType&&(ar=Math.max(ar,lr.x+lr.width+cr),ir=Math.max(ir,lr.y+lr.height+cr))}}));return nr.x=or,nr.y=sr,nr.width=ar-or,nr.height=ir-sr,nr},Yp=function getVisibleElements(er){er||(er=kp(Cp.getSVGContent()).children());var tr=[];return kp(er).children().each((function(er,rr){rr.getBBox&&tr.push(rr)})),tr.reverse()},Jp=function getStrokedBBoxDefaultVisible(er){return er||(er=Yp()),Xp(er,Cp.addSVGElementFromJson,Cp.pathActions)},$p=function getRotationAngleFromTransformList(er,tr){if(!er)return 0;for(var rr=er.numberOfItems,nr=0;nr");var tr=er.shortcut||"";sg("#cmenu_canvas").append("
  • "+er.label+""+tr+"
  • ")}(er)}))};_export({target:"Array",proto:!0},{fill:Dd}),addToUnscopables("fill");var ug=[],dg=ug.sort,hg=fails((function(){ug.sort(void 0)})),Ag=fails((function(){ug.sort(null)})),pg=arrayMethodIsStrict("sort");_export({target:"Array",proto:!0,forced:hg||!Ag||!pg},{sort:function sort(er){return void 0===er?dg.call(toObject(this)):dg.call(toObject(this),aFunction$1(er))}}),_export({target:"Object",stat:!0,forced:Object.assign!==Gl},{assign:Gl});var gg="undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{},fg=ih.ArrayBuffer,mg=tr.ArrayBuffer;_export({global:!0,forced:mg!==fg},{ArrayBuffer:fg}),setSpecies("ArrayBuffer"),_export({global:!0,forced:!Fd},{DataView:ih.DataView});var _g=Math.floor;_export({target:"Number",stat:!0},{isInteger:function isInteger(er){return!isObject(er)&&isFinite(er)&&_g(er)===er}}),_export({target:"Number",stat:!0},{MAX_SAFE_INTEGER:9007199254740991});var vg=pr.f,yg=fails((function(){vg(1)}));_export({target:"Object",stat:!0,forced:!rr||yg,sham:!rr},{getOwnPropertyDescriptor:function getOwnPropertyDescriptor(er,tr){return vg(toIndexedObject(er),tr)}});var bg=cu.f,wg=fails((function(){return!Object.getOwnPropertyNames(1)}));_export({target:"Object",stat:!0,forced:wg},{getOwnPropertyNames:bg}),_export({global:!0,forced:parseFloat!=$i},{parseFloat:$i}),_export({global:!0,forced:parseInt!=ro},{parseInt:ro}),rr&&("g"!=/./g.flags||Ls.UNSUPPORTED_Y)&&fr.f(RegExp.prototype,"flags",{configurable:!0,get:regexpFlags});var kg=Qi.trim;_export({target:"String",proto:!0,forced:function(er){return fails((function(){return!!Fi[er]()||"​…᠎"!="​…᠎"[er]()||Fi[er].name!==er}))}("trim")},{trim:function trim(){return kg(this)}});var xg=/"/g,createHtml=function(er,tr,rr,nr){var ar=String(requireObjectCoercible(er)),ir="<"+tr;return""!==rr&&(ir+=" "+rr+'="'+String(nr).replace(xg,""")+'"'),ir+">"+ar+""},stringHtmlForced=function(er){return fails((function(){var tr=""[er]('"');return tr!==tr.toLowerCase()||tr.split('"').length>3}))};_export({target:"String",proto:!0,forced:stringHtmlForced("link")},{link:function link(er){return createHtml(this,"a","href",er)}}),Ph("Float32",(function(er){return function Float32Array(tr,rr,nr){return er(this,tr,rr,nr)}})),Ph("Float64",(function(er){return function Float64Array(tr,rr,nr){return er(this,tr,rr,nr)}})),Ph("Int8",(function(er){return function Int8Array(tr,rr,nr){return er(this,tr,rr,nr)}})),Ph("Int16",(function(er){return function Int16Array(tr,rr,nr){return er(this,tr,rr,nr)}})),Ph("Int32",(function(er){return function Int32Array(tr,rr,nr){return er(this,tr,rr,nr)}})),Ph("Uint8",(function(er){return function Uint8ClampedArray(tr,rr,nr){return er(this,tr,rr,nr)}}),!0),Ph("Uint16",(function(er){return function Uint16Array(tr,rr,nr){return er(this,tr,rr,nr)}})),Ph("Uint32",(function(er){return function Uint32Array(tr,rr,nr){return er(this,tr,rr,nr)}})); /** @license * * jsPDF - PDF Document creation from JavaScript @@ -60,7 +60,7 @@ function jQueryPluginSVG(er){var tr=er.fn.attr;return er.fn.attr=function(er,rr) * siefkenj, ahwolf, rickygu, Midnith, saintclair, eaparango, * kim3er, mfo, alnorth, Flamenco */ -var Cf=function(){return"undefined"!=typeof window?window:void 0!==gf?gf:"undefined"!=typeof self?self:this}();function e(){Cf.console&&"function"==typeof Cf.console.log&&Cf.console.log.apply(Cf.console,arguments)}var Bf={log:e,warn:function warn(er){Cf.console&&("function"==typeof Cf.console.warn?Cf.console.warn.apply(Cf.console,arguments):e.call(null,arguments))},error:function error(er){Cf.console&&("function"==typeof Cf.console.error?Cf.console.error.apply(Cf.console,arguments):e(er))}}; +var Sg=function(){return"undefined"!=typeof window?window:void 0!==gg?gg:"undefined"!=typeof self?self:this}();function e(){Sg.console&&"function"==typeof Sg.console.log&&Sg.console.log.apply(Sg.console,arguments)}var Cg={log:e,warn:function warn(er){Sg.console&&("function"==typeof Sg.console.warn?Sg.console.warn.apply(Sg.console,arguments):e.call(null,arguments))},error:function error(er){Sg.console&&("function"==typeof Sg.console.error?Sg.console.error.apply(Sg.console,arguments):e(er))}}; /** * @license * FileSaver.js @@ -70,13 +70,13 @@ var Cf=function(){return"undefined"!=typeof window?window:void 0!==gf?gf:"undefi * * License : https://github.com/eligrey/FileSaver.js/blob/master/LICENSE.md (MIT) * source : http://purl.eligrey.com/github/FileSaver.js - */function r(er,tr,rr){var nr=new XMLHttpRequest;nr.open("GET",er),nr.responseType="blob",nr.onload=function(){Lf(nr.response,tr,rr)},nr.onerror=function(){Bf.error("could not download file")},nr.send()}function i(er){var tr=new XMLHttpRequest;tr.open("HEAD",er,!1);try{tr.send()}catch(er){}return tr.status>=200&&tr.status<=299}function a(er){try{er.dispatchEvent(new MouseEvent("click"))}catch(rr){var tr=document.createEvent("MouseEvents");tr.initMouseEvent("click",!0,!0,window,0,0,0,80,20,!1,!1,!1,!1,0,null),er.dispatchEvent(tr)}}var Ef,Nf,Lf=Cf.saveAs||("object"!=("undefined"==typeof window?"undefined":_typeof(window))||window!==Cf?function(){}:"download"in HTMLAnchorElement.prototype?function(er,tr,rr){var nr=Cf.URL||Cf.webkitURL,ar=document.createElement("a");tr=tr||er.name||"download",ar.download=tr,ar.rel="noopener","string"==typeof er?(ar.href=er,ar.origin!==location.origin?i(ar.href)?r(er,tr,rr):a(ar,ar.target="_blank"):a(ar)):(ar.href=nr.createObjectURL(er),setTimeout((function(){nr.revokeObjectURL(ar.href)}),4e4),setTimeout((function(){a(ar)}),0))}:"msSaveOrOpenBlob"in navigator?function(er,tr,rr){if(tr=tr||er.name||"download","string"==typeof er)if(i(er))r(er,tr,rr);else{var nr=document.createElement("a");nr.href=er,nr.target="_blank",setTimeout((function(){a(nr)}))}else navigator.msSaveOrOpenBlob(function(er,tr){return void 0===tr?tr={autoBom:!1}:"object"!=_typeof(tr)&&(Bf.warn("Deprecated: Expected third argument to be a object"),tr={autoBom:!tr}),tr.autoBom&&/^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(er.type)?new Blob([String.fromCharCode(65279),er],{type:er.type}):er}(er,rr),tr)}:function(er,tr,rr,nr){if((nr=nr||open("","_blank"))&&(nr.document.title=nr.document.body.innerText="downloading..."),"string"==typeof er)return r(er,tr,rr);var ar="application/octet-stream"===er.type,ir=/constructor/i.test(Cf.HTMLElement)||Cf.safari,or=/CriOS\/[\d]+/.test(navigator.userAgent);if((or||ar&&ir)&&"object"==("undefined"==typeof FileReader?"undefined":_typeof(FileReader))){var sr=new FileReader;sr.onloadend=function(){var er=sr.result;er=or?er:er.replace(/^data:[^;]*;/,"data:attachment/file;"),nr?nr.location.href=er:location=er,nr=null},sr.readAsDataURL(er)}else{var lr=Cf.URL||Cf.webkitURL,cr=lr.createObjectURL(er);nr?nr.location=cr:location.href=cr,nr=null,setTimeout((function(){lr.revokeObjectURL(cr)}),4e4)}}); + */function r(er,tr,rr){var nr=new XMLHttpRequest;nr.open("GET",er),nr.responseType="blob",nr.onload=function(){Ng(nr.response,tr,rr)},nr.onerror=function(){Cg.error("could not download file")},nr.send()}function i(er){var tr=new XMLHttpRequest;tr.open("HEAD",er,!1);try{tr.send()}catch(er){}return tr.status>=200&&tr.status<=299}function a(er){try{er.dispatchEvent(new MouseEvent("click"))}catch(rr){var tr=document.createEvent("MouseEvents");tr.initMouseEvent("click",!0,!0,window,0,0,0,80,20,!1,!1,!1,!1,0,null),er.dispatchEvent(tr)}}var Bg,Eg,Ng=Sg.saveAs||("object"!=("undefined"==typeof window?"undefined":_typeof(window))||window!==Sg?function(){}:"download"in HTMLAnchorElement.prototype?function(er,tr,rr){var nr=Sg.URL||Sg.webkitURL,ar=document.createElement("a");tr=tr||er.name||"download",ar.download=tr,ar.rel="noopener","string"==typeof er?(ar.href=er,ar.origin!==location.origin?i(ar.href)?r(er,tr,rr):a(ar,ar.target="_blank"):a(ar)):(ar.href=nr.createObjectURL(er),setTimeout((function(){nr.revokeObjectURL(ar.href)}),4e4),setTimeout((function(){a(ar)}),0))}:"msSaveOrOpenBlob"in navigator?function(er,tr,rr){if(tr=tr||er.name||"download","string"==typeof er)if(i(er))r(er,tr,rr);else{var nr=document.createElement("a");nr.href=er,nr.target="_blank",setTimeout((function(){a(nr)}))}else navigator.msSaveOrOpenBlob(function(er,tr){return void 0===tr?tr={autoBom:!1}:"object"!=_typeof(tr)&&(Cg.warn("Deprecated: Expected third argument to be a object"),tr={autoBom:!tr}),tr.autoBom&&/^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(er.type)?new Blob([String.fromCharCode(65279),er],{type:er.type}):er}(er,rr),tr)}:function(er,tr,rr,nr){if((nr=nr||open("","_blank"))&&(nr.document.title=nr.document.body.innerText="downloading..."),"string"==typeof er)return r(er,tr,rr);var ar="application/octet-stream"===er.type,ir=/constructor/i.test(Sg.HTMLElement)||Sg.safari,or=/CriOS\/[\d]+/.test(navigator.userAgent);if((or||ar&&ir)&&"object"==("undefined"==typeof FileReader?"undefined":_typeof(FileReader))){var sr=new FileReader;sr.onloadend=function(){var er=sr.result;er=or?er:er.replace(/^data:[^;]*;/,"data:attachment/file;"),nr?nr.location.href=er:location=er,nr=null},sr.readAsDataURL(er)}else{var lr=Sg.URL||Sg.webkitURL,cr=lr.createObjectURL(er);nr?nr.location=cr:location.href=cr,nr=null,setTimeout((function(){lr.revokeObjectURL(cr)}),4e4)}}); /** * A class to parse color values * @author Stoyan Stefanov * {@link http://www.phpied.com/rgb-color-parser-in-javascript/} * @license Use it if you like it - */function c(er){var tr;er=er||"",this.ok=!1,"#"==er.charAt(0)&&(er=er.substr(1,6)),er={aliceblue:"f0f8ff",antiquewhite:"faebd7",aqua:"00ffff",aquamarine:"7fffd4",azure:"f0ffff",beige:"f5f5dc",bisque:"ffe4c4",black:"000000",blanchedalmond:"ffebcd",blue:"0000ff",blueviolet:"8a2be2",brown:"a52a2a",burlywood:"deb887",cadetblue:"5f9ea0",chartreuse:"7fff00",chocolate:"d2691e",coral:"ff7f50",cornflowerblue:"6495ed",cornsilk:"fff8dc",crimson:"dc143c",cyan:"00ffff",darkblue:"00008b",darkcyan:"008b8b",darkgoldenrod:"b8860b",darkgray:"a9a9a9",darkgreen:"006400",darkkhaki:"bdb76b",darkmagenta:"8b008b",darkolivegreen:"556b2f",darkorange:"ff8c00",darkorchid:"9932cc",darkred:"8b0000",darksalmon:"e9967a",darkseagreen:"8fbc8f",darkslateblue:"483d8b",darkslategray:"2f4f4f",darkturquoise:"00ced1",darkviolet:"9400d3",deeppink:"ff1493",deepskyblue:"00bfff",dimgray:"696969",dodgerblue:"1e90ff",feldspar:"d19275",firebrick:"b22222",floralwhite:"fffaf0",forestgreen:"228b22",fuchsia:"ff00ff",gainsboro:"dcdcdc",ghostwhite:"f8f8ff",gold:"ffd700",goldenrod:"daa520",gray:"808080",green:"008000",greenyellow:"adff2f",honeydew:"f0fff0",hotpink:"ff69b4",indianred:"cd5c5c",indigo:"4b0082",ivory:"fffff0",khaki:"f0e68c",lavender:"e6e6fa",lavenderblush:"fff0f5",lawngreen:"7cfc00",lemonchiffon:"fffacd",lightblue:"add8e6",lightcoral:"f08080",lightcyan:"e0ffff",lightgoldenrodyellow:"fafad2",lightgrey:"d3d3d3",lightgreen:"90ee90",lightpink:"ffb6c1",lightsalmon:"ffa07a",lightseagreen:"20b2aa",lightskyblue:"87cefa",lightslateblue:"8470ff",lightslategray:"778899",lightsteelblue:"b0c4de",lightyellow:"ffffe0",lime:"00ff00",limegreen:"32cd32",linen:"faf0e6",magenta:"ff00ff",maroon:"800000",mediumaquamarine:"66cdaa",mediumblue:"0000cd",mediumorchid:"ba55d3",mediumpurple:"9370d8",mediumseagreen:"3cb371",mediumslateblue:"7b68ee",mediumspringgreen:"00fa9a",mediumturquoise:"48d1cc",mediumvioletred:"c71585",midnightblue:"191970",mintcream:"f5fffa",mistyrose:"ffe4e1",moccasin:"ffe4b5",navajowhite:"ffdead",navy:"000080",oldlace:"fdf5e6",olive:"808000",olivedrab:"6b8e23",orange:"ffa500",orangered:"ff4500",orchid:"da70d6",palegoldenrod:"eee8aa",palegreen:"98fb98",paleturquoise:"afeeee",palevioletred:"d87093",papayawhip:"ffefd5",peachpuff:"ffdab9",peru:"cd853f",pink:"ffc0cb",plum:"dda0dd",powderblue:"b0e0e6",purple:"800080",red:"ff0000",rosybrown:"bc8f8f",royalblue:"4169e1",saddlebrown:"8b4513",salmon:"fa8072",sandybrown:"f4a460",seagreen:"2e8b57",seashell:"fff5ee",sienna:"a0522d",silver:"c0c0c0",skyblue:"87ceeb",slateblue:"6a5acd",slategray:"708090",snow:"fffafa",springgreen:"00ff7f",steelblue:"4682b4",tan:"d2b48c",teal:"008080",thistle:"d8bfd8",tomato:"ff6347",turquoise:"40e0d0",violet:"ee82ee",violetred:"d02090",wheat:"f5deb3",white:"ffffff",whitesmoke:"f5f5f5",yellow:"ffff00",yellowgreen:"9acd32"}[er=(er=er.replace(/ /g,"")).toLowerCase()]||er;for(var rr=[{re:/^rgb\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})\)$/,example:["rgb(123, 234, 45)","rgb(255,234,245)"],process:function process(er){return[parseInt(er[1]),parseInt(er[2]),parseInt(er[3])]}},{re:/^(\w{2})(\w{2})(\w{2})$/,example:["#00ff00","336699"],process:function process(er){return[parseInt(er[1],16),parseInt(er[2],16),parseInt(er[3],16)]}},{re:/^(\w{1})(\w{1})(\w{1})$/,example:["#fb0","f0f"],process:function process(er){return[parseInt(er[1]+er[1],16),parseInt(er[2]+er[2],16),parseInt(er[3]+er[3],16)]}}],nr=0;nr255?255:this.r,this.g=this.g<0||isNaN(this.g)?0:this.g>255?255:this.g,this.b=this.b<0||isNaN(this.b)?0:this.b>255?255:this.b,this.toRGB=function(){return"rgb("+this.r+", "+this.g+", "+this.b+")"},this.toHex=function(){var er=this.r.toString(16),tr=this.g.toString(16),rr=this.b.toString(16);return 1==er.length&&(er="0"+er),1==tr.length&&(tr="0"+tr),1==rr.length&&(rr="0"+rr),"#"+er+tr+rr}}function h(er){if("object"!=_typeof(er))throw new Error("Invalid Context passed to initialize PubSub (jsPDF-module)");var tr={};this.subscribe=function(er,rr,nr){if(nr=nr||!1,"string"!=typeof er||"function"!=typeof rr||"boolean"!=typeof nr)throw new Error("Invalid arguments passed to PubSub.subscribe (jsPDF-module)");tr.hasOwnProperty(er)||(tr[er]={});var ar=Math.random().toString(35);return tr[er][ar]=[rr,!!nr],ar},this.unsubscribe=function(er){for(var rr in tr)if(tr[rr][er])return delete tr[rr][er],0===Object.keys(tr[rr]).length&&delete tr[rr],!0;return!1},this.publish=function(rr){if(tr.hasOwnProperty(rr)){var nr=Array.prototype.slice.call(arguments,1),ar=[];for(var ir in tr[rr]){var or=tr[rr][ir];try{or[0].apply(er,nr)}catch(er){Cf.console&&Bf.error("jsPDF PubSub Error",er.message,er)}or[1]&&ar.push(ir)}ar.length&&ar.forEach(this.unsubscribe)}},this.getTopics=function(){return tr}}function l(er){if(!(this instanceof l))return new l(er);var tr="opacity,stroke-opacity".split(",");for(var rr in er)er.hasOwnProperty(rr)&&tr.indexOf(rr)>=0&&(this[rr]=er[rr]);this.id="",this.objectNumber=-1}function f$8(er,tr){this.gState=er,this.matrix=tr,this.id="",this.objectNumber=-1}function d(er,tr,rr,nr,ar){if(!(this instanceof d))return new d(er,tr,rr,nr,ar);this.type="axial"===er?2:3,this.coords=tr,this.colors=rr,f$8.call(this,nr,ar)}function p(er,tr,rr,nr,ar){if(!(this instanceof p))return new p(er,tr,rr,nr,ar);this.boundingBox=er,this.xStep=tr,this.yStep=rr,this.stream="",this.cloneIndex=0,f$8.call(this,nr,ar)}function g(er){var tr,rr="string"==typeof arguments[0]?arguments[0]:"p",nr=arguments[1],ar=arguments[2],ir=arguments[3],or=[],sr=1,lr=16,cr="S";"object"==_typeof(er=er||{})&&(rr=er.orientation,nr=er.unit||nr,ar=er.format||ar,ir=er.compress||er.compressPdf||ir,sr="number"==typeof er.userUnit?Math.abs(er.userUnit):1,void 0!==er.precision&&(tr=er.precision),void 0!==er.floatPrecision&&(lr=er.floatPrecision),cr=er.defaultPathOperation||"S"),or=er.filters||(!0===ir?["FlateEncode"]:or),nr=nr||"mm",rr=(""+(rr||"P")).toLowerCase();var ur=er.putOnlyUsedFonts||!1,dr={},hr={internal:{},__private__:{}};hr.__private__.PubSub=h;var pr="1.3",Ar=hr.__private__.getPdfVersion=function(){return pr};hr.__private__.setPdfVersion=function(er){pr=er};var fr={a0:[2383.94,3370.39],a1:[1683.78,2383.94],a2:[1190.55,1683.78],a3:[841.89,1190.55],a4:[595.28,841.89],a5:[419.53,595.28],a6:[297.64,419.53],a7:[209.76,297.64],a8:[147.4,209.76],a9:[104.88,147.4],a10:[73.7,104.88],b0:[2834.65,4008.19],b1:[2004.09,2834.65],b2:[1417.32,2004.09],b3:[1000.63,1417.32],b4:[708.66,1000.63],b5:[498.9,708.66],b6:[354.33,498.9],b7:[249.45,354.33],b8:[175.75,249.45],b9:[124.72,175.75],b10:[87.87,124.72],c0:[2599.37,3676.54],c1:[1836.85,2599.37],c2:[1298.27,1836.85],c3:[918.43,1298.27],c4:[649.13,918.43],c5:[459.21,649.13],c6:[323.15,459.21],c7:[229.61,323.15],c8:[161.57,229.61],c9:[113.39,161.57],c10:[79.37,113.39],dl:[311.81,623.62],letter:[612,792],"government-letter":[576,756],legal:[612,1008],"junior-legal":[576,360],ledger:[1224,792],tabloid:[792,1224],"credit-card":[153,243]};hr.__private__.getPageFormats=function(){return fr};var gr=hr.__private__.getPageFormat=function(er){return fr[er]};ar=ar||"a4";var mr={COMPAT:"compat",ADVANCED:"advanced"},_r=mr.COMPAT;function F(){this.saveGraphicsState(),Wr(new pa(Wn,0,0,-Wn,0,ro()*Wn).toString()+" cm"),this.setFontSize(this.getFontSize()/Wn),cr="n",_r=mr.ADVANCED}function I(){this.restoreGraphicsState(),cr="S",_r=mr.COMPAT}hr.advancedAPI=function(er){var tr=_r===mr.COMPAT;return tr&&F.call(this),"function"!=typeof er||(er(this),tr&&I.call(this)),this},hr.compatAPI=function(er){var tr=_r===mr.ADVANCED;return tr&&I.call(this),"function"!=typeof er||(er(this),tr&&F.call(this)),this},hr.isAdvancedAPI=function(){return _r===mr.ADVANCED};var vr,yr=function j(er){if(_r!==mr.ADVANCED)throw new Error(er+" is only available in 'advanced' API mode. You need to call advancedAPI() first.")},br=hr.roundToPrecision=hr.__private__.roundToPrecision=function(er,rr){var nr=tr||rr;if(isNaN(er)||isNaN(nr))throw new Error("Invalid argument passed to jsPDF.roundToPrecision");return er.toFixed(nr).replace(/0+$/,"")};vr=hr.hpf=hr.__private__.hpf="number"==typeof lr?function(er){if(isNaN(er))throw new Error("Invalid argument passed to jsPDF.hpf");return br(er,lr)}:"smart"===lr?function(er){if(isNaN(er))throw new Error("Invalid argument passed to jsPDF.hpf");return br(er,er>-1&&er<1?16:5)}:function(er){if(isNaN(er))throw new Error("Invalid argument passed to jsPDF.hpf");return br(er,16)};var wr=hr.f2=hr.__private__.f2=function(er){if(isNaN(er))throw new Error("Invalid argument passed to jsPDF.f2");return br(er,2)},kr=hr.__private__.f3=function(er){if(isNaN(er))throw new Error("Invalid argument passed to jsPDF.f3");return br(er,3)},xr=hr.scale=hr.__private__.scale=function(er){if(isNaN(er))throw new Error("Invalid argument passed to jsPDF.scale");return _r===mr.COMPAT?er*Wn:_r===mr.ADVANCED?er:void 0},Sr=function q(er){return _r===mr.COMPAT?ro()-er:_r===mr.ADVANCED?er:void 0},Cr=function R(er){return xr(Sr(er))};hr.__private__.setPrecision=hr.setPrecision=function(er){"number"==typeof parseInt(er,10)&&(tr=parseInt(er,10))};var Br,Er="00000000000000000000000000000000",Nr=hr.__private__.getFileId=function(){return Er},Lr=hr.__private__.setFileId=function(er){return Er=void 0!==er&&/^[a-fA-F0-9]{32}$/.test(er)?er.toUpperCase():Er.split("").map((function(){return"ABCDEF0123456789".charAt(Math.floor(16*Math.random()))})).join("")};hr.setFileId=function(er){return Lr(er),this},hr.getFileId=function(){return Nr()};var Pr=hr.__private__.convertDateToPDFDate=function(er){var tr=er.getTimezoneOffset(),rr=tr<0?"+":"-",nr=Math.floor(Math.abs(tr/60)),ar=Math.abs(tr%60),ir=[rr,Rr(nr),"'",Rr(ar),"'"].join("");return["D:",er.getFullYear(),Rr(er.getMonth()+1),Rr(er.getDate()),Rr(er.getHours()),Rr(er.getMinutes()),Rr(er.getSeconds()),ir].join("")},Tr=hr.__private__.convertPDFDateToDate=function(er){var tr=parseInt(er.substr(2,4),10),rr=parseInt(er.substr(6,2),10)-1,nr=parseInt(er.substr(8,2),10),ar=parseInt(er.substr(10,2),10),ir=parseInt(er.substr(12,2),10),or=parseInt(er.substr(14,2),10);return new Date(tr,rr,nr,ar,ir,or,0)},Fr=hr.__private__.setCreationDate=function(er){var tr;if(void 0===er&&(er=new Date),er instanceof Date)tr=Pr(er);else{if(!/^D:(20[0-2][0-9]|203[0-7]|19[7-9][0-9])(0[0-9]|1[0-2])([0-2][0-9]|3[0-1])(0[0-9]|1[0-9]|2[0-3])(0[0-9]|[1-5][0-9])(0[0-9]|[1-5][0-9])(\+0[0-9]|\+1[0-4]|-0[0-9]|-1[0-1])'(0[0-9]|[1-5][0-9])'?$/.test(er))throw new Error("Invalid argument passed to jsPDF.setCreationDate");tr=er}return Br=tr},Ur=hr.__private__.getCreationDate=function(er){var tr=Br;return"jsDate"===er&&(tr=Tr(Br)),tr};hr.setCreationDate=function(er){return Fr(er),this},hr.getCreationDate=function(er){return Ur(er)};var Ir,Rr=hr.__private__.padd2=function(er){return("0"+parseInt(er)).slice(-2)},Mr=hr.__private__.padd2Hex=function(er){return("00"+(er=er.toString())).substr(er.length)},Qr=0,Or=[],Dr=[],jr=0,Hr=[],Gr=[],Vr=!1,zr=Dr,Kr=function it(){Qr=0,jr=0,Dr=[],Or=[],Hr=[],ba=_a(),wa=_a()};hr.__private__.setCustomOutputDestination=function(er){Vr=!0,zr=er};var qr=function at(er){Vr||(zr=er)};hr.__private__.resetCustomOutputDestination=function(){Vr=!1,zr=Dr};var Wr=hr.__private__.out=function(er){return er=er.toString(),jr+=er.length+1,zr.push(er),zr},Xr=hr.__private__.write=function(er){return Wr(1===arguments.length?er.toString():Array.prototype.join.call(arguments," "))},Yr=hr.__private__.getArrayBuffer=function(er){for(var tr=er.length,rr=new ArrayBuffer(tr),nr=new Uint8Array(rr);tr--;)nr[tr]=er.charCodeAt(tr);return rr},Jr=[["Helvetica","helvetica","normal","WinAnsiEncoding"],["Helvetica-Bold","helvetica","bold","WinAnsiEncoding"],["Helvetica-Oblique","helvetica","italic","WinAnsiEncoding"],["Helvetica-BoldOblique","helvetica","bolditalic","WinAnsiEncoding"],["Courier","courier","normal","WinAnsiEncoding"],["Courier-Bold","courier","bold","WinAnsiEncoding"],["Courier-Oblique","courier","italic","WinAnsiEncoding"],["Courier-BoldOblique","courier","bolditalic","WinAnsiEncoding"],["Times-Roman","times","normal","WinAnsiEncoding"],["Times-Bold","times","bold","WinAnsiEncoding"],["Times-Italic","times","italic","WinAnsiEncoding"],["Times-BoldItalic","times","bolditalic","WinAnsiEncoding"],["ZapfDingbats","zapfdingbats","normal",null],["Symbol","symbol","normal",null]];hr.__private__.getStandardFonts=function(){return Jr};var $r=er.fontSize||16;hr.__private__.setFontSize=hr.setFontSize=function(er){return $r=_r===mr.ADVANCED?er/Wn:er,this};var Zr,Tn=hr.__private__.getFontSize=hr.getFontSize=function(){return _r===mr.COMPAT?$r:$r*Wn},Un=er.R2L||!1;hr.__private__.setR2L=hr.setR2L=function(er){return Un=er,this},hr.__private__.getR2L=hr.getR2L=function(){return Un};var Qn,Dn=hr.__private__.setZoomMode=function(er){if(/^\d*\.?\d*%$/.test(er))Zr=er;else if(isNaN(er)){if(-1===[void 0,null,"fullwidth","fullheight","fullpage","original"].indexOf(er))throw new Error('zoom must be Integer (e.g. 2), a percentage Value (e.g. 300%) or fullwidth, fullheight, fullpage, original. "'+er+'" is not recognized.');Zr=er}else Zr=parseInt(er,10)};hr.__private__.getZoomMode=function(){return Zr};var Hn,Gn=hr.__private__.setPageMode=function(er){if(-1==[void 0,null,"UseNone","UseOutlines","UseThumbs","FullScreen"].indexOf(er))throw new Error('Page mode must be one of UseNone, UseOutlines, UseThumbs, or FullScreen. "'+er+'" is not recognized.');Qn=er};hr.__private__.getPageMode=function(){return Qn};var Vn=hr.__private__.setLayoutMode=function(er){if(-1==[void 0,null,"continuous","single","twoleft","tworight","two"].indexOf(er))throw new Error('Layout mode must be one of continuous, single, twoleft, tworight. "'+er+'" is not recognized.');Hn=er};hr.__private__.getLayoutMode=function(){return Hn},hr.__private__.setDisplayMode=hr.setDisplayMode=function(er,tr,rr){return Dn(er),Vn(tr),Gn(rr),this};var zn={title:"",subject:"",author:"",keywords:"",creator:""};hr.__private__.getDocumentProperty=function(er){if(-1===Object.keys(zn).indexOf(er))throw new Error("Invalid argument passed to jsPDF.getDocumentProperty");return zn[er]},hr.__private__.getDocumentProperties=function(){return zn},hr.__private__.setDocumentProperties=hr.setProperties=hr.setDocumentProperties=function(er){for(var tr in zn)zn.hasOwnProperty(tr)&&er[tr]&&(zn[tr]=er[tr]);return this},hr.__private__.setDocumentProperty=function(er,tr){if(-1===Object.keys(zn).indexOf(er))throw new Error("Invalid arguments passed to jsPDF.setDocumentProperty");return zn[er]=tr};var Kn,Wn,Xn,Yn,Jn,$n={},Zn={},ea=[],ta={},ra={},na={},aa={},ia=null,oa=0,sa=[],la=new h(hr),ca=er.hotfixes||[],ua={},da={},ha=[],pa=function Dt(er,tr,rr,nr,ar,ir){if(!(this instanceof Dt))return new Dt(er,tr,rr,nr,ar,ir);isNaN(er)&&(er=1),isNaN(tr)&&(tr=0),isNaN(rr)&&(rr=0),isNaN(nr)&&(nr=1),isNaN(ar)&&(ar=0),isNaN(ir)&&(ir=0),this._matrix=[er,tr,rr,nr,ar,ir]};Object.defineProperty(pa.prototype,"sx",{get:function get(){return this._matrix[0]},set:function set(er){this._matrix[0]=er}}),Object.defineProperty(pa.prototype,"shy",{get:function get(){return this._matrix[1]},set:function set(er){this._matrix[1]=er}}),Object.defineProperty(pa.prototype,"shx",{get:function get(){return this._matrix[2]},set:function set(er){this._matrix[2]=er}}),Object.defineProperty(pa.prototype,"sy",{get:function get(){return this._matrix[3]},set:function set(er){this._matrix[3]=er}}),Object.defineProperty(pa.prototype,"tx",{get:function get(){return this._matrix[4]},set:function set(er){this._matrix[4]=er}}),Object.defineProperty(pa.prototype,"ty",{get:function get(){return this._matrix[5]},set:function set(er){this._matrix[5]=er}}),Object.defineProperty(pa.prototype,"a",{get:function get(){return this._matrix[0]},set:function set(er){this._matrix[0]=er}}),Object.defineProperty(pa.prototype,"b",{get:function get(){return this._matrix[1]},set:function set(er){this._matrix[1]=er}}),Object.defineProperty(pa.prototype,"c",{get:function get(){return this._matrix[2]},set:function set(er){this._matrix[2]=er}}),Object.defineProperty(pa.prototype,"d",{get:function get(){return this._matrix[3]},set:function set(er){this._matrix[3]=er}}),Object.defineProperty(pa.prototype,"e",{get:function get(){return this._matrix[4]},set:function set(er){this._matrix[4]=er}}),Object.defineProperty(pa.prototype,"f",{get:function get(){return this._matrix[5]},set:function set(er){this._matrix[5]=er}}),Object.defineProperty(pa.prototype,"rotation",{get:function get(){return Math.atan2(this.shx,this.sx)}}),Object.defineProperty(pa.prototype,"scaleX",{get:function get(){return this.decompose().scale.sx}}),Object.defineProperty(pa.prototype,"scaleY",{get:function get(){return this.decompose().scale.sy}}),Object.defineProperty(pa.prototype,"isIdentity",{get:function get(){return 1===this.sx&&0===this.shy&&0===this.shx&&1===this.sy&&0===this.tx&&0===this.ty}}),pa.prototype.join=function(er){return[this.sx,this.shy,this.shx,this.sy,this.tx,this.ty].map(vr).join(er)},pa.prototype.multiply=function(er){var tr=er.sx*this.sx+er.shy*this.shx,rr=er.sx*this.shy+er.shy*this.sy,nr=er.shx*this.sx+er.sy*this.shx,ar=er.shx*this.shy+er.sy*this.sy,ir=er.tx*this.sx+er.ty*this.shx+this.tx,or=er.tx*this.shy+er.ty*this.sy+this.ty;return new pa(tr,rr,nr,ar,ir,or)},pa.prototype.decompose=function(){var er=this.sx,tr=this.shy,rr=this.shx,nr=this.sy,ar=this.tx,ir=this.ty,or=Math.sqrt(er*er+tr*tr),sr=(er/=or)*rr+(tr/=or)*nr;rr-=er*sr,nr-=tr*sr;var lr=Math.sqrt(rr*rr+nr*nr);return sr/=lr,er*(nr/=lr)>16&255,nr=lr>>8&255,ar=255&lr}if(void 0===nr||void 0===ir&&rr===nr&&nr===ar)if("string"==typeof rr)tr=rr+" "+or[0];else switch(er.precision){case 2:tr=wr(rr/255)+" "+or[0];break;case 3:default:tr=kr(rr/255)+" "+or[0]}else if(void 0===ir||"object"==_typeof(ir)){if(ir&&!isNaN(ir.a)&&0===ir.a)return["1.","1.","1.",or[1]].join(" ");if("string"==typeof rr)tr=[rr,nr,ar,or[1]].join(" ");else switch(er.precision){case 2:tr=[wr(rr/255),wr(nr/255),wr(ar/255),or[1]].join(" ");break;default:case 3:tr=[kr(rr/255),kr(nr/255),kr(ar/255),or[1]].join(" ")}}else if("string"==typeof rr)tr=[rr,nr,ar,ir,or[2]].join(" ");else switch(er.precision){case 2:tr=[wr(rr),wr(nr),wr(ar),wr(ir),or[2]].join(" ");break;case 3:default:tr=[kr(rr),kr(nr),kr(ar),kr(ir),or[2]].join(" ")}return tr},Sa=hr.__private__.getFilters=function(){return or},Ca=hr.__private__.putStream=function(er){var tr=(er=er||{}).data||"",rr=er.filters||Sa(),nr=er.alreadyAppliedFilters||[],ar=er.addLength1||!1,ir=tr.length,or={};!0===rr&&(rr=["FlateEncode"]);var sr=er.additionalKeyValues||[],lr=(or=void 0!==g.API.processDataByFilters?g.API.processDataByFilters(tr,rr):{data:tr,reverseChain:[]}).reverseChain+(Array.isArray(nr)?nr.join(" "):nr.toString());if(0!==or.data.length&&(sr.push({key:"Length",value:or.data.length}),!0===ar&&sr.push({key:"Length1",value:ir})),0!=lr.length)if(lr.split("/").length-1==1)sr.push({key:"Filter",value:lr});else{sr.push({key:"Filter",value:"["+lr+"]"});for(var cr=0;cr>"),0!==or.data.length&&(Wr("stream"),Wr(or.data),Wr("endstream"))},Ba=hr.__private__.putPage=function(er){var tr=er.number,rr=er.data,nr=er.objId,ar=er.contentsObjId;va(nr,!0),Wr("<>"),Wr("endobj");var ir=rr.join("\n");return _r===mr.ADVANCED&&(ir+="\nQ"),va(ar,!0),Ca({data:ir,filters:Sa()}),Wr("endobj"),nr},Ea=hr.__private__.putPages=function(){var er,tr,rr=[];for(er=1;er<=oa;er++)sa[er].objId=_a(),sa[er].contentsObjId=_a();for(er=1;er<=oa;er++)rr.push(Ba({number:er,data:Gr[er],objId:sa[er].objId,contentsObjId:sa[er].contentsObjId,mediaBox:sa[er].mediaBox,cropBox:sa[er].cropBox,bleedBox:sa[er].bleedBox,trimBox:sa[er].trimBox,artBox:sa[er].artBox,userUnit:sa[er].userUnit,rootDictionaryObjId:ba,resourceDictionaryObjId:wa}));va(ba,!0),Wr("<>"),Wr("endobj"),la.publish("postPutPages")},Na=function ne(er){var tr=function e(er,tr){return-1!==er.indexOf(" ")?"("+$a(er,tr)+")":$a(er,tr)};la.publish("putFont",{font:er,out:Wr,newObject:ma,putStream:Ca,pdfEscapeWithNeededParanthesis:tr}),!0!==er.isAlreadyPutted&&(er.objectNumber=ma(),Wr("<<"),Wr("/Type /Font"),Wr("/BaseFont /"+tr(er.postScriptName)),Wr("/Subtype /Type1"),"string"==typeof er.encoding&&Wr("/Encoding /"+er.encoding),Wr("/FirstChar 32"),Wr("/LastChar 255"),Wr(">>"),Wr("endobj"))},La=function re(){for(var er in $n)$n.hasOwnProperty(er)&&(!1===ur||!0===ur&&dr.hasOwnProperty(er))&&Na($n[er])},Pa=function ie(er){er.objectNumber=ma();var tr=[];tr.push({key:"Type",value:"/XObject"}),tr.push({key:"Subtype",value:"/Form"}),tr.push({key:"BBox",value:"["+[vr(er.x),vr(er.y),vr(er.x+er.width),vr(er.y+er.height)].join(" ")+"]"}),tr.push({key:"Matrix",value:"["+er.matrix.toString()+"]"});var rr=er.pages[1].join("\n");Ca({data:rr,additionalKeyValues:tr}),Wr("endobj")},Ta=function ae(){for(var er in ua)ua.hasOwnProperty(er)&&Pa(ua[er])},Fa=function oe(er,tr){var rr,nr=[],ar=1/(tr-1);for(rr=0;rr<1;rr+=ar)nr.push(rr);if(nr.push(1),0!=er[0].offset){var ir={offset:0,color:er[0].color};er.unshift(ir)}if(1!=er[er.length-1].offset){var or={offset:1,color:er[er.length-1].color};er.push(or)}for(var sr="",lr=0,cr=0;crer[lr+1].offset;)lr++;var ur=er[lr].offset,dr=(rr-ur)/(er[lr+1].offset-ur),hr=er[lr].color,pr=er[lr+1].color;sr+=Mr(Math.round((1-dr)*hr[0]+dr*pr[0]).toString(16))+Mr(Math.round((1-dr)*hr[1]+dr*pr[1]).toString(16))+Mr(Math.round((1-dr)*hr[2]+dr*pr[2]).toString(16))}return sr.trim()},Ua=function se(er,tr){tr||(tr=21);var rr=ma(),nr=Fa(er.colors,tr),ar=[];ar.push({key:"FunctionType",value:"0"}),ar.push({key:"Domain",value:"[0.0 1.0]"}),ar.push({key:"Size",value:"["+tr+"]"}),ar.push({key:"BitsPerSample",value:"8"}),ar.push({key:"Range",value:"[0.0 1.0 0.0 1.0 0.0 1.0]"}),ar.push({key:"Decode",value:"[0.0 1.0 0.0 1.0 0.0 1.0]"}),Ca({data:nr,additionalKeyValues:ar,alreadyAppliedFilters:["/ASCIIHexDecode"]}),Wr("endobj"),er.objectNumber=ma(),Wr("<< /ShadingType "+er.type),Wr("/ColorSpace /DeviceRGB");var ir="/Coords ["+vr(parseFloat(er.coords[0]))+" "+vr(parseFloat(er.coords[1]))+" ";2===er.type?ir+=vr(parseFloat(er.coords[2]))+" "+vr(parseFloat(er.coords[3])):ir+=vr(parseFloat(er.coords[2]))+" "+vr(parseFloat(er.coords[3]))+" "+vr(parseFloat(er.coords[4]))+" "+vr(parseFloat(er.coords[5])),Wr(ir+="]"),er.matrix&&Wr("/Matrix ["+er.matrix.toString()+"]"),Wr("/Function "+rr+" 0 R"),Wr("/Extend [true true]"),Wr(">>"),Wr("endobj")},Ia=function ue(er,tr){var rr=_a(),nr=ma();tr.push({resourcesOid:rr,objectOid:nr}),er.objectNumber=nr;var ar=[];ar.push({key:"Type",value:"/Pattern"}),ar.push({key:"PatternType",value:"1"}),ar.push({key:"PaintType",value:"1"}),ar.push({key:"TilingType",value:"1"}),ar.push({key:"BBox",value:"["+er.boundingBox.map(vr).join(" ")+"]"}),ar.push({key:"XStep",value:vr(er.xStep)}),ar.push({key:"YStep",value:vr(er.yStep)}),ar.push({key:"Resources",value:rr+" 0 R"}),er.matrix&&ar.push({key:"Matrix",value:"["+er.matrix.toString()+"]"}),Ca({data:er.stream,additionalKeyValues:ar}),Wr("endobj")},Ra=function ce(er){var tr;for(tr in ta)ta.hasOwnProperty(tr)&&(ta[tr]instanceof d?Ua(ta[tr]):ta[tr]instanceof p&&Ia(ta[tr],er))},Ma=function he(er){for(var tr in er.objectNumber=ma(),Wr("<<"),er)switch(tr){case"opacity":Wr("/ca "+wr(er[tr]));break;case"stroke-opacity":Wr("/CA "+wr(er[tr]))}Wr(">>"),Wr("endobj")},Qa=function le(){var er;for(er in na)na.hasOwnProperty(er)&&Ma(na[er])},Oa=function fe(){for(var er in Wr("/XObject <<"),ua)ua.hasOwnProperty(er)&&ua[er].objectNumber>=0&&Wr("/"+er+" "+ua[er].objectNumber+" 0 R");la.publish("putXobjectDict"),Wr(">>")},Da=function de(){for(var er in Wr("/Font <<"),$n)$n.hasOwnProperty(er)&&(!1===ur||!0===ur&&dr.hasOwnProperty(er))&&Wr("/"+er+" "+$n[er].objectNumber+" 0 R");Wr(">>")},ja=function pe(){if(Object.keys(ta).length>0){for(var er in Wr("/Shading <<"),ta)ta.hasOwnProperty(er)&&ta[er]instanceof d&&ta[er].objectNumber>=0&&Wr("/"+er+" "+ta[er].objectNumber+" 0 R");la.publish("putShadingPatternDict"),Wr(">>")}},Ha=function ge(er){if(Object.keys(ta).length>0){for(var tr in Wr("/Pattern <<"),ta)ta.hasOwnProperty(tr)&&ta[tr]instanceof hr.TilingPattern&&ta[tr].objectNumber>=0&&ta[tr].objectNumber>")}},Ga=function me(){if(Object.keys(na).length>0){var er;for(er in Wr("/ExtGState <<"),na)na.hasOwnProperty(er)&&na[er].objectNumber>=0&&Wr("/"+er+" "+na[er].objectNumber+" 0 R");la.publish("putGStateDict"),Wr(">>")}},Va=function ve(er){va(er.resourcesOid,!0),Wr("<<"),Wr("/ProcSet [/PDF /Text /ImageB /ImageC /ImageI]"),Da(),ja(),Ha(er.objectOid),Ga(),Oa(),Wr(">>"),Wr("endobj")},za=function be(){var er=[];La(),Qa(),Ta(),Ra(er),la.publish("putResources"),er.forEach(Va),Va({resourcesOid:wa,objectOid:Number.MAX_SAFE_INTEGER}),la.publish("postPutResources")},Ka=function ye(){la.publish("putAdditionalObjects");for(var er=0;er>8&&(lr=!0);er=sr.join("")}for(rr=er.length;void 0===lr&&0!==rr;)er.charCodeAt(rr-1)>>8&&(lr=!0),rr--;if(!lr)return er;for(sr=tr.noBOM?[]:[254,255],rr=0,nr=er.length;rr>8)>>8)throw new Error("Character at position "+rr+" of string '"+er+"' exceeds 16bits. Cannot be encoded into UCS-2 BE");sr.push(ur),sr.push(cr-(ur<<8))}return String.fromCharCode.apply(void 0,sr)},$a=hr.__private__.pdfEscape=hr.pdfEscape=function(er,tr){return Ja(er,tr).replace(/\\/g,"\\\\").replace(/\(/g,"\\(").replace(/\)/g,"\\)")},Za=hr.__private__.beginPage=function(er){Gr[++oa]=[],sa[oa]={objId:0,contentsObjId:0,userUnit:Number(sr),artBox:null,bleedBox:null,cropBox:null,trimBox:null,mediaBox:{bottomLeftX:0,bottomLeftY:0,topRightX:Number(er[0]),topRightY:Number(er[1])}},ri(oa),qr(Gr[Ir])},ei=function Pe(er,tr){var nr,ir,or;switch(rr=tr||rr,"string"==typeof er&&(nr=gr(er.toLowerCase()),Array.isArray(nr)&&(ir=nr[0],or=nr[1])),Array.isArray(er)&&(ir=er[0]*Wn,or=er[1]*Wn),isNaN(ir)&&(ir=ar[0],or=ar[1]),(ir>14400||or>14400)&&(Bf.warn("A page in a PDF can not be wider or taller than 14400 userUnit. jsPDF limits the width/height to 14400"),ir=Math.min(14400,ir),or=Math.min(14400,or)),ar=[ir,or],rr.substr(0,1)){case"l":or>ir&&(ar=[or,ir]);break;case"p":ir>or&&(ar=[or,ir])}Za(ar),Pi(Li),Wr(Oi),0!==zi&&Wr(zi+" J"),0!==Ki&&Wr(Ki+" j"),la.publish("addPage",{pageNumber:oa})},ti=function ke(er){er>0&&er<=oa&&(Gr.splice(er,1),sa.splice(er,1),oa--,Ir>oa&&(Ir=oa),this.setPage(Ir))},ri=function Fe(er){er>0&&er<=oa&&(Ir=er)},ni=hr.__private__.getNumberOfPages=hr.getNumberOfPages=function(){return Gr.length-1},ai=function Ce(er,tr,rr){var nr,ar=void 0;return rr=rr||{},er=void 0!==er?er:$n[Kn].fontName,tr=void 0!==tr?tr:$n[Kn].fontStyle,nr=er.toLowerCase(),void 0!==Zn[nr]&&void 0!==Zn[nr][tr]?ar=Zn[nr][tr]:void 0!==Zn[er]&&void 0!==Zn[er][tr]?ar=Zn[er][tr]:!1===rr.disableWarning&&Bf.warn("Unable to look up font label for font '"+er+"', '"+tr+"'. Refer to getFontList() for available fonts."),ar||rr.noFallback||null==(ar=Zn.times[tr])&&(ar=Zn.times.normal),ar},ii=hr.__private__.putInfo=function(){for(var er in ma(),Wr("<<"),Wr("/Producer (jsPDF "+g.version+")"),zn)zn.hasOwnProperty(er)&&zn[er]&&Wr("/"+er.substr(0,1).toUpperCase()+er.substr(1)+" ("+$a(zn[er])+")");Wr("/CreationDate ("+Br+")"),Wr(">>"),Wr("endobj")},oi=hr.__private__.putCatalog=function(er){var tr=(er=er||{}).rootDictionaryObjId||ba;switch(ma(),Wr("<<"),Wr("/Type /Catalog"),Wr("/Pages "+tr+" 0 R"),Zr||(Zr="fullwidth"),Zr){case"fullwidth":Wr("/OpenAction [3 0 R /FitH null]");break;case"fullheight":Wr("/OpenAction [3 0 R /FitV null]");break;case"fullpage":Wr("/OpenAction [3 0 R /Fit]");break;case"original":Wr("/OpenAction [3 0 R /XYZ null null 1]");break;default:var rr=""+Zr;"%"===rr.substr(rr.length-1)&&(Zr=parseInt(Zr)/100),"number"==typeof Zr&&Wr("/OpenAction [3 0 R /XYZ null null "+wr(Zr)+"]")}switch(Hn||(Hn="continuous"),Hn){case"continuous":Wr("/PageLayout /OneColumn");break;case"single":Wr("/PageLayout /SinglePage");break;case"two":case"twoleft":Wr("/PageLayout /TwoColumnLeft");break;case"tworight":Wr("/PageLayout /TwoColumnRight")}Qn&&Wr("/PageMode /"+Qn),la.publish("putCatalog"),Wr(">>"),Wr("endobj")},si=hr.__private__.putTrailer=function(){Wr("trailer"),Wr("<<"),Wr("/Size "+(Qr+1)),Wr("/Root "+Qr+" 0 R"),Wr("/Info "+(Qr-1)+" 0 R"),Wr("/ID [ <"+Er+"> <"+Er+"> ]"),Wr(">>")},li=hr.__private__.putHeader=function(){Wr("%PDF-"+pr),Wr("%ºß¬à")},ci=hr.__private__.putXRef=function(){var er="0000000000";Wr("xref"),Wr("0 "+(Qr+1)),Wr("0000000000 65535 f ");for(var tr=1;tr<=Qr;tr++)"function"==typeof Or[tr]?Wr((er+Or[tr]()).slice(-10)+" 00000 n "):void 0!==Or[tr]?Wr((er+Or[tr]).slice(-10)+" 00000 n "):Wr("0000000000 00000 n ")},ui=hr.__private__.buildDocument=function(){Kr(),qr(Dr),la.publish("buildDocument"),li(),Ea(),Ka(),za(),ii(),oi();var er=jr;return ci(),si(),Wr("startxref"),Wr(""+er),Wr("%%EOF"),qr(Gr[Ir]),Dr.join("\n")},di=hr.__private__.getBlob=function(er){return new Blob([Yr(er)],{type:"application/pdf"})},hi=hr.output=hr.__private__.output=Ya((function(er,tr){switch("string"==typeof(tr=tr||{})?tr={filename:tr}:tr.filename=tr.filename||"generated.pdf",er){case void 0:return ui();case"save":hr.save(tr.filename);break;case"arraybuffer":return Yr(ui());case"blob":return di(ui());case"bloburi":case"bloburl":if(void 0!==Cf.URL&&"function"==typeof Cf.URL.createObjectURL)return Cf.URL&&Cf.URL.createObjectURL(di(ui()))||void 0;Bf.warn("bloburl is not supported by your system, because URL.createObjectURL is not supported by your browser.");break;case"datauristring":case"dataurlstring":var rr="",nr=ui();try{rr=Nf(nr)}catch(er){rr=Nf(unescape(encodeURIComponent(nr)))}return"data:application/pdf;filename="+tr.filename+";base64,"+rr;case"pdfobjectnewwindow":if("[object Window]"===Object.prototype.toString.call(Cf)){var ar='