From 03c073e1c459480575a9d708fbde10a2825b55d2 Mon Sep 17 00:00:00 2001 From: Liuyang <2746366019@qq.com> Date: Mon, 24 Mar 2025 11:11:35 +0800 Subject: [PATCH] =?UTF-8?q?feat(llm):=20=E6=B7=BB=E5=8A=A0=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E9=9B=86=E7=A4=BA=E4=BE=8B=E6=96=87=E4=BB=B6=E4=B8=8B?= =?UTF-8?q?=E8=BD=BD=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 DatasetController 中的 downloadExampleFile 方法 - 支持下载 txt、xlsx、csv 和 json 四种格式的示例文件 - 示例文件存放在 resources/file/dataset_example 目录下 - 根据 type 参数确定文件类型和 Content-Type - 使用 ClassPathResource 加载文件并写入响应输出流 --- .../admin/dataset/DatasetController.java | 87 ++++++++++++++---- .../dataset_example/dataset_example_csv.csv | 11 +++ .../dataset_example/dataset_example_json.json | 23 +++++ .../dataset_example/dataset_example_txt.txt | 1 + .../dataset_example/dataset_example_xlsx.xlsx | Bin 0 -> 13164 bytes 5 files changed, 104 insertions(+), 18 deletions(-) create mode 100644 yudao-module-llm/yudao-module-llm-biz/src/main/resources/file/dataset_example/dataset_example_csv.csv create mode 100644 yudao-module-llm/yudao-module-llm-biz/src/main/resources/file/dataset_example/dataset_example_json.json create mode 100644 yudao-module-llm/yudao-module-llm-biz/src/main/resources/file/dataset_example/dataset_example_txt.txt create mode 100644 yudao-module-llm/yudao-module-llm-biz/src/main/resources/file/dataset_example/dataset_example_xlsx.xlsx diff --git a/yudao-module-llm/yudao-module-llm-biz/src/main/java/cn/iocoder/yudao/module/llm/controller/admin/dataset/DatasetController.java b/yudao-module-llm/yudao-module-llm-biz/src/main/java/cn/iocoder/yudao/module/llm/controller/admin/dataset/DatasetController.java index 9f71eb155..ebb0d855a 100644 --- a/yudao-module-llm/yudao-module-llm-biz/src/main/java/cn/iocoder/yudao/module/llm/controller/admin/dataset/DatasetController.java +++ b/yudao-module-llm/yudao-module-llm-biz/src/main/java/cn/iocoder/yudao/module/llm/controller/admin/dataset/DatasetController.java @@ -6,7 +6,6 @@ import cn.iocoder.yudao.framework.common.pojo.PageParam; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; -import cn.iocoder.yudao.module.llm.controller.admin.dataset.dto.DataJsonTemplate; import cn.iocoder.yudao.module.llm.controller.admin.dataset.vo.DatasetPageReqVO; import cn.iocoder.yudao.module.llm.controller.admin.dataset.vo.DatasetRespVO; import cn.iocoder.yudao.module.llm.controller.admin.dataset.vo.DatasetSaveReqVO; @@ -16,14 +15,18 @@ import cn.iocoder.yudao.module.llm.service.dataset.DatasetService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; -import org.springframework.security.access.prepost.PreAuthorize; +import org.apache.commons.io.IOUtils; +import org.springframework.core.io.ClassPathResource; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; import javax.servlet.http.HttpServletResponse; import javax.validation.Valid; +import java.io.FileNotFoundException; import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; import java.util.List; import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT; @@ -40,23 +43,23 @@ public class DatasetController { @PostMapping("/create") @Operation(summary = "创建数据集") -// @PreAuthorize("@ss.hasPermission('llm:dataset:create')") - public CommonResult createDataset(@Valid @RequestBody DatasetSaveReqVO createReqVO) { + // @PreAuthorize("@ss.hasPermission('llm:dataset:create')") + public CommonResult createDataset (@Valid @RequestBody DatasetSaveReqVO createReqVO) { return success(datasetService.createDataset(createReqVO)); } @PutMapping("/update") @Operation(summary = "更新数据集") -// @PreAuthorize("@ss.hasPermission('llm:dataset:update')") - public CommonResult updateDataset(@Valid @RequestBody DatasetSaveReqVO updateReqVO) { + // @PreAuthorize("@ss.hasPermission('llm:dataset:update')") + public CommonResult updateDataset (@Valid @RequestBody DatasetSaveReqVO updateReqVO) { datasetService.updateDataset(updateReqVO); return success(true); } @GetMapping("/all") @Operation(summary = "查询所有数据集接口") -// @PreAuthorize("@ss.hasPermission('llm:dataset:query')") - public CommonResult> all() { + // @PreAuthorize("@ss.hasPermission('llm:dataset:query')") + public CommonResult> all () { List list = datasetService.queryAll(); return success(list); } @@ -64,8 +67,8 @@ public class DatasetController { @DeleteMapping("/delete") @Operation(summary = "删除数据集") @Parameter(name = "id", description = "编号", required = true) -// @PreAuthorize("@ss.hasPermission('llm:dataset:delete')") - public CommonResult deleteDataset(@RequestParam("id") Long id) { + // @PreAuthorize("@ss.hasPermission('llm:dataset:delete')") + public CommonResult deleteDataset (@RequestParam("id") Long id) { datasetService.deleteDataset(id); return success(true); } @@ -73,30 +76,78 @@ public class DatasetController { @GetMapping("/get") @Operation(summary = "获得数据集") @Parameter(name = "id", description = "编号", required = true, example = "1024") -// @PreAuthorize("@ss.hasPermission('llm:dataset:query')") - public CommonResult getDataset(@RequestParam("id") Long id) { + // @PreAuthorize("@ss.hasPermission('llm:dataset:query')") + public CommonResult getDataset (@RequestParam("id") Long id) { return success(datasetService.getDataset(id)); } @GetMapping("/page") @Operation(summary = "获得数据集分页") -// @PreAuthorize("@ss.hasPermission('llm:dataset:query')") - public CommonResult> getDatasetPage(@Valid DatasetPageReqVO pageReqVO) { + // @PreAuthorize("@ss.hasPermission('llm:dataset:query')") + public CommonResult> getDatasetPage (@Valid DatasetPageReqVO pageReqVO) { PageResult pageResult = datasetService.getDatasetPage(pageReqVO); return success(BeanUtils.toBean(pageResult, DatasetRespVO.class)); } @GetMapping("/export-excel") @Operation(summary = "导出数据集 Excel") -// @PreAuthorize("@ss.hasPermission('llm:dataset:export')") + // @PreAuthorize("@ss.hasPermission('llm:dataset:export')") @ApiAccessLog(operateType = EXPORT) - public void exportDatasetExcel(@Valid DatasetPageReqVO pageReqVO, - HttpServletResponse response) throws IOException { + public void exportDatasetExcel (@Valid DatasetPageReqVO pageReqVO, + HttpServletResponse response) throws IOException { pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); List list = datasetService.getDatasetPage(pageReqVO).getList(); // 导出 Excel ExcelUtils.write(response, "数据集.xls", "数据", DatasetRespVO.class, - BeanUtils.toBean(list, DatasetRespVO.class)); + BeanUtils.toBean(list, DatasetRespVO.class)); } + @GetMapping("/download-example") + @Operation(summary = "下载示例文件") + public void downloadExampleFile (@RequestParam("type") int type, HttpServletResponse response) throws IOException { + String fileName; + String contentType; + + // 根据 type 参数确定文件名和 Content-Type + switch (type) { + // txt 文件 + case 1: + fileName = "dataset_example_txt.txt"; + contentType = "text/plain"; + break; + // xlsx + case 2: + fileName = "dataset_example_xlsx.xlsx"; + contentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"; + break; + // csv + case 3: + fileName = "dataset_example_csv.csv"; + contentType = "text/csv"; + break; + // json + case 4: + fileName = "dataset_example_json.json"; + contentType = "application/json"; + break; + default: + throw new IllegalArgumentException("无效的 type 参数"); + } + + // 从 resources/file/dataset_example 目录加载文件 + ClassPathResource resource = new ClassPathResource("file/dataset_example/" + fileName); + if (!resource.exists()) { + throw new FileNotFoundException("文件未找到: " + fileName); + } + + // 设置响应头 + response.setContentType(contentType); + response.setHeader("Content-Disposition", "attachment; filename=" + fileName); + + // 将文件内容写入响应输出流 + try (InputStream inputStream = resource.getInputStream(); + OutputStream outputStream = response.getOutputStream()) { + IOUtils.copy(inputStream, outputStream); + } + } } diff --git a/yudao-module-llm/yudao-module-llm-biz/src/main/resources/file/dataset_example/dataset_example_csv.csv b/yudao-module-llm/yudao-module-llm-biz/src/main/resources/file/dataset_example/dataset_example_csv.csv new file mode 100644 index 000000000..0f118df2e --- /dev/null +++ b/yudao-module-llm/yudao-module-llm-biz/src/main/resources/file/dataset_example/dataset_example_csv.csv @@ -0,0 +1,11 @@ +system,question,answers +你是一个专业的新闻摘要撰写助手,擅长使用简洁明了的语言来提炼核心信息。,"据台湾《旺报》报道,大陆游客赴台自由行第五批城市有望在今年底前宣布并上路。新开放城市预计在10个左右,可望包括海口、兰州、银川、呼和浩特4个省会级城市。海口的亲们!是不是很兴奋啊! +生成摘要如下:","大陆游客赴台自由行有望新增海口" +你是一个专业的新闻摘要撰写助手,擅长使用简洁明了的语言来提炼核心信息。,"央视报道,北海道某家烤肉店,给顾客提供所谓“松阪牛肉”实际是产地来源不明的普通牛肉,每片约180克的冒牌牛肉,售价高达3700日元,比普通牛肉高20倍。店家见人下菜碟,冒牌牛肉从未向日本人出售,全部卖给中国游客。 +生成摘要如下:","日本消费陷阱:冒牌牛肉不卖当地人只卖中国游客" +你是一个专业的新闻摘要撰写助手,擅长使用简洁明了的语言来提炼核心信息。,"12日上午,“圆明重光”圆明园文化展在省博物院隆重开展。该展览分“远逝辉煌”“百年沧桑”以及“圆明重光”三个部分,通过图文资料、精致的建筑、新颖的数字多媒体技术及珍贵的圆明园馆藏文物,展示圆明园鼎盛、蒙尘与重华的历程。 +生成摘要如下:","圆明园文化展海口开展市民可免费观展" +你是一个专业的新闻摘要撰写助手,擅长使用简洁明了的语言来提炼核心信息。,"记者12日从海南高速铁路有限公司获悉,西环高铁自2013年9月底全面施工以来,工程正有序快速推进。截至今年2月底,已累计完成投资176.5亿元,约占总投资的66%。其中,今年头两个月,完成投资14.6亿元,为年度计划的19%。 +生成摘要如下:","西环高铁工程快速推进" +你是一个专业的新闻摘要撰写助手,擅长使用简洁明了的语言来提炼核心信息。,"琼中黎族苗族自治县有这么一位黎族乡村医生王成瞩,他今年62岁了,在44年的风雨行医路中,他背坏了8个药箱,免费为乡亲们看病送药,亲手接生58个孩子,每年接诊上万人次……他像是山村里流动的“120”, +生成摘要如下:","琼中村医给困难群众治疗从不收钱" \ No newline at end of file diff --git a/yudao-module-llm/yudao-module-llm-biz/src/main/resources/file/dataset_example/dataset_example_json.json b/yudao-module-llm/yudao-module-llm-biz/src/main/resources/file/dataset_example/dataset_example_json.json new file mode 100644 index 000000000..53d3d4dc7 --- /dev/null +++ b/yudao-module-llm/yudao-module-llm-biz/src/main/resources/file/dataset_example/dataset_example_json.json @@ -0,0 +1,23 @@ +[ + { + "system": "你是一个专业的新闻摘要撰写助手,擅长使用简洁明了的语言来提炼核心信息。", + "question": "据路透社报道,俄罗斯经济发展部部长AlexeiUlyukayev当地时间周六(1月31日)表示,俄经济发展部已向政府提交了2015年度经济发展指标最新预测,此次预测是基于原油年平均价格为每桶50美元,而去年12月份的预测基于原油年平均价格为每桶80美元", + "answers": [ + "俄罗斯预计今年国内GDP将萎缩3%" + ] + }, + { + "system": "你是一个专业的新闻摘要撰写助手,擅长使用简洁明了的语言来提炼核心信息。", + "question": "1973年一桩“奸污”谜案,将符福山的人生划成了对等的两半:前40年,他是人民教师;后40年,他被三女生揭发奸污,遭除名并一生背负辱名。40年后3个“被奸污”女生终承认真相:为能被推荐上高中,3人是受人蛊惑,作伪证诬告“遭奸污”。", + "answers": [ + "海南教师被诬告奸污3女生背负辱名40年" + ] + }, + { + "system": "你是一个专业的新闻摘要撰写助手,擅长使用简洁明了的语言来提炼核心信息。", + "question": "8日白天,海南北部地区阴天有小阵雨,南部地区多云。9、10日全岛多云。11日,一股较强冷空气来袭,全岛阴天为主,气温下降明显。岛民们未来一周看不见太阳了,要记得保暖防寒哦~南海君最不喜欢湿冷的天气了,你呢?", + "answers": [ + "11日较强冷空气再袭海南" + ] + } +] \ No newline at end of file diff --git a/yudao-module-llm/yudao-module-llm-biz/src/main/resources/file/dataset_example/dataset_example_txt.txt b/yudao-module-llm/yudao-module-llm-biz/src/main/resources/file/dataset_example/dataset_example_txt.txt new file mode 100644 index 000000000..eabde8ccb --- /dev/null +++ b/yudao-module-llm/yudao-module-llm-biz/src/main/resources/file/dataset_example/dataset_example_txt.txt @@ -0,0 +1 @@ +请根据下面的新闻生成摘要, 内容如下:新华社受权于18日全文播发修改后的《中华人民共和国立法法》,修改后的立法法分为“总则”“法律”“行政法规”“地方性法规、自治条例和单行条例、规章”“适用与备案审查”“附则”等6章,共计105条。\n生成摘要如下: [["修改后的立法法全文公布"]] \ No newline at end of file diff --git a/yudao-module-llm/yudao-module-llm-biz/src/main/resources/file/dataset_example/dataset_example_xlsx.xlsx b/yudao-module-llm/yudao-module-llm-biz/src/main/resources/file/dataset_example/dataset_example_xlsx.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..ebeb9de05fd78db3b2e7e015ffeb01bf9dfee1fb GIT binary patch literal 13164 zcma*Ob6_7`*Df5}wr#6HW81cE+qN3pHXAibV>Gs#q_Nd}NqgQKeV^|+Xa6yi-^{w! z+H>uhmDy`wBPR(A0tN8iLS?o;zVH91LB9QAWNRqrU~A_{FZX7K@^%2?m)V4X79b-a z001Wt006>2&GhZ;=-jNWvf_IsfEf`&&H~O59BRxX!;-8ba<_$P)VhX#SYaWkE&L%fX4@D*MtO zOVBA3vNs;>&2T4f<)l3Xv0S3HKkke5(QVBrz`7~ZIu-Kykqd5S6YiK~9Jp%ok-cdhP){k%WioDT__)mHbZ5@o?`Sp&Umgr|d2{{AZ$lL9fo~iB+ zZU#=)=ESIEx)2d?XhzLoA(^(ZwOw#_&UeH7Nw53UF<~6O9FDiQy?mN8ACVu>Ybg-M!?c>((xBfBYHKdD`B2c;>2=S31{VYPh>lWX zCv+R^iq^9jmrz*rGcRxsGNTAoH@dcidlHy&Goe6*2zhf}t2OAt9=SlE6Wn6NFB_HM z6{|VukGl~{$$Xz|it|pJG$R~2X24aW^;VkYGp!|Z}4@Hg+v@fRzgCJ$xz(GxDz6x`))Faz8m1*bmO^IY>>av z4gW?r^1tYIc673}ekZ&ro?o(`0psn4ekI(^CY8=`#Ksel1P2J)BFV$WJOJvZ+VVTP!zP*%Lt2#3iI z3XXifC0oPbf!N{F_ZOwe=nZu2$1xm*7npb1Hrz{8!B+p^%j#LV(!7&DqWhIpeMt()15FjK}QjmDm za1?^ZltUJc>KOvefj*Rfc~One>-}ck_^>vki+2O^U_q?SIz0V+dM1*HJa^vDF{D9- zXWXKDi*wo3^CJhQ;oZQyF_VCiUPZ0z)B%HiQi4G4Vmf(Hu#fbqXr$ilZq+JL|U$<$DAxn;v1D4e{m=r$nXfyr@j zLZ6}HsfGJ$qBEh4Vm|1R@WKr-l7tq{^73inY8>~X&_KA4N&cMG{UBl0me*HfF5e?r zbRroX6{?L)v}nW_VfcR7k<45E5@=XQiBr)|9T!MlC6iQIAsbX4V@>M;h#Mnv^=d_?-Fxa_$psKz*EP!icLaz|So=>E>yA4asUwp2 z*;!0Ys7o6x@FXxfz z%w%X%f1yyvFyR5Iyo z4oZ7wkH{CUdjNSe-M$-lDr?g_2gE+*y`r zO*9jwKZJmgtMG?$fl9L-N3e}sNwb|{AayoD34Eh8tM8~bqc*D-9*QI2wjWJ-Kg7i4 z)}smXL>@(Asv;i7MJg@gY1l!Wq z?y3i;PVDzjC-?xkC%JoSDOD^^Q%jHEGOvw{?eLz7FrVGe6G=YyuFq$yY(7Q>fA`;+DMd1C2c1nFLxkXHRJWT+x zB;iqglDCk&zS}`OuB>b1zFXLa2_KCWz?Ft*p zXZS@|g15X(-i!_I9I;rJQ6-H%U=xaGo}QwnnE!D`+#7p&#}BZ-T|X7Dwuf*Xwm-huHaMIWR0wkcec@ex*XY+9Pa$7k`$+ z%+odGMG_k?0cyx_%uQ-}JyYy#dH(54`%4BD2_kD`J4%9AIq&=6fuFPCsQ6Tzo7KY%1GE9M(3c!5nxWZKbdqU zD%gkYc@}{Q<5WneF!dE+UPB)i68NN0j1(xcWu3X_&XM^!sC6lH#wG)6eeI3s8Rx@* z3#ajOlwJx`jpGGPRTqaxu%2&B)eFbYo=utAfO;F?(p5CVpKgANR3%Q+`2E;nIh&s7 zq3(JChQfp;n>w|e_u?bL6Dq~ALK|!g;8pOc51k?`gu9(35;AtKTrKk4o9+={>SG9M zbo?iBqX6%)ZMqnd0E2M=TO_TtI>Bx&teMWZYfx#Wl_!SYI7DcVnrz?KqX)(7qld(u z(8(D5pH9!;r!V^PX=zQj=wbr5`%*W2ZVwjl3;42qt}ZXo_uSM6ULX6(KR-Xab0RRA z5l%8m}P6F0W@QO;!jUzJ9 zVc$Sy09VgTZLlNKaHy$E9Y~oOT4LySEsn$Blo^K_CoYYm@Zdfv4(a4n{%FxT_Ax+` zSN=PmFs_uOG*cllc^q1#i#do-dg>uewTo4QE4niW^{huIPP>>G#F#`7KGJ^L1y?pD zPI5fXb{HzG4{}AV)NrrXy|9)n)w$D04ACye_! zG(f_#(;-hJDZa_PM4LUkeo2!r9b^MrN8M>|fz?!0m-vxQ(OY5n+S}I=XnMixuco{1 zwm!G!>b&52e0*B2#cSE5jiOfC)$U&FU3ZvJkSu)}#Kb1&C}JZqOD?%cGw6-+?RX3@ zemAt3BxtCy^+W4Ny#_GIYTkS*oFEQ=ypDZyB7Z4ya3oT#zNHD6)R}p=@3YA~m~7YS zz4O4~b9neGTh2V0xUddPCZmvJ56p&*)sUIVOOMG(6s0d*V-^~v%#Ib9(^6%Qt$S2~ z@Ttmyy{n(5f(gEB_l!t$ zg?DK`b4zAd89YP*SR=W1uaDNV7FQDl`=pq-Wc1LNQ6*CezOfu~YpwZ1A946vnvkn!CETcxy z?CzPPdh1Zz{x(JR*n1N-5#kTf3Pl)$uguEVK0phg$A%|>_%;rpB3!yFc<5BSa={64 zkKTaMfn~S|w05}Avj|FdIaWWR9ZFwUG8U7U*@ zNOU4@V{f6j`fPDkVzWlGx~^SG#ubmg744Gxv$u@l!Fc-U#Mdv8EG`!ML-Q_HMPcQ7_mbaF7aF?D=@^{moRx5ZX>@qv$f)hpf70}~@rNTKmG=!j1zaL3-&-v`H7 z8)@`!Uak8kzF$QVvE40}FJ>QK8k~VfS5Fa7W7G4Tbjo$N?s2I*?0TeN6~moX2W9~Q zTkm$ZlzNtV8A<TDR-zaeM?{XX5#%>+7xTqzPVC zb(hY=<4wz%N{a5pv%S0X{-~<&t1G>V>H^-@>B!M&y6yaY_tV_!>XGUO&1df}uBX$E zJ=EvRoU`?}Um-PTuM91ZYfpO%x-~uxot?M0D{bzn$A_yc3$`jIc-}XsPsvTG%(A_= zPs!}BH!qjA*MY$g>8kW98=W3?w-z_C6_%s6x?@#c9*je>*NQmW+JR%PIiGdZUvl>D zTyr!61?v`SxkBbR8@N8GkW)8c6U{Zw^3*kzjNsL+6^_FM%Lp?(*Wn|6;PrGhf)!y> zPj(h;CsZl_@W&UhdxnW$1Wo^HRI^8}8x$-oG zT+O78;2*UA5*uqaD|$nhykLK%TE4CnB3mel5~b0V)@q~p9K>}@HIH`8k2c|Ma3k=| z`m2uct%XX>bzpppBfFF_%1iH}sYpoZ7}G>x*omnE3m1AY5-Ph-m5rB6t?*4H0~HF# z>-72J6Zp18>SITWdVCYXuzD5|UO);5lv)=yLcU1qwkE>MtZr{?e#blkl%~SVM_l1d z<`5cXO8Me(>M20bIjYk6aN|!LCMC!BV@BW~QZVP?t7OEhJPGrqtokxv&x2QPCTE+m zR=!uK50M=v<>FJ9%*{~ExEN`0j=K;IYfJbB_OD(M;oI@~4=pZcAwbWnn_AA_>8aZr z$QAfaHkTM<_v%8Nl|fj&CQyklFE>1@5BPH*PDHqArI#y5fW>EtHYMpSHj<%`w+yd2x$*cZS3i#q&H!`aaD6UA0kb@6F{ ziX$VuBQR9BDjC>t*)?A4C<@iU2fYvJR-=v+!utDj&W~~7MK(GUL0#Ey?Jxt3c2B4dNKTg?YPEn=gF7K_HITc6%;TWH8C^aYzh$M zPyMiXw05uD1#f}wVW5;g6lnlOH7d0lq~oW_7+4ZDyJXMN7H}+OVg}41&Acx587@lP6&Z2xu7yb=<4N?H_%8 zhPb4g16y;}d9r><`&3NocBqHgAJzn#7uTtR;pSMuK_@Wntm5@EqQLJxW&YlcAXz}e{O|$S4Pjj}?)6psGFtP%(BxqTCpm< zh{1+xbc5UFVWZx+(e<=@%dpE}ayNNcx3iGpDm_eYrVB$HB-v;MZRJ+Q2&34xUlUTb zUNn060pu?Mf!Z&kM{|&tmtK?~I*(5zPDX0p)3|IA&hm6LhKV|I08!^1IyOI5Z(?j%k1OLuhTH2jmyBV1V>eUec>fga<-5n^>KD zCKFa%&9A40+N<=rh!NTZ&=bChyY%=L#-CuJwQOqMjm@!Fn})P;gjec;IxKDpP)6Qf z&zF&Lbf4K|Wz&n{vY!SdoJ&-v-Ixeg@92;=I;H=Lr_&@?L?yp^+b6QUGA`olrQ1NvTh6$F=IiLBsk z^+q!=3eKP+wcZ20FHC*SZ_Zhx=nhIc%6z|~{aVUQBar*MSxluJchKa~BUn@HQWnnQ z8d>Ub7m%=5(hgKuDUeSKY|RN~_*6{TY0RD|Uyx&C>3-eG3Yx079mu?JgZw^cLY6EX z*3rOF98W7ToXtR!C@$u6=ULt=g3;VC-*~FJt^E&)$+odO>(`Xk$rrt(3s*j=r@EZ1 zh1>m32ENj1fO^X|f-)ze=0{TvE{GzLHE=tY0#|0S3zQovWqb#HA@cK_ue(JSd9pup zF$>`9^*xL1q0ern9V(~0D+e=kxbsob7WTd(Q}j5~PVnL)i&~a$ z0HK@YmFY2w$FZL-Bk@O_LKGq% zqU*M(H!VO_>0HlovgCwSOU_;)T*ubyd@;ZAvYRA0&*MMHphKGjPNoG3Bxkdu zG^_T?v)G!!<#Q_p#QYiuVUPKCHYJry36pB6B>4fr`>a_l>J16RT&l7}? z8^^PDJN;0nmS076+pnyp2i83|c}DL~rOni+2hQ=wy+ zuRH3&X`<>0XN+kffy?D>h{k~L;r73% zO%U6~g>EQi!-;c1mTJUQYj< zny!y1QBw=hpBzaCa0+dGaFPD zPA#o$Awo^Dw&<8Yglha}&N7i7s5Lan)V$KMm`JPQ1YbXHVcg0W>~0b5AF-!f5#}dD zSW=Wwx4z<5v{f>#;O8O8oj6LR*Y#UNh2;I{X0nTH@`n-BU9Ns#8X;ngHbq$So59V( zcAg%tmJTNI`$K=woqcqBU@*X?M#h?V56`|Fy%M~2;gz~z$P4audl77|NlbSDh%8|| z-<(`O{<`y>HnKe6zC7|!?_QK8_tgWPQhy*P z+7p(98(_>2C)mI)93YC5h9J0mqb*Be7IqRIG8xO-ijv9Lm%am_Ve@34iBGyQZRUB+ z0Iu~hv@aOmCsAjBot65{-U@QlU{ECkY#0F0nn`7ZIMqXd%NKU=qqv(ex3?(Us*vZD zR@EQSg8CVy#ujbP@#@gg{ZZg6zRN~;UmChAYpbQ_Bp*-939+62FcpwoAnAFcz00fv`yp+Nymq&|*SUTv`8 zvU2s5GO$UU4XZELwJc94lw~);_8%GMtks8NXHv7PcFyncM3Dz*;sk63u+&UNld!Ec z8LD88h;(|;pSN+ki^4@15a;ZUClg1e2wZ*k#uIk+OW3?a;B``&a+B^am?-M4vV!&; z-lRu!J8TLYekSc0SW=5zBRj*hb)AYbbpWRGO!FJN{QP?CYlnyJeHUQ;ljrQ{ zK}uv6t;P(LL&vlKgKHh(q3>JZinEOjGS(~8Q&7t{runp0m!0XXr_&`+pKEl=R#S9* z-)eN;x!@uOD9KpLI8P{7fL-8NZol3V_PYt}E;AeqtrSnEPuiKj&AWpE5Lk!eDGr?H z^I+4^THXj}Am>D~S~!4wi|G{mE9BMqQ6#wo;P4*(0mn-Xpd|RS_Hv+~IYzJ-tG^$c zQH!a_iC9HGvc?Xj86kX0>t}=dZmD(A;@`$7J@myn%0c?Whus=(X7G5&VPJ%VJgkiG zt9gs#r8n^H(vG6k*@~D?*6R+I3gzjW-x!HB{5+G`vt_DRkei&57JouqhwjIPSfkw3 zZu<|Ec*rDq0W9c?g09-6i-kJ>@UNYiCe=po&hgm>^-V6x-iq--cP#NXkE?PW#eeEK zb^{%LGWGeIfTgFhoxqNdTkY zuP1=KV})4S6&<0Ien$j0B^Ok!LU=+!;!mbO=ngn_`YsN>Z{2^9-Y+R?AhwI26Q%4q zR@WK;^RamG!S|I32TGZJX2Bje{PZYWozc$+=YHe+?^*zPV%Yc5xAnq}x8`kN~r*(Mp1G349!|L8N5_26kGlHFw4p3 z$&e|VBbEy%@7PJ6Ze1PSoD3{4ash=2qVF_T5D=s8{7aMpIdJJs0UxQxptKxCi0%W$ z+;Bhpww$)P{TzH?o&u5*sZ}V4MNDuP#-c&*B$e7o(qd6FSIvyG0__d1gpikx)>`Qn zfGviJfyzrO=p9YiC)smfKqwYLGj4%<#8!VhwhY7&+3c!&C{bA}iF zL7Z12aoFsUZHdiu9XdD#QN^m(6GDS8?TE8xZ)odG^hhI64!_-O2Nq08Gvxe}z>g7_ z(awsU0mebaRRI>wDL~}hbh`#=1zO88oin}331~$kp`vK7B>lkGZYHBD=jGF&9b3d+ zhB^xiy4Ixvt;2e*J&Y~cQRNhZbnQ`)PLdl>c`(>G-FIlUn4Y5R&v+1bWt4kJFMQht zI^RBxk(dsp4`e*8>9Z$#w(xj)kL)L~caW@&9oXJJji>hCUR{GcnhM5ex9L=yUz$B; zT-g45+$XK#&=%j8Fhr#R0Nz$1f7O7T+^vj%6@TWmPGYe|F<)Z_UTc>jcyk{+ZGAej z>36+a6p8|D>Z)_pR0segyLD4#1N3S&X&$SPD;BO@ zSN-Qgsc{#MS%L2log;ttG<>qoLAc4xFQ(Wts4>6Wi|e?V|_0sUTK6!$i;-HN27@O%W@nxkw)!OW@OIuMJ!$W~lcr^7+Gjj~H7##gQ9 zbN9pT6s!(?kZ$9b7F!7iMzr7ui&-zh{8yhF2JRjM6FU7eX7qmK^rWeh^pV_a-hbpuFHu(t< zOM=$jUg5>5 z{aI=}wNj-O{rP4|l%R#FBoWm>{gp>7)PWAv(3e}Jj$`URR0J`jbMqw9uv(s5(ZKSP zLg{=V$&n&r28(5`X|%ZFF#qOU;Y3Cb%gKD?DhaoSqjXekqcSqkHhKhPUM$Q(2y`>I z1@gdzWTsPrLnV2#3r)jvxWS~&MecLla9SiGFi6Kc#DF1EHVV6fqu&Ik6!5l=-PSi! zG^dFcY+2TWj@hK8HnkN1PmH``p8!}^omdBzxwH}3Yp>_-jqD>feG%ON7^U>c5JRqA zjnS+*)qc!6sT4h*WChZFyl9;-+`>O3YH#CTy>5okHZ%>|vC%9;i@}h3m{uBwGEuHo zUMW(bqM1lD9yIA;q)i?Fwq+d=HQ6!asRzJJzWK_Ey!Yh zm=J)5#fs$@CTjOJN57ao-A>c(((T1&GmCAi%;pktGk+tvwedqhv#-^G3t)Rmq4B$-vqa8L2`P7$r0~uiaIy z3_b`E8YLd93x-kD2O}UF!4T%Fg+yB!a8yKx5oJV&5fns+Z5vx#bqK1}N}qEuztGk@ z5RO-7L5qW=&=r2QI1ZqrOfmdadn$5pNSNFu@fqb7rTQ~{bGjw3Y&6B1z@?3PjAK^e z(wS=lj7=Ph&oV#sa_yWSjY|TnqXPtT^0a^t*)8OazdC$Lxf{fZRf85zC2^Sxt_aosvY#X{ zm!)V?kSzd;liAM=dT8R9Em7eYr@v2OT+O)9`)C8?34nct?X=lh8fJkblvu{Wmx@#Q zb05YS9yOUY%tj_zC>eG;Ly=Ve&@VIdZP!E~?g8BxRGFnnE8nAhszRoUi(~l}7Qvy2 zbdXdv)3Jh7waT%GG{(&b8h)PXb29i263c`+S)WFqy-br3V(39cGymxGJRXWY?dK+N z%k+)qK>PPi)0pi^FXH6eMq|I_b~CL10?o+z-0~f>aHZ*4oAOY_1CjbTXeo7VY}h&f%y z^nErK7~K&-2BQjkhN0~eHn^Ax^7eR+y}CGg9oX){nIII9ipJxWUcOQnL>4f(eh{9? z77Zj5>fbwY&Ea#;j5}AG3R1)He)zI`<_fS=Fa%G>_h5DzIf-Glbs;%HrcXYfWGe=0 zPKS+0%>afVG_5ukG89WUAnVSEji)Fl47v<4CjMA72n>zqjmjW)BheQE7mP93=gKYR z+OAZ?z{Y**M0l#u)wkG#cr@9L5!0Y1js)N8Z%8m;TCR$Ljn~kQ&`_qMZ{@aoB(PiT z5nQ(wZwV1k-6N5p?u^%P9+92e3uV}Eh{omyxmft?G_)obsFgxjLMz`vx{2ziwu`D4j0wT`el%prN<3`o zS2rCb|0ld={;=^KEJGvwuw=vc;x!{H_edwJ+?rb4D4Psuy=F12rj?_$H~d|_-Q(-xFBg{D+M|4ej*w3x zb6xIpu;i~3*>g``|BIyUO{@Z->tJm4r&7(6!=>}}?cBzjoDlji8@hMPs)R|20S1J@ zcU|m$x3nuN;*t|R(GO`OZ@)CD*C{gO1oe~dE`E8MZ|&f*=@0uE8(u~o*lPqjjKwjX z0nYLPA8m(Sy5-Nk+|GNv zjqPuAV!iF(W?R3_{yFFRKkQ0d^uI~}?t<6($GTIpQWPY1tt1Fn=6U?$22;XmA;+(W zT59YF?FkC8Z9#0oy6(osR@Npt!sw;Gf!E|xNg#ZeuI)NQ@nWfQl_dykYVm-;LzNP% zt+2Iiw&gIJNFBb37jn5M>|q=-rTof)!-`6nKbgf=DDRk3mMEVQc>2z+d~p%@H`8nb zThziXZ-8kjM)KD)+~sEWd!(_0uxxrEv2F8V;4qOAIQ8BfIws=b(Tlr^!4Fwe-HszG z+6pwI3wmspeRe*?+*JlC4!jkXFms<^HVAQt2`|HU)QC7;V;C-f49$K1_spd9Lc`JY zZAJxp>OMRmAW@-fHEFMYn3MWiK&;_ zsA)lpeQw~an!xqb=Z_W)>fk*A<+$^e;*{KWG4+7dwU>Z6<5J#@MAHltZU_!^COx*E zT_5PWBsUe(HDK9rxOcXQ z012#f*|(>qIFVg9@$+Cm*FK{0@XI)r`5oAPb_7u02RR=ddMLTOnyBq>q`Vn{I+@r! zpcPp5E5gyyOw)PQdu7P>3??TD2!!%WA@Ex%|L4fO-M|2V00eK_7TPy8!T%no z-wyt>M)p19{BG}}djjge^UuG7{+WT^F~5Tf{e}7U#Qe8l?^?az?LF9g`^U!s|Bm

A!;hkM{jf_@C3{ zpC0}!Wc=*`m+-fTzsef_@7Jyf@eBGt+RlI9A%Chn|BmSKPuSmD&p*5TXU*+z2c-DF z;{KDi|JLbuo%!$fKEgJ?NBAB5m+JiAJ^xd8{*L`UYM=fW_HPxsoFwS4hZXVd`wj3n KJ6Za7-2Vp%kC;LL literal 0 HcmV?d00001