From c97b1b635e794e209b69a1272e2eb1caf3633091 Mon Sep 17 00:00:00 2001 From: Pomax Date: Sun, 9 Aug 2020 17:16:50 -0700 Subject: [PATCH] control (#261) --- chapters/control/content.en-GB.md | 8 +- chapters/control/handler.js | 159 -------------- chapters/control/index.js | 3 - chapters/control/lerp-cubic.js | 62 ++++++ chapters/control/lerp-fifteenth.js | 81 +++++++ chapters/control/lerp-quadratic.js | 61 ++++++ chapters/explanation/content.en-GB.md | 2 +- chapters/explanation/content.ja-JP.md | 2 +- chapters/explanation/content.zh-CN.md | 2 +- chapters/introduction/content.en-GB.md | 4 +- chapters/introduction/content.ja-JP.md | 4 +- chapters/introduction/content.zh-CN.md | 4 +- chapters/toc.js | 9 +- index.html | 76 +++++-- lib/custom-element/api/base-api.js | 26 ++- lib/custom-element/api/graphics-api.js | 199 ++++++++++++++++-- lib/custom-element/api/types/bezier.js | 4 +- lib/custom-element/api/types/vector.js | 147 +++++++------ lib/custom-element/api/util/shape.js | 28 +-- lib/custom-element/custom-element.js | 10 +- lib/custom-element/graphics-element.js | 15 +- .../lib/perform-code-surgery.js | 1 - lib/custom-element/lib/split-code-sections.js | 58 ++--- lib/site/referrer.js | 26 ++- lib/site/social-updater.js | 57 +++-- package-lock.json | 4 - package.json | 17 +- tools/build.js | 7 +- tools/build/create-index-page.js | 8 +- tools/build/get-all-chapter-files.js | 5 +- .../generate-graphics-module.js} | 13 +- .../{ => graphics}/generate-placeholders.js | 25 ++- .../build/{ => markdown}/convert-markdown.js | 31 +-- tools/build/markdown/inject-fallback.js | 39 ---- .../markdown/preprocess-graphics-element.js | 67 ++++++ tools/build/process-locale.js | 13 +- tools/images/chapters/control/lerp-cubic.png | Bin 0 -> 16566 bytes .../chapters/control/lerp-fifteenth.png | Bin 0 -> 29174 bytes .../chapters/control/lerp-quadratic.png | Bin 0 -> 13980 bytes tools/images/chapters/explanation/circle.png | Bin 0 -> 6586 bytes tools/images/chapters/introduction/cubic.png | Bin 0 -> 10072 bytes .../chapters/introduction/quadratic.png | Bin 0 -> 8807 bytes .../images/chapters/whatis/interpolation.png | Bin 0 -> 30131 bytes 43 files changed, 812 insertions(+), 465 deletions(-) delete mode 100644 chapters/control/handler.js delete mode 100644 chapters/control/index.js create mode 100644 chapters/control/lerp-cubic.js create mode 100644 chapters/control/lerp-fifteenth.js create mode 100644 chapters/control/lerp-quadratic.js rename tools/build/{rewrite-graphics-element.js => graphics/generate-graphics-module.js} (70%) rename tools/build/{ => graphics}/generate-placeholders.js (77%) rename tools/build/{ => markdown}/convert-markdown.js (52%) delete mode 100644 tools/build/markdown/inject-fallback.js create mode 100644 tools/build/markdown/preprocess-graphics-element.js create mode 100644 tools/images/chapters/control/lerp-cubic.png create mode 100644 tools/images/chapters/control/lerp-fifteenth.png create mode 100644 tools/images/chapters/control/lerp-quadratic.png create mode 100644 tools/images/chapters/explanation/circle.png create mode 100644 tools/images/chapters/introduction/cubic.png create mode 100644 tools/images/chapters/introduction/quadratic.png create mode 100644 tools/images/chapters/whatis/interpolation.png diff --git a/chapters/control/content.en-GB.md b/chapters/control/content.en-GB.md index 580468b5..1808c27d 100644 --- a/chapters/control/content.en-GB.md +++ b/chapters/control/content.en-GB.md @@ -5,9 +5,9 @@ Bézier curves are, like all "splines", interpolation functions. This means that The following graphs show the interpolation functions for quadratic and cubic curves, with "S" being the strength of a point's contribution to the total sum of the Bézier function. Click or click-drag to see the interpolation percentages for each curve-defining point at a specific t value.
- - - + + +
Also shown is the interpolation function for a 15th order Bézier function. As you can see, the start and end point contribute considerably more to the curve's shape than any other point in the control point set. @@ -34,7 +34,7 @@ That looks complicated, but as it so happens, the "weights" are actually just th Which gives us the curve we saw at the top of the article: - + What else can we do with Bézier curves? Quite a lot, actually. The rest of this article covers a multitude of possible operations and algorithms that we can apply, and the tasks they achieve. diff --git a/chapters/control/handler.js b/chapters/control/handler.js deleted file mode 100644 index d80a55fd..00000000 --- a/chapters/control/handler.js +++ /dev/null @@ -1,159 +0,0 @@ -module.exports = { - drawCubic: function(api) { - var curve = api.getDefaultCubic(); - api.setCurve(curve); - }, - - drawCurve: function(api, curve) { - api.reset(); - api.drawSkeleton(curve); - api.drawCurve(curve); - }, - - drawFunction: function(api, label, where, generator) { - api.setRandomColor(); - api.drawFunction(generator); - api.setFill(api.getColor()); - if (label) api.text(label, where); - }, - - drawLerpBox: function(api, dim, pad, p) { - api.noColor(); - api.setFill("rgba(0,0,100,0.2)"); - var p1 = {x: p.x-5, y:pad}, - p2 = {x:p.x + 5, y:dim}; - api.drawRect(p1, p2); - api.setColor("black"); - }, - - drawLerpPoint: function(api, tf, pad, fwh, p) { - p.y = pad + tf*fwh; - api.drawCircle(p, 3); - api.setFill("black"); - api.text(((tf*10000)|0)/100 + "%", {x:p.x+10, y:p.y+4}); - api.noFill(); - }, - - drawQuadraticLerp: function(api) { - api.reset(); - - var dim = api.getPanelWidth(), - pad = 20, - fwh = dim - pad*2; - - api.drawAxes(pad, "t",0,1, "S","0%","100%"); - - var p = api.hover; - if (p && p.x >= pad && p.x <= dim-pad) { - this.drawLerpBox(api, dim, pad, p); - var t = (p.x-pad)/fwh; - this.drawLerpPoint(api, (1-t)*(1-t), pad, fwh, p); - this.drawLerpPoint(api, 2*(1-t)*(t), pad, fwh, p); - this.drawLerpPoint(api, (t)*(t), pad, fwh, p); - } - - this.drawFunction(api, "first term", {x: pad*2, y: fwh}, function(t) { - return { - x: pad + t * fwh, - y: pad + fwh * (1-t) * (1-t) - }; - }); - this.drawFunction(api, "second term", {x: dim/2 - 1.5*pad, y: dim/2 + pad}, function(t) { - return { - x: pad + t * fwh, - y: pad + fwh * 2 * (1-t) * (t) - }; - }); - this.drawFunction(api, "third term", {x: fwh - pad*2.5, y: fwh}, function(t) { - return { - x: pad + t * fwh, - y: pad + fwh * (t) * (t) - }; - }); - }, - - drawCubicLerp: function(api) { - api.reset(); - - var dim = api.getPanelWidth(), - pad = 20, - fwh = dim - pad*2; - - api.drawAxes(pad, "t",0,1, "S","0%","100%"); - - var p = api.hover; - if (p && p.x >= pad && p.x <= dim-pad) { - this.drawLerpBox(api, dim, pad, p); - var t = (p.x-pad)/fwh; - this.drawLerpPoint(api, (1-t)*(1-t)*(1-t), pad, fwh, p); - this.drawLerpPoint(api, 3*(1-t)*(1-t)*(t), pad, fwh, p); - this.drawLerpPoint(api, 3*(1-t)*(t)*(t), pad, fwh, p); - this.drawLerpPoint(api, (t)*(t)*(t), pad, fwh, p); - } - - this.drawFunction(api, "first term", {x: pad*2, y: fwh}, function(t) { - return { - x: pad + t * fwh, - y: pad + fwh * (1-t) * (1-t) * (1-t) - }; - }); - this.drawFunction(api, "second term", {x: dim/2 - 4*pad, y: dim/2 }, function(t) { - return { - x: pad + t * fwh, - y: pad + fwh * 3 * (1-t) * (1-t) * (t) - }; - }); - this.drawFunction(api, "third term", {x: dim/2 + 2*pad, y: dim/2}, function(t) { - return { - x: pad + t * fwh, - y: pad + fwh * 3 * (1-t) * (t) * (t) - }; - }); - this.drawFunction(api, "fourth term", {x: fwh - pad*2.5, y: fwh}, function(t) { - return { - x: pad + t * fwh, - y: pad + fwh * (t) * (t) * (t) - }; - }); - }, - - draw15thLerp: function(api) { - api.reset(); - - var dim = api.getPanelWidth(), - pad = 20, - fwh = dim - pad*2; - - api.drawAxes(pad, "t",0,1, "S","0%","100%"); - - var factors = [1,15,105,455,1365,3003,5005,6435,6435,5005,3003,1365,455,105,15,1]; - - var p = api.hover, n; - if (p && p.x >= pad && p.x <= dim-pad) { - this.drawLerpBox(api, dim, pad, p); - for(n=0; n<=15; n++) { - var t = (p.x-pad)/fwh, - tf = factors[n] * Math.pow(1-t, 15-n) * Math.pow(t, n); - this.drawLerpPoint(api, tf, pad, fwh, p); - } - } - - for(n=0; n<=15; n++) { - var label = false, position = false; - if (n===0) { - label = "first term"; - position = {x: pad + 5, y: fwh}; - } - if (n===15) { - label = "last term"; - position = {x: dim - 3.5*pad, y: fwh}; - } - this.drawFunction(api, label, position, function(t) { - return { - x: pad + t * fwh, - y: pad + fwh * factors[n] * Math.pow(1-t, 15-n) * Math.pow(t, n) - }; - }); - } - } -}; diff --git a/chapters/control/index.js b/chapters/control/index.js deleted file mode 100644 index 5f464b2b..00000000 --- a/chapters/control/index.js +++ /dev/null @@ -1,3 +0,0 @@ -var handler = require("./handler.js"); -var generateBase = require("../../generate-base"); -module.exports = generateBase("control", handler); \ No newline at end of file diff --git a/chapters/control/lerp-cubic.js b/chapters/control/lerp-cubic.js new file mode 100644 index 00000000..8585f55e --- /dev/null +++ b/chapters/control/lerp-cubic.js @@ -0,0 +1,62 @@ +setup() { + const w = this.width, + h = this.height; + + this.f = [ + t => ({ x: t * w, y: h * (1-t) ** 3 }), + t => ({ x: t * w, y: h * 3 * (1-t) ** 2 * t }), + t => ({ x: t * w, y: h * 3 * (1-t) * t ** 2 }), + t => ({ x: t * w, y: h * t ** 3}) + ]; + + this.s = this.f.map(f => plot(f) ); +} + +draw() { + resetTransform(); + clear(); + setFill(`black`); + setStroke(`black`); + + scale(0.8, 0.9); + translate(40,20); + drawAxes(`t`, 0, 10, `S`, `0%`, `100%`, 40, 20); + + noFill(); + + this.s.forEach(s => { + setStroke( randomColor() ); + drawShape(s); + }) + + this.drawHighlight(); +} + +drawHighlight() { + if (this.cursor.down) { + + let c = screenToWorld(this.cursor); + if (c.x < 0) return; + if (c.x > this.width) return; + + noStroke(); + setFill(`rgba(255,0,0,0.3)`); + rect(c.x - 2, 0, 5, this.height); + + const p = this.f.map(f => f(c.x / this.width)); + + setFill(`black`); + p.forEach(p => { + circle(p.x, p.y, 3); + text(`${ round(100 * p.y/this.height) }%`, p.x + 10, p.y); + }); + } +} + +onMouseMove() { + redraw(); +} + +onMouseUp() { + redraw(); +} diff --git a/chapters/control/lerp-fifteenth.js b/chapters/control/lerp-fifteenth.js new file mode 100644 index 00000000..fb41bbf1 --- /dev/null +++ b/chapters/control/lerp-fifteenth.js @@ -0,0 +1,81 @@ +setup() { + this.degree = 15; + this.triangle = [[1], [1,1]]; + this.generate(); +} + +binomial(n,k) { + if (!this.triangle[n]) { + while(!this.triangle[n]) { + let last = this.triangle.slice(-1)[0]; + let next = last.map((v,i) => v + last[i+1]); + next.pop(); + this.triangle.push([1, ...next, 1]); + } + } + return this.triangle[n][k]; +} + +generate() { + const w = this.width, + h = this.height, + d = this.degree; + + this.f = [...new Array(d+1)].map((_,i) => { + return t => ({ + x: t * w, + y: h * this.binomial(d,i) * (1-t) ** (d-i) * t ** (i) + }); + }); + + this.s = this.f.map(f => plot(f, 0, 1, d*4) ); +} + +draw() { + resetTransform(); + clear(); + setFill(`black`); + setStroke(`black`); + + scale(0.8, 0.9); + translate(40,20); + drawAxes(`t`, 0, 10, `S`, `0%`, `100%`, 40, 20); + + noFill(); + + this.s.forEach(s => { + setStroke( randomColor() ); + drawShape(s); + }) + + this.drawHighlight(); +} + +drawHighlight() { + if (this.cursor.down) { + + let c = screenToWorld(this.cursor); + if (c.x < 0) return; + if (c.x > this.width) return; + + noStroke(); + setFill(`rgba(255,0,0,0.3)`); + rect(c.x - 2, 0, 5, this.height); + + const p = this.f.map(f => f(c.x / this.width)); + + setFill(`black`); + p.forEach(p => { + circle(p.x, p.y, 3); + text(`${ round(100 * p.y/this.height) }%`, p.x + 10, p.y); + }); + } +} + +onMouseMove() { + redraw(); +} + +onMouseUp() { + redraw(); +} diff --git a/chapters/control/lerp-quadratic.js b/chapters/control/lerp-quadratic.js new file mode 100644 index 00000000..e62887da --- /dev/null +++ b/chapters/control/lerp-quadratic.js @@ -0,0 +1,61 @@ +setup() { + const w = this.width, + h = this.height; + + this.f = [ + t => ({ x: t * w, y: h * (1-t) ** 2 }), + t => ({ x: t * w, y: h * 2 * (1-t) * t }), + t => ({ x: t * w, y: h * t ** 2 }) + ]; + + this.s = this.f.map(f => plot(f) ); +} + +draw() { + resetTransform(); + clear(); + setFill(`black`); + setStroke(`black`); + + scale(0.8, 0.9); + translate(40,20); + drawAxes(`t`, 0, 10, `S`, `0%`, `100%`, 40, 20); + + noFill(); + + this.s.forEach(s => { + setStroke( randomColor() ); + drawShape(s); + }) + + this.drawHighlight(); +} + +drawHighlight() { + if (this.cursor.down) { + + let c = screenToWorld(this.cursor); + if (c.x < 0) return; + if (c.x > this.width) return; + + noStroke(); + setFill(`rgba(255,0,0,0.3)`); + rect(c.x - 2, 0, 5, this.height); + + const p = this.f.map(f => f(c.x / this.width)); + + setFill(`black`); + p.forEach(p => { + circle(p.x, p.y, 3); + text(`${ round(100 * p.y/this.height) }%`, p.x + 10, p.y); + }); + } +} + +onMouseMove() { + redraw(); +} + +onMouseUp() { + redraw(); +} diff --git a/chapters/explanation/content.en-GB.md b/chapters/explanation/content.en-GB.md index 7a7edc59..578c74a2 100644 --- a/chapters/explanation/content.en-GB.md +++ b/chapters/explanation/content.en-GB.md @@ -41,7 +41,7 @@ There we go. x/y coordinates, linked through some mystery value y coordinate in terms of an x coordinate, like normal functions do, but they instead link the values to a "control" variable. If we vary the value of t, then with every change we get two values, which we can use as (x,y) coordinates in a graph. The above set of functions, for instance, generates points on a circle: We can range t from negative to positive infinity, and the resulting (x,y) coordinates will always lie on a circle with radius 1 around the origin (0,0). If we plot it for t from 0 to 5, we get this (use your up and down arrow keys to change the plot end value): - + Bézier curves are just one out of the many classes of parametric functions, and are characterised by using the same base function for all of the output values. In the example we saw above, the x and y values were generated by different functions (one uses a sine, the other a cosine); but Bézier curves use the "binomial polynomial" for both the x and y outputs. So what are binomial polynomials? diff --git a/chapters/explanation/content.ja-JP.md b/chapters/explanation/content.ja-JP.md index 79aeadb0..01aa1164 100644 --- a/chapters/explanation/content.ja-JP.md +++ b/chapters/explanation/content.ja-JP.md @@ -39,7 +39,7 @@ というわけで、普通の関数ではy座標をx座標によって定義しますが、パラメトリック曲線ではそうではなく、座標の値を「制御」変数と結びつけます。tの値を変化させるたびに2つの値が変化するので、これをグラフ上の座標 (x,y)として使うことができます。例えば、先ほどの関数の組は円周上の点を生成します。負の無限大から正の無限大へとtを動かすと、得られる座標(x,y)は常に中心(0,0)・半径1の円の上に乗ります。tを0から5まで変化させてプロットした場合は、このようになります(上下キーでプロットの上限を変更できます)。 - + ベジエ曲線はパラメトリック関数の一種であり、どの次元に対しても同じ基底関数を使うという点で特徴づけられます。先ほどの例では、xの値とyの値とで異なる関数(正弦関数と余弦関数)を使っていましたが、ベジエ曲線ではxyの両方で「二項係数多項式」を使います。では、二項係数多項式とは何でしょう? diff --git a/chapters/explanation/content.zh-CN.md b/chapters/explanation/content.zh-CN.md index 1feaec2a..c16ff7d9 100644 --- a/chapters/explanation/content.zh-CN.md +++ b/chapters/explanation/content.zh-CN.md @@ -39,7 +39,7 @@ 所以,参数曲线不像一般函数那样,通过x坐标来定义y坐标,而是用一个“控制”变量将它们连接起来。如果改变t的值,每次变化时我们都能得到两个值,这可以作为图形中的(x,y)坐标。比如上面的方程组,生成位于一个圆上的点:我们可以使t在正负极值间变化,得到的输出(x,y)都会位于一个以原点(0,0)为中心且半径为1的圆上。如果我们画出t从0到5时的值,将得到如下图像(你可以用上下键来改变画的点和值): - + 贝塞尔曲线是(一种)参数方程,并在它的多个维度上使用相同的基本方程。在上述的例子中x值和y值使用了不同的方程,与此不同的是,贝塞尔曲线的xy都用了“二项多项式”。那什么是二项多项式呢? diff --git a/chapters/introduction/content.en-GB.md b/chapters/introduction/content.en-GB.md index 557d3337..c2e52e45 100644 --- a/chapters/introduction/content.en-GB.md +++ b/chapters/introduction/content.en-GB.md @@ -3,8 +3,8 @@ Let's start with the good stuff: when we're talking about Bézier curves, we're talking about the things that you can see in the following graphics. They run from some start point to some end point, with their curvature influenced by one or more "intermediate" control points. Now, because all the graphics on this page are interactive, go manipulate those curves a bit: click-drag the points, and see how their shape changes based on what you do.
- - + +
These curves are used a lot in computer aided design and computer aided manufacturing (CAD/CAM) applications, as well as in graphic design programs like Adobe Illustrator and Photoshop, Inkscape, GIMP, etc. and in graphic technologies like scalable vector graphics (SVG) and OpenType fonts (TTF/OTF). A lot of things use Bézier curves, so if you want to learn more about them... prepare to get your learn on! diff --git a/chapters/introduction/content.ja-JP.md b/chapters/introduction/content.ja-JP.md index 5b2d004b..b3719637 100644 --- a/chapters/introduction/content.ja-JP.md +++ b/chapters/introduction/content.ja-JP.md @@ -3,8 +3,8 @@ まずは良い例から始めましょう。ベジエ曲線というのは、下の図に表示されているもののことです。ベジエ曲線はある始点からある終点へと延びており、その曲率は1個以上の「中間」制御点に左右されています。さて、このページの図はどれもインタラクティブになっていますので、ここで曲線をちょっと操作してみましょう。点をドラッグしたとき、曲線の形がそれに応じてどう変化するのか、確かめてみてください。
- - + +
ベジエ曲線は、CAD(computer aided designやCAM(computer aided manufacturing)のアプリケーションで多用されています。もちろん、Adobe Illustrator・Photoshop・Inkscape・Gimp などのグラフィックデザインアプリケーションや、SVG(scalable vector graphics)・OpenTypeフォント(otf/ttf)のようなグラフィック技術でも利用されています。ベジエ曲線はたくさんのものに使われていますので、これについてもっと詳しく学びたいのであれば……さあ、準備しましょう! diff --git a/chapters/introduction/content.zh-CN.md b/chapters/introduction/content.zh-CN.md index 4a09912b..5e1aaabe 100644 --- a/chapters/introduction/content.zh-CN.md +++ b/chapters/introduction/content.zh-CN.md @@ -3,8 +3,8 @@ 让我们有个好的开始:当我们在谈论贝塞尔曲线的时候,所指的就是你在如下图像看到的东西。它们从某些起点开始,到终点结束,并且受到一个或多个的“中间”控制点的影响。本页面上的图形都是可交互的,你可以拖动这些点,看看这些形状在你的操作下会怎么变化。
- - + +
这些曲线在计算机辅助设计和计算机辅助制造应用(CAD/CAM)中用的很多。在图形设计软件中也常用到,像Adobe Illustrator, Photoshop, Inkscape, Gimp等等。还可以应用在一些图形技术中,像矢量图形(SVG)和OpenType字体(ttf/otf)。许多东西都用到贝塞尔曲线,如果你想更了解它们...准备好继续往下学吧! diff --git a/chapters/toc.js b/chapters/toc.js index e6fd1f63..7e729dca 100644 --- a/chapters/toc.js +++ b/chapters/toc.js @@ -1,10 +1,5 @@ /** - * This is an ordered list of all sections used in the Bezier primer. - * - * The ordering you see here reflects the ordering in which sections - '* are present on the Primer page', - * a REALLY good reason to =) - * + * This is the section ordering used in the Primer. */ export default [ 'preface', @@ -61,7 +56,7 @@ export default [ // "things made of more than on curve" 'polybezier', 'shapes', - // 'drawing', + // 'drawing', // still just waiting to be finished...... // curve offsetting 'projections', diff --git a/index.html b/index.html index 91bf5893..88eedd03 100644 --- a/index.html +++ b/index.html @@ -912,21 +912,54 @@ function Bezier(3,t): curve-defining point at a specific t value.

- - + + + Scripts are disabled. Showing fallback image. + + - + + + Scripts are disabled. Showing fallback image. + + + width="275" + height="275" + src="./chapters/control/lerp-fifteenth.js" + > + + + Scripts are disabled. Showing fallback image. +

@@ -967,11 +1000,22 @@ function Bezier(3,t): loading="lazy" />

Which gives us the curve we saw at the top of the article:

- + width="275" + height="275" + src="./chapters/control/../introduction/cubic.js" + > + + + Scripts are disabled. Showing fallback image. +

What else can we do with Bézier curves? Quite a lot, actually. The diff --git a/lib/custom-element/api/base-api.js b/lib/custom-element/api/base-api.js index 3dbe01cc..c2d70c4a 100644 --- a/lib/custom-element/api/base-api.js +++ b/lib/custom-element/api/base-api.js @@ -63,6 +63,8 @@ class BaseAPI { this.cursor = {}; + const release = typeof document !== "undefined" ? document : canvas; + [`touchstart`, `mousedown`].forEach((evtName) => canvas.addEventListener(evtName, (evt) => this.onMouseDown(evt)) ); @@ -72,7 +74,7 @@ class BaseAPI { ); [`touchend`, `mouseup`].forEach((evtName) => - canvas.addEventListener(evtName, (evt) => this.onMouseUp(evt)) + release.addEventListener(evtName, (evt) => this.onMouseUp(evt)) ); this.keyboard = {}; @@ -82,7 +84,7 @@ class BaseAPI { ); [`keyup`].forEach((evtName) => - canvas.addEventListener(evtName, (evt) => this.onKeyUp(evt)) + release.addEventListener(evtName, (evt) => this.onKeyUp(evt)) ); } @@ -91,13 +93,13 @@ class BaseAPI { */ getCursorCoords(evt) { const left = evt.target.offsetLeft, - top = evt.target.offsetTop; + top = evt.target.offsetTop; let x, y; if (evt.targetTouches) { const touch = evt.targetTouches; - for (let i=0; i this.forceFocus(); + canvas._force_listener = () => { + // I have NO idea why forceFocus() causes a scroll, but + // I don't have time to dig into what is no doubt deep + // black spec magic, so: check where we are, force the + // focus() state, and then force the scroll position to + // what it should be. + const x = Math.round(window.scrollX); + const y = Math.round(window.scrollY); + // Oh yeah... using round() because apparently scrollTo + // is not NOT idempotent and rounding errors cause it to + // drift. IT'S FUCKING HILARIOUS + this.forceFocus(); + window.scrollTo(x, y); + }; [`touchstart`, `mousedown`].forEach((evtName) => canvas.addEventListener(evtName, canvas._force_listener) ); @@ -254,6 +269,7 @@ function enhanceContext(ctx) { strokeStyle: ctx.strokeStyle, fillStyle: ctx.fillStyle, lineWidth: ctx.lineWidth, + textAlign: ctx.textAlign, transform: [m.a, m.b, m.c, m.d, m.e, m.f], }; styles.push(e); diff --git a/lib/custom-element/api/graphics-api.js b/lib/custom-element/api/graphics-api.js index 5222b890..44d36bb8 100644 --- a/lib/custom-element/api/graphics-api.js +++ b/lib/custom-element/api/graphics-api.js @@ -7,12 +7,30 @@ import { BaseAPI } from "./base-api.js"; const MOUSE_PRECISION_ZONE = 5; const TOUCH_PRECISION_ZONE = 30; +let CURRENT_HUE = 0; + /** * Our Graphics API, which is the "public" side of the API. */ class GraphicsAPI extends BaseAPI { static get constants() { - return [`POINTER`, `HAND`, `PI`, `TAU`, `POLYGON`, `CURVE`, `BEZIER`]; + return [ + `POINTER`, + `HAND`, + `PI`, + `TAU`, + `POLYGON`, + `CURVE`, + `BEZIER`, + `CENTER`, + `LEFT`, + `RIGHT`, + ]; + } + + draw() { + CURRENT_HUE = 0; + super.draw(); } get PI() { @@ -36,11 +54,22 @@ class GraphicsAPI extends BaseAPI { get BEZIER() { return Shape.BEZIER; } + get CENTER() { + return `center`; + } + get LEFT() { + return `left`; + } + get RIGHT() { + return `right`; + } onMouseDown(evt) { super.onMouseDown(evt); - const cdist = evt.targetTouches ? TOUCH_PRECISION_ZONE : MOUSE_PRECISION_ZONE; + const cdist = evt.targetTouches + ? TOUCH_PRECISION_ZONE + : MOUSE_PRECISION_ZONE; for (let i = 0, e = this.moveable.length, p, d; i < e; i++) { p = this.moveable[i]; @@ -92,6 +121,51 @@ class GraphicsAPI extends BaseAPI { this.ctx.rotate(angle); } + /** + * transforms: scale + */ + scale(x, y) { + y = y ?? x; + this.ctx.scale(x, y); + } + /** + * transforms: screen to world + */ + screenToWorld(x, y) { + if (y === undefined) { + y = x.y; + x = x.x; + } + + let M = this.ctx.getTransform().invertSelf(); + + let ret = { + x: x * M.a + y * M.c + M.e, + y: x * M.b + y * M.d + M.f, + }; + + return ret; + } + + /** + * transforms: world to screen + */ + worldToScreen(x, y) { + if (y === undefined) { + y = x.y; + x = x.x; + } + + let M = this.ctx.getTransform(); + + let ret = { + x: x * M.a + y * M.c + M.e, + y: x * M.b + y * M.d + M.f, + }; + + return ret; + } + /** * transforms: reset */ @@ -131,6 +205,14 @@ class GraphicsAPI extends BaseAPI { this.canvas.style.cursor = type; } + /** + * Get a random color + */ + randomColor(a = 1.0) { + CURRENT_HUE = (CURRENT_HUE + 73) % 360; + return `hsla(${CURRENT_HUE},50%,50%,${a})`; + } + /** * Set the context fillStyle */ @@ -209,12 +291,18 @@ class GraphicsAPI extends BaseAPI { /** * Draw text on the canvas */ - text(str, x, y) { + text(str, x, y, alignment) { if (y === undefined) { y = x.y; x = x.x; } + const ctx = this.ctx; + if (alignment) { + ctx.cacheStyle(); + ctx.textAlign = alignment; + } this.ctx.fillText(str, x, y); + if (alignment) ctx.restoreStyle(); } /** @@ -225,6 +313,25 @@ class GraphicsAPI extends BaseAPI { this.ctx.strokeRect(x, y, w, h); } + /** + * Draw a function plot from [start] to [end] in [steps] steps. + * Returns the plot shape so that it can be cached for redrawing. + */ + plot(fn, start = 0, end = 1, steps = 24) { + const ctx = this.ctx; + ctx.cacheStyle(); + ctx.fillStyle = `transparent`; + const interval = end - start; + this.start(); + for (let i = 0, e = steps - 1, v; i < steps; i++) { + v = fn(start + (interval * i) / e); + this.vertex(v.x, v.y); + } + this.end(); + ctx.restoreStyle(); + return this.currentShape; + } + /** * A signal for starting a complex shape */ @@ -246,6 +353,14 @@ class GraphicsAPI extends BaseAPI { this.currentShape.vertex({ x, y }); } + /** + * Draw a previously created shape + */ + drawShape(shape) { + this.currentShape = shape; + this.end(); + } + /** * A signal to draw the current complex shape */ @@ -254,12 +369,56 @@ class GraphicsAPI extends BaseAPI { let { x, y } = this.currentShape.first; this.ctx.moveTo(x, y); this.currentShape.segments.forEach((s) => - this[`draw${s.type}`](this.ctx, s.points, s.factor) + this[`draw${s.type}`](s.points, s.factor) ); this.ctx.fill(); this.ctx.stroke(); } + /** + * Polygon draw function + */ + drawPolygon(points) { + points.forEach((p) => this.ctx.lineTo(p.x, p.y)); + } + + /** + * Curve draw function, which draws a CR curve as a series of Beziers + */ + drawCatmullRom(points, f) { + // invent a virtual first and last point + const f0 = points[0], + f1 = points[1], + fn = f0.reflect(f1), + l1 = points[points.length - 2], + l0 = points[points.length - 1], + ln = l0.reflect(l1), + cpoints = [fn, ...points, ln]; + + // four point sliding window over the segment + for (let i = 0, e = cpoints.length - 3; i < e; i++) { + let [c1, c2, c3, c4] = cpoints.slice(i, i + 4); + let p2 = { + x: c2.x + (c3.x - c1.x) / (6 * f), + y: c2.y + (c3.y - c1.y) / (6 * f), + }; + let p3 = { + x: c3.x - (c4.x - c2.x) / (6 * f), + y: c3.y - (c4.y - c2.y) / (6 * f), + }; + this.ctx.bezierCurveTo(p2.x, p2.y, p3.x, p3.y, c3.x, c3.y); + } + } + + /** + * Curve draw function, which assumes Bezier coordinates + */ + drawBezier(points) { + for (let i = 0, e = points.length; i < e; i += 3) { + let [p1, p2, p3] = points.slice(i, i + 3); + this.ctx.bezierCurveTo(p1.x, p1.y, p2.x, p2.y, p3.x, p3.y); + } + } /** * Yield a snapshot of the current shape. */ @@ -267,14 +426,6 @@ class GraphicsAPI extends BaseAPI { return this.currentShape; } - /** - * Draw a previously created shape - */ - drawShape(shape) { - this.currentShape = shape; - this.end(); - } - /** * convenient grid drawing function */ @@ -287,6 +438,30 @@ class GraphicsAPI extends BaseAPI { } } + /** + * convenient axis drawing function + * + * api.drawAxes(pad, "t",0,1, "S","0%","100%"); + * + */ + drawAxes(hlabel, hs, he, vlabel, vs, ve) { + const h = this.height; + const w = this.width; + + this.line(0, 0, w, 0); + this.line(0, 0, 0, h); + + const hpos = 0 - 5; + this.text(`${hlabel} →`, this.width / 2, hpos, this.CENTER); + this.text(hs, 0, hpos, this.CENTER); + this.text(he, w, hpos, this.CENTER); + + const vpos = -10; + this.text(`${vlabel}\n↓`, vpos, this.height / 2, this.RIGHT); + this.text(vs, vpos, 0 + 5, this.RIGHT); + this.text(ve, vpos, h, this.RIGHT); + } + /** * math functions */ diff --git a/lib/custom-element/api/types/bezier.js b/lib/custom-element/api/types/bezier.js index fbae1100..8ecb6ced 100644 --- a/lib/custom-element/api/types/bezier.js +++ b/lib/custom-element/api/types/bezier.js @@ -5,11 +5,11 @@ import { Bezier as Original } from "../../lib/bezierjs/bezier.js"; */ class Bezier extends Original { static defaultQuadratic(apiInstance) { - return new Bezier(apiInstance, 70,250, 20,110, 220,60); + return new Bezier(apiInstance, 70, 250, 20, 110, 220, 60); } static defaultCubic(apiInstance) { - return new Bezier(apiInstance, 110,150, 25,190, 210,250, 210,30); + return new Bezier(apiInstance, 110, 150, 25, 190, 210, 250, 210, 30); } constructor(apiInstance, ...coords) { diff --git a/lib/custom-element/api/types/vector.js b/lib/custom-element/api/types/vector.js index 591dbfcd..c67832ca 100644 --- a/lib/custom-element/api/types/vector.js +++ b/lib/custom-element/api/types/vector.js @@ -1,80 +1,77 @@ class Vector { - constructor(x, y, z) { - if (arguments.length === 1) { - z = x.z; - y = x.y; - x = x.x; - } - this.x = x; - this.y = y; - if (z !== undefined) { - this.z = z; - } + constructor(x, y, z) { + if (arguments.length === 1) { + z = x.z; + y = x.y; + x = x.x; } - dist(other, y, z = 0) { - if (y !== undefined) other = { x: other, y, z }; - let sum = 0; - sum += (this.x - other.x) ** 2; - sum += (this.y - other.y) ** 2; - let z1 = this.z ?? 0; - let z2 = other.z ?? 0; - sum += (z1 - z2) ** 2; - return sum ** 0.5; - } - normalize(f) { - let mag = this.dist(0, 0, 0); - return new Vector( - (f * this.x) / mag, - (f * this.y) / mag, - (f * this.z) / mag - ); - } - getAngle() { - return -Math.atan2(this.y, this.x); - } - reflect(other) { - let p = new Vector( - other.x - this.x, - other.y - this.y - ); - if (other.z !== undefined) { - p.z = other.z - if (this.z !== undefined) { - p.z -= this.z; - } - } - return this.subtract(p); - } - add(other) { - let p = new Vector(this.x + other.x, this.y + other.y); - if (this.z !== undefined) { - p.z = this.z; - if (other.z !== undefined) { - p.z += other.z; - } - } - return p; - } - subtract(other) { - let p = new Vector(this.x - other.x, this.y - other.y); - if (this.z !== undefined) { - p.z = this.z; - if (other.z !== undefined) { - p.z -= other.z; - } - } - return p; - } - scale(f = 1) { - if (f === 0) { - return new Vector(0, 0, this.z === undefined ? undefined : 0); - } - let p = new Vector(this.x * f, this.y * f); - if (this.z !== undefined) { - p.z = this.z * f; - } - return p; + this.x = x; + this.y = y; + if (z !== undefined) { + this.z = z; } } + dist(other, y, z = 0) { + if (y !== undefined) other = { x: other, y, z }; + let sum = 0; + sum += (this.x - other.x) ** 2; + sum += (this.y - other.y) ** 2; + let z1 = this.z ?? 0; + let z2 = other.z ?? 0; + sum += (z1 - z2) ** 2; + return sum ** 0.5; + } + normalize(f) { + let mag = this.dist(0, 0, 0); + return new Vector( + (f * this.x) / mag, + (f * this.y) / mag, + (f * this.z) / mag + ); + } + getAngle() { + return -Math.atan2(this.y, this.x); + } + reflect(other) { + let p = new Vector(other.x - this.x, other.y - this.y); + if (other.z !== undefined) { + p.z = other.z; + if (this.z !== undefined) { + p.z -= this.z; + } + } + return this.subtract(p); + } + add(other) { + let p = new Vector(this.x + other.x, this.y + other.y); + if (this.z !== undefined) { + p.z = this.z; + if (other.z !== undefined) { + p.z += other.z; + } + } + return p; + } + subtract(other) { + let p = new Vector(this.x - other.x, this.y - other.y); + if (this.z !== undefined) { + p.z = this.z; + if (other.z !== undefined) { + p.z -= other.z; + } + } + return p; + } + scale(f = 1) { + if (f === 0) { + return new Vector(0, 0, this.z === undefined ? undefined : 0); + } + let p = new Vector(this.x * f, this.y * f); + if (this.z !== undefined) { + p.z = this.z * f; + } + return p; + } +} - export { Vector }; +export { Vector }; diff --git a/lib/custom-element/api/util/shape.js b/lib/custom-element/api/util/shape.js index 2e5f10b7..fd9c64d2 100644 --- a/lib/custom-element/api/util/shape.js +++ b/lib/custom-element/api/util/shape.js @@ -1,17 +1,3 @@ -/** - * A shape subpath - */ -class Segment { - constructor(type, factor) { - this.type = type; - this.factor = factor; - this.points = []; - } - add(p) { - this.points.push(p); - } -} - /** * A complex shape, represented as a collection of paths * that can be either polygon, Catmull-Rom curves, or @@ -40,4 +26,18 @@ Shape.POLYGON = `Polygon`; Shape.CURVE = `CatmullRom`; Shape.BEZIER = `Bezier`; +/** + * A shape subpath + */ +class Segment { + constructor(type, factor) { + this.type = type; + this.factor = factor; + this.points = []; + } + add(p) { + this.points.push(p); + } +} + export { Shape, Segment }; diff --git a/lib/custom-element/custom-element.js b/lib/custom-element/custom-element.js index a7cddb16..a6abf7cf 100644 --- a/lib/custom-element/custom-element.js +++ b/lib/custom-element/custom-element.js @@ -42,14 +42,14 @@ class CustomElement extends HTMLElement { super(); if (!customElements.resolveScope) { - customElements.resolveScope = function(scope) { + customElements.resolveScope = function (scope) { try { return scope.getRootNode().host; } catch (e) { console.warn(e); } return window; - } + }; } this._options = options; @@ -63,7 +63,11 @@ class CustomElement extends HTMLElement { this.render(); }, attributes: (record) => { - this.handleAttributeChange(record.attributeName, record.oldValue, this.getAttribute(record.attributeName)); + this.handleAttributeChange( + record.attributeName, + record.oldValue, + this.getAttribute(record.attributeName) + ); this.render(); }, }; diff --git a/lib/custom-element/graphics-element.js b/lib/custom-element/graphics-element.js index 4dbe1f5e..58977d6c 100644 --- a/lib/custom-element/graphics-element.js +++ b/lib/custom-element/graphics-element.js @@ -35,7 +35,8 @@ class GraphicsElement extends CustomElement { :host style { display: none; } :host canvas { display: block; margin: auto; border-radius: 0; } :host canvas:focus { ${ - this.getAttribute(`focus-css`) || `border: 1px solid red !important; margin: -1px; ` + this.getAttribute(`focus-css`) || + `border: 1px solid red !important; margin: -1px; ` } } :host a.view-source { float: left; font-size: 60%; text-decoration: none; } :host label { display: block; font-style:italic; font-size: 0.9em; text-align: right; } @@ -160,7 +161,9 @@ class GraphicsElement extends CustomElement { const script = (this.script = document.createElement(`script`)); script.type = "module"; - script.src = `data:application/javascript;charset=utf-8,${encodeURIComponent(this.code)}`; + script.src = `data:application/javascript;charset=utf-8,${encodeURIComponent( + this.code + )}`; if (rerender) this.render(); } @@ -219,10 +222,12 @@ class GraphicsElement extends CustomElement { if (this.canvas) slotParent.insertBefore(this.canvas, this._slot); if (this.label) slotParent.insertBefore(this.label, this._slot); - const a = document.createElement('a'); - a.classList.add('view-source'); + const a = document.createElement("a"); + a.classList.add("view-source"); a.textContent = `view source`; - a.href = new URL(`data:text/plain;charset=utf-8,${encodeURIComponent(this.rawCode)}`); + a.href = new URL( + `data:text/plain;charset=utf-8,${encodeURIComponent(this.rawCode)}` + ); a.target = `_blank`; if (this.label) slotParent.insertBefore(a, this.label); } diff --git a/lib/custom-element/lib/perform-code-surgery.js b/lib/custom-element/lib/perform-code-surgery.js index d83c1512..c6ff6c19 100644 --- a/lib/custom-element/lib/perform-code-surgery.js +++ b/lib/custom-element/lib/perform-code-surgery.js @@ -1,7 +1,6 @@ import { GraphicsAPI } from "../api/graphics-api.js"; export default function performCodeSurgery(code) { - // 1. ensure that anything that needs to run by first calling its super function, does so. GraphicsAPI.superCallers.forEach((name) => { diff --git a/lib/custom-element/lib/split-code-sections.js b/lib/custom-element/lib/split-code-sections.js index c603a18e..f3c96785 100644 --- a/lib/custom-element/lib/split-code-sections.js +++ b/lib/custom-element/lib/split-code-sections.js @@ -3,37 +3,37 @@ * We're going to regexp our way to flawed victory here. */ export default function splitCodeSections(code) { - const re = /\b[\w\W][^\s]*?\([^)]*\)[\r\n\s]*{/; - const cuts = []; - for(let result = code.match(re); result; result=code.match(re)) { - result = result[0]; + const re = /\b[\w\W][^\s]*?\([^)]*\)[\r\n\s]*{/; + const cuts = []; + for (let result = code.match(re); result; result = code.match(re)) { + result = result[0]; - let start = code.indexOf(result); - let end = start + result.length; - let depth = 0; - let slice = Array.from(code).slice(start + result.length); + let start = code.indexOf(result); + let end = start + result.length; + let depth = 0; + let slice = Array.from(code).slice(start + result.length); - slice.some((c,pos) => { - if (c === `{`) { - depth++; + slice.some((c, pos) => { + if (c === `{`) { + depth++; + return false; + } + if (c === `}`) { + if (depth > 0) { + depth--; return false; } - if (c === `}`) { - if (depth > 0) { - depth--; - return false; - } - end += pos + 1; - return true; - } - }); + end += pos + 1; + return true; + } + }); - let cut = code.slice(start, end); - cuts.push(cut); - code = code.replace(cut, ``); - } - return { - quasiGlobal: code, - classCode: cuts.join(`\n`) - }; - } \ No newline at end of file + let cut = code.slice(start, end); + cuts.push(cut); + code = code.replace(cut, ``); + } + return { + quasiGlobal: code, + classCode: cuts.join(`\n`), + }; +} diff --git a/lib/site/referrer.js b/lib/site/referrer.js index 1118d060..6884c395 100644 --- a/lib/site/referrer.js +++ b/lib/site/referrer.js @@ -24,16 +24,28 @@ * */ (function referrer(l) { - var page = l.substring(l.lastIndexOf('/')+1).replace(".html",''); + var page = l.substring(l.lastIndexOf("/") + 1).replace(".html", ""); page = page || "index.html"; // we don't care about file or localhost, for obvious reasons var loc = window.location.toString(); - if(loc.indexOf("file:///")!==-1) return; - if(loc.indexOf("localhost")!==-1) return; + if (loc.indexOf("file:///") !== -1) return; + if (loc.indexOf("localhost") !== -1) return; // right, continue var url = "http://pomax.nihongoresources.com/pages/bezierinfo/logger.php"; var xhr = new XMLHttpRequest(); - xhr.open("GET", url + "?" + "referrer=" + encodeURIComponent(document.referrer) + "&for=" + page, true); - try { xhr.send(null); } - catch(e) { /* you don't care about this error, and I can't see it, so why would we do anything with it? */ } -}(window.location.toString())); + xhr.open( + "GET", + url + + "?" + + "referrer=" + + encodeURIComponent(document.referrer) + + "&for=" + + page, + true + ); + try { + xhr.send(null); + } catch (e) { + /* you don't care about this error, and I can't see it, so why would we do anything with it? */ + } +})(window.location.toString()); diff --git a/lib/site/social-updater.js b/lib/site/social-updater.js index 45d862a4..89c52095 100644 --- a/lib/site/social-updater.js +++ b/lib/site/social-updater.js @@ -4,7 +4,6 @@ * base article itself. */ (function tryToBind() { - if (!document.querySelector(`map[name="rhtimap"]`)) { return setTimeout(tryToBind, 300); } @@ -13,33 +12,37 @@ constructor() { this.section = false; this.hash = false; - this.socials = ["rdt","hn","twt"]; + this.socials = ["rdt", "hn", "twt"]; } update(data) { this.section = data.section; this.hash = data.hash; - this.socials.forEach(social => { + this.socials.forEach((social) => { var area = document.querySelector(`map area.sclnk-${social}`); area.href = this[`get_${social}`](); }); } get url() { - return encodeURIComponent(`https://pomax.github.io/bezierinfo${this.hash ? this.hash : ''}`); + return encodeURIComponent( + `https://pomax.github.io/bezierinfo${this.hash ? this.hash : ""}` + ); } getTitle() { var title = `A Primer on Bézier Curves`; if (this.section) { - title = `${this.section}-${title}`; + title = `${this.section}-${title}`; } return encodeURIComponent(title); } get_rdt() { var title = this.getTitle(); - var text = encodeURIComponent(`A free, online book for when you really need to know how to do Bézier things.`); + var text = encodeURIComponent( + `A free, online book for when you really need to know how to do Bézier things.` + ); return `https://www.reddit.com/submit?url=${this.url}&title=${title}&text=${text}`; } @@ -49,32 +52,40 @@ } get_twt() { - var text = encodeURIComponent(`Reading "${this.section}" by @TheRealPomax over on `) + this.url; + var text = + encodeURIComponent( + `Reading "${this.section}" by @TheRealPomax over on ` + ) + this.url; return `https://twitter.com/intent/tweet?original_referer=${this.url}&text=${text}&hashtags=bezier,curves,maths`; } - }; - + } // we set the section and fragmentid based on which ever section's heading is nearest // the top of the screen, either just off-screen or in-screen var tracker = new Tracker(); var anchors = Array.from(document.querySelectorAll("section h2 a")); - var sections = anchors.map(a => a.parentNode); - var sectionData = sections.map(section => { + var sections = anchors.map((a) => a.parentNode); + var sectionData = sections.map((section) => { return { section: section.textContent, - hash: section.querySelector("a").hash + hash: section.querySelector("a").hash, }; }); - window.addEventListener("scroll", function(evt) { - var min = 99999999999999999; - var element = false; - sections.forEach( (s,pos) => { - var v = Math.abs(s.getBoundingClientRect().top); - if (v < min) { min = v; element = pos; } - }); - tracker.update(sectionData[element]); - }, { passive: true }); - -}()); + window.addEventListener( + "scroll", + function (evt) { + var min = 99999999999999999; + var element = false; + sections.forEach((s, pos) => { + var v = Math.abs(s.getBoundingClientRect().top); + if (v < min) { + min = v; + element = pos; + } + }); + tracker.update(sectionData[element]); + }, + { passive: true } + ); +})(); diff --git a/package-lock.json b/package-lock.json index c9afac72..91d9938f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -280,10 +280,6 @@ "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", "dev": true }, - "codesurgeon": { - "version": "file:lib/custom-element", - "dev": true - }, "color-convert": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", diff --git a/package.json b/package.json index 065dc162..db113c39 100644 --- a/package.json +++ b/package.json @@ -8,19 +8,21 @@ "homepage": "https://pomax.github.io/bezierinfo", "repository": { "type": "git", - "url": "git+https://github.com/Pomax/bezierinfo.git" + "url": "git+https://github.com/Pomax/BezierInfo-2.git" }, "bugs": { - "url": "https://github.com/Pomax/bezierinfo/issues" + "url": "https://github.com/Pomax/BezierInfo-2/issues" }, "scripts": { - "time": "node ./mark.js", - "start": "run-s time lint build time", - "lint": "prettier ./tools --write", - "build": "node ./tools/build.js", + "start": "rm -f .timing && run-s time lint:* build time", "test": "run-p server browser", + "---": "---", + "browser": "open-cli http://localhost:8000", + "build": "node ./tools/build.js", + "lint:tools": "prettier ./tools --write", + "lint:lib": "prettier ./lib --write", "server": "http-server -p 8000 --cors", - "browser": "open-cli http://localhost:8000" + "time": "node ./mark.js" }, "keywords": [ "Bezier", @@ -33,7 +35,6 @@ "devDependencies": { "bezier-js": "^2.6.1", "canvas": "^2.6.1", - "codesurgeon": "file:./lib/custom-element", "fs-extra": "^9.0.1", "glob": "^7.1.6", "http-server": "^0.12.3", diff --git a/tools/build.js b/tools/build.js index fb56f05b..fe6cf128 100644 --- a/tools/build.js +++ b/tools/build.js @@ -1,7 +1,7 @@ import LocaleStrings from "./locale-strings.js"; -import getAllChapterFiles from "./build/get-all-chapter-files.js"; -import processLocale from "./build/process-locale.js"; -import createIndexPages from "./build/create-index-page.js"; +import { getAllChapterFiles } from "./build/get-all-chapter-files.js"; +import { processLocale } from "./build/process-locale.js"; +import { createIndexPages } from "./build/create-index-page.js"; /** * main entry point: @@ -10,6 +10,7 @@ import createIndexPages from "./build/create-index-page.js"; */ getAllChapterFiles().then((chapterFiles) => { const languageCodes = Object.keys(chapterFiles); + languageCodes.forEach(async (locale) => { const localeStrings = new LocaleStrings(locale); const chapters = await processLocale(locale, localeStrings, chapterFiles); diff --git a/tools/build/create-index-page.js b/tools/build/create-index-page.js index ec5bb450..aaf36dce 100644 --- a/tools/build/create-index-page.js +++ b/tools/build/create-index-page.js @@ -11,11 +11,7 @@ nunjucks.configure(".", { autoescape: false }); /** * ...docs go here... */ -export default async function createIndexPages( - locale, - localeStrings, - chapters -) { +async function createIndexPages(locale, localeStrings, chapters) { const defaultLocale = localeStrings.getDefaultLocale(); const base = locale !== defaultLocale ? `` : ``; const langSwitcher = generateLangSwitcher(localeStrings); @@ -70,3 +66,5 @@ export default async function createIndexPages( fs.writeFileSync(path.join(locale, `index.html`), data, `utf8`); } } + +export { createIndexPages }; diff --git a/tools/build/get-all-chapter-files.js b/tools/build/get-all-chapter-files.js index acf1a55d..7c3ac581 100644 --- a/tools/build/get-all-chapter-files.js +++ b/tools/build/get-all-chapter-files.js @@ -9,7 +9,8 @@ const BASEDIR = path.join(__dirname, "..", ".."); /** * ...docs go here... */ -export default /* async */ function getAllChapterFiles() { + +/* async */ function getAllChapterFiles() { return new Promise((resolve, reject) => { glob(path.join(BASEDIR, `chapters/**/content*md`), (err, files) => { if (err) reject(err); @@ -28,3 +29,5 @@ export default /* async */ function getAllChapterFiles() { }); }); } + +export { getAllChapterFiles }; diff --git a/tools/build/rewrite-graphics-element.js b/tools/build/graphics/generate-graphics-module.js similarity index 70% rename from tools/build/rewrite-graphics-element.js rename to tools/build/graphics/generate-graphics-module.js index f3af449f..2164fb6c 100644 --- a/tools/build/rewrite-graphics-element.js +++ b/tools/build/graphics/generate-graphics-module.js @@ -1,8 +1,11 @@ -import splitCodeSections from "../../lib/custom-element/lib/split-code-sections.js"; -import performCodeSurgery from "../../lib/custom-element/lib/perform-code-surgery.js"; +import splitCodeSections from "../../../lib/custom-element/lib/split-code-sections.js"; +import performCodeSurgery from "../../../lib/custom-element/lib/perform-code-surgery.js"; import prettier from "prettier"; -export default function rewriteGraphicsElement(code, width, height) { +/** + * ...docs go here... + */ +function generateGraphicsModule(code, width, height) { const split = splitCodeSections(code); const globalCode = split.quasiGlobal; const classCode = performCodeSurgery(split.classCode); @@ -10,7 +13,7 @@ export default function rewriteGraphicsElement(code, width, height) { return prettier.format( ` import CanvasBuilder from 'canvas'; - import { GraphicsAPI, Bezier, Vector } from "../../lib/custom-element/api/graphics-api.js"; + import { GraphicsAPI, Bezier, Vector } from "../../../lib/custom-element/api/graphics-api.js"; const noop = (()=>{}); @@ -37,3 +40,5 @@ export default function rewriteGraphicsElement(code, width, height) { { parser: `babel` } ); } + +export { generateGraphicsModule }; diff --git a/tools/build/generate-placeholders.js b/tools/build/graphics/generate-placeholders.js similarity index 77% rename from tools/build/generate-placeholders.js rename to tools/build/graphics/generate-placeholders.js index 8bb50462..2c8bb881 100644 --- a/tools/build/generate-placeholders.js +++ b/tools/build/graphics/generate-placeholders.js @@ -1,11 +1,14 @@ import fs from "fs-extra"; import path from "path"; -import rewriteGraphicsElement from "./rewrite-graphics-element.js"; +import { generateGraphicsModule } from "./generate-graphics-module.js"; const moduleURL = new URL(import.meta.url); const __dirname = path.dirname(moduleURL.href.replace(`file:///`, ``)); -export default async function generatePlaceHolders(localeStrings, markdown) { +/** + * ...docs go here... + */ +async function generatePlaceHolders(localeStrings, markdown) { const locale = localeStrings.getCurrentLocale(); if (locale !== localeStrings.getDefaultLocale()) return; @@ -36,20 +39,27 @@ export default async function generatePlaceHolders(localeStrings, markdown) { sourcePaths.map(async (srcPath, i) => { try { // Get the sketch code - const sourcePath = path.join(__dirname, "..", "..", srcPath); - const code = fs.readFileSync(sourcePath).toString(`utf8`); + const sourcePath = path.join(__dirname, "..", "..", "..", srcPath); + let code; + try { + code = fs.readFileSync(sourcePath).toString(`utf8`); + } catch (e) { + console.log(srcPath, sourcePath); + throw e; + } const width = elements[keys[i]].match(`width="([^"]+)"`)[1]; const height = elements[keys[i]].match(`height="([^"]+)"`)[1]; // Convert this to a valid JS module code and write this to // a temporary file so we can import it. - const nodeCode = rewriteGraphicsElement(code, width, height); + const nodeCode = generateGraphicsModule(code, width, height); const fileName = `./nodecode.${Date.now()}.${Math.random()}.js`; const tempFile = path.join(__dirname, fileName); fs.writeFileSync(tempFile, nodeCode, `utf8`); // Import our entirely valid JS module, which will run the - // sketch code and + // sketch code and export a canvas instance that we can turn + // into an actual image file. const { canvas } = await import(fileName); fs.unlinkSync(tempFile); @@ -59,6 +69,7 @@ export default async function generatePlaceHolders(localeStrings, markdown) { const imageData = Buffer.from(dataURI.substring(start), `base64`); const destPath = path.join(__dirname, "..", "..", "images", srcPath); const filename = destPath.replace(`.js`, `.png`); + // console.log(`Writing placeholder to ${filename}`); fs.ensureDirSync(path.dirname(destPath)); fs.writeFileSync(filename, imageData); @@ -68,3 +79,5 @@ export default async function generatePlaceHolders(localeStrings, markdown) { }) ); } + +export { generatePlaceHolders }; diff --git a/tools/build/convert-markdown.js b/tools/build/markdown/convert-markdown.js similarity index 52% rename from tools/build/convert-markdown.js rename to tools/build/markdown/convert-markdown.js index e0f7211b..ff095db4 100644 --- a/tools/build/convert-markdown.js +++ b/tools/build/markdown/convert-markdown.js @@ -1,27 +1,30 @@ import marked from "marked"; -import latexToSVG from "./latex/latex-to-svg.js"; -import injectGraphicsFallback from "./markdown/inject-fallback.js"; -import extractLaTeX from "./markdown/extract-latex.js"; +import latexToSVG from "../latex/latex-to-svg.js"; +import preprocessGraphicsElement from "./preprocess-graphics-element.js"; +import extractLaTeX from "./extract-latex.js"; import nunjucks from "nunjucks"; nunjucks.configure(".", { autoescape: false }); /** * ...docs go here... */ -export default async function convertMarkDown( - chapter, - localeStrings, - markdown -) { - markdown = injectGraphicsFallback(chapter, localeStrings, markdown); +async function convertMarkDown(chapter, localeStrings, markdown) { + markdown = preprocessGraphicsElement(chapter, localeStrings, markdown); + // This yields the original markdown with all LaTeX blocked replaced with + // uniquely named templating variables, referencing keys in the `latex` array. const { data, latex } = extractLaTeX(markdown); await Promise.all( - Object.keys(latex).map(async (key, pos) => { - const svg = await latexToSVG(latex[key], chapter, localeStrings, pos + 1); - return (latex[key] = svg); - }) + Object.keys(latex).map( + async (key, pos) => + (latex[key] = await latexToSVG( + latex[key], + chapter, + localeStrings, + pos + 1 + )) + ) ); let converted = marked(data, { @@ -44,3 +47,5 @@ export default async function convertMarkDown( return nunjucks.renderString(converted, latex); } + +export { convertMarkDown }; diff --git a/tools/build/markdown/inject-fallback.js b/tools/build/markdown/inject-fallback.js deleted file mode 100644 index e3a9326a..00000000 --- a/tools/build/markdown/inject-fallback.js +++ /dev/null @@ -1,39 +0,0 @@ -/** - * ...docs go here... - */ -export default function injectGraphicsFallback( - chapter, - localeStrings, - markdown -) { - const translate = localeStrings.translate; - - let pos = -1, - data = markdown, - startmark = ``; - - do { - pos = data.indexOf(startmark, pos); - if (pos !== -1) { - let endpos = data.indexOf(endmark, pos) + endmark.length; - let slice = data.slice(pos, endpos); - let updated = slice.replace( - /width="([^"]+)"\s+height="([^"]+)"\s+src="([^"]+)"\s*>/, - (_, width, height, src) => { - src = src.replace(`./`, `./chapters/${chapter}/`); - let img = src.replace(`./`, `./images/`).replace(`.js`, `.png`); - return `width="${width}" height="${height}" src="${src}"> - - - ${translate`disabledMessage`} - `; - } - ); - data = data.replace(slice, updated); - pos += updated.length; - } - } while (pos !== -1); - - return data; -} diff --git a/tools/build/markdown/preprocess-graphics-element.js b/tools/build/markdown/preprocess-graphics-element.js new file mode 100644 index 00000000..85aa5a7b --- /dev/null +++ b/tools/build/markdown/preprocess-graphics-element.js @@ -0,0 +1,67 @@ +/** + * ...docs go here... + */ +function preprocessGraphicsElement(chapter, localeStrings, markdown) { + const translate = localeStrings.translate; + + let pos = -1, + data = markdown, + startmark = ``; + + do { + pos = data.indexOf(startmark, pos); + if (pos !== -1) { + // extract a ... segment + let endpos = data.indexOf(endmark, pos) + endmark.length; + let slice = data.slice(pos, endpos); + let updated = slice; + + // if there are no width/height attributes, inject them + + // FIXME: This will not work if there is UI html that + // TODO: uses width/height attributes, of course! + + if (updated.indexOf(`width=`) === -1) + updated = updated.replace( + /title="([^"]+)"\s*/, + `title="$1" width="275" ` + ); + + if (updated.indexOf(`height=`) === -1) + updated = updated.replace( + /width="(\d+)\s*"/, + `width="$1" height="275" ` + ); + + // Then add in the fallback code + updated = updated.replace( + /width="([^"]+)"\s+height="([^"]+)"\s+src="([^"]+)"\s*>/, + (_, width, height, src) => { + if (src.indexOf(`../`) === 0) src = `./chapters/${chapter}/${src}`; + else { + if (src[0] !== `.`) src = `./${src}`; + src = src.replace(`./`, `./chapters/${chapter}/`); + } + + let img = src.replace(`./`, `./images/`).replace(`.js`, `.png`); + + // TODO: generate fallback image right here, since this is where we need + // to know what the code-hash is so we can properly link images. + + return `width="${width}" height="${height}" src="${src}"> + + + ${translate`disabledMessage`} + `; + } + ); + data = data.replace(slice, updated); + pos += updated.length; + } + } while (pos !== -1); + + return data; +} + +export default preprocessGraphicsElement; diff --git a/tools/build/process-locale.js b/tools/build/process-locale.js index c0f64a02..07242ac0 100644 --- a/tools/build/process-locale.js +++ b/tools/build/process-locale.js @@ -1,7 +1,7 @@ import fs from "fs-extra"; import path from "path"; -import convertMarkDown from "./convert-markdown.js"; -import generatePlaceHolders from "./generate-placeholders.js"; +import { convertMarkDown } from "./markdown/convert-markdown.js"; +import { generatePlaceHolders } from "./graphics/generate-placeholders.js"; import nunjucks from "nunjucks"; import toc from "../../chapters/toc.js"; @@ -23,13 +23,8 @@ nunjucks.configure(".", { autoescape: false }); /** * ...docs go here... */ -export default async function processLocale( - locale, - localeStrings, - chapterFiles -) { +async function processLocale(locale, localeStrings, chapterFiles) { const defaultLocale = localeStrings.getDefaultLocale(); - const translate = localeStrings.translate; const localeFiles = chapterFiles[locale]; let localized = 0; @@ -80,3 +75,5 @@ export default async function processLocale( return chapters; } + +export { processLocale }; diff --git a/tools/images/chapters/control/lerp-cubic.png b/tools/images/chapters/control/lerp-cubic.png new file mode 100644 index 0000000000000000000000000000000000000000..104451e78008037c1ae9e557917203ebe9e605bb GIT binary patch literal 16566 zcmYkk1yCGa(>BbVpb4(QB}j003vLSpcL?qdi$ekgcXyKD?z%{DcXxN!#rcNkt-tCo zpcZCodd@lReRUK1O+gCf1HlIv7#I{8X>ny3nE$Zeeh}e-D>y})jlc)Ik(`t`%4Ex&Z?d5jP zj6YUf%Stcy^lVZI9tyasvNPmP|T1!jMtB4>9V1!c{-I{p`*>U{chm}XC4 zj~AK~M=2wU4*Ms0+6j*g(cc{1kOI+PEQAFEwu4+e1<`*UodN_a;((~tm7ALzcz?B5 zV?IX0JA@7!ee?2ocJ*{MX3UnV;O@OMn8={p7?YHQ8+;;H&r-EuqwCNCcf8aPEyvUp z7#D}xB#WV7e74%kV9=&}$`)8Ny}Ue3U(q7!;cvNMW8IZgLtMHOrL)RrU`L|F*V1 z-<{F0oAjfMvWW~}o5{(YA-v7dq> z$5y3XrYtKP#^H5qGho3X+tbtIlt_`$3tjVLrlO&dlS^h2Jebqb*3QNFEGg~0H|pwW zD(cn(UG-81fg)Vie4sLkiHQK4Cogw~^0v244#McmW6GO$3Ent0MHDI7bvRR^)#Af&aq&Ou(?u#p<>mP$B}cgiYn6uYx!1hefj72?(_=N~G&SAd6%~w_z5hO#K+B+6 z`J=N_G&n1%m{Nu)`-A_ummmrILaP_|)!tY^Z7ntoWM!29tfecCN)D#5u<-jv=dY+T zWpvn{qX|m|85yKxT_+@f*TyeT_uD%=7qdF{RSp}XAZo0kB*v|+XyIO~I=&Kp5p?Wg zDZ|Sd4FkvLo4KpYA!c^)u_l-OD#*@`iQRnEq%VrtX0;{NZPg>#cB$UgE1h}tg`jmX zNZ(kZMChXUXKq|fZT(uSq_WIBCymftdCkucl#wVhjD~Xyz8*c$U{H?Ti*^B0}b}5*XppLk8 zF-+fBtfKz6#?rVY!~Qh5vgq5Af&lxJW*rgXjnaZz;fd9>`pCqdHYf0#Di^0!Iss%c zYOuUFzs6`vr}C(5{#yOmlaT9qqR+;YK5jK=X2^eL3EAi&eEc&efe($99-dVse&TF| zq`71nXU-(ivmWp)fy-l zp|ac`FSMK}ww&0vm?(-43RaKQf?EZj*DP8Ljea)}d9U^CpLsdz<-=)yd%Upk!q?f= z<+1-K_>+(~55W6A6SgXs1LYu8V$Z?3AXks7t!AROGy$|5W-N089ma$?7oul1uWRUM zoU%KDS`ex2_R}8>_XAIE!QM%$ypoBCrh%}g0sp22QH}Ut<&r}a?c7@Xr7TlgOTV-$ zdgt~d6%#i0&m_;b{GcBuZ;DYn1YNZVEKgV_7PUN{G?tkC8Wu+G+<$G9q4mn)g(Wkg z+v}n0H-Bw$`Op2}-Gue~i&=y}a}PJ=sE}WEGYe1Onj*QZX=Hqrkl6w;jS;DO(Iq3u z6UZ`|VZbt*QG)!^iXWW1g*#+!zJPoMCrT?TWA5(UIS5c1R=|Y9Pv`H2goFZvgV~+7 zrNPJZB4F^XWtTXWh;%aEW4c^FA_#`8Ur{P1JL)?32UeDjjg@gvJ>9C8Ct(*tki){f zg|hM3sj%2yfy7?HuX%RixmnAcvg-KTL4`#S@$?>-%B?Y{Z9eL7BrbC7Ds0{ZM#7=g z_hR9n18s#~_+Wpw`D0vyr4N=C0|jlI*+H}3i+m;LlW-g6A)RAOA=z#mRe$z2j%>Su zKh(EQuA9S_O0*0Y2ht90f`W4$3+ z2*;0ZEb6o=K7Upur0f%~_o`{FfCQOQ)r{au$70Za=N!)z*w%N%D+(iV7L3pSNF<+r z$bN=5-lmk{vPwt$ZZ$7r+J(9Zu|m2KCirx*vBys7!3FPAxNNFCt=^-tL%5)yJvLv- z@si*~8`>5txEMs)Q7#s_?4ea1Uo0RyD`Opw%lPiMnJ$?|UzFi*KkiX}g-)BQ8asQG z>{7ao3=#6-w6qYB{LhIhmL7q+)A@7y4j5htb) zfRz_2;}>^{-g#rPz@yR7x$}^}6n(L*ZS6AKef~?jpzjw#xH)F-?N04^vw-4A^2KhW zgws@j%{nHaL?D);(_~!Dm}gvfkaz$OYUQP#-raCCq}9^qpI*?-?qQPfdC-MtfLf`& zJ@t?nMfI$-prk|eZk#M4rz_+WzQ1-!hP{=WS#qiBtbI-?7%RVb#r?>iH3+%ylYoEa z4-Qp2)8~J@W-59luZ)_5-60*zpM?Kg(F*Ek4R52TWMutOrDcd(e7=p1L0x0EHkb`& zTpz)RYHH7^uL^(lc1_s@)BCkCB{m|G2HVVOG1#hGfjO0{%7dDZssE0Cq&n@C7M*;T zaNRX2FFnn5wkJIkoiJxhEx;0gcYYxbhay(sdP3`a z-E(7k9TU5llf!>B49ZlV;)buSHR$i-=u6jMqRasDD$AQSZ54>zmSEKw| zdacQEw*+=FE#rS4_t}>2w)>Q4Pm4CP=pP+N$@U`6_|pJO+S5!RtFCHjS%=BZ8+S*m zY8QU&$`??j zVI5&ApC3`(2NRSE(fN6enUka?nr>@$qU`TwT7{y1h?|nu^UJB|U_8nR=QY!&cZbMC z5S-(^^TFI^Dv{DIC2mQ3W#rV87vS6XjPrE=l@F=kopoHvt$|cdsD#~%-&?dI&OEBj z>dTczZy|)mMYOdzy`m@C6tBN%fUo9DMJW5O?co2?-_zX1fW0sS?BsK;^yG&3~=~EJo$c=B?_cMX*K#H47IO$SJE&Y zxdw}ukWj|AwocNbn~XYPzw5fgTU*yOvHJd1sjpD(xMrO|mPT9;h2AkWJO_ zR*=Y3$Kd2kD4h5+ZOZMqACGyt%KUe2hP7MoQ|MqQJJAlA44Ce)Ax7tt^*4p!3%rr& zSeKquzJ|uxPU~ON`@MhG_@CC7)$^>O(=5Kycd6O?WMKrcM1)DbyNdz^XEdC%(Q_o9 z1{L{>-7luZG;L2kq#P~G$o2%|2P)f9-%Nt=YIUZ6#bBlD!q}71ubQPY>@@XilfIK} zji-N=zEC!geQzUCsjVmxqxfS6I^AA3932nWe$q@5N|^NOqfeO!%{l54ze2NTe~27O zn3}gvL2=egw(cP{=g^7Ealc#TH5>4QP$m^iPxJ;Fn$fj$YHbque5!1T_sJ9=T=MuU zSFhUX_pw~tnoxXm(le;vJq;;!3>|lU8A)Sw+Qf3p{&DqB&tgYA!kR+m>V3gn{)2)y ziuRL_t{Z#tU*MR%HQ@=Zpb!%StGY0LX1U#FnJNJuKjz2qG`(sA^NUC>mb;&-qkhJp zY;lO6y!%i=I!Ay2Ezup;SG)8P*Me0YE-JZsXm0*{LY{C+o}s^I+!3fW$4DlSy8QN9 zGTv+vVg8&&(2E8>rL0?1o=!pfH(%+pd-@uJUuCRUKQ@tS*e&sJ-VJ$d^0wia>T85@ zS8BvWbwCRywHFm`kKnMql_YmtX<;d8uMQQRz3?F)R{xounb<5E!`|~jNia3EEEjvs z^N!pFPS6w}+Rk)G&>1#py-V_`ilZTBDO4;nthwAwwDsNS(>sLF@birsgrLji*UNq; zo6U|RgzIMeu;r&sZ=SOzP_Y|V<<^0KKLT8g5I>U7Z?=cZl(MqzByW(%idi+LIR>ea z$Y~r=r%^+7r33yBaa{}Bb@ZJz3e$?8PYr&Vq`dSG>%Gskms4y^44Ei(O-ySQ(aAwg z4Fy=lX6yD9XL)s9?4Apf$Y^Grog1)}59e1a{Iqw)$OBAk?qQS*v>at73#0rKg*PDL zwti#(+?mA=gWERwAG811@f#Wiq+w>y$_#CijtV}0VFUFBn^)@xvHbU~L=|vT{ien_ z_gB_lh1Puco~);mWoi>=hnmzaLJ|3$T(iq{@r#0yOcgoBj%Y*RRSDNA{d{Df%+hY1 z@xnyM+-V(@U3HShM_fE96m#{>UwsgS=EX(9x`+{{6{-zmY`3)c=({*ylUGD@@=n~B zcr_s3#VLhWwMibvgtG39;U^5sUy-(u^*cO+o?T%g?-`H1PFVgMXfs)zLW_*o;nK9# zJEn6F=&ctWB|e`su)Bv6sb!)FWIU5JQ0sR$o+B?DT3FS6uUiO31RvKvoqpSnMf#Ug z>B7~tUp!irk&H2zT_Lwa`mvg})FQqPSL&nejro(c*hMsSV~^iWIeTfl)@P=U$mG5p zaz2aTJQ1TI$RsVhXnnWT=GI7K+FUB~uF}we(U?uo3uo_BPtd^q27YPDNGt>yz5w=O zpD`fi3S7Qq!1qFoa}D83iglh`csw+`T%~u~*97>&`|TD-2lXX<;yo!f{ROTnU61cj zW}+A%=W$m;exy7B7#)|v+s&<<5zZHH$Mq;|eU18OU|BM}PV7{9pLB0*%FXQjDHvhi z@wdpS6A=^HLh{8cepp`5VDqEfl=|wU-xc7fe3u{14|PykP4|xi@1Sm9^9HLMs$vQ* zg-rDyv?F!0^?65HrU0yOnC)~5Li*L_IW7S$xIMXcxoKENU8ybQx0`&X< z4oC#c_}jy(=|#FMCOEHwD%-R0&IpIA8L8Xunn0&c8J+afeNBp{=pG7))~~hcX)ES! zfx0t|={t~9YBmcNtePyh5_k#03)_3MHm0@i@Bnj&i}FsYORBBvoLd|^m4P|0L@?67 z!kGVTiiE$o;nSS6TX<|_G1TwPT-_fkHw`(abstEMdQrz`z`+sSzf2bh-s7y*lzjgW zi!GbHXTJ3&dU;|m?`T0YxlbWdWc^|>E#3S9Le zgNbd<_rG3*bF!SykgM7jnM1>aV|-`IMdFT+nRLZ1Pdu53p4eXC=UlGiy0~}J=hgjU z3fRmx^ORO8A+BClJZryNv72z zFUs%^?KlxjTo}HSTEZ+XTBQLFWG8R#{8%rwbXmV=awLoJ3te5E)rzQtZ3?w%h=0qZ_Zn4tII%ERwa3BLo(;V%V#@3dn{9cVDbs2=pOcA zqx5$?Zp#^j^tFbQbfE_hU^C1|IiZcO3(2}HcU13uu+9PI-6nQmGnY}iDUmlC1ox{f zPQ;AyOO&`XUE%iV)!mnoa;XEUm(nR44EKllD^Y~1k_{F!NVQi4?EQiJOBTcG!wcfl zEq{A*S#=X;6Q}#jAu?9(e`vgpJr4 z`kZdTe%j=*Ul&$bbQ3RAVSgfhe-X}Jd2^xLfSRzJZ=^5y#HeUKsyrQ7tD*%d2m(B< z1?S-Y>=~EgI~K+VqNJ4iAw9{4Km?DAr3~szD)h;SjDr0KBJ|gR8hDO(@B9UR$ zQQA#%2T38{?RQtQMz2VTa|Es|5tDCTXJZ`q7RM7JSmA zj-=-InpEk_c`iCmwajR`>4U;}W>e#TTT)y4o?gjh_)Exmsc#l}C?sKP)HVtP4ykm5g)WKg*A3RXKBFn)&r^?Qo$ zXse{us@c->`b$#dMA0Z~4trOljSWY1YidAGaR%D_D_WdOFzf(p-}@a_Q@Aj-YE~Mk z7_}72*3&ttY3QJeDxE$RoaOYk)ghKpC{jU}S$^@S~1YUH1IlgYP0NP`XSSdkhF{;$@DeO#8_|C zSR5Y3)hdQ4p6zo|e{6?MX1uegBDTgur8}qVF7Byf6Da8!nxq#uU)d0ZB(~Eoc4xB8 z1p*RBVDUiC&+JBPE|KTozRdFD*q_=r<`3RrRM!>K4e7t%jrdGU=7SMD{tu5ek9lHD zOM9&J@{su{&3<9{(HPsj*44%O_N-xF5%+_{h06}xF4*OS`Tav>yv zr(t_;nGY2A95J1$Q^?-XuQ#Z5HEHec1coOq|6-Q?@pOx}NJ|QcGe-&USjf5*EpU(@ zmtczPXH;(Eue{oitpz$E62g}*y9~$#K$5V>;5uSUC9=PEb)61rw5k%j2?yUR(vEpE3eE9-Zb zP}@vuu06pafG$lfMohTS*SX&rd zCg6jFcz%>QJ6F~6oIcm)*U}$On?cA0LS6Ip||v{6fr!ws_}>S?K4j z8ZO*VUmNMnI6jMR8%Qr>00L|B@M#CNg=7oEFpdOWQAUa}5*OMu^6Em368&9O8*%J~ zxni!sp8wL|Gf?Qr?H@ob9=$N4kwh1w3=wQ?F<~ITs0c7%qsSGG&k5o!6cKawW!=A6V)jT0@CmrZ$wZ}57tFn^nOaKo9mMrLfHvFa@KgN}U_F`JMxQbSAv z0!TBTDciUKl`^nie`vfwEd}Y**QYhQCsZToM_;6{q!MuYQ{|t8onb6tLG?35<;C!_ zpQo>Q@u@hi3vK2*Jl?R=4Lg2 z4w!2f8s4a$of1$n8v2PR9p3&Eh7@{F{lwU=NeVv-`rcRLQJ@#SC#{21vCX_Y5RrbN zareL_SZ5s&ab3vrGe?SMEy3QYq&{i|19!W}xCZ`W`q4u*^KbI;&+3Yc zNw_#{kJ#`M=av*C4ENxD+PnPYT!V^3oA0YH(eB>kDB{icxwUK6iq0Ar*r>#k~O(M6XEWH?xoKcn0K;&CzJea zaWFC?b%&>L5Zuky-eId#@+OCdVuA&Ca*WrVY?GX0v!Dhx zR;9?8+U(UfQ;#JOp^j9(hy=nnt|=k8JEXuYqx%T~3vhV6g{3hD!s`2fHN#D&@AA~l z+O(Z7OGvWTAz@`i^{P%6EzS$i%Oa(yEjik>$CDE|an>u>g|GqwAkpg=6Ija1dTO0h zWg@$!Kgsy$&QyQ?qZMGIj|4(|&6*|GGEzNL;}c)?G%y>@2^uWbeZ03CGDP3O2TjXd zr=}z*VjHH@f7uOYB?oXjfZOy|Zl2AFQb5&s`Jq=mKIV=DqtC~wxawGYW9()&&>RjJ z&=wyPI7QRp?#JY$@X)D1x5d! z*J%DN3UUHS2HA3CwCr!RK%{@9n>6P#1KPP$BO~DVT#(dAk1-a{^{)Ne_G}>%5;Xb>%^G5rxLKsgTp+(+l+HvFFQ=zj%^os51VFeheFEcui-T1FSw2 zAc~d%>6>sf;GlpQGV%B?R3;)tymGCG#+pj%@pA7-*~3H$^=4#OMM$yeaD)-a!T5q$gW(6AB0#tsw1RqnWH~`>{kB*3e{F1 z;VuA*VwZ+FCj6Q%=9PSD?|EFC`liEX-BCL&<031bk+L~P{bJ7xSCiz&>d;5>Dq2X= zowPy3pHn~8cRpW0>-!S}uVEUHl?fTUfj;rz2+H{ib0ES*LEW2Vm3*oCzIO5Go=`Ys zw~@VY=B(8HjamZv6aeMopF@anL|+Q16pBYZg!I)qNvR=FoD72_6+=v0#Jp^KY+?12 zSV)4MwH@=HT(cD|W+ow1RqQQWTuymdowlL8Pf=!b???V zv5fIk*2l2UNLpFH(H_Tj*LY;J_X|f^8}((~fPvUVj09u~ZAT-g-G9!MRVn!ut)Ar2 zmuF6b=S1Vf1bT868kTL0nfsUo1W@?I46kA1KmH3u$cK9B)Z|lRV%e?#ibnezc<+UY z$-L($7PA_i8j5%A>DBT6J)+E2!TOOCg6f{`RXg7>qY4({wR43pmHFfzPz5y-$Iawo zPsjEyYAl-)2kIErnD(yoTxTr|_^s+Aerz3}~-$MopR&kc9Y{dCzl+pn~Oa^{qx{tHci^ zjZBI8>L1S-8J*_AUWY4x)l|W=S9AYqXhHKTAA7_KPKfD~6>1{6+v&GE zjvj~f!c?voSdeZ$tg~%NuL@NwpDO$AIrLyYAxr-C59aq?0$jD}|6q)zVM-~C>0t54-Ia(&{E=h}OfgBrtk4wlzV*tP0$OQjh@ zVZ?f_L|uyMR^JJPwdJSik2H~KpS^@-3f+qCCK{bv*F zeo!OUdI+K+zsP<%v#hMW7!#TM6YI!&F)xGRqUt*7@cZ%OAO68j*Bt<4ArqwixAT}3 zfEaJkBxw0Tj;>y5LF=ruRrZ+S4y{Y&6b@muiH8snw)Pi87|*gWb739_b(OP|xbBY# z?VUCam*@YiO;O^E+0JChA8+0zj|vvq?QaK1CN6u*{5=BGvERQI;B?F7Y$?(vUmpIk z2Vj7|#WS#X-B_Cy5uqSDoTr0BRsSbffh!UH=yyF#3-@y!%o8QG0zB)oJ-SVZpo=cy ziQwv)86bZvF(BH_DtRzGcUq-#$ipzaBoqsH#K?sjCw^3aU%LS5XT0zKqq0jZlIQPL zAxlm%pI)$fw7Sv@0D$q2!sMD~eea(u9QKFRrKBN(p#h}0#z!u`^g(J%B>(`!X7oK| z3Yter0aDn^@}0WNH9_{Qm&4TiTVt1dg_K#5T4*p?YE8f=AP=mA7rpEK zwZ$IR50rJ-`2jLUFRl30qeS#jJ6-h1`)#?CrbM=JZ_rm^B^oo7g*Ox?6Af_S+fDDY z0jTXL!Kc=3=9@O;=L_qge&pG#943A;PVf7QQ(nvX!^LtllEo|P98q`&>rDwZ)p?)i z@~A&fVvHwhqn7o0T1y?yq$J;0k6qq*3m!$S1Cr z^rQ_3Q(E^7;glrd{npOF(~Yp#g2uSZ(?!d!@=J?3MgygOcOq+!X=$YwV2~{vsA3=U zx0rFb>$KgE%XD9y#QZiXeA}JA8jy8vbHKxQv+{dMuIqJB?WnvFis9hIW#sEO)6Ow-U&J%HP3YL`x*So2-QLyCrMwkEip zQ#d()Mr?l#ww+rEVc`t`3T>=2JpLY!!kxQ6kZj{j%=b3n+I2sGnOQgB_1lEQp|eEm zkv+k8&~<+4bI0~JqEu*ZOzZD|iG2_W|#9kCsx38|Ja)C13Anqv28Rnop zH1CNcv*};?IDrpnWc}O&A~Q`(pmMDAhCM>UAM$OpEg%7GvSl);v+lm8W zt1Cj}GUsQCsIfNJJA)UjK*Hw}%5spu6vrf5GI_2)5pCXz0>suW)nfyojGcdjx;X=r zy#}|f^0nj%?Px7Q2o;21C7sC7p3N(Cm~Ion)|mI%iAJ`Y8*NeA_ppjG&wEZw)@ihSd}O8=N#rfxjp@Y54!=D4njcw-72z8=mKW3+i36|4$VxU$ zUCBC15cS%`3C{hty1Cs(>@jpfHMx&o?3A*H`5|FUKJ;cQ@iDlP77``(k}jW_o^e|^ zO~>|<0y_PB+MwT0Z?#)?_QB&}G(w0|t&LwiCF9rkR#L^>wc#s-w*6TKEtM`i%HvOB zqmCl3tx%w5@nR1Z1tOr`(Cc)>$?T>hotXA48nXg+OLy2;=%AhN;z9G{chAq>nk?XS z@tY|2wPlarjlcGU`Tk+mOd;J0Ke|Q;BzirisQ%W>W&u3t&w?uU@<>9r$wwv1 zfzhnaS2pSsCH&&!R7p9)3Lrs7qpG5nY_|@tIaB%$&izr_{mXmqSR|qVd2jogI+@q%c)u_KM(E*jZ6zGAM2-y*I&WRCgKisV{0_`>`<_L5KPXlJIAnNm+ipp9WJ`=IKM(=(9Y?JpiFJA0zXnx$ zmxOwpZBH(nIrf7y|GY+CZ2M`4U6=6Zx{=rbtpc|W8zG1!Z5}b7KJ&iEphjf_Jhq?d zYHx5)iPpDD*pd}V!$9TCFZj;c9g@Fx>YP2al@}N#AD5O5Y{XC2iMzu&*|#5j zLMgZW`3*3qM{C&MR>pf!@Om9zVjQMv@N;6qn+7@$AHf$s`AOvO{hM61m9zI(4!;<| z%ys}8vtcSr?o_BB*>?UAbsmTE05emuDSvi@HQDeW!v^VSuOBZE|iR?H<#m{whlUvKT8_{l+1@D8k~^LP-dX-Q#cl*I zR?Ij&m3c0q>aFA#8L?S>!3xWF@8o1^i}2RFGBs+oNr4O!qMWdle+w&uN@L=gTS^J@tc7$pm?0UL0Rg@gWvR zmDOf$DD(}f`}@_b9wyj$5g~UgupHKq#5(9H0LvR%bmL^$VHs|I_sGjOOt#7G%YJck zFtnx`Dgjshp-!&-!2^`r&A)vm^3^`G%luHMxj10SMBPvnc)UwN$9D*%uH=F&S;IfX z;o-Ums?QTYYnFm9!_o$rY^b5qSofx7;=%Y)L2}Au_yhmlJ!ahZOT_)I>yp)1Vh0vA zZ!kSP-?5=9z!ta7K8(kEt%O9E88&UbMRZdykcEhaP`${f)po>`kL>k6GvBL*(l##h z#7jv!js8aGSZVPzIjX(5(u1U&_p;OqZSLm+CYk4(!iAK@v?qMeh(rG^pRF06 z4e+f8B+!-(uH-V9GHtP8#IFvCy}0aBbW7igRPWra0ce)h-IB%K@_d$mw=4VAgEmg$ z?`vdMyF%sX#y!W%cUq;k*lMr+JzcnbHtDPFM3Jyl4FOvw{!cf^u9qX=0gdj;-DrN9 zW&wiC?7PB@(8k*xG7nRO7y=)B?MN?V@CWn!i4vI>jx_&@42W-B0lMKP4A7F5S9c`C z+N`nld1E+^i5+NV!*vdKI-^(q00?1a`?d}5mf0|iw35O zrsYt@gxZjd+pC zK`B>Vw0biTi7~-gu}(@x#z?Iivy0m$d#q2N`oo#q_CrSK;wTpeDxR|bW7Pm&MHcU? z(dV!YaiWCS00~-L7qt{9oh#CEDxcTNIZRExA-3`d0PrMCQEEFd0xfjwwJ@OcLzXC% zcnDDsdQPxlg2n^fdt>4$qpuDI07&U54Km{YDb|(S)RYSJ!Sg!Bhbd1b1c;FOw~JiE zpB#Bd!ncUs04>D>dSOO99H7gqtERmyFQO(Hi3NiP+JMdSLX* z3ed-dYt3)?pQTeW#TW7OuYL@S>e^vTJ4_N7M4mZo124z4m$JfGQdFI1x%zm08_W`3 z?;O6T9Irr2Ybjf~+-n%qPd6fQ)>=aWkY$B($mm&jSosM}1a$d^oCbhOW3dpVVcs*E=*i zAq~W;j2C7uA?Z07SY@U)hEve$tJAvCRy$dwT%WCFbFaF0#il1DzI8b<(oj7pH_2gO zGu?+-ge9lN*!Z}GwSI!-iQG)f1{x1;A)Enl8x24KpfeawrLA7_RN3S+kZPbN`Skoq zDcNBXbHJiyH{yMgpuL_5z`~#|09t`V+sRQ4&JY2z%Yo#}AKQ6It-x;uDFz@??0lIV zBdRy69Cy2J7s`4PTBK1A9FXCt!}$;WIGMtp+Rl+S-y|FVZJxE)=*+RIV!;HgT1Fh^|ZTYlYo21aeB=z@z~2c)B?#%_vez z>QVx43J%RCk~k^UqZlrZbK-@F0rQwx-7MezD>4~^-O<&PK^kRgObia+E2DJTwIbyU1drh{)k1haBUq#v46dj62$;q7wY@f3x=n+s5v$UcYEx70! zTl(TgD@wY7wGlb{`%h7&+NpBJ-?5;9j!XM}W+sG>Oi3;t98zsp!$0SR@TqZi_&Mbl zfP5hqg8e5tln7r`4;(MWrEnN;=+s>smfIgL{+_a9N7V|)5l>vXdGLyW=4L=q<&P!) zz~BGk$l|*#CBu?bJ(nN&fU;z9`YpyfR&;}q^r>>7kSu9omvBel7Vtz9%Rt4Q{&Mi= z{!uIhqes;g0N(`U4ud3x{B5mxX&BOSj)Y0-WB4H_Du&9st!Y4;F2HO=m~K$WZ|}&x z;kWBfxmGx#v3UJ@L1ZxKK$r2Pni{}T79VPmHs9d5Ma%gG=EvBNgFvUeXqm>8_9BxT zE$W1MXYP2d|NjsaazvVtcAhv)G+w@g&xRCA`aq;HUgd;G0bC~`jIvb8l)4T%!7?j$ZJtlUvTKmtcbA= zIRO6yB7jJPlZG#S70Xq6!Ua_BaiY=UHvwh_M$3U<} z_HiQ{f_}feOq)UWGO(giuvi zw1;jAP{9GZj{nyUOMz(KLo-MSk@(x%4Ctz7_tyWI0tnYOlNh=u)hY_45_lqEw*0fu zrZ=D~f%>7TpG11Jp=r*WN``=!k^8NP$rl+77-7*0paJX&%cp2<4X_j|yTEPDI^AJL z3<1eEmZ&$5eJ$+^3>~q{ucuA!|4sh38&nJ-j*#XIY8yQ;z!KbOr13d-0;|s zBx3*ToyMLrgQhrdvSznz9?noohQZatj$!iC`d81KPH+r-?(8{8WCAw$ z1L!tqWjeG@?|vx6Q#>VM#*UH+#9&PBo)6S=RPBo6Arb7CAuP1z`eNR9u)vOB3qmrn zMefH2g=ZWeSy**+4mjp8_S4A#6SR)~av|h0?P6%DbXyd)6fC240&mnq8@0aix9^uy zlgxsK>#`6iti+F++{hoWJ^m^^`oEu4h#OF`YU>TvwTN`Zs%SGkuY+_$R!ZdVV0 z0<=x8DL~^rmWE@X&}Z!p`S@jiQ1Ki(Dbp!B?nBUgC`JP9oob(LSMJbc$jmBv8X1yL zQ1k>L&{Ubg_&Wb}A9tS3RfXOMW|iYAQ~nb+vtn5%m{C9~{flri;jMhkb+X({@N5F*XeCRsq+}@`h{ona%(O#(bp>&xrUTk7Z z?Qa=Ti+`(9&??}w!=bj#oUxc*bw3IK;s$h+9h_XTGL0sVT>s>A5z<~91oRHh zA%}&wSYN)y!k-eb6RCw6z{$S}&`tNRFcl(^ySjbH4b?BXeW5ymGR|JKs}J9=`TX95 zL}KFJ^5Vnvgz_?Ah)yx6r5;-p5`YNkTW*TXMp%me8LpwSenaT|IDq4lBZip}VFk(j zmwALkN?k^b<9-k@Zt3&3A#9nw5((1WoI22I311jm{Ny4EaG2<$|9Gg8r_4N}6|hOE zOB9VR6t@&?sT!Y+pf9HXjTOecPz}S!fpSa=z zbwEpQSEHlqfoi{=AQ{tV)QFC~H>=#37_!l!dS(-2x(0OS0%j6X(3}WMatGd{R~{Rm zI?kj3urU7@?IGGxQ40PD3K)?F59~auo1{#0?O_tIpeM@4?jZRa0Rg-}0_?Z;_66YP zc0pY&__HIxcl6OPN1HE+Y`QZ_CMm$E5js8xF!BrA!6<=@_Qx~*2*D5sk6PZg=gxz0 z!m0%b($JUVdgUUcCzf^u6|nJub0YlT=BTz(Sdz03zc7J-6b1{6&h8j1aFrzrsi$_K zE;$4ThdOf?ewvOLnCW|CWJ5mM_@Bwb{Ze*_O?KFaHx2;CBMD&TIU?Yf^%l3pl?Krp=h-KEDKMzR`$YC$#-tvl>yi!pZ$YOAP|1F^rHgxNnjC zKTAX*|FQCFmAlPLVWGu&yVTX>#8pbsDIRCTQICs$DEt+OZ#r^d(GY(hIM9PjuI!&w z-lu@5v;1B>R{dU|vD)S*Cp-P&K5Euk%~+ByRT(2xwB8ahGBU!nJf1>;vEbY#302Nh zDgl;{-)?qW5&h3~=nzMcbD1C$2N31=K>l@kd6^>Y_kv{5ax<%=)#OCww&IFMuU^V? zU<{Da1;(8j^jlKepHJ+!_x7%!?XQ`@ysaIc5;bsgumz54(O8^cK_Fxx6kbCzu&}c; zyE&YBn~?@)se_}19`o16zmM|Xi?TT@`N^AmCqKxC#dIOI2Zl#jVT z;MW05ohFE~zRjMg5|yf|s)~+<6`)>{XVC78jfaqi0O)4zZJ2n-C27lL;f<=t}_6NH`v!`M zrM)1d#lz)$>b{EI79f-C^Fu&HMEpLPD>IzJ8sKrY>$nxkopoJh-1hQd9U=L7PTz~M zuC8u4lRtTQczEhmH_uk8`e5ApIr9z|PGtPvYU19)g4-3qB-5IJk!)KlD-4#(i9OyQ94NP5NVn8-rJ;2>ayQBEkR$Fn|I4PVlaE2L>>J0sOy#0bw$L0Sw>|!GJIszyJpDhhRXM3}65Q z_(L!tOa?H30sJAjrou!flVSDh)yT`syO!M;zySWA#g;8wuyW-}$mMdY^5e&kWBvN| z&}cM&*tM>iFkx91lP6C`K|ulTx#u3pWU_13l>ssC&axxpOB@ojUc0 zX(!iAnAF$TBQY@%0FaoNi2C~aYt@wjIDpY;gifdH``;c$jT(gw8#Z9+(xw09-VNZl zqId2I1Oh}vM4-93`48bM_(Qn-1~3fM_csw){T{$y1LMb!$3qW2gzW5WJpAy(edSl1 zKDXX_E0!)@ip0c3JoC&m*P^Qf_!YQ%uKiJS@0w{Qv9YnJuC4|E)YjG_CMM=ub!7lf zz%UFrjD5bh(CrgT_ad57D`G=qS>=&Q$$1r z)z{ZwtF8>d2@V`MKnV#6bolULyY(84hQ^K^OG}n4`7ifu0PbM(=FJop6-BSS@(Q)I zv=9-|(W6HxAt8YteDFbf^wCHEuxnj2Gl$RT)s+D_!PKc! z(bm=mqtR%${`~p#`1{}gj(PLu{g-<-0C%8PtNTn(mSq6|Q>IM8x^?SNQ&aPYnxzcU zfPOlF0Sw^x<5&Aka&vRBdi82FG&BGJIF7@nO`CA&&>;Xob8|D+uV4Si_HqCN7{Fg1 zzsk&!$z-_ao_jED+BB?Qy&9#ZrP#P}Bi65954l{9BS(&4+qP}6SS){5e+Mvt0sKYr ztAxq!-MjI`6Hj2(s#Uo8=9_Wp(j^oZ7i0SL>B!2;!lg@>uxZmKNTpJ@d9L|%x|7;J zYPtA|C1;PL`*t4V;Ag*bx0o^gDCnx1et%!ZtGA9}2m}H#gx*y>h9NM$ym-I-&7fZy zXLT)N7!a?QBZ2q?0>JWm=r|q+`sM%L3$r{1+*OZ&LG15+590VZ?Gma4ZiD0D*-E9x;Gf2*x4+j{v?&1Y&!JD&Ob<#=-|{5`$O) z7*+tG1rTy3FvNn-u@G=Q{v82l216V`fRK#fa}0WKKma2kU;&W@5O4sW>-o+9W#vj_ z0Rs*^VnIBDMFg0H3^;}dlYjxsW5DuwAO-WXXf!?u?WGkLa-JgIO2h21t69W zGX&sx42b1JU=l!R7C>a-LuBEB$MPVw@Bvl;KFfedfRHmlL^z{CuFS3or#d%dZu3^#;QHjTSovxbcJzm832YD5cRa9U-&ajPbII1ut(T1 zJ+%x&;1j?HdL|tJKF3*gv`5(V%tvBaa14P3z%l^CSimv>F=hzJ0x*D(EZ~6ypE&S| z1&9GL3@k!E2t0s<00}^>2p}Oih+q~ISct&#c;Jy4B-Vlvo53(9kjM-MEI5$`;BnwY zEI1*+usu(OXX1fp=7HfD@Tlh>cmR*bfY0Z^2ndY$7op1Wz?k^pECO^x0uAE<4bKx= zz6b`M5PE?p4157hJU#$Gz!8KT3xS>oPVEg+Nx-TkU=3ne44z;O9^fo|fMLKF8X@4D z;co%Lj0^$|Jop;~@HPnGW$6(bCO!wVkcC-j1W(We0n-XGx*&oAB2EPc1Pf0LBO`&) zp9g)Y1;#Kv^q~fD5(^lk06d)tW|IVRaRAyp{L$g%4UyRbPqP^!BcRMrM0ax-L|!_G zJ#=`su^J7B4eZ0TLm`ycHu~9gL9C{$TYwC=2tU$j?Qm^ddrUorIW2 zo`66if!5fLR&@#5)FqIs3c-;DL&ERI;Ltn47kHsXuRy)70}Z-Plxdn#rfx#4Bp9Ou z2I1C_p$O*rp{>h^c7+l3EjrXTX;Igtg}l>%!Li;LmF$nvDgKBH_Jpa!2xGem#ttL2 zjXG#$I&|0SKxPiU$v*HO<_G^YUr3@Dm^585tGZz9>VTo64SIPKbS(|g$r}KP02J;C zLy#HzAU!C`7h-WBghC&H5rG8<6K90M(hZHV3ue}UKuHV&C2n+fb%yflSwlHlqeAvjJv~gMi_|TPQ+^NP-y801WX7MKA&(FnfS!6vEWagF(wc zp)#Yr(+F9M4oz}B)ZJ$Ag*-3<0?QEm{Dg>(^h9KcC&D}h2omt&%`uR$fY?mncUu63 z8TuAIbd5TgRc1iIfa4fgSOU*i2#+WUykfoJ86t)_KmdWn41tFU45I^a-7qPdp{c2W zUfu|kq77!91{|^A3xp6z{NWK00!c(Hd}31I6*UM#KYs{(eW2wj(B55+Hgy@4IvEr? z8F)Moc!+}_6ncTj69eGEL?-CW8g!ewpf#((@O)w9`=Y}lf`UBZ>lu$oNf?qm0}$%r zhhVV}0)<}i6L_P!$&BJEHHxZLD6i8%DBvMJN`lyE38KR#2o4Y<#9xG9e=*o5J-Tw0 zP~<70uIz?qxCgw4c)>f~3tn*&c!Y@I5h{jB(Sr7jbSR2)p=*-CHz@@^Nhy#-#y}Dk z2hXqw7&$%4+D@QYeiS@LfCRtci11BCgl{Um#UapHO!%=O6Q|qCaAQy+9t?=ZNdIU^ z_#)&MEAiPkm3Z`)Fg$*54ETHoO?w*9nk9!MI{5cad58E_t2wJyt%6J@>oap!tXP4Y zZ@w7-aPZ(kEL^w{x88ay;^X6ym6e4lQ>I}0bjN1Qif>n=%1Z~Xd=ftTzYz%b7Xtt^ z^*ZGIyBq;2J{a+GQeS)4U_j%(osge6g6IbyMdZ}`!3eI%LzTV}#iuII=*gZ$_uK4suN?>J<4<=o_JD{LoBZ zfOrt%{f8pSI|8wuA&B(~g}=}X-4-M2wVkNdb)crZ1EuN~beVNX_6frX-zY>{!qHSm z$gNPIs<9h^z9I~c@xhQ7Z}@o%VKD<;okr9&Xi-+BhRMt!CD8}Nll?G$R3Lm=pjFz1 z&O#LwWg75BJOrfp!Z*PSl0Xso0)SPS(Osd2rcwh_ml57cJ_r~c2#;tJ^sV_&7w1D$ zSq@=9AbgXD!h28xBysWZij9N7%Nu5m653`N^l}-xWmQmA7s8-ugE>e5O_&+Nq-X@k zk4C7^Py~1lg0E*Jc#QS;u}R;BjLs@#D{E1qX~7Wh2qZ})2<2PgK^kcEGBm1-;U)A( zjNfoXc#nd-J{}kH6ezAzAu+}qX^DOqKG+w@gM1+tS+7~BD>Z02(T2A3?T|!C5IEW& zfusH5JH!VJzn>{*G@||TImk~Rg2kXm*v*p>Fl-FG1|@=FuJF_t+Hj$EBbwDkNDi5V zw1~Um?-|`!Zy^ppHRoejV>YIS55wQ0uY*UwvHQiADwI`g@YV~-h>MZ{0E`_*6#O$6 zzBgY&#BEdIn~>sYO8zeVDq$j%$uMEU1WcPY4e9CWC@n1opWmYfPM$m&&ph)C%w{vz zty|}oX7cGbYmgt@g%<|Bgk#cHEPXDmuZ}oE&dPH5C;K4rVe1KIRw+^Y{buN!8j<$S zQV6`ftm=t4RJWZ$cKv1~h2DXYu}?t26Wd(BQqzJ%@;qd8R^i^rF?cj;yp>Stg+^yV zdR9A5UT%d_W5$D%qA>O5aEOG~1B>Gfw*E{)rgkAp~crMSWKm z^kyXzf^NjnusadzGuZC4wy+#7m$u_zNi~YJO+dH`d`}i*eBy9ld>TdtM1$uftXiuz zLwZtb0`;92;VJY-wEtLy=)%F(v_V;t4MS%e0@B7J?E1;@OCAA+ z;i1i_#+kNaoNg-y1K`G>A-FCe0V%$b;4`+@Ap$NGmE&Z=Md+A(_=hzhTrwQjCrn0i z$PM80tOXQj;?Q(Nj)r|r5cvxcaYqURvgHOEe zJF;*_WXXO+S=&imANMShLvObdG60~p7_qqc0HQtp@ofA}@E3Yo)$cjlgz_2<=D(N> z9`DM#EM8oIuqhE}&0C9vN9VvZG}7U_`aSs7aVB|rdHDI~pYh;>5B7z?YqeT@@WBUI zv}h4TA`v!k-i)xYFqb})FE*~j`KUJhICU`=Z7jyr>%(!wu%Nzr*2p6Lm0XN|D;fTS zeQfAkjvqnu!Mzx^=mUs@Lu~3TtO0qlZK!EKiyM;WA|`Nx-F|2-M*Prl5og;<@OaD( zxF=$i-9ZNct(^w!Jl=>)1)aF>)(G5xTO|0lIP& zXxQHjtxSigX%UFNHxdE~-{CXS%bU=4;WV1gpM=s&fOErxAxurh9pPgzK41tW0$ZVI zFl$iVaULbD$Duc?kPM(Ia2=2Tk4Dm5n1iP-W0j+0FpzYi#NMhm;dh6{7yly;%zJB0L9J(?)(SEiSssbha z#{?qsz9{&n`ay3}pj>_!RjsGsA@sxGu)8oQ_-2TOwqwAe*FjMvMeC&#=xV4$WqcG0 zheYAJ!4ohkG!0Rnfi^UK{WGvQc&-_Ter`c*xC9T}9*Hrj0U)xVMv;lq_H$@d6=77w zG>nP74+4`X8h>g=5kVp+7DK8%I~+Yx%hZHRf`NeCofcH7o< zW#DYp8Vm`!4dY^;f{<^^v)!n{f};I+C~_30Mhvs5udLPJ-y6!Ydg*A0#aG5x=cNwF zk2E9gy%EU&=yjyM{2l}nZ->w1_u!fat!?;n1CGZvWA~J$Xjd9Be{BKQy>%VL{l56> zIxVu^FU75^M?oO5mHb`VQdE7p2B~i^hIhPucdo|Jg3~1*ASP%$#>D*{jvTg~rfzJh zJBLzrGv=q@l3()hW@4Var+3qT6R2@)_ z&qnNB$rv1chn1OX4;GHaVR;_*Hf17#@xm0j2|VdVc!tFwcG^?$88pO(#%N-(_jEIU zI@^rN6GHL8ZIK8Luocn(pfxFx-Lwz6wMXDrl7#U-PhjwaDG>TO*2KE&s!+CeC42`D z#h^!LKok(c(id>uqV>R^lvK-KvSi7UKZUa!$jQz@mA?j$C*2M& z4*{Ax4B!Ze36=D<5&Mh46EdjY)r6>tw%UhhWEA{ThoNNU`|uwz3L^gin>J#B4+e+b ziK@1fsE{8=Y|sSodA5T=!WZF&pdlFS9gdY{2cTz7NcD}j$*Lsc(AaepI$Dc+ZXSY$ zhFfs*LI9HEf)V0iPzodh1da(n65|2@120`HASep`y`AAOi!Z>~@ zn9B!ny2=A5&DSCB!ACIqu5l1bJRQ;kK$pG-S%!7!7ytqAXz?tz!U1FsCe8`EMZAZo}MMBa8k_#!cCcW*?S^bEWrVj&I)2FDTh zpJ~R2UzZ^w*aL6RO2G{ygCOyAETHujCMZ7@V6bTt{O=XwlGoP|OFR+oon&`hH2kz3 zbvrjB`Gq$TdFTD$drIu`HL*GzE?EW(nQ(8~5_k&z?6#}bc3^4AK`cz2h7o>IcH4Zo zwhVXN9Ex!xt>15#v;z#EhmeUq0=ebv0Yu(@zr%a|-T1?@e0~EqY}h~#9bMG-JEy#h zR&B4a+ctAq3Dq5HcF0RpQ$^C3W|B#zbb8I=#(lIa^EuM!iW&8Dn*&r`|A%SkJ% zBO;=fHa&gvRXIKThLqB!?RM!j`c^tqx}0`p&L&ysWve=q(nQr8Dkkr;NvBV?lvCGL&&M8E14|{VD(KP+ zS)?q!^8U3Z1sy0|N#A7uAIUY9edUIZR?1!cDwTiv30Vw!r@U2qIc?2+j`AA!Ic=vj z>1d{OGgWEY9JV=hx|x=(F0orzzN(ZIIbD6fvlh>BdcEI^Yc5P4JG_MSmY$buwy-qo z!%Vwv%~~^^oGB%X-r|s7+l6$>efuB8naxhG+tigqJEb#8W3WH5`r|@JIZe-4OQq^2 zs%|+(2cUWWW+}b4eJvfCewIqtR64!4{?OD_ zQ|^*~P|4@ZsJfzw=6;e*%fBt5<_^b$nB!O~YB@riETVp_R5sXOgTd$7wq=$I?G?w^MqX{pZ?yZ!_PNl2&Jbyl2k3M69{z*;)*G z%2__oW&eH;uDLLI=D>T@+VAVK;LAdiwK^Eo+htU~&G}XZwcEB(`4^wMymn((Htm$o zqHcrzuV#PLXyo+R`Q`L^<~w9Gt6jD)tW?tU1sQbUoPAA7W7g5Th2PTq#oI_>)DUZC zsruVGx-d&h>Pn4E{zOC;3rl;y*hc%Gd4w*0x83Cg>4lj!(1n_>X-mc|I{)o4IyF0! zI`W-sbG^9SSwl0V-_Yjj^HlZ27LvX=gE})WyCx)}{8A;&o}WppzPU_4UYbLhHD8mN zHMm7fM06%Sm-akyhz@_8PG+NfLbtMBL$el1>DvQ!WHz&8R4J%<-TPFy`du<>?LX&+ z1I=`PdIl*9T|X0pSxZ~fU!-ronMSJGGMDW&hIaZ^I*aPNvR$_QwEP5ZslDj5&9?pZ zwEck0Zk@Kin+g}^_5Id&v{K>c3te9K_u!iPOtQ1HA(!YeZqP6UiF!QsT7w1kavf6R zeQnzN5B5R9XO)P#BMf|zeP^Qoun~}-Iu5g11>Yf#*VBDHBjD>9g|p=!Vo>nS5b_<^ zwiXQv%0I;QeqlIg4uydO()^%wz({}irTC)g!!m$j;Fn^%a?y)=xeoK!6~KE?5+0oWFbo$DqV2+I z1dbX9p2)t>rWZU$0I!xrbbRN5`r$hfFwKG?DdX+>kgi6wX8>-|iE;GI9_$YX?s(>9 z#3ZGNsVh@Cjy%n6aX^nBjx2zoX{yT>A5cMgMtZ?GGJ003H3C-xT3$E}GkAujMbr+oJ} z<)L2JiFrdNJB;nt>MU5jxe9O283KWwW%bq*a!BI5;gj4mkM!-$&^6T|c=U}f@9Q_? zPZd=zuwlandTIA^%Idmed&)cY^yU}&4r!|QHB!l@TBm$11_NcjGKaeB>smZ8ZJ;3@WOz{&F^-Iz$<-%^+2Uefyb+h+{b_ z-BL@ZpU)y?rG{9}Lel#0>09Y6YVWRbc{BCfzoX2#vq)81OvS2Znw7bQzN^1Xu5_Z# z?i$)Dokh9z-xJGOsIpc=&;Kinw(P1U)`><{qH3fW8EffKv$aW}EK*X&^o!JX&elxT z>ddrcZ4oV5TSVOs)PEu(O?@Rv7tEyQa|g-XZKkX@^QiLc8gh9vzo6#Fuc`2(g=8`G zXjl0yM`&}-Tryc~O-;R7O0^aj^EHyS|z--<(Aa2Y1+*J!Y+$F27qy zS<6evVzBm6w5UpGbH;QkYO%kYnpvx*qGj(=$;Zq4CJzyjku}rjm8a?Lf<2@*+4t9! zwH&7H8Plm%Wi8}PCYC<`rjq8bC?K`Q`dxBFw4>oN&C1+B)!p{}S|){&^4`d%%FoM) zGxyx9yhBfOmSobt(~c*Z)qUx-l)L7V9yZ({zBo z%X^(H?3MdrIScL1dy`7#CtdQja4gNu-bSS==Y3JBO*HdODVa?6eNC)^rL5;Otjbz5 zPLu5L4=(%gdvMLo9F5S7kmzuv_+Hrqwy|9gFhF#ut*XiJ81O|rv|Q{&=vdoj;9iIW zgP@nUpu4&ferdy<_9M_c0ZP3L^&J-x8#Dn#94?lAfFPftNR4^isx6OUa7#!E_BUlg zrt8Eg|2UWTd7irrwP!n2XOb{BB^Uv|j@9#C_@($l65)x$Wu*`&df~m@74Y&DV8M)` z@ba*~lqvEHK-jH!q2=TObYxyY(3tDN@cB?xb>rgvLd4z`j?`K4;0dgiXK!%`QbO-Q zrtEvvD>5-Ca9m$lx~94kMN8gB*zI>Be)@A(aV~s@hY5l4;6PYeb`;4z;Rq4;m}eHw zi1hN0(V?lt-NQeGpTv4ulh0=`VN@W9fEDY?Ff_>*!GU6!ITkC+enN*ygJr`WL#Wu+ z+ywx>2OnXR!=cFTLgQ{36fvGyw4nt5_e2sVjdvcK(hFUK39{Wm@J=d#z^4@fsbgHm zVASp0f^Jz2(*Cgs4Bz@aMEDGW#@LR`ro9*%G7${J;B3_w@biqonCM4c_UDHNDS}1b zxGUVb>9~1U9d5iX7|DtDP2sMrP5?mQxGV83%CbBNB;N3jwI3nul{wU1SL?Db9LLhJ!i7}Q^b=)O zt|n>4DyQwu97_udx6`+E>5h34N2@D;qW4RFAPdJ*l}tm^7i3UHy?a-Jbb0^)AOJ~3 zK~zpwBBGWOCGEO5oephq?clp|VUFr{eM>ou=27FR8agpUN{R}1uE|kG{de?Z&Ro(O z71Vm}G)Z5YNtznxOV&h0)tWY%Dcww`TgymiRM5Vhxs+S~9l2vSRMcu{#v4*PkjL31;kmLYr7|^*3jYdPbt6YC)!`Q&?(Pe)OL5!oUE;6Vx2peI}}EmJwKBy7ROJh z;%v=9-R8a-NJNz1+(LKFJ3^oC&-zt#2hKLp+z+y;_FyArK6jZ6ZLZBoWvQCZPtPDt z&6VYQj$^5O%PK10V*ex3bm9QzFP~4W8{>%MSlXKRDy_ftIGHRum+kw^8?|dw>&tD` zbnKk-cA3vzCiW^5sPg;INm)_glK=0)H9xpq%<`c&TOaTw;PVh3Anq}D93Xm98042a z!5Ubn{Jj$g!++FuXxO*QWnWBY6(o!RN<$a)W`)c40v;cW(;mTLc^)oxR$A3AH6;jgQi6xeoi6^{+R=Pi{o*l zF4v%FMJYxuO@nv*mC$pB;bF+%Uj=K>q2cHbE1J&iOOT&AjI@6&cA3rq06Mb*7DE>} zo&en@*W+ksLpDbF#~{VWary=T7)=~5<#b}wjgHMYeWMQIFc0vqN}VukR1o?&PHFf< z@TZC@7uc|21AVq}ExnchwN2f=^d{PUw!tZV>6Timb>nNz8jX}WcNQ5s9LJP!97`v1 z|3S^2QmXH`NC)#?cS}1VB2t*NG%Irh6{&jqd!eI*Ud`P=M%M9HtU<1$84IOUQD>{6 zbSMq<><3cHue8<*SOZJh^9!hIORdxX6s)PFj3q^VUniZsnWS&bqON@B+8%2%QQ>nveyGZ)%MKW~QYAC7-HC>n?C2fOaZGknL zDet4#sV%GLp4C-lBz=7*85NxlY5IfXSlX5MI#qXEq}r|=+LANR={RaPXlPdE7N=vS z7Y9x@(Ux7cPTMr>mQm9_+j*1!@tb7QxNipj7F=^-vVOyQdNKP8o4V!>JkUWY49dUzW%1p|bTP?a6wP^d@WJ_g(#E znqRQn;Y7LEQ9(1L>!?}RWmV2{94%i{O6#`TH_tZgtfs|li^y!YKS?_?Iw)(-Wio57 zT(`SkOXp`~kfzS{dogKLl=<#+)Ru9Mr2m*f+9vyfVfJvTb_<=WTGRLYc;#xkEZgp| z{rklS=|a0}GnC_q=DeLn3KyvW`SWu~-)t)^vzER{9P8f4@weidn>h>^u*BJvM+AAG zQ*DBUb*w6j{YCIi^g>&&{`-$iE}P(|T2o$1s@xVlp}uCanLi+Ny5T-de~z4OsL-s@-5M00>@B)h4PNA*4#-@FtstGEK0XGIGy5yZ**oCAxFZerI2_y@_)MfuNNPYwS ze$k6OMu6K=-ob^c&tWjDT=M3K!=9#}@krD-Y^qIn+h348$OmuD7=m{`FT&!ligELZ zVB9e_%qb1SV=#Q-Q0N-;%L;ZvQ|gvA`P-kN61Ho#&C$c*XZr*tiST?WZwqicishLtTytYpc#;UefJu^=bE!COmw%^T=y;nF>BB_TR&Q z1Ahr&B4qfmaJG)rQG@-FSLu8r`zCmSHL&PzbnJBNg=b_G0>+F(^Wpt{W%X_65a^SH zAfIGg-kuQ{6E_{{#8s&Nz zO)QcIIZr=O4Ui>A5iLX!swMA!BJ~GK4`Bh4n^a&3|yRDtX zJ^l=uj~s+asRR*+V%avN#Xjw@ePZbC5b`A`Z#m+yO@*cj7duPwT>KOO!1D={QKxOk zkrrE%${tQ;wZg=4m~np`maHuX%ekl3@B}=BPmO>gPl?De{tmZ3ycz;8Zw#Nm995fE zLlhiQ6fngsYziBUW8h7HZVedQ4MY$ReM2$kQSb|R~PU6GiPrz5`Tmbc5 zQ^3QRQ31#=QR1%gVGd23t3fOwe@QXoW+VW_L4Ks!ExOj9Pe5B=g@mW(000smosF*i zOHfxkUJWa1ISjEtg5*%gTE@+T{*DXv--9C-N|O!;n+xzv-1TntY4_nqms$w`DDxEX zA7LvrE!`>zz5aZS<*y@5%(lWL#9xdq7k(1}h`1>To%t%5wXP5U;(K}`_HR$3?)z_0 z(|Qcy0b?K$+itqlA2$u2hl0i(Q0Z+2mVq_l-{rgUcFJQA{BkS;k72N2=!4kZBt@CV z`5>-t>c)>J8?bm*D(;&YiIjLBe6pp&(J2~M=qgd8WJ@h>+%y)g=^c=tYI98l07R(X zxDH`AO@UTkkIw8%?$H5|bzXw6zzZT#AgVgfyG?hgvl2DkO_&ls92;tWcKZ;MQyFbY z&uPckACAR$d+SkB>D=rE01!~}NdMr8R*zxeRv)}O5 z(CREGC{y9a>m2RY)&pV*CZ!4DP+M)!tW`tk{XZg1`~(uH%v!s3$+14DXwW#NXLt-^ z?hHl4@m9C47k1kn=&q?kMfNtN#ysJ&y-47Nn+Cs%^zwg$u5uQCUilO5kDP#5iM2rT z7Icd!3_7jvQ`}d~NnX!Cp85YbK3h!Tb`+D|)cmRYgKh-(yleR^VoR7*dVQCs9 zp&l6X;c(RNYD7myr_1}P{(2pF9-c^=^D;*KYXxe4*a&5@Yb~m_Jsky&+i}l`m3UzI za^yAbL1lZoOS(K|JvP>y#)=V7;^m~<;VbaO=ar{i(q)$@u;W+*K6qsqLW4c9?9E~L zXnh$PTWlw_)%|U$183rp^lUr;fG^=Ab>T3Sttja^io*^}DkaL+tU&5(iy-i_HYYqo zqYydi0aSkfg;hBbhht?cFlq2>@DRB6$J`kE6wcTGh)PW}CWpGWL;SJyR@`|@m`fj# zrcB+JA$&E=-D(K_*EJKM$JEKIbZzRyO^rbP5xINkb}^=d@=k3xvg zP~tj4gnQ>?c7mBe~s(DZneE-M0EWkwRqqU1mCVbEhUA&H8$%Qy12`(RdgK~Z{T zbuUx)10sA<5$!+9;eGUnMCb=OLUFer=kz3izJ3vK^qd@1Z*v~Z1^~)@`z8+1BTW8x zG!vm0RCatOK#vpF9lwdlPYB<52|Ds!w`DmaWZpUO4Twiqw);n!j*EW|HSOu>=&l4y z95&P(!OMyFIiKm#rvyE!CfU3x^fg~*w=)S zOH;wvaYTpQ76wVY7aD%FzQ>yHH^6U5DnhQGXhYKp{EX{tPo~blE?EQ$h!lnSl=<>(GHV>?1gWdbDdV*nq;I>jC8AQ-Ks%%}NTGGSH;h8p zKwG3UsIy-ixn4;#GS*VL+VQ@q+e_45lo@OkRQkBekV&eMms%XRaSDu5WuA45* zkdnUDd2SACVkzr|3{sW$?CaWk;WXthd&}*BuG+nusP52r^nKRz)UI)z8`gJSj-xqQ zTd7f}pi8nJ=#uP5mo!UO6;Vm0%4Ivw!cpdI$9tvJ9r%vgGS9i)*WZf2gfPibRMFb1 zgAUuR{H~Nr>s&unBBC=dWs|Pm@qpqumJUj1k;&2%by~G?9W@==|Ev0aq2?P}a(=eU z4Q%>DWzx}1>3S+tw9s=OW>R&ddzr%(b!wXVu9Uh|MrulLqw{a(Ioy}DKf3Z1bYZ5H zj0z)ZWpyNdaR%w-t`o@=#d(zZ<}5O)6x3~KrybH~sZCw#l1{EJr7hBDNn>d5OE1V% zxZa$q&7h_k(r>7`yPZ@T6U|zbNtwl6F6mf~qxmZe==8-_GAT`TVV0DXrS6T9?z(Q0 z&bmbEifWR+K9fvp_vna-Sfhc?&VPV13cqrjhKOiiQy#6a>Y30+i}~5qQ$TT z`^N!Tfq>2e6@o|FSL@`8Y?xUcVncdVTHoXpRDAIX!Y17Xp3t>A2>{^SpX38g&6J^gEyo*a9`XA+&bJnx*&fsLIORo>gzHDo>Snapw!C&uL5;@**PqN4li*76&8HD-K7? zR^Z#VHas0S5fg%vT+(?7#7Omxzy~FVadwvl&)gl48%8=`xc~r$VK8BI5LT=$1@CYx zM$Jq>;AqGD+w_OXUj$aCN5z^G81~L|c!s-w!d**u8LExBh$s^vWUOSZCN;e;E%)jfQu>(-=ob+>6}iLw4Jy-l8!`3k$iYJL6g zRzv9R{`2{*_)7>AAECsd0~P>61H@=o8r=%!;(PEBGCBY)7j2hF4JHM;4J`=rv0j#o zn0g-+c{$KGI}d#0h_JT$5MCYp0DL?mkQVhIE?2K{*(adqyyA8Hs`1hNcOYI8g3Wd3 zToVBR0XZL)=K*JfqrFkt(Crq#`1>PK`%{xmd5!!i62tGYDQ9>* zB+PmdHQ#*cl<(R00;KrHAkwo(4IdhLFLb6Z)VBZZvQO*wR^f@sF$nS%;f2IIP^50a z`3~C^kgHL(yAeWf0b-|wxAoQ-})WjgW>TI^YG(He0C5-enOOeUgeVR zQuP{0M1dF?`vhVicoH5VVW{|O6`ajf0>N?%CDD!>6E7 ze%z+~rxVS%?+*7&FHNNe-b0)(`*LOzc>gQm^njz&f3LvZC1L>ZiIV_eptf2bCDgW^ z#GtUrc4-1ejt0lFcC(6so}^)Po|rrzS#@7SYwU2?pPX_9+Lb2UHNMAB z!e@9`l==w1u04Yqt>dUwMVT56Ct5M`)gIpi!vJqRn~e1AcKn>v?vSqiLOK+=*%nZAQ&^woAXg$dmm5ov{lyB+l(COMK=<5XYis+gA?hzN$F|mN>kacxPYP z#KgJK8oQ7wbDY=m-NAZvD2>{qQM~Ft!_^$g$NBdeLp{z{R?+aaZzu^dG5% z?*BVv2fqi|$tweZJY@q|;xN|E`M>}$JnT*swVpu#;HdgWEf^kyxG2|0Z2*8OUjcsy z{=q){NoNaRjlYaA;ei3?L}eU3*dMtSuD2TKMdBk-sM&u-JCQ5$5agW%<$$)2u!S48z0S zLl>YynS)}vZC=xXbIr)FP~n~DQmg{F1Ux>Lrrn1vbr(^ov5jc%%2T3db3I1CKMXwa zm41qZJS=!66(4_D0ks{o#jH`I- z1%D@gCgQk1ed~c<{AGlRx4;wK7K6k3u)v=EP0SY8b~pfpjSoaui5g~2kNI@9C9S->k>%ng!7CRe$##1r&2S#+@SOj?|p`c-hP2HwLb(ng61R{cLZQ4ZdFgzE3 zI~Eu3g1P_KjezVGWk`NH?iVe~8h+kFET1b*2HpJ+w%@hj1_O^O^8G;YUT!``!d7#G9iVd%^6Kv9s1mQx4&$`7{W;9_S5 z7NZM1h_YKDGHi@LS5Gt)8+U@IZj+^#d~wp>?ZE{3O%tX^Yf4Yf{& zU|;)7&;2pzsp)9kzYAu~mFpa8$;6Gpsqhy$ekl_Yo<~jlS+w_y1TB|oP+Y6V!xJ5U zX>JZq#)P0Gd{S}6vtPZp5#m50q9;4{=7$A&VA;!Q_+VohWGy;yCL@YISd4^OFF9QT z=6munX2ozc>~DtrR2$kgWw=`_&$IzO79LHM=a7`=y~%FN4mk#GzBoxaal=w?gd! zKwYGQZ>sZEn*Y{H4)7NeCcaKW>U%LZB>-7v?wdMscZWlELJpby9OA?7a*Iab<&Bs} zp6qkRnm7ygHC@7E(T)cq0PuMt+?Mh-&Xs)xqeTObBYd{A60bi#*kzK|Q?WOJi15Aa z0@O8H$d0vQ#LKQ@G@`>K_~*=IELm5Kj88sC=q(cwG|qmWkkvg(1Q@eoII4fF#`#^_ zaA(?kkceH!cJMtV82+ynC_VTCvQO^9is4T}!guZ1^A-o;zO?tSC-(#FJd=rkzdiy! z64y)I6N2I~F=Pmq=N&@sq9UZdmF(6|Y4c_d#)+ThsI2RTZ149VBE&xUlv5gp$6)a5 zLs9uzIfx?|EE*gy`v_A~-iCnZ{2pVbK7poFd%>A{LgY8p{ER1K$6GB0JHxQhJ5kz} zjuYqGFy&U~8)Nl{BC87lW1YV@bGI6T|2<*iICHocqX)Z}^w$f4gpbfM0jND!h3H`S z&sYtgbSDh0El?E~;!ukew}*~^kI=P4EWm3JM#nvkQ^oJ$z=cK(i}yuBlzS@Xo5}Yg zyR!xxcO1uhgZz z`1|(CxJ)w0PMAs9!!1@SirYHssG>;KsYSq?JYPGof)3(m4C=L__*^od2 z1hUB9xl3-}eSd$16>^t5IIEIIxSWn~D z5=Q^}_W@lOl^aFO_*fb~tYdlkBTUJ-lmtVz-|M|0&NKi3AOJ~3K~$9bD3YhoqH)zH zly=wCWb0=3h``QZ1{j@qB5NzZVM?J9y)N)PqR!17KKJA7*H_DA=$C~d!h(svVU9tk zL?-Lox*w>l^OLZyOeb0w_@ovx8KZvlJ9aPqE6eNFabbGkfhaHeH1z6`Y^;8rtIy01 z_&Swb!Hs?ry;)1ee7Y1Lef~{XY zUx-GDd}u$~x8~@FzbPX%;0t8nr#S9~a4gtaT1dJyui4yww_fOV?KAHHwb8GSnt#jm z@;ZK<;Et|j>@R|w%lIIZ^MXR$@c<@Z=-8ZlzlIRwV=_}TwY1W`yckG(+&l_0MJ5_9 z=?admEhbUBW}D-PRC~k#z$8i&Ew(Y7uL2u?!r9dYR!04CR=u4r`q3-M96sIPid}?S zLBHT{!;=LP1(BVkpuIDw^^oL&m6?Ntpl`!K9vQ2aNX(IqGjBHkRN_=VNlJO^oZ_3f(WhJMg?6F-xk&kVuzKttn^?rzBA}zaw#RPWsD$2h2 ztMvDNoNNR7L5Q7MWG(I>fn@q_C3m#a@y+${I&$j)(U9^MD_a-mjk<6xod;~d(Vy++ zo|_r1#hWT^z#3n=W^%SPGRsa?t4Q(k_LH`a39LYlPr}6=lNizL{EsZwrNLjRdoB~T zMKfF&6_GYB?pIbrdh(;sG-*f(d+JF_vOfitzTV%#3S8_0Jr9Il;0MgU@M_WXv2U|ze`%C?SuQUM)*hh{S9EmB%j4~+K5r34o%*A?*^+uN6OMHXR}@ta z1^ifNwh=0)H`u&psOp(K&Ml`t@2oY?h@3!H9)jp%pL0F6zf9_b$e%dqmoyN3752j1 zH-Ewt%Zp8OL`LZKBv1nd6x^l~1zwNth*Kd{dT;mZ;lPu|fbib~TPYncC+0)CkfXPJ zzXo@8Sqz5&xx<^Ae zxMfcuk00YyArOFG`>CXriS*7l8&W`G-7C*LP!A&4zFJ$CFV}LoT0fOShA>fGy&zEZ zX5XY=W_!_&w_@iZmvP3D+#ph~;(R8MxLbedP_*XYCtibIBfex-E2~5BreF3tVFT?! z!t_B(wswO`%Nt8kaEjK#?B$Q^{;;DW{iiN>ciV%cj#lemGg^l)e@dn*`43udMyL~e z_}80b5`O4UG}Be>r{FKw8vSj!UJ@vrpVMRDa=kn0I4M1i=hl4--bTv34ux#R`#0{8 zS&2*6*S+*fD$kF1P5AK7tV(@%J^IKEB#(uhfi}f|b)F&&ZC$T5kX13p%g=U9oS^@V zI7sWgU(Bh^5o4yBEXk`Ld*e~aD9sGnpByxGmNH0#Za=9J!MJl@q4#IIl-LA-y5bTi zR^L$N7xZMR`@pT{8nL^dv!3 zL&6Xijghpb5=_0al$%C}jnewJg0jYBX%rT50hxB?P${_$z1XSN#;61f@}1LS9;_mb z%Yn6M>0g&GwCZuL>;o1CBds)@#RIFLmtut^5tXh&X%sem?>BCyXobDuQKIG66F=MV z%)aRcdpsX~pX_{}974zOG4L}XC@sEss<91&jEouOqit&}jtfB?@idQ<^&q=pCbnWv z`0HNPtHYW1B^ppZa)i=kya+aifNa#}?bmME_nP>j?Lvvz{I25w{lO(m$;65aZJ0yH zys|gs9!D@NtC=e)iO1tv&|G5`K&aZ`mx!0OUty==E(6#qfA~F9{yNZRP_2aN2T|aI4FAvy!NF033F60hX&t$VU zBWbVmzePX*aLAd3*wVu`^|gWeLZ|nX7=W0N6fo>w?*g@7O~xCwT4#bZ+&WO zrbVT*{WJL;dAg$A7su9D2Fn6*G#f9vLMsFM*^!{Ue&R250*HcZh1D)XbWSSh&vzvw z9E%U;zt)acE1y!nV+=9Gm#ap%zu3DA-%;C_-x*%tVU#!dx&ypV{w&@o(TUJ<_yY`* zS^BAN%w)CG?QEg&wZe!db9`LQi?)VU1T`g0WXO5muZS2Ca>T^%>22Rx!0bDnnm$HO zB$A6ninJFRDZ-G@G(NVSfMYAUXS5((oeJZ%g-7h(U(p!x=92XCy_wpM;YiX@ivQODKZCpfw~G}E}2L4?3-^G2{wEm zI2!~%D9iS{v5!3$em~E<;)mtzMF}oK=Z@59L~-#r|9+sJ-nhPd`cYc^Uy&2-oOsE{ z<*Sl=hyj9bZEI!t;ZJ>Y#j7kw)l4U(i!j}k)aBr@rJfd%6eV95;dI_NpaFbnxWY6pWvHN&W^QoDp>{U%}sK+e&Re^j!&kcVMpV_=`oOW@xX6kIh!mgs=e1|7O zy+q4xQ5Vcjro5{NtdE7{+gEk7Qit3DLyZKUQl|88SqAECU!e4b#pZ(&`t(7Bc40QEBQJs6K+ zJ5R+@dAP@{<)|bGsY%m{m@j%i{=87F;nrPW$93f)TW^oSotQ#Y$9$!gJJ)~V`4nj#MtJJT0B7-xEYsttIAegnC*_gJFKVLc1ikJ z7r!r6xZ&h&d0!D}7klz0qr|8?cx$rwj;Z}fwK`fhyRXql|BtByK&YYQ?Prf)XY9`^ zk)q9H3p%g|O7TYz^tHMZV?Svwj!hT%XJPczgun8I7z0UI`OVF|9|!>75Tzb7$)B&u4$)PbIoW zkE1eMjT`Kvd?o;SVz-Wr3S>AGP1iuTeI;1x)h3{M=qq|W zr~{b1(YNj+2hG?|i8&CU>z@Jv;l7h%O(i+S4}~Iu*=(Gu@Hwx<3hfJejUdL4v)o!F?`#T|rsari1B#!m~ zEb?))6UjUjJq*D4@(Lzv8LBIv&tHV!#YVeLp85v*Jpv}UwpEPqXDwC=D- z*AMG%3*#$r0F3Pm5Z<;NCjna*+1#0^uF$AeWAiR+v6kO}G@%bCxOly}5S}xfA{E2x zW;%#Te#Ml8O2!YQf*-oqGjPf$U!T_aJ35V-mT;N+o!EL~zKfP>tREgg-ksF6?9+2i z*8d_&yOcE^;4FwSh%EA=*%j*iVkd}Rl)4eAT)8{*tg`^APs3N zbJWHjcbkqnUm4&*5+2WgL33)aK6Ss(BEEm!0b?3^zF68uz-n~v%dRN2j;oglgZ6S=XBw$_dL(b3kxQ9sCX){0(|&;@Jt zR@7j}CUMT)=-N2BQs6-*fW!#&7574xzLBk>|JoocD}5SN_Nz&kK~?I*gvn%M%ZVyOG6!!1dai4lFy43C z`^+4Z&Gjg;TkC=;?6SbiNF=BU5zGeG8jR<8IB?yJtQ9?qjKneEN)SX-@e6!Rll=h= z#?Gydt_{;#HG$ACO1aU_{q@NXw(=UtQ@HipJ#EXxxwp8nK4tbxMd;7^;k4$}uXZAG zev+N~S%yDtr1<&d%X-HhkBR1Us&lr#A!R?fOXYM{itBLN z{j!Oz)wYQSgO=upk?86K>*K<2Lc6a{&%F{cIfR-7k6*)3g`htx3%J{Go54ZznVUw~ zbxt>VfdNcY!{wb=H}Y^L+VfleyMw^qdYu)r}%|qFubm?HAZBw z(yVJ(ske@<>y2+y!fbo9=GxH4Ml1sy)OWaf<6-0Z7}(`gLuG=p2+`xG0M}L60v?k7 zM9ITy>JU%TgffE%sSgl`3lSEliu@qY1dN(6e_CSnl3dl;MDC)$ReJCWE&n#9dTX-K z?quFd)j3AF+JQa*P7JtM4+slcL4yrd`z^YZL@a=>1txVMX2fpbpn7sn z1z0{kWPQi$pCXw4@X)cx4fFbPq2F-Eez9)1)wbLJT$LAccgSR`UJ<@LSM8B|2|iH3`qEMK+*^;Bj0^4+|l0KpCp2x7+{Ob zqDzs00bX;;i_q!!-Y=6;CE37q?(7L$5?KFsXbQt46qQvE=r_GFdjKXNv`%mH#KD;6 zBoBLd*cR2-eLu4^d!~o@D6Tt}H`W(Se+H`>!bQt_Z}Pdn>;M}?IwIH_S0cqc&LIJi zDOp_phupy4Iun89DrQNtoWW(CHHp0GX|vKUTburahIPjqN+5X@hrg)t_5QmnhJl37 z3h!yR$M@iNw=Nf~xX%jP8{wPfW3;Wl{QAq`wapSSZ{d^$=~5BUIEOGf)Kc70_YZiU zx#%VH?p)iZ^B3L*HXx40T;5vVpQ0!=9L1}6_)7`t}vZE&5>m*3!w8JO) z*g~!|8LB$3bAM7_@T_n0b->8UeKUS}(9Ex$W;(_`-?`vDIyFqgoRljq8o5j`U49U7 zxPvc|ip^&2t3?3o!SSMkuIe|7hQZwXIbU_=)!vKFj}VrNL4s6B55rseX8Z?)a3$nl zDb*gUiZ9Y<)vr8PKt4O}Qj09P68Kozs|e_rJPWu zv$ww$CTYr*pM)B~*P3VI^6g?{uv@#zQ+fk(J{>etMP~lvk=umu@PQds<9i)65Kj*; zq2ke~ot}Pdb!nX@&Np;jy0A`b_Ey{w?~&H6|CX649gNBB4Y3nBZ~t(tE( z0<_XQlT#`{SyzMVlewx4U^<@X1~rV14o-RqRqL*$get4jFdpvl5ZV1z^&qiwny1ThAQ;QD9d~08Zy;uyC6U?0?TMUx zt(r6g0(3f-iTXhWO~3Q!&59vbX8mT^Rd03(RVN3VH7*k{H^ zhl==Ia&T3Jry%y3YK&RSE?JGVK7nHfhjG+`4gCoU0Nd5}n8Kpt?a=3C6>=h0iQ1Mj z0>!`Kd&95R)lJ9mm@vfGzS0Jm;+o9@`uBSOTGJPOeoFtgRy95)H9}{OJx{oJxu+-J zVq(~}0b6BPe>s+-uHV#ihg(h0Ph7s`iMzN($Tc5bU48!I5pke?H4y zR#>(Z5I@6STk*1#>MvSN>VDOTdty>nSA>*MO277XY1+GbE~uHX$}E!_#JC zI_iY{jZiz_rK|pyh~54%&3oB_hTNwkbI$-Wrl7IoLzX_M=8SAlG&Wv5l6F6XTZJIf zexZ-Ht549VtMcWjg~RIcmBTq;qm}n24;wA5?&j7G-&Si;{xTljN&9e;22FU9#1?8Bs z@d>#mQ=iWs-la&9tgTezHBR@;JoVpxz&6rUrZ-*oxYEo7VR$gE%9?z?8+NPile#|e zPEWyj_IWUrgw+{t(e&)GG-a2`bY?%%QKxE#CF>uFn2pIDnUdM-N8fzEywI3aUyo(C z$wn?eRd>O;5W@&ANpc3@5^8lcWNuS|S+pP>!9b@61c3gIEFTB{k76%BgmQwEzmSDg z=QS($^KlKIhZ`^0T05Fpi5;IC-vAAy2ZC7BO}m2U@m9omMdnl|h+9FE=c&x8cSXpZ zaQU70g70Y+%EA)}EoQvKj^YQCI=--a_v0@z#+H}$<}c1g*jo!ju1WCvAwH(IpUjTb zO)@dVedAhKR~NKN{?deVgC&+(X(b61OX)H_ z2>oL+GQUjjYwCOY@ie{~p}2sEx<-LW)ctp32XqBVrUr=vm3!{L-NYD2I<0oY7@YZx z4*%d4)T!($-<&c~%cI(M3sL=yNN#=W+a7@z5gaG6vB9Y>@TFBo4~=*_Qk?Few!ATD zes&ykBHlD1SJ|orrF6^OJ7g^g2?o9 zn4Fp?8cd{kG4{~=18Gd@y_ly2QPQ$o525=pTdlPo1IkAh$xq?S6`#{}>^K`1z$!N4 zl}Xjt)pYxHs~lEnR4z`g9_#zo(srnZBZIdR-pVBKLe&!lIySINg@5+Qf#b4(w#=_Zzb~(KIM@!8uDO?fb1p@6 zaFh5sTOyAm#+%6NbDCV{H@~Jf*VQeSl-0(iSI}?)zni*O-`xHfQ~;f0$-^jv1cP_E z7zTN-*gMZO?$pUz3?z-*(kDw}j!{O84kgHN{xn)+N-k$2T`NRmxJNYe*sVZ@KBn~y znhG5aKTkCK&T4mC4Fw+;U&shvYV+|JBq{nv6F19(Tz_U`acoLbV99`H*iDQD)2zHz z>G=*lxjuA~i7)0WQ>UJh(GPJbLT8?(Yl1l?rv7A~#$S8I+1 zN_H@{m9bSVg8R>N|6f0q6HHJZW-}RA?|sktQm0O>ov*3jg)sJZV#}cEg6Sc+OHm#t z^u9o3h29xNPye(=IvfxehgjT|7Q$s%`9W*Fa?*-d=#G;A_~I7(_=I zJQS-nX~mHoPsovdO-%-rLd)=Y0FAuWIl)@|1l>G5FV&#C&w=k}N#n`2jWqGY5YYg1P;VK_3SP(( zvb;+cEcGtVO_CeNTa8h@_#tA+(9RC^p@vn$k`)L= zw<(%$Pfp+JR8^Tas4P$`F+sDf!uQMML6vp`J45N9P1fRyn~>oBCHHBEGb$3>D+)PM z5YHhTn#n2oL<54{{^AJ@=AbFHf?<~lOUT_x^LU)sx~Y$Du&MFHQd6Lv+$PwJUSH7<=00PVy!W-o-dMxvDeZ zN{`l^nmbB;#0bZ`uOrF4F}b*+8j5&SIEtj_O}c=s)AD}DyYEG=H@pY(%VR_ZPXK+P zgkB7Yz`dcGP?kAu?3$)TRBFxpAVvPF|ZtDzhy1|IusKqqgy>RYkY2F4)6<2vJ{@}_45b)YRiS5bfRw?^Y z6d}r|SR3Cg`WxI?O-t<-%8Qo9DP=m~21+23xCOzRIFYg!MbD`0PSqW%bk0)~*I3rx zuff>Z*dfZrAW68gBH2n7*A`D5ZQFFt^FlrMZ2|#awm}WWy|K(hm(gMGB-j1!oT<1W z1OMFIUvdYhk_a?_RZGY>Z|I{(*wj#rJK&c0I3d=)m0%F2HXZGF-bL$9a0h^oJ~c)E zt&3Wh4}jU#MXg3c@b}VDLy<-*_{{p6e5gl*N#|iPBC^Xin*weuVhdEf6V4JZXunn! zIgDZH#ryxN>EkGr`x(|uY}k&2>a5qw*~%d!X_ljsRlM#K=~$E*Vg)_C?${?fz8^I! zHHZ$}?kA8NJsR?2gle#3yRfUfB*LP3-Ef&2m~*PC1zP`>A*{_liN0WDCUTqnoktXF zD#~#uM>7au-M6_eV?PocHmT?Io~|8caPNcs&~@Q1`M4d>M= zgP!Jm4N6oTtJ?8`4TiP$L{o9*vEb1RS9=|4-;L`$OYJX|{9sd}gwoo&jf6Hud9;QE z6AyvKh31Sc>;ZH$oDZKYv1xO@SS$jT-Or?LsHJzNmQ;3b_=dLnr&Pm*nS8lCp#or{ zzmFA;svg}m+skpW39}<;a60VPZ6kd~7>dRVk)cdvkjeI^XA<$Fx#0MZO!-ihA&h% zRL6PaVoK$VWHaRMOlUKB2-ie7gWm(gbJ?_%O8d;uW$p0RnH_DYw_H*W+sIRCpx;Dh zq|opConALmi#&e?EYFKuid{Fa{rNP0n07A$PP=ljc4hv`WT$a*6)^w`5Rr0qM}@fq z*le7T4T`5{FV*&^sCnv!?UKxQRyXJ>w9fVLMdNqx4)ZWCy5J18b>EQ)JZZ=uo&M^w zB-9+ZfpQ+mv+gF8p(t*~P>?d&86)?z;aKT&IG$1u#mU(?xOEQj%g*B%?6-dLEzoIY3HI;BfYm!oaSGW^@Gi>Aq&XJ*qwD86~!7_3VOIk2tI0 z(LXlS2k6;pge8AjFkNzNb?o8j8vE;AaKjsU$lcLAD?>A3fp(HUZWxc6DkE@OvEcOx z<4K6TSfOBK$#cDvW=LF74^Jr#c0?#_={F*P-E>>JxO&9badYUz=|*Shz-{rq&`GG1 zkngu|0R^fwkqh(B3rMWf4S6Pu>Y!Sa&^YXyUF8zcRb6yJc^`v|F$n3pXs*hZ>BFB5 z_5!}+<5?c-&fVwht==%<4O;QM$$0;zhZ+A%_0EC%vd^}a9Wc`^uOyq@ZPaaRzmWj6 z)G-D5#eq;}g}@7>dk^I++Od!HR=`q7)rEc{oe0tz^lrBVx%%F0~meG2I%k5~6h z?ktd;(Cpb;V)ha;HfuKFzzcb7!@*DHyO`nttdFY^iH>m^QGdjt%-0NBLo?ybHn ziH7p?L@JffbRAnr%kCtQ>}G=0*&wA1vBkZBfu$vx$+OoGF&v^|`a$ZU38!OmODGoy z45Q|6igg=mYI4XW?hlaTaQ(BO89Twxk0PoHxFHcrZ+)$tes6rgsPuSM3V8QMMWlOm zhy1a0vQ`O**v+ljbo>~`V#30cF(gEDK{spQ zb`_H+guH(W_w&r8$eF-#jK~4~Vi3tfz_^8R}-Y~va zk2CZ6NUW4kXO^Py zLkJ3U69r-8$pBSz{7BeJno$sI;Wj%Bd91+l7)%hZys@#dW~aXp5fRa{_t7uG*ZZxm zrjvK%u_&Rscr!l8-HM^Qm48m0LR*QtkO15nKjNvRYaBPk^gTB|2tRBm8ZO_$loz07 z@qa40!wt!avUD?+Ky?ekmZxW6Xuh73d)P0C^}LzY0Lr1*r@^p2&?9z8N)KK-ehnIG za@uNoJS=}05P21~wPjQkx>04d_xWPL3Pe2=`mj+9j_a(@l<^4>3rIJ=?kv!~61{GJeRX>#U0&6_ z^gF^U2$P##>z<+V!-)!%97cVvLJRiKRFPb;n~rS^s4oAsoC0+?H>O~Ik!X$^jtTr3 z7n$61{hj;S>X=PcJAMTu%FIX<@rx_mF*&+6D;+bl`Qc2dtA~dR#IEtfQG@33FJl^M z%;yO8@BnP?l0>WtkvBn}RZpr^U1#9mQ#z=Hts79!a3NW<5^-7Mvb3Fxu{uObs%qlE zby9wEV%kgvGTw4uTVp{@fps!n0!#iGtA|wdoCOCahtJhwV^!Oiy)1|EboF1at zkWdPOWd=<*dB2JxhJ?V$82P+Kpaa~Ck$$jqFOOk{7>QOz^&N7CpS)1#C7{*5lzNP{ge%Kg{MABqA9%tsvx1dCn?#;z_0l+R~>QN@^W5&dR zzukx>KyTy@|4*N0`9K}#(7pDa%gT3HKF)APype;3o6b5)^mYIBLyo=~>SysU?|uv# zQmQ+{Z497j;MKT_$^-NX~g zOVGDdJX^x6>1sMFKo`Oh-7-PvTL-h%MvFN(@m&%XyNKPf1eGs*(4xI?70{x_?{6{D zi;3#l`Tv_tU~zQUE@$|&9~C=T#xrh+vc@V1^TL#!k9_%4z#8I9Zz`hnCo5HWq=rZ45K#Ka|GE@&b&gn86XM-lDwTVXTZ8(z>kG ze3DQdNq;#~S4!%$Iz=37i1KQ0Eac#LbxEMQz-^Qqs5u#r_nz+KmtF@sCUq+n32z2P zevYO_lx89QkU$9)H%kf?XKY32*yJral}|KbZ?i!vM*9#n1ncqm3h zu@7CssTjZ!(BOcW{`G7kvciy3`2d=ZKHlzy*n9Ej2Su*XAp=pweqZCIpzCdFOMFP| zxNO0OI5|WByoI2W~CiN(}k`g4I26@-y1PN?xfAHd|LOG%Zq(G^9lADpZp) zak&lIZl?r*7xc_$hWGzL(qFl*tRyb^Qv}#>6SGSKGYC{3-S0m70mmZtpLV7#CQuCV z;fNx(m^hC^g+)Tm1x{-%6KJV?NJR^dfci_gm1;fMIE*PF&x*B!0L?JPw8FmldVdf_jEX=6yg-!-+Sc{8tDHd@T9i z4pLD<_PpVsAJK-CyHM{oNUGuj_-D=H(&bV7{oVj*Xzz~uOJ5M1hos2{wN>%mh4gQ3 zX}y_|6sTBP?8F&YV5I+5*Z~i7{8P|qKcoy*6xxuI{};?KP{}YRR5J=hQLJ}e64$bD zMkS&7sGNfkDt3L71omgPD>4YyPJa;qPYuO(C4>NyYz37<`wWo_;@_ z^V(ZuHu5NB#hu}G(MOG)%QxFDt2~m zE&&W4gtEy=SXt3c2tP4i?M+A*Pe1s%q%9-a-~4?x4WhW_m@z~21*t>X)Z((UW0Xs& zSy*Dz(}}BM&CJcGmX?P9RhN>2cWA%C=P)1L=Q+NR{OS0O8XD$9y1y3BFvQ-%PfkuU z8gyiG+06Z&n+sdC-EBFlENE&1*VM58qu^U3U?7$G=fOW!ccKQy&wOg`oX7@hYZKqx z+%)Mj-yScDtE;EX55Pc~-1-%GR{jlW(|QmJI;u~D9fW&7W8|L~jw3o`T!1a-8%bdj zI9L1z1`~n=PB@u6?u}pX2Sl9v@H9OAY&$*H{8DFTRGFK%v6q&XJood$Khx6_Kd+cU z5h_-K>PGZFjT)%z=l2qroGDIgGG@-<(DCq(s{%?=1=%x!acH}M*V59;be#g)LML&y zT!X`5RWQH6&!VwX|4u}3fzRntQv4PcIp}ZkY8_d!uC%l2Y22~_0GPl@?ST)s0j5+| kgc=<(6pR0V$EY_1QsP^sw!JwoD3K!!P!c3jDP|b-e`LYefB*mh literal 0 HcmV?d00001 diff --git a/tools/images/chapters/control/lerp-quadratic.png b/tools/images/chapters/control/lerp-quadratic.png new file mode 100644 index 0000000000000000000000000000000000000000..78a2fe515dc9af52ac31866b77dd241c7d7f8ff2 GIT binary patch literal 13980 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

vBUh zs}>C5u2AxVPw-r$oN3x;;t~>0=MyThD$^O^l)|DS_(;02>0H&mKQTAxk3Vd>WvHyI zL~y;?&RN^osG=2vu7Bi7BwHJIf-=7arvT}H8XVTWtO|Qk2x>*qfq|&l4C;;}l!wia z?p5Xsyl7_Q4^XVp3b@!FoQbnN8ibockKZReywNJvsOzA{UD2v>(vBi)!m z!=G*)ad(*>JC)v}dvVp=Myzf)5&AlnU# zkMH$-@j8~x1Y25K+U(88oI#0jt5|FQd-xIyH3I{Lg9EoxP0H4m_4@ic=1x^r6?c7o zy+46HWO!H>q{%&hez~C$onw@huXXRuO zsi`F3Hqo#ltDb=Y1`&~aPsp>g!=)5Xn~hS_8D@xdqT@1r2wdAJ`S5q}G&7Nl5i0W8 zNbHk|JM#g<1y1q?-M6Z})**z0g9B7zzQjC*9A=LP*Mqv_5zg>$fr-CbLRCy z{{AQ%0|}x-$-E`jm&%F^9o9PyqP zOA-X#uHdY+w4W{qwZBF(M71t-5qf%hB$K$JiZ$w)U9T+F)zuxrmRVZX+?D1lee((s zd>i)BE${+AlKd4Q6Tp3gn)>PG9lgXX8k9!Owc;>vTkCa2{4;PnW<4BE3Jw3-%^XJF sL!uWa7OwZUT#_8h{PO?1%ysM`bYQ`r;f<~iuA3o1g{6gx1++c?4{XrKlK=n! literal 0 HcmV?d00001 diff --git a/tools/images/chapters/explanation/circle.png b/tools/images/chapters/explanation/circle.png new file mode 100644 index 0000000000000000000000000000000000000000..9ed3ba054c28ddc3068ec636de4789f72368ea02 GIT binary patch literal 6586 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 NXkXFOEK#?9_Fn~zPL2Qo literal 0 HcmV?d00001 diff --git a/tools/images/chapters/introduction/cubic.png b/tools/images/chapters/introduction/cubic.png new file mode 100644 index 0000000000000000000000000000000000000000..eb1257325d4e8ea497fb0bcc26936821e42c1e4a GIT binary patch literal 10072 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 literal 0 HcmV?d00001 diff --git a/tools/images/chapters/introduction/quadratic.png b/tools/images/chapters/introduction/quadratic.png new file mode 100644 index 0000000000000000000000000000000000000000..3aecf69ecfa2ba4db60de3bf9f6751677909d6d3 GIT binary patch literal 8807 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 literal 0 HcmV?d00001