From 2afcdd59b1e3f309b3774865e6b79cd7a4999ad6 Mon Sep 17 00:00:00 2001 From: kekee000 Date: Fri, 3 Apr 2015 22:08:59 +0800 Subject: [PATCH] add test case --- demo/findBreakPoints.html | 65 +++++ demo/fitImage.html | 50 ++++ demo/js/canvasFindBreakPoint.js | 4 +- demo/js/findBreakPoints.js | 75 +++++ demo/js/fitImage.js | 139 ++++++++++ test/findBreakPoints.js | 471 ++++++++++++++++++++++++++++++++ test/qg.jpg | Bin 0 -> 24056 bytes 7 files changed, 802 insertions(+), 2 deletions(-) create mode 100644 demo/findBreakPoints.html create mode 100644 demo/fitImage.html create mode 100644 demo/js/findBreakPoints.js create mode 100644 demo/js/fitImage.js create mode 100644 test/findBreakPoints.js create mode 100644 test/qg.jpg diff --git a/demo/findBreakPoints.html b/demo/findBreakPoints.html new file mode 100644 index 0000000..e52e7c4 --- /dev/null +++ b/demo/findBreakPoints.html @@ -0,0 +1,65 @@ + + + + + 查找拐点 + + + + + +
+
+ + + + + diff --git a/demo/fitImage.html b/demo/fitImage.html new file mode 100644 index 0000000..52b268e --- /dev/null +++ b/demo/fitImage.html @@ -0,0 +1,50 @@ + + + + + canvas拟合图像 + + + + + + + +
+ + 灰度阈值: +
+ + +
+ + + + + diff --git a/demo/js/canvasFindBreakPoint.js b/demo/js/canvasFindBreakPoint.js index aeb8acf..5942189 100644 --- a/demo/js/canvasFindBreakPoint.js +++ b/demo/js/canvasFindBreakPoint.js @@ -114,7 +114,7 @@ define( else if (p.inflexion) { ctx.fillStyle = 'blue'; } - ctx.fillRect(p.x, p.y, p.right == 1 ? 4 : 2, p.right == 1 ? 4 : 2); + ctx.fillRect(p.x, p.y, p.right == 1 ? 6 : 3, p.right == 1 ? 6 : 3); }); } @@ -215,7 +215,7 @@ define( refresh(); } - img.src = '../test/rw1.jpg'; + img.src = '../test/qg.gif'; } }; diff --git a/demo/js/findBreakPoints.js b/demo/js/findBreakPoints.js new file mode 100644 index 0000000..e30614c --- /dev/null +++ b/demo/js/findBreakPoints.js @@ -0,0 +1,75 @@ +/** + * @file 寻找关键点 + * @author mengke01(kekee000@gmail.com) + */ + +define( + function (require) { + var fitBezier = require('graphics/image/contour/fitBezier'); + var findBreakPoints = require('graphics/image/contour/findBreakPoints'); + var pathUtil = require('graphics/pathUtil'); + var data = require('demo/../data/image-contours3'); + var drawPath = require('render/util/drawPath'); + + var entry = { + + /** + * 初始化 + */ + init: function () { + var breakPoints = []; + var html = ''; + + data.forEach(function(c) { + c.splice(c.length - 1, 1); + }); + + + data.forEach(function (contour) { + contour.forEach(function(p) { + html += ''; + }); + }); + + $('#points').html(html); + + data.forEach(function (contour) { + contour = pathUtil.scale(contour, 10); + var points = findBreakPoints(contour, 10); + if (points) { + points.forEach(function (p) { + breakPoints.push(p); + }); + } + contour = pathUtil.scale(contour, 0.1); + }); + + breakPoints.forEach(function (p) { + console.log(p.right); + }); + + html = ''; + for (var i = 0, l = breakPoints.length; i < l; i++) { + var c = "break"; + if (breakPoints[i].tangency) { + c = 'tangency'; + } + else if(breakPoints[i].inflexion) { + c = 'inflexion'; + } + var width = ''; + if (breakPoints[i].right == 1) { + width = 'width: 4px;height: 4px'; + } + html += ''; + } + + $('#points-break').html(html); + } + }; + + entry.init(); + + return entry; + } +); diff --git a/demo/js/fitImage.js b/demo/js/fitImage.js new file mode 100644 index 0000000..ae22358 --- /dev/null +++ b/demo/js/fitImage.js @@ -0,0 +1,139 @@ +/** + * @file canvas读取图片 + * @author mengke01(kekee000@gmail.com) + */ + +define( + function (require) { + + var lang = require('common/lang'); + + var ImageProcessor = require('graphics/image/ImageProcessor'); + var ContourPointsProcessor = require('graphics/image/ContourPointsProcessor'); + var pathsUtil = require('graphics/pathsUtil'); + var editor = require('editor/main'); + + var ctx = null; + var canvas = null; + var curImage = null; + + function onUpFileChange(e) { + var file = e.target.files[0]; + var reader = new FileReader(); + reader.onload = function(e) { + + var image = curImage = new Image(); + image.onload = function () { + getContours(image); + }; + + image.src = e.target.result; + } + + reader.onerror = function(e) { + console.error(e); + }; + + reader.readAsDataURL(file); + } + + function getContours(image) { + ctx.clearRect(0,0, canvas.width, canvas.height); + var width = image.width; + var height = image.height; + canvas.width = image.width; + canvas.height = image.height; + + ctx.drawImage(image, 0, 0, width, height); + var imgData = ctx.getImageData(0, 0, width, height); + var result = new ImageProcessor(imgData).binarize(+$('#threshold-gray').val()).get(); + + var putData = imgData.data; + for (var y = 0; y < height; y ++) { + var line = width * y; + for (var x = 0; x < width; x++) { + var offset = line + x; + if (result.data[offset] === 0) { + putData[offset * 4] = 208; + putData[offset * 4 + 1] = 247; + putData[offset * 4 + 2] = 113; + putData[offset * 4 + 3] = 255; + } + else { + putData[offset * 4] = 255; + putData[offset * 4 + 1] = 255; + putData[offset * 4 + 2] = 255; + putData[offset * 4 + 3] = 255; + } + } + } + contourProcessor = new ContourPointsProcessor(); + contourProcessor.import(result); + var contours = contourProcessor.get(); + + contours.forEach(function (contour) { + contour.forEach(function (p) { + var offset = p.y * width + p.x; + putData[offset * 4] = 255; + putData[offset * 4 + 1] = 0; + putData[offset * 4 + 2] = 0; + putData[offset * 4 + 3] = 255; + }); + }); + ctx.putImageData(imgData, 0, 0); + + getBreakPoint(); + + var contours = contourProcessor.getContours(); + window.editor.setFont({ + contours: pathsUtil.flip(contours) + }); + } + + + function getBreakPoint() { + var breakPoints = contourProcessor.getBreakPoints(); + breakPoints.forEach(function (p) { + ctx.beginPath(); + if (p.breakPoint) { + ctx.fillStyle = 'red'; + } + else if (p.inflexion) { + ctx.fillStyle = 'blue'; + } + ctx.fillRect(p.x, p.y, p.right == 1 ? 6 : 3, p.right == 1 ? 6 : 3); + }); + + } + + function refresh() { + curImage && getContours(curImage); + } + + var entry = { + + /** + * 初始化 + */ + init: function () { + + window.editor = editor.create($('#render-view').get(0)); + document.getElementById('upload-file').addEventListener('change', onUpFileChange); + canvas = document.getElementById("canvas"); + ctx = canvas.getContext("2d"); + $('#threshold-gray').on('change', refresh); + + var img = new Image(); + img.onload = function () { + curImage = img; + refresh(); + }; + img.src = '../test/qg.gif'; + } + }; + + entry.init(); + + return entry; + } +); diff --git a/test/findBreakPoints.js b/test/findBreakPoints.js new file mode 100644 index 0000000..5b6c08d --- /dev/null +++ b/test/findBreakPoints.js @@ -0,0 +1,471 @@ +/** + * @file 查找轮廓中的关键点 + * @author mengke01(kekee000@gmail.com) + * + * 查找方法为此处文章的方法 + * http://wenku.baidu.com/link?url=Sz1BbYjfA7IeHAMVJ1TPlXiMhACc6sWhHliPJqAUxxtC5K9PYf4j3ile6patUEUMOE_9uJdsS1EGJBFLVbhXcn7Qe8l_FxuT3QVI8nm1aZG + * + * 关键点标记定义: + * + * p.left 左侧类型 + * p.right: 右侧类型 + * 直线为1, + * 曲线为2 + */ + + +define( + function (require) { + + var makeLink = require('graphics/pathUtil').makeLink; + var getCos = require('graphics/vector').getCos; + var getDist = require('graphics/vector').getDist; + + var THETA_TANGENCY = 0.1; // 相切抑制 + var THETA_CORNER = 0.5; // 拐点抑制 + var THETA_MARK_COUNT = 0.8; // 标记点个数抑制 + var THETA_INFLEXION_RANGE = 0.05; // 切线点之间的距离抑制 + + + function isSegmentLine(contour, start, end, isLast) { + var contourSize = contour.length; + var mid; + var thetaDistance = 10; // 判断直线点距离 + + // 判断中间点距离 + if (isLast) { + mid = contour[Math.floor(start.index + (contourSize - start.index + end.index) / 2) % contourSize]; + } + else { + mid = contour[Math.floor((start.index + end.index) / 2)]; + } + + if (getDist(start, end, mid) > thetaDistance) { + return false; + } + + // 随机选取 几个点进行直线判断 + var startIndex = start.index; + var endIndex = end.index; + if (isLast) { + startIndex = start.index; + endIndex = contourSize + end.index; + } + + // 距离比较长的话可以适当放大 + if (endIndex - startIndex > 100) { + thetaDistance = 20; + } + + var step = Math.floor(Math.max((endIndex - startIndex) / 10, 4)); + var lineFlag = true; + + for (var j = startIndex + step; j < endIndex; j += step) { + var dist = getDist(start, end, contour[j % contourSize]); + if (dist > thetaDistance) { + lineFlag = false; + break; + } + } + + return lineFlag; + } + + + /** + * 计算当前点的theta值 + * + * @param {Object} cur 当前点 + * @param {Object} leftR 左侧平均 + * @param {Object} rightR 右侧平均 + * @return {number} theta值 + */ + function computeTheta(p, leftR, rightR) { + var leftX = 0; + var leftY = 0; + var t = 0; + var cur = p; + while (t++ < leftR) { + cur = cur.prev; + leftX += cur.x; + leftY += cur.y; + } + leftX = leftX / leftR; + leftY = leftY / leftR; + + // 右侧分量 + var rightX = 0; + var rightY = 0; + t = 0; + cur = p; + while (t++ < rightR) { + cur = cur.next; + rightX += cur.x; + rightY += cur.y; + } + rightX = rightX / rightR; + rightY = rightY / rightR; + + leftX = p.x - leftX; + leftY = p.y - leftY; + rightX = rightX - p.x; + rightY = rightY - p.y; + var theta = Math.acos(getCos(leftX, leftY, rightX, rightY)); + var m = leftX * rightY - rightX * leftY; + if (m > 0) { + return theta; + } + else if (m < 0) { + return -theta; + } + + return 0; + } + + /** + * 标记点的左右已经被访问过了 + * + * @param {Object} p 点 + * @param {number} rl 左半径 + * @param {number} rr 右半径 + */ + function markVisited(p, rl, rr) { + var j; + var left = p; + var right = p; + p.visited = true; + + if (!rr || rr === rl) { + j = 0; + while (j++ < rl) { + left = left.prev; + right = right.next; + left.visited = right.visited = true; + } + } + else { + + j = 0; + while (j++ < rl) { + left = left.prev; + left.visited = true; + } + + j = 0; + while (j++ < rr) { + right = right.next; + right.visited = true; + } + } + } + + /** + * 查找和标记直线点 + * + * @param {Array} contour 轮廓 + * @param {Array} breakPoints 关键点 + * @param {number} r 查找范围 + * @return {Array} 关键点 + */ + function findLinePoints(contour, breakPoints, r) { + + // 根据角点查找竖直和水平线 + var linePoints = []; + + var contourSize = contour.length; + for (var i = 0, l = breakPoints.length; i < l; i++) { + var isLast = i === l - 1; + var p = breakPoints[i]; + var next = isLast ? breakPoints[0] : breakPoints[i + 1]; + + if (p.right === 1) { + continue; + } + + var range = isLast ? contourSize - p.index + next.index : next.index - p.index; + if (range < r) { + p.right = 1; + next.left = 1; + } + else if (isSegmentLine(contour, p, next, isLast)){ + p.right = 1; + next.left = 1; + } + } + + return breakPoints; + } + + + + + + /** + * 查找竖直和水平直线点 + * + * @param {Array} contour 轮廓 + * @param {Array} breakPoints 关键点 + * @param {number} r 查找范围 + * @return {Array} 关键点 + */ + function findVerticalAndHorizontalPoints(contour, breakPoints, r) { + + var contourSize = contour.length; + for (var i = 0, l = contourSize; i < l; i++) { + var p = contour[i]; + var cur; + var count; + + // 查找竖直直线点 + if (p.x === p.next.x && p.x === p.next.next.x) { + cur = p.next.next; + count = 2; + + while (cur.x === cur.next.x) { + cur = cur.next; + count++; + } + + if (count > 40) { + + cur = cur.prev; + //p.right = 1; + if (-1 == breakPoints.indexOf(p)) { + breakPoints.push(p); + } + + markVisited(p, r, count + r); + // 判断是否角点 + p.theta = computeTheta(p, r, 1); + p.absTheta = Math.abs(p.theta); + + if (p.absTheta > THETA_CORNER) { + p.breakPoint = true; + } + else if (p.absTheta <= THETA_TANGENCY) { + p.tangency = true; + } + + if (count > 80) { + //cur.left = 1; + if (-1 == breakPoints.indexOf(cur)) { + breakPoints.push(cur); + } + + cur.theta = computeTheta(cur, 1, r); + cur.absTheta = Math.abs(cur.theta); + + if (cur.absTheta > THETA_CORNER) { + cur.breakPoint = true; + } + else if (cur.absTheta < THETA_TANGENCY) { + cur.tangency = true; + } + } + i += count; + } + + } + else if (p.y === p.next.y && p.y === p.next.next.y) { + cur = p.next.next; + count = 2; + + while (cur.y === cur.next.y) { + cur = cur.next; + count++; + } + + if (count > 40) { + + cur = cur.prev; + + //p.right = 1; + if (-1 == breakPoints.indexOf(p)) { + breakPoints.push(p); + } + //cur.left = 1; + if (-1 == breakPoints.indexOf(cur)) { + breakPoints.push(cur); + } + + markVisited(p, r, count + r); + // 判断是否角点 + p.theta = computeTheta(p, r, 1); + p.absTheta = Math.abs(p.theta); + + if (p.absTheta > THETA_CORNER) { + p.breakPoint = true; + } + else if (p.absTheta > THETA_TANGENCY) { + p.tangency = true; + } + + cur.theta = computeTheta(cur, 1, r); + cur.absTheta = Math.abs(cur.theta); + + if (cur.absTheta > THETA_CORNER) { + cur.breakPoint = true; + } + else if (cur.absTheta < THETA_TANGENCY) { + cur.tangency = true; + } + + i += count; + } + } + + } + + breakPoints.sort(function (a, b) { + return a.index - b.index; + }); + + return breakPoints; + } + + + + /** + * 查找和标记拐点 + * + * @param {Array} contour 轮廓 + * @param {Array} breakPoints 关键点 + * @param {number} r 查找范围 + * @return {Array} 关键点 + */ + function findBreakPoints(contour, breakPoints, r) { + + var j; + var left; + var right; + var max; + contour.forEach(function (p) { + if (p.mark && !p.visited) { + j = 0; + left = p; + right = p; + + max = p.absTheta; + while (j++ < r) { + left = left.prev; + right = right.next; + + if (left.absTheta > max) { + max = left.absTheta; + } + + if (right.absTheta > max) { + max = right.absTheta; + } + } + + if (max === p.absTheta) { + p.breakPoint = true; + breakPoints.push(p); + markVisited(p, r); + } + } + }); + + return breakPoints; + } + + function fixStartPoint(contour) { + + var i; + var l; + + var minY = contour[0].y; + var firstLine = [0]; + for (i = 1, l = contour.length; i < l; i++) { + if (contour[i].y < minY) { + minY = contour[i].y; + firstLine = [i]; + } + else if (contour[i].y === minY) { + firstLine.push(i); + } + } + + var index = firstLine[0]; + var minX = contour[index].x; + for (i = 1, l = firstLine.length; i < l; i++) { + if (contour[firstLine[i]].x < minX) { + minX = contour[firstLine[i]].x; + index = firstLine[i]; + } + } + + if (index !== 0) { + return contour.slice(index).concat(contour.slice(0, index)); + } + + return contour; + } + + + /** + * 查找轮廓中的关键点 + * + * @param {Array} contour 轮廓点集合 + * @return {Array} 轮廓点集合 + */ + function getBreakPoints(contour) { + + //contour = fixStartPoint(contour); + + contour = makeLink(contour); + + var r = contour.length > 16 ? 10 : 4; + + var contourSize = contour.length; + var breakPoints = []; + + if (contour.length > 60) { + breakPoints = findVerticalAndHorizontalPoints(contour, breakPoints, r); + } + + + for (var i = 0, l = contourSize; i < l; i++) { + p = contour[i]; + if (!p.visited) { + p.theta = computeTheta(p, r, r); + p.absTheta = Math.abs(p.theta); + + if (p.absTheta > THETA_CORNER) { + p.mark = true; + } + else if (p.absTheta > THETA_TANGENCY) { + p.markTangency = true; + } + } + } + + // 非极大抑制查找角点 + breakPoints = findBreakPoints(contour, breakPoints, r); + + // 没有找到拐点,说明拐点不明显,或者为连续曲线,这里采用4等分 + if (breakPoints.length < 2) { + + if (contourSize < 100) { + var step = Math.floor(contourSize / 2) + 1; + } + else { + var step = Math.floor(contourSize / 4) + 1; + } + var startIndex = breakPoints[0] ? breakPoints[0].index : 0; + for (var i = 0; i < contourSize; i += step) { + breakPoints.push(contour[(startIndex + i) % contourSize]); + } + } + + breakPoints.sort(function (a, b) { + return a.index - b.index; + }); + + return breakPoints; + } + + return getBreakPoints; + } +); diff --git a/test/qg.jpg b/test/qg.jpg new file mode 100644 index 0000000000000000000000000000000000000000..089bdfcdf591abfe3e0147eb9df3fe0529705ab3 GIT binary patch literal 24056 zcmd42cUV+Q(=WP)EJ>mWN{}2RNE9SV9-?H)pn&9@5f~K&Bo8o19DyNA&KVUXOU^kb z$r%LhfP4Gx{eIuQ=RW8BbBc#vJ*%s#f7QLZySi4dtI?}jfIwabECYZ*AV3cJ2V6}6 zk^lx88X7tp20A*%Eezy84i*Lm77i{pHV!s6E&=Wh5#ZwACb*4{OH52cLQH)B-o1PG zY5vf)5)dXPCLS){T>^r;6r_Zt6n_f;|7Nb5075JjK%F>0ZHe#(6r(bUUiL^F0Rp~WnaGDW#HqN@{dU`|Hk+Z(cGtHxS|VTvf6M)*lga!&!2oDCY-* zHWc!+8{~Vv(kzqD)y_4)G6-+Vpe0wF_|I#IhX_mVl-& z%IQ{>rJv-9sfC^ZDgQ?pRVhDj#`A_5C5nJW^Yl%EqeiA;Dij|loj}KX${>>B0Kn8u zF#f*S>K@6xYULsJlCR`2PyOuRtuJsgUCs}$~zLn#AIpPRKSPQh{s87+{VG$m{3sbePdLE-ayM~`TN>feU;mK-EHilJL> zb8dk){};ga*xX%no+=;O6=Q#V-ZSAuVcIjOph|uY$d=dV@an>>E@ZR>?*}}h7H(jL?}KLBCSvz5ddxHKdsaW=b2ub1U04H+ z2UgNEa1z@bQ^$)#B3~*l&y3PaR^UdorwJFJZ@qhLFBWDx4JJz{LNUx7 zTq}QU`y;c%+=eNH9UNX(Gaj;-k6~*3gyw%RhQ_wk$hMw2XuO^&cenrTA=g>Nx*WFr zH7ANkq4}hWtbFFrk_Sa8Qs-vp3w{WFVXk|q5f6eNO+-;zx&}g(dDm~V zsFCQ%2c5UIH97qcHT`vKXY1Z_cSXNdq1K$bVhH_Y+=OJ{z8=qvb`eC{opIz$Nnu)= zPn|7-4DC=0FSB&Hnv!s#n}v%|v$LXp?jdZdUNTVO=?)Vj--w1~;yiktk7 z_hj;nM_KpC#k*<`l=N>^fB*Vkz%D;o?YChOr2G7F-@oJ-xhIQG`ODLb)}Quc zl_<(QT^doTedEAMYFyi7^8uH+*F-je6m9T%ek$x92iUf3D}!O37WCuqO8&m077C@J zpkmUxz|v$@5c?Yn7MvZbQ9zR&Uh08UV4a%X^L_&kv_Z<#_vQu@T|~WxLj+jEvlHgM z5p@Z87`D=8O>r!?&Gy53^(L~Lv>@`yCok7yB|S+pjaBu;p4##aQ*r9T`6~SSAfW}6 z8iU>;9(e-yPn9_PBL-M1Jgxwu=>@+uRMNlU{Jw(tExvb?Da}0#QLjp?l`B^>T?p|A zt0sc#yOTdX3TD07>AbrXNf!2=Jp7yE=u`eq7JA-sgBm-|M!X z54U7#RngCmXG*)t%>CkfAmZ;e{F%Pqm@i(`C1)R@3@dfhsMI>&qUL)%A11GQ*45;2 zt!GQsVn}{Ui=8o+(rKMXpYf%v{fC%x-?VKWQ8ax;j3yTaSr%PeTN0j>n zGLi)FvJkJRa3qAp`ay5CDn^Ubp&ue7vj^|1q}eB`>S^alWer8>0>*sZ<=Z(=*3wm3 z4i?$^)R%u|5w8muMPvYU9b0`u-8$`J&h4RNds0MF!er2o@?;0u7^u&3HP%&J4$1A6 z{Eo-)S%!R_y1Fo*{}UmAN$=5bS_6B@TbZJrHet!fd?BU7Mea%`0Eyl^w50T^0rB){~<^~cE z+>D4<@@w_bUvEK=bZV$GhTldWQu((U$UG9&GHt9gy2a-1?Qm&Afcx`baBhB}+fPWG ztn=6N_k^xYkOq29F2?Oxw2so9ZX0(l16h!3CXRwmFZx8?(2$0j?;JwuewHP3ZfVj+ z9GLB`3Lol--<~uv&0h1}(B0)!Ba%+4UbwSHWaY~*@($k&6T=^;*_Pe$xTBHQeoRI{ zioG~-ThmH~Z8AJdBI1O%q{H+{L`*d$t>T3o&0VQYk71VPG_TEUCU3a-iuP73zJFqC z5eAQXZ9z@JaZPN_{&77=DZ@%Bobr&Z858<<#Wz<}sIVosfx@E%y&kqc+p>fh-?WDx zaT_Aih4Qt(d?{y@m#8N*2(P#&rZ&CW?jAU*Nsu&z5?E}06ZT= zzx7ABY9{93?M<8CS2rree?0%_6oS0}eO&!Err=quk{?#G51znJ#%JRp`;b?>KInbp zGC~u z9yI+fjOy}|Ur%P#SPv^k8daEt@_D}H7LVC<3Rj*~N00(vAV>*iZ}!zSLo$}h*!KdP z9d!Pdw!We90ppS$+mf&EG@3Z^fIR-zi@bVh*C)!><$De7c6KLTro}Tvz{PGz9atrj~;?O zgSplxQX8w5jV9dh2aS?Y1=CkK!uuZ$vCFaX?g`2X23`R<0ub|vDeJ?>QyO)-GV4s3IuVG^@`S9k-&R3VVh3fQKS3nih0=(B>?5xRy^QZS`_IM&< zWp9zy*ic_DBGiaqk%!SIywoRUSHKQx<-M1-dhYHB-&ksIIGABz>hQp(a2>SybTs_X zQ0VZR(o5K}c--{ig6Bg>J4-G80P(vVg9wq`C<+Rl!zdQJ+JjjPJ^9fMxw);Ra*bTs zoexqmsZ2jjaO26!&`m}r+$JjywTdMwUyulCpoG4UR|s)0tLm<582F%j!I0u)OxFtl z)Jjzgb`0MKEgUiACHg(Mxfe~1IUBmYvKTLlAE`Sd3RSf}#$w*?_hd{eIX%s%H!UQk z??Nm4XT$xsJjy#;zHGR;P%KMO=QQG(d(Mu7r#vjc`@At`1x4%w6hs6;%2c1zS*lrR zbri}+KhD!u4MIzsAH2U9S~nv)(oKH~DZ1wQABe9q?-1_hDzlbNRGH|M@c=hZu+!%A zxXl&t2o040DFCu`yB|T9Z?GqzlDGBL-n(ifu7~O?$QtrLDEo6uCh_UI>?lW4cN}?l zN4M-Ig|Y~(Yrn{f!meCL>B8G>P@w~om%Jj}a^m>nLgiBw`O}`~xk5%LbTTq4R11dS zTl?Ig;*YzdVU$(7y|9mF^b<-nMKP%i{)mvOpdd^dtULqPag2{&gT6h&PB+Si#@?Zg zt(vfpsh)d^O*^;!w;?6_6xTA*MpZz;9@_4BcQ; z2zyu(NMMSHr}iXw;G#DEWAyKgu)_GP-DK&8=1@FYbrBpIdYoU;)te%+u7w4$eqg0G zXsweFliqRd@1Eayy!b6b$wC>TBBCi@7rSBeI$@M0)4G#7b1Yzwc*v;M`!%S`-q#R0 zZ&yuERzX*H)#h+Xe}lK82Nh6yvT)qbQ>ux5CFk^poPFn0UlQO(%wLmW?vJI{>`z|CL<|%M{Sn4%I z830(eCR{Apr}-}|`h9dYMV|E+zH1~utTNkZhJy4U0AS{(oMQx2^slxXn*Pwv=IIdQ zL$7(V%~h8k5ze!WGP#;L;KH^xY~eaQkv_RG+aY&36yuAVP?h1=lHJqR6M3udU(f+G z!U~3wEvgvRw!BFlWIB1tMSTCgQGPnn7BAbcA8^AHRzPgu`r=71aj;8IsAVm zG`%wOOrN)Fi?PklPL)1qhF-*An=!zr=w}p_(48 z!)y3?@9FtvM|n;P=({mD=(a$GG$NpaYWo)_t3_+)hQdx_Jqee8MJab*7+p2^}-NgoG(wB z$;lVqABlq@|FW2Qctjvd+f{r`k<*K^=IaYWvh?Bm$0J>JCmERg;u16fnvA)WbhM}x z%FfTe)SQy+_NtA~WMi624V~5;Tnl-@ygG~X)zx#W$5aykAA3vWRB~c2C1dVEyKKz2 zUq+Rge4fp1+T!jTsMy8&l<-JnoOHsYk)lBGq&8y`g$K!g=Fi@efd$U75@uj%?&^sm z1V%-B&h(STiqczR#u#hWnrpsR$3IT{$pgnwAKRIp7TqDb_9?Li%3GixFfzRh$?My+ z?}^w4a+Hm2$f`d2C{CtF8iB2$z0p< z$0}Ik&}JqN+J4BX`94Y&l*j3|`l`^?WX+$i93g>*=}5T`g~&o${ggTnie|)je$hd;e@3Y z?0ano3oeL-r7HkBecqUc!vEPe1QDr$kWiAzHCrtZcCy910thNJ&uAX)Pk0SX3+p)_ zJ2#zaIY%Jps8w9p%=o!nZa70uUb3`Kia@69jJ=o;H(b~=p5T_L0H05f^obNf` zx82yXT|(ORGQG1FjYW{p(ti?x+fYKr5sR5m#K6>4{v=pW5PXyn*uH|C3swg)nubW7I0T|Bd2`0}56@G}2Coivco1B$>{Y7F5x5n)B z@%fBRKo6*K{WzHqxRE3!(B;e8K>gI8d% zUc+)WG?XXRZsC37Aa+iDJe9~4MfISi_*45zSjcz@h`^xMc1Mpttp44v`yFXlz|l|Y zi(Z1TnF653iGan3x$Zza2A>EWWx1YP zAtsjx!sF9As4RM_zsCk-jXxKiCBOU6=0fK2lMVA#()%-ptT;(L2z2%K47KSi#_X9d z-!7u+d!_nmaCQ!-I(BvtoK@1aiZ!*!VkGXglaYF4cQw60LKO)S9n3R`;}e}mRQ4+) zoxt=jx0WkO_ny7wV{3!hc(s+T@w?`$RI-4Zq^vrVwgp8{7uvxk0)$%T1n(=(X4a_J!om?&CPw9_*y<|k8g)b<&CtV49V(5}*7v zX_sfaY{Y$mp{jFnSgIl5A^Eb5_O$7vYpvrEXs1FzdkLAieJe z%TQh84~IcxA@RS>61nF)U!Yg6Wi<#c7+8Nur5D*zsnQiu4Hi9sqi%zo%g8JrleL%I z>zhvEWJhn~GnF(?^)K{Ao#7uRJUPv3dV4(r|3M&4{%=FC6Lmeo-f!%{h54ALiZWt3 zExsxru?vuFDC<8{5n?a-XU2RC!p1ipOV)#Q+&;ebQ1g-Z9uQ-n;Ud0X$N=DWoStNU zein`=4xM~RbHp3SP>UA!+95cSti_SqF~Dm=2XO^F!_Nlr<@%wJdxvNLghn@ z2kn_6MsIdZ1q-hQN%j@skkx9%CiWlD#7*|$*H|`brmlJ zh^J>9*|Xb{9e=v`XDmF);ig?`jrX^|0@i&q4yMG$Y+q$9^`ED*c~dn+(}-Bv)mf81 zZd;ftM_-83anAR%VB$vQOS28gi^O9Pp4II8=J#2473P~Bo+%f4X@R?UXHwBstTLa$ zwf|z-#6^C8ldlf0O>j5tqWrMaS+AUe1e=cJJ*#3aPl=Fg!=A45JOAh@GeI?P!KRyK z;-*#pB$)J;+_ddh8m}~(VRz!5dzSL%<2+qrl@AFfCpQhn_~yc-I^?%D$=V#v>6)HB zry0!fb_0*ltu5rZnT2hx^YIqw!5>}MnQwf~sq`rtGFr6fG9E^xt2l1K z1Y-B(nyk}u)Zv;r@;Mq*8u0^^>U%~;r0gvzd!ZMZsGpI&YCZ;+75z~Fcg_85KYpMI zU4({|(#j$x{kTt*JsnQOIqhlws*hr9XjB?UV{3KsxxCfB#@ikF8MS`>*P$5n04iI* zm3xgY+)9#nJGJ98kE`(BIF)?d84K4vW&jjuknklFmU6}xhbFhDx+ZCBApBO0UuW$; zrzH@$B~oGg_23go&(|*`59{S052q6}Y-(<*&o6KAbt6HM1*v81&uaryHeut0f z#t}nHA@ONO(FPUbc@DJ0WYRTK6TQpYw>VrG`Z>O)*QIOCd6t=5h-rDZp}GBKE^-EH zRQRNw+c}w`Zl+@BSW6m5C4Ay`OPq&73u4W#La95DH0>8aMC)g%F3x>s-kQ+JLus5d zxJ^~cJamzK8`80MetTpj!o}`m@h`8sSJW5fMW}QE#porWt{W-Vmm;WmJX3pNTRT*f zwjl>OX~$zjfrF+x)4oCqqI$&xhmdW*sLSvJy<|#B@4IVWBi5p#;affs+HR9E2L4TK z&2Q#Ed|jS13uF#3+Oh0eGQ?I5gk_Xy%{lTWIEU|x0&K=NhTymsT>(1hR5k96PKQ-f zWDo5RtY-F?YEZf$e+&hHQ{CQilJab*KTIQiR!X|7tLYhKYPqG?J1@?hD!-Ry$*Tu3 zj$cpC7vFJ`DOSCP(hy#2zvcbP*2+(%K;n&>!;qDxzWl3nxVFPNOU&E7#S#w7U2Yn( z?kqjmGNJzV?@6?3ccMEqqUU8~^xK+z{;GQ) zS3=afsm~6T-#sq`D+*~~Qu#^+WGK*Y$vX6nJ!O$GuOl?BhQPNC%5w;h7sduPe>jwY z;i{s+Nyp^eV~HW0x{<~-)}4lY%3IUY$~F63L*KH$o@<7Bu&^5s8wqz|TmwK|%hI=O zuIUe}yvL11_cd6$IW)AI92moonB2DuxXSYAybQ5)mgjTdfTTJX75@h$uP8##2=G^JiBir zTF6H&R%dU|?K|AfhXMJ;pMnuF$~lu$o@u3hE$S45IHOYaRE&YKd(Le?C`Cn!Zn zuhjJfn8UMAs!2to?|UW+5A2Cr;4uEyhVph(tyQ)_^KeCk`vE7_UH=ZTuPA?&A+fEG z54TvY7Jf@reJ)5!-nlv^OUrS{B0CuqM@kLBiyGr^w$|!LOccj9OmXu#o*C+`gWX0V zV0GD;6)3T`$r6ep3U4%Q@8#qUBnoKmri7RC`|X`^g8&EsGGtI?_6Jn*6H#TAAkLz z+8|6Rq(k2R>gR=8t|fY_?;zObahGJ2eaoVq0Hx`|-W?-Sr3YY}+6&H*$oEZvms?A# zdPTuq(sjM$`)AJWJ^}9JSqYl+v3JzWW>L-f!@5;!Y(Ln3QxPj?wRv#V|GM9bqn~sy z@-yOB8|Jk?fn0lnHtoI$-c#kBUp7V& zlP)@sblgx(iug4LJCl{#a*B@x6to23DbX7k@F=pk`}@a$p3kGca{=X?^%sHnM+6U| zlyb!a~xtLAa9uy8gt66!~|S8VZSaUEzhIQS9tuvNFc3$Y3tceo5&C zW8gEwP#3m@(355B&Ym?04DuV%?^J`bGUq%_x>U7wD~MCJXV2aJ3fMk@; zYR@8%G?9klY{XVCHhUxlI?hM?2G#QeubIPf-BF5~?~|(blRG$7Xm-e^Ga8$bf)BF2 zo5D`ClFm|a2zO3W_$*|Q_94JCDyqt?UDRBhQ}Kg7*_yIi7$Obz^L=#_G%%POVP{7l z^5)Jq3JpbL&QmYAYAk5)+b*RZeq4vGOstP7Y5{;UW25bvYf$^V%v3P8e~P6@&96>w zc3yokP93h>r1R{?3KBi*o<@53;v+HBCW%jgh_`ZImEHIR?-O4pgIv+roa_raThl~v zzCo6TzXR9<5~(xxQh&I9NUzuO#48N{o|O>CI_@mgZm*B;RnEyvczRLM`= z9iq)-s2@~n1%&0=Pr&cLK}Aeu=2|br>7Tg2On#U}p`TkTR59lz=Q;fb-fbM&cnV?2 zGjA@nb*p*e6-E^Q%~hGJUu`~QsdlY!@Ap;$rExQhIAegq6uLrHH0*1&&>(vl1!O<~ zfHS523h-o=U0C+Be0~dgqWa0xkYm}wp9L!YlRio(H``FI7S%}6bB+EU*vCB7G zR1tcFcuxw%2r_FI>L1C{MPw(@{>wSbNz}F0*758X{v`JCXLduIDZg)Yuy7^|^;_JM z6*&F^NV^FD%)L}H4(p|B64KT824!|Ol|Pxq$i5WTT+VQk@a|~~ZR01k8b8p}oe6xJ zR;0Stt6J6nq^Dj%=QziTM=heR$*YO4HUFT;+0|(?RJul1&F3JiL!!p%ED7Wf03Z2P z3zOM&EI(5qw-Uv)s13tsram0pP|#~+%}7$+EKZc*^JE1ZPiD%f{p#@_8KBWuN=ZK~J$t0$i4v)IhY$MW;OXj}If~rhX0q<&GAOn#lO;r; zp;{cY;i<0`)9@TKhgN*^nS%9$IjGV=V>fWG6VUBV@_cs7i}Ed>M}x^DT2C{v6@pu> zp@{6dYJn81U0N;@!4ZAe7NPa9*84na!|5Givdvvxr}2IWh%E772j z5Fqu5)>G#330;Q}myB|}%b&i>wx!&yi9WNmGyu5_Od~u#N2_debFftNy&W~jmjs`nnWmJ6<{UsZi~knNA>mLU98>K`;JzQEfmQ1j7e{gKe=vB00bM; zEzIWEYtwAhiJ}rxVM4cBdy&`rkdt{~UK-AIXF!@iCEbWS;nT>dH0_eJzcctEkHv^I zT{R)HbW0+1f71Llpezp1bQgbAPml_TGL6rb(T!*d!%r8Jho~ZVtmOE~k}NgvY$S!r z!Ff+j_n{nvW}QS(i03A0|dn zmb7R0tY3#BUSm~##5qk9;*=ZE^GpA!P?Z@)sfLj5X-u^i1|z6fsEM~|Z_y*eTyzuM z0+M;ENnd@(5VFpJqPIn7tb2+NfVTkPJg{^hyqm!!7`{&V&_VQTu)Zkdp5hIDkaR`e z`5yRElK4mwjTJy?`l&YFqrU!w(2ZEilU0mQA=K=g5oPU9=LlbSYvnj5o4#s!X?He#~+@+I0L)7reaV|OD&&bg%eaic&dMf^G6$gFV-t-HZQjc1^|mUP@Rv+;O|>N`LI7wo zy>Hz$A<4>sgL_$n@nJ$3d0Gc7{R-F*J_hQ?Z>4HnJVxAauZ3>qtkNbwtjdUSUjIog zGI=I{BD*MsqJy*;qc%MrmB;7Eo0Y0X z1ji>R1Ves8kR?D`t)b7U=@sxG7};BQ0MN@Lx|aeOUoU-El;j0`z1M`#1ps~VYtCyT zylnJY-s)Loy+A-ljBjrJPVg-vGnITE%@r-ijjWb+C|QfCsYiq8brS`wF4_?HH24N+ z3oiQ*CLdXD5Y?O@>f5?=qxfM(g&!jw#S@ z3p#-$H33rhv@>MW_@Zgs8CJ~;X*ZPOjv=YY+IcQO=X<(-ozds4pkndA(BO-+hz@wI zyZeCMlIyO3%ez_CM}z*8lzJ5kP1KgH)V?S(%U1ueIhb}r-ZK$f* zErijR(We>8!I(ZP-P~lDkJBqJnxuaAvs7v$SI<;!o2>3MJi4|NQ3|h8GoMDF z!>1Q`->VGDJsiRk!Fj~YWICEBBb|$ zBc-INTP7h@y9gah9YMuP?`lPEi* z34Yek2YFTVM+2w?-Qb=ES#am$)}*<*!t827LZGebH&6|{%EsY5>rW}0$$lCK-#Vl(5*NMUv#zyZ5qYUoP{}PDoJ^(OIi0BB2e#VG0?2&UsA_#9T|vPA0N zVxFk#m0SmQO0OArFd}ECs0 z2suXMR`)OP^Tsy5JL|j+_2rfzJhTVKXl|HsB{j?MBxfDzPrTP5E~J~b+{N7;=rHu+ zztG2%KczS38*$KHA3?V=vnqU`ma9G~fT$}tq;@28Qqw1rZVGt=tZ{wose6CdR=I9I z7_aOtA990-CMDh6)ub~;HpX%)g6{roLLJw^Nu*9TkaSv>MY;w3myY9ZE6tsX`;Q~j z%8BkVhmrb6+i>-Ru_TC_pfOo!QsRP;-ty??eikn1u1HhLe_Kj1JQVC> zufZ{f<|)5HTzNar6!9?nkN{T$Kpz>c5s=MLpAt4Z>s+Vf@L=8@cy|;9fnRHMVT)a7 z$4J;zF6B#jjp4h-DAA6^`4G+{I?us~Qo8Ot#{9Had0@46rG-g9A-w0u3&CA6I`@5X zExor(RUAUlbfhrFYelAtZM~2b%lC0a?1W9Lz4*JQ%;$^62Rsu!(n) zbdDdOx5%KHX)Td{psZI&<4V^fsS1^_lzARG0m$w|)=%zgh%Mvz&UGarp{xyaKXiLE_>7V47fY_Hoc# z^8ltX^a7?P;;10mnyk0|w=^Sgz^q5KC2;@KZaOup&gSo4NNMlk$Y($L{kCBi_03 z<`~$iX;n1Vyb{yU_%09VPvi*zG81j8-VL(Sd2VJxV<}$8GW_&yhZM{Lg0sAVS>G*x zFgp%1NH1E^a{cAIEuw0Z#!vYc3%T!9<2PQ=b{kEjW&$WjHWByI`ht`l&R>{TKK2ys z+ui>O#5V!2g*Ft+DpPdzEXxum9bfrpAYXVRk1!Ad5IzO#MBN#IoCIpJ)ru!FpWwHTGN9qSuN&E zr}e!kFq40AeAk3pCw@;}O<%F+4FS$tnh>4zfG&rMlUe5@^sQtSs_8eOy9!`2tBBxZ zLbL=Fy7Bydd&!OLhu-IriNdFfmaoOQ(2)}%s8|G`Wv3|Hd44X}P@atjLG}tNaV_6V zWm|3??Yv#uh6wowoS9JIu@5Y zzB7FGMU#(&Mb+XnyeWW^RZDn;E=%|{3!q!i%(jx&lySvL$v&lS60|3Jd_ofg<}?9T zi@gjVO)@<%7}RyBW+$4FZ-73--Rm2-*WMht$1sdviYFSQo9Y_2{cG#?{n^ge~s0o?(=LUWdB*R9?#+- z1*6Y;7)kfT1woFO3#Qnns=UBA1XzmzW~#m3q4$S!q7dX*ab@{ItU9XVc@hstq2*wF z)f9w&)JI8}ww6!ERL#Bg@$Ip4R)oFycaIDNyj-^VJm{?w0K&8lrc3L`>zN~E&cC?j z=r;?J6$b#Dms0IPHBT%PVwB1>zTej!_Mn|n-d*hJYI3tq=*)28)~*py62wtK45%aV+rJwk!(yqH!Wm#yM>@JiV}41*h(=ziGBX)k&s6ja#1i?PTPpnK10QHPq%uDB z0NlLT&A&c|agczhU_4MOTAvtsz?UJW6R>G_Asx9CUpqay`thZaz!_ zxh2Vw7mkmIEc~x`vIrw;1#;(;px4KZGmjLQpOzhm~X0!ot{T@Q4H^s92F#ppkIiH z%uS)RJD}m~X1E~`t))z$p>D89dLZSqZ2CHdeBo$DC{(nMFUckEl;tQMXdK?eNVe}a zezw*&`A*4%FdcD{vSImM!)N(**DrA|ng>1wNxClPI`lgViG*yNL^C}bv>@qg<+doJ zF>0GNifLbBf*hxQ?roOEI_%A(4*ah9A1O$hzs3=J*wQq*J&i=_bKPxcvFtW94ghrs zd9ZXiL11rnW*G6;kk<&S;8<+bPSv&HWVn?v$cU)6uiv(bI?Z5KJ&Qpph5$fkA?350 ztz0wKFn(D{iL~!87(`+1@!ZhRKHfO8>4o>;gV>)$XQFf=CK7bKl0WRoDe~bf-zEjE`q++CzcGFvF&m_nqJ!}HT5!oD@o5# z4=-;g+TA3IES&zH755>*Eupc|luan2V4*-Vv%G5@89Q|!G%t8_ON^Tjh_~s69l*xb z?dw6V?cKX;>sD*3a7H4zSJZ+`8z6Sx0mU*{f`pzW8d%cuA$<_iMRlMB9RVnq6OR@v z5q-~IPv^Bt`1s&#T!2B~Ym7GO;Ebetjxtm7C57}aGdy##j6y^OhNh@&e=PVr1A2Ot z>&amq=8C4TV@E`~v2M%xOPp35pxS)jPuXBQob<3_Ntr^+klu+v2GzU?001G)gci{d zaJ*J_jiUJ5jzzGm5jq}BWnxyGuhegv*#6%4JSWAUwW_a&-|we{rTr|MS>%Vx;l4(S zB0I-CQ7K!Km2hovbt6_ttv!2poP8HVqJ8 z*Lz`qO8clS5}wkwO4#D}Fer~6f>5nt3IRs{ymn%vZjI^09N z4m-Ttay|-sosB`Zi;FJMN(ZLY;&$C>D3l(!IE+*VlU%Qrqv1;39W< z?l4!{+iX(xGmdc_{6I{?;cpLC+n^%DZj_ffamF?GptfqIPu5kiCr%zE@!IZDyC3~$ z!y&o_D^H3wMo@bu4IK-2fGEgy*}uqo!BTecsB#KNb(>u1E4LwDvn870S2?UM0JAZx zapSQ3*9OkH1YpyPltKrOpKEKfnpiGTZkNBLpehu4cQAdB5caLQ0Y|%|)k_im#f@%I z=beY~PP!qa8I25w(KaRHN(#txL-K0SdGl9o5JS8ae!svMO;)poym1AmN_$!)ADML= zE$d9fzHut~LG^j+h#hY9U@KJEY{50>xn#dGFg`I)`o$o;|K4Lu_#s5R3AtN&nZ=%3 zFH%17)Gn3eBa8fNtaLhno90IHuY}avPH;5L;wjz1h~Od2_W@VTV&lUmO#);wS*Pim z`DJjw?hmie!C_=DQ}&s22;+6hzlmaHM7w>{xK>L#RKq~_z$an{@&)M@pFQuV9Nc)C zg~ML0o5f%@FUwxSb?+h4CkwY?pKVDt)#A_&irsQ?WrqzRcWXr*x7(F-=uveKDf~Oa zB$OnqGk>**=bv)2AstP<&g<`uT$`@z_2Hige+-)d=eNW&V1Z3<&Rf>#@&7ytk>L?A z`|;f_7)vyV(C;Vv!`jZ{B{H!O`oiKWv)7WyunYeXam{e$$TQiP7AYAb&z^HOYcVa7 z(wn2{V;8vr0@i)Kh^-v1^eDs$IXQ32UC{b($-mOfS{seviL+p3x^}5dm)6Cs8HeJY zFVHQ}_1+LLNDgIi8CT~^IT`ZA`tJNik*jW@_CqMze_w-9b!+lz5bHjZr))lKp9k@< z#X^R)YkS%-9s;PW{eBI}iN8*jE{8|)Vvu^@x^=`dB-5KzIQO;Z$yh0ic{8Rsl%Com z&}naAf$aEA#tykC!hEKpN=3dhS-6a-ACtgIIvgT)-W$H5PVedezN%An!wUcu%Ol_^ z_vaiVrOD&bUCupQ&Z~Z#kT2rMb%-OSf9wr;+++5N$N;i<`ko6c#^*H4 z)9Ng=_PK=avU|GV(I;`PDH+o?A&beFUKkx>)c)GI0xB)gKU_=vi$I^*YE*PovT}Zg*!Uyg6+4#kArAWxv7@R{ zjr?q8qO=OZ3G;afRYLcKLpGs-!wwh(a4WXGp`wTQbnxYDJF;6U6@D(N z?q%a4aSUvMw88;xf1?3?PCV1rZzvFat@2ruu{PFuvrV_^bQd%S0E?kt8W}RNcI@(* z=}ucA_f&q%fCh53EJ-T7tddrDbT0N3vdzTgyMi##4aNmzEGC){JDRi9+pAcd40li2 zWAYm_#Od@xZ1Z&9skF+QHu@Y)G4O6UB90eUu}qBd3jT>;qeOYv7Qs&T01qwLCh21JX_R&JKk44wTFhtS~it_M;?2Bl58 zKEG|)CZwMDUbKWc>vE>LJe@*VhTvC~1#;LLnefgss&0A0=iK@iuDUwg3fXdQ8UY?v zd)+M;R-kLo0_4We1+lTzUt{GM>?qxkuY2~M{HZTg1I7FAX8QXI+FJ;+Eq`1(C4n`V z;X&vO$|IZB>v_C)AwXiSoi7^=+5u4c`cxX0Qh#lboqYur&mvEDULT!ij2ARnC#j$- zua?ZE$m}OE4CXK0EHMh!*;<(2f_q>gI|MBt%?qqL7*b3i2kR!H+9;22Kf!zT&VpyI zUoezu+^32EwqmAuhI+cX9en7J}VF?jd+$}oM&$YypO zE(XuD5g)2I$KDl5b$*!cpRWMbexPOjiSBBd{sAeu`tC0(y7r!f#Wq~EjEbq4nKSO0 z?2gN4nRJ(55uT9dTyOiy@K=+yFYX(K3?rT}txYN#-*wfq_AyVcA6jnCB&to5w%J|Z zpfqkW(F}VzB>#O^r6yNFqMk7^68R;Yo=pPbA1uLlAFnz7NvIt)ORi6Ji#fgB^N^F+5l`6nn9mENsLyGT5%nny zTYPI$L@Z1$7cXxd%11UV&X1hE0aTRXu!nE5hph)=w@Nj_U(rTAGJ5wqmsMk_y<^k5 zwN4qFBDikOEh8%5nyTY>Xzrm8B#V3+)vB{Xr=)y;?vz1p(tbPMZOTZLDI9%LA26N$ zV+Ei7hP7o2|D0VuhNY^<^@lDX-e=1Imv?z7o2G zT%59tEwx|70>7iuSlgN|+#Q2%YD?g9iO;;rqlX@~h@&TwbL1w2p43EJ+#o!OQI`*1 z%B~ar>g@()rMDfIn3}?r^I61%@8aBkX?cYksR)HM9FlyMx~O5RFkEVfBb{@moW?q&IjVi&mn`hF)Nje9mV}+ zyV5ES(m8w9TMi*VvTI33RgX2bKMz{rsPLBd$=F<&)$CmcKz>;2@vi0z)(=jEwX2>f zceox8`nGVo)ccDIS|}y*R+!RYS4Tof`>?-RqrY+U=RnJ6( z>Now*j$^Dj6aI06;E&;972z;d7v(kgK&vOVj+a7`w(hTYC=QWhh2Ca){QhvQCfma( zIY-06R!8Z>NW1{ZAIU$N%-UCDxo^DG3t)Q9R)fB8<*$JAkI5-wg3(XOy17V40koXb z$f7wrFmXmP-Jc$dMgthd%8mP3$s46Ozv%i;`%r9oS;$~xf(*AWE{EQ z6c=h|8E8akZVaNtzPLl_6! zpE|d89Agtm4w;zv>B1O)YfOPNH<5y=s#Y8Nf1O-xaINhvX8n1 zCY~tWcaQ$o)_;2U7DwlV%uvcaoqE==U|H}Y*w=YGS(v9TR3j!Z}nx_p_$_kHf`oa=gS7~cRAotPg{neM;7`J^W`POzbfGX|$U z>ikt3za?>nL!dWQB~hv&!z4#?F8Q1we#)N(`o_=SrtM*pb{JK~8@XpHEgpJHJuFqT zNRz@F2;&GG-%QLz@QE-ois9llwO2hk1msxG4UM>ZzhMKLI*44sh0UjDW?o)l?Sy-j zq#N`#a_y+OVJp_3US(O(y(BH)OZXAvopEqMr8G&Q9tSkDBvgfMPFfGEf;Miy)z-G z+ADTfY-|_XUL@g5nd_Acqn6%Ge_IaOL3gl5^NGo7lDm?FhVf3K|HPrm&P1 z&fGqdD%QGvlXy^7B(QWwr={ty57eDp;f3~o7^Opd}$3F|V8 z>qANkHi|;PXBUluP3QZPqVK@yLq(GR_#didWDBGP=88s{0~>u|S4*VE^hOFolol1w z-A6%NT+D{dm;GGnX3S%pogu(EVCMb(sr&(N1rd)r5w-=Ye{=AZtGU-F?4_$mo|aOY zcH*TKw@%*XQ8E4~!h92WoWk7lxJ?m__KG8|m!xzfY2F}s+9zYHUfv3CUFldaCFzKD zVd&XCfu>kR(=;I3puZAhXB=Xspka+q=({AN>q)5pj5jp~@({BM1H7OU?7IZk+Xyk0 zn4TBWoLJ1R=_O=WG1nsgC6w3N=Fx@oiZXZG2&dFsUdoqk8tEURiZhhDUd~{&ovkee z)MbWO58kzu8A#Z;^y<_Tac1ZH*rwlF&(Fr9rWxr}vMM^W29^*)oCrS6kETRKy?F2R z8rr`QvUM{Xh>ja@Ofi!7;ZSc;4cC_Pl3dEE&laPsNFJcB3SOtclin_ms0T?nYEA1f zO`eu5<>0|tn^wS3!sbw|z^{SFm*GF6eWNh9Q9>`H4zY_V{>ZLOUVc< zq?rw=Q0u?bQdfz-B|$GR;jdSBq)LAHABdl)izFc+0bf=fnQ`&7rLqGG5ji<|SxJo_ zO<}?QId{vQYr`dD7#q&ubAz3yoS3wMvuVq8YZKaKbEf{=V?9B%@4>Q!K8r_YF+KMi z61~dd882$b!{;mWbAg!lT}f<+TeGK@=$G$%Lu^CL`fUkn4{q~_Ju~IpT=BeIs|VO| zoB#?*2NFP&?OW8#9!cg1L4fdlcr)e7D>)N$k9igH1wK=^$LkCIUMa(V$AcQcO&t(zea0&&cqxj;KSX36psOl2^>Sj>_6PE#)BZ=N0q0ik!L=jP3ZcvT zTW0QB30f|a$~~fq$hvh_T8#TDd3ta>U0TL1oq?_<|Dc5C?5b zAWU(n-5f86q`xxa%ElzU>B%hm?8AyS1f;1G#=r!z6q!Nb(5hHnSQL*$3t!}D+u8xD%4R*;?GSmSGOA4R^HmC(Gc6rs zpH07=-f#6vPu3MZvLd{wjhe_2XyiAI2&VVN&c*7xO)a`aNsE2(h4kc}t+TLFxG5@A z*E<@Zs(2;v*cv8u!Bv!U$?idw&M)lT&HWaT;$C6@9H*u zM|5jnza6}|TvPv|Q+4zDYHHu{AlLl6PyhZfJ|7qW^-6{`Q|q%CCvshk3z$Z`=-yYO zge`$o1A%%dU$(b#*UVko_li^_iw{02yWI~45B>}APYH19!%K&gaLP}*REhbphrk9K z+IEyY+2M5Y%T-9xy`fGHHy#OWhThFd9qKX;2QP`K`wVkiv~$P$Ylo_`MHIS%y(5>Z&K9zUjdmoe1yjnWa@ zK?7UwCx8L*j9i)5yCkEgl=WAuxzPcHZt{FKB*V1%^ z<2OU-(`n|2m-iTH4c;8W)vIH7${hr8qLO(Gvfj6P)df1t7Hs9UpWAkrQ!>HZCG2uVj~x4i1JDiGOw zE*O7xR78*tG11(7LiZSm>eijldWSr7q0U;IUuI$Q*L!N_wvgMy?l%?;`ux;F80nv2 zNI%Gw-;2WI=r5Y@?mHsFYza;N3T`%jWm)nJRd4+##4Z0d2`DjVIh@0K>gFu_QTIKe z;}&$`)=KRTWCZ3lGCGyFquRQMbp|Jk`&f%UujTri%2zLg|N288xaU)2UkT;+G{^Ht z&zwF*Cof(gjI(Vijq0$Icjh@#y!@%eZniOdi*UMn(fxJZ7E>&&u^yt)BEB6rVgAgw zY^I&37C__*fA848Dpc&F!o(4sE3Q}3?hz_5XA30gNNBA?*4cD!dDv$dwxG)`zASp$ zW(HY_+?s4jI#AniK6){CNBR$&9+bv*S&!?^jV&Yhv#twaC=+aO<9DZ$O#HBb>HHQy2h(UW{QL&RLEStB# zQG@r7>-`cC+@lp4sy`?p!jyA09BR{3Wid*A>=A>UJT5-LltM7oo$7Z|#k}v4+J2Bp zf@6Pa{#^iZE%uih8#`%?XNwi+ry!EpC4?Y^PVjXhIY)%?eChL_uWF4% z2grbcdHpxZmUGf(9qV=Izd9HP9!wm^nJrue*oZ*Jfj}j5(dRkyY;gK-0c$xekrw#a z!5?IW>5+gK&Z{?D5-F+VI z2xVsRcjEKE&QxU>_h$eBIV9k|3}*Gt_o0iZC_VYwBlACA5|73;W*_2XW`NkNql-ge zw0*xj<9Z4m_Op%O{qba!*o#Lyd1c_ttlkNobP1|d&a%jiEL?DVW}*WPWQKU1=K|+( z4}KT!XGq;>WT+sN3f9~VzC3JoQ===TvS8He2N~Tb*Olxq5Jn55%_di21z5Sj&|caF z#ba$&-@CL+!Fi*7EL6t-PjAEP=ZoU{< z5})#?_`W{BkV6%a#{3wlO4Z=upLs~gkjk`o+>Si>{OvADKw(P}uJ{{_JYD~{68l`) z+=27kO5qI&hzd0^fjZq)LFCB}ZWP4mX~5 zcTGB>j6JPM)^}Po_ICFi1!mHM1JM(|+4N6QmLz0Pn?%FB_=uW7WrD@t_EhtxQwpVu zzQD|3?xr7*I4aj2;v)L&Vc3EzLrB_wk|*kG1KXuNm8OPZo@2Z-{f&!WCFVFOBSd%R znWl-9zW^2uJ2J?z!M}t-d@ik_OmsN;ljC#p?fq)!#05tFf)x{c6Urn0-Y-ifQ>}Wu5k7RZ`)Y{8&Csc|jj4hO7V_mPN4wI3 zS>wrUIn9I`r1Rlr)Qyi_hH997L7od-SAYx6rXk6o^`_q8z>SLtvyiP?F8&Y~>PPSR z{pLBZc(PJ<+amsyA#~r+?Zfw`stg4k2oAVG=+(V+sA~Q!8!j*|@Rvou7rX|7GHzAo z4;|0w@-!i1S}xkmrkYa>T$O>ikb9{xM}fy5M2LzGh`t3-H*LN+N;3>ulZ}b^P{e6 zjzOqj^f*T=oFZf%2}-Pi%m50Y1BF|9uDT9B7y*BXt|4yb2N`qSf$ja-QcEfLFF1Um1EllK3u@pAq0GqgmBE@Vbt4?v%9%Z{ym4Ekbl^ikcN3f7bG~7rp6%fD-sHIA zsc!yR4Xfp6ZWn5A2CpPmyYM?RS%S6 zo>nEm41ADKo|!c~OX?X1j+*?nD=d!zUq|J&KANANhi-=^bla*C<8=K#{-Fd&+OU#) zk>0+WXWBi_g=V6oWJ+r?`0q+10()g;BJAN{ka1y$4xpGA0 zj6=LvI&Xj_Z`wa5{IA2=*vy5Xylht-RT{TvTw*yCjp8vzm)?PsRy?nsl1ZzR?HF)-st{ZF=Pb<(LvGva}-^F+6Fi- zQjOKPUV_FOofkPuTJvd<4~>{=#9bSOrrXN`KL{R5en~nvdo2-DQWiaa%jrGeZZI(X zmqL}Qk(WSx#XxY(6C)rvrWnrwY_t*iYJ-CTIw-P#*BC%kX0dvCo;v;=<$|yK(xcWc zo{GXp7MOIDMI*bs))0{=`Kj6~F425XX6@lLcfkiJXGN+^mc7%BhH%bU@(SIcda4|( i`K52KZ!oASEx6~Ls-LGOLL_i4@XwC?|9SRf=>Gut&s2o~ literal 0 HcmV?d00001