From 237ccc059df051e69337ae77bb9ff5e63676ca06 Mon Sep 17 00:00:00 2001 From: Yong Date: Wed, 13 Oct 2021 14:46:51 -0600 Subject: [PATCH] Done draw frog3D, delete unused Gene method --- README.md | 12 +- README_ENG.md | 7 + .../com/gitee/drinkjava2/frog/Animal.java | 104 +++++----- .../gitee/drinkjava2/frog/Application.java | 1 - .../java/com/gitee/drinkjava2/frog/Env.java | 34 ++-- .../drinkjava2/frog/brain/BrainPicture.java | 41 +++- .../com/gitee/drinkjava2/frog/brain/Cell.java | 34 +++- .../gitee/drinkjava2/frog/brain/Cells3D.java | 8 +- .../com/gitee/drinkjava2/frog/egg/Egg.java | 2 +- .../com/gitee/drinkjava2/frog/gene/Gene.java | 181 ++++++++++-------- .../frog/judge/BrainShapeJudge.java | 71 +++++++ .../gitee/drinkjava2/frog/util/Point3D.java | 31 +++ .../frog/util/StringPixelUtils.java | 88 +++++++++ .../gitee/drinkjava2/frog/util/Systemout.java | 2 +- result13_frog3d.gif | Bin 0 -> 68965 bytes 版本提交记录.md | 6 + 16 files changed, 441 insertions(+), 181 deletions(-) create mode 100644 core/bottom_up/src/main/java/com/gitee/drinkjava2/frog/judge/BrainShapeJudge.java create mode 100644 core/bottom_up/src/main/java/com/gitee/drinkjava2/frog/util/Point3D.java create mode 100644 core/bottom_up/src/main/java/com/gitee/drinkjava2/frog/util/StringPixelUtils.java create mode 100644 result13_frog3d.gif diff --git a/README.md b/README.md index a5f6c5b..1f5b9d4 100644 --- a/README.md +++ b/README.md @@ -143,11 +143,18 @@ Frog: 这是人工生命的主体,目前起名叫青蛙(Frog),其实叫什 位于history\005a1目录下,演示用5个声母和5个韵母的组合来关联到25个图像的识别,这样可以减少声音输入区的数量。它的另一个目的是演示体全息存贮的工作模式可以同时处理多个方向的信号。这个演示分辨率极差,只有约一半的识别率,但我不打算继续改进了。 ![result12](result12_letter_test2.png) +2021-10-13 失败的细胞分裂尝试 +这次本来想模仿生物细胞的分裂,从一个细胞开始分裂出任意指定的三维形状,并设计了split、goto等基因命令,但是做来做去做不出结果,细胞们就象跳蚤一样乱跑不听使唤,最终还是决定放弃,细胞分裂这个算法太难了。细胞分裂的优点是更“象”生物,而且估计可以利用分形原理缩小基因的长度,基因相当于一种自带循环和条件判断的计算机语言。 +最终生成三维形状这个目标还是借助简单遗传算法完成,通过细胞在相邻位置随机生成,并在基因里记录每个细胞的坐标的方式来实现,基因命令被删得只剩一个了,就是随机生成细胞。 +用遗传算法来生成任意形状,就好象一个画家在画画,但是画什么根本不知道,只知道听从旁边人打分,画的好就打高分,画的不好就打低分,这样一直循环下去,最终画的内容只由打分的人决定。目前速度上还有改进余地,比如让新细胞有更多变异率。 +![result13](result13_frog3d.gif) +生成三维形状目的是为生成三维脑结构做准备,神经网络空间上应该是三维的,这样实现模式识别会很方便,而早期随机连线结构损失了空间位置信息,三维全息演示问题则是它是手工设计的,优化困难。 + ## 运行方式 | Run 运行history各个子目录下的run.bat批处理文件即可启动运行,history下有多个子目录,按时间和版本号顺序按列,存放着这个项目演化过程中的主要历史版本供演示。 另外如果想要研究这个项目的早期版本,可以结合gitk命令和参考"版本提交记录.md"的介绍,用git reset命令回复到以前任一个版本,例如用: -git reset --hard ae34b07e 可以转回到以前一个分组测试的找食版本。 +git reset --hard ae34b07e 可以转回到以前一个分组测试的找食版本。 码云上通常是大版本提交,跑出结果才会更新,github上则是日常提交。 ## 重要参数 | Parameters 在Env.java类中以下有以下可调整参数,请手工修改这些参数进行不同的测试,前5个参数很重要: @@ -171,5 +178,6 @@ FOOD_QTY:食物的数量,食物越多,则Frog的生存率就越高,能 欢迎发issue、评论等方式提出建议或加入开发组。 ## 关注我 | About Me +[Gitee](https://gitee.com/drinkjava2) [Github](https://github.com/drinkjava2) -微信:yong99819981(如想长期关注本项目、或想参与项目实际编码开发的,请加我并留言加"人工生命群") \ No newline at end of file +微信:yong99819981(如想长期关注本项目、或参与开发,请加我并留言"人工生命群") \ No newline at end of file diff --git a/README_ENG.md b/README_ENG.md index 98be967..2fce281 100644 --- a/README_ENG.md +++ b/README_ENG.md @@ -133,6 +133,13 @@ The basic principle of these two modes is based on the back propagation of signa Located in the history\005a1 directory, the demonstration uses a combination of 5 initials and 5 finals to associate with the recognition of 25 images, which can reduce the number of voice input areas. Its other purpose is to demonstrate that the working mode of volume holographic storage can process signals in multiple directions at the same time. The resolution of this demo is very poor, only about half of the recognition rate, but I do not intend to continue to improve. ![result12](result12_letter_test2.png) +2021-10-13 Failed cell division attempts +This time I wanted to imitate the division of biological cells, starting from a cell to divide into any specified 3D shape, and designing split, goto and other genetic commands, but doing it and doing it can’t produce results, and the cells run around like fleas. I didn't listen to my orders, and finally decided to give up. The algorithm of cell division is too difficult. The advantage of cell division is that it is more "like" organisms, and it is estimated that the length of genes can be reduced by the principle of fractal. Genes are equivalent to a computer language with loops and conditional judgments. +Finally, the goal of generating three-dimensional shapes is accomplished with the help of simple genetic algorithms. The cells are randomly generated in adjacent positions and the coordinates of each cell are recorded in the gene. Only one gene command is deleted, which is random generate cell. +Using genetic algorithms to generate arbitrary shapes is like a painter who is drawing, but he doesn’t know what he is painting. He just listens to the scores of the people next to him. If he paints well, he scores a high score, and if he paints badly, he scores a low score. The loop continues, and the final content of the painting is only determined by the person who scores it. There is still room for improvement in speed, such as allowing new cells to have more mutation rates. +![result13](result13_frog3d.gif) +The purpose of generating three-dimensional shapes is to prepare for the generation of three-dimensional brain structures. The neural network space should be three-dimensional, so that it will be very convenient to realize pattern recognition. However, the early random connection structure lost the spatial position information. The problem of the three-dimensional holographic demonstration is that it is Hand-designed, optimization is difficult. + ## License [Apache 2.0] (http://www.apache.org/licenses/LICENSE-2.0) diff --git a/core/bottom_up/src/main/java/com/gitee/drinkjava2/frog/Animal.java b/core/bottom_up/src/main/java/com/gitee/drinkjava2/frog/Animal.java index 5079671..24bdb59 100644 --- a/core/bottom_up/src/main/java/com/gitee/drinkjava2/frog/Animal.java +++ b/core/bottom_up/src/main/java/com/gitee/drinkjava2/frog/Animal.java @@ -23,6 +23,7 @@ import com.gitee.drinkjava2.frog.brain.Cell; import com.gitee.drinkjava2.frog.brain.Cells3D; import com.gitee.drinkjava2.frog.egg.Egg; import com.gitee.drinkjava2.frog.gene.Gene; +import com.gitee.drinkjava2.frog.judge.BrainShapeJudge; import com.gitee.drinkjava2.frog.objects.Material; import com.gitee.drinkjava2.frog.util.RandomUtils; @@ -38,7 +39,7 @@ import com.gitee.drinkjava2.frog.util.RandomUtils; public abstract class Animal {// 这个程序大量用到public变量而不是getter/setter,主要是为了编程方便和简洁,但缺点是编程者需要小心维护各个变量 public static BufferedImage FROG_IMAGE; public static BufferedImage snakeImage; - transient public ArrayList gene = new ArrayList<>(); // Animal的基因只保存一份,这是人工生命与实际生物(每个细胞都保留一份基因)的最大不同 + transient public ArrayList gene = new ArrayList<>(); // Animal的基因只保存一份,这是人工生命与实际生物(每个细胞都保留一份基因)的最大不同 static { try { @@ -49,9 +50,9 @@ public abstract class Animal {// 这个程序大量用到public变量而不是ge } /** brain cells */ - public List cells = new ArrayList<>(); - public Cells3D cells3D = new Cells3D(); + public List cells = new ArrayList<>(); + public Cells3D cells3D = new Cells3D(this); public int x; // animal在Env中的x坐标 public int y; // animal在Env中的y坐标 @@ -65,7 +66,6 @@ public abstract class Animal {// 这个程序大量用到public变量而不是ge public Animal(Egg egg) {// x, y 是虑拟环境的坐标 this.gene.addAll(egg.gene); //动物的基因是蛋的基因的拷贝 - Gene.mutation(this); //但是有小概率基因突变 if (Env.BORN_AT_RANDOM_PLACE) { //是否随机出生在地图上? x = RandomUtils.nextInt(Env.ENV_WIDTH); y = RandomUtils.nextInt(Env.ENV_HEIGHT); @@ -86,64 +86,55 @@ public abstract class Animal {// 这个程序大量用到public变量而不是ge private static final int MIN_ENERGY_LIMIT = Integer.MIN_VALUE + 20000; private static final int MAX_ENERGY_LIMIT = Integer.MAX_VALUE - 20000; - public void bigAward() {//energy大小是环境对animal唯一的奖罚,也是animal唯一的下蛋竟争标准。调用下面6个方法来进行不同程度的奖罚 - energy += 5000; - if (energy > MAX_ENERGY_LIMIT) - energy = MAX_ENERGY_LIMIT; - } + //energy大小是环境对animal唯一的奖罚,也是animal唯一的下蛋竟争标准。调用下面6个方法来进行不同程度的奖罚 - public void normalAward() { - energy += 50; - if (energy > MAX_ENERGY_LIMIT) - energy = MAX_ENERGY_LIMIT; - } + //@formatter:off 下面几行是重要的奖罚方法,会经常调整或注释掉,集中放在一起,不要格式化为多行 + // public void bigAward() { energy += 5000; if (energy > MAX_ENERGY_LIMIT)energy = MAX_ENERGY_LIMIT; } + public void normalAward() { energy += 50; if (energy > MAX_ENERGY_LIMIT)energy = MAX_ENERGY_LIMIT; } + //public void tinyAward() { energy += 1; if (energy > MAX_ENERGY_LIMIT)energy = MAX_ENERGY_LIMIT; } + //public void bigPenalty() { energy -= 5000; if (energy < MIN_ENERGY_LIMIT)energy = MIN_ENERGY_LIMIT; } + public void normalPenalty() { energy -= 100; if (energy < MIN_ENERGY_LIMIT)energy = MIN_ENERGY_LIMIT; } + //public void tinyPenalty() { energy -= 1 ; if (energy < MIN_ENERGY_LIMIT)energy = MIN_ENERGY_LIMIT; } + public void kill() {this.alive = false; this.energy = MIN_ENERGY_LIMIT; Env.clearMaterial(x, y, animalMaterial); } //kill是最大的惩罚 + //@formatter:on - public void tinyAward() { - energy++; - if (energy > MAX_ENERGY_LIMIT) - energy = MAX_ENERGY_LIMIT; - } +// public void initAnimal() { // 初始化animal,生成脑细胞是在这一步 +// new Cell(this, Env.BRAIN_XSIZE / 2, Env.BRAIN_YSIZE / 2, Env.BRAIN_ZSIZE / 2, 0, 0, 10);//第一个细胞生成于脑的中心,它的基因指针指向起始0行 +// int oldCellsQTY, newCellsQTY, start = 0, end = 0; +// do { +// oldCellsQTY = this.cells.size(); +// for (end = start; end < gene.size()-1; end++) { +// if(Gene.toCode(gene.get(end))==Gene.NEW_CELL)break; +// } +// +// for (int i = 0; i < cells.size(); i++) {//重要,开始对每一个细胞调用基因这门语言,启动细胞的分裂,这个分裂是在一个时间周期内完成,以后要改进为利用图形卡的加速功能并发执行以加快分裂速度 +// Gene.run(this, cells.get(i)); +// } +// start=end; +// newCellsQTY = this.cells.size(); +// //Application.brainPic.drawBrainPicture(); //慢动作放映生成每个细胞过程 +// } while (oldCellsQTY != newCellsQTY && newCellsQTY < Env.CELLS_MAX_QTY && start Env.CELLS_MAX_QTY) //如果细胞分裂到达极限值CELLS_LIMIT才停止,说明很可能有无限循环分裂的癌细胞存在,这个生物应扣分淘汰掉 +// this.energy = MIN_ENERGY_LIMIT; +// Gene.mutation(this); //有小概率基因突变 +// } - public void bigPenalty() { - energy -= 5000; - if (energy < MIN_ENERGY_LIMIT) - energy = MIN_ENERGY_LIMIT; - } - - public void normalPenalty() { - energy -= 50; - if (energy < MIN_ENERGY_LIMIT) - energy = MIN_ENERGY_LIMIT; - } - - public void tinyPenalty() { - energy--; - if (energy < MIN_ENERGY_LIMIT) - energy = MIN_ENERGY_LIMIT; - } - - public void initAnimal() { // 初始化animal,生成脑细胞是在这一步 - Cell cell = new Cell(this, Env.BRAIN_XSIZE / 2, Env.BRAIN_YSIZE / 2, Env.BRAIN_ZSIZE / 2, 0, 0, 0); //第一个细胞生成于脑的中心,它的基因语言指针指向起始0行位置 - this.cells.add(cell); - int oldCellsQTY; - int newCellsQTY; - do { - oldCellsQTY = this.cells.size(); - Gene.run(this, cell); //重要,开始调用基因这门语言,启动细胞的分裂,这个分裂是在一个时间周期内完成,以后要改进为利用图形卡的加速功能并发执行以加快分裂速度 - newCellsQTY = this.cells.size(); - } while (oldCellsQTY != newCellsQTY && newCellsQTY < Env.CELLS_MAX_QTY); //直到所有细胞都停止分裂或细胞分裂超过CELLS_LIMIT个才停止 - if (newCellsQTY > Env.CELLS_MAX_QTY) //如果细胞分裂到达极限值CELLS_LIMIT才停止,说明很可能有无限循环分裂的癌细胞存在,这个生物应扣分淘汰掉 - this.energy = MIN_ENERGY_LIMIT; + public void initAnimal() { // 初始化animal,生成脑细胞是在这一步 + + Gene.run(this); //运行基因语言,生成细胞 + BrainShapeJudge.judge(this); //重要,对细胞的形状是否符合模子的形状进行能量奖励或扣分 + Gene.mutation(this); //有小概率基因突变 } public boolean active() {// 这个active方法在每一步循环都会被调用,是脑思考的最小帧 // 如果能量小于0、出界、与非食物的点重合则判死 if (!alive) { - energy =MIN_ENERGY_LIMIT; // 死掉的青蛙也要消耗能量,确保淘汰出局 + energy = MIN_ENERGY_LIMIT; // 死掉的青蛙确保淘汰出局 return false; } if (energy < 0 || Env.outsideEnv(x, y) || Env.bricks[x][y] >= Material.KILL_ANIMAL) { - energy = MIN_ENERGY_LIMIT; kill(); return false; } @@ -160,14 +151,15 @@ public abstract class Animal {// 这个程序大量用到public变量而不是ge g.drawImage(animalImage, x - 8, y - 8, 16, 16, null);// 减去坐标,保证嘴巴显示在当前x,y处 } - public void kill() {// 杀死当前动物 - this.alive = false; - Env.clearMaterial(x, y, animalMaterial); - } - /** Check if x,y,z out of animal's brain range */ public static boolean outBrainRange(int x, int y, int z) {// 检查指定坐标是否超出animal脑空间界限 return x < 0 || x >= Env.BRAIN_XSIZE || y < 0 || y >= Env.BRAIN_YSIZE || z < 0 || z >= Env.BRAIN_ZSIZE; } + public Cell getOneRandomCell() { + if (cells.isEmpty()) + return null; + return cells.get(RandomUtils.nextInt(cells.size())); + + } } diff --git a/core/bottom_up/src/main/java/com/gitee/drinkjava2/frog/Application.java b/core/bottom_up/src/main/java/com/gitee/drinkjava2/frog/Application.java index 25f812d..55c676b 100644 --- a/core/bottom_up/src/main/java/com/gitee/drinkjava2/frog/Application.java +++ b/core/bottom_up/src/main/java/com/gitee/drinkjava2/frog/Application.java @@ -110,7 +110,6 @@ public class Application { mainFrame.add(label); mainFrame.setVisible(true); - mainFrame.setTitle("这是一个空框架,用随机生成基因的方式来实现细胞3D分裂还没开始做"); env.run(); } diff --git a/core/bottom_up/src/main/java/com/gitee/drinkjava2/frog/Env.java b/core/bottom_up/src/main/java/com/gitee/drinkjava2/frog/Env.java index 9a27116..1a932a6 100644 --- a/core/bottom_up/src/main/java/com/gitee/drinkjava2/frog/Env.java +++ b/core/bottom_up/src/main/java/com/gitee/drinkjava2/frog/Env.java @@ -9,9 +9,9 @@ import java.util.List; import javax.swing.JPanel; -import com.gitee.drinkjava2.frog.brain.Cells3D; import com.gitee.drinkjava2.frog.egg.Egg; import com.gitee.drinkjava2.frog.egg.FrogEggTool; +import com.gitee.drinkjava2.frog.gene.Gene; import com.gitee.drinkjava2.frog.objects.EnvObject; import com.gitee.drinkjava2.frog.objects.Food; import com.gitee.drinkjava2.frog.objects.Material; @@ -37,16 +37,16 @@ public class Env extends JPanel { public static final int FROG_PER_EGG = 4; // 每个青蛙蛋可以孵出几个青蛙 - public static final boolean BORN_AT_RANDOM_PLACE = true;// 孵出动物落在地图上随机位置,而不是在蛋所在地 - public static final int SCREEN = 1; // 分几屏测完 + + public static final boolean BORN_AT_RANDOM_PLACE = true;// 孵出动物落在地图上随机位置,而不是在蛋所在地 /** Frog's brain size */ // 脑细胞位于脑范围内,是个三维结构,在animal中用一个List来存贮表示的同时,也用一个Cell3D动态数组来表示 - public static final int BRAIN_XSIZE = 20; // 脑在X方向长度 - public static final int BRAIN_YSIZE = 20; // 脑在Y方向长度 - public static final int BRAIN_ZSIZE = 20; // 脑在Z方向长度 + public static final int BRAIN_XSIZE = 100; // 脑在X方向长度,取值最大为1000 + public static final int BRAIN_YSIZE = 100; // 脑在Y方向长度,取值最大为1000 + public static final int BRAIN_ZSIZE = 100; // 脑在Z方向长度,取值最大为1000 - public static final int CELLS_MAX_QTY = 100; //脑细胞总数不能超过这个值 + public static final int CELLS_MAX_QTY = 4000; //脑细胞总数不能超过这个值 /** SHOW first animal's brain structure */ public static boolean SHOW_FIRST_ANIMAL_BRAIN = true; // 是否显示脑图在Env区的右侧 @@ -137,21 +137,6 @@ public class Env extends JPanel { return false; } - public static boolean foundAndAteFrog(int x, int y) {// 如果x,y有青蛙,将其杀死,返回true - if (x < 0 || y < 0 || x >= ENV_WIDTH || y >= ENV_HEIGHT) - return false;// 如果出界返回false; - int frogNo = Env.bricks[x][y] & Material.FROG_TAG; - if (frogNo > 0) { - Frog f = frogs.get(frogNo - 1); - if (f.alive) { - Env.frog_ated++; - f.kill(); - return true; - } - } - return false; - } - public static void setMaterial(int x, int y, int material) { if (Env.insideEnv(x, y)) Env.bricks[x][y] = Env.bricks[x][y] | material; @@ -307,6 +292,11 @@ public class Env extends JPanel { checkIfPause(); for (int j = 0; j < FROG_PER_SCREEN; j++) { Frog f = frogs.get(current_screen * FROG_PER_SCREEN + j); + if (j == 0) { + System.out.println("======== cells: "+f.cells.size()+" ========="); + //Gene.printGene(f); + } + f.cells=null; // 清空frog脑细胞所占用的内存 f.cells3D=null; } diff --git a/core/bottom_up/src/main/java/com/gitee/drinkjava2/frog/brain/BrainPicture.java b/core/bottom_up/src/main/java/com/gitee/drinkjava2/frog/brain/BrainPicture.java index 2432868..fceb6f6 100644 --- a/core/bottom_up/src/main/java/com/gitee/drinkjava2/frog/brain/BrainPicture.java +++ b/core/bottom_up/src/main/java/com/gitee/drinkjava2/frog/brain/BrainPicture.java @@ -19,6 +19,7 @@ import javax.swing.JPanel; import com.gitee.drinkjava2.frog.Animal; import com.gitee.drinkjava2.frog.Application; import com.gitee.drinkjava2.frog.Env; +import com.gitee.drinkjava2.frog.judge.BrainShapeJudge; import com.gitee.drinkjava2.frog.util.ColorUtils; /** @@ -244,6 +245,36 @@ public class BrainPicture extends JPanel { round(r * scale)); } + /** 画一个圆 */ + public void drawCircle(float px1, float py1, float pz1, float r) {//这个方法实际和上面的一样的,只是改成了drawOval + double x1 = px1 - Env.BRAIN_XSIZE / 2; + double y1 = -py1 + Env.BRAIN_YSIZE / 2;// 屏幕的y坐标是反的,显示时要正过来 + double z1 = pz1 - Env.BRAIN_ZSIZE / 2; + x1 = x1 * scale; + y1 = y1 * scale; + z1 = z1 * scale; + double x, y, z; + y = y1 * cos(xAngle) - z1 * sin(xAngle);// 绕x轴转 + z = y1 * sin(xAngle) + z1 * cos(xAngle); + y1 = y; + z1 = z; + + x = z1 * sin(yAngle) + x1 * cos(yAngle);// 绕y轴转 + // z = z1 * cos(yAngle) - x1 * sin(yAngle); + x1 = x; + // z1 = z; + + x = x1 * cos(zAngle) - y1 * sin(zAngle);// 绕z轴转 + y = x1 * sin(zAngle) + y1 * cos(zAngle); + x1 = x; + y1 = y; + + g.setColor(picColor); + g.drawOval(round((float) x1 + Env.FROG_BRAIN_DISP_WIDTH / 2 + xOffset - r * scale * .5f), + round((float) y1 + Env.FROG_BRAIN_DISP_WIDTH / 2 + yOffset - r * scale * .5f), round(r * scale), + round(r * scale)); + } + public void drawText(float px1, float py1, float pz1, String text) { drawText(px1, py1, pz1, text, 12); } @@ -301,8 +332,14 @@ public class BrainPicture extends JPanel { drawLine(0, 0, 0, 0, 1, 0); drawLine(0, 0, 0, 0, 0, 1); - for (Cell cell : a.cells) { - setPicColor(ColorUtils.grayColor(cell.energy));// 用灰度表示活跃度 + setPicColor(Color.gray); + BrainShapeJudge.show(this);//这行显示脑形状这个模子 + + for (Cell cell : a.cells) { //这里开始画出细胞 + if (cell.color != null) + setPicColor(cell.color); + else + setPicColor(ColorUtils.grayColor(cell.energy));// 用灰度级表示细胞能量大小 drawCell(cell); } diff --git a/core/bottom_up/src/main/java/com/gitee/drinkjava2/frog/brain/Cell.java b/core/bottom_up/src/main/java/com/gitee/drinkjava2/frog/brain/Cell.java index 4fd23b9..c371550 100644 --- a/core/bottom_up/src/main/java/com/gitee/drinkjava2/frog/brain/Cell.java +++ b/core/bottom_up/src/main/java/com/gitee/drinkjava2/frog/brain/Cell.java @@ -10,6 +10,8 @@ */ package com.gitee.drinkjava2.frog.brain; +import java.awt.Color; + import com.gitee.drinkjava2.frog.Animal; /** @@ -29,7 +31,8 @@ import com.gitee.drinkjava2.frog.Animal; public class Cell { //cell数量非常庞大,不需要序列化 public int x; //x,y,z 是细胞的中心点在脑中的位置 public int y; - public int z; + public int z; + public Color color; //这个颜色只是用于调试 public int geneIndex; //指向青蛙基因单例中的行号。每个细胞的基因都相同,但是不同的是在基因链中的行号 @@ -47,9 +50,15 @@ public class Cell { //cell数量非常庞大,不需要序列化 this.geneIndex = geneIndex; this.splitCount = splitCount; this.splitLimit = splitLimit; - animal.cells.add(this); - animal.cells3D.putCell(this, animal.cells.size()); //在cell3D中登记cell序号 - animal.normalAward(); //TODO: 调试用,待删 + if (!Animal.outBrainRange(x, y, z)) { + Cell c= animal.cells3D.getCell(x, y, z); + if(c!=null) + animal.normalPenalty(); + else { + animal.cells.add(this); + animal.cells3D.putCell(this, animal.cells.size()); //在cell3D中登记cell序号 + } + } } public void split(Animal animal, int direction) {//细胞在一个或多个方向上分裂克隆,有6(对应立方体的6个面)、7(包含本身点)、27(包含立方体侧边、项点方向)等选项,这里先采用6个方向的方案 @@ -59,23 +68,23 @@ public class Cell { //cell数量非常庞大,不需要序列化 if ((direction & 1) > 0) {//上 zz++; clone(animal, xx, yy, zz); //简单在指定隔壁位置克隆,暂不采用推开其它细胞的高运算量方案,这个要等图型卡加速用上后再考虑推开其它细胞 - } + } else if ((direction & 0b10) > 0) {//下 zz--; clone(animal, xx, yy, zz); - } + } else if ((direction & 0b100) > 0) {//左 xx--; clone(animal, xx, yy, zz); - } + } else if ((direction & 0b1000) > 0) {//右 xx++; clone(animal, xx, yy, zz); - } + } else if ((direction & 0b10000) > 0) {//前 yy--; clone(animal, xx, yy, zz); - } + } else if ((direction & 0b100000) > 0) {//后 yy++; clone(animal, xx, yy, zz); @@ -85,7 +94,12 @@ public class Cell { //cell数量非常庞大,不需要序列化 public void clone(Animal animal, int xx, int yy, int zz) {//在指定坐标克隆当前细胞 if (Animal.outBrainRange(xx, yy, zz)) return; - new Cell(animal, xx, yy, zz, geneIndex, splitCount, splitLimit); + if (animal.cells3D.existCell(xx, yy, zz)) { + // animal.tinyPenalty(); + } else { + if(splitCount0; //arrayIndex为0时是空,为1时表示animal.cells[0]; } /** Get a cell at position (x,y,z), if not exist, return null */ - public Cell getCell(Animal animal, int x, int y, int z) {// 返回指定脑坐标的cell ,如果不存在,返回null + public Cell getCell(int x, int y, int z) {// 返回指定脑坐标的cell ,如果不存在,返回null if (cells[x] == null || cells[x][y] == null) return null; int arrayIndex=cells[x][y][z]; //arrayIndex为0时是空,为1时表示animal.cells[0]; diff --git a/core/bottom_up/src/main/java/com/gitee/drinkjava2/frog/egg/Egg.java b/core/bottom_up/src/main/java/com/gitee/drinkjava2/frog/egg/Egg.java index f77137c..22c5a08 100644 --- a/core/bottom_up/src/main/java/com/gitee/drinkjava2/frog/egg/Egg.java +++ b/core/bottom_up/src/main/java/com/gitee/drinkjava2/frog/egg/Egg.java @@ -35,7 +35,7 @@ public class Egg implements Serializable { // gene is a language similar like BASIC created by random // 基因是随机生成的一种类似Basic语言的字符串符列,保存在蛋中,和实际生物每个细胞都要保存一份基因不同,程序中每个细胞仅保存着基因的指针和当前细胞位于基因链中的行号,并不需要保存基因的副本,这样可以极大地减少内存占用 - public ArrayList gene =new ArrayList<>(); + public ArrayList gene =new ArrayList<>(); public Egg() {// 无中生有,创建一个蛋,先有蛋,后有蛙d x = RandomUtils.nextInt(Env.ENV_WIDTH); diff --git a/core/bottom_up/src/main/java/com/gitee/drinkjava2/frog/gene/Gene.java b/core/bottom_up/src/main/java/com/gitee/drinkjava2/frog/gene/Gene.java index 3e84f7e..6681cae 100644 --- a/core/bottom_up/src/main/java/com/gitee/drinkjava2/frog/gene/Gene.java +++ b/core/bottom_up/src/main/java/com/gitee/drinkjava2/frog/gene/Gene.java @@ -10,9 +10,11 @@ */ package com.gitee.drinkjava2.frog.gene; +import java.awt.Color; import java.util.List; import com.gitee.drinkjava2.frog.Animal; +import com.gitee.drinkjava2.frog.Env; import com.gitee.drinkjava2.frog.brain.Cell; import com.gitee.drinkjava2.frog.util.RandomUtils; @@ -22,127 +24,140 @@ import com.gitee.drinkjava2.frog.util.RandomUtils; * Gene是一个仿造大自然随机生成的语言。它采用类似BASIC的语法,只有少数几个字键字。这个类里定义语言的关键字常量和对这些关键字的解析行为, * 这个语言主要的作用是实现分裂造形,包括 身体结构造形(不重要,但先实现这个)和脑细胞结构造形(重点) * - * Gene语法的每行由若干部分组成,第一部分是关键字,占2格,第二、三、四等部分是可选内容,由关键字决定,如: + * Gene语法的每行由一个long编码表示,高32位是关键字,低32位是参数,由关键字决定,如: * - * 10100 表示跳转到100行语句执行, 即10(=GOTO) + 100(行号) - * 110 表示结束执行,停止细胞分裂, 即11(结束) + 0(参数) + * 10 + 100 表示跳转到100行语句执行, 即10(=GOTO) + 100(行号) + * 11 + 0 表示结束执行,停止细胞分裂, 即11(结束) + 0(参数) * * @author Yong Zhu * @since 2021-09-16 */ public class Gene {// NOSONAR - private static int index = 9; //关键字是一个两位数字字符,从10开始依次往下排。关键字没有可读性,调试时要用printGene方法将关键字转为可读的语句 - public static final int FIRST_KEYWORD = 10; - public static final int GOTO = nextKeyword(); //GOTO关键字=10 - public static final int END = nextKeyword(); //结束执行=11 - public static final int SPLIT = nextKeyword(); //执行细胞分裂, 分裂方向由第二部分的数值决定,一个细胞有可能同时在多个方向分裂出多个细胞,有6个或27个方向等 - public static final int SPLIT_LIMIT = nextKeyword(); //细胞分裂寿命, 0表示可以无限分裂 - public static final int IF = nextKeyword(); //IF关键字,暂没用到 + private static int index = 9; //关键字是一个两位数字字符,从10开始依次往下排。关键字没有可读性,调试时要用printGene方法将关键字转为可读的语句 + public static String[] TEXT = new String[20]; //这里存放关键字的文字解释,供打印输出用 + + //下面这些基因关键字是失败的尝试,从2021-10-13这个提交开始不再使用 + // public static final int GOTO = nextKeyword("GOTO"); //GOTO关键字=10 + // public static final int END = nextKeyword("END"); //结束执行=11 + // public static final int SPLIT = nextKeyword("SPLIT"); //执行细胞分裂, 分裂方向由第二部分的数值决定,一个细胞有可能同时在多个方向分裂出多个细胞,有6个或27个方向等 + // public static final int SPLIT_LIMIT = nextKeyword("SPLIT_LIMIT"); //细胞分裂寿命, 0表示可以无限分裂 + public static final int NEW_CELL = nextKeyword("NEW_CELL"); //在新位置新创建一个细胞,而不是由其它细胞分裂出来 + + public static final int FIRST_KEYWORD = NEW_CELL; public static final int LAST_KEYWORD = index; //最后一个关键字 - public static String[] TEXT = new String[LAST_KEYWORD + 1]; //这里存放关键字的文字解释,供打印输出用 - static { - TEXT[GOTO] = "GOTO"; - TEXT[END] = "END"; - TEXT[SPLIT] = "SPLIT"; - TEXT[SPLIT_LIMIT] = "SPLIT_LIMIT"; - TEXT[IF] = "IF"; + static private int nextKeyword(String explain) { + index++; + TEXT[index] = explain; + return index; } - static private int nextKeyword() { - return ++index; + static final StringBuilder sb = new StringBuilder(); //用来将方向转为可读的英文缩写 + + public static int toCode(Long gene) { + return (int) (gene >> 32); + } + + public static int toParam(Long gene) { + return (int) (gene & 0xffffffffL); + } + + public static long toGene(int code, int param) { + long code_ = code; + return (code_ << 32) + param; } public static void printGene(Animal animal) { int i = 0; - for (String s : animal.gene) { - int code = Integer.parseInt(s.substring(0, 2)); - String paramStr = s.substring(2); + for (long gene : animal.gene) { + int code = toCode(gene); + int param = toParam(gene); + String paramStr = "" + param; System.out.println(i++ + " " + TEXT[code] + " " + paramStr); } } - - //execute gene language - public static void run(Animal animal, Cell cell) { //对于给定的细胞,由基因、这个细胞所处的行号、细胞的分裂寿命、细胞已分裂的次数、以及细胞所处的身体坐标、以及细胞周围是否有细胞包围来决定它的下一步分裂行为 - if (cell.geneIndex < 0 || cell.geneIndex >= animal.gene.size()) - return; - String oneLine = animal.gene.get(cell.geneIndex); - int code = Integer.parseInt(oneLine.substring(0, 2)); - if (code == END) {//如果是END, 结束分裂,参数就不需要解读了 - cell.geneIndex = -1;//改为-1,以后直接跳过这个细胞,不再执行上面的Integer.parseInt - return; - } - int param; //每行基因分为代码和参数两个部分,参数暂定为一个整数 - try { - param = Integer.parseInt(oneLine.substring(2)); - } catch (NumberFormatException e) { //除了END等关键字外,下面的code都需要参数, 如果参数不是整数扣除青蛙能量 - animal.bigPenalty(); - return; - } - - if (code == GOTO) { - if (param < 0 || param >= animal.gene.size()) {//行号太大、太小都不行 - animal.bigPenalty(); - return; + public static void run(Animal animal) { //对于给定的细胞,由基因、这个细胞所处的行号、细胞的分裂寿命、细胞已分裂的次数、以及细胞所处的身体坐标、以及细胞周围是否有细胞包围来决定它的下一步分裂行为 + for (int i = 0; i < animal.gene.size(); i++) { + long gene = animal.gene.get(i); + int code = toCode(gene); + int param = toParam(gene); + if (code == NEW_CELL) { //新建一个细胞 + int x = param / 1000000; + int y = (param - x * 1000000) / 1000; + int z = param % 1000; + Cell c = new Cell(animal, x, y, z, i, 0, 10); + c.color = Color.RED; } - cell.geneIndex = param; - } else if (code == SPLIT_LIMIT) {//重定义细胞寿命 - cell.splitLimit = param; - cell.geneIndex++; - } else if (code == SPLIT) { //执行细胞分裂 - cell.geneIndex++; - if (param < 0 || param > 63) //如果是分裂的话,param应该随机生成落在0~63之内,每个二进制的一个位代表1个分裂方向,共有上下左右前后6个方向 - return; - cell.split(animal, param);//cell在参数代表的方向进行分裂克隆,可以同时在多个方向克隆出多个细胞 } } - private static int randomParam(Animal animal, int code) {//根据基因code生成一个随机合理参数 + private static Long randomGeneCode(Animal animal) {//生成一个随机的基因行 + long code = RandomUtils.nextInt(LAST_KEYWORD - FIRST_KEYWORD) + FIRST_KEYWORD; + int param = randomGeneParam(animal, code); + return (code << 32) + param; + } + + public static int randomGeneParam(Animal animal, long code) {//根据基因code生成一个随机合理参数 int param = 0; - if (code == GOTO) { - param = RandomUtils.nextInt(animal.gene.size()); - } else if (code == SPLIT_LIMIT) {//细胞寿命 - param = RandomUtils.nextInt(60); //注: 细胞寿命60这个参数以后要写在基因里 - } else if (code == SPLIT) { //细胞分裂 - param = RandomUtils.nextInt(64); + if (code == NEW_CELL) { //新的细胞坐标位置参数,用一个整数表示, 值为 X*1000000 + Y*1000 + Z + if (animal.cells.isEmpty()) { //如果animal没有细胞,位置取脑的中间 + return Env.BRAIN_XSIZE / 2 * 1000000 + Env.BRAIN_YSIZE / 2 * 1000 + Env.BRAIN_ZSIZE / 2; + } else { //如果脑细胞已有了,随机取一个脑细胞,返回它的一个相邻坐标位置 + Cell c = animal.getOneRandomCell(); + int x = c.x; + int y = c.y; + int z = c.z; + x += RandomUtils.nextInt(5) - 2; + y += RandomUtils.nextInt(5) - 2; + z += RandomUtils.nextInt(5) - 2; + return x * 1000000 + y * 1000 + z; + } } return param; } - private static String randomGene(Animal animal) {//生成一个随机的基因行 - int code = RandomUtils.nextInt(LAST_KEYWORD + 1 - FIRST_KEYWORD) + FIRST_KEYWORD; - return "" + code + randomParam(animal, code); - } + public static void mutation(Animal animal) {//基因随机突变,分为:新增、删除、拷贝、改变、参数改变等情况 + List genes = animal.gene; - public static void mutation(Animal animal) {//基因随机突变,分为:新增、删除、拷贝、改变、参数改变等情况 - List genes = animal.gene; + if (RandomUtils.percent(10)) { + genes.add(toGene(NEW_CELL, randomGeneParam(animal, NEW_CELL))); + return; + } - if (RandomUtils.percent(5)) //新增,注:5这个魔数以后要写在基因里,成为基因的一部分,下同 - genes.add(RandomUtils.nextInt(genes.size()), randomGene(animal)); + float percent = 5; //注:percent这个魔数以后要写在基因里,成为基因的一部分 + if (RandomUtils.percent(percent * 3)) + genes.add(RandomUtils.nextInt(genes.size()), randomGeneCode(animal)); - if (genes.size() > 0 && RandomUtils.percent(3)) //删除 + if (genes.size() > 0 && RandomUtils.percent(percent)) //删除 genes.remove(RandomUtils.nextInt(genes.size())); - if (genes.size() > 0 && RandomUtils.percent(3)) //改变 - genes.set(RandomUtils.nextInt(genes.size()), randomGene(animal)); + if (genes.size() > 0 && RandomUtils.percent(percent)) //改变 + genes.set(RandomUtils.nextInt(genes.size()), randomGeneCode(animal)); - if (genes.size() > 0 && RandomUtils.percent(5)) { //改变参数 + if (genes.size() > 0 && RandomUtils.percent(percent)) { //改变参数 int index = RandomUtils.nextInt(genes.size()); - String gene = genes.get(index); - int code = Integer.parseInt(gene.substring(0, 2)); - int param = randomParam(animal, code); - genes.set(index, "" + code + param); + long gene = genes.get(index); + long code = toCode(gene); + int param = randomGeneParam(animal, code); //参数是与code相关的,不同的code其合理参数范围是不一样的 + genes.set(index, (code << 32) + param); } - if (genes.size() > 0 && RandomUtils.percent(1)) { //批量拷贝,一次拷贝不超过基因长度的1/3 - genes.addAll(RandomUtils.nextInt(genes.size()), genes.subList(0, RandomUtils.nextInt(genes.size() / 3))); + if (genes.size() > 0 && RandomUtils.percent(percent)) { //批量拷贝,一次拷贝不超过基因长度的1/2 + genes.addAll(RandomUtils.nextInt(genes.size()), genes.subList(0, RandomUtils.nextInt(genes.size() / 2))); + } + + if (genes.size() > 0 && RandomUtils.percent(percent)) { //批量删除 + int start = RandomUtils.nextInt(genes.size()); + int end = RandomUtils.nextInt(genes.size()); + if (start > end) { + int tmp = start; + start = end; + end = tmp; + } + genes.subList(start, end).clear(); } -// if (genes.size() > 0 && RandomUtils.percent(1)) { //批量删除,一次删除不超过基因长度的1/5 -// genes.subList(0, RandomUtils.nextInt(genes.size() / 5)).clear(); -// } } - } diff --git a/core/bottom_up/src/main/java/com/gitee/drinkjava2/frog/judge/BrainShapeJudge.java b/core/bottom_up/src/main/java/com/gitee/drinkjava2/frog/judge/BrainShapeJudge.java new file mode 100644 index 0000000..a85db2f --- /dev/null +++ b/core/bottom_up/src/main/java/com/gitee/drinkjava2/frog/judge/BrainShapeJudge.java @@ -0,0 +1,71 @@ +package com.gitee.drinkjava2.frog.judge; + +import java.awt.Font; +import java.util.ArrayList; +import java.util.List; + +import com.gitee.drinkjava2.frog.Animal; +import com.gitee.drinkjava2.frog.Env; +import com.gitee.drinkjava2.frog.brain.BrainPicture; +import com.gitee.drinkjava2.frog.brain.Cell; +import com.gitee.drinkjava2.frog.util.Point3D; +import com.gitee.drinkjava2.frog.util.StringPixelUtils; + +/** + * execute method be called after animal's initAnimal method + * + * 这个类的judge方法在动物的初始化后被调用,根据脑细胞群的三维结构形状来对动物进行奖罚,即加减它的能量值,这是一个临时类,只是用来检验细胞三维成形功能,以后可能改名或删除 + * 这个类的show方法在绘脑图时调用,在脑图里显示脑细胞群的三维形状,用空心圆来表示,这个三维形状就像是一个模子,细胞长在这个模子里的有奖,否则扣分 + */ +public class BrainShapeJudge {//NOSONAR + private static Point3D C = new Point3D(Env.BRAIN_XSIZE / 2, Env.BRAIN_YSIZE / 2, Env.BRAIN_ZSIZE / 2); + private static boolean[][][] shape = new boolean[Env.BRAIN_XSIZE][Env.BRAIN_YSIZE][Env.BRAIN_ZSIZE]; + private static List pointList = new ArrayList<>(); //pointList存放上面shape的所有有效点,用来加快显示循环而不用遍历三维数组 + static { + putPixiel("FROG"); + } + + private static void putPixiel(String str) { + byte[][] c = StringPixelUtils.getStringPixels(Font.SANS_SERIF, Font.PLAIN, 12, str); //要把frog二维像素变成立体的三维点放到points里和pointsList里供使用 + int w = c.length; + int h = c[0].length; + for (int z = 0; z < 5; z++) { + for (int y = 0; y < h; y++) { + for (int x = 0; x < w; x++) { + if (c[x][y] > 0) { + Point3D p = new Point3D(C.x + x, C.y + y, C.z + z); + if (!Animal.outBrainRange(p.x, p.y, p.z)) { + shape[p.x][p.y][p.z] = true; + pointList.add(p); + } + } + } + } + } + for (int z = 0; z < 2; z++) + for (int x = 0; x < 33; x++) { //再划一条线把字连起来,目前细胞不能隔空分裂,只能在紧邻位置分裂 + Point3D p = new Point3D(C.x + x, C.y, C.z + z); + if (!Animal.outBrainRange(p.x, p.y, p.z)) { + shape[p.x][p.y][p.z] = true; + pointList.add(p); + } + } + + } + + public static void judge(Animal animal) {//检查animal的脑细胞是否位于brainShape的范围内 + for (Cell c : animal.cells) { + if (shape[c.x][c.y][c.z]) { + animal.normalAward(); + } else { + animal.normalPenalty(); + } + } + } + + public static void show(BrainPicture pic) {// 在脑图上显示当前形状 + for (Point3D p : pointList) + pic.drawCircle(p.x, p.y, p.z, 1); + } + +} diff --git a/core/bottom_up/src/main/java/com/gitee/drinkjava2/frog/util/Point3D.java b/core/bottom_up/src/main/java/com/gitee/drinkjava2/frog/util/Point3D.java new file mode 100644 index 0000000..1c7cc45 --- /dev/null +++ b/core/bottom_up/src/main/java/com/gitee/drinkjava2/frog/util/Point3D.java @@ -0,0 +1,31 @@ +/* + * Copyright 2018 the original author or authors. + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by + * applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS + * OF ANY KIND, either express or implied. See the License for the specific + * language governing permissions and limitations under the License. + */ +package com.gitee.drinkjava2.frog.util; + +/** + * Point has x,y,z value + * + * @author Yong Zhu + * @since 2021-10-01 + */ +@SuppressWarnings("all") +public class Point3D { + public int x; + public int y; + public int z; + + public Point3D(int x, int y, int z) { + this.x = x; + this.y = y; + this.z = z; + } + +} diff --git a/core/bottom_up/src/main/java/com/gitee/drinkjava2/frog/util/StringPixelUtils.java b/core/bottom_up/src/main/java/com/gitee/drinkjava2/frog/util/StringPixelUtils.java new file mode 100644 index 0000000..8438e0d --- /dev/null +++ b/core/bottom_up/src/main/java/com/gitee/drinkjava2/frog/util/StringPixelUtils.java @@ -0,0 +1,88 @@ +/* Copyright 2018-2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by + * applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS + * OF ANY KIND, either express or implied. See the License for the specific + * language governing permissions and limitations under the License. + */ +package com.gitee.drinkjava2.frog.util; + +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.image.BufferedImage; +import java.util.HashMap; +import java.util.Map; + +/** + * StringPixelUtils used to get pixel array from a given string + * + * 根据给定的字体和字符串,返回它的像素点阵,lettersMap[0][0]是左下角素 + * + * @author Yong Zhu + * @since 2.0.2 + */ +public class StringPixelUtils { + private static final Map lettersMap = new HashMap<>(); + + public static byte[][] getSanserif10Pixels(String s) { + return getStringPixels(Font.SANS_SERIF, Font.PLAIN, 10, s); + } + + public static byte[][] getSanserif12Pixels(String s) { + return getStringPixels(Font.SANS_SERIF, Font.PLAIN, 12, s); + } + + public static byte[][] getSanserifItalic10Pixels(String s) { + return getStringPixels(Font.SANS_SERIF, Font.ITALIC, 10, s); + } + + /* 在内存 BufferedImage里输出文本并获取它的像素点 */ + public static byte[][] getStringPixels(String fontName, int fontStyle, int fontSize, String s) { + String key = new StringBuilder(fontName).append("_").append(fontStyle).append("_").append(fontSize).append("_") + .append(s).toString(); + if (lettersMap.containsKey(key)) + return lettersMap.get(key); + Font font = new Font(fontName, fontStyle, fontSize); + + BufferedImage bi = new BufferedImage(fontSize * 10, fontSize * 50, BufferedImage.TYPE_INT_RGB); + Graphics g = bi.getGraphics(); + Graphics2D g2d = (Graphics2D) g; + g2d.setFont(font); + FontMetrics fm = g2d.getFontMetrics(); + int strHeight = fm.getAscent() + fm.getDescent() - 3; + int strWidth = fm.stringWidth(s); + g2d.drawString(s, 0, fm.getAscent() - fm.getLeading() - 1); + byte[][] b = new byte[strWidth][strHeight]; + for (int y = 0; y < strHeight; y++) + for (int x = 0; x < strWidth; x++) + if (bi.getRGB(x, y) == -1) + b[x][strHeight - y - 1] = 1; + else + b[x][strHeight - y - 1] = 0; + lettersMap.put(key, b); + return b; + } + + //*- 这个是测试输出,平时不需要用 + public static void main(String[] args) { + byte[][] c = getStringPixels(Font.SANS_SERIF, Font.PLAIN, 12, "FROG"); + int w = c.length; + int h = c[0].length; + + for (int y = 0; y < h; y++) { + for (int x = 0; x < w; x++) { + if (c[x][h - y - 1] > 0) + System.out.print("*"); + else + System.out.print(" "); + } + System.out.println(); + } + } + //*/ +} diff --git a/core/bottom_up/src/main/java/com/gitee/drinkjava2/frog/util/Systemout.java b/core/bottom_up/src/main/java/com/gitee/drinkjava2/frog/util/Systemout.java index 0bcfb28..5c008df 100644 --- a/core/bottom_up/src/main/java/com/gitee/drinkjava2/frog/util/Systemout.java +++ b/core/bottom_up/src/main/java/com/gitee/drinkjava2/frog/util/Systemout.java @@ -23,7 +23,7 @@ public class Systemout { System.out.print(obj); } - public static void printdln(Object obj) { + public static void println(Object obj) { if (allowPrint) System.out.println(obj); } diff --git a/result13_frog3d.gif b/result13_frog3d.gif new file mode 100644 index 0000000000000000000000000000000000000000..f480f59fe266e40770075f5b0f400bce5fac044f GIT binary patch literal 68965 zcmaI7Wl&t*x9&@DcWE@ZyGtOrySq!{+BgJv*Tx+hcMk-2cYkr01PvslPu~CD_ugH% z&N;Pe)v7sb)u=J%r{_1uGvyRy1%)icKUBa_!@y9z!oyI&{QW}FRAscaq$Jd3xY;@3 zKK$Kc{rkfF`&$VV3JnPff&ROOfrUmSS5MzymF2f>#kcN#{e=~ED4%s2TX{Lvaf>#7 zue|=8c=k5;@&^kYHF~76+L$|A|b@B&5JZ>_(gtk`voh9sBAxd9aCM z$m~DmC*I>=IP3s}M%hc_c%?{F+#Ap|?YLjNP5SA&wnVsht9mAXC!r4Yy@yQc#(0+| zv9DefZ{`;p89NN8DMeDKaed)T;YDygItQFtfA3650?b;(*skXZEv>~ z+Q2Ks;9p&A1j*!gBbSDfim95>{E@;rOm|ioY(_CbR!Z78$*+J}-hQni>22o?ZFqf0$@T;CL;A^ud-d64Anb!&r7(rEDgGm=DLH zE6*P=WS0{`wdOVCU&|zqEq;e$N5S%K@@OjliqdX3a((tZBY`!GXc_6#Az(I8{Esi# zp3sEYmjFx(-B>&3Tw}o&$MrVVrIvv z@`A&T?a#28%O6T_jTl%UTVBwUV+%mO!Engb^@~z4FZEH>%1Y9%Br1=7cRWkoXx1l_{r$Eo@^>*GawP zh2?4_x=;yrTp6IVh@`DE%}BkG1t{aweEUVqVCuUVg0@TpzGPti9m2x3{8dZ63fldHB?4Igz4OG7V< zNf2M%X*D_nnd7L1$qq0{DynI3&{ZS0&KUjdXm z1XUwBXWF~O*)hXEhEpTHD%%rF#Xd6ZF!nLm{}yGT&(*XN+FhbxxoS;5CQ<3gsSw_; zGmic<^<1(bmUtR22!}$G-kS=4=IAp&Yq^_RlfcnLf-cIscuq}TnTui2cE{s*w&T-i z#M58VvkpZ~>e%KtW1|eQ=u;p=bSZeixEKLjCC%73ptD{*)3P;Jf80vYp8d_~$8!v~ z7eq4RD^bIxf6=C+tXlzhRCqBo@y9!XsCyctmZ^8EAe+sSjYMNUz;XZUn%Y0KwMpMD zYTAf0&~r-tObzy%jkN?htL}%PywhaEAK$Ao_TaisLYIt~0&X0Fwc-j+_^TKW7h!BM z4JE#(RP>DSp@&}lH1>#CZ|rMM;#s%Iy{+VHLts{RVS@SS#EHyUw~OQnjsrYZ@|Ay$ zoRvLpT|kuV8n|*#5^CDEI2FI|zAkA}j1xIX)AVlNdy3+DLGGf7;oCaKlZs$<2Eo@ zNpVh_F>lVsCGgd81)FYw;^dtgq)BEGWxU?nd(Nu(Rgx4AL0*<)NHyw3N$ct--*DjQ zZTO4+LTZvX6`qSta@}K6`_B3&VcRs3noqO?OO>D1_u@2&l=ml9{W>sszdPqR*&wP+ zG`=m~ei>3GBkYq)r)+RdDI~SXldne6LXD6Znkf(vK~#+kWfy^P7ft&{&!TE-nugC< z3U?!_ndmf_)8pxIK0UDMd0&}2FXgl@>DTJ@KQM6R?{l?IjFU1wYJh}PO88< zr~Pp_vnK~`LQXH+nNFBwT`xx#voP3y9`Ajw0@vALJUhM|QOF7Xl-W5{CMcWLEqdA3Yk%m(zgqMg9s#s@m>-CuiEpznDh}YkDkak}<5}3LA(KJCi-C zRA17xew=1E_0yQWxIj!-oAkO04GwOQS!cx^(4q!2*|NV@?0?*&A2R(-9`uZ8F6qt} zL?CA2;Q7i&In?RBnos7OWtcBVpXxVVQ(l;5`wcM7r%g%$@d^D^PxzTgNENj}FBhR5 zcXO=kGp!v*Uau8dStpfMp35S{NTMr^$lNK+XsiVhY`pv2LMTns*Rey2&Cnd0;jA7) zRIBQfyV$DfVZpmxr^#;CG=pVrXY%Fx)FPKxB2r6JvI=0ijj1O;bwdmFlIks$D61=u zq(A?uKejW-_d1y&W-P2NBHNSbB$sR25{WYo^(2c+OP@8 zodk4cQV+$EXheE1USvV+4((ff#v%>MzG;|HH0%0 zmh1uLM^eZpAopo(COD%*@eg2ne;Af(RerwtF5<(<%elUUsHAN1!Jjyz!A#(K{QYhi zZuOBtuLZfI>z;Re>e?LjQ_XCcfMy!mL@hcI16#+1m3aRPw_-Ov#?_%9Q=Y5Vr0Mn% znxyMRIBI>XPmLp_%!NF`e;;@O*=z~_53iB+T_g;t19vs`X_(43UW z2q+jF9_;7iFH7W2CvPpVE;<}(1sHQft5j+}HJa1${R8jV-EJyMgtLQ z;IQ$0b5|*1jM^F|`{Jwp4vDJjid)8xrt=C++HlCv(7<>#U~7_b!i^`efqh_1T0MuY z*U=jBMI-oN;24#yt)lAXShR&Cx9uS;fmUnWj;m#&O|)uC2<* zBs|$F`*e;M=jAGik|FgPwQdt<1C01HmXQg~_EoD+TGy3xIM0YDN|lL>(aHG$c_0+u zbgmfAG{11RG7#po60s##c;lvF<8gK(_Wu=~<bD;OlVctpN1tEB^yv zTuO5q0%pHIWeXyJSJSh)h?1$IeMYjf11_wC6r9lSbz!^1e>18bMtIKiT4ao<=XJ+q zGpQBX=W^iWwzhg^u6dS=7(Ob)uX%D4 z)^<_(A8f%6LK4D+0SVn;c7_5!!h&0Z(8z8NZYGz;D%r`40tTG|6o_BMWd6EA;WSEt zhrRk~PT|{lVUJIKAX8p5N?v1ib|!Q)n$;%p{Uwy)yy)%K;_nic85p`&1Tz)N=UsGf zP?RxQ+z^_np5vA(Rg&tfgKJpgf>#m;E+L(YA@MKKh*d$o%*9kJLPNDdhz1M#f;-1c znZaO|%Tk`2QeKAyH0-R~)UvUrvVHNas)w>M?CcWXLaDfdgV^$;i^B8QLgmW{!tYV8 z@)=qr6=L=k&e9c=;TeA>DvX#j-zziCwi2z*D{O=_EiNnkc?`Up$Sen z{trpIa3i;HM*Lu1Crt`?fJu0TXD(IDX8s=$5n-fZ6k&w_e-ZtqlZyYtricb{t(DKW zShgm(S++bBXAYGg(7w1R$D8~=YuhjmQ`Y$!ZzzY2*wFFDw zwkd6%uUY|ne#DFp)a@U4jEI zhfBOdvW{f_0=e>J<2t-(=&}(=9u0uE0eL}N^Qy8yCjKc{WVI#N$vVgc`0j7}yQ3_* zUn<0>1#$T_B^%-XY(4cnwESfv(^kK#O2n;#OnjixWLsWL8U>XD;yQ>T(nF18&Z#pnep#b@MG^P z!RV0+!OQDx{3_=t2T3<0XAs*;lZM7n>v?v%nF!J^?}f!$_o|^HKsZl}OSvI1lPuoZ zMK!HeAtfo)_fX!$B5Cd$9m%Y|vCcg{kH&MG#cvy1+NkWG;)KfSYzmT}Z*^sUd1_{| zDaBFq<4?t%Qidj4o5GX>m%2p7WB8{OtgG6JWVGM$v3YT`^t=)XhfaB8mz?*d`6t~` z998PdJ=hIPGe=+=0_UR;?6VI$dqt78F!qn6i#kj9-wWJQ6pk(IKk#e-sni<#Q~Sj# zzpGamIFv{kvbmEKB3r5(67{{|6BDda=c1rTZ^9ldbliP{bxh=6PT@F?p@>@6mB&1o znv&UL?x>&W{!yRj+#n3BjH%sgXx^;#WgqCAb|#JS(x{aMp?sO=FehspwCQ{kc(srt zjyKVQij8cNePG5V#G2f(Q)lHLOoNqPVEUdTfGfLCp|d#qR1nl7YPS&tKtv)7&n)2H z=c1F@s-NL~;8>>PmL9|NXekv} zYpq3QFbd*4ar5@mlaJ)WkXsA9&D10cup!5n7dS7^o)j~ii9c%oBku&zVgfp0@RH)s{=Mc6qhasViztmtc z{=}xG>dS^q+>kY6eKcW^Ob?${SRQZ_qnvz<3xg}$LAWp^SSC&@xAVe-#Uj?`LDrZQ zdT4(jKDH=a_0dq1<~nN3QuazqN>ag)F+H%!QLo@hald6xFigK~yg1-IS-+yD9(L8# z6W?!RMq%n}@#w~Nl04O9aa*OLg*e-Q%reZ-VaGjja}z-{;)pJZoN-y9@)fMM3XbAl zHYGM?eJohwTRpMq|eIq1nk0V_g7fK!WD zE`h_`W)|P{oXnjEZ(bLqN1`xh6#_;v_~(4E8M6;r-^bXezJ0(dUbHHvtb=8$+@{R7 z*#q}wb6m>WbgXh)VD2vjc!}xdar8l0HuWbkZwiIQUnZX!Vw+khSb9jqN-uOHJ;1X5RH^M@-9CzXLoO)+EJLiy7WH6%0&<%#nqO!5nV( zXri73O*YwqkY4FLF5~$3z%Ncme=d7(vXUlbYeiD;>NOwN%%hE7el^0&Ql_# zYgM3M_t;6pHspD`WEPHYS4jh6^BnXi5Tx`K%sdW_fIEkU6Y@xCzIOfW>|kVt+b+gX zEJrLBzYEXkQM^^|s06=F_?U89iNcf$%N96*#>34x4S%7w$aOfyDbJt+t*aM^NJqct zgs;R9j&uO)myA8yFre`+eo*_3fNX|Tz@8Z^>W_yqum4EI4Zj#I6S09!w3_Utp(a01 zT4M3MLNn1+rb#_ORYGNj%5+j!^nQ58g^_ISy*8ELysEVuRcg(;Z@3-q2Od)1-#Gm;`1)s#?lJbt_ zUT7ime(%wFe9ah{Q$W;^;O2b!HyiZmV|^`OS(DkxLlnmI;!s8Aib2i&w@{cgtT)JsL4r6%|vXl#PMA=g5^z(Zj$Pw zf48cRl|!!!cr7@zK+r7N5U6s-$* zcqEOMEuNZF1LQ$UI--+dbx;8LZql<9)+eW%-zz(D(h^B5klG2yUKdDW7s5MiPxF?@EN8^ z7!*86Q1L6%4P3N|kPu2$tPbOP&?(qGPi^HEXI!eWj?H4E5$ClPbwUb0F~55tW2^7a zJ35eWeA&FGy?Cm3U3700`p&?I?gB`0Ke7|VV&0Q=Ko*YTb0uNo{Rc4}Y4mgXWiqg5 zqq(Owqx7pYmoV9|{T66=wi|V|<8={%hg)kPf>iUf(l--TIran2=X^b;K1Dehs1oVB;miT58#x zbq+IDkAx%w>v?q1)d)TB#j|Sxj;ED-O0IU&qf?$XpodYrn`fyv?lNu7!PecUtYJWu zM^L1?o4?-AtbmYIb`TBS#H){ixV@u=ERXvBED`}>@+~Hyfgvg4qH>_aqzS90Kqn8w zH*=E_l;Je?aV&3*?)H%@y2?4`?w;GagF*fy)Ko|jmQ@w&pL(lMF@zG=t*sPwzaz%T^}pP@S;lr7&dI!E|TZ@Jc_%fw9Y4YwB^ssEN}<1zMQ zG?zfe@-;fYzmF}#EXi$tR+baEAmDI>cxS0@;ggD-jr8Y!6G+0MmAV5n$#KZ;MdGU@ zPyp{lA!%RQM6~qxHt8~E{r-T*Z`DN#j)`UP`APt6*c=9+lSWR{M+ao4Rw{Z{pd>L= zN&183H{rks3`90ex{*%C`SW4m50YkjFh;g}W8O*onIryjk22mVjoqhBJb~Nu_u^Sl z;Q7&w*qG}y_Le7gP+loP{*cLeY0d2)=+A$+rQ?r29|TQ%j*fGEb9XNs0W^dO-^+>- zr2BpEpuS$BrjZ~&eF|Ff@t!--sSe{m$tELR_tJ=hag@g0C-hA~3UfSD4!{@qwDuVp z$waG4ek+2H6qy$^3<^g2lIP?9?b%yu&G*C`#<|UvAI?{hfX#l~%8CIu=*5L@g3R(o z`~8Tpj8F>W$?=b!^dXXunyeW0xxcR*y6gtEWQm91Ps=@g1y1RRVGI3R?a0U#v5oXd z=?q2qE>THF@gf0ROGf3-NW9jXN&>5PKpGtsYSjoIk;+bXGdo~eMgV9-(_7t(O3+HA zlJU5mR@VcCH!NzOM~iOQSej7n1^PouPAr4s1Sj>>Zv4o)7_?LwrXZjAu*GmXfz(#n;N;V^ zLxC6x%8Zx{dcE&Lq<$8Q&L7JpsS$|WYQYQyt99ZWS5 zkK!g)r|?OZ6aH+O><&()c0=NlE3f-PtbOwH!&2B=M3nanPrH5I&?L`&x?vlS_wS`I zft_LF`tT@^woYy0s~6JKl)Nzt5;!9T8xX(Y^c9KMaaqpqt@WacD_nQVz z)Wa?H0JQ)$KWOeFEJm~st=V)Zu> zjB`hul!{1&0?B12zKCKH#dNEw0&&SN7GQfQZVt_`N0sfz_?${Hh~rL4c0EySeY%lx zO&RiGMS@V|)P6+>Dx_Tw5@!#I5~BAv(779dTwGKcYlaeli3OMiGe{zCW2zVM)7?BV z!TvfI3uz^Hx$(zOD!KwSgWaaw3dC~J@s*b~Je&D>qk@lQFObRFJhSn`_C7S5TQE1fGc-2ar7twp;?kb9D zMId?pjDaUf)4Hgy94$I_Xdp}TbmA!*AI)7Qh6FmqX31CX**E?YmPp>phB9Y{Yc#(5 zLxSy_V1D^rcRIa>XxmG#;MU3g!m?w>71O+oWczVH(G1qW^K`AtH@O=(*JBLVEyG`mj4|O6aUM@ z+D`uts2g)eBmWMlCsKUri6J+r5yF>ZepC?yhqqDUB-t~{$xB|?(TmKr zR^ZWc}8?LItrB1!4TOxQ7M5dt#6 z;g#?Qu=d1DFOd)F*^h3%lO?>H5{M*m4k><9gO^Mdi<{Mz+`n=Tb5Xk$16U+z;p>o` zNb_m~MpC=I#}(JVe#3s8_> zvuS-d$UmWoW+)1=A6{|>+J+Tok!Bfbh9kK}=%< zk`P2X1-1F93o7~2&}!XUhc%@MRn#sn64J^Qu$IJU7AU87E7gTDOrEAMTj}!6=ErOn zE?Ar+s`HeRb?+>EpNG<@iXyONXbE3}ayEW|M@<=dG^g7&zepsxB&M`#_ zHLS1QvF*N=-8HgrY9v6S5w0Km*1a9V^J8CDj;pBesArS9g+r075VN-u*Fjcii#!s{EN&(_ftOE>+L z*tgSdJNOV$!)QB*^#fjjJc^oFUsZdII4ja=;$2fO2+cnFFouBpF^iIkzGF9NXi*OH zlh7#OBa7JkeQ695LCaPk4g6+Yq`NOZf~YhJLz$=;1=lJp<*E2_h6B0aRyw%`UWMJN z4pnKU%BQR(aDs0o4q8W!?<)H8U(Cf3=>f!(a%{%#1iCkDj7ACe*i~gIG(k)gRfLhG zi8C%J3E(Jaj^xDJH?xz8)X7ni6Ky3?V~TN(n}Mm3aeRzS2dRQJ!kR90<;Y4&k^A*o^lU=!gg(3=EO9p z-wsPPvyt>ve~S7^T3~b`3EYgK@ug>>uYcGct%Q=*oI=Wtc`L!Hvhm1F&8+l2sS=MN zNI~T+lB+}1bKSj@+v&YEM>}Z+YyPM`k8d!Xn!t10e2x@*vuoiOd+wtkoxl$L$K4l^ zl4@VhMz#Chm(DF%iY`WSE$4I867J@9YzL^oTzhDOVi+TOx>cgzc~W#6dt?sv(CemC ze1G!A&+4wG4Q_4@rHJCz$aTKJoXICfg26(G2Hxz0*dQ~A}Q6*T#rWFO|X3|%*jd-0Y!K}0OL3%PH`Ms0HSYQ$YBRgK*8|*KhM56Z)~`f zo`C=|#F#M{%TQlD){mIgYn*a~T)6smbBGf5gGyry+DAZY8dc=c@~__`-92gQ9Kx{- zXEn1}$}`~~qQ$>$aKnYZme45ykxFG!{SB`SiRr)!JM|i#UwSnGp#&=B=o9Q-!!|nm zr_*i{%Q?2JbVPVr?1EeFY%I#QyUap-alMGp6|Qd%i(S^b(lH1S;?609jzwrJxi z@a->Kvb9P0CeCK*W9q^*6mq(k@)57g)J4wzM0smCR`O(Dc};uV6xQ6XWnAQ!aqRtstt7(`7&wK;psQhCb)BTtn((&9b-aJM|#+5>kKQ* zX^nt0{thek3!cX`YKEV+w^r?~@)blF~Mn9e~+XGOmPpRR5O}7!CRL7A68CK{c0_A4}>-E zPk55>y1(Qy{SBMGfNV3;Y+Ge)u!Y=dt6Zt-!xzBUkB*jXUmbO)83lzI=}p7e>8ns5 zQaY##ow*EGP*)Ij`(P^9n!M@%i8egzo|Ac?fo^RbUDf0@rC>`wL+cPmWS3GtyLV&?!QmU^NJaFp-&+bFsPXZ|5^ z)1oR`Ul=Z@b0&n#`1^OTgh(=bO)Mf+1@LtBPOiuGftnIH7=b2@xdmZIY+(wsK77B*$#wEG&iW)wC~ZL>kzzj+Z3f>3aCuiuMsEZ_cz)^#Fiv zCh!zbBk)oT97NziZTjV|sXjcO#}>5?>um3>dqR23Bcu)_2o^I*Ps?x!u!%P6ibX2N_nZw;hYd%c>F>ok=fT9rE-Q(mRj zo{lQQLGnoJRJbe3O>d%W`bh7~_`DXmcIb+?T|BRR<} zDZl`gxSc-v!*C*iR|%ZRE?`-eB<5kuyXUdXDnaxSY-ABET4C`8^i-LkX^^4;n}H~g zvZVi+fQJ|$+d+G*XdIli5h%a$XyT~LyIHQ&<|UYlOI8C8wRRkOvW=`Wu(aiO@-ELS z*j+`MF0_lHFNyyQxP&dOm}HD8eUs52rr!(NRI9+i^4ONQCN zSYLo(TtZ^CqZ6~k!xOzxU6^`2qd8$MY~nPO3D`Au_?lv#j9-b}7wo7Ee&UQs!2CnmxSE~_*iOfq zly=hPPSab@y3D#cCAhD!T1eHL-{^*sdQgVrsI@;xp<7g;{pzL|{c%r9R&9rV*3=i@ ztYqA=v;sLB+qh+b_qv>&sOw$HIBUT;%4*i08IN@$pBDZoWEwmY$f7mNhwk=JK_T}< z{>6sS2Q_!`?P_P9gi@3njjODsyn6Jxo3}yxm(()9!Gkf^)_@M3;RKID<#DD3O$9e8 zY+;u8(!EDM|I{$~Q}$|3^E%mBa7Gni$Gd%LxqG1y53~N=`#_+R5xO_szCX!t>d>?v zbpYzmHA~{aEi6*fK1ni}aXYje!4Ym&3{QR21|iSHeOiF#Tp>G;n`Pc}lbL`Q4nV4cLk z{e|O~kAm1}%J70JZ14(=VT*{fvMr!$7Oyl;l8gIn7IaKnnP9ErDks4xq$JMBJ1xV~ z$Ay8+-E$9^&f z7ptL_q2)(nj}IppFL)%N9v4&|exj0O_C}p1b|>*;)!MHNtM?@1tJIL!NoCE1geGI& zRg95)yQ(iP0qBZKi7?Vw2sAHj?8suPcP-|1N|gXC;V*FS3UN#b#2-1_h?R0xd4T_oER*-+?8pK{-ffae z10FuXate07Ipvj--04%lOzkd{;xYEUxV!f7+G63Ec0kbRTDCq z;q!KzuB!|g5z8I)$K;hyCsRpa%^8Cm!Z&5PA(qnenaGdg33GQeK>YG1q;uM8ZiQnm z)f+3bKDr#Cd{e#QpqQncgdas0i9y>gpt2q4WtiNBs%;@F6z732B{OLgG&RvAD6A>6 zF>I$r&O8}cw_KlFZl<%{l#s}dA3IVd7MUw_qFb z9;hX5*WB#2dU}bE@QXXAqv^ik=E5J?wp^L3178QaXUg}nkYl78t?W@m8x#| z-hmNZw~n^ywR`X_w3PQ78c$j#TZ=62DImi*Q4Qp`+5Nrd~5i zb^S6TDfZG7Hbh$H_I9jWh4f96lhx0~eQM0~$B>6&$rLHY7r#}OhUJ<_ax#8~6Y>`i z?19&I`k;Sgn(k%KArLFn@G^%v;ueH_(pXNBQF}9Z*E#=Y(6sBUz&cv`N=U#HRpZyp z{T>qkm(vQsEpf&^8i^WR zNVhsIVw`$a)4uDFJNnlQv1R2)+FP*v;auG!2jLhcHhtFmu~5N(RP1=;@P6Ns-dp+T zYxC(8<*%vW|8)Q${}mnF|2xq^Pjpd~WiJPd+S-6_fF8IlpGD8)u{`9j>rTzM(V4nL3EKwQph_+E_z~T8)HU?eSN;OqAodA=<6+JIycA)C z&bp(fr#+;`dc0fb>Jo&eD@Upq&xpnd<~rBdnASwBDZb|SJ2TFkxvJHqvA__;un1x# z|D-5uyVJc%oK&!zVA3z3G85Xrm!GsA(}qUlAVx7*6fwglu(|7q z;IiEu;9NSu1Zv)m^?}B*t4u{qTEXarca=ZLUn!0Iu@F@Z6DgWb`ph{Le=5BT{e~)H zmkRU^Em5~yCq%cvj^8VaLIiQiKy0&#OQCTvAYdtV2>*vJ{~*p5nHC=F;Vsw$nsshx z^XH7jV*Jx#4cl;DYxr-$C7XlfDkhj&E8*wkDn~%AVLju+>3Ws0+|Rn=l>Nn~hIZaL zWIu;viByilePmbB&EOJ-&OaVr{l2RlZhp6Y^_NQ=A-xxlV(%dbvbQ8Aj`zUXb`eSo zu9|?^<(JE!M9@e8fwOjXYXWmx>hd4>Fi6BzMe`@206DU1L-&9Of46bK_4+52{KCPOZ2I866^QZ)?&mk0V`Ol zIJ^dath)P_32x1Lu)*dBg#REJaKDgy;d$w4X<|E2(u1oj#>BJi`A-p?&_NgE!OuYZ zJWU#~-JQW1Ts1nvg2aft(D9KZday87?I7X;yO6cphCCfmMPkRyB<0bd#aT z$b9r49s&}OrLVf`eYlxVLC=RLS zKAq?obXNGXfi%nTFo3M@a#P7XLzp?Y{6lGk{oItl1NT-G%1jf9Hr0n7G_qbKNJ*)z z{nxNuo52WCTw?o7H}=k&h-BQ$e2|rGh^!0jxDrPo{DIOu{e^o^Ru89Y>~)a`YxHiv zk!{_agYnt~9M^rt(_qwYNp*ANBNMZ(IGiO}Rf)SH@lvASD?C^Tua=UlS0TjkywNA( zhfC;>fhSCr&lr}L@$W7EDRv)CnI~nv1bb^2zcH~i#0lG}%V6^IHto;Z7fOCFCt}vZ zMe0~X%hLCvzj$7DR`Mv_t*542OKR}9xSLY6gw$9+KXx#9nb6&mZ)!%2`mW`v;+Vz# zffD<#(B(21wj`C+x54LYyOI{1fE^|i3P_D3ZBUoeZleOJiIL5xgHwe^TC4pHSnf^? zhHCE^?o_XC64&EI2C5yKI!V7})%~g-OKTuf7c3A}UH?I-4AYo*iJImUW- z*n@-WT3lLnIF!5zHai>jo2I+=9dCtf7yg!o^zdJ_?bG)kt(xCcu?K>}&9Cr=Cok6q z0vS&Yc{~zz7zrf4$pDe9!er`L0sR1EXUg_z`QDnb_}}E;8FWZ@;28)+iVdVx$$pu6 zI>bog%%Mlq19o~#TYFu!kI_bI5C@IJ4Co?K5Yif;EHV=9q}Ly7n1O zGNEIJgc&Sh3C7Ty~v2 zs8p4g(@=s#7;JEY@Pgtf>Y8Pk6MFAV6h}C!6pmPCyk4kso>ykaFx^#FK!I_^VVvH` ztb41;Tf@ z3DlhThOF3Xbs+T_`G{yU<#lm}Puzh3H9olkup5FZ8E9q(G4di&KrSSv3n!GmGj zy3Jpwbk2&i{oRk)@P|UDuBYL$9M)0vdhP$vj+XDycfg-BH5wEs3K;Ldv=6YHh7mJQ zpR5se+U&Yxa|(q>fcho@)yPJFbI9+Gs~aE*7W`tTX#tYm%9BQ)Oea_iHx z4J-dwl|~`G>dCpb7lK90aoWhT2jeaoan;i%X@;AfZN*xk0u{^#sGn7xB2Y=&yTB%x z+|LyWGwkKlcxKkR?Ysg8ML91CeZYaXh3{;|3=x_8ufd5kb>7>XAyYfnCAkoj(-<1D zUmI^}hR&U1F3IcYdctZyM+oYt)bfz~H*O56OQ?yJ%$+wP2`x6=JzeFFiLdDcUQ;-! z*gI9@3>7SA2J4;1%e4dANA`W& zJMu@*L>#Nv_sH0rC@*}MlC@1HluxDW{oHpj4YX+!j;(NwcLvp{GA|4MTF{xF#Aflf zvqE%7Hi+N(^$QhqoG}yc9DI^o3!T-&cbEas4=`F#x_i*PHb>AgrLCF%Nm%rDZ-i=@ zSKkj0_vOP(Onk{I6j|p~6Va6AmM27a89Q0;g5{2{Hw@#e?giUfDeF9b?q;*L=|*{B zh+p55Gko;vcu8$QkDe98z8Xi*MxUGdX@_-;I^910IY(8}?0OB<#sNUYj>Y_#o7lv2 zyvfcU-+5X$>okRj0CyDZ3KuP1p4T9ft*|gz=WgYre7FFOqR&p}-ETh2wZea|yxp8} z-ins{1pDzsU75slEOP$?0+2059I`0UaDQP!)9a-;v#v7Doi9`|vy>95Z7=X|fJTo3N zycRTj?D;15C56uqG0OYv8DKiwOF4xlwJH?x8I4T9*WNC0iovDz)PmP1r23IumjTou zgORZCC2rjJJAdG>jxbBNKt;M>VuCM0J~lfbb+WGT58!Y#WIsL-7vH%?E|IR{2ASA- zC>cV?l&q!nxt}E{;%zXZgGfsn(R5r|0G4k(13ks|RxD)RH2KvPO=E z_i^>2Q=>bRX?k*2{uv2e@lantk_SYyXS?u2)C-TL_H;?%ylFHhK0ZIY3V(qERran>eb+)@T$O%=hfG{Df6S0xgtDDCrL0%vMjQ=) zd|0?)byR$>e*CW!>8E2Cd^$HIb!k3z1%XHy0rP|zw**steElfrTKL3e!Ju$j&|^g6 z;!pWidBg96yc7h9Ku#Dedbn!&ghP1+m9;2RL63;$B-{-Rj0x@QpDOp~NfY?VKLz8) zM-uY@@wQe{7RSj$8ICu;u6X02A0f8L_9;t`-hz5AIb90p*o2N|U4pJi|0 zXE#a2H*MI!cg5sXfdBe#WwL<`_Q8ovfk|DFc|Kr>p#Eo+^d}!5o9^^{p(vus93R?j zbClpm!RT`Pc#@VCU)y;gc8i!af&W1=GHy8Q%Lr-&l$$pz3dyX!V0~5snH5pnUj4)uZ z1QDk}wL2uNTA>SZ=oR!zoYO+=AWRY?J5>D;8w<>l@DpO{dFq1mzi+!**H|0M{uM`3 z19uP|U-!$==o8#;C3oe}T4Rhivf8Gb{lHh)-y0)xVwfPS%v<^2*BV3^pM#QKZdBh& zUw$;Pi^(FD=fQ^-=9Ly!IWyF$+eD#ez8Td(SG0i-@G2Qj z3}{0LQPiC5`BlZCQf4@E^>wc!bYm&FJ~E%Y)g|Y^ygYH`baLa9hJ3%>8KaX-sW{ZD zbz4ze&1=Y*yKQyg+Y85(PqpiLmfNXx3S0SUou?Dmn1Do~Po>_chNfR19>sby-cUC{|JH6z=3;pM?f$%kE%JQ9O16X`m#W^E zr)voqhglF}h%kVGA=|S$;HNk$JARA*0`BrW@M#G92bJ$@se6W~365ED4bSju3(t*g zE;m!kZ2oH!@)b$#3aM^)K6@@}DyQ`hL)#yRZ_%=*=$HY}#Qg}O55jBcX#Y$~YWkw$ zuHt|EH4r_ff?c@yQ6|}-l@R1LSvHR8y(m|rs1NMY3BZ#aTj0~M24dOn#Uj!8si5F| zR8LVkqDrEy0VX=~3gIiTV1B>HvF9f-C=Wuu5ztTiJY;Ky!!@~2jk}+UO%ra7exeei z$=o)NgBmmf@Hb;y{1{xkL5~OSjO3yN&!x5$I@TdX8s%*y4j-bTIB=$s_1SPTCMv1J z8)Lq)8Nz;+V9Hhx^#09Y#}elrGpXwO|VLYoRKnJiC4a-+#5`J2fW7KzszG==yPMRp#i1Rn)*3>SxAgT$c zhC(iMIz8g`>r2@N6+dr0^<0AL`?5^3tJ|VXl6J*vmcws@ z=o%b*s_j}NFShdK1o1)N3tffJ-CV5N(6k3p&;-~=rM9GSYyMQOaKJ(l>1q3&_Y`sT z*uuZxYhevvpNwMX=FN8#+6(YZr=-3y#nQ%r_1U@Ow^IAEEJu;CsM0lBB>NX*xWC9T z_9#nHI?s}U`SaxUXFkO{TvQ+_bWk*h4eqyB%sAiNZ`u{PB9FuQy(rVUoQ)1# zH})ec`3hPH30-6qUNBh?sdLq)rKikvO*srgkp%_!cY}X%_9v*9I=~uK=5}W8!6>7C z#!Dsk6Z_iHKXFw^6oA$r!z^cg{Y1_15_I&eR|wi1`r}v`ys{=ZR2d=$YS+&)ZP|Fc z{cR&9b>;QGu)<=Ia$^lgX0uMQGY4?8PhD(6+CR#8(mJ-gY}n<-XSO*94Gg}>qSDM( zw8UeRbwZnO5C%2U%mO3ZE-8gxx1 zWbDau(kR0s+auJq_;d;g7!&rb)LA!!w!>1q3zF@2$JA{Ur3ZvoVvsG|&jPQ69`Iax zaj>PIv_YNe@NVXZC{ftLSujM#Xrbv^rb)LHouBQ@=H$!;w+sEK3j3cXz?_Yz`*|Nn1%1 zy;i4*)1)3gk=ItYi^=l22N(gcK0AY&MVu5ql(An(BnI%}-KzI_`OK*4Q2|n|+Z^&_ z=@1;U*iQ=bT3=1vB4so!#ItPEq$p8NI8tdEA3YujELs&(yxwX3tcToT^+0=nkr&L3 zX$rb(D;(y16j#u3s>bHOP$7?@7HvYS$)f9_Ay)QXezVFl5!Ixl@}2(1$f9p`a;&qD zTkVl2QPb$Nrevhpym9^DE{VBmM)x|Yl@Q71O$*YiBM40`=BZ9_u`?O*of-*+k55pc zb}m*_b}29AyVbMSO9oD~Zc60wV4mv#w4+y6)xsqpz2RpTZdg^7_SwSSal+pM`tzxv z6;vzL8uvt$4ddgnld|cb;Ix)ENkiy99tv$KFIKS>xTIuqt`V0zzqd-ZNi5v3byX@E zq1+s_517@aIV`NqblcmOEY=zm&X25Dvh)v$vM=mjg1`7Z$QHXh89w?Y>OOP#?Q}I{ zEK(?1VrO>3g|VdT_3UqE9pS!J<$NXOK-THj4r9yAizBgmPm!Bu&C}?duvKvHgEE{wVNZlHyA!hadu-jr~l53NZ@F}XX z2DD48gj4GIw36>y`)t4nJTTGi2VVT^wvJPJ(p`0GcCQUS$DLqI+yi%jXD0zI5WOCR zY#=odt-aCR-T*J+SR(2OsETdr;uvqt6l9Hj3+m1Qg?UKD5XkV*>+96?uOgxwnPd;w zOw#?5cp80I{i7o1XwAg{rrNe(zDoWEP1+(>(n3>t>Pw|)I5?$oG>Db=1$a=_l0zc0 z%shv%$!Ckv8TeCb^>IVIBuvsCY*&-+uu0HJ`7L#w^kyP9+sz!s?Mtq2i3O?P*3PwQ z4aT+2w54?8TSU3i{Ka8zmsAlrVpHju+ttoIab^D8YuQ1;8sz=kV&8@5mj)~+jG{Fz zEZ+;T0Ny3!($L>JL7yZ2Lw-Oh%y4&D#(b=gPY!N?IO6xLpvxnU6Aya8Sr2P>8!OH- zX6XG|(`PNx&0ufU?)p)xB zs93cks)qv~uQ!a5(FSKgbk)dsJRse}VC1R~i*ukot_sZ^o23^i<&IYl4a{lU5)wng zqk6oubMUR-bDrGss`w)J5Z9*Yboa^U3=HoHYoxa`F?Oe@XQo+I;y5xIC@1UqVMtNu zvE?Nf*kJ46v&^$Y6M2F7!A`uZqcTdan)f;2_rw6aC z`;i=ruPpW@#DNLmim}XyBx`CRho8T1+guSUX5mGjXEFUsRQTs|s%XDC9#hu(f2+G~=>93aALiHpbJ zP+-d>w~8A30f=gfG)AOXd+?5mkHn}F&~VokIX?|N_-R`1;swRPIk*&=p9-WgkLX>C z9$g_(pA7O?bQ_;{0vw@`$=c?eD`@R2-2LQ4owW6Rj{8pFqWl9p!#1YP$K(E|hg~MP z;wj=>O5V8KCtufnp2ztq9NfF+p>J(!Kf)-X=}T<;Wr#zM34#8c!LeRf3WQ^Qcm4$$ zKd}c81KmNzCoA2x?qxEGD)Ja6&<^vlmgLdm43`BDm7H`-Pogdm`McBD7&@gG(@*nf zVw)#@Fp@Hn0&SaGthxFpHa#jd!GwC;)_^6?ko{FZY&V-==XbpSHIS!G_QD0y*e<2mi4RQJLZivWaKC zV59>if#fpEeyA?>~yv|a@Bax4!K*v2~P?!zj)5C2w2UQeAFfg3r4p!5L7 zR6ul|L6>pVV6vFYm!HRZWUsl+wk(HTuBV_(5(y7}d6iUmh$ui^fe(MIO|5am6Ziql z>n(HJc`@t8v#pBJUpse~8qe3U$OcL zJkdml@8_hIdOS0T?xVEphCph3=a>^u|FKUn-*IoVuRBJIl)2)yoGu_xWIMTT`wywo zlZp0G7)w_d#8QkcQ4s9PjP-kHC0b>=1U*(hbbBxh+h^x&b)k~5&2VGAjMUNDC-=d@ObuYzBpNWCtd(bU_FT`)M{G#P8Se*v%vM%?*P3~$$xzb;52^yttUpaZss}> z$KE9*eb&V!SN&V5pFm_r&r>^P9#_?PxBMf;Aj>L+qj;9(&lp{yzRhn+12-h-Ol^Hu zWF$?+@HRfZ$jUL7O{!mwZLvZ05%M_!GvSp$hvZ`&JdQisRWoBXOhlZR&2Wu%$7f(B znNrh28Yw>w+ghyNbTm(K{AT(&vO5Xulm%GaI2~U52|BeTg~KwL7&ThH3}43-8(Ay- zEk=fb&gelVO!Kz1X@(IcbaWK4vok9l*89gvLhiy;Qdtaty#xcf%fl2|@#+olzP`Us zWNHZDy6xR z!O1EWs+$*sJxdRW7?JvS{a|XiKATI`c_o}5X%hJ6ura)RcUkK3ZePnxPsprUu(yJ$ zpciKKs3?Zq;&1DMaGOHbkh(TNwj%*AYnQ3h*kPQbtkZG8EP2D*I=}6v zyh4^)@CAED&zK&kMQ$uLdoAF@WWr`1>rn|V>~Mt%WOU0Egai$GiQ!#dR>b1wG40R1 zBnstDC|iz_jFlJ@IzurONqcP&y@6uv`NAO18SM9Jd;&8iber7w=;w4L;XE#eozH1! z>SQ4-cX~H`vpRM~^nWd!6YmqJK9gPZDQ>MlD-zKA^X{|Yc&S^Q1l_%JTzym89R z+2_%YD!BLbBAG%TI9pTZ;-J~CbKK0x0N2kO)i+*>JMfZMfbo}H7RMC?-9VP`Iu&NP z^Gh1y<02n@ZcU$yB8zN6F*Qla30%c(#qPHf>2jis)hm=s zVeYOYK){Z!pPrlJDk)5fd5YCz=YB!acj`)?1j>OQs?CT8A!ANx%qk=DGtE5e6cThw zfUIZZREN&?`ir~hGJ*ZS!+=2|tWk`x)>wM~mn?bNl&`oX^T;3tY^;|=G@|Konv3>n zohDllU)KbzLJFJ8?}V==0>`fMRpNIC7};~1Iv&=@qxxKx*<5LJLdse*xNhP+o`;g} zehgd=krvTtu5&Ju_^S01)rz8}dOV^=5V6 zw|#uSi2c06y@p3Bg)0kku^EuvooyJz_htg!%K>={k^D>;+i-}qY z-?Bk@l!4}UiC%5Ay1qlJpTP?zWR_c7%Pc*4?07<>pErxNz1IXYEcB6L=sB4?!91SFyBoIqOEqPU(}WY8=wq(|2ZE`kuhv znqz5!g<8>2)oA76zgQEN zjRD}wAQz}MSQ|<0!*fZLp9^0@jFB}sGR~+BL|+QZxqnP)^28)xG62r z8kzI(dk5aJs_Y@=s6P>1Hom-T6lTqPq8T(F(2@FSkPw40dEP!*4p`K!m7Lvpa zkbdeaeA%%=35vhQZhuZILpY2{i(O`s+lo^LNFS|(tiOUG>wB2o?oP3nuA(`$kK>FL z6Q&1eI*>>vN1EPWr*LyTCBASS8&)vJ))fhlaA$YVADFJ0uFFF^(Q+a0{#CBCyn zKM~=rsvq`Ue;<;2P{xuAJHcxrY#-xebeiN}8P;glH$!!#J)Iaw<^Rr)e1FuX{4kTz zuzn3^W9x2O`N3V$&Ty{n{#Nfr_AMN`uxF;BUr)^5 zdgQy0`dpSCz7`o6scrt$$f_1CWn$r-pP??q7l9KZIZr_U z0YkgEWH{`NxvWVgg~+HV5b3b~b+HW5On}|FE%-N%Fg61xu+s7Uo@DMps6ZSx@SNBI zL8E6rOmyA&=^op zalftI@N2v-LtMJmzlCwEzD?W&A9dEN`Eiq`D!~5RD0o#qas(3H9m#ea1-{`RzeG~H z0fgs8#vjVX=UYji=()O8Cgz5lC9D6(h6nvWI`#icTl3E&n>dWss85aF*V}{Uuzs9= zS}Ai39eaj45+X363-0=n-$IN5_2?sR_#n504v{ibn+l-IT}W~FiqH|zP?+n?fLR)m z*cPxiJ_phf)&!8>FgF|^CJt^!e6-0B~=$Ms4xw=X@a<(^L zoMLMESsw*WzM;`2aWJ?oQS}p*uDXP(Z#po|P6m%6ak}W)0*|tpzs%5#OuYYD*+#H?}%oSt;;6vHF-@S9zGa>5#?Y&n7T`7GbomeKS7bY z0`IvBS`DVMhE2wvkdZEniHp|0p}+qrM`aMinCJ7Prgdq`bg$$RIPY62tM-A>#-TvG zvgIg+?S7ghat9Z{?wjFqsyIQuvj%5Zj;~`ohG$`B`iUtHMZ#W-^e7kk!4S^<+t3h6 zOJh^*tD_*x{$+CHAhfOig_&bdu zs5tVLD@;;56~iROTPXq#hn_n`qn_kSe?vbVZyB=|*>i=lmedmsp{25XJ83-!wKVDl z(y_byCx>^CtudVQ0QTeO319WT6QgYn^&G2S9TohDU8$LxX-z z+w3k|JTbT5ldL~|hc1wPEVRSpbY+j}i0&+cJ+OKJP1v*>@BxZPye+*Y6^xL@l&ATT zAY-4X&*--)@r+i*RLWj>c4!_sfa;`JbBnW-U?b2&OuAV8RXgQ2p{Bk3Iz&Z9s|3uB zi$nRoa_PWj7S`H6-n>moBg>7PLuLr!yIMG)oxF;w@%u?O?2zzpq+THSeH1`+FiKt{5ZuLp+AoYDrAe>%pGM zm8NDEe&~C04bJ^#ZVt^@3;pmnpIV1pI@nSOO8Y5eO$#+6^+xUCn7vP%0U$g3bz0{7 zGzD~=4()1-D}@USHXX@CLk5T~Gd6h)(U`rH@w3D(%q9`KYBTA|AiIb@#mEE{tu${a zsiScroL&Jrbp>GpaA#6IvZJvE2>T!QQ`paaO<1R1Q3a$wS%s| z)RxKdE~b94tjZgI9-_zloF5*D%5aXnOxYoU3@1LJwTp7~vrFjsINSf|==0SEB-8k& zEJZ|4@`|rx(m_(Lp^;L|w{7B|)u38W zXuJ?zB4`Cuf&hbX=nMg(*egVdDPJe3T=A}Pl5gIg)!HM9} zwzj-OYLpvY(C`k|LpmW`IJrRc=XEqSL7qtWG^#Tq5j19G#qZ(V?mkJz{#R#2QVk~Zoe0$Y)w1U#5vDTpbo+{5zI(#b zbKREfcKg<0TC2m#bhWwT4LGLB%i@B6wm+8>UpxEa3ALFdcVwG?+g4^hhlTzG5PXzj zjT2W|hhrDWv<|?C-b`X9#_UjxD?1Oy-fs8APC)_uU>56`id!TT$bEgsR=jv02~M&e zC`~I5+bT|U(n%dHFFSY10B)TrxP)T7mh{U0o^~d(X*YY;DfLJqC*wAY?G@1hFVy_= zcXkf8&o&xa8j6ylA`B?d*=cCU_V=-2PiM5?&mjb#+IzG|!tsSHy|)v?lEXwlc0+yS zYetzNOSR8h1lptrUiXPHSB`2H(IR5hO_iVc5^?0F8o$>no?!`AB}gj0X~?BCHe1Ja zfJ3Wje|64G`xc*Nt>p0=Wf2{`d(^FRS0aln3)eP=o@~8nl2+OZ=)Yr*8MX^AZCIPJ zU$0nye!6W>xmJWh-ZY9_;n|D-R$rxIwfHwKA;QMi0tcFz(TcC5?FJ||qDl4hh+(yr z4uo=-xVz96cT}i&7J!&KKkfPQbz#0(<%P8sp)(KUU~uhX-IPv`C_*g^x;>@~c+jy=`LujTvHebkS@u$}O+{YZX= zdX5vx`(4=XF=}9oe9#zJ#r5~Pj*_WME=s&wJJ#v@Fp)V>SBRFhKBr9gPoZCB$DQ<( z(UV{9HyI4O-U*DKs<2%**=U*FM+rZhpX`;qC;T?C+!}jx>h=)HX>}cR4&(Z-kL>O& z>EP$=UFZYripuJb|KzZ1f1DmZwlf}sNS+6N=7r~m3k4j-zt0c^mK2ancj?+bC-VJS zN}cEo6y5WCRp65GC}^^|Aw$99^LTFkJGL#?X}fwxwwrO+*e@zRAgT8=@~g@7)!(b7 z8W+hKW9*p0H3pfxI1>}0yIzVQgLeo2;9vBnUtjINyz@v2z3A2lAt#0Y4eVn#nVK8e zzZM*@8no83ruEv@_L*4Fi_h>To=z8~B|5prUK z3M1f8g!GlI!mzx;NB2Yve$tJ(GW4S3>wLNo9l*GH0-xO*6H37CTNH%|APje%|0jIN zS&NU1KzKKVL?M$0^FQavX#cuX*8ep}{?G2zxj3{j-Z<5@Ev{lEc0?*9XWi-_$7#mZ zY=tu6_R?J-IyXet8}RY==EEMsK_E!wlWpeL(kjW?ThCOZ&`)k$UDgmUJt@r+qapPIe-m8A{<^N-dZUDh z>!7c22lhEeqH_l17WXMR-RzLEC0OPE`DT=#y~KiKbf;WhPd2J1aJ_doEf(_Uxb6yv zmO?Cit(VkNE~!W=7z2I7Z(T7`$mxSO($n&OVF)*gnv)78rnz*=m+>sxqwBJG7LA+J zkf-Q|SWw8#hwD=Cz(zJK(hH#tmS=cAeIQ6krrX0hDcr??(qn9BMN%M8 z`ojm$zg~BiNrSS;2Jh1CD@hd+y#a^N{C{?W<4Y z(HQbxdu)JDGalu~xdRFR7p+#SVK||CZz0@v;hJBWo2jX-JSz>F1ze#9?Ngg|W;v?& zZ%(njh%-b-8p*TP>{H)ZycYuyt;Q#e#pL?c{hp>Xp2X+sr{Y5Qw_LG1roEBbj*#7H zWhxsK0;WSwOXAknYl@Fw!X`hy>Kc10X2}-FKja}$`1&Dhru%h+7KmKHCGR-1Tv{%hOJ6QqJh(uj&Nkq}u&i7r3-UyQ1|7^UHC%CJ->LtYVrX;%Y zKW45cIYS9>N$OfhHT=NM3-Zw7sZ!LCBSk?9|;=X%28N~3^mWBn|cwRO50X* zeX}`e8aI*L51uE?+y%QC!)jjmrUO_zU8AHE{zPUM3aSd62>k7{JS&VV=7U5pdN3Nx zmY2bXM|iZ4?XU>(oL9vUO9QNosG9I}tHle2bOOs<7A>nQZeO(%mpG5I-0(aja`ccA z8V?9OHO{Ee#v)^lO}IbIE9NZugyMk7*`hs^j@O9|%_ZAM zvK;q?svOv&^{PrM#}O`x!M!_5Th1Gp*thhVEGSO>Q0~)XZLv<+dwS~D9)-O7JAS(P zFz?7#S>B2lCu53UG-l&5`Eb)6_}(}S6G-EN_ci6ch|hRLoTs`6LXSZ0Z&uE30cp5$cIl(KD+T5-AGy}7^22cYS^$;tt_`8 z)>No^c$I^M(M=fNKbv7}fD${r8fCMytS}Q;=}Gl1G;zrGW!`;C#SQlkJ=Y$YHm9sB z2LBKopXog7&7^oH$3!E5 zdXn@`A9w9{B^fXk=wi}CjCy$lyGQ~CW|1!+ntn+an|NVm&lXyTa*QYVYCp$$==^B9tUXt>#4SNMJ{B!% zg_Vi7fEAmM=BT`0@N--yiRzXTnr=j-_QqY2C3)HhZ=tF_;t*2i2zKF2kfP&v)W9O%bh76HNlFs)Rxja0II) zUV=9I$x|40&&Ba5KTRk&vVK#^8J(gi5fCXgmCt;-jPSSgA-M;E@SK-E)s#bhleC^- zJBGFatiFxoe~SstfE(Qqg6~*QdgS_%gU*I?l-C4RoAKlZ?%v!0_<`LrMQL;`3<2|a z{fi$O?pmiz{YhPUNNK@v-%@6Mk`p{#P84wZ;!#-rFzdrvob?^(WOX!?Jc6n797z~S zcjzaSmKVwu59zr28NUeEH)eB2gVGwi+7fOx8LiWhaz@*is??8I!)gJHQgjOO+jSOy z3qg2wUflwHsd2UYbb2|}+L)~00sO<}9OgpBjZCUlcXmj{euM&Iw=AI@Ma8T)(^}Pb zC7_q>^=gB1%45Nh}o`Q#%0Z&Zj1H1XBux5fHJ_&tVW z^wFjlfcyuu!T0K6aI<@%0UA1A)g`-$+k@*n+BkEoCo%pa9uKYqqk{0S&SAVu&hC#f zBLi2Zk!2)zH3V8aqak;VeSELZj%PiBFO0Fxc0(0C;#Z1_SF1acWB#L!bADYpv;yr2 z{D&{L1-V3gM`YY}l8&JwJDQ815gsKUBb;shs^g{l?d?w1apxXSfOtCgT6<_It1f;A z+4WSFl$7}y-Icq9$^2q?xJ{m4G_cd=AH6u&abQS@w;xDp32*fXfov#}=5ASR%L7@vrjSH507ks5H6w7Owd2kh$OYyfjC4POU11K^ zb~W19h`D-e3G)mEP#m|c5CXuRvxw?w!n1^0K%2|+e(||E``AeES~o~yfE&+)E_ppE zq**VHuBwPF@9Ts>MZ(Tq^t8Sw4aT44U&g#rb&+bPxy$A1#PzG~`Fr~GH*2PdT^UXn zYvO#?<%PxijNAr%Il2KFT$BF%6C`-Amh0^Ra z9Id?ZekvmbW2`c4W~*iQ_|D4A6M+`;Z^l1kwJ-{Fo&rkVr?4*OhD#i8SFrjHEWQ|x zuEuicoUGyUS+1z!2lZ^s<-3?T`;UkTb>#HTPWO*E`+1&02D8w2m8qNe-dv(p$5-3>QX`R)&WOeTuT>X0Z44#PzZGCsXhg?eufxuxUL*O-a#X zLc)@nlw+{vornxKg9?@HaJ_i>ii(ddO(o5-6i`rTR14wPWnjUzwHfpVvYCQBXr;s} zVXLWwGRvhg$Luq4$TIo#1F_u8prRbnmiwsx|hTFTWTH!DKXn)RE=IC zwyjQfbRI8=`iUAUhV8LLI-&Ide@=Nd(GJsx=8#6rX#JDW#SA$6WADG#_zxMeHT+IZ zKVm!uNXA||@H>ewj%1?T{s%llM|UBuE(sFC)RO`hbyeBXTf<+Ecu>AL$d$ z=>WU}nOZ^P=Me@jiD8uFEya;`ui6ei#%#DzGSKdAF9t}DQTnt2^5^x-Vp$m zJEdehS^5G|obvICOr08pe3}!UU>|uP2p)Emk%} z^dTDZf-7FZy)7ocR@h{@Q+XIe1qnlMIOD}>M4bLz+gO%X@yv*jf0O#GohFOyq*F?a zH?F{AZ9hSeVeBg|WRX^=g?lE;g`7e`5N+bf=%ibi!G)&*+nj_@lELkgz7yhNN)tXa zA6~5$r^rX?xF7NS69S0Nd|g)x-+=h12VF#a8y@-A-zOy?>wSq4$&pCYN$F zk(H%b=N6Dx6{8pfNhWmGe8c~MNndnN!=?AmQpo88IH>{B^*}iEdh!f}!P=9!{axg* zh`HV3vE5nDpQw_)`H-}%rvQD!zg?I%RC?uN=FP?ATD&mSq1>HoZu&!dVucw^&1q-?vQRUfqvZB{h2ai%;rc(2w3ZR9;``aKJgm}fT zanvP+%vGs$dID%DMW4Fk#ibGd6X#HXa{j0Kr-Ul}C;I;{Ar5$7iZeD&tVNr2ODJwJ$3~dE<6@Lv>9dAPuR7-Vb zN3B&mO|M0NTc-gWUEL^cE7!y@H+0i?>iLDb#kS?SDdUyJtqr4{rM_LwnaPt`&a-Z= zm8F~2yYCN2z^5m(A5(Xl(3fq08y1V!J30PpsqQeSNY@tJkH3*-zmUp)1)FN%&oml;6F1|N9@3f2JCFNAN zN%&ZUm432G_Xl4cq8~bsnc_!jdzC6F*$Pj9PflvHP}8T#DapBYXx|(avK6@GbT(?- zPm&9x&PBd$;t7|1>HC~&q{C>Ss~i%&BimCJS1gr!o$t8SQMFx-n&TOY4RqI<1Ik3r zV98t-3_Tfp#V))}?rlUk7qI<&e;mC|t1voLu3x)X1dYk9rv2^ybrt~t^O8ffJwDKi z)-*l4Tjln?zQR`$30o4bWrvlsv?+QIqSF?!5g-s~YXHVF)YUL%0VLEW}cnRY(KKJ)5u}z9S8^^MC^4NF~4bY!_laCrC=)wEV%2`o? z-dh*QTOLiQKXRrRWCxl{8eA8LfYtp-u0pn(HZf4O}@ep6F_SCpqZD_K7Q}$U)R@D zWjf@ev2~D@iYZji#Sv<}7RQr>)=;Sl^JX9VJ7uibd2mZ^;3{P+Y|X~~a*d>n;mlXM z>M=Pa&UX>zlMfzj#t*lx2qmksuc9$Oy3J=cjB;2!L|z&0+fcpUe{pcbTFTWg->!7!Uf_n1Yl^!S|+bQ3=VH0ZF3K^NsO7Gt&u zo&f|y(B>$7NUanl`*NMumSC>yDcL^pijJbTMr}LP+{OGAmTsdkI+CMVR6<<>>|(G9 zvN^Pde9A~tQBqV_^pgT+Z)}LUJH#tPn!G9Q`SSzwJi;_Vf|yD@BFBE?NmZ zVrnN2n%ZYhb4XJ=O}4oD1%D|M@&OVuDX4CaZjtza6j^*4KS?98RQZHayGl`{+0FEU zItda~Rs~&b&DfD!mbqy$_84;JZ`~5lD)A$8(7DtN^mNlb)$OWVjI{l@n7p9T@ z2xwrj;)`ig8ECrk7S5TyqiB^?WW^C5Ak1@Q%HUcByOReqnVGXi)u7i;bKlL%iY#S@ z$)z8q(?BuI=mBBH1Cz2il`AFv&k5%_Qp5_)496I}KZqjP=GYP7^d%_X z5mJW^(o#E zP^i0os`uJ}aGij_;B3E7n%~OT<=!61^r}YS%`J-Z4Jb1-L zK9B(z=v%#@w!sqDoRiv5!w@#jE-&j+A7;OWMp@Q6Zm~`8VLW;0DIN(nE^|m1jy)Do zQg7~8Zz%}pD?Gu^8eXWQtl@FkfEC0108yJU8e`Is3&_L@K?6O!h*)W1dk7r_dpy3V z+8&FUD1_bP-o!H2LP)>gwG@$Y?dU~Vg_RKvnw%1|jU0 zZ0=m9`J-^SXL$`;S>I2dOxgeXu&4iAm#aRFo9NMyRZ^H<=;2}Bb@3wO26CI&^NbhS zp-XG8YibcHfaDl;Jv5hyULDnQ53zL+lJ1X!McjIf;Py!?#d!IsZ`Bzca!gLUs1sxhMw_YqJq|<$GY!D@g9b&c@CCQ~+Ki<>m9=Z~I@p zR)+R>-z@OP(W4iLu(yO`P7BY*bm+ZR1sxkC9`M)8Blr4%6a{~_zb3iqSF5v)ZdBfe4gW~hUDu(4xAc?CyDZfj=8ardB6EeRN z3qWUE)*DBHp~Zs$So9^J!>G61&TEJsZ1bi507z5mhIoYW`P?Ghi&tS%>|*~@r;aG| zi&F`NVRy)vkib`s&*aBrFj^(&>_4x)jA>AttJ0y_c?GOhvp!5ZHQWjn2aodC&>*)% zt`91q!ZV(G@2};a^1HOC^Vna@8^iCKWyal%8)f)m^&I&-yb{kfkB)*@BZ%#30KTt5 zSP`;4M{d~yArq9rJ0Eylft{xG`0#W-G2D%@OcZpBh%pH~+|LxDsq30AO##?HV2qmM z*w)ocCMhRmzOOJG{kX6c98MO#{ zvl!}G&IUKNlW2LpK!w%y`njW^p<{xVKj^5zj@c|x_>_i>r3%cNdtGUB)7aK z^V0^2p21w9$!i;qEq@glQQg-G>GVkrXb*9GUQ!%sll3X$K?#_*iEA z6Y;OI8IM*br`!-d{3KWc_nnQ{O<%0-n7luwWRtH!HuQY=`(PuP{4YOKXOsDvT7|fT5Ts3)WS~T}c#dL; zvyD|6|3>Vb4_HQ5C~}e_Gs}DJpeWi_C|3bRjy@9o!K76IFSay9_P$uCl6V%0VI|#u zjWMkKNS#N>OqeNCl*swZeaUnbZNr$VSaqpvWzupfL}aj3Ls7j&7lq6_57rM3*j7M3gzP~ z=6*>H=`IS>uaxw#et=Z+`KpIsrh*l-6NH3Q>?)J=t73`bL#HdViK=oheX2`gW-z0Q zKZK&(UaMfOs>`w!*TSoHW1<`_(!aulPerH8BiBg272&7Gw_H}YzE?|vYB1j8J&J2o zr)vIm$Q2Ul(haJxm(!MW)$PZI#!m(~57q72 z)f@QK_h@h&XQ%yED4-=^rh4-`lYu0ez7j#up`S6+zWVr~D_YX%!c4m8)rehHL_r zuV}w0B}ESEVEOqXU%HrPw_y^MFJ@^NqT=btwHXk%n=+Tn+q7Z(wOKLeC7KpHU6osF z6ubN)bk@&w^Y8Ff>Tu2J*e~nw|J4z+)e#!k6mHNN>E9Wh(;3^-8Nbz;@T)V4xGP1t zE6u*cM!zemCzU9+E4-$QbfznLzpIeBt5~=@tEQ{mzgsw~yV}32)*k`+|H<%v|1-n? zw=5lYm6>k~+Dmiu>uS(2J1}F@yL+^UBh)ARQ0IKxyB9Y*cPEoi$2+q>U|zRg zX8)Z1Tr>*dXUi4F+5I7kRjEwbjC&ef6b%R??lQ+$h@bJn_$c`dMw=7FCFDYu^CV+0 zp4a7?o&u8#*OOG0mZ`wtxaK1jYMPH_QiOQn#-`Xxgfr?Xa{FnVBA2aZa^-DsDSdI% z<+b*-bF`W&G3wWWr{oW9mlG5I| zM(9V*?8BLW zMC)&B|0;ONA6Kr_RWi?s`WxZNEi5=ix~R#3;`mt-_zGs9wD;$<(2<)fFwJS><)Xy< zmeX5|_xYiEY)9tKkL1JY?~k*BSbtw9QTi`N2K>cf|9mj8ijx{1W1jDR+JB=jl=+SR z8Xt&cTwxl7_7}1fW?g5wu8E0Hn`7Dx!le=)O+GJ(xy0iHM7PE06$>GQR*mFYP+m5@ zIK9qCBa!NOVZRc9Z~&aae>4b8gvJXAlQvBGEMt{f-qxgK>9VA3nJdc$bbVAqAPl|>$bzHEN#zWT#Vnk5Rx(_eF8EL-33evJFgFwAVJyf<7N#bjGd4GjutluvF4;_kE6RFW|jjmH#^M&%wxN}%>T6PZlzTslr^4|Zx z-hW1yZ9gbgc&Ql|;L3k9ENn!1C-`}hgDU2c#1eC;_kcTB<9=6dr?b}+jVpgf5?X8e z*@uNImlmgqzR>72ei?)=Lt`YL>^f=OHiT_N)5$E0^V}h2a|JB%0TLC?+ZMlBV*QAj zK3heL+H!Dw2$pf_&;lB~eC9wk)NU#QJGL$jUrzl{RAPeD-qtpZ$L~{|R^&3|%Mof4 zdHx@ay#-U8ZP;x|(8e7acXxMpcbDKa8l1)*8i#IZ+#Q0u1_(|0R7a-?psV-B#nw#DK zARzcr`by~bspnT$_9Xl@wC@IMU8Yko)8Ji$g0T{)tjF|_^wK0JwXHuHNd z5T%EZt`u&ErsLHO)VLLQVaBVl%IE)3(v%xN zm&N&=(E1|JCKMx4cgQCIiAg@hIk(Lx=qeUbW^>qH*kIqhy2fU(DSNv@$qTXQh_JBD zkCeIhvWUwL#OvsGeaRM0Z%fAnnEA2w{6gpQ5R8ZNsjkv~gwTxq1potiS%qSM*c?G> z+Z4M>eRQH2Tx@KFelvbh%Jsvw;LfT!n&PGroH?-iKE=az?>-C){SVEnHlTysoS$s@kDXCoru$GI?6j`ZSSFAoJ#~91kfwI9ssb;bK zO0VJV+Ity}B&=#K5U$$VFd@H$gCEv_64q!N^{3C^caH|x>${F4E4=A5{tC+qO!>gt z1iwXk1x=uXR=GR4r8B&<@%fLt=^)X}xTey_^1%!2fiqR2lrs#^+xjG3@cL19m;ZOe zFIX%}s+*UJoo2x~EQ|Znf(YGci;2W~4}#_ouTS-0)0BpDxDjg+m5WH91Sk-9$I!gC- zOp0D8QF-#3Y}8ONi&r7L4kLL(i&Tevs(CR@7w{a|KIrG+qPsN@XSHZukQ;wNX5V zbUKCVO{Ju<^fgK@$b_BzrIeH2^`lkoy&0Fcl#I+@;{6zC!V6An7z_v|xh?|=4izsI zL(weK2`y#fpqy1xE7kuQBAR+OR`~Yodz^-IWA;WLHl97Yv?iOL4mU{f(S&%vUb+WL zKk>(M+-!aBFB#7JGD5zVi@~=gm=!zj9W$S@mAtgp39&zt4f^X=K`DkTGw!Wh5~_QH zN)u9b_qzoB*AZmp-v0Tb-Gh2L0l)hfxQw1Xg?d+&{Xh8L!%|;thl-q+)ZTw}Fgd&)NYwffEjOS6q$di) z9||a74Ee6B=}B5+zLe?_aukFUx`pf6*4)w=7X0c|jQ!0e<~YiGqEqcCVKaVqPjFy7 zo10moF6bkCSy-7b*z8o>7DL~Ey3ua{zgW9|Lt^WmsdVr&F{hUJP|nbxm~mK#dCm(j zSKHq5`w-1b@{)L}`v)=?+fv>WEb< zGrGGyD%6>w2-#NgBvwd-NE8xm93AxJU{`9V;&Y(p$maoZbhi2~99PL8F$FFuH_`HT zh=p2&wTG#jIO-nRNO*bMK6?BvmsQh`_Ctz`5OO*?^a1sN74*RLs}R1Gc>SB;TNO7) zAk*QzZ@F)z$}K-_4tVX=D*=e=69|B`%ZY*xgET=&-cdo#D3|IdaJP0NNqITJs%o0C1zL*zHhXQXX&1xnN334R^=b1pBm|(+9gD? z0Rk{RsMZHE9RlAUiw0$rGMxed`#qRfV2Nwd^vyUS&n4amz=s$B{u2l*P$fMvH!WCMKFUh z2SHi$pzJOJHnbTyt0BU^7HKyYpXFg6*x=q(sBH=G z@SSW-F*o-_G|wk$FS48f-keg~oG>rAj96yyQx18QX$y9 zoe}{ErT^=A_=n++W26n}4>1%@*Q*!vFc zCpJj59I8j0DKJ&Hy08cPeH)}C{&D_Gg>JQdk%YRP|N7xU{oa%R858Bb)liW*8Ve8Y zC-#5l$fhi#jGGZZfT%TZ>E*hE! z+rjl+1uwItK{mDz{6aEc|92&d1j&VYgiEzNQNzKn$zEP6cSmRTNiHCR3?6sEtZ5;n zWPxfWyXQBIn?y8{A|;5YnZU{@m^j()14sfgl9=Yb0pIgAzR73CeiCvS(qxGrbd zx4OJFzGN>H&Y9s}ud_~5HP@p4f#!#t$twz-oTKreh!tVPWA!p-MCP$2jcuKiu_ajP zB;S&K%sEN*gteM97BuffXMs+JN~HrvX`ynZu6N9g2k-)NF@D(`0aNYefMnow!2mg) zoUO-PC-rw#=-%Hvt`y8<5Xm;fzS2SfUYPumbnMha)fTQjb-7H!lncg{QfjVb7M`Z+ zwfkCShF&B(9@T4(g`hbiY5;FOZB?{ld|q5&IEjf(RJIvx1F~Lbmg1A74LWj47yQHQ z(2CW4k|f#{h@B;OO7_mnsJ<7!mM>KtU>TUY!4ly?&*oa^z+X?|Owe_mnMkU6P85j#8XC+|#*iqI(uy3OW9+NI_M+ry9nDM|x!I=71@nIt zA2CMEb!#H$M^(TTyA1zKAvnJU#IRc?$^0lQbLjeY@MhPPE9sR@@ziQy?@vAAfpz31 z;<5NgRFsp!P3{4tr+pmzFKKddrZik8X@0Ig zwO`q~$P=X-@IRZC3p%{~Y_toPPZmR*{LW8`xjB9M#gsvdN!L=L?PO#XHS<@S!;9W& z`}_7v)7?>^a&y(H)TZCk$ZK#w?{@i($H9u(wBgp&7h?gOMgQn+dX<%#W1(vHArA+g z`dO=~EnE(-m$p-KMKSS@|6+M5Y#lD}rHk=|y*5AbeA~;ICI5zg9*w72t%#m6&*`zsXqFXTy?yyW?oG>81G z6gji1sBNq(yR_3rT@&kPJXEC5pMdgsX!7>jMn^{sBH6p1T$u`O4}n< zg%sqfDm2mS0AYpkMLnnM$n4iMS1Jshzye_fn{ zfgr{Dj?0#ZwR-xsAxJ)}{RuVxljVsQT zPm2wYj@e0r^N?8s;f}vswn-fa`-{;Bbg7Vqc5b1;b%y?Dqf5oR50;Th!81t;y~V_| zp5)b({^Uk>($h&Q7)+L7&YCW4Bo*feH3vf*2qrhW#q?FxNQ@k6{cSqM|0FNSecLAn zzMy-^NntWBR*SMzmp9iF(uoMq$S+eHbd(>OQSr@UAsORGEi<@dz+(i`hx`dX7X93# z&zfDIVT~Gk^&s#xp=%bLK-X|?E3EqhojMuvqATU3^fJoB|6Cr>SE|Hp-LKA1N#Fqj zEtw)9)z8=xnAAv&PfD|5&ULAKhl@JaQGFO&TN(FFZ2rabgP`Bsk_60}6IO9@ra&{a z6Bv?9IiJ*&OtKJ=GaM{R=Ql6Xr-cLKU8?+bs$L*%v8~TLV0CFulWS>4eD`h$YuRS* zXf$%2HOsdw|GhM!>{&i~$9};i6dAKWZmcV1)h^!+#aYtYJA24u$ub%oi;s2cJ2>ub z=R04WaLlhXbZm7iN7>8*WkW5C<{`bi0W>%Pi?@Y%^^T+)P@63Hewr`x0N$Ikc> za&$(ozb&N%{>^60@I&tCFjfh}MdH4th<{b=A5I>rEm?NkNB?NfpAGv#DH3B%V)T` zTWxV1cS+7C+$XQ66l=@5k$)dYr+35V!WIA2i}5FA(^u2$ShnmlLwG{@(yRK1$a(h@ zTfM)oS+b8}zrM26nBz5MuZa}iX(Wz~pZlILTY8~4qNnHV!3MX}Sq0`a0-f1sOPctu z?qB^2lAY7X#w55AdQ6BD?d9w+BlOMktbWM65TPp%2Y})?3|g$Qtid>wLD@xqRr`_p z)nmD)Xl4f$TJiPKY9Z^5T1$>|6QHgJz!f>V*i7rSlyz3?|?tttzBR0g^I5=5*60b(uF)mjDkOgfB0wY zQY`u{8TSv##7!?Lx|SfDm%Rw%Ss`DEEunMIZBf=>wafdE|KR_eJ+MFbQ%K$^ij?$z z+rCsy{_ywUcxfRWS2TC*hcBZ}@sl89Gk47d_)qnxjg$zQev5I$f3$r+F1CGEPNxlD z%b)WlpSwq%aqR^;(SjLQG~@9j!x;9wT#O zB>n}OvUmGmfA=Q_f$4g17ip;|OhKvD(M5*(YKOiJcLB5peE;o5wH@1|I)(N^1=yy- zyp+SG0LId_F%-EmBDLXoVA1(NkX%o!%tIg-2;pyc_yw;dE?hrJ#0e)lE}zLxk2TKV zB+?c{J0|Sz+@n>?tT{T#*Ax|&8D~nG+AR+WD&fQahURJNn z?@91KNyWyP1eI}sJB@OnKdj4?Y}w8aLg>b1h|CT8gmQolW&mS4PW{8>H!*LF_ zgW!qd_o;|?LX2K;GbChDq2Nw5~ipfwM)1Joj51mrON`&2MCFTzl67&@UnXEyIq zAlsOUhs#xl`~=gjEu>2%?ahCZz#40b3I*0=e!b6paE4CUQ$K*XEcbN~PoT$0C_K|% zGQ!YiR#=g}ya<~!;u<;N1oqZ<{Mv&$)&pS_P0`K$P+BcNn~})~YR$H0ORTAZRy${S8Np*z;p9R(>$z|P!~YQ}0RNjv5#b%}T4)Tr zE=z7l`hI~E3N!LfWr$p#>GFsSxMG;ROg-Kxly6zMz0&X7v-OIi#hGLlRnJvEpr_@1Z)_{Oh!y9>x6-jR9b1MQ10?*@fv~tZqU~kTU}J82}?j%D!={@I7sqi8M^%6454Q3 z@7Xy`h8|d;MGnWbCu?F$s>SwD@?Xx8iwmui1^hO`7HyOl|NbaU4*4!_K0E8Ajrogv zeM;B_t$?JRa0FYA)K39;#AM9c4&Zr8Y0IvC$Gn9GNhT(3W_GI!Uq0G)9rWbD8puD%C;c zAcO-Z4DcHVXY2aYLang;dL6e#x+UNKdppL2@m%b^1!?1*RK=E5jC`2KB8@{=H%-mP zVwuQo7fx1GOI(~*iGuuFj*=A?M9`rKZ0$4*|E8mW#d%VlZ-K^Y;@HW5@Nt(5Gt|p6 zq?V1m6c9V%V5s2m7z9e=oLI$k;Xqv@F?^Ul#r0F)P_vRI@G-Fp6c4U}Q%Xh$8kA;) z3Q{-P5u8<(dJg8#+Hw&Gp*LOym9e>c*2hP=DZT0%{q*~g;j#`w9*QjuT-H7>YRDAx z%LWUHf-J1r$iYSx*h*)RO=L z2@u)Ln%}*X&K)QJghz_@4(;ag?9rciN*v}foKbSW7a+AWhzg(=SL>Mpvdz-!+J-s% zAAgpj3QWc~+u2MweJ*T7=kxji?DqVcC7MT8MJ~U;J6Rg8SEDy8SO?OL)UPK)HhMMl zt0M54#<1fw@|&2p-50yhDe{`yDiUygY-p7M(`QELLf6k5f8@6L0ktr%|9rEy1#pc^ zt9;y^k`N!e3p3aoI+S+L#zWvxYe>AP&ir}UV08pcT>t6ho+DvZYc_d_Xl9F5dc*>`dGt?lsj5sFXwo8 zr`XD;@65vXPxgLDg~Qu+hax|P8uSRRsIa+gJ`Z-pdMEnEbMR+z&=Xfxz_F6&zZ&cZlMx2$$ud{A8f<9Xvt1#v zoH1!GDbyMSQ>e) zxS84z_&dLjxf(h$KCxg9xb?L}L-ReS|JtDa{0NBUBIowetXa6jGp`ignPt2V*7|f> z)}>jbWJMx^G@cc>e@3a!hVZ3ehQm@p?wjO(e1EpfEvV{?h3aeuu_}H|nAsza$QC-S z+=3#Ew1a?#Oi}8}EYXlhbcS2ToL{&V1Zo#dlS+5Zt(L_@JB>6-m~+9e?^3sHqC_fx zG#WTyo6j`yGyEXmOURa&Y6n(0uLP=*t#@SCwIrR*;UyXN$~EK+l{zG5^sW;8Wv|u7 zX9IE&_Fl=&AUO+hDvqt9n(p{?#-D#IgTR;jjNv)yy<18{XmXSPb&6-iHY#!IZD2yM z-YE+a*^y~T@JL28rMwmvQsq3VHjFomYKETwr3duF>e7mev*FXo&r}zvs~sG@wYCIo zSxc#c1ctAG0?P z$OK+Y@~rC;FV5=8&s6pLwLu^I%4``YUg{8FnxD0aT(H9o`^~zr<;8?-9?$Lu*M<1m z4rZ8)NqeXMFyoIk;$KIP&fw)`%5|polo4~VbJP{#Qwwh3ow^L9SyFe3??`G&=kZi3FE^0*l^yt+GjiXYXcfh0{6!p;xsei zS+1kDYy26)tXFUJ(^zF~)Oo}(U#8tYBX+c)xz*m=j0BG3#kSaynRiumBlz|$$id%E zzc>tWTM|L+TyWBGJebla8VJCP%kT3kIXWe49Q=D#VDQo?gEzJG8D{@7c<0rI69k>( zvwjfdOA|mHWsrII?Q!=8g7#&|td^|p$J};}KbG5))tYOiwT{Acs`gNLa8|4I>W;AC zO4!bZn8ne(@X_W*-x9R5K~XvX1<54JIF06U&cOuJbN}5>b^F!KnmbjEUlCW#y$THO z(Lb|IlPx5pAGZn}Z2v9Yg$6nsXj#_!CN@Ov$2$|0(>D?uuHkiBjLe`020Q%H_*yL5 zIKS;YmG}DNwkLn!%^m%K){K%Aol%f(FkVi}cxn8;)R+&jy%H6**j3movM9$)KK+U7 zCLGCraeS`Sw6ej6f5=hOU1EKKYcM~UF&1T zvPXHPu2+-|UicJWr40H#uOep1RKb<+C&yiP1xMlVc%&Z_iBPr`j4p3~|ji z;?#3c>m-)U)Aiu-!l+Yp{DOiwK#EH>5hTLkYIP$rzejH=5Gc7SrOwQd-XSz#$F3yo za}0Nj=Zl`xkM4Q!im|5%W0uZz4x}QYHE@bxLef(*byXA%k86v`Foa-~DPjr;& zCDiXouvWd8guUB4aTB^N->%Ws_v+;$h(9u72~Axo4>ayOSwg_!w)d7_yA!cG=__7y zg_K9*MRGl~9uyjpsV`Th3+@ATz=#1m5&EXq`-*ayB<8;}M2(>8jY}mcryNDjcI# z9lS;2*744i>egvZ)mq2^)N3MYYLc!FNS-pZ*_ldf-T}TB@G_;#Fp1Pq5Kh!SvY{j4 zUkCUFk_JPoqXh_pejKo{0I>OcObeLYl|>Y`ACrEl22(#|Ue_Wa?PR#ESUN{jI83@f z92?@sXFj7c{0-1BR!p&1mE(Od8f5W`iT2BK^bp-iUh?-HM0I!sIthqKle|7=wv;Pd zjKZkMI5o1ljq13F$Q;5*$ofsv;U;vY`dMFVtUAG_6`k*$g5Xzy)|U^4dO_T`q%Mqz zhV4X{+Htxn41tJV)V1$6)b48I+MptNTMww zLM$D!m@o&9@HfasZBH_vREGt55IAxX-V5-+ywH^M2~E+uCavz^oRM|VFIf=pOgoo@ zOosTtpuDhdwQN8o$qC%}q{o2N35Kf1|7%_?M=h&^49DlY$gXbU)J?%hTFgX+Fdj0H zgR_dUOYG@kc!FB-V4I7RuyR{(Xx=GR6&@Im&6O|6di@CtoS2jH+8P-P%MU<&-4lZA`s6VYAGJgd}ft9p}~A+C4=Ru&KDuZp`$VMeHW4YwIVdogFem%@i7@rHnPty=Dy9Uqk$kY3{QiVS~i40l; zmNhq%+ysKU>_E8a9%_z+w+4jk@-{jm)eh>`uqXI4IHwqH^&2tz9>U$1nay@XoFZ8J z)1;J+AevV>&6Qn0GrtnI9#_3qbV1iDwG4hPT8k#O6-WJ|-au4Knwx89@(kI3w!^J$qCBV*PB5Vw&lwW( zJSO7mVgf%AHSg9p&u=7|mWH2`Lf>JwoT;?L0b0;3T4HNkmh^M31thPK@-Q{ZUep`- z@}%DR2awFhytzMn2tH&0rO7cfUe{sv5Gk=97@J1hvs&xRhVcw*UR__SC2boeM|x_;c^Q$lK`W5feF5a0CX9&6d=zHGm$I(qtz~kT0J#(0} z>B^6`(1N#_%e~*-1?T$s+|@%?%k9*4G}F!<-()tGD}Cyf^ML;2uIUeZ^WAe)C8&~G zkeC{yDTH0E%*9_d*x$XbkF2k+Znm$vpxex@I8#_Mxgy`kyT2>B-vhzF(myfryh&oU zz*T%;oFa29WME=5dK?ptWx*?qUuYh4aIt|Ski1XrCgunFfV*S8l10MyW;*}o;G8eE z=u6#Uf5$9+AYI>}GVKr+`OrScr>ohtBTtIX`+olu4b+I?PhD$6Lr(1oV(s&+!zh%) zXoVf9g~OEnZE2gsBeTkx-FZ>SsDyt%)of%h)Q|j|8Hwl`q5d&KMmc)x+s*XR223Hq z^0&SHutO|pO6!+W+};L`7cJ*$lk&r0Yhr zgy(SgPTEp8{qYG)Rz0%=(;pGfsk}EKDj2j0@htm_2>iOra`@RX6vB!I{fFSNw#41 zGtu6pchmW1_8a0D63O`+^cMZe$yJ-O8fP2qYJV{(DMH8lQ`|RaZ#E^dwHQ*53dIXe zzl3RG2Ny_LM-vbrTT|`Qe)pT(oeQs~e%UT&NPp$kNf*r8WuqlQrO@Q$caFnDXSw*8 zF@Jrk5XnzTq=}(N66e>%m>zcqNQrAmNe*8lQbT>;<~W z97N~%6&}|Hu3$z1eMj2m=1o1&ARe|dEf_jFk1Jo1V`(D!i?#7%9m{QXV$c}XWpti8 zCfkR%!C@$Xl4cY_XYCq7JarTzmi2rP|NKSB5-Z)KX_rhn**fnFyV2bRlceC~gVS;0 z8>x~hX%Gocvl3MRDfaAf7NvPABy zu3c(ipWa$`WdBhKfhN2A?HiS)zLR)dd>yA$h#`nNk&Ud%&kGOa)JJjgKMxXlpM7Ym zYE_vTyiDWp-igGj1|Dv1T>alNgHsR!*Nk&ww0Nm%3Fs_#x>3gg@Y8*T^M)=e<|r6f z&$tU-S+f7SMsm^enH=-ihx*Z^Sp<(7v_&i(!WBMXl1Z6cjKAjhiG3L74^@N)HAa8sc9JSLUBF}{^fV2WbpCXD~xJ4(5nAdE>e*BNbsy;t^64u@-VF(6 z?4w?Ct5GZ2;RMAjCrER=E{0fxHy%w-rl6nBXP4QD>woO$BP3&*zt@Ur2RP>C z(Zb{?mC-mp%tlj(@mBhqEFHqw`iN}%=r`csw|qaL3$<}SY~D->ezhcq|PN-yPrB=G5^{9Dn7xeH~bC)Zy6PN#4&%~F^HTFcTid0$xGw=pWYPK(nI!+o0& zgfw(rC^dBgpLs918sbKLYKuz8T~6fbzE`EEJHWPWE|DTtB(+%CZZ$x&)6YI`@(*Ms zev~{^lrwZ6tgn|^_}}`O4@c)Dyr-nc5QXrI$Npy>?!pfcT=|M51FXMJl7qG16y{nB zuUgtz)@r}mViiJ>g#3hJPnv8fd|b97gvrJC>>CM#l1Q@>TIcET6o<#JBjC`*Ge zLKS5CF2WS|Ea{|H8AsQDAz5o0rxFO&v}k<+nYC=;?*5T)C~{F~)dNNjJdzK^VR^<@ zI&d&QQZ<3OaNRVQ_WJD9aXR&w-}hBkbwI^?M=sK`d@vz)=vW%$l`2oS3k-DV!Y6E4 zxhr0P?MvfA+7&J9O#C=Bis^=$9cRn|J7(fSQDJ7+E0jh?ZPs~)Nzv--h@He71|7Mt zDa`}^xHk|RH@8< z3lad(9d+53I*?&(S~0j%&%?ZGS|ShTCS)jeIt=&G`9AZ6ij0qnf945_#~4d_cjEA@ zCpsDm*_EDRgQmry1|lKrhNRyTmZNuCG@01kl=T=jzj)l~b|UF2Ub89^4V0E{epj|= z0IYt5PHST;DFLz1@INx8GhtffgSS~3X-Uvk2_>1i2iWwu#bzp}SY3LRb(=Kr&nh{E zfNnJRGv!?en#;z;3+4F+PF@E4&aTmcXc}1>v|o z6B$IUL#^;=tZ5>ubHY`2RR_;(t>1ET^OI?08XM4{QK-jJjtp0O72CX6fBui1*$8ee zc2?i$Z`2Z-fFD&n?FMYMK1_BfmUWUD#CP2sH%azrpr}l1&&V+(7T<0p^H^SLvIkq5Q*4OIvy46LEoz zIgT&dK8Vak0(%%6VnjQW2v&*X1LfW~q{y&Z3%vmWbM-Ljy=;U|_V(Cn+yc+m7%!^+C7MtGA{rrq z)&}Ks3#rD_6`B77{B4NbA8K^GYUQ!Hi>%?6lM1@e^EdPRpa6$p)Q)Nz>TKRoK00=H3 zIu#-<>{oOUtil=>nnU(5DS3Ox6}%S)LNlI0^Esw>)SU7W^a~{v304OBZ>@?RR|j>l z_$(ihbN9q#JCYeP#3QZfKC9>mP7&=Hn>**a69a8N03njOj%n9HK0XOH-JTq*UM%s> z(n=n{$@f-W{!Ek7tl`2|N-7NS#k^n}VFPkeC@lrgP0>45C#738#@#spx~p)?%H< z^;dc{H_9S$69OarBTZnDKJAfPs;OX5Qg&bnRgbx1907rk6R>h+q(-A5%^iR@JPSrsp5idmMm(iJQwVVJk zH8ONLa?vWK$5ou@?5w`gd586bR^gJyZe$4p!P~?|qdPo*`{FDmhXF$$F z-8d~iLNC5jE8chU{=-&$4RtB$$t@YXE=CZPy-h56hf#`TUV>;|iX2=5s4v+SlAoV1 zmBvH!Mb9K;&uK!+z&y<$RWAd%l#!j4MLw1RG0GX(%jtp$+-Q;6qRRChkz1BrdBg*F z^YK5DR0xSz@YjRITw}FeD#Xu{WiS#1&maDy}x45-Y*eIcO`D>iLyA>{W5o zm4@}&sQ;5qii&`SApS1we;{!FC;#TH&5HC2`2Wo3Y?NaE9|X=v;jaH1fg|v{@eP49 z+gtL#5I8XtZwMSox`Ho4n!-3q@C|NDV}fv3t_AVZEqfh<_dVsj{0P-}PkY_B?6_#0P?C(Zr9`7v{+2EywuL4o$}|u zg`rOi7(pLiplN2?W-az)KN;s=_{}=fI!O-)18HqO>_pWG6+@Bok4Seo9Of+V?_c(> zyT82`WJ?HqO(avu(*KW)dB+n?={C!YWgTrKWX40W#8+@U!7A8RDwfXt&SBZs{+mC- zjw$r8oJ@)Z6}X4aP_4Qr#jH>AP3OfiQaP5xf#{uwh_73%h6SSxM2RVp+w(DTiD6*ZQwoD9r+oZAIzEfb%ZLdV=ZpD~VMMfw(Qb z)di!bpBWS0swHuuLVoMoIzHv=a~VYV)7F7Mn3OHulP=e_ytR)+)1#%dkzC%$zv>mK zMCJ&rJcQC}@BG=r0(bov$MeixXs`0J6Up&gr>sTvpo(=1a%Vu&Ewy0dPLr_j*BZGnP?>1~&zO$JteO+N|=*3TWD_-iQ){9+8TRutUqdw5?G4LT+E8l6_St5vy*sKq#Re(^j1$Mktv zCg5z^F~l?d8jjw}+uSgcFOKxSf>-Q)6<@5Uhr#>A!E}JObbA5@vrGB?F1yxq7B*(m ze}1Z;6(tj?lZ&rTNs#gXp)Vp)h7_N6sXsIh<<d%_8u3!wxE{I!x{oCN;Vw)=x#{4eQlTTpr{PvW($jI+FfRo0)5xO3cohIp zUFD()0AouOu||iG7McR1`R&jGv&QC@iv!}Trah|g(e%u-~q4C8b)~D#xz8Y#fq$_|_sdl8KpJ(it9IEGv+1XWg znaPetGsYmT6HrMm6N_2bZGt}rHqhllo|qXTQbVDS#9j$}H*-=ZaN5-iSR@X((r};L zIQ#1zn>Zl{@+$h0*Nu@Sj-+~ChM?)em!^dH%xu1(5elisl=2cU5S76EW3nE9Q$r_ zKUwQQVdfmfBo!R?d zRM-+*gnl2u(dJ-^mjfkf7`+StEo%ExeI|RgPxiV#I}m3YJTVu)t^Znwifnh3Mb#&o zY-UjVNF~&mwfNZsXAvq)a`P_K_2CE_qrtoT2vjP(_NK4QT8`fZja>7kd|9B~oV#_D zFZlcljs6zdO&C*O;6KKj-B-k0X-W#r01Ck-cwcJj4uX3t`j+OQ6@}KXe>d>I`7)Fg zKyBS9VE+xZw-reHiwbe+!>YKzrbS0YTzHNo_!M0?VZyo5GZGFK52M$ey7KrOnhklY z1L8OjrK~k$w6N)~F46cJ>jidJ%^?t_;*P~5tDnCeB~S(?E@E8zTX}^tv^2B*y1BGU zL+qau;$RzTw82mq%8D3=0p?2RQZw%gyt33mmcO-uWWGge>LL%i~B*-^d?Ua3ZqZ+{ zXo17_$$jz<5#G8#b^nsdFFJ@kO@t*p=DO{LypH_3l&FDS!*&?0tvbW~ldgk9dX$)k!$BCoJNA2a1GMv!-_xQP%w?#6l=g_@^xUMcRTdq zJ5*OcTu~A74VpmF9euwV#{7Dp$?TF*)x#LdoTQZjywl6#^ov((#d6K%!vw>Sl%Q7+ zE~xfWfJF-jAR_%5JbYD5r2~G6oK71Lb$%282eIz;=>I|E<0)h46QLGR^b_2Hd#=Z# z3fU6{MvtsnD;emKANWyCsGdG%NzqG0pFpsgf+cKnJ;ad8Y_l1b-C>Z3babc)6DPPL z)`8#PV^^ZhI9PHgkDe8&OpO{am5XNYjg@Ec6C!~qm@=v+?4*d?@dR(!4>vbsG$G+o zjDm}JrwR19h^VkNcL}qzf#kgkGs-BD6GQTulFRNH=kC%3Vk}1!bbt@a^^;Uc=D zqH;5r{I`@#mMHz&MOcoWP{)!txdNGR$<<;lnO#r13(An{E=hnKpjPmDp!_g10PfC{=C-)RO7mjuaLifu$j@ftfx0mj>S?yy4u>LU&C zEJQChX>=+=m6S_((nY#AN=hwE_U^;fiWQ)zA}q3SMl^1X&`rBOi=#5baU#!gBG%L# z8l(!+RLfq;%V9YMh%&{20{QIoQ|ic=>!zcLP~a}l)r2H94(c4MF<^h6YDRGYJU(ly zBDDfc+lX2leO3yI%W8SY(KKck*H`A%Qd0nl4ezU+0;jzEUzEL7P+S4Gwu!sDYj6ne z?(Xi|xVyVFuHDeMHtuc#f?EjgNpL4Xf+u14&VOd={8LjiH8=Ze-|U;Ne%D&>^BC4< zy;Lt~Cq4sgQ#T5rKWb><*s9)6N(9!6|2zobDc05W)MXmS1Z?r3LK55R&_YbSwwWz- zSlt7=>sJV?$a1R~g}Kf~9Vt(Bq}!M$j8Go}@rI`e-JU>SXT;9DVgWPUXhyngNsYqy zx*k(Zqw9HOd1xhyI(ytr)|vGqFZCvMO=oD(VHJ{0ym0pJXj(FKeA3Fb!0=I))Vi&@ zx8CNzB88bF5luFsNV7GarFpr>wdl$Dxi2l4sx=(>EngU0)lXV*lWWP)TZ!4i2xjSA zN!oynZJsJn#$>2>QXA8S7`v$r2RS$OcI@SO{dHdx|8|qKPx-J)yKsLywPyOgn?myC(*))!b1Mvcr*WdU@qnP@4$Td-+@{1e+Fjx z$^Qgq#P`6g_fq)IjJ3GOoeCbZT3B1eELd=y$SZX3Z@*A@R&QoINbU_=SU33{78T7M z7!;ELWQ~J~OiW8BOHRqi0TE@Tg7fo}Aq6Grd8HMg^2+MOqMG^`XhXAqQ%k#BT}QWL zTTj1d#K6!XVe#;oV&C}G#HZ=Gna}fIWhWO`1Yy@VHn&!HM3#4duzkmci$^~~3qH+0 zIYzq}Wxm1qb#?apTI?PM?sWa+-~Ro^2b4Zt;_8uc}8WBNS2T6I(VfPipgNz_|7s%qmY(|m&juv+J*49hmu zg!SooT=k(bzV$cHIN@b?tXY@uJKwV~pvkg7c>1nN@Y&27Ba)-ys^6H!bTSA(_rng! z?EwIvPWQn?*yRKb;R2K`zPe+ShRa_)KmXHTce~tgPGN(`%Hx|G+s3MP;O@o=jU*Px zy|qFzlj|4h7u{u%iqna7`wum@!DOE{;(}5`0cDL8&WRHi;uBOeoR%!~bOJH$Z4d4vbe8 z%ywIs7D5e+a+1Rjz=A04NONXYR*(@#XOy{w41%}9x$(wHj1#&250Mq{YJX&JWJ06$ zS+pUCvH2X+2fXoaPxJ}3pwn&ObtbSd@zR)yA^RM729?(E7B~vL>3O1r{C4U+LdaFl zfEb0>k}ikGoHNpZUZ1O>8RUFH1S#;0j^JY0G~zvR492?el`i{V53r*&^iAa+)tPj| zul8(9#eWn5%P6Xng6nFivrwz7ZK3c+K=2n53uBluVtbS_0e;=WxHMm8_qQnxAvRQY zdA8a}0{dKt65`*WRHg zsAlp9jGkkgc` zY)y9Df;0mJjq@)({*ERkR+2@zVDcS30U36w&W9o* z=O-AYpvdlt>Q9lTv02gFgXy-`zYk&*w+oTdraMD+*~lRAF|t3-=3x_SA2X~^A{@)9 zfAehc9T_W725+nt)#czpk5YK|lfM1^-A-2y{OWzmV*U0nesK1AGAcw@+J`Qdk9~St z?2oaqbv}At-+Yz-u_S?ADz|vpC zxkS%kxbayA354xmScVmtSm?A;1I2Y1#tg`Nj7e58l&POag$OmULU=JqY48J;e(xg6 z0_KVcswTlx%6P`_zXBz49dvuJ?%DhewtJySiV_xex!CBIT=&(DdLM_0Y!40DMfv28 zR+oY*%PRBm?v%{=m9ne#^p{4xPTu8YoC%->u+~aYtjN2_yxL z^fCx2PRi-<*Tht@eGw;h7*)^2_CdM&07v{XF-OoAnpZ&~rsS9r)I(SCbTe~m(b*Dx zOfRsdjKPzd2w79(PyWZyH^hMQ(XM%YEvz5r$mmL;CwZ zR?ZM29v^pd{lR@{#cU(3%)X>LGuW>603cz_3zs>Jp=a;o6$-mS|0(XYwh$MdXDpMP zts52j($1N)Wj#GQAFOCTtaV)*$fih`MqbC(ygFjT#6hjreN|;_DVv=6dHOQB`TV}pwHFx7hPkL}!?IOz_jK9~` zz}--l3XC2``csq+XXGTd@lo!6(6LG1QnH#DcK4(!{Olo;m7}fsq`p z5F24yncMSlP<({ut_+(YOJuWWVFLOdT>Ol?!XrQ1#|bT?ZAInf|Fsr6@!7;y2<%Zm zagJqo9KpuS&WoI{4X#iaTkw+%(h}ni?8fZsT{%#K_&1Ta_>@NfZ77UeJOK}VnS;_p zM%)a5g^%JMfM@BOU!wr73L;dE~60NYt5kTwy_|J|pm98R65e1{{Xg$n$S7 zV{MHmWb_6$qn}ANWA0mHR9{YCGIc~diH`FYQN%1BMY@~gGC4p9GJdJ4i-%Tcq{e@D zjH$QAep_9Me}5qkWvvUwH(SUuj=u^;Ika%ra2Ag%AcIrDLjq9&GUXHX83fPMEI&S# zH2hV;I=w>BzsyhV3~1!z#M+S=yhtV1bI!o(`+^ux)$3K)p}p8@aT1f-Tv5LE$yMD& zl990mm56cVTof^m@L^K1(MQkJVC()3-}p`ETNy~wY$J7_snbKvt6ljbHA=V(XOn|o zh=;+F8IKdkZ^yCc(`xA?S&6*v!G*jtL+2p_%_rpZd1}Soyrxeap%9rosj4z$=K!i7=9ks3->d}+KA2biNoc7U3 z+7J}ks@4{;x1-21PvF;}SyCTa6E8QQq3d)YhFaEpdsvKFfDe2`y-8%iZefIYkAhK& zzHIXNUXie5M=0_P_O|!OnAtkvpKMG-+cAlBghAb}3j6qhIE5#2TX~ z-YVTz>x67?x8YOBviLmFDM#vr1}glzQSlR6B7`aDs> zOCChD{^N4*{smhlf8&xjAkb+z3J^on4~l_!MZN|EhOF3AeD@|8Hbcpu3LtTQ2` zlerd^HOit@Z6WHA=7yK*mJ5*QmT!!fwl<226|}|1Nr{eEEqF?`p8^c)#q>W>nUO>* z;3w?YIE-W`Ewrf?dGYEplRca|)d&cVjPq{(7J3QP*!2(J?o3apPP{e*^u+pY<0o}+ zV<|UI zGb3Xq20dbZQTyqfhw^AK2S4H?Goo?{oN2#1Ed!c7-%R@i17&sjJ7c~xCZgWBV7t^P zNW3IIEJi{^)V)i)Zt@pJps7HzV*r19uIqr2G-|K^FM6OyPimP@dJZWIb%N-mW57HV zNWI~9nXRMVozoTMc!ey1hZ9o+A$np4g|g@%^vH+N?@}RE65gU(eb7;WeJsu< z3~|;IHvonGaYA!6NHV>$a3>+L1CsZn+YjRdPGPPr0uIiWR*`ls0VoFq(;3%o_~zdT7(Gb-V0b_o@k_=e<`s8>X|~KfJ3^_L!^?Y9Act_wT(}p{9uB1?)d(O?Vb|W1kBpzKG5f6A z91W`F1vKzQS)Jhs7t1f55MO%#gEQNl@V|P7Z`bDJv3S+dhgzY< zaY4ABC&cKTs^?2X8&R2)oS2toC{GoPz*8!@NDqr z-ul4f69)4BYw4ZJ&p>-*4R4f+s% z%K=hQ;pF>r*n1ne6_Znr8(!_=;LmX8O&S+Xpe{!5_Yx3|HK_Wt*9~f#`?##&O7~HNoQ8l^?Ed*J;?6l?H&bU-UT(MO5Nt@-Dlu;imYn#cDMgm{PnG5{U`sW zq((E5-YoQ72zn#=MlWcVb)K*f#-%tR5?A}RgA&}=iCUu-QlN9uS3};`by82Y-5QbK z7|m5zj-J?8U;EWtZ&=kdd8&Wp{gSp@AEr#7-axyb6zdBc<^uU(IL+XS3;e6e;D%}0 zX8$0E=ituk-~z&@eN(t^qMtTRKOLJ6o)&ys>i={}K6w55X%A=UZX5GAqv_D9=g<>5 z=1c$3*RMnW3NTb>VJFb?LXR^cf{2H{iXNe#QSXGU1;m&>%Pj5qzl1ja^je?(OK2l`JMbT& z4e$c@zl1jQ-2V~U0RA(aXqc*f-{z08zHjr}-?#a}Zqn`FZ@NV_nnP@P`oq(Ue!WFn zn?=ROi3Uo#keeVxX1=A2VZa)~(9>n5s^a$D#32I0$25lq40posjI)<$OZ`#sj11JH%lbo2KW z>9ozQp?R(~s*8-&FS8sZ+r=d~fp4;>Ed8rZbY;TkHl*?t#MNM4VLdJ5`3mC9>Tx*w zyvr8&6E248Ym$60@fj*?hNy!3H22-;G#8WQni((hiCBqo{KtWVU-GjW3J$AD<*rLe z&Dt`+q8g&PZ^f#P#O?u>o0@y=wKceBWYF0KIg&O zjq>MY*wt(***Xg+t=Yo7s zDHADLKLk-fp+HpiykcwolXys@3dy-%WCM*9W=w+%?--ehE8q@tyz?zg>;nL-DCZ## zeJwxguto0A8?nbtEb+YWXGSpi(46xtVu(f_QcpQ5vKwlcq|3HE?AMNu~)0EQ~lZdepWndOoRvP zZkQ52Ce@yc$4CpL8LmatRJL*+FN)&6r^%RM?YB!Md!7N?jX8yKO%j6uR}+GXJFW2l z+-bPUcWOb^z|ng--i#0REbTExyRJM5IA3;r79`X0xiG2PF-AZ)go*9hi*%x{@4AO+ z??ob@fNtCPH~U(Bj_xk{N_`JT{tk?F(e*_Y3^7CZm+OM2+F#|<9$M;zCaf8LlOf%6 z$hLoB{cRrH0(X$&2R)Nzd&15#LJbXU+vE&Beb{=#v-#)Zo+Ub6StafAQGhsuIz`~r zoP7QPkw8>{=tAuR-1RB6KheIx^xTY3B%jEw0xZAr9m~kBr|oJ#@!4|G?LP=85jbJTaOa92 zW&d=(HG>b>EK#PATK-MX`lI7pjl%WxBfu>HezA?3WZ6>zf6Gg%%xq8b+)GpyEm&vx zeEqi+59?lr=*yX1Dl2m@O4vCZ>k4O97%n)d-TM`eW7HIVsJhO%(bJY}s_duhsrW=H ztcGZvCGK{${z7g!mfIq<`SG8RnG0`&T?Vv72T+=zPm80t9 zPXCfCqBm^$cE)b7cF8Afnm-ZAFoT8DYBap(jM^QXj};6Gul}{hi(F9zlF(1;TePfK zQ_yd^ZH}Y&HNZGaioV&LFEvA{y{P3+{rS0Q=dhsOtpE?{O9P_JYFoT+#awvt5DiPu0}$04ZwE%M#toGQz4WQ_zvZ6=I>=DLyb0l_6s>mrYd~j)B~!Y55GX)NS=CY& zMwj-x88B1BQ#w5`iL>?+xx|b@Z9S2Ap7-b1Q8K=_IG6gTJQaB~cg|WdAqWUtceI{6 zJV2pXZ_&{Q(wnUki+|WamE5Zmy8^fj80oLo2{udBHrPpvm7JxejFD>`Mog0@*k-y{ zfl*uhBaFlmklB1Nc9QfpbvD?7JzO99S{rOq4xmW5=!{*STJAowM`y`ZYVzl%4g~51 zmh%NN;x3Lu%Deu@0X|HAHL?=pa|C1MqK}teDF4l%r#oW_+PeKpW1_ z5bI`%_4FuPqL?`wR?Qd8Hw}d=9$DfSQ%AUfuL9f0`D|i65yb)}yOHp91_r1PRN#f6g2LHU1GFvcCb#Nfg@KR+(F*{F=_)8b{m6aoxis2=NFl% z6SxYmJW6aQ$49$XpfC7bEq)D-7Lw#GL*u6|yd1KD41z0KI4%){f{w_xert}IKT<#6ciXIt(kmUwQ}kLbGecJ?e`G#^_jaOI>IOr5-8lcc zH&kP4k%KHq(y2CdqGRG`h#dB$Ue)4kr_WEo1v^*Ads~qYn$niv8fd!Ks~KPYT0W+B zy7|spyq*sabo`cQIxXXy!OK0UvMj})c{04?{#K4}CYYA;oqRypS96ya+FfshpV;9P zNkrrNvwb!{tu`~DS-bt8`|qKrmLonu;98#vN0$SCT2Hg{%ZQ!E4)1nj|wY_}q{x5T-KgXuxV~zKp1`0eJw$decB*IRp5-4~`EXgnFs>1gI znnT=5OrC@OhQ3i{c${2f=Vj>0ML4(9sUNZgt=p|Kq9fQ@e>S8g8h4CDjN)pZagce;v~BYXYq5>OoK!-n)}SB&pbL70SgT*R z+9)Ezt>kF98+vM-(EUU9*@oIvb$cOxj_O6^ndn65@sm*M5oqp$+xO;?Nr+@@Q3JIE zacIRU@x(@z#^nshef`C~Rw@m)3MciHq=SvuCx~MyRl#yFQgn=6KJ=4TLS`R{Z^V^# zE*CYi4+SCuje%UwBp>nV18<2FNPDc^g(CX9uyV+*dLL$!;auE9>K4dJ)u-yC1+1!yZ_c+-)us|B4gvUqcJ?=lT$=Vl2S9XSb>Sz zxp~YW^bAOG34TFgX=N2oc?InM?%C++?du;H{4_K~UIZP>tw9?dpGld7nSR%%PA)92 z1}(2`CeN>IeY4y7z8|=EaO`??a{hyC_u{9@#?3E_-w%h6&tCH{f0h1_AfOO@wW5(m zLPE#VW4@76A7^Vk&7F z!+|+nYI`qfuO{lBXmw*HAsN4}(C@a}S1|V03pAS#d2r<9;E)VQeomnN5RUU?wmiY3Q^nc#UVkwyZh z{fYGPqE8JIDR1m@BPDrAE3@r6{OD1hq?H#PrGgyIBRS*Cr*rVTCi255(k2(vINJh_ zlMg5lt>rv4#&V3Uf@{nCblQ5M`A#YhJLvMDu9GY$yseBRIXJ^IHr_xQp_G%ZKua23ZRjoRRNRENZsFmk2B|Q-9S=ANXJuWz z&<}u1E{*z(6ii;zE>F7B{Psdga_Z5q?Pm#8b+M{;DvfqJ%EfsVab^Um_+y^FwO&?`|Q#67u-d?Bp}mp#Kys=T)9vk~Lva{flx zP3#B~)8&mmsO~%}%eO7=YD^IHypjUb%=VW2bYm*oD}V&%_$59|_ZrzR4T zyMamR_unj!gwoZD<4ZCTjp{}w?#I`cF(Jq1 zw~mN?(NRr`?s$-hsRvFlqLL?#$TA@nQ>O0XN7GF<+-_dS zf)`X(?9YpsA8+rDwp4%kfZvDP5^xT`(DZqkf|`um9q?lIi6EZp&poGK!!OfSUpR9?*?i{;4u@1Ae6K5B;gqI7;MQ$>m~fK;mT*{}_o)gd+AJl*(RcPt{k<)b1VJ(t`Ew|H96n&^A zU}e9`Q7yP%S`5QC!ftSkbM{6o_Xea7nUWJp1B<3&ed32GX{xc2KxNMg_i`0 z9FYR?_j-^@MuI^v)^fxerwtkZ-Xou^(mzt>;i znDufy`k1_a3JX7-d6q!{v;0*BT|rK_yiDz78O2DuXa3ivURfW!#@1>Kq);jc4w&-{ z>a;dT9szfL9-$mFM#(oP!V9e0WKPM(A=O!X`9-(bD-he+s68E!mWQ%$`UqZ zwDDd5{uID6%W^FHlMSi_rww=4TOkW(V*HvxA`m<2Je`p?S_B!AsNP;Nqwl7})Wdp= zE&<+`JR|DeF*8KC|C_0s&@I$4zNFe>GcJ6Aw#-h)9<4&e^c!JTX=jT>Ix@3WLb2Bf z^M)f%H)SQGwZiOSLk~O{>$BfLx3~Hw%eG0K2V_h>wDitjdD5RkG2T(REpvS9d1iM% zhsGZV{==t-jPmrS9nHQvW%mSYtU018p1LyL(M9()M!8gsPWf%-8p`n?nF>K-vJeR! z1TZQ9S5!h^rkI~wl}(63tuu)r*-~7;R66wBFLIj!!$j)^*<;+9_gz_u;rrM&VM&uR zNLjQ^=Rnfcr`Jg=?&Ue>TTK+s@WFV=u?7YIH67PFKa%g@u}LE!)wy!5_@p z$fFW}382fmsSbTARCU>JPAyXO@(hDHak6M9?@m$tIcOBv4|Onjue5u0k0|UKYfo3S!)4JEV@T z2UX?s%})1YAw|GW7=GzFbbEH(oV~Zq*Kw}vx?Btws4Ue`XIxa_*)0zk{4g!#Dxanl z1oZPG@0E|5cZe?(o11OhQ>qp+?z`PRW27vaiLRAWTylFZU&a*j4m!U4{swXG(Du1C z{w_`ss7=)b`<)f_7x6i}uc2j*<{DwjO{gj_Js6`uF0m6O`${0D*2x>4;6#*QS|HD18Sf~u7r5?Y6tX7waIAfW6rgWt|L;-JSpm<4 z4tMv^o%grArEU=W2Vo;5cr+9(&}wL}zR6Li#ouFxlLPM-T(%j(s3=(@eh2tZ0d7YE z%7@ERz6v=KI&s78Q^q6 zERKI_SZ&Yl#SFae2L5B9nIw*(kduyFc9~yupzZd_HFUFoI}Sr&Vu18`miklH$8#!G z_(l>4oOZf9ILKExBox9j1y(W&R~rw<((xoDQ=^1;(M5;B^JB#8RLMBl>(byIs%>?f z1@p%=JUZVJ2m3Qxb{_^>$GUSLrL@wAzn>!Z9Kp#OxnRiBea&TX#|?L`62n;w)@-AM z^CQmd%8tR-?J*ckhA z!dC?>8@dj_0@D?Zgiuo8PYDY07=(mV3;;gu3enha@adx;0Mqggvpngkf$|_L^_WVd zT_wO*eTU1tl;Z#eIzjtueZcyPU%kFI)?)%_0nQ9|0kR6Yz zP2Hxn+xDF_3DZ9IT3lBOek{#+hhy2UL8x?937(ASbQS4raBSk!i-C#X*D?hRBCl2? z_(_eC9y2~7<9vh|m97QlSefqf_>qtBvp)ya3dDExaKz!e<2m>qDXAMOCy{bT5i1pT z(3!^2MY`Tw&um&?`={%93u4A|{dCgCaRB{z`z<8Drjz#$RrX2ndWiiaTw3cV&Mgo@ z-V+!(QqrQObK^($c1A9Xq9h7K2Zusq=a>tjXFwICAZF3$@DWBd6l(_ZQux|tdfCEN z2;e?B5Z1UsWhig(^ErjtT#XG0RY<-Bsi--w>E{27b_#O}29PR=!&`wfq00axYdFo5 z^%OXPGTq_aoVZ+?4b_}P^=zmngTIq6iyOzWtGr5ryrFLiqkGs))&Z?$sk9oZvV;-P zP{SB(ou^833^8V|1@SQ9lZM?tgVNq&B#=z_tWiA1di}_g#KGmFxGy#Ry4Z)kP_YSB zWH_^NMdv!wa&3?-oxVw{emPf62&<0zZ{OSrfjUNKf@Nj*K0A4|v5?qSVnzqP^J-Gs zfVe-o@xMPAZMX^bcOM`4fG#WEAQ;Kk6r#CTK^>} z^v)_HcBwa;_9PV5!C0-?J754MVR4hSYEF9)lC)XW>C!_z>`n@GCX7$yDTdGz8cQL* zJO*5RtUN2Sy=(1(xn-{zWVmlW=F7e&XeU*q{U-F8!7o{nGV7ouv|N(y2Ce?4Z>&{d zhEzfas$uKK+h;Qt!OEJ4nuMh4L#bEYZ2{*6W0*6`1(MHuXt41kH z&bh94bu6ERUoLzy>7;#2)^r4KZ;R!YLYOI1I&0(VX2%I52%SH-kepjLL7(QR-Uq5S zB~x^^EMHXLAmZ0%wHitAg6yu<`RJ|VTirA!YxN55C&{#uW_4ufDU9Z}lBuz!tn4RB z^rsT&5B^H$m9uZL30(_KO_OeRkH; zNh&~f`iUFL7GV?iU*8BNb&m&_J<}R%$-f)c14L5UTxxrT$Y1Px_=IwddxoWxhdaB6 z-hK>i_jjhoQG}_ql3?^ZoKp(rjUaaWGmwAUFF^9Y8G;F|#JlzPAq7?;R4pKQ-d$AB z6bu-mkM1b;ABm38K}T1TKe@e(F3^7_uZknZ2gnJhJsF|E+k9@V`vlBw+Bo)l)pJDf zHVU1T2oDI0ORB0o%xfn#2TzRZq0qjQ;=}d^`En=XYbUJLY6!aYFZ(C@T>`kJX>@X| z$?_+4yuw1wT>$z-LM zCh)13Qxq99u$N>O~t@} z=2i3NrBWs)x9Pno80pU9QVKeRxrm5l@I}SC?=FW0c4D@&G{Y#ylGvSfw-^4XHM7Gh zdgM67RSShzw@JawecG8Ctgk9%^TuxMh+m6cLls7HvRm+5d?xB3-Tf+^C?=VgR@PmL zqVA!3Gn;HZSWnT*T1!7hIHgVT{y%d$#%%c?#aQA@U+sN|e=Rh-lx*lv*R0wsTxcVZ zW#y0}L}e{?<)k6eOK@nh*QSOTRcd!iZg6B7WAL_i#yD)%e15f^T~an^p>?`3N_DjX zcg3o4ZXmQpFlE(Re8q)hKG3*L$0X0zd};2+c4%k1@N!ymYmKeeIWl!IB5Wfzbt9^1 z;{Ox%~FMc$7T{{pDmNQ@v8B?mX|@P0Rj>jwLy;-v&{Ys9*oW z_lk+!cksK<)qUYY{b}&6c@bGiiGtUw4X+)!cuD51 zhRlr~s&s#}$d4tW(_63r8@>-9ypf0TH=x`ZC;{mcto2ZCKMbl&;uO0+!$OB+V4ObM zEsm1G6(K+WrCD-k;>%|>-4UCCVF7xfh6y093&yM&dn;;!i}J!$hJ74me~k9)A29#Bc?#o(=jITur=wX zb}E?$Yk_vSiNL8WcD4E7J-6IrKkMi-CPR6*vk@zw&%KP=X^E$JWpQf?W;|0P#QBv- z&bdVu6h9nI5Ff>Yi@~PN|1A^k43UwjA7YuTG`pVT3QeH3*pVi8D4Db)wDlZzr*ZWywhyTR zNt7cWzUy-)8W1p`EJR+KFZuOp*ObQf1F(3BoYDQqBKARl;7($Sg>7?|Px{$E zx~c(vp(sQX>mQJ-qL3#=6(U#1J^(bbRUo&YaKg>(vCv*$3#OO*kUc|kwo-W9b$UBn z2zWt;ze0qGMd`0R{?_ra zdTqbsLw~%+%gcu&e;)-ku`u574tP$*?myO^bOM3D&ooMYNU}~n@Rn~Wem55BOK>{r zkC8vOxCJex2m(WO2AzH(6;c(P_FAgj9`NgsIA0qR8!Wq}SH%uFi+>65>Z4c+bm(|q z!DbNEDH>^7hZSo@lI`NgF278W&e`!0Iw#w$!hsIspk2F;Draa$uF`xERu_fcp;^gk z@9GhcCWOzB!PK|yiZ4R3kbNdL+u84ujl=SJPNsxQuj$T_{=!R=OlgpN?%@>(nW&6Sy~QUiueTZrh=k?fLg!c%E7x8cXWJL(f{%S@TpaaFsbPQnLU+N9$891vBi(1^a7 za!&z$ieff$#U9CW4M9&j@P+&d^Be%qj_)w8I@q+Ju6!miDRY3Gb8p*HR(UKUvNO|k z+A!k}8aO!V{=i(3J=6atLo=j+(i^42(__>BgG5xjB}M(ej*Gy4KMDdT{Q(b-hs82;D~<~=*(*D81o-v$kMDHv zscoGf;3seXCi;_&KD+6Yd9Ut|B02i+AI;Nt1EG-IYAhr9!l;)AX!Bd|Sl~Wc*;O3x z=+WHtkWK*jPrxfFORP*J1m>&dM+EYI&3+Hc3%wXC0rO0>A2Ti@|2vL(c zfL}pgGE|d6gD+iPU z^QCHBVWyAv#M|Kg%oK!gBmiXMzOo7LmGSjiGZU?`J0XtqvE{6R6BPdt3Q(e=r}y#2 z;U%9GRR;zX$7m~7x>uG{cy@;4;ChgshFXs&Jj7#mcObpo1&OT3#Y~0M=$Wb402KqZ zTdIOgGA#}t9m4OK{AHEJJP|Dr73Qpsb=Q5MjEN{fys$Uq=n@83NjP!A1Zv3uIPpBY zF~MM%B?p*5mkqo~v`5Oc!+>ZIl*AcIzwAL+6K5l5M~$cbkQSP zhv>Unjo7LL>^n})0L0rV8N=P%7ZA9u87Y!IBT^Wrx9wYxtUAy>XHkKDKiY6)8l^fI zin2PPcAt{dA7^WpCHkHMMU~=4n7w^A#8ntDj@}GoJM#SCVIBYJhxd&{!wERb(Wj^f z`JQGZ{dn>R6FKS!<@Dy|{IQM+p8|b*Or;`Db3e&hZ~#qsXMI{U6RSl<4ook8(z-t4 zq8x+&ON$>kPPm54oT&j^8wS{N69Ikm=z=IeAd>zT%z`Ak<<~-r zgtOHrAZmu{rOWZMh!FO&9R1k1YC*PW9(kUSm(cP%>Q6zv~| z!p`x)DVf4)W2N!4YixJVCFtYoTO)<2 zxu7Q)k#K*vyBK!f8Ct%ra(}~8PBLEfSh>JnWK82UESAa^r_5pF%GSh6#k$HIVL`#O zN{q7ns!dzrvs_f?s&inLVPC1MjVqx;TCS7VZDNV}S&5xVv5g7z#tC|e3Z3bK9-vk~ zLZG&FP(PJwx1^6>NJ|%{t3%GK*PWyyX9~kuYbKq*_DR(_4`p&_I{#l0QOzTpJEsThaCrCN*)B>&+d73JbME-AT5S!wQg@$J z1?#nK5peStk8R2Ug27+CDBmf9o<4hW7l55Q`dtt{jM|>KhRKn)Mlm6;riXd&Wa_cz z_EDxr8{&E9IW@I;CTuGRp-GYow#r9#G@5emJ%2Hl5#YYSos|jEQT68k@jB}>!_6lm zHsCb6cwezoxbwmyfA=A*Ung}Jct5ND=WKT$DNZo9 zxoXa7>Sd(*v20ZMJ#H6o&#`{t1TycIlj%LAM7^8mBqrHN1%$UN0gJCnP+KK5D(T3> znrW*-L?-f1xw|%s2`uj96$D{)I`m{>>&WfapDK}M=)@RB{3~iYRmz!Em^D1JnNUCt zwAFcXYo*$-w`-)%2XO)Nu{?!0B-TQula;qIL|>E9xQ4|VkZSGq5giuWwJYX?$a=Sj z%ktYiO4bE(RkX2pN-s+FeoV@dh&{|EqQoHA6J8^ZL7hW$nSP3ZS4=5xjA_b;f<$$gkUdfk;&t`3n3{}cUgn+m&||}WP|!7`>`lspR#xW0T`do zsSGzR#c2uwhd?lDi59qlN~#eRxz`RG zYO+*`a{zSNmM&?D6PI8C=~E=5s99u7Mm!7GaA%s^^=ajaml;iZ!(7Pbrn25*nBfAO&cbRgvatS58v!<}OqcW&ul@f)*;N z>4C>wq_z;jz@e#X#~h@udG?O1yj&_4ut5Z+ibB1jc4D%C|5ZcIj}o@R>~8f82w-qg zb%v5-{slPbu}wDnTeKh2huxti9oko{)*aiOQR=#QpI|P$;b;f)$@f^j@}62{uaf>7 zEuqGtN-iK1Ei-5>H9c2tGMiF5FSX|hm{Ve7N(?DGMB=hsfl<=vn0v>OY(;6rYAH-^|Q_C&a;@UlB!v(1%r%}$U2j$OLnnp?gsexUMT|_yXv*e{ptx+fIe};1llcJYKG4#I4a3-ahfcpl*2uQ0~6*fFgOL@SQk0!TpfBt$$Y0NAoV z=meVJuV)N2kQHk77Id5tJx0sm@H|AKdaz@LY?v7Ql6J#jxX^@@t3t_!m%$inFn2rK znh*g;LL`z3gMEUaP`U?1CW_5uxmttU>Q}@;|NQERR|`Snr1&QXa_EXySkA2G6-2Y~ z&}!GpBIA~5F!o_?fE<&cjS`VSS&So(J7kXzOZdkFK0}P->!MJw*T=KH3N2(zq~BiC z!bnbOlBi)GtvE=;JG!uQWTfK`BLElGD5M}WavSc(NGeCh0z!e2V*GYd6a>n0W(g4& z$B=kR8`ZF2f}o)iRY@+r@r_8HY~9B6VnjA(L70vVge9W}#b6XuQGlF_AQ>Y#R|3Zg`W&-pX&gDMa$>6kD`ozu`p5q zdpHx6Vnm};$fXkz^CEb9?u-Tv=sNB5jA&?a8^U5~*eEDcM&{J!36=~j9F&dw=)`D|hZRy~?md>}1 zbB+vYRr*-9E*bcgGrMF96a0!evifjeHT4r=@pjfDDfW*bC7{H9(?+*I_KeVc2v;Us z#W;8dl!wSH<}ee@y-c*CQVp#tACyXxW<+@h8<*iw8#+C%q=cTG;v+vX8>kjCs855S zzRF0M?X}T@^pjrTyi?f5zAmEl|Jkfq1L)iq^sNTb{pw+b;-%686ttbV9CvLivmw5a zKs<0_1#_l}wmoizy=t7O8CNozw+~q_CqBb);C^uQAWH5cIt+BpMP}Oxb&` zF1+_yhN&#LSct(eW)5+%^qwkuM>{wS>}q;MNV+xblx=`W_dtw~)FiW3ol&SNpRmkvq%&?ep-$6^ z`Jx1*l2X-%$3260NB9 zP(E#mQbHKEMt$wv-%Eoc&382JY=^qR>9}jSoj9{&3yo@~G4!@c^wpJf%?KU?`%BzA zW}R_F>tQQ<*|qcpCz%cHXy4h`(vC>A%Y5i-zeU^I%r>_f^6i1*I^6vfG`V&C=5yD< z-0BuhNC{fuc9&S*ik?+A5OQF83s&EX2CPaQ%AxXCkqvy$UDP9tBR%SHb38Yc;&N}#!w zgtqZIPBzvU?m78Z|J-4q=hSx|F1pZ}#B-<_o#;pROVXddI;A&V#Z0d{)#Mtk zHd#zmjkjy>jh1kvCA-;EZB)V$c)}8HJBQo8cDTRp?Q|co-5)1+yvIH69|0Yoa=|OX z{hE*zuV&$SefavF7mjDUZ{y45c)3NsR+C5X<1a6H$ZH<+l;3fAO?G z{^F0GC0vd0CFwQ_N08A!aQMF>{U?9{NPqxnfG$#i2zY?`vVc<6fcu941pojc`2+!s s0096j1pp@i2mlBGq5uE?0RI4hfPer100ImQj)u$a&(sn@9$EkZJHg|C#Q*>R literal 0 HcmV?d00001 diff --git a/版本提交记录.md b/版本提交记录.md index b31bcdb..833703d 100644 --- a/版本提交记录.md +++ b/版本提交记录.md @@ -224,3 +224,9 @@ T:顶视 F:前视 L:左视 R:右视 X:斜视 方向键:剖视 空格: 2021-08-13 演示同时处理多个方向的信号 位于history\005a1目录下,演示用5个声母和5个韵母的组合来关联到25个图像的识别,这样可以减少声音输入区的数量。它的另一个目的是演示体全息存贮的工作模式可以同时处理多个方向的信号。这个演示分辨率极差,只有约一半的识别率,但我不打算继续改进了。 ![result12](result12_letter_test2.png) + +2021-10-13 失败的细胞分裂尝试 +这次本来想模仿生物细胞的分裂,从一个细胞开始分裂出任意指定的三维形状,并设计了split、goto等基因命令,但是做来做去做不出结果,细胞们就象跳蚤一样乱跑不听使唤,最终还是决定放弃,细胞分裂这个算法太难了。细胞分裂的优点是更“象”生物,而且估计可以利用分形原理缩小基因的长度,基因相当于一种自带循环和条件判断的计算机语言。 +最终生成三维形状这个目标还是借助简单遗传算法完成,通过细胞在相邻位置随机生成,并在基因里记录每个细胞的坐标的方式来实现,基因命令被删得只剩一个了,就是随机生成细胞。 +用遗传算法来生成任意形状,就好象一个画家在画画,但是画什么根本不知道,只知道听从旁边人打分,画的好就打高分,画的不好就打低分,这样一直循环下去,最终画的内容只由打分的人决定。目前速度上还有改进余地,比如让新细胞有更多变异率。 +![result13](result13_frog3d.gif)