From 92d4e56543bad4cc30f52516ea43af37f83bbc25 Mon Sep 17 00:00:00 2001 From: Stefan Goessner Date: Mon, 20 Jun 2016 19:38:32 +0200 Subject: [PATCH] Release 2.2 --- README.md | 13 +- api/README.md | 48 +-- .../catrom-quarter-works-unexpectedly.html | 83 ----- examples/catrom.html | 84 ----- examples/catrom.js | 31 -- examples/cr.html | 62 ---- examples/hs.html | 202 ++++++++--- examples/hs2.html | 110 ------ examples/ply_perf.html | 89 +++++ examples/spline.html | 23 ++ examples/use.html | 22 ++ g2.js | 340 ++++++++---------- g2.min.js | 2 +- g2.min.js.gz | Bin 4867 -> 4860 bytes 14 files changed, 478 insertions(+), 631 deletions(-) delete mode 100644 examples/catrom-quarter-works-unexpectedly.html delete mode 100644 examples/catrom.html delete mode 100644 examples/catrom.js delete mode 100644 examples/cr.html delete mode 100644 examples/hs2.html create mode 100644 examples/ply_perf.html create mode 100644 examples/spline.html create mode 100644 examples/use.html diff --git a/README.md b/README.md index 5b49712..8e3fb39 100644 --- a/README.md +++ b/README.md @@ -48,7 +48,7 @@ See the [API Reference](api/README.md) for details. ## GitCDN Use the link [https://gitcdn.xyz/repo/goessner/g2/master/g2.min.js](https://gitcdn.xyz/repo/goessner/g2/master/g2.min.js) -for getting the latest commit as a rqw file. +for getting the latest commit as a raw file. In HTML use ... ```html @@ -66,6 +66,17 @@ g2 is licensed under the terms of the MIT License. #Change Log +## 2.2.0 - 2016-06-20 +### Added + +* `g2.spline` performing 'centripetal Catmull-Rom' interpolation. + +### Modified + +* experimental `g2.State.hatch` removed. +* +* `g2.prototype.ply.iterator`default iterators modified for improved efficiency and working also with splines. + ## 2.1.1 - 2016-05-15 ### Modified diff --git a/api/README.md b/api/README.md index aaabdb1..54e93bf 100644 --- a/api/README.md +++ b/api/README.md @@ -38,20 +38,19 @@ Create a queue of 2D graphics commands. * [.cir(x, y, r, [style])](#g2+cir) ⇒ object * [.arc(x, y, r, [w], [dw], [style])](#g2+arc) ⇒ object * [.ply(parr, [mode], args)](#g2+ply) ⇒ object + * [.spline(p, [closed], style)](#g2+spline) ⇒ object * [.beg(args)](#g2+beg) ⇒ object * [.end()](#g2+end) ⇒ object * [.clr()](#g2+clr) ⇒ object * [.grid([color], [size])](#g2+grid) ⇒ object * [.use(g, args)](#g2+use) ⇒ object * [.style(args)](#g2+style) ⇒ object - * [.exe(ctx, [g])](#g2+exe) ⇒ object + * [.exe(ctx)](#g2+exe) ⇒ object * [.cpy(g)](#g2+cpy) ⇒ object * [.pntToUsr(x, y, [h])](#g2+pntToUsr) ⇒ object * [.vecToUsr(x, y)](#g2+vecToUsr) ⇒ object - * [.dump([space])](#g2+dump) ⇒ string * _static_ * [.symbol](#g2.symbol) : object - * [.transparent](#g2.transparent) : string ### g2.cartesian([on]) ⇒ object @@ -368,6 +367,24 @@ Draw polygon by points. Using iterator function for getting points from array by ```js g2().ply([100,50,120,60,80,70]), .ply([150,60],[170,70],[130,80]],true), .ply({x:160,y:70},{x:180,y:80},{x:140,y:90}],'split'), .exe(ctx); ``` + +### g2.spline(p, [closed], style) ⇒ object +Draw spline by points. Implementing a centripetal Catmull-Rom spline (thus avoiding cusps and self-intersections). Using iterator function for getting points from array by index. It must return current point object {x,y} or object {done:true}. Default iterator expects sequence of x/y-coordinates as a flat array [x,y,...], array of [[x,y],...] arrays or array of [{x,y},...] objects. + +**Kind**: instance method of [g2](#g2) +**Returns**: object - this +**See** + +- https://pomax.github.io/bezierinfo +- https://de.wikipedia.org/wiki/Kubisch_Hermitescher_Spline [Example](https://goessner.github.io/g2-svg/test/index.html#ply) + + +| Param | Type | Default | Description | +| --- | --- | --- | --- | +| p | array | | Array of points. | +| [closed] | bool | false | Closed spline. | +| style | object | | Style object. | + ### g2.beg(args) ⇒ object Begin subcommands. Current state is saved. Optionally apply transformation or style properties. [Example](https://goessner.github.io/g2-svg/test/index.html#beg-end) @@ -464,16 +481,15 @@ Apply new style properties. g = g2(); g2().style({ fs:"#58dbfa", // Set fill style. lw:10, // Set line width. ls:"#313942", // Set line style. lj:"round" }) // Set line join. .rec(10,10,300,100) .style({ lw:20, // Set line width. fs:"transparent", // Set fill style. sh:[10,0,10,"black"], // Set shadow x-translation. ld:[1,2] }) // Set line dash. .p().m(40,40).c(150,150,200,0,280,50).drw() .exe(ctx); ``` -### g2.exe(ctx, [g]) ⇒ object +### g2.exe(ctx) ⇒ object Execute g2 commands. It does so automatically and recursively with 'use'ed commands. **Kind**: instance method of [g2](#g2) **Returns**: object - g2 -| Param | Type | Default | Description | -| --- | --- | --- | --- | -| ctx | object | | Context. | -| [g] | object | this | g2 Object to execute. This argument is set by 'g2' and usually not by the user. | +| Param | Type | Description | +| --- | --- | --- | +| ctx | object | Context. | ### g2.cpy(g) ⇒ object @@ -519,17 +535,6 @@ Get user coordinates from device coordinates for unbound vector. | x | float | x-value in device units. | | y | float | y-value in device units. | - -### g2.dump([space]) ⇒ string -Debug helper method. Convert g2 command queue to JSON formatted string. - -**Kind**: instance method of [g2](#g2) -**Returns**: string - JSON string of command queue. - -| Param | Type | Description | -| --- | --- | --- | -| [space] | string | Number of spaces to use for indenting JSON output. | - ### g2.symbol : object Namespace for symbol objects. A symbol can be used by `use("symbolname")`. @@ -539,8 +544,3 @@ Namespace for symbol objects. A symbol can be used by `use("symbolname")`. ```js g2.symbol.cross = g2().lin(5,5,-5,-5).lin(5,-5,-5,5); // Define symbol. g2().use("cross",{x:100,y:100}) // Draw cross at position 100,100. .exe(ctx); // Render to context. ``` - -### g2.transparent : string -Current version. Using semantic versioning 'http://semver.org/'. - -**Kind**: static constant of [g2](#g2) diff --git a/examples/catrom-quarter-works-unexpectedly.html b/examples/catrom-quarter-works-unexpectedly.html deleted file mode 100644 index 278416c..0000000 --- a/examples/catrom-quarter-works-unexpectedly.html +++ /dev/null @@ -1,83 +0,0 @@ - - - - - g2 - pattern - - - - -

g2 - Catmull-Rom

- - - - - diff --git a/examples/catrom.html b/examples/catrom.html deleted file mode 100644 index 18fac83..0000000 --- a/examples/catrom.html +++ /dev/null @@ -1,84 +0,0 @@ - - - - - g2 - pattern - - - - -

g2 - Catmull-Rom

- - - - - diff --git a/examples/catrom.js b/examples/catrom.js deleted file mode 100644 index 6acbdb8..0000000 --- a/examples/catrom.js +++ /dev/null @@ -1,31 +0,0 @@ -// s. http://stackoverflow.com/questions/9489736/catmull-rom-curve-with-no-cusps-and-no-self-intersections - -// c0 + c1*t + c2*t*t + c3*t*t*t -function evalPoly3(c,t) { - return c[0] + c[1]*t + c[2]*t*t + c[3]*t*t*t; -} - -function toCubic(p0,p1,p2,p3) { - var d0 = Math.sqrt(Math.hypot(p1.x-p0.x,p1.y-p0.y)), - d1 = Math.sqrt(Math.hypot(p2.x-p1.x,p2.y-p1.y)), - d2 = Math.sqrt(Math.hypot(p3.x-p2.x,p3.y-p2.y)); - - // safety check for repeated points - if (d1 < 1e-4) d1 = 1.0; - if (d0 < 1e-4) d0 = d1; - if (d2 < 1e-4) d2 = d1; - - // s. https://de.wikipedia.org/wiki/Kubisch_Hermitescher_Spline - var tx1 = ((p1.x - p0.x) / d0 - (p2.x - p0.x) / (d0 + d1) + (p2.x - p1.x) / d1), - tx2 = ((p2.x - p1.x) / d1 - (p3.x - p1.x) / (d1 + d2) + (p3.x - p2.x) / d2), - ty1 = ((p1.y - p0.y) / d0 - (p2.y - p0.y) / (d0 + d1) + (p2.y - p1.y) / d1), - ty2 = ((p2.y - p1.y) / d1 - (p3.y - p1.y) / (d1 + d2) + (p3.y - p2.y) / d2); - - return [ { x:p1.x, y:p1.y, dx:tx1, dy:ty1 }, - { x:p2.x, y:p2.y, dx:tx2, dy:ty2 } ]; -} - -var p0 = {x:0,y:0}, p1 = {x:10,y:10}, p2 = {x:20,y:10}, p3 = {x:30,y:0}, - q = toCubic(p0,p1,p2,p3); - -console.log(q); diff --git a/examples/cr.html b/examples/cr.html deleted file mode 100644 index 8e3b5d1..0000000 --- a/examples/cr.html +++ /dev/null @@ -1,62 +0,0 @@ - - - - Catmull-Rom - - - -

Catmull-Rom

- - - - - \ No newline at end of file diff --git a/examples/hs.html b/examples/hs.html index 4f51158..17365b8 100644 --- a/examples/hs.html +++ b/examples/hs.html @@ -7,64 +7,166 @@ -

Hermite-Spline

- - - + \ No newline at end of file diff --git a/examples/hs2.html b/examples/hs2.html deleted file mode 100644 index 9426758..0000000 --- a/examples/hs2.html +++ /dev/null @@ -1,110 +0,0 @@ - - - - Hermite-Spline - - - -

Hermite-Spline

- - - - - \ No newline at end of file diff --git a/examples/ply_perf.html b/examples/ply_perf.html new file mode 100644 index 0000000..0d3a9fc --- /dev/null +++ b/examples/ply_perf.html @@ -0,0 +1,89 @@ + + + + +g2 vs Canvas + + + + +

g2 vs Canvas

+ +

+ + + + + + + \ No newline at end of file diff --git a/examples/spline.html b/examples/spline.html new file mode 100644 index 0000000..2fc96f1 --- /dev/null +++ b/examples/spline.html @@ -0,0 +1,23 @@ + + + + + g2 - spline + + + + +

g2 - spline

+ + + + + diff --git a/examples/use.html b/examples/use.html new file mode 100644 index 0000000..66971bd --- /dev/null +++ b/examples/use.html @@ -0,0 +1,22 @@ + + + + + wiki - use + + + +

wiki - use

+ + + + + diff --git a/g2.js b/g2.js index ab02f55..c8d1f6b 100644 --- a/g2.js +++ b/g2.js @@ -270,11 +270,11 @@ g2.prototype.z = function z() { * @returns {object} g2 */ g2.prototype.stroke = function stroke(style,d) { - var args = (style === undefined && d === undefined) ? [] // no args + var args = (style === undefined && d === undefined) ? false // no args : (typeof style === "string") ? [null,style] // svg path string as single argument : (typeof style === "object" && !d) ? [style] // style object as single argument : [style,d]; // both arguments - return this.addCmd({c:stroke,a:args}); + return this.addCmd(args?{c:stroke,a:args}:{c:stroke}); }; /** @@ -286,11 +286,11 @@ g2.prototype.stroke = function stroke(style,d) { * @returns {object} g2 */ g2.prototype.fill = function fill(style,d) { - var args = (style === undefined && d === undefined) ? [] // no args + var args = (style === undefined && d === undefined) ? false // no args : (typeof style === "string") ? [null,style] // svg path string as single argument : (typeof style === "object" && !d) ? [style] // style object as single argument : [style,d]; // both arguments - return this.addCmd({c:fill,a:args}); + return this.addCmd(args?{c:fill,a:args}:{c:fill}); }; /** @@ -450,22 +450,80 @@ g2.prototype.ply = function ply(pts,mode,args) { this.addCmd({c:ply,a:[pts,mode,itr,args]}); return this; }; - -// predefined polygon point iterators +// predefined spline point iterators g2.prototype.ply.iterators = { - "x,y": function(arr,i) { return i < arr.length/2 ? {x:arr[2*i],y:arr[2*i+1]} : {done:true,count:arr.length/2}; }, - "[x,y]": function(arr,i) { return i < arr.length ? {x:arr[i][0],y:arr[i][1]} : {done:true,count:arr.length}; }, - "{x,y}": function(arr,i) { return i < arr.length ? arr[i] : {done:true,count:arr.length}; } + "x,y": function(pts) { function pitr(i) { return {x:pts[2*i],y:pts[2*i+1]}; }; pitr.len = pts.length/2; return pitr; }, + "[x,y]": function(pts) { function pitr(i) { return {x:pts[i][0],y:pts[i][1]}; }; pitr.len = pts.length; return pitr; }, + "{x,y}": function(pts) { function pitr(i) { return pts[i]; }; pitr.len = pts.length; return pitr; } }; -g2.prototype.ply.itrOf = function itrOf(pts,args) { +g2.prototype.ply.itrOf = function(pts,args) { return !(pts && pts.length) ? undefined - : args && typeof args.itr === "function" ? args.itr - : typeof pts[0] === "number" ? g2.prototype.ply.iterators["x,y"] - : Array.isArray(pts[0]) && pts[0].length >= 2 ? g2.prototype.ply.iterators["[x,y]"] - : typeof pts[0] === "object" && "x" in pts[0] && "y" in pts[0] ? g2.prototype.ply.iterators["{x,y}"] + : args && typeof args.itr === "function" ? args.itr(pts) + : typeof pts[0] === "number" ? g2.prototype.ply.iterators["x,y"](pts) + : Array.isArray(pts[0]) && pts[0].length >= 2 ? g2.prototype.ply.iterators["[x,y]"](pts) + : typeof pts[0] === "object" && "x" in pts[0] && "y" in pts[0] ? g2.prototype.ply.iterators["{x,y}"](pts) : undefined; }; +/** + * Draw spline by points. + * Implementing a centripetal Catmull-Rom spline (thus avoiding cusps and self-intersections). + * Using iterator function for getting points from array by index. + * It must return current point object {x,y} or object {done:true}. + * Default iterator expects sequence of x/y-coordinates as a flat array [x,y,...], + * array of [[x,y],...] arrays or array of [{x,y},...] objects. + * @see https://pomax.github.io/bezierinfo + * @see https://de.wikipedia.org/wiki/Kubisch_Hermitescher_Spline + * [Example](https://goessner.github.io/g2-svg/test/index.html#ply) + * @method + * @returns {object} this + * @param {array} p Array of points. + * @param {bool} [closed = false] Closed spline. + * @param {object} style Style object. + */ +g2.prototype.spline = function spline(p,closed,style) { + var pi = g2.prototype.ply.itrOf(p,style); // points iterator ... + if (pi) { + var b = [], i, n = pi.len, + p1, p2, p3, p4, d1, d2, d3, d1d2, d2d3, scl2, scl3, den2, den3; + + for (var i=0; i < (closed ? n : n-1); i++) { + if (i === 0) { + p1 = closed ? pi(n-1) : {x:2*pi(0).x-pi(1).x, y:2*pi(0).y-pi(1).y}; + p2 = pi(0); + p3 = pi(1); + p4 = n === 2 ? (closed ? pi(0) : {x:2*pi(1).x-pi(0).x, y:2*pi(1).y-pi(0).y}) : pi(2); + d1 = Math.max(Math.hypot(p2.x-p1.x,p2.y-p1.y),Number.EPSILON); // don't allow .. + d2 = Math.max(Math.hypot(p3.x-p2.x,p3.y-p2.y),Number.EPSILON); // point distances .. + } + else { + p1 = p2; + p2 = p3; + p3 = p4; + p4 = (i === n-2) ? (closed ? pi(0) : {x:2*pi(n-1).x-pi(n-2).x, y:2*pi(n-1).y-pi(n-2).y}) + : (i === n-1) ? pi(1) + : pi(i+2); + d1 = d2; + d2 = d3; + } + d3 = Math.max(Math.hypot(p4.x-p3.x,p4.y-p3.y),Number.EPSILON); + d1d2 = Math.sqrt(d1*d2), d2d3 = Math.sqrt(d2*d3), + scl2 = 2*d1 + 3*d1d2 + d2, + scl3 = 2*d3 + 3*d2d3 + d2, + den2 = 3*(d1 + d1d2), + den3 = 3*(d3 + d2d3); + b.push({ x: p2.x, y: p2.y, + x1: (-d2*p1.x + scl2*p2.x + d1*p3.x)/den2, + y1: (-d2*p1.y + scl2*p2.y + d1*p3.y)/den2, + x2: (-d2*p4.x + scl3*p3.x + d3*p2.x)/den3, + y2: (-d2*p4.y + scl3*p3.y + d3*p2.y)/den3 }); + } + b.push(closed ? {x:pi(0).x,y:pi(0).y} : {x:pi(n-1).x,y:pi(n-1).y}); + this.addCmd({c:spline,a:[b,closed,style]}); + } + return this; +} + /** * Begin subcommands. Current state is saved. * Optionally apply transformation or style properties. @@ -628,27 +686,21 @@ g2.prototype.style = function style(args) { * @method * @returns {object} g2 * @param {object} ctx Context. - * @param {object} [g=this] g2 Object to execute. This argument is set by 'g2' and usually not by the user. */ -g2.prototype.exe = function exe(ctx,g) { - var ifc = g2.ifcof(ctx); - if (ifc) { - var cmds = (g || this).cmds; - if (this.state && this.state.loading) { // give images a chance to complete loading .. - requestAnimationFrame(exe.bind(this,ctx,g)); // .. so wait a while .. - } - else if (ctx && cmds) { - var context = g2.context[ifc](ctx), gstate = g && g.state; - exe.pre[ifc].call(context,this); - if (g) // external g2 in use .. copy state - g.state = this.state; - for (var i=0,n=cmds.length,cmd; i < n; i++) // invoke the command queue - if ((cmd=cmds[this.curIdx = i]).c[ifc]) - cmd.c[ifc].apply(context,cmd.a); // save current command index - if (g) // external g2 in use .. restore state - g.state = gstate; - exe.post[ifc].call(context,this); - } +g2.prototype.exe = function exe(ctx) { + var state = this.state; + if (state.loading) // give images a chance to complete loading .. + requestAnimationFrame(exe.bind(this,ctx)); // .. so wait a while .. + else if (ctx) { + var context, ifc, cmds = this.cmds; + state.pre(ctx); + context = state.ctx; + ifc = state.ifc; + exe.pre[ifc].call(context,this); + for (var i=0,n=cmds.length,cmd; i < n; i++) // invoke the command queue + (cmd=cmds[this.curIdx = i]).c[ifc].apply(context,cmd.a); + exe.post[ifc].call(context,this); + state.post(); } return this; }; @@ -741,62 +793,11 @@ g2.prototype.vecToUsr = function vecToUsr(x,y) { : {x:x/trf.scl, y: y/trf.scl}; }; -/** - * Debug helper method. - * Convert g2 command queue to JSON formatted string. - * @param {string} [space] Number of spaces to use for indenting JSON output. - * @return {string} JSON string of command queue. - */ -g2.prototype.dump = function(space) { - function trace(obj) { - var out = [],o,cmd,a,c,args; - for (var i=0, n=obj.cmds.length; i < n; i++) { - args = []; - cmd = obj.cmds[i]; - a = cmd.a; - for (var j=0,m=a && a.length || 0; j < m; j++) { - if (typeof a[j] === "object" && a[j] instanceof g2) { - if (a[j] !== obj) args.push(trace(a[j])); - } - else if (a[j] !== undefined) - args.push(a[j]); - } - c = /\W*function\s+([\w\$]+)\(/.exec(cmd.c.toString())[1]; - if (args.length) { - o = {}; - o[c] = args; - } - else - o = c; - out.push(o); - } - return out; - } - return JSON.stringify(trace(this), undefined, space); -}; - // === g2 statics ==== -/** - * Current version. - * Using semantic versioning 'http://semver.org/'. - * @type {string} - * @const - */ g2.transparent = "rgba(0, 0, 0, 0)"; g2.exeStack = 0; g2.context = Object.create(null); // object holding functions getting context objects (if supported!) g2.ifc = Object.create(null); // object holding interface strings .. -/** - * Get interface string (i.e. 'svg') from graphics context. - * @private - */ -g2.ifcof = function(ctx) { - for (var ifc in g2.ifc) { - if (g2.ifc[ifc](ctx)) - return ifc; - } - return false; -} /** * State stack management class. @@ -813,7 +814,13 @@ g2.State = { this.loadHdl = []; // .. or else .. }, // pre / post command execution ... - pre: function(ctx) { this.ifc = g2.ifcof(ctx); this.ctx = g2.context[this.ifc](ctx); this.stack = [{}]; this._current = {}; }, + pre: function(ctx) { + for (var ifc in g2.ifc) + if (g2.ifc[ifc](ctx)) + this.ctx = g2.context[this.ifc = ifc](ctx); + this.stack = [{}]; + this._current = {}; + }, post: function() { delete this.ctx; delete this.ifc; }, // manage style properties ... @@ -825,10 +832,11 @@ g2.State = { }, add: function(args) { var ifcState = g2.State[this.ifc], m2, val, trf = {}; +// console.log(args) for (var m in args) { val = args[m]; - if (typeof val === "string" && val[0] === "@") - val = this.get(val.substr(1)); + if (typeof val === "string" && val[0] === "@" && !(val = this.get(val.substr(1)))) // simply cancel referencing with unknown attribute name ... + break; if (m === "x" || m === "y" || m === "w" || m === "scl") // transform .. trf[m] = val; else if (!(m in this._current) || val !== this._current[m]) { @@ -885,7 +893,6 @@ g2.State = { lc: "butt", // lineCap lj: "miter", // lineJoin lwnosc: false, // lineWidth nonscalable .. -// lm: "normal", // linemode .. "normal" or 'jitter' ml: 10, // miterLimit sh: [0,0,0,g2.transparent], // shadow foc: "#000", // fontColor @@ -908,37 +915,30 @@ g2.State = { */ g2.symbol = Object.create(null); // {}; -g2.symbolNameOf = function(g) { - for (var m in g2.symbol) - if (g2.symbol[m] === g) - return m; - return false; -} - // insert in browser environment only !!! if (typeof CanvasRenderingContext2D !== "undefined") { // use shortcut 'c2d' g2.ifc.c2d = function(ctx) { return ctx instanceof CanvasRenderingContext2D; } g2.context.c2d = function(ctx) { return ctx; } -g2.prototype.exe.pre.c2d = function(owner) { // owner g2 object ... - if (g2.exeStack++ === 0) { // outermost g2 ... - var state = owner.state, t = state.trf; // initial transform (zoom, pan ...) - this.g2 = owner; - this.fillStyle = g2.transparent; - this.lineWidth = 1; - this.strokeStyle = "#000"; - this.setLineDash([]); - this.font = state.cssFont; +g2.prototype.exe.pre.c2d = function(g) { // using g2 object .. + if (!this.g2ified) { // first time call using this canvas context .. + this.fillStyle = g2.transparent; // style ... + this.font = g.state.cssFont; + this.save(); // intentionally no corrsponding restore .. + this.g2ified = true; + } + + if (g2.exeStack++ === 0) { // outermost g2 ... + var state = (this.g2state = g.state), t = state.trf; // initial transform (zoom, pan ...) this.setTransform(t.scl,0,0,state.cartesian?-t.scl:t.scl,t.x+0.5,(state.cartesian?this.canvas.height-t.y:t.y)+0.5); - state.pre(this); + this.save(); } }; g2.prototype.exe.post.c2d = function() { if (--g2.exeStack === 0) { - this.g2.state.post(); - this.fillStyle = "#000000"; - delete this.g2; + delete this.g2state; + this.restore(); } }; g2.prototype.p.c2d = CanvasRenderingContext2D.prototype.beginPath; @@ -956,26 +956,26 @@ g2.prototype.a.c2d = CanvasRenderingContext2D.prototype.arc; g2.prototype.z.c2d = CanvasRenderingContext2D.prototype.closePath; g2.prototype.stroke.c2d = function stroke_c2d(style,d) { - if (style) { this.save(); this.g2.state.save().add(style); } + if (style) { this.save(); this.g2state.save().add(style); } if (d && typeof Path2D !== "undefined") this.stroke(new Path2D(d)); else this.stroke(); - if (style) { this.g2.state.restore(); this.restore(); } + if (style) { this.g2state.restore(); this.restore(); } }; g2.prototype.fill.c2d = function fill_c2d(style,d) { - if (style) { this.save();this.g2.state.save().add(style); } + if (style) { this.save();this.g2state.save().add(style); } if (d && typeof Path2D !== "undefined") this.fill(new Path2D(d)); else this.fill(); - if (style) { this.g2.state.restore(); this.restore(); } + if (style) { this.g2state.restore(); this.restore(); } }; g2.prototype.drw.c2d = function drw_c2d(style,d) { var p2d = d && typeof Path2D !== "undefined" ? new Path2D(d) : false; - if (style) { this.save();this.g2.state.save().add(style); } + if (style) { this.save();this.g2state.save().add(style); } p2d ? this.fill(p2d) : this.fill(); if (this.fillStyle !== g2.transparent && this.shadowColor !== g2.transparent) { var tmp = this.shadowColor; // avoid stroke shadow when filled ... @@ -985,11 +985,11 @@ g2.prototype.drw.c2d = function drw_c2d(style,d) { } else p2d ? this.stroke(p2d) : this.stroke(); - if (style) { this.g2.state.restore(); this.restore(); } + if (style) { this.g2state.restore(); this.restore(); } }; g2.prototype.txt.c2d = function txt_c2d(s,x,y,w,style) { - var state = this.g2.state; + var state = this.g2state; this.save(); if (style) state.save().add(style); @@ -1011,7 +1011,7 @@ g2.prototype.txt.c2d = function txt_c2d(s,x,y,w,style) { }; g2.prototype.img.c2d = function img_c2d(img,x,y,b,h,xoff,yoff,dx,dy) { - var cartesian = this.g2.state.cartesian; + var cartesian = this.g2state.cartesian; b = b || img && img.width; h = h || img && img.height; if (cartesian) { this.scale(1,-1); y = -y-h; } @@ -1023,78 +1023,71 @@ g2.prototype.img.c2d = function img_c2d(img,x,y,b,h,xoff,yoff,dx,dy) { }; g2.prototype.lin.c2d = function lin_c2d(x1,y1,x2,y2,style) { - if (style) { this.save();this.g2.state.save().add(style); } + if (style) { this.save();this.g2state.save().add(style); } this.beginPath(); this.moveTo(x1,y1); this.lineTo(x2,y2); this.stroke(); - if (style) { this.g2.state.restore(); this.restore(); } + if (style) { this.g2state.restore(); this.restore(); } }; g2.prototype.rec.c2d = function rec_c2d(x,y,b,h,style) { - if (style) { this.save();this.g2.state.save().add(style); } + if (style) { this.save();this.g2state.save().add(style); } this.beginPath(); this.rect(x,y,b,h); g2.prototype.drw.c2d.call(this); - if (style) { this.g2.state.restore(); this.restore(); } + if (style) { this.g2state.restore(); this.restore(); } }; g2.prototype.cir.c2d = function cir_c2d(x,y,r,style) { - if (style) { this.save();this.g2.state.save().add(style); } + if (style) { this.save();this.g2state.save().add(style); } this.beginPath(); this.arc(x,y,r,0,Math.PI*2,true); g2.prototype.drw.c2d.call(this); - if (style) { this.g2.state.restore(); this.restore(); } + if (style) { this.g2state.restore(); this.restore(); } }; g2.prototype.arc.c2d = function arc_c2d(x,y,r,w,dw,style) { - if (style) { this.save();this.g2.state.save().add(style); } + if (style) { this.save();this.g2state.save().add(style); } this.beginPath(); this.arc(x,y,r,w,w+dw,dw<0); g2.prototype.drw.c2d.call(this); - if (style) { this.g2.state.restore(); this.restore(); } + if (style) { this.g2state.restore(); this.restore(); } }; -g2.prototype.ply.c2d = function ply_c2d(parr,mode,itr,style) { +g2.prototype.ply.c2d = function ply_c2d(pts,mode,pi,style) { var p, i = 0, split = mode === "split"; - p = itr(parr,i++); - if (!p.done) { // draw polygon .. - this.beginPath(); - this.moveTo(p.x,p.y); - while (!(p = itr(parr,i++)).done) { - if (split && i%2) this.moveTo(p.x,p.y); - else this.lineTo(p.x,p.y); - } - if (mode && !split) // closed then .. - this.closePath(); + this.beginPath(); + this.moveTo((p=pi(0)).x,p.y); + for (i=1; i < pi.len; i++) { + p = pi(i); + if (split && i%2) this.moveTo(p.x,p.y); + else this.lineTo(p.x,p.y); } + if (mode && !split) // closed then .. + this.closePath(); + g2.prototype.drw.c2d.call(this,style); return i-1; // number of points .. }; -g2.prototype.ply.c2d = function ply_c2d(parr,mode,itr,style) { - var p, i = 0, split = mode === "split"; - p = itr(parr,i++); - if (!p.done) { // draw polygon .. - this.beginPath(); - this.moveTo(p.x,p.y); - while (!(p = itr(parr,i++)).done) { - if (split && i%2) this.moveTo(p.x,p.y); - else this.lineTo(p.x,p.y); - } - if (mode && !split) // closed then .. - this.closePath(); - } + +g2.prototype.spline.c2d = function spline_c2d(b,closed,style) { + this.beginPath(); + this.moveTo(b[0].x,b[0].y); + for (var i=0, n=b.length; i < n-1; i++) + this.bezierCurveTo(b[i].x1,b[i].y1,b[i].x2,b[i].y2,b[i+1].x,b[i+1].y); + if (closed) + this.closePath(); g2.prototype.drw.c2d.call(this,style); - return i-1; // number of points .. }; g2.prototype.beg.c2d = function beg_c2d(args) { this.save(); - this.g2.state.save().add(args); + this.g2state.save().add(args); }; g2.prototype.end.c2d = function end_c2d() { - this.g2.state.restore(); + this.g2state.restore(); this.restore(); }; @@ -1106,7 +1099,7 @@ g2.prototype.clr.c2d = function clr_c2d() { }; g2.prototype.grid.c2d = function grid_c2d(color,size) { - var state = this.g2.state, trf = state.trf0, + var state = this.g2state, trf = state.trf0, b = this.canvas.width, h = this.canvas.height, sz = size || g2.prototype.grid.getSize(state,trf.scl), xoff = trf.x ? trf.x%sz-sz : 0, yoff = trf.y ? trf.y%sz-sz : 0; @@ -1124,21 +1117,23 @@ g2.prototype.grid.c2d = function grid_c2d(color,size) { }; g2.prototype.use.c2d = function use_c2d(g,args) { - var owner = this.g2; + var state = this.g2state, gstate = g.state; this.save(); - owner.state.save().add(args); - owner.exe(this,g); - owner.state.restore(); + state.save().add(args); + g.state = state; + g.exe(this); + g.state = gstate; + state.restore(); this.restore(); }; g2.prototype.style.c2d = function style_c2d(args) { - this.g2.state.add(args); + this.g2state.add(args); }; g2.State.c2d = { - "fs": function(val) { this.fillStyle = g2.State.c2d.texture.call(this,val); }, - "ls": function(val) { this.strokeStyle = g2.State.c2d.texture.call(this,val); }, + "fs": function(val) { this.fillStyle = val === "transparent" ? g2.transparent : val; }, + "ls": function(val) { this.strokeStyle = val === "transparent" ? g2.transparent : val; }, "lw": function(val,state) { this.lineWidth = val/(state.get("lwnosc") ? state.trf.scl : 1); }, "lc": function(val) { this.lineCap = val; }, "lj": function(val) { this.lineJoin = val; }, @@ -1182,14 +1177,6 @@ g2.State.c2d = { if (scl !== 1) g2.State.c2d.lwscale.call(this, val ? 1/scl : scl) }, - // helper functions .. no styling or transformation attributes .. ! - // color, gradient or pattern ... - texture: function texture(val) { - return val.indexof && ( // must be string - val.indexOf("hatch(") === 0 ? g2.State.c2d.hatch.call(this,val.substring(6,val.indexOf(")",7)).split(",")) - : val === "transparent" ? g2.transparent - : val) || val; - }, // linewidth dependent scaling helper function ... lwscale: function(scl) { var ld = this.getLineDash(); @@ -1201,23 +1188,6 @@ g2.State.c2d = { this.setLineDash(ld); } }, - hatch: function hatch(val) { - var ctx = document.createElement('canvas').getContext('2d'), - sz = +val[3] || 10, sz2 = (sz+1)*0.5; - ctx.canvas.width = ctx.canvas.height = sz; - ctx.fillStyle = val[1] || "white"; - ctx.fillRect(0,0,sz,sz); - ctx.strokeStyle = val[0] || "black"; - ctx.lineWidth = +val[2] || 1; - ctx.lineCap = "square"; - ctx.beginPath(); - ctx.moveTo(sz2,0.5); - ctx.lineTo(sz+0.5,sz2); - ctx.moveTo(0.5,sz2); - ctx.lineTo(sz2,sz+0.5); - ctx.stroke(); - return ctx.createPattern(ctx.canvas,'repeat'); - } }; } // end of typeof CanvasRenderingContext2D !!! diff --git a/g2.min.js b/g2.min.js index 25a152d..c2f526d 100644 --- a/g2.min.js +++ b/g2.min.js @@ -4,4 +4,4 @@ * @link https://github.com/goessner/g2 * */ -function g2(){if(this instanceof g2){if(arguments)Object.assign(this,arguments);this.cmds=[];this.curIdx=false;return this}else return g2.apply(Object.create(g2.prototype),arguments)}g2.prototype.addCmd=function(t){this.cmds.push("proto"in t.c?Object.assign(Object.create(t.c.proto),{g2:this},t):t);return this};Object.defineProperty(g2.prototype,"curCmd",{get:function(){return this.curIdx!==false?this.cmds[this.curIdx]:null}});Object.defineProperty(g2.prototype,"state",{get:function(){return this._state||(this._state=g2.State.create(this))}});g2.prototype.cartesian=function t(e){this.state.cartesian=e!==false;return this};g2.prototype.pan=function e(t,i){this.state.trf0.x+=t;this.state.trf0.y+=i;return this};g2.prototype.zoom=function i(t,e,s){this.state.trf0.x=(1-t)*(e||0)+t*this.state.trf0.x;this.state.trf0.y=(1-t)*(s||0)+t*this.state.trf0.y;this.state.trf0.scl*=t;return this};g2.prototype.view=function s(t,e,i){this.state.trf0.x=t;this.state.trf0.y=e;this.state.trf0.scl=i;return this};g2.prototype.del=function r(){this.cmds.length=0;return this};g2.prototype._curPnt=function(){var t=this.cmds.length&&this.cmds[this.cmds.length-1]||false;return t&&(t.cp||t.a)};g2.prototype.p=function n(){return this.addCmd({c:n})};g2.prototype.m=function o(t,e){return this.addCmd({c:o,a:[t,e]})};g2.prototype.l=function a(t,e){return this.addCmd({c:a,a:[t,e]})};g2.prototype.q=function c(t,e,i,s){return this.addCmd({c:c,a:[t,e,i,s],cp:[i,s]})};g2.prototype.c=function h(t,e,i,s,r,n){return this.addCmd({c:h,a:[t,e,i,s,r,n],cp:[r,n]})};g2.prototype.a=function f(t,e,i){var s=this._curPnt(),r=2*Math.PI;if(s&&(t>Number.EPSILON&&t-r)){var n=e-s[0],o=i-s[1],a=Math.tan(t/2),c=n/2-o/a/2,h=o/2+n/a/2,d=Math.atan2(-h,-c);return this.addCmd({c:f,a:[s[0]+c,s[1]+h,Math.hypot(c,h),d,d+t,t<0],cp:[e,i]})}else return this.addCmd({c:g2.prototype.l,a:[e,i]})};g2.prototype.z=function d(){return this.addCmd({c:d})};g2.prototype.stroke=function p(t,e){var i=t===undefined&&e===undefined?[]:typeof t==="string"?[null,t]:typeof t==="object"&&!e?[t]:[t,e];return this.addCmd({c:p,a:i})};g2.prototype.fill=function l(t,e){var i=t===undefined&&e===undefined?[]:typeof t==="string"?[null,t]:typeof t==="object"&&!e?[t]:[t,e];return this.addCmd({c:l,a:i})};g2.prototype.drw=function u(t,e){var i=t===undefined&&e===undefined?[]:typeof t==="string"?[null,t]:typeof t==="object"&&!e?[t]:[t,e];return this.addCmd({c:u,a:i})};g2.prototype.txt=function g(t,e,i,s,r){return this.addCmd({c:g,a:[t,e||0,i||0,s||0,r]})};g2.prototype.img=function y(t,e,i,s,r,n,o,a,c){var h=new Image,f=this.state;f.loading++;h.onload=function d(){f.loaded()};h.onerror=function(){h.src=g2.prototype.img.broken};h.src=t;return this.addCmd({c:y,a:[h,e+.5||0,i+.5||0,s,r,n,o,a,c]})};g2.prototype.img.broken="data:image/gif;base64,R0lGODlhHgAeAKIAAAAAmWZmmZnM/////8zMzGZmZgAAAAAAACwAAAAAHgAeAEADimi63P5ryAmEqHfqPRWfRQF+nEeeqImum0oJQxUThGaQ7hSs95ezvB4Q+BvihBSAclk6fgKiAkE0kE6RNqwkUBtMa1OpVlI0lsbmFjrdWbMH5Tdcu6wbf7J8YM9H4y0YAE0+dHVKIV0Efm5VGiEpY1A0UVMSBYtPGl1eNZhnEBGEck6jZ6WfoKmgCQA7";g2.prototype.lin=function m(t,e,i,s,r){return this.addCmd({c:m,a:[t,e,i,s,r]})};g2.prototype.rec=function v(t,e,i,s,r){return this.addCmd({c:v,a:[t,e,i,s,r]})};g2.prototype.cir=function x(t,e,i,s){return this.addCmd({c:x,a:[t,e,i,s]})};g2.prototype.arc=function b(t,e,i,s,r,n){return this.addCmd({c:b,a:[t,e,i,s||0,r||2*Math.PI,n]})};g2.prototype.ply=function C(t,e,i){var s=C.itrOf(t,i);if(s)this.addCmd({c:C,a:[t,e,s,i]});return this};g2.prototype.ply.iterators={"x,y":function(t,e){return e=2?g2.prototype.ply.iterators["[x,y]"]:typeof t[0]==="object"&&"x"in t[0]&&"y"in t[0]?g2.prototype.ply.iterators["{x,y}"]:undefined};g2.prototype.beg=function j(t){return this.addCmd(t?{c:j,a:[t],open:true}:{c:j,open:true})};g2.prototype.end=function S(){return this.addCmd({c:S})};g2.prototype.end.myBeg=function(t){if(t.c===g2.prototype.beg.cmd&&t.open===true){delete t.open;return true}return false};g2.prototype.clr=function k(){return this.addCmd({c:k})};g2.prototype.grid=function A(t,e){this.state.gridBase=2;this.state.gridExp=1;return this.addCmd({c:A,a:[t,e]})};g2.prototype.grid.getSize=function(t,e){var i=t.gridBase||2,s=t.gridExp||1,r;while((r=e*i*Math.pow(10,s))<14||r>35){if(r<14){if(i==1)i=2;else if(i==2)i=5;else if(i==5){i=1;s++}}else{if(i==1){i=5;s--}else if(i==2)i=1;else if(i==5)i=2}}t.gridBase=i;t.gridExp=s;return r};g2.prototype.use=function O(t,e){if(typeof t==="string")t=g2.symbol[t];if(t&&t!==this){var i=this.state;if(t.state&&t.state.loading){i.loading++;t.state.onload(g2.State.prototype.loaded.bind(i))}this.addCmd({c:O,a:[t,e]})}return this};g2.prototype.style=function P(t){return this.addCmd({c:P,a:[t]})};g2.prototype.exe=function T(t,e){var i=g2.ifcof(t);if(i){var s=(e||this).cmds;if(this.state&&this.state.loading){requestAnimationFrame(T.bind(this,t,e))}else if(t&&s){var r=g2.context[i](t),n=e&&e.state;T.pre[i].call(r,this);if(e)e.state=this.state;for(var o=0,a=s.length,c;o=0;e--)if(t(this.cmds[e],e,this.cmds))return e;return false};g2.prototype.pntToUsr=function _(t,e,i){var s=this.state&&this.state.trf0||false;return!s?{x:t,y:e}:this.state.cartesian?{x:(t-s.x)/s.scl,y:-(e-(i-s.y))/s.scl}:{x:(t-s.x)/s.scl,y:(e-s.y)/s.scl}};g2.prototype.vecToUsr=function E(t,e){var i=this.state&&this.state.trf0||false;return!i?{x:t,y:e}:this.state.cartesian?{x:t/i.scl,y:-e/i.scl}:{x:t/i.scl,y:e/i.scl}};g2.prototype.dump=function(t){function e(t){var i=[],s,r,n,o,a;for(var c=0,h=t.cmds.length;c1){this.shadowOffsetX=t[0];this.shadowOffsetY=t[1];this.shadowBlur=t[2]||0;this.shadowColor=t[3]||"rgba(0,0,0,0.5)"}},thal:function(t){this.textAlign=t},tval:function(t){this.textBaseline=t},fos:function(t,e){this.font=e.cssFont},fow:function(t,e){this.font=e.cssFont},foz:function(t,e){this.font=e.cssFont},fof:function(t,e){this.font=e.cssFont},trf:function(t,e){var i=t.scl||1,s=i*(t.w?Math.sin(t.w):0),r=i*(t.w?Math.cos(t.w):1);this.transform(r,s,-s,r,t.x||0,t.y||0);if(e.get("lwnosc")&&i!==1)g2.State.c2d.lwscale.call(this,1/i)},matrix:function(t){this.transform.apply(this,t)},lwnosc:function(t,e){var i=e.trf.scl;if(i!==1)g2.State.c2d.lwscale.call(this,t?1/i:i)},texture:function X(t){return t.indexof&&(t.indexOf("hatch(")===0?g2.State.c2d.hatch.call(this,t.substring(6,t.indexOf(")",7)).split(",")):t==="transparent"?g2.transparent:t)||t},lwscale:function(t){var e=this.getLineDash();this.lineWidth*=t;if(e.length){for(var i=0,s=e.length;iNumber.EPSILON&&t-r)){var o=e-i[0],n=s-i[1],a=Math.tan(t/2),h=o/2-n/a/2,c=n/2+o/a/2,p=Math.atan2(-c,-h);return this.addCmd({c:f,a:[i[0]+h,i[1]+c,Math.hypot(h,c),p,p+t,t<0],cp:[e,s]})}else return this.addCmd({c:g2.prototype.l,a:[e,s]})};g2.prototype.z=function p(){return this.addCmd({c:p})};g2.prototype.stroke=function d(t,e){var s=t===undefined&&e===undefined?false:typeof t==="string"?[null,t]:typeof t==="object"&&!e?[t]:[t,e];return this.addCmd(s?{c:d,a:s}:{c:d})};g2.prototype.fill=function l(t,e){var s=t===undefined&&e===undefined?false:typeof t==="string"?[null,t]:typeof t==="object"&&!e?[t]:[t,e];return this.addCmd(s?{c:l,a:s}:{c:l})};g2.prototype.drw=function u(t,e){var s=t===undefined&&e===undefined?[]:typeof t==="string"?[null,t]:typeof t==="object"&&!e?[t]:[t,e];return this.addCmd({c:u,a:s})};g2.prototype.txt=function g(t,e,s,i,r){return this.addCmd({c:g,a:[t,e||0,s||0,i||0,r]})};g2.prototype.img=function y(t,e,s,i,r,o,n,a,h){var c=new Image,f=this.state;f.loading++;c.onload=function p(){f.loaded()};c.onerror=function(){c.src=g2.prototype.img.broken};c.src=t;return this.addCmd({c:y,a:[c,e+.5||0,s+.5||0,i,r,o,n,a,h]})};g2.prototype.img.broken="data:image/gif;base64,R0lGODlhHgAeAKIAAAAAmWZmmZnM/////8zMzGZmZgAAAAAAACwAAAAAHgAeAEADimi63P5ryAmEqHfqPRWfRQF+nEeeqImum0oJQxUThGaQ7hSs95ezvB4Q+BvihBSAclk6fgKiAkE0kE6RNqwkUBtMa1OpVlI0lsbmFjrdWbMH5Tdcu6wbf7J8YM9H4y0YAE0+dHVKIV0Efm5VGiEpY1A0UVMSBYtPGl1eNZhnEBGEck6jZ6WfoKmgCQA7";g2.prototype.lin=function x(t,e,s,i,r){return this.addCmd({c:x,a:[t,e,s,i,r]})};g2.prototype.rec=function m(t,e,s,i,r){return this.addCmd({c:m,a:[t,e,s,i,r]})};g2.prototype.cir=function v(t,e,s,i){return this.addCmd({c:v,a:[t,e,s,i]})};g2.prototype.arc=function b(t,e,s,i,r,o){return this.addCmd({c:b,a:[t,e,s,i||0,r||2*Math.PI,o]})};g2.prototype.ply=function C(t,e,s){var i=C.itrOf(t,s);if(i)this.addCmd({c:C,a:[t,e,i,s]});return this};g2.prototype.ply.iterators={"x,y":function(t){function e(e){return{x:t[2*e],y:t[2*e+1]}}e.len=t.length/2;return e},"[x,y]":function(t){function e(e){return{x:t[e][0],y:t[e][1]}}e.len=t.length;return e},"{x,y}":function(t){function e(e){return t[e]}e.len=t.length;return e}};g2.prototype.ply.itrOf=function(t,e){return!(t&&t.length)?undefined:e&&typeof e.itr==="function"?e.itr(t):typeof t[0]==="number"?g2.prototype.ply.iterators["x,y"](t):Array.isArray(t[0])&&t[0].length>=2?g2.prototype.ply.iterators["[x,y]"](t):typeof t[0]==="object"&&"x"in t[0]&&"y"in t[0]?g2.prototype.ply.iterators["{x,y}"](t):undefined};g2.prototype.spline=function w(t,e,s){var i=g2.prototype.ply.itrOf(t,s);if(i){var r=[],o,n=i.len,a,h,c,f,p,d,l,u,g,y,x,m,v;for(var o=0;o<(e?n:n-1);o++){if(o===0){a=e?i(n-1):{x:2*i(0).x-i(1).x,y:2*i(0).y-i(1).y};h=i(0);c=i(1);f=n===2?e?i(0):{x:2*i(1).x-i(0).x,y:2*i(1).y-i(0).y}:i(2);p=Math.max(Math.hypot(h.x-a.x,h.y-a.y),Number.EPSILON);d=Math.max(Math.hypot(c.x-h.x,c.y-h.y),Number.EPSILON)}else{a=h;h=c;c=f;f=o===n-2?e?i(0):{x:2*i(n-1).x-i(n-2).x,y:2*i(n-1).y-i(n-2).y}:o===n-1?i(1):i(o+2);p=d;d=l}l=Math.max(Math.hypot(f.x-c.x,f.y-c.y),Number.EPSILON);u=Math.sqrt(p*d),g=Math.sqrt(d*l),y=2*p+3*u+d,x=2*l+3*g+d,m=3*(p+u),v=3*(l+g);r.push({x:h.x,y:h.y,x1:(-d*a.x+y*h.x+p*c.x)/m,y1:(-d*a.y+y*h.y+p*c.y)/m,x2:(-d*f.x+x*c.x+l*h.x)/v,y2:(-d*f.y+x*c.y+l*h.y)/v})}r.push(e?{x:i(0).x,y:i(0).y}:{x:i(n-1).x,y:i(n-1).y});this.addCmd({c:w,a:[r,e,s]})}return this};g2.prototype.beg=function j(t){return this.addCmd(t?{c:j,a:[t],open:true}:{c:j,open:true})};g2.prototype.end=function O(){return this.addCmd({c:O})};g2.prototype.end.myBeg=function(t){if(t.c===g2.prototype.beg.cmd&&t.open===true){delete t.open;return true}return false};g2.prototype.clr=function A(){return this.addCmd({c:A})};g2.prototype.grid=function P(t,e){this.state.gridBase=2;this.state.gridExp=1;return this.addCmd({c:P,a:[t,e]})};g2.prototype.grid.getSize=function(t,e){var s=t.gridBase||2,i=t.gridExp||1,r;while((r=e*s*Math.pow(10,i))<14||r>35){if(r<14){if(s==1)s=2;else if(s==2)s=5;else if(s==5){s=1;i++}}else{if(s==1){s=5;i--}else if(s==2)s=1;else if(s==5)s=2}}t.gridBase=s;t.gridExp=i;return r};g2.prototype.use=function k(t,e){if(typeof t==="string")t=g2.symbol[t];if(t&&t!==this){var s=this.state;if(t.state&&t.state.loading){s.loading++;t.state.onload(g2.State.prototype.loaded.bind(s))}this.addCmd({c:k,a:[t,e]})}return this};g2.prototype.style=function M(t){return this.addCmd({c:M,a:[t]})};g2.prototype.exe=function S(t){var e=this.state;if(e.loading)requestAnimationFrame(S.bind(this,t));else if(t){var s,i,r=this.cmds;e.pre(t);s=e.ctx;i=e.ifc;S.pre[i].call(s,this);for(var o=0,n=r.length,a;o=0;e--)if(t(this.cmds[e],e,this.cmds))return e;return false};g2.prototype.pntToUsr=function I(t,e,s){var i=this.state&&this.state.trf0||false;return!i?{x:t,y:e}:this.state.cartesian?{x:(t-i.x)/i.scl,y:-(e-(s-i.y))/i.scl}:{x:(t-i.x)/i.scl,y:(e-i.y)/i.scl}};g2.prototype.vecToUsr=function E(t,e){var s=this.state&&this.state.trf0||false;return!s?{x:t,y:e}:this.state.cartesian?{x:t/s.scl,y:-e/s.scl}:{x:t/s.scl,y:e/s.scl}};g2.transparent="rgba(0, 0, 0, 0)";g2.exeStack=0;g2.context=Object.create(null);g2.ifc=Object.create(null);g2.State={create:function(){var t=Object.create(this.prototype);t.constructor.apply(t,arguments);return t},prototype:{constructor:function(){this.stack=[{}];this._current={};this.trf0={x:0,y:0,w:0,scl:1};this.loading=0;this.loadHdl=[]},pre:function(t){for(var e in g2.ifc)if(g2.ifc[e](t))this.ctx=g2.context[this.ifc=e](t);this.stack=[{}];this._current={}},post:function(){delete this.ctx;delete this.ifc},get:function(t){return t in this?this[t]:this._current[t]||g2.State[t]},set:function(t,e){this._current[t]=e},add:function(t){var e=g2.State[this.ifc],s,i,r={};for(var o in t){i=t[o];if(typeof i==="string"&&i[0]==="@"&&!(i=this.get(i.substr(1))))break;if(o==="x"||o==="y"||o==="w"||o==="scl")r[o]=i;else if(!(o in this._current)||i!==this._current[o]){this._current[o]=i;if(e[o])e[o].call(this.ctx,i,this)}}if(Object.keys(r).length){this.trf=r;if(e["trf"])e["trf"].call(this.ctx,r,this)}return this},save:function(){this.stack.push(Object.assign({},this._current));return this},restore:function(){this._current=Object.assign({},this.stack.pop());return this},get current(){return this._current},set current(t){this._current=t},get trf(){return this._current.trf||this.trf0},set trf(t){var e=t.w||0,s=t.scl||1,i=s*(e?Math.sin(e):0),r=s*(e?Math.cos(e):1),o=this._current.trf||this.trf0;this._current.trf={x:r*o.x-i*o.y+(t.x||0),y:i*o.x+r*o.y+(t.y||0),w:o.w+e,scl:o.scl*s}},get lwOwner(){return this._current["lw"]},get cssFont(){var t=this.get("fos"),e=this.get("fow");return(t==="normal"?"":t+" ")+(e==="normal"?"":e+" ")+(this.get("foz")+"px "+this.get("fof"))},onload:function _(t){this.loadHdl.push(t)},loaded:function z(){if(--this.loading===0){while(this.loadHdl.length)this.loadHdl.pop()()}}},fs:g2.transparent,ls:"#000",lw:1,lc:"butt",lj:"miter",lwnosc:false,ml:10,sh:[0,0,0,g2.transparent],foc:"#000",fos:"normal",fow:"normal",foz:12,fof:"serif",foznosc:false,trf:{x:0,y:0,w:0,scl:1}};g2.symbol=Object.create(null);if(typeof CanvasRenderingContext2D!=="undefined"){g2.ifc.c2d=function(t){return t instanceof CanvasRenderingContext2D};g2.context.c2d=function(t){return t};g2.prototype.exe.pre.c2d=function(t){if(!this.g2ified){this.fillStyle=g2.transparent;this.font=t.state.cssFont;this.save();this.g2ified=true}if(g2.exeStack++===0){var e=this.g2state=t.state,s=e.trf;this.setTransform(s.scl,0,0,e.cartesian?-s.scl:s.scl,s.x+.5,(e.cartesian?this.canvas.height-s.y:s.y)+.5);this.save()}};g2.prototype.exe.post.c2d=function(){if(--g2.exeStack===0){delete this.g2state;this.restore()}};g2.prototype.p.c2d=CanvasRenderingContext2D.prototype.beginPath;g2.prototype.m.c2d=CanvasRenderingContext2D.prototype.moveTo;g2.prototype.l.c2d=CanvasRenderingContext2D.prototype.lineTo;g2.prototype.q.c2d=CanvasRenderingContext2D.prototype.quadraticCurveTo;g2.prototype.c.c2d=CanvasRenderingContext2D.prototype.bezierCurveTo;g2.prototype.a.c2d=CanvasRenderingContext2D.prototype.arc;g2.prototype.z.c2d=CanvasRenderingContext2D.prototype.closePath;g2.prototype.stroke.c2d=function R(t,e){if(t){this.save();this.g2state.save().add(t)}if(e&&typeof Path2D!=="undefined")this.stroke(new Path2D(e));else this.stroke();if(t){this.g2state.restore();this.restore()}};g2.prototype.fill.c2d=function B(t,e){if(t){this.save();this.g2state.save().add(t)}if(e&&typeof Path2D!=="undefined")this.fill(new Path2D(e));else this.fill();if(t){this.g2state.restore();this.restore()}};g2.prototype.drw.c2d=function N(t,e){var s=e&&typeof Path2D!=="undefined"?new Path2D(e):false;if(t){this.save();this.g2state.save().add(t)}s?this.fill(s):this.fill();if(this.fillStyle!==g2.transparent&&this.shadowColor!==g2.transparent){var i=this.shadowColor;this.shadowColor="transparent";s?this.stroke(s):this.stroke();this.shadowColor=i}else s?this.stroke(s):this.stroke();if(t){this.g2state.restore();this.restore()}};g2.prototype.txt.c2d=function q(t,e,s,i,r){var o=this.g2state;this.save();if(r)o.save().add(r);if(i){var n=Math.sin(i),a=Math.cos(i);this.transform(a,n,-n,a,(1-a)*e+n*s,-n*e+(1-a)*s)}if(o.cartesian){this.scale(1,-1);s=-s}if(o.get("foc")!==g2.transparent){this.fillStyle=o.get("foc");this.fillText(t,e,s)}else{this.fillText(t,e,s);this.strokeText(t,e,s)}if(r)o.restore();this.restore()};g2.prototype.img.c2d=function H(t,e,s,i,r,o,n,a,h){var c=this.g2state.cartesian;i=i||t&&t.width;r=r||t&&t.height;if(c){this.scale(1,-1);s=-s-r}if(o||n||a||h)this.drawImage(t,o,n,a,h,e,s,i,r);else this.drawImage(t,e,s,i,r);if(c){this.scale(1,-1)}};g2.prototype.lin.c2d=function L(t,e,s,i,r){if(r){this.save();this.g2state.save().add(r)}this.beginPath();this.moveTo(t,e);this.lineTo(s,i);this.stroke();if(r){this.g2state.restore();this.restore()}};g2.prototype.rec.c2d=function F(t,e,s,i,r){if(r){this.save();this.g2state.save().add(r)}this.beginPath();this.rect(t,e,s,i);g2.prototype.drw.c2d.call(this);if(r){this.g2state.restore();this.restore()}};g2.prototype.cir.c2d=function W(t,e,s,i){if(i){this.save();this.g2state.save().add(i)}this.beginPath();this.arc(t,e,s,0,Math.PI*2,true);g2.prototype.drw.c2d.call(this);if(i){this.g2state.restore();this.restore()}};g2.prototype.arc.c2d=function G(t,e,s,i,r,o){if(o){this.save();this.g2state.save().add(o)}this.beginPath();this.arc(t,e,s,i,i+r,r<0);g2.prototype.drw.c2d.call(this);if(o){this.g2state.restore();this.restore()}};g2.prototype.ply.c2d=function Z(t,e,s,i){var r,o=0,n=e==="split";this.beginPath();this.moveTo((r=s(0)).x,r.y);for(o=1;o1){this.shadowOffsetX=t[0];this.shadowOffsetY=t[1];this.shadowBlur=t[2]||0;this.shadowColor=t[3]||"rgba(0,0,0,0.5)"}},thal:function(t){this.textAlign=t},tval:function(t){this.textBaseline=t},fos:function(t,e){this.font=e.cssFont},fow:function(t,e){this.font=e.cssFont},foz:function(t,e){this.font=e.cssFont},fof:function(t,e){this.font=e.cssFont},trf:function(t,e){var s=t.scl||1,i=s*(t.w?Math.sin(t.w):0),r=s*(t.w?Math.cos(t.w):1);this.transform(r,i,-i,r,t.x||0,t.y||0);if(e.get("lwnosc")&&s!==1)g2.State.c2d.lwscale.call(this,1/s)},matrix:function(t){this.transform.apply(this,t)},lwnosc:function(t,e){var s=e.trf.scl;if(s!==1)g2.State.c2d.lwscale.call(this,t?1/s:s)},lwscale:function(t){var e=this.getLineDash();this.lineWidth*=t;if(e.length){for(var s=0,i=e.length;sUYI6Y18*7u=Ht>6A`X7ipy|F=XK%2C+&!v~^ zHBH+zX)b-`hUxf>49*#wNanx+{(E;N+mda#(AP{acOb8{tKF5fFFB{}_J<#|+O6rZ zW%^cY*dKh-9Xx7Xr8My3){}&C9#bZUd=-U0jX7;Sd-|&NgKQTa@oj6CrVDPLo=(Gb zw!G>2$^3Mhqn}QPVjzB;eh@5UKMj)@<}|HM7?|lS>p@9-A)bG)}qo z{N@ey)1Jq9IE}?{qB*^k&s!{_ z%*?6#jCv_G0lZ*Inxxr+TG})_y`$$%CKvOGn~MTGS(}oL-eSpTrXdC!VcY`JqlyHz z8KEI5TVyjG+JaG%T6Stxcz1HF2@S%SzF^6MvNWskOAL@4_%eVHP3@99Yf}(X+Iiqg z{ftV!ueIK>9WSG3x3i9#m8T%b{geJ7#%#By_T&PUD{SPN5Pg<~vsRStdn~0q^x{I_ zK+~kT#*vafgo0qrg|8A^=%ip;!Yjm57W8}Tj+;7lVAgT@J#^nC$y^cUK$wzn4{6sN zbW^KsfwVq9c)P7`j*}BSe~axF4yRS$ zCW_yrx}Ed$Z*F`$+11gsEfAwp4`If{v#+6l+@PQ-%Daz(caXwcMPVivmV}3>%#cbx zW=#BreGQE!Nnerl3zCG9To%LQk zb-+V}xO!jyxSZcm*1LRh_4J45Kf?N-F<8#CZUg>hmsyf<;?iz--5-y^sFy+19F3Il#^=GtnLz+AjhfOA*Ij7!Hv6Upz)L?w^ZRya4n?5 zxSP7JyNsn9n4FwY{c$ADlnq4Ced9<2Xod0A7+s?uA?di%nFya^oSZzMqig6Bdw8E3 z`3M-DfSi11W2?b(5JuWziT)o9M0kgp15?O69nXXgCH^LiUA3Ohy(uMutNe@;^rFO@faINy zA3j-V40X2ubev4rVP!|!qCyLF~|H@Nd-z!BZ)0c~X{r%!07_fUu`zjXnW z$W7|5F#)q-hbR|B$$@j@ar)>}^0FU2dH!`Y`*wOx&%b|qjz9BXU(e^S<7cP%^ZC1H z@1DG#zn-4UpNp0F65}t=zYgc&qfcHuWZC)r^6j_5+ZQi?4PO5AO((vj^zGC6a^6qA z`)U32tJxFpr_W|r{ELV5-QD9)f9gEG3ulk7&i&~2Q84{JJioo{-(Eg?`QzKw?az3--%lA)z z>0bu(hrc`tFBiWL&ig-|(XT=B{d{`y)A?sc z&GCg=V77k$##>i>OjG%cYF=ypetPrw(DOs4=-s`~vEFIa_BcJJ@pf~JN4+WO;O0?X&$bf4vSgoju_WKcYGvaI!5Q7$ySrFPId!i zckd_LLQ)6GG&LgCTd2Ph2R<+%>MUqjqteLR6u{DsQ$$BwUf>%e0RrwyQx6j2h*(59 z#^~^pT#FSMBknn49`tbWZ6XN^=7g`Dn=jqreT4Eg7&qBaPRCe7&MUys&WiSZROJ## zs--gOp~)fwsM^h|>Ta%6uWxQSjzNI{4YeDBxWZf$p9BzvO-MwRWJ)r!CUbJ<1PL=` znAmrcGn0;DJMIoFC+T!VWg-EI`_{&D=_oX@$A(=uY=>sw>aDw>Ie;&c6_89qvYj(? z5#adn1=IpJ20FtL66u#D29iX-AR%!Pf+XzF99m8ugwDOSsfUz+=mFNOm%(>tk!k>J zIg`C;KA_D2%?Gqu6HUgWAnOd+_ks5S7)J%f-8$=WH)kHY1p5k_NvIG(A`eC=8OW1# zghUfyFWNI}@^ob_DGy zwCC<8ZFA9CTI3E}QD+LKPF8S0su@ZFpRh3ow%MJuLBE}>J%i6h8#uB~=Oin7GSQQX zo(y}|L(vn!=rxY+M9>d7cO)x%GSQQXo(y`xhUc@>5zJrigJSssCNwIcg>u0>*R1yn ztv4fic5v8s-%u?edt;`1T~CTZ?Hl0_;QTCTY^Q8VMS%N8JvZDBjkVzH`N2Ho`98$n zJbSFMhKz*)X6mqa>H=Vfj|LSvfo|l*+Ca5|rnDuYg`pN~=53Jy)ZKfex%cyf9G^Eh zp0ZGr^@X(dW#B6NA49a~4xJkGa=mZ|2g1!42hw|q*@J4^RrpRB#Y!?!P6;srfjqjH zY`Yy0=B#F6L`{>qw9RD%u}D_tpbxQ(bvF2PyJcT~@=&Op!J}w!*Bw|K1Q6+|1PlT2 zPzL}G2XVqqXD7@?iMYXmVYj=hVGkY<`nOu$RF#2v_{T6-h>+JGDY$fNa7r*(g#F5J}5M^3FUbF^j^c;xf-mdN*M_ zF|o*5TkG3=t?xaqFi93^!al1XSVixdJg&{Nwbt;j0AC1AYeFk28GXB?JUx#gZ9$xG zm^Y{9m6QXKpi*rWi&&5oajdG$Ij9E;oep>5kfm!Ugzqr$oh$6P4#!ZxjUp3h;WFs% z7o0WAV-wy`dwZ1sGglUMZNdH||r^FBS(wP4xZG~g1s z(cv$&Q2Q0?p|-bDS%(DCENab$4*e41E!yo`$e&pbfWR9ZS@~#LMcD1! zW6BqC`YQREYxewUv$9wm?OG|jS|ffCq9;zl-Ga;8cjbWHX4(zWwTD;+hoN1Qc1;ej z%*uf~d(SW!1w)Dv_4+*ZYa(1~CjKu7z>g3hJ>>=K6q*IY3JlPaNtnco`NCrqD)I)K z-gsu8wDMmIb9y`}U;+JGw~tSL5~mc3O4W-mEMDPN51N9#U49nf% z+nXJ!idyw$gi#KMt3goh%LX}pzGPw63Bq!oB`WcTq7OF{jFBXnSq#Jz7ir_qTvhP4w+ zx8XDEK%Bb9t6|Iv5!_(~I1}KNo%B{6Dy&f=?uPkJ${ekpub@tTK<;ZJS{dV9!<>Hu zR;Dn%>ZBM!!VQbi3S?yzi)4y$Bu?1ei;R(B*lEXT8CJ)nH8{=TI+=F>Fc#~U(b1uS zVL_NAqwR7Vwf>L`t1PREsATx9hQ5=po^-pqU6y4XnH=e4ij$1tna&F@zVrA?$j~X8&kN~v zhF?E`g)D1#hP9Dys^f@*oSC zrzxT>u@&@4tt-H`?BsCFdk=}J50GYDsI)hu;dGV)N@l~K1!FCp|K0xNrmF1Xm}p`N zp;VZlq>{vQ5tLjBFR1FA=>^-?9C)~0$i)V9cB zm_EWVJR|C&1E*_O?i1XWk@PT_jP$8bgY- zy*|*X16)JHG92Jb?UtM~wRxJ@p{!6g(EhbOm)5*l>#e%_EnZI230FK07G$kNS3T1& zxMH`6H30&zG!-!>JmuMG>0Uf|U!jY4VDMg{XTkMr+~xp)h6Hf2uM_22ik;wl5F8Ci zcYxKrE*GPUsLVI4#=QY{CUp!r5dbp^gX_##SW zC6q3pehC-wqJ*{zCwLL;GWneQTwD|XfX2E^=xn=zYvrZ$vANqtq7sn1QWIv-SFYH{fAjpnD;-ra zzWJBMfC@Hjcb19D&hkkjjv{3Vh0kYJd4lvLs0 zlnSP;O7%oPUGn<;ILVUtOBRx_!w5U;A0<-qH${T7VO6Bp`Sitm1w`Idh;$a;Q~8w~=@ghm%}qmj+Eh;wmOO|B zo(k&B_oxb_DvK*gcd++8jH)(%DhliO$t+$r0oL%V5LtS3c#lcFQ4^lAuDCxGT&qAh zClLaP0TJI>{=FXN&*Hl?0EldeX;2A&SpnQ?-jY{E{`oINMvc4eDyd)0V|QiauDVL- zceBb;Go>7ebW(iEZXiNE_7V*q_Gr1I^lPM!)7^)mIc+N)fC!gyf71yGiLt5(&2&CFcxA!nV zbB6}vIQXr2JQ?_;+pY1D@B4=Gj=!R;?x1ch)ba3Lk3ikFGjRN~!0|h-h{M#W@?j}U zauNV$v%p@sGcs`#z+Rk9oJ9k>PZm{d27sMn{JooS$!oUYyL(nU?KJ~ht{)a~Omd98 z_@`@Gg;UVb;l~~iyeY5o_FFw>FHUH2&m_lh0A-6pD>C3QD1W zfySzKIa1p+>8VL&BrWTRhBXqUq@F10Va3ze2x#aR-oi!tZ}xY8mxQtCPxkkJ?eW?3 zAb_1OMyZmjzVi2QCJr2A34Ce4(~g>J$z%S<~$0gVu8}TLqqV@8C)tDg~j693aQ#=QPmW~ zR>uu{cigbxm|?Id_UxYe1q$R?ea2v{5_KI5`4rJ;m9?}tTVIv=T zpGLP@Zq^QiRdYM=p96&!@{KNUoFzwn(0l=R_!*d8IED0@j}d2&B>-^qR8ngPKkDjW io=lbzt-LENL15??34`nS>Lb(UYI6X^8~u0NH1K!csGYf4wj zHejC}8(YZZxsH-}P3%lknxskockU$FlIk}ui2!%?q>t~-Xwqjvx2Ila^htja48k!ZJ|%oclNwHJ2n^K308(#;)9H9= zE9?;^AtyErPie|izMK-rAhR(inqj|xHt7dS6yV8OYL1{wFISx`SC_4%%CoB$=Oy7Xh zCQ9Ro$pj%FSasuz2&X10AnV2jWSkCK%|$)netB?N58^#|Z_;$45yya-xNHmRz-~9V zb7+G;T27rGRsgDmvn6cDl4WHHi^him-^1;7Oy-(fhTLvd#5O$yWE;J`%ITA_rbcbk zVa6mG@=?&*v-%IP%NGd`4D-4UX^jVEEC&bLpv!ZOc5l5d8ppu_`rmZD2Iq9jW}^8m znX~eLdlh-fro7BBffSXxYh~(&UKi$j6%2-=!hIORoftl943XSem+it5Ar=MGbEB!( zg@-E2NTVEOC|&9%yU>mVS`8;r!$TEys8J6jYPq{i>~6OAw&T*EbNDpmqvnezK12wH zyZ7C*+2oSY=J|_@C%-&@2K#?ZVLOi-mGSQy)RBncm}szWtLLUc3=i#|8wLU|58*67 z>Nsu`BuAY_dK4aY+)#tmeZ8m zkvnqSzT2;JmmjyJZa{9(jSf;(oJA`E0%}e99Mbyi?=;+gWf|i%y&`(;6!$_ZEDm@O z1hYhjf&Re(F<(!*Jr6Ko>_#vP5XH&RI_Y8%ad~kv6#>OMIJienx-cgUc!v(BAYxqM za}bXW4;laOT#mPL*{8sHLJ)Y|2na%HO3m;v zYBCxHWu}^!XyXa25z~B!ww5U8$R+jWeIcs+Z3>`8u3`_Ye#k-HC>P|z1OGB)&ZDGAD>KSlUDlE%f+v+M~}jnUym->xA)1-^~0}T z)*oKSqlXu#(fI1YVEA)E}cX8fczW|xy6KhXZ$%cqa; zzwSq~2lLCp*FSyp?&-IWzgo85ou0Sq{l{;9e)6VuKA7Bp^C&)_zH6Vhetq-w;^8~~ z;?cNGp1mI>=MNv9M^_I%ynpa^kp4Uwp1nN%+A4*(*hs-9w;SH15KXGer^JX)*SF)l zz6DYVdY>m)Lok<5Lc{Ugv>tTL6V?jHYl_454SunA7J2k>!e@ z>6D0_WyF|>C8kGI$pA7!L!MF=tgMB*wDN?%kf@Mju5zxU&dF-w@owjk^xUOhiJSB=mM`VgUfhUz1(-LtV@72A5LI;}6|Fa7 zZlbRG8PZ;?f?oY3xIbH+-&3o zrjZwC1@|AqNllJsPA1q?&*EZIK8D7|F?6+)P@r}+P3rSB-63#LgGW(3!dfj%ZKOe>n zx8Tfmj@w_Y*YvwD?+cYvcoh$E5VV~b1P}?c9O%HneRBZUfH ztJ{Uuh<~%uyu%GQXFOn;mS{;CGiGGb&xIC{?v}jH;b=T;Ik`;7V9Rhmi(}$mAd;a> zcY22efP4fn`H-bbK*PwI)TGLt?5xzHxm5X6^D<8Qb_`{g(q2C|_IhVX03yq=A?%B? z!)kmlq`OvqYhkQ^ZJG>##e*mXiACVbBO2CCgnGo?9;dW|}4_I-N0H_ePAFn|Y0uxYy8jo%2A~L}( zaTG`)txc(oSks^dH_ogq;YNOX9QtX!?!ZDj3JRsTAnk#mK*EW{FIlw&Qc*K3QA&`V zl<_h@8*>Az>PHcRRdrn8s!T*vBiHx=_q$}YT$Wrw*7GnL*}H3`FtSk!+sPk3EewKB zZ}+Brt>I8|Ff%NDO90_wITt7xzhJhZ2Z7&<_qqT?F$Bh~GG)#7ngrD{luy2cY8PoV z9OTc=0U+goJS=~8oGdNz_r!>4!e6JqG9ys@QOp1<-l3~@#d6p^Ch{rBq#%}VtFGd- z%^R$_aE=&O`~b9JlZG9`*wRsh8*d93KmkYwQ7%Q2s3gLngLbpnqW z!+JOyEnnzolWAdx%@T6PYPY8^iMhK+;O?VOG_$M6?CeidTdf~whW)bo>oHuc&8 ztnCNM!9k){!hOIW9QXYJF4lgKbO*)U3{mAw1G{oNik!!URltfvO z`mrR!azBf+ho3Ha$glc01Np``9=)ARH4t5EA|BL;-u1>i9) zcL{&z@E5$rYs=Xz=mstQ`nW#^BS!`@@pL#q4HY82JpK5>47?d&4*_mt66iqO(uDHV zJHza&_YCXCH5*rE1_S#kpib}yR@e%(U|_w@_777Vmnl3t`7JL9$i{`>QlKWIM21KU zE2{(`QGOUCf+6%F-c5SG_I_qWLC9UyJ?(qTQKvr$XoJ#bmjGk89g#OA2(qx&Yw@tm z9$+uC$GPQDpcAk>C%$J3779{1>ot?HUys46lI#MHNLO$Uey9{B+Z2~&xeCB2lfNQM zW>Y6WIx_1Es6=GJvjxcHLm8n=eu|OXW#Kj1Zt?O2DmH3Y8@DKGF;j6VVcV^?j_B6orohR5lzl`qx8nuk8oaO=cYD%YmhR_aYtk&R6 zlCsDXValD1J-myLyl%_I|BCo}?jVgajG$~!X$@cI=F5%O?!d2sXE8$KffzEVfH`yO)@5tL?vYvegx4P$hLURs?X?Okt@fnLWyK-%P$exACb;w>3NImeNJ(Izy^TRzb zlRO`>oRy4b&8X84wgwfImF+{hF;bMBh_>J4D&Q!q&VK53G^5}t!Cwbp9bYKPmZ4$$owum* z%o7bAN)0Mq2@T41wxiW%XaN!<}=HRaDC+RhLotAnr zcU=q{URnI{u8Tj;!ajxSOLR7)RUV?dqPZkDF`-*=gm=XO4VhBI{H`mbamq+V{nGG@ zo>#lkl?r7mn0rVQ(RQN-vEYD#0HAe00O?dt7sJtPXr3w{2)>R?()2vi($qCYnY3h_ z=-17bHhWQ|hyS5SNNuY?`RqRw2m0|vX&##;hW#v_6d04y%KwXMIMIT{j#rYZcx(Xi z;(42uJw{+FAoHkvC8s+FKsc3Gi^ZC)#@Y4%CdjY?szHW)!yos zY4-U}0kd!J0d@$S#8f_2ZO@ggyk=P}j6e-G&t9_+NqHWBLa5<1u-6Zt-h~cyEz`po z2H-&s#KN`{9eOfjh(buv+HRu_go8#bpt8&`vYahjSBe@Yw2mmR;V@E#J=x0GHe&{2 zbAeRL&ONAp%23>bk2}BMC~k#ThR*_MU5nc59CHLHaZ&lMqB3sEXot!gR48q|PS@*j zy^iD&0pVjVz7?@~#ze-HIxEUx`Sf;T+VpgQE6V+&#vz+ecXW6v+bKF+D_|9W#mSQ= zQ8)l3%)QGj`S1D=d=60*Klv0j*FeyJITfVu3SL3DAyy?$z-+mj}6 zQYeFe(Q&pcR0l@xf_f&)Snj1_olf~c*!`Mwb+t8Vw5#7W6czLGuVfFE&k>5aezots zUzP6*ikRNmMW(9PvbMOAiJx*BkdTnR!t(%UjQf{7`Q7S`Y(H1nU@r;y&dk*cl45a6 zl$M|#RVAGSRpMxU>-EmB7w{;?%cUbaw2Kq?`$gJFp&Ajv`|M)SThz+Hd>4xp+RYrbAvpG8q*RWIRXkIC!CqabvlYFcmmqvL@;st3>tHJxGv zdzqt?18}5dtNTIZPJ;wi_m8K3zp@${RK?X41~!`UTdi=$N_VH9wrqD%-Bm9kFp4*H z)z62wzvc?~B}0jgpDRhM^2fYwBNwa&OqYPG>6{7M#4F{D664em^}iAVt-HIUn3q}) zCG+4%Hj#Oytn69NiKzKBMUf2=LJ_iTVEDOFlp5yhx z^v(8Bj8+vwb8b;lza}hOx7wX0m966D&Vfwbi3ffHTzJTbIy-cy;Wx9Q+>D{*u}BB- z?`qUDd^l{4LLR|CXmqgbc~YPxW=uMw#VA|<4_pI7zAjz7jr`ehz3m(} z;d{nHQWKD3J_Fw*5*=;uM8Pux@?!WmnQA6a&SESPWcA7nzJ>6YV<>DRyp9-kc@DK< zFpC2ggEB5fyoEf2WT^miMP`%VYOy-cjCp)j^Aa2(G)H!xKxh9Z6bQi4o7kDmu0_cd pCM@i1>DJ67?a#)f@coM%f{b9AQuq#{_zD5l{}Ws~0Brj_0082*Uhn__