一、C标准I/O库函数、Unbuffered I/O函数
1. C标准I/O库函数是如何用系统调用的
fopen(3)
调用open(2)打开制定的文件,返回一个文件描述符(一个int类型的编号),分配一个FILE结构体,其中包含该文件的描述符、I/O缓冲区和当前读写位置等信息,返回这个FILE结构体的地址。
fgetc(3)
通过传入的FILE *参数找到该文件的描述符、I/O缓冲区和当前读写位置,判断能否从I/O缓冲区读到下一个字符,如果能就直接返回该字符,否则调用read(2)把文件描述符传进去,让内核读取该文件的数据到I/O缓冲区,然后返回下一个字符。(对于C标准I/O 来说打开的文件由FILE *指针表示,对于内核来说,打开的文件由文件描述符标示,文件描述符从open系统调用获得,在使用read、write、close系统调用时都需要传文件描述符。)
fputc(3)
判断该文件的I/O缓冲区是否有空间再存放一个字符,如果有则直接保存在I/O缓冲区中并返回,如果I/O缓冲区中已满就调用write(2),让内核把I/O缓冲区的内容写回文件。
fclose(3)
如果I/O缓冲区中还有数据没写回文件,就调用write(2)写回文件然后再调用close(2)关闭文件,释放FILE结构体和I/O缓冲区。
open、read、write、close等系统函数称为无缓冲I/O(Unbuffered I/O)函数,用户程序在读写文件时既可以调用C标准I/O库函数,也可以直接调用底层的Unbuffered I/O函数,那个各自使用场景是什么呢?
- 用Unbuffered I/O函数每次读写都要进内核,调一个系统调用比调一个用户控件的函数要慢很多,所以在用户程序开辟I/O缓冲区还是必要的,用C标准I/O库函数比较方便。
- 用C标准I/O库函数要时刻注意I/O缓冲区和实际文件有可能不一致,在必要时调用fflush(3)。
- UNIX的传统是Everything is a file,I/O函数不仅可以读写文件还可以读写设备。在读写设备时通常是不希望有缓冲的。比如网络设置的读写就希望是实时读写。
C标准库函数是C标准的一部分,而Unbuffered I/O函数是UNIX标准的一部分。只有在UNXI平台上才能用Unbuffered I/O函数,windows上不行。
2. 文件描述符
每个进程在linux内核中都有一个task_struct结构体来维护进程相关的信息,称为进程描述符(Process Descriptor),而在操作系统理论中称为进程控制块(PCB, Process Control Block)。task_struct中有一个指针指向files_struct结构体,称为文件描述符表,其中每个表项包含一个指向已打开的文件的指针,如下图所示:
aaarticlea/png;base64,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" alt="" />
用户程序不能直接访问内核中的文件描述符表,而只能使用文件描述符表的索引(即0、1、2、3这些数字),这些索引就称为文件描述符,用int型变量保存。当调用open打开一个文件或创建一个新文件时,内核分配一个文件描述符并返回给用户程序,该文件描述符边项中的指针指向新打开的文件。当读写文件时,用户程序把文件描述符传给read或write,内核根据文件描述符找到相应的表项,再通过表项中的指针找到相应的文件。
程序启动时会自动打开三个文件:标准输入、标准输出和标准错误输出。在C标准中分别用FILE *指针stdin、stdout、stderr表示。这三个文件的描述符分别是0、1、2,保存在相应的FILE结构体中。头文件unistd.h中有如下的宏定义来表示这三个文件描述符:
#define STDIN_FILENO 0
#define STDOUT_FILENO 1
#define STDERR_FILENO 2
二、open/close
1. open
open函数可以打开或创建一个文件。
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
在Man Page中open函数有两中形式,一种带2个参数,一种带3个参数,在C代码中open函数的声明是这样的:
int open(const char *pathname, int flags, ...);
最后的可变参数可以是0个或1个,由flags参数中的标志位决定。
pathname参数是要打开或创建的文件名,可以是相对路径也可以是绝对路径。flags参数有一系列常数值可供选择,可以同时选择多个常数用按位或运算符连接起来,所以这些常数的定义都以O_开头,表示or。
必选项:以下三个常数中必须指定一个,且仅允许指定一个。
- O_RDONLY 只读打开
- O_WRONLY 只写打开
- O_RDWR 可读可写文件
以下选项可以同时制定0个或多个,和必选项按位或起来作为flags参数,可选项有很多,以下是其中一部分可选项:
- O_APPEND 表示追加。如果文件已有内容,这次打开文件所写的数据附加到文件的末尾而不覆盖原来的内容。
- O_CREAT 若此文件不存在则创建它。使用此选项时需要提供第三个参数mode,表示文件的访问权限
- O_EXCL 若同时指定了O_CREAT,并且文件已存在,则出错返回。
- O_TRUNC 如果文件已存在,并且以只写或可读可写方式打开,则将其长度截断为0字节。
- O_NONBLOCK 对于设备文件,以O_NONBLOCK方式打开可以做非阻塞I/O(Nonblock I/O)。
open函数与C标准I/O库的fopen函数有些细微的区别:
- 以可写的方式fopen一个文件时,如果文件不存在则自动创建,而open需要制定O_CREAT才会创建文件,否则文件不存在就出错返回。
- 以w或w+方式fopen一个文件时,如果文件已存在就截断为0字节,而open一个文件必须明确指定O_TRUNC才会截断文件,否则直接在原来的数据上改写。
第三个参数mode指定文件权限,可以用八进制数表示,比如0644表示-rw-r--r--,也可以用S_IRUSR、S_IWUSR等宏定义按位或起来表示。注意:文件权限由open的mode参数和当前进程的umask掩码共同决定。
Shell进程的umask掩码可以用umask命令查看:
$ umask
用touch命令创建一个文件时,创建权限是0666,而touch进程继承了Shell进程的umask掩码,所以最终的文件权限是0666&~022 = 0644。
2. close
close函数关闭一个已打开的文件:
#include <unistd.h>
int close(int fd);
返回值:成功返回0,出错返回-1并设置errno
参数fd是要关闭的文件描述符。当一个进程结束时,内核对该进程所有尚未关闭的文件描述符调用close关闭,所以即使用户程序不调用close在终止时内核也会自动关闭它打开的所有文件。
由 open 返回的文件描述符一定是该进程尚未使用的最小描述符。由于程序启动时自动打开文件描述符0、1、2,因此第一次调用 open 打开文件通常会返回描述符3,再调用 open 就会返回4。可以利用这一点在标准输入、标准输出或标准错误输出上打开一个新文件,实现重定向的功能。例如,首先调用 close 关闭文件描述符1,然后调用 open 打开一个常规文件,则一定会返回文件描述符1,这时候标准输出就不再是终端,而是一个常规文件了,再调用 printf 就不会打印到屏幕上,而是写到这个文件中了。
三、 read/write
1. read
read函数从打开的设备或文件读取数据
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
返回值:成功返回读取的字节数,出错返回-1并设置errno,如果在调read之前已达到文件末尾,则这次read返回0
参数count是请求读取的字节数,读上来的数据保存在缓冲buf中,同时文件的当前读写位置向后移。这个读写位置和使用C标准库时的读写位置有可能不同。返回值类型为ssize_t表示有符号的size_t,这样既可以返回正的字节数(正数)、0(到达文件末尾)也可以返回负值-1(出错)。read返回时,返回值说明了buf中前多少字节是刚读上来的。有些情况下实际读到的字节数(返回值)会小于请求读的字节数count,例如:
- 读常规文件时,在读到count字节之前就到达文件末尾了。
- 从终端设备读,通常以行为单位,读到换行符就返回了。
- 从网络读数据,根据不同的传输层协议和内核缓存机制,返回值可能小于请求的字节数。
2. write
write函数向打开的设备或文件中写数据。
#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);
成功返回写入的字节数,出错返回-1并设置errno
写常规文件时,write的返回值通常等于请求写的字节数,而向终端设备或网络写则不一定。
3. 阻塞
读常规文件是不会阻塞的,不管读多少字节,read一定会在有限的时间内返回。从终端设备或网络读则不一定,如果从终端输入的数据没有换行符,调用read读终端设备就会阻塞,如果网络上没有接收到数据包,调用read从网络读就会阻塞,至于会阻塞多长时间也是不确定的。如果一直没有数据就一直阻塞在那里。写操作同理。
当进程调用一个阻塞的系统函数时,该进程被置于睡眠状态,这时内核调度其他进程运行,直到该进程等待的事件发生了(比如网络上接收到了数据包,或者调用sleep指定的睡眠时间到了)它才有可能继续运行。与睡眠状态相对的是运行状态。在linux内核中,处于运行状态的进程分为两种情况:
- 正在被调度执行。CPU处于该进程的上下文环境中,程序计数器(eip)里保存着该进程的指令地址,通用寄存器里保存着该进程运算过程的中间结果,正在执行该进程的指令,正在读写该进程的地址空间。
- 就绪状态。该进程不需要等待什么事件发生,随时可以执行,但CPU暂时还在执行另一个进程,所以该进程在一个就绪队列中等待被内核调度。
如果在open一个设备时指定了O_NONBLOCK标志,read/write就不会阻塞。
四、lseek
lseek和标准I/O库的fseek函数类似,可以移动当前读写位置(或者叫偏移量)。
#include <sys/types.h>
#include <unistd.h> off_t lseek(int fd, off_t offset, int whence);
参数offset和whence的含义和fseek函数完全相同。对于whience的设置有三种形式,SEEK_SET,SEEK_CUR,SEEK_END,和fseek一样,偏移量允许超过文件末尾,这种情况下对该文件的下一次写操作将延长文件,中间空洞的部分读出来都是0。
若lseek成功执行,则返回新的偏移量,因此可用以下方法确定一个打开文件的当前偏移量:
off_t currpos;
currpos = lseek(fd, , SEEK_CUR);
设备一般是不可以设置偏移量的。如果设备不支持lseek则lseek返回-1,并将errno设置为ESPIPE。注意fseek和lseek在返回值上有细微的差别,fseek成功时返回0失败时返回-1。要返回当前偏移量需调用ftell,而lseek成功时返回当前偏移量失败时返回-1。
五、fcntl
STDIN_FILENO在程序启动时已经被自动打开,所以我们要改变STD_FILENO的打开方式(比如设置O_NONBLOCK)必须用open函数重新打开。另外一种方法就是用fcntl函数改变一个一打开的文件的属性,可以重新设置读、写、追加、非阻塞等标志,而不必重新open文件。
#include <unistd.h>
#include <fcntl.h> int fcntl(int fd, int cmd);
int fcntl(int fd, int cmd, long arg);
int fcntl(int fd, int cmd, struct flock *lock);
这个函数和open一样,也是用可变参数实现的,可变参数的类型和个数取决于前面的cmd参数。
下面的程序使用F_GETFL和F_SETFL这两种fcntl命令改变STDIN_FILENO的属性:
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#define MSG_TRY "try again\n"
int main(void)
{
char buf[];
int n;
int flags;
flags = fcntl(STDIN_FILENO, F_GETFL);
flags |= O_NONBLOCK;
if (fcntl(STDIN_FILENO, F_SETFL, flags) == -)
{
perror("fcntl");
exit();
}
tryagain:
n = read(STDIN_FILENO, buf, );
if (n < ) {
if (errno == EAGAIN) {
sleep();
write(STDOUT_FILENO, MSG_TRY,
strlen(MSG_TRY));
goto tryagain;
}
perror("read stdin");
exit();
}
write(STDOUT_FILENO, buf, n);
return ;
}
六、ioctl
ioctl用于向设备发控制和配置命令,有些命令也需要读写一些数据,但这些数据是不能用read/write读写的,称为Out-of-band数据。也就是说,read/write读写的数据是in-band数据,是I/O操作的主体,而ioctl命令传送的是控制信息,其中的数据是辅助的数据,例如在串口线上收发数据通过read/write操作,而串口的的波特率、校验位、停止位通过ioctl设置,A/D转换的结果通过read读取,而A/D转换的精度和工作频率通过ioctl设置。
#include <sys/ioctl.h>
int ioctl(int d, int request, ...);
d是某个设备的文件描述符。request是ioctl的命令,可变参数取决于request,通常是一个指向变量或结构体的指针。若出错则返回-1,若成功则返回其他值,返回值也是取决于request。下面的程序使用TIOCGWINSZ命令获得终端设备的窗口大小。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
int main(void)
{
struct winsize size;
if (isatty(STDOUT_FILENO) == )
exit();
if(ioctl(STDOUT_FILENO, TIOCGWINSZ, &size)<) {
perror("ioctl TIOCGWINSZ error");
exit();
}
printf("%d rows, %d columns\n", size.ws_row, size.ws_col);
return ;
}
七、mmap
mmap可以把磁盘文件的一部分直接映射到内存,这样文件中的位置直接就有对应的内存地址,对文件的读写可以直接用指针来做而不需要read/write函数。
#include <sys/mman.h>
void *mmap(void *addr, size_t len, int prot, int flag, int filedes, off_t off);
int munmp(void *addr, size_t len);
该函数各参数的作用图示如下:
aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAAAfsAAAGFCAIAAAB1wc00AAAgAElEQVR4nOzdaVRb+X34f7fpaX9p0tOetqe/R/3/2qan56TNJJNkJpNJJuPMTCYZb2MbL2MbY+yx8YLBuzE2BmxjdjCbzGJ2EPtmMGLfV7FKgFgFAu0S2nfpXunq/+CeqAq2J57ri8TyeZ08yMhfvveK5Y24uvd7d9gBAABsDzvcvQMAAABcBIoPAADbBRQfAAC2Cyg+AABsF1B8AADYLqD4AACwXUDxAQBgu4DiAwDAdgHFJ0Kr1U5MTPT29vYAkvT29k5NTZnNZnd/bQHYyqD4RLBYrFu3bt28efMOIElAQMCdO3c4HI67v7YAbGXrUnwURRUKBZvNFovFb/5RVqtVrVYvLS0JBAIEQb7tRq1Wq0qlwj/carU6HkcQRCKRLC4uyuXybzvn6wwNDV2+fLm6uroOkKSiouLChQt9fX1kfY0AAC9bl+IbjcaRkZGYmJiqqirnx202m0AgGB0dfeVvAovFMjU1lZycXFhYqFarv+1GLRbL5ORkcnJyUVGRyWRyPK7ValtaWmJjY0msCYPBSEhIcN4KeEsGgyEyMrKzs9PdOwLAVrYuxTebzcPDwz4+PpGRkc6PW63WmZmZ2tpaNpuNP4JhGIZh+P9HUXRycvLmzVvBwSEymezbbhRF0YmJidu3bz948ECn0zkeNxqNtbW1Z86cWfPrx8F5HxyP2Gy21/2n3W5nMBixsbEEfi2B1zEYDGFhYV1dXe7eEQC2snUpPoZhbDb7xo0bDx8+lEqlbDZbJBIhCIIgiEgkmp+fVyqVdrsdQRCFQrG8vMzn87VardFoXFpaCgsLu3v37tzc3NLSEp/Pt1gsztOiKKpWq5eXl9lstlqtxktttVq1Wq1YLB4aGrp7925oaKhWq8Xnl8vlfD6/rq7u/PnzlZWVCIJotVqdTqdQKFZWVjQaDT6Gy+VKpVIEQTAMMxqNAoFgcXFRJpNZrVaLxSKVShcXF4VCoeNYExSfdFB8AFxgvd655XA4t27duux3uampKTk5OSkpaWxsbHV1taWlhUqlslgso9E4MTFBo9GeP39OoVAyMzP7+vqmpqYiIyPPnTtXWlqamZkZExPT09ODoig+J4qiKysrLS0tpaWlMTExVCpVoVCYzealpaWOjo66uronT554eHjcvx+s0+k0Gs3ExERjY2N5efmdO3c8PDyqq6uFQmFNdU1OTk5xcTGFQunr65ucnGxsbGxsbCwoKBgcHBSLxX19fV1dXTU1NbW1tRwOZ2xsrKOjg0ajlZaWLiws4HsCxScdFB8AF1jH4t+4ccPX13dgYKC4uPjSpUuJiQkrKytUKvX8+fM1NTWzs7Px8fFZWVmjo6MPHz708PCorKycnp4ODw//+szXDQ0NdXV1/v7+wcHBUqkUn9NisczNzbW2tnZ2dgYGBnp6eo6Ojs7NzWVnZ1dWVg4ODubm5n711VfBwcEKhaKzs5NCoXR1dfX29oaHh3t4eFRVVfH5/LjYuAMHDiQkJJSWllZUVKSmptbV1TGZzLi4uDt37jx//vze3XsdHR0jIyPt7e0dHR0PHjwoKioaHx9vbm6enJzE9wSKTzooPgAusL6v8R89eoQgiEAgiIyMDA6+LxQKu7q6rl69WlVV1dXVdeHChdzcXK1Wm5ub6+/vz2KxeDxeWFjY3bv3xGKxQqGgUChXr1x1vLK2Wq0CgaC/v39wcDAxMfHQoUMvXryorq6+cePG7OwsvtFHjx49fPhwYWEhKir64cOH+JurfX19Fy9erKys1Ol0xcXF3qe8u7q68OP7Z8+ebWlpmZ6ezsnJuXz5clFR0blzPqGhocXFxQwGY2ho6OrVq/7+/llZWd3d3Y43nKH4pIPiA+AC61j827dv4+/cCoXC6OjokJAQoVDY2dl55cqVqqqqhYWFiIiIhw8ftre3l5aWVlVV6fV6LpcbHh4eGhoqlUrlcvnTp6k3btycn5/H59TpdDQa7dGjRzQaLS8vz9PTs7KyMjc398L58zwez263r6ysREREhIWFTUxMBAYGPnz4ED/Q39/ff/ny5aqqKq1WW1xc7OvrOzo6iqJoRUXFF3/4Q3FxcWtra01NTUNDA5vNLiktvX7jxunTp+/evdvf39/S0hIYGHjmzBl/f/+WlhZ8T6D4pIPiA+AC6/XO7dLS0s2bNyMiIjAMEwgEUVFRwcHBQqGwo6PDz8+vsrJSr9fX1NQEBASUlpayWCz8vdyVlZXHjx8HBwdLJBK5XE6hUK5fvz43N4dPu7KyEhwcfPXqVbFYXP+i3uukV1VVVVVlpZeXV0tLC36qz40bN0JDQ5eWliIiIi5duiQQCIxGY11d3alTpyoqKjQaDZVKvXDhwtDQEIIgNBrtyJEjpaWlPB5PIBAolUqpVDoxMbGwsEClUi9dulRaWrq4uDg7O9vQ0BAQEBAXF4fvCRSfdFB8AFxgvc7HHxgYuHz5clBQEJ/Pl0gkFArl7t27fX19RUVFZ8+effbsmVQqra6uPn36dHBwMIVCoVKpw8PDdDo9ICDg+vXrExMTKpUqLy/v2rVrg4OD+Ju3EokkISHB19eXTqfX1db5nPPBP+r+/fs3btyorq6uqam5efNmQEAAi8Wi0Wjnz/tERUXV1dXl5eX6+JxLS0tjMBhJSUne3qdramrUavX8/HxkZGRQUFBVVdXAwACHwxkZGUlOTu7v7+/o6CgrK6PRaDk5OTQabWBgoKqqynG2OBSfdFB8AFxgXYqv1+snJibKy8ufP3++vLxsMBjGx8fr6+uHh4c7OjqKiora2tpYLFZxcXFoaGh0VFRoaOiZM2fu3LnT0NBQWVlZXl4+NzeHX5BVV1c3PT2NnxaJIMjU1FRBQUFXV9fCwkJDQ0N/f79cLh8bG8vIyCgoKOjv7+/u7q6trZ2fn5fL5Y2NjU+fPq2pqRkbG2tsbGxtbWUwGI2NjVQqtbe3V6VSWSwW/Ah+dnZ2V1eXQCBgs9nl5eUtLS3Dw8P4C//a2tq6ujo6nY7vEv4Eofikg+ID4ALrdVTHZrNZrVabzYZfu+R4BIcgSFdXV0xMDJ1Ot1gsYrGYkpJy9erV8fFxfIDzR9lsNscVUhiG4QOc/8lms6EoiiAI/jg+wG6344+jKGr7I6sTfBPOH+sYg6KoYxOO/3S+CAuKTzooPgAu4J6V1KxWa09Pz+PHj2tra5eWlhgMRl5eXnFxsUKhcMv+fFtQfNJB8QFwAbetnYlfjVVaWtrY2Njc3NzT08Pn8921M98WFJ90UHwAXMCdqyXrdDoOhzM7O7uysuK8Es7GB8UnHRQfABeA9fGJgOKTDooPgAtA8YmA4pMOig+AC0DxiYDikw6KD4ALQPGJgOKTDooPgAtA8YmA4pMOig+AC0DxiWAwGE+ePDEYDO7eka3DYDBERETAXQ8BWFdQfCKGhob8/C6XlJSUA5IUFhaev3Chv7/f3V9bALYyKD4RAwMDHh4Hr1+/fheQ5Pbt2wcOHhweHnb31xaArQyKT8TY2NiDBw9mZ2e5gCRzc3N3797t7u5299cWgK0Mik8Eg8GIj4/X6/Xu3pGtw2AwhIeHw3F8ANYVFJ8IOFeHdHCuDgAuAMUnYrMX32az6fV6sVis0WgcK1G7FxQfABeA4hOx2YuPIMj8/Hx6enpra6vzuv9uBMUHwAWg+ERswOKbzeaFhQUGg/Emg1EUnZqaOnHiRFhYGBQfgO0Dik+E24uP3+pLq9WKxWK1Wm2z2WQyGYVCCQwMxO/5haIo/q9arRY/boNhGIqiGo1GIpEYjUY+n+/j4xMYGGi32202m9lsxm8m7C5QfABcAIpPhHuLj2GYyWRis9k9PT2tra1lZWVyuZzH4/n6+u7du5fJZEokkunp6aampoKCgsLCQi6Xi2GYTqdjMplNTU15eXmNjY0ikcjPzy8oKAg/wvP8+XM2m+2Wp4OD4gPgAlB8ItxbfKvVyufz09LSMjIy+vv7KRQKj8dbXFw8efLkZ5991tjYuLi42NTUVF1dnZqa6uHhkZOTo9frOzo6srKy6urqnj17Fh8fLxKJLl++HBAQsLCwkJmZmZSUNDk56Zang4PiA+ACUHwi3F58NpsdGBh47dq158+fDwwMaDSalZWV69eue530UigUGo2GwWCMj4/TaLQTJ07cunWLy+VevXq1qqrKarWq1eq5uTmRSOTr63vo0KGYmJjq6mqtVuuW5+IAxQfABaD4RLj9qI5KpaqsrPT29j558uSdO3cYDIZIJHrw4MHFixetViuPx0tPT09LS6uoqLhw4cKVK1fm5+f37Nnd0NDgmEQkEl26dOlXv/rVwYMHm5qaEARxy3NxgOID4AJQfCLc/hpfo9EsLi6Ojo4+e/bM29s7JydHIBCEhIRcvHjRYDDQaLSDBw82NjbOzc0FBgb6+fktLS0dOXI4KirKYrFgGIZhGH5U58yZM4mJiVeuXOnq6nJv9KH4ALgAFJ8I9xYff681Pz9/aGhobGwsLy+vra1tdXU1Pj5+7969PT091dXVHh4eDQ0NTCbzxo0b586dW1paSkpKOnbsWFlZWW9v7+zs7MTExJkzZ27evDkzM5OUlOTv7z84OGi1Wt3yjOxQfABcAopPhNtf4/N4vJycnIKCgq6urpGREa1WazabBwcH/f39i4qK2Gw2hUJJTk4eGxurr69PSUnhcrkCgSAjI+P+/fsZGRnt7e0jIyPx8fGpqanz8/NisTgnJ6eiosKNL/Oh+AC4ABSfCLefj4+fjK9SqQwGgyPTKIoqFAqVSmWz2QwGg0KhMJvNCILo9XoEQWw2m8lkWl1dVSgUer3eZDJptVqdTmc2m/Hz8R1n7rsFFB8AF4DiE+H24m89UHwAXACKTwQUn3RQfABcAIpPBBSfdFB8AFwAik8EFJ90UHwAXACKTwRefI1G4+4d2Tqg+AC4ABSfiPHx8cjISJFIpP0jvV6/Zu1Jq9VqMBi0TtaMwTAMP5Hmm8e8yTwoiup0ujVjnE+uf8NtIQiyZh6DwbBmHnxVzjXzOC+5jM/zZ8es2WepVBoaGgr3uQVgXUHxiaDT6WdOn0lJScn+o+rqaoFA4DxmdXW1trY220llZSWPx3MMQBCEw+GUlpY6j6mqquJyuY4xNpvtFfNUVDhvy2q1CgSCgoLCNdtSKpWOMSiKrqyslJSUOI8pLS0ViUTOY5aXl4uKih0DcnJyaDSaSqVas63c3Nxsp0HV1TUmk8l5Hg6Hk5OTs2Z/jEaj8zxcLreoqMgxIC0t7dQp78HBwbf92gAAXg+KT8TAwMDhQ4cDAgKC/iglJWVxcdF5jEAgSEtLC3KSmJg4NzfnGGCxWKampmJjY/93xP37SUlJs7OzjjE2m43P56enp6+Zx3llYxRF2Wz248ePncckJSZJpVLHGARBZmdno6OjncfExsZyOBznMTMzM5GRUY4BwSEhWVlZMplszbZCQ0P/d5eDg1NSKM43eUcQZHJyMjg4eM3zch6Doujs7GxERIRjSMCdO4cOHR4aGnrbrw0A4PWg+EQwGIwnT544Jwy8JYPBEB4e3tnZ6e4dAWArg+ITAefqkA7euQXABaD4REDxSQfFB8AFoPhEQPFJB8UHwAWg+ERA8UkHxQfABaD4REDxSQfFB8AFoPhEQPFJB8UHwAWg+ERA8UkHxQfABaD4REDxSQfFB8AFoPhEQPFJB8UHwAWg+ERA8UkHxQfABaD4REDxSQfFB8AFoPhEQPFJB8UHwAWg+ERA8UkHxQfABaD4REDxSQfFB8AFoPhEQPFJB8UHwAWg+ERA8UkHxQfABaD4REDxSQfFB8AFoPhEQPFJB8UHwAWg+EQwGIz4+Hi46yGJDAZDREREX1+fu3cEgK1s2xUfQRC9Xm+xWN5mkrGxsQcPHkxPT88DkjCZzICAgKqqKscjCwsLq6urjs85hmFms3l5edn5oxYWFpRKpfMYo9G4ZuaFhQWz2ew8RqFQrBkjFottNhuGYfgYFEV5PN6aMXK53DEA/0bicrlrNqTT6ZzHaDSahYUF5zF8Ph9FUecxUql0zRiZTGaz2RwDrFarSCRyHrOwsKBSqZzHGAyGxcVF50nYbLbJZHLekEKhYLPZzmMkEsmanZFIJGt2Ri6XW61WxwCLxSIQCJzHLC4uajQa553RaDRLS0trnvWan7jV1dU1OyMWixEEcQxAUXTNs3Z+aisrK1wuVywWm81m5/0Hf9b2Kj6GYTwer6WlZWlp6W3mGRgYOHTo0O3bt+8DktwJuLNz504vLy/HI6Ghoc3Nzc5fO6lUmpKS4vxRjx49GhgYcB7D5/PXzBwaGiqVSp3HdHd3BwcHO4+pqqqyWCyOduh0uqysrDXzdHR0OLdPo9E8e/bMeZ6wsLCZmRnnMUwmMywszHmS/Pz8Nb8VGhoaHjx44DymtbXV+VeUwWAoKysLDQ11ftZ0Ot15zPLycnR0tPMkERERfD7fOcQ9PT3h4eHOY54/f67RaJx3pra29tGjR2uetcFgcAxQKBQFBQXOOxMVFcVkMp13hslkxsXFrXnWzr+87XZ7Y2Pjmp2pqalx/uWt1WorKyvX7AwuPDw8NTU1PT29rKxMKBQ6779Op+NwOMvLy3K53Gg0Oj99gNtexbdYLC9evDjp6fn8+fO3eWlAp9PPnDmTnJycCkiSmJh48MDBgIAAxyMZGRlraq5UKsvKypw/KjMzc3Jy0nmMRCJZM3NGRoZCoXAeMzY2lpaW5jymvb0dQRDHt4TBYHj+/PmaeUZGRpxrrtPpqqurnefJysricDjOY+bn57OyspwnefHihdFodP7e6+vry8jIcB5Dp9OdXxEbjcaWlhbnMZmZmVNTU86viEUiUV5envMkOTk5EonEOXkMBiMnJ8d5TFdX15pfP11dXZmZmWuetdFodAzQaDT19fXOO5OXlzc/P++8M/Pz8wUFBc6T1NfXq1Qq55+g/v7+7Oxs5zGdnZ0ajcYxQK/Xt7e3r9kZx1OrqKioqKior6+XSCTO+89mszMzM5OTk6urq7u7u4eHh5eXl00m08s/wtvW9iq+SqVKTEj40f/8T1JS0tsc2GEymUlJSc7f5eAtGQyG2NjYkZERd+8I2MRWV1e7u7uLi4vz8vISExNDQ0MrKirW/HmxzW2v4vP5/Fu3bv3DP/yDv7+/XC4nPA+cq0M6OFcHkMVsNqtUKh6PNz09zePxnI84oSjKZrNZLJZEIjEajc5/kG0T26j4NpttcnLy6NGj3/nOd/bs2bOwsEB4Kig+6aD4wAWMRmNJSUlkZGReXl5jYyOLxVIoFM4H9La8bVR8s9nc2Nj43nvv7dix44MPPujs7CT8ZYbikw6KD1wAwzCdTjc2NpaVlRUSEhIVFVVZWcnj8VAUdfeuucg2Kr5Go0lNTfunf/qnHTt2/Md//EdaWhrhA/FQfNJB8YGLKZXK+vr67OzsmZmZ7fOe3DYqvlAovHPnzo4dO3bs2PH3f//3fn5+a84feHNQfNJB8cFGgKKoTCZTqVRb9VX/dik+hmETExOHDx/Gi/+Xf/mXu3fvJnxWPhSfdFB8sBFotdr29vaampqxsTGlUrn1zujfLsVHEIRGo73zzjs7/ujnP/95c3MzsUP5UHzSQfHBRmAymRgMxpMnT0JCQsrKyiYnJ9Vq9Vbq/nYpvk6nS0tL+/73v+8o/r/+678+efKE2N9uUHzSQfHBBoFf3d3R0REZGRkcHEyj0Zyv4NvstkvxZTJZeHj497/3vb/927/9m7/5m+9+9//8y7/8y7Vr14hdhwXFJx0UH2woNptNpVI1Njbm5+e/5aIsG8p2Kb5ara6urj7v43P06NGPd+7cv//LS5cu5ebmEnuPHopPOig+2IBsNpvVaoWjOpvYwsJCdnZ2f3//20wCxScdFB9sfBiGqdVqmUzmfB3v5rLtij8/P5+ent7b2/s2k0DxSQfFBxufzWaj0+kFBQVDQ0Ob9PYYUHwioPikg+KDjc9ms01PT8fExOBLeSsUik13wAeKTwQUn3RQfLBZiMXi4uLiu3fvFhUVcbnczXW9LhSfCCg+6aD4YBMxGo2tra337t0rLi5+m1V4XQ+KTwQUn3RQfLC5WK3WycnJwcHBzXW2PhSfCCg+6aD4ALgAFJ8IKD7poPhgs0NRFEGQDf5eLhSfCCg+6aD4YLOTyWQzMzMSiWQj31oLik8EFJ90UHyw2S0vL1MolKKiIqFQuGGjD8UnAopPOig+2OyMRmNnZ+eDBw8KCgqEQuHGPLwDxScCik86KD7YAlAU7evrCw0NpVKpEolkA94+F4pPBBSfdFB8sDVYrdaBgYHIyMj29vYNuPwOFJ8IKD7poPhgK5mYmGAwGDqdzt07shYUnwgoPumg+AC4ABSfCCg+6aD4ALgAFJ8IKD7poPhgq7JYLCaTidgNVkkHxScCik86KD7Yqvh8/uDgIJfL3Qgn6UPxiYDikw6KD7aqxcXF2NjY7OxskUjk9vM1ofhEQPFJB8UHW5XVau3p6QkNDX3+/LlWq3XvzkDxiYDikw6KD7a2qqqq0NDQvr4+i8Xixt2A4hMBxScdFB9sbTqdLisrKyUlZWVlxY27AcUnAopPOig+2PJWVlaqq6tZLJYb9wGKTwQUn3RQfLAdaDQavV7vxh2A4hMBxScdFB8AF4DiEwHFJx0UHwAXgOITAcUnHRQfbCsmk8lgMLj+miwoPhFQfNJB8cG2wmQye3p6VldXXXxNFhSfCCg+6aD4YFtpaWkJCwvr6elBEMSV24XiEwHF/7ZsNptarRaJRCqV6pUDoPhgW9FoNKmpqZmZmS6+VRYUnwgo/rdlNpvb2tru3r1bWlr6ygFQfLDddHd3R0dH9/b2uvJlPhSfiD9bfAzDbDYbfmtj/P+v+TWOYZjVan3dg84fvuZfX36rB/sj5//v/ODL4x1bwTf08r++/ODLI1/51PBH1uwkhmEIgszPz588efL+/fuv+HxB8cH2YzQaU1PTMjIypFKpyzYKxSfidcXH02YwGHQ6nVQq5XA4Go1Gq9Xy+XyxWIyvp4GPUSgUXC5XpVKhKGq1Wk0mk16vVyqVHA5HoVAYDAaxWMzj8QwGg/2PFdZqtVwul8fj6XQ6vKomk8loNGq1WoFAoFarlUqlSqUymUwWi0WlUqlUKsdrB3wGk8mk0+m0Wu3y8rJYLDYajXK5fHl5WavV4k1HEESlUi0vLwsEArPZbLPZzGazwWAwGo2rq6scDketVjumwp8mn8/n8/mO/TSbzRKJBJ8T/2VgtVoNBoNQKJybm7tw4eKDBw9e+SmF4oNtiE6n5+fnz8zMuGyLUHwiXld8s9k8NzdXW1vb0NBQW1v78OHDnJycjo6O9PT0J0+e0Ol0PH9TU1PNzc1FRUWVlZVsNlssFre1tVVXVzc1NUVFRSUnJ7e3txcVFcXGxtbX1yMIYrFYuFxub29vbW1tTk5OeXm5WCyWyWTt7e319fW1tbWPHj3q7u7OyMjIysoSi8VSqbSysrKurk6pVOI7ZrValUplX19fcXFxX19fQkJCeHh4S0tLXV1dTExMYWGhWq1GEGRpaamuri41NTUiIqK/v99gMIyOjtbU1HR3d1Op1MDAwLS0NIlEolQq8Y9tb29/8uTJvXv3Xrx4gf/6GRkZqauro1Kp5eXlUqkUQRAul0un00tKShITEz/99LOwsLBXfkqh+GAbslgs+Cs8l20Rik/E64qv1WorKys/+eSTU6dOMZnMhISEn/3sZ3FxcR0dHf7+/l9//bVMJmOxWPfv329vb19cXLx379794Pt9fX2nTp3au3dvR0dHaWnpxx9/fOnSpf7+/qSkpM8//3x5eZnH46WmplKpVLPZTKcPHT9+IiEhYXp62tvb+zcf/yYmJiYyMpJOp1++fHnfvn1qtVogEDx8+LCyslKtVisUCoVCIZfL2Wz2vXv3/uu//quhoaGjo+PLL7/8wx/+0N/fX1lZ+dFHHzU3NxsMhq6urpKSEjqdfuXKFW9vb5lMhj8FvOnJycmfffZpREQEm80+duzYr3/96+zs7IqKijt37uz87c6enp7Jyclbt26NjY3x+XxPT8+UlBQulxsbG1tRUTE9PV1YWPjTn/708ePHr/yUQvEBcAEoPhHfcBx/YWHh+vXroaGhdrt9YGDgyy+/rK+vV6vVhYWF3t7eTCaztrbWy+vk2NgYk8mMjIw853NudnY2IyPDz8/PYrHMz8/7+PhER0fb7fbR0dHdu3b19PT09PT4+/sPDw/b7XatVkulUvft2ycSiXJycg4dPsThcOx2u9FobGpq+uroVwwGg8vlZmdny+VysVj89OnTp0+fUqlULpfb2dn5+ee/U6lUcrk8PDz81KlTVquVx+N5enqmp6dbrVa5XD4+Pl5dXR0SErJz504EQRgMxv79+8vKyux2u8FgKC0t+eCXHyiVyuzs7C+//JLP59vtdplM9vXXX1+7di0tLe38+fOzs7OTk5O3b98+efJkZWXlmTNnNBoNhmEqler69esPHz585acUig+AC0DxifiG4s/Pz1+5cgUv/uDA4MEDBxsbG1UqVUFBwfnz50dHR1NTnx45criurq6jo6Oqqqq1tZXD4SQlJV29etVgMCwsLFy4cCE2NtZut4+Oju7Zs6evr6+2ttbT05PJZNrtdgRBOjo69uzZs7y8nJWVdf78eTy7NpttYWHh8uXL4eHhvb293d3dJpOJzWZHRkZGRETk5ORwudzm5ubPP/+dRqORy+URERFff/01iqI8Hu/06dPZ2dlKpTI/P//OnTvPnz+Pi4v7eOfHCIIMDQ199dVX9fX1+KaHh4f+8Iffy2Sy1NTUU6dOicViDMOUSmVsbGxwcHBwcMiePXs7Ojra29vLysqamppiYmJOnDiBIAiGYTKZ7NKlS1B8ANxocxcfRVGdTqdWq81m8xt+yHq/czs7O+vn5xccHIxh2ED/wP4v99NoNDymZ8+eZTAYRUVFx48dY2Xfrn0AACAASURBVDAYSqVSq9WazWaxWBwXF+fn56fX6x2v8TEMGx0d3bVrV19fX1dX15EjRyoqKvDnW1tbe+nSJblcnpaWdubMGS6Xi58to1AoUlNTd+3a9eTJk6WlJZvNht9S2Ww2W61Wo9FYV1f32WefKpVKmUwWFhbm7e1tsVh4PJ63t3dOTs709PSRI0diY2MNBgONRvvkk99aLJahoSEPD4/y8nKr1apSqUpKSqKjo7VabUpKypEjR5aXl/Gj/xEREb29vVFRUceOHVtYWFCpVPgb0ZmZmZ9//vns7CyKoisrK6dOnXrw4MErzyCC4oNtC8Mwo9Go0WhccLOUzV18uVze1NREpVLZbPYbfsi6Fh9F0bGxsYsXL96/f1+j0bS3tx88eLC8vHx1dbW0tPTs2bN0On18fNzHxycqKmpqamphYWFpaYnD4Tx+/NjX11csFo+Pj3/99dfh4eF6vZ7JZHp4eDQ0NCwtLT169OjatWtzc3Pz8/MFBQXd3d0ikSguLg5/7Y+iqN1uRxBkcHBw965dcXFxa87wtdlsCoWisLBw1xdfzM/P83i8oKCg06dPS6VSPp9/8eJFCoXCYrHOnTsXExPDZrPT09N379ktk8mGh4c/+eSTmzdvstlsBoNRWFgolUp1Oh2FQnn33XdLS0sXFhZaW1urq6vNZnN3d/fhw4dTUlKWl5cXFxfn5+enJicPHjwYHh4+NzdXUVFx5MjRwMDAV974DYoPti2bzTY2Noafx7HeV2Nt7uIbDIaKioqHDx+KRKI3/JB1Lb5are7s7ExPTy8oKBgeHqbRaE+fPq2pqVlZWZmbm8vPz29ublYqlTMzM9HR0Q8ePKirq5NIJAwGIzs7Ozc3t6urq6OjIy0tLT8/f25uTiqVFhQUVFVVCYVCkUhUUFCQnJxcW1s7NTVlsVhmZmYyMjLS09Orq6vxPcEwTCgUpqSkNDY2rtkxBEEWFxeLiorS0tIaGxsZDEZ6enpmZiadTlcqlfX19VQqlcVi9fb23rt3r7Ozc35+Picnp7Ozc2xsbNeuXUeOHAkLC2tsbMSX9tZqtRQK5Zcf/vLKlStxcXFMJtNiseCnZtLp9EePHoWEhLS1ten1evy4UFBQ0P3794eGhlpaWtLS0sbHx1/+lELxwXY2NDQUHh7e2tqKv3pbP5u++MXFRY8fh+EXDVksFvx8cwRB8HPPLRaLxWLB70KA//Jc76M6jiuhnK/Acr48yjES3+dXXjP18hVV9j+9Nsp5vOO0d7VaPTExUVdXJ5PJXrljr9uK8wDn3TabzUNDQ0eOHKmtrXW+LEur1SYnJ3t6egoEgpcvtrLZbCiKOs+MP7LmU7QGFB9sZyKRKCMjA/8bel03tLmLr1Ao8vLyUlJSrFarQqGYnZ1taGgoLy/ncDj9/f2lpaUsFmt6ejo3N7ehoQE/0LElV1nAD9rU1tY+e/bsLZ+aA4ZhJpOpt7d3z549lZWVzslWKBRxcXEeHh5cLvflC3GJgeKDba6+vj42NpbJZK7rgZ3NXfz5+fnExMSqqiqpVNrQ0FBTU5Obm3vjxo3Ozs6kpCQvL6/8/Py6ujofH5+YmFiTyWTfosW3Wq1sNjskJKS6upqse6rZbDaZTFZUVOTj4/P06VO5XI4/jqLowsLCgwcPfH1929ra3vw9828GxQfbHJ1Ox4+dkvUz9Uqbu/gjIyNPnjwZHh6m0+kxMTF1dXV1dXVlZWVCobCiouLGjRtNTU3Dw8NxcXE0Gg0//rAli49hmF6v5/P5JL7Xb7PZdDrd1NTU9PQ0k8l0PFmr1SqRSMbGxmZmZubm5sjaIhQfbHMqlYpKpZaVlb18VJZEm7j4GIa1traGh4dzOJy6urqAgIDy8vLZ2Vm1Wq1SqZ49e+bv749fduTn59fT0+OC4/hbgPOB/jUPOg7grHk/gBRQfADkcrlEIoHX+K9mNBoLCgru3r27vLycl5eXkJAgFAoRBDGbzTwe78mThPj4eIvFUltb6+Pj4ziFcWsUH3+r1vkNUrKmRRBEIpGIxWLnvqMoqlAo+Hw+iqL40m9ms1kulysUCjiOD8AmsomLLxAI4uPjAwMDBwcHnz17Fh4ePjk5iZ8GPjY2hh/JwS998vX17ezsxE8D37zFx8uLL2mJoqhYLJ6fnyfxMA6GYfgyDwkJCYmJifj7AfhGV1ZWsrOz8bNgWSyWTqfjcDjR0dEUCoWstw2g+AC4wCYuvlgsLikpwc9nmp2dzczMzM/PHxsbU6lUs7OzL1684PP5arWaRqOlp6cvLi7iH7Vxiv/KgycvL4vvgCDI8vJyT0+PwWDQarVNTU1xcXGOfcBeteC+Y87X7YDzWvZWq3VlZSUhIaG6unpgYMBoNNrtdpvNJpFIEhISqFTqyMjI9PR0UFAQn88XCAQXL1709fXVaDSO5/I2t2mG4gPgApu4+MS4sfh4E/V6vVarNRgMMpmMx+OpVCo8lPhCygqFQigUqtVqFEURBMGX19fpdDKZbHV1NTs7+/jx4/h69EqlUiKR4Ad2UBRVq9VCoRC/IBafCr8KQaFQCAQCjUbj3H18T3Q6nUQiwdfWt9lsBoOhtrbW398fXzsB/+VhsVgGBgaOHz9Op9PNZrNarebz+fiKC48fP/b398dXSTOZTPianfiy+AQ+pVB8AOx2O35dEekHbB2g+EQQKz5+vmNdXV1aWhqNRouOjj5//nxMTAyPx0NRVCQStbS0tLa25ubmJiUlsVgsNpudk5Pz7Nmzqqqq4ODgoaGhiIiI3/3ud+Xl5d3d3UVFRSUlJUKh0GKxsNns+vr6hoYGCoVSUFCwvLzc1NSUlJRUW1ubmZkZGBiYmpqqUCgce4IgCI/Ha2lpaWpqysnJSU5Oxu9AGxcX95vf/CY/P39lZQX/htPr9cXFxb94//2kpCQmk1laWlqQny+Xy1Uq1aNHj/z9/bVarV6v7+rqqq2tpVKpmZmZq6urBD6lUHwA7Ha7VqtlMBhLS0tv8xfzN4DiE0H4Nb5GoyksLHzvvfcePnzY0NCQmJi4e/fu8PBwHo9XXFyclpbG4XB6enouXbp08+ZNOp0eFBT0i1/8orCwMC0trbm5OSgo6OOPP87Nze3r64uIiDh44ACTyVxaWgoODm5ubuZyueXl5V9++eXTp0/r6urefffdqKiovr6+p0+ffvbZZzQazbEbEomEQqGkp6evrKz09PScOnXq0aNHMpksNDT0Vx9++PTpU3wFZrvdrtVqMzIyfvrTn4aHhzOZzKysrA8++IDD4TiKr1arx8fHL126xGKx6HT64cOHnz17RuBlPhQfALvdrlKpMjIyampq1umMHSg+EW9zHJ9Op3/xxa7q6mq73S6Xy1NTU48dO/bixYvLly93dnba7Xb86Mru3bu7urqKi4sPHjyAH6gRCASJiUne3t58Pl+n01VXV588eZLJZNJotK+//hq/QkokEt29e/fcuXOTk5N/+MMf6urqMAxjs9kHDhxIT0/Hd8BsNg8MDPj4+PT39+Obq6qq+u3OnXw+PyMj4+jRr+bn5x3JNhqNL1682LdvH37/5dHR0Q8++AA/GPXo0SM/Pz+RSEShUC5evKjRaHg83r17927fvo2/B/CtQPEBsNvtVqsVX1mLrHMi1oDiE/GWxd//5f729na73a5Wq8vLywMCAmpraw8fOoz3DkXRvt4+j4MejY2NVCr1+LFj+AfK5fLU1LRz53zkcrlWqy0tLfXy8hofH8/Lyzt9+jRefLlcnpiYePHiRTqdvnvX7tbWVgzDFhYWPDw8MjIy8HmMRmNjY+OhQ4dGRkbwzQ0NDe3cuZPD4RQWFp48eRJfcB9nNpvb2to8PA6Njo4iCDIwMPDhh790Lv7Kysrt27f37NlTUlKSl5eXm5s7NjYGr/EBIKykpCQ9PV0gEKzH5FB8It6y+Hv37H3+/LnRaORyufhCmywWy8vLKyUlxWg0qtXqpqamwMDA8fHx3NzcI0eOIAhis9nkcjmFQjl9+rREIsGXqvf09JyYmKDR6nft+oLJZJrNZoFAEBMTExsbOzEx8fnnnzc2Nlqt1vn5efw1Ph5ii8VCp9M9PDzy8/NNJpNWq21sbDxz+rRarc7JyTl+/Pjy8rJjqTWj0djS0nLgwIGhoSGLxdLf3//BL37B5XJlMtnDhw8vX76Mb/HEiROrq6tGoxFfjp/Am05QfABwvb29GRkZU1NT6zE5FJ+Ityz+h7/80NfXt6mpqbOzs7q6enZ2Vi6XZ2Zmnjlzhkaj9ff3FxYWNjc3LywshIWFeRw8OD09ja8JWlJS8sUXX1Cp1Lm5ubi4uAMHDjQ1NS0uLl69evXevXuDg4N9fX0ZGRnd3d00Gu2TTz7JyclRq9UcDsfLyyssLEyn0+H7IJPJoqNjzp4919nZOTw8nJeX193dLRQKHz16tH///t7eXvw0f6vVKpPJsrOz//DFF+Xl5SqVqry8/Fe/+nV3d/fk5KS/v7+3tzeLxRoeHj58+HB8fHxTU9Po6KhAICCw4isUHwDczMxMamoqftCVdFB8It6y+B988IGnp2d8fHxra6vj9iAKhaKmpoZCoTQ3N09MTOD3w6JSqTk5OW1tbfhBG7FY/OTJk8jISAaDQaVSMzIyWltbdTodn8/PysoqLi5uaWnhcDgajaa+vh5//0csFuOv4ouKipRKpWM31Gp1cXFxenp6S0vL+Pi41Wrl8/m5ubkZGRmdnZ34qnP4EjpVVVVpaWm1tbUymay+vj4rK6ulpYVOp2dnZ2dnZ+NnbdLp9Hv37sXFxTU2Njp+r3wrUHwAcKurq83NzSwWaz0mh+IT8ZbFP3jgIFlrGm8ZUHwAHPCbXqzHzFB8IgifnYmiaFdX1959+xoaGtb7ZjebCxQfABeA4hNB+AoskUiUlpZ2/Pjx5ORkHo/3NvuwxUDxAXABKD4RhF/jIwiiUqkUCoVKpXLBfes3ESg+AM7IXY3cAYpPhNtXS956oPgAOFitVpPJtB4HfqH4REDxSQfFBwCHYZhYLB4ZGXG+FpIsUHwioPikg+IDgMMwbGJioqCggMlkkj45FJ8IKD7poPgAODCZzOTk5L6+PtJnhuITAcUnHRQfAIfx8fGwsLCWlhbSZ4biEwHFJx0UHwAHLpdLoVDa2tpInxmKTwQUn3RQfAAc5HJ5dnY2FJ8EUPyNCYoPgAMUnzRQ/I0Jig+AAxSfNFD8jQmKD4ADFJ80UPyNCYoPgAMUnzRQ/I0Jig+AAxSfNFD8jQmKD4CDXC4vKCjo7OwkfWYoPhFQfNJB8QFwMJvNS0tLYrGY9Jmh+ERA8UkHxQfABaD4REDxSQfFB8AFoPhEQPFJB8UHwAWg+ERA8UkHxQfAAcMwm81ms9lInxmKTwQUn3RQfAAcEAQRCARyuZz0maH4REDxSQfFB8BBLpdTqdT1+HGA4hMBxScdFB8AB5lM9uzZM1gfnwRQ/I0Jig+AA1xzSxoo/sYExQfAQSaTZWVltba2kj4zFJ8IKD7poPgAOMhksszMTCg+CaD4GxMUHwAHhUJRVFTU3d1N+sxQfCKg+KSD4gPggKKoXC7XarWkzwzFJwKKTzooPgAuAMUnAopPOig+AC6wXYqPYZjVakVRdH5+vqCgYHBwEEVRq9WKYRiB2aD4pIPiA+AC26X4er1+cHAwPT394cOHJ06cuHXrVkZGRltbG4IgBGaD4pMOig+AA76uDrHXo99suxRfJBIFBgbucPJXf/VXXl5eZrOZwGxQfNJB8QFwMBqNLBaLx+ORPvN2Kb5Op6NQKH/zN//HUfx/+7d/o1AoVquVwGxQfNJB8QFwkMvlmZmZsMoCcQiCvHjx4oc//KGj+O+//z7h20hC8UkHxQfAQS6Xb+VrbjEnb/I4sU2Mj4/v37/fUfzdu3YJBAJis0HxSQfFB8Bhi6+rg6KoVqtVKpUmk8nxIIZhKIqq1WqlUknsaPsafD7/5s2beO7//h/+4erVq4STDcUnHRQfAAc3r6vjuCHLm7zWxl+Sf6s3muVyeVFRUUBAgPMzxDBMLBZnZGTcuXNnbGzsDaf6Bmq1Oikp6Xvf+96OHTt+8IMfZGRkEDtRxw7FXwdQfAAcZDJZenp6U1MT6TO/tvjOh1M0Gs3Q0BCdTtdoNC//65qPQlGUyWR2dXW9HMTXHboxmUyVlZXHjh3Ly8tzflyv12dlZR09enTNMyd2nMdsNr948eLdd9/dsWPHL3/5S/wiLGJTQfFJB8UHwEGtVtNotNHRUdJnfkXx8QiqVCqRSKTX6zEMm52dvXPnTnR0tEwmw1+/azQahUKBoqjjFT0OQRCdThcXF+fv7y8UCp1jimGYxWJRqVRqtRr/CwCHIIjFYhkYGLhy5QpefMfjZrO5sbHx4sWLTU1NzluxWCwWi+XbPlWbzcZkMg8dOvSd73xn3759y8vL+IM2m81qtVqtVsde/dmpoPikg+ID4GCz2QwGAylHs9d4RfHVanVPT09paWlKSgqFQpmbmxseHj516tRXX31VUVExOTnZ0NAQFRXl4+MTFBQ0MzMzMTGRlJSEX9x0/fr19vb2kJCQL774IiMjg8Vi4XNiGDYzM5ORkREUFOTj41NYWGgymSwWC4vFKiwsjIqKOnjw4Mcff1xSUoJhmMFgGBsby8nJCQ8P37Nnz+7du7u6umZnZ1NSUlJTUyMjo86fvzA4OEjg2eKH8v/xH//xxo0bCoXCbrebzeaBgQE/P78LFy5QqdS5uTkURR2HsF5Xfyg+6aD4ALjAK4rf1tYWEhLS3NzM5XI7OjomJyd7e3tPnDjhedLzxYsXg4ODXV1dMzMzRUVFXl5eWVlZEokkODj4s88+S0lJqa6ubmtru3Xr1u7du4uKijgcDj6nXq8fGxvr7u5mMBhhYWG+vr4TExOtra0REREDAwOzs7NJSUlffvkllUo1GAxVVVVRUVEsFmtqaurRo0cHDx5sb29XKBSPHz/+6KOPUlJSKioqJiYm7H96Ms+bUKlUiYmJP/7xjzMzM/FHTCZTbW0tftbm9773vf/3//6/X/36V35+fmVlZSsrK84v/J3rz2Aw4uLitFrtt90B8Dp6vf7x48c9PT1rHnf+znzdx5I1Zs1IV475Vt/Mb/zTDcBaryh+b2/v8ePHjx79qqSkhMPhmM1mFosVGBgYFxcnk8nMZrNMJpuYmIiPj9+/f39CQoJarU5LTb18+fLKyorNZlOr1bGxsdevXxeJRI45bTabXq9fWlqi0Wh+fn6nT58uLi6Oj4+nUCj4iqC9vb2XLl3Kz89nMpkhISGFhYU2m81ut9NotLNnzzY3N6MompeXd/rM6eXlZQzD8H+1WCyrq6tLbwz/1bJz585nz57hj8zMzGRmZv3wh/+940/99V//9T//8z+///77V69eLS8v53A4KIo6ns7o6GhwcDCTyXzzTYNvxmKxrl+/XlJS4vygXC53/s602WxKpXLNB645eGiz2XQ63Zoxa07DxTDMbDavGcPhcBAEWTMVj8dbM8xoNOLfezgEQYRC4ZoxSqXSeYzVan35u1SpVDpf/YdhmFKp5HA4r/zkLC8vC4VCoVBoMBicZ4bfAeDbekXxTSZTf3+/n5/fj3/84927djU1NU1PT9+7dy8hIUGhUOD/FB0dXV9ff/PmzaSkJLVanZaWeu3aNfznSqvVxsXF3bp1SyKROOZUKpXPnj07f/58aWlpVlZWQEBAdnZ2SEhIcnKyTqfDMMxR/P7+/qtXr1KpVHyZMxqNdu7cuebmZovFkpube/78eeefXi6X+yA09Cc/+cmP3/h/77zzzo9+9KMf//jH+H/+6J13/v3f/u273/3ujlf5i7/4i+9///v/+Z//ee3aNaVS6dhud3f3T9/96f/8z/+8+Xbhf9/8vx+9886//Mv//cEPfuB45OfvvZeQkOD8nWmxWNLT050/6ifvvnv27FnnCNpstvb29jWTnzx50nkeDMM4HM7777/vPGbnzt/ib1M5hpnN5kOHDjmPefcnPxkeHnbenEQi8fb2fvenP3UelpOb6/w+k16vDw4O/vl77zkGvPfz97Kzs53PRbbZbNnZ2R/88pev/OTs3Lnz1KlTJ0+eHBoacj7BzGw2K5VKx9tpUP8tY/2+mq8ovkwmEwqFJpNJIBAEhwQnpyRPTU0FBASkpKTo9XpKSsrVK1d4PN7o6OiVK1fxZKc+fXr9+nWxWIxhmFarjYmOvn37tlKpdOyx441Zo9FYUlJy5cqVmpqaiIgI/PeE1Wqtra396quvqFTqzMzM9WvXQkNCjEajyWTKy8s7cuRIR0eH1WotKCg4f/48vhWynj+CIK2trT/72c+cK/93f/d3//3fP/ziiy9u3rxZXV3N5XLXfBSDwUhISDAajWTtBjAYDJGRkcTentkmDAYDHnfHIyKRKCUlJS4uLj8/v6+vT6VS4a+ToPubncFgYLFYL5fn7b2i+D09Pffu3UtNTW1qaiovL2cwGHw+P+h+0O9///vc3Nzs7OwjR448efKkurr6woULt27damhouH79+qFDh2g0Gn4VVXp6+ieffBIdHe3Y46WlpcDAQE9Pz8rKSgqF4uXlVVRU9Pz588OHD1+8eDE7O/vx48e7d+9++PDh0tJSYWHh3r17b926lZeXFxQUtGvXrqSkJDqdfufOnT1797x48QJ/05UUJpOpoqLiBz/4wXe/+9133vnR4cOH79+/X1ZWxmazv+F1E7xzSzp45/bPevm70WQyDQwMxMXFXbp0yd/f/8aNG2lpaTwej9hqUWDjkMlkqampjY2NpM/8iuJzudznz59XVlZ2dXU5DppPT09TKBT8BW9DQ0NpaenMzMz4+Hh7e3tHR8eLFy9qamoGBgbw1/VcLjcvLy83N9ex9huGYdPT03l5ee3t7Ww2u6enZ3x8XKVS9fX1JSYmlpaWTkxM0On05uZmkUikUqmamprwXypTU1P9/f3Nzc3Dw8P19fXV1dV9fX0kFt9isczOzubm5hYXF09NTeGHmP7sqyQoPumg+AQ4vyjh8/llZWX5+flQ/C3ApdfcvnxiwBueQvDK8a+b9i2R9fyJzQzFJx0U/y298tvYarWaTCbnNx7AprDF19XZdKD4pIPirwe9Xh8TE3P8+PH6+nr8ZGJ37xF4I1D8jQWKTzoo/nqw2Wxyuby1tdXb2/vMmTNNTU0KhQJe8m98MpksIyOjubmZ9Jmh+ERA8UkHxV8PjoM8Foulo6Pj2LHjwcHBMpnM3fsF/gyVSlVTU0On00mfGYpPBBSfdFD8dYVhGL4g1cjIiF6vd/fugD8Dg/vcbihQfNJB8V2A9BMfwKYDxScCik86KL5bLC8vr8cCjWDDguITAcUnHRTfLWpqavz9/cfHxwnfHQhsLlB8IqD4pIPiu4VarS4oKDh69GhtbS0c399Q4Dj+BgLFJx0U3y0wDLNare3t7SdOnEhLS5NKpXDu5kag1Wo7OjqmpqZInxmKTwQUn3RQfDeyWq0TExPe3t7FxcX46uXAvfArsNx2Z3OwBhSfdFB897LZbEtLS3Nzc85rOAN3kcvlrltXB/xZUHzSQfHdznGzT3fvCIBVFjYYKD7poPgAOEDxNxYoPumg+BuK0WjkcDhGoxFe8ruFTCbLzMxsaWkhfWYoPhFQfNJB8TcUhUIRGhqalpa25lbDwDX0ev3g4ODc3BzpM0PxiYDikw6Kv6HYbDYmk+nj45OTk6NSqdy9O9sOhmEoiq7HnW2g+ERA8UkHxd9Q8PP029ravL2929ra4JbOrrdOKyBB8YmA4pMOir8BoShaUlJy4cKF4eFhi8Xi7t0BJIDiEwHFJx0Uf2NCECQpKamxsVGn07l7XwAJoPhEQPFJB8XfsDQajVarhbulbw1QfCKg+KSD4m9YsKq+66nV6vr6+tHRUdJnhuITAcUnHRQfAAf8PrdwPv5GAcUnHRQfAAeZTAbr6mwgUHzSQfE3Pp1ONzw8LBAIUBR1975scbDKwsYCxScdFH/j02q18fHxFApldXXV3fuyxUHxNxYoPumg+BsfhmG9vb23b99mMplwl8R1tbq6SqFQGhoaSJ8Zik8EFJ90UPxNQa/XR0dHp6eny2Qyd+/LVmY0Gufn5wUCAekzQ/GJYDAYcXFxcLcgEhkMhsePH0PxNzgMw7q6uoKCgoaHh81ms7t3Z8vCV7lYjztQQvGJGBsbCw0NZbFY3D8SiURr1h4xm81isZjrRCQSGQwGxwCbzabX6wUCwTeMwTDs5XmEQqHztjAMMxqNPB5vzRjny+JfuS2BQOA8Dz6Gz+c7j5FKpc7z4Nvi/imRSOR8eQ6GYXq9fs0YoVC4ZozBYHDe1tzcXGBgYE9Pz9t+bcA6M5vNoaGhpaWl8DfuZgTFJ6Knp+eDX3zw4Ycf/ubjj/H/nT5zZmRkxHnM3Nzc+fPnHQN+8/HHnidPDgwMOAYYjcbOzs7Dhw87Bny8c6eXl1dfX59jjNVqnZmZuXDhwv+O+fjjk56ezttCEGR4eHj37j3O2/I66bW8vOwYYzab+/r6PDw8nMccPnKEwWA4j+np6dm//4BjwCeffHLlyhUej+e8rZGRkU8/+8wxZudvf3vmzNfOP/xms7mjo+OT3/72T5/XKeclGBEE6e/v37dvn2PMrz/66Ne//mh8fPwtvzRgvWEYxuFwhEIhHMrfjKD4RIyPj0dGRgoEAvkfqVSqNT8AKIqq1Wq5E5VKteb1stlsViqV3zzmTeaxWCwKhWLNGOdT6PAxa7alVCqd9/mVYzQazZrX5haLRf6nVCqV85+f+PP6s2PW7DOfzw8NDYWjOpsCfsABrsLdjKD4RMA7t6TD37nt7Ox0944A4H4oispkMo1GQ/rMUHwioPikg3N1AHBQqVQ1NTV0Op30maH4REDxSQfFB8AB7nO7sbi9+BaLZWFhoaSkpKura2u8gQbF33T4fD6NRoMb4a4HWFdnY3F78REEmZiYOHfuvZlUmwAAIABJREFU3L1796D4wC2USuX169fn5ubgLVzSwSoLG4vbi49hGJ/PDwwMvHr1qs1mW3O3CvzyjTXn4WzwO1pA8Tcds9n8+PFjGo0Gt8cinUwme/bsGRzV2SjcXny73S4Sie7fv+/l5dXT00OlUisrK5VKpd1uN5vNbDa7s7OzqamJwWBYrVaZTDYwMFBaWpqfn8/hcAwGA4vFGhkZmZ6erquri42NbWtrc/vLNCj+pmOz2Wpra2NiYvh8vrv3ZauRy+WFhYXr8eMAxSdigxQ/KCjo088+LSkpoVAohw4dSkxMNBqNfX19cXFxbW1tpaWlZ8+enZiYGBgYePLkSVFRkY+Pz+3bt6VSaV5e3t49e4OCgnJycvz8/D766KOCggI3Phc7FH8TwjBsamrK399/fn7e3fuy1ZjN5qWlJbFYTPrMUHwiNk7xvb29dTodn8+Pi4s7fvy4UCi8f/9+YmKiyWRaXFz09fUNDw9XKpVCoXBiYuLu3buf/e53er2eyWR6eHhQKBSdTsfj8eLj4z/55FOJROLGpwPF34wEAsHNmzeHhoacLwkEbw+/9HI9jsRC8YnYIMW/f//+lStXMAxTKpWpqanHjx9fWlo6evToqVPeVVVVOTk5kZGRjY2NPT09wcHBubm5CQkJn376qU6nYzAYJ0+erKiosNvtKIoODw9//PHH67FQ35uD4m9GBoOht7eXw+FA8TcLKD4RG6T4ISEhjuI/pTw9ceLE0tLSsWPHbt8O4HK5KysrAoGAxWL5+flFRETweLza2ue///3nePE9PT0rKyvtdrvBYGhubvbz83PvOT9Q/M0IXy0DRVG3vw8E3hAUnwi3F99msy0tLV2/fv3cuXNarVapVKakpBw4cGB5eTkyMvLIkSN0Ol0ikchksvb2dk9Pz/DwcIFAkJ6e/tFHH4nFYgaDsXfv3sePHwsEAjab/fTp06GhIff+0ELxAXABKD4Rbi++wWDo6uq6detWYGDg4OCgXq9vaWm5ceNGf38/l8uNjY09duxYaGhoU1OTTCbLz88/duxYWVlZf3//3bt3GxsbmUzmF1988asPP7x582ZBQQGPx3P7X+VQfAAcLBaLUChUKBSkzwzFJ8LtxbfZbEajUaFQKJVKk8nk+E+TyWS1WjUajVgslsvlBoMBX/VeKpXqdDqz2axSqdRq9djY2IkTJ/Lz82UymVar3Qin6kPxAXCQy+V5eXkdHR2kzwzFJ8LtxX8bKIpOTk56eXnV1ta6e1/+FxR/8zKbzUajcSO8btgyYJWFjWXzFt9ms8nl8qysrM8++ywkJGTj3K0Uir9JWSyWwcFBOp0OV96SCFZZ2Fg2dfH1ej2DwWhtbR0cHNw4t+qF4m9SJpOptLS0oqJiPQ46b1tQ/I1l8xYfwzCbzWaxWMxms8ViWY9bJxMDxd+kEATJzMykUCjrcYHotgXr6mwsm7f4GxYUf5PCMKysrCwpKUkkErl7X7YOhUJRVFTU3d1N+sxQfCIYDEZycrLzjWTBWzIYDFFRUXDXw82opaUlJSVFKBS6e0e2DgRBlErlerw1AsUngk6ne3t7JyYmpgGSJCUlnTp1aj1u8wbWW1tbG4VCgeKTCPsj0meG4hPR39+/d+/e8+fP+wGSXLp0ad++fSMjI+7+2oJvDYq/iUDxiWAwGNHR0WKxWAJIsry8/OjRIziOvxlB8TcRKD4RDAYjLi5u45za6AxFUYlEMjU1ZTQaCU+CYZjJZJqfn+dwOK8cYLPZVCrV2NiYXq8nvBVnBoPh8ePHcBx/M4LibyJQfCJIOVfHYrHMzs6+ePHidT8qCILMzc2VlZUZjUZ8vWz8fEqj0Tg2NlZTU/PKOVksVlBQ0OXLlyUSiVKpfPHiBYvF+rb7ptfrq6urvb29MzMzX/5Xq9UqEolSU1M///z3S0tLr5wBX1XxzZfrgXN1Ni8oPukMBgOTyXzd6623AcUngpTim83mmZmZmpqa1y1MjyDI7OwslUo1mUw6na61tTU7O1sulxuNxpGRkfLy8pc/xGazSaXSp0+fHj9+gsfjKZXKmpqaycnJb7tvNpttcXHx3LlzUVFRL/8r/hdAf3//e++998pfJxiGqdXqvLy8srKyN9wiFH/zamlpSUxMdO/9FbYYhUJRWFi4Hn/yQvGJeF3xLRaLXC5fXV01GAwIgsjlcolEYrFYtFqtWCxeXV2dm5vr7u5eWFjAL4PCj19rtVqDwSCVSsVi8cLCQk9Pz9TUFIqiCIKIRKLl5WWz2SyVSp88eeLv78/lcrVaLZ/P5/F4CIIgCCIUCkdGRnp6ejgcDoZhGo2msLDQ09NzZWVFo9FwOByZTIZPNTs7u7CwsLi4ODc3J5PJbDabTqdbWFiYmpricrn4U0AQhMfjDQ8P19fXe3l5RUdHv/wcp6en6XR6SUnJz3/+cxaLhWGY2WyenZ3t6+uj0+n48m18Pt/Hxyc2NtZsNqMoury8PDAw0NXV9bp1HaD4m1dfX19eXp7ErfdQ22LwpVBgXZ2N4nXFl0qlOTk5YWFhExMTMpksNzfn3r17PB6vt7f3zp07ERERxcXFvr6+533O9/f3r66uFhQUhIaGjo2NTU9Ph4WF3b9/Pz8///r1614nvZqamsRicUFBQUhICJfLXVpa8vX1/d3vfpeTk9PV1UWhUCIjI+VyOY/Hy83NjY+P9/f39/X1XV5exot/8uTJ+fn57u7u+/fv19TUqFSqkpKSzMzMqqqqoKCgo0ePTkxMSKVSKpWal5eXnp4eFBQ0NzdnMBj6+vqKioqSkpKuXbv2/vvvx8bGOp4dfuuV6urq8vLyuLi4U6dO/fu///vCwoLZbB4YGIiPj3/w4MHBgwfxP0qGh4c//fRTT0/Pzs7O7u7uvLy8qKioEydOBAUFvfINBij+5qVQKHg8ntlsdveObB2wysLG8rriKxSKzMxMzxOeAwMDKpUqLS1t3759HA6HTqcfO3bs6tWrCoVicHDQz88vLCxMoVDk5eUdO3asra1tbm7u8uXLFy5cEAqFDAYjICDg+vUbPB6voqLi97///dzcHJvNvnjx4r59+6qrq5lMZmJi4v79+6VSqVQqnZqakkgk3d3dhw4dolKpjuIvLS0NDQ15eXmlpKTghwWFQuHk5OTRo0eDgoJWV1erqqoiIiJWV1cXFhYCAgICAgJGR0fv3r07NTUlk8nGx8cPHDgQExODPzUMw3Q6XUlJSXBwsEqlEv7/7b15UFvZmfD9Zub9Jslkqt5kKpPqvFOVmcpMMjOVTGdSmU6qOzO9ue12u/FuvLPYGLMYAwYbGzD7bvZ9B2PMLnYEAkksQkhCCAmtSAjtAklo3wXavj/uN3zE7nZsrG4EnN9fIK7OPVdX+ulwzvM8Z22tt7fv17/+9fLy8ubmJovFkkgkPB4vMTHx2rVrKpUKh8MdOXLk9u3bRCIRi8Wur69LpdJnz5599NHHXznLBIy/f3E6nQ6HA2yD5UGA8b2LrzO+xWIZHh7x8/Ofm5szm809PT3nzp0TCoXLy8vh4eEpKSkul0skEqWmpsbHx5vN5tHRUT8/v4mJCZFIlJycnJCQ4HQ6ZTLZkydP7t69K5PJcDjcsWNHWSzW+vp6dnZ2ZGSkTCbTarWdnZ0+Pj4KhUKn042Pj1dVVZWVlfn6+paUlEDG9/PzE4vFfD4/NDS0tLTU6XTabDaZTJaQkBAQECASieRyeVxc3KVLl4aGhjo6Oh48eJCUlFRVVRUSEmK1Wl0ul1QqvXPnzvasjsvlWltbu337dmNjo9vtttvtFArlgw8+YDAYdrtdKBTW19c3Nzc/fPjw5MlTGxsbEokkICCgqKgIKtzf3d3d0NCQl5f38ccff+XsJDA+ALCNUqmsr68HdXW8ha8zvtVqHRkZ8ff3x+FwFosFBoNduHBBLBZzOJyIiIj09HS32y0Wi9PS0hISEqxW6/j4eEBAAAqFkkgkaWlpSUlJbrdbJpPl5+dHR0crFAoCgXD8+OdsNlsmk+Xm5t67d0+tVptMpp6enrNnz8rl8qGhofDwcDgcjkajb926BRn/+fPn/v7+UqlUJBKFh4eXlZW53W6dTldXV3f+/HkKheJ0OtfW1kJDQ2/evMlkMul0+tLSEoPByM7Ovnr1qtls3jb+zjG+RCK5cuVKZWWl2+222+1kMvmDDz6AlgTi4+PT09Pn5+crKyvPnj23sbEhlUoDAwPLysqMRiN0OQQCYWho6PPPPwfGBwBejU6nGxsbW1xc9HjLwPi74dXGv3DhwtDQkEQiKS4u/vTTT5eXlykUir+//4MHD2w2m0gkSkxMjIyMVKlUMBjs3LmzfX19bDY7JiYmMjLSbDbLZLLs7OygoCAulzs+Pv7HP/6RRCKtr6/n5uYGBwdzudyNjY2GhoZjxz7ncDgFBQV+fn48Ho9Op1++fDknJ0cul9dU15w9c5bFYrFYrOvXr2dnZ6tUqu6urk8/+aS5uVmpVDKZzOnp6fLy8vPnz1OpVL1er9frtVptS0vLJ598gsFgtFotHo8/duxYcnIyFGHpcrlUKlVcXNyVy1eg1enW1taf//zni4uLXC73iy++qKurUyqVZWVlR44cEYlEUqnU398/NTVVLBafO3cuNjZWo9EgkcgPPvhgdHT05ZqdwPgAwDZ2u12n03kq2WUnwPi74euMb7fbFxYWbty4ERwcXF9fn52dffr06YaGhu7u7tOnTwcHB0PzM/n5+UFBQWNjY9nZ2ceOHc3IyOjq6vLz87ty5Qoej1cqlVVVVZcuXXr27FlWZuann3zy9OnT9fV1GAx24sSJx48fI5HI+/fvf37sWG9v78DAwLVr10pKSkZHR2NjYx8+fIhGo+Pi4o4dPVZXV9fa2urj43Pnzh0EAhEeHn7ixIna2tq2traKiorBwUEulxsVFRUQEFBdXd3f38/lcgUCQUxMzLVr1yoqKhoaGu7cuRMYGMhisaCr29raWlhYOHvmbGxsbGNjY0tLi4+PT2lp6crKSnJyMjQ91dTUdPHixbGxMb1en5mZ+V//9cfu7u7i4uKrV692d3cPDg6ePXu2urr65bcyMP7+BSrBDebxPQioq+NdfJ3xXS6XxWLhcrlEIpHH4ykUCoFAsLGxodFo+Hy+WCy2WCxbW1sbGxtisVir1cpkMh6PJ5PJ1Gq1UCgUCoVGo9Fut6tUKqFQqFKpZOvrPB5PpVJBsZ7z8/M0Gk2v10ulUh6Pp9FotFrt0tISjUbT6XTr6+vr6+t6vX5tbY3H421sbKhUKj6fL5FIdDqdWCwWCARKpVKlUkELAHa7XSwWLywsLCwsQPvl2u12qVSKx+OhL5719XWRSLQdWgNFYa6srMzOzrJYLI1GIxQK5XK51WpdW1vD4XBra2sajUYkEul0OofDIZVKp6enJRKJUqkkEAirq6s6nU4oFCqVypd3yAPG37+IRCIymQz2wNoXAOPvhldnYDmdzq2tLY9v+wk1+0KJZigXd2tra3dtulyura2tnXF10CNWq/UV3bDZbDvPuL3Lys5L3vkglH/76uLSwPj7l8nJyerqalAff18AjL8bwI4oHgcYf/+CRCLLyspAzu2+ABh/NwDjexxg/P0LqKvjcYxGIzR36vGWgfF3AzC+xwHG378A43scqMoCyMDyFoDxPQ4w/v4FmtUBxvcgUAYWqKvjLXiP8aFqaFB6LYvFkslkr/9cqAqbl4RYAOPvX6Da3SqVaq87cnAAVRa8C+8xvlqtHhgY6OvrKy0t9fX1faPyqkajEYFAwGAwb6iBBYy/f7FYLFCw71535OAAjO9deInxTSbT5ORkbW2tRCLB4/Hnz59HIBCv/3SHw8Hj8QoKCvB4/MtJsN8ywPgAwDYbGxuVlZVjY2MebxkYfzd4ifHFYnFmZubg4ODm5iaFQrl27VpfX9/MzEx/fz80vbO1tcXn80dGRoaGhng8nsPhkMvl4+Pjg4ODS0tLbrfbYrEgkciEhITX36zqGwIYHwDYxmg0YrFYEKvjLXiD8aGq9FFRUUQi0W63Ly4uHj9+PC4urr6+PiQkJCoqSiqVrq6u1tbWTk5O1tfX9/f3i8XipqammZmZrq6upqYmrVbrdDrZbPb58+e5XO4eXosbGB8A2IHT6TSbzd/EdCsw/m7wBuNDhc+Cg4OhwTuJRPLx8amoqBAKhSMjI8ePH29sbOzs7AwJCZHL5Twej8ViTU1O+fn5QZU46XQ6tGYrFAqvXLnS09Ozh9fiBsYHAL4VgPF3gzcYX61WV1dXBwUFicViu91OIpEuXrwIh8MdDgefzw8LC8vKykKhUB9//PHFixeTkpLweDyTwTx79uyXX34ZExMzPDwMzeSIxeLAwECo6v0eAoy/f3E4HHa7fc+XggCvAzD+bvAG42u12ubm5rCwMKFQCBn/6tVrk5OTbrdbJBLdu3fv+fPnWq2WSCTW1tYGBgaGhoYymUwGg9HW1hYZGel33W9ubg462M/Pr7Ozcw+vxQ2Mv59ZWVnBYrF7vqwFeB2A8XeDNxgfWnQNCwujUCh2u51AIHzy6af19fUqlWpubi4nJ4dOp1MoFCKRqFAohoaGHj58ODIyQiAQ9Ho9kUhMTEiE9Lq6unrixAkymbyH1+IGxt/PTE1N1dbWgkpqHsTpdFqt1m8ingIYfzd4g/GhRdeYmBhoJofFYgUGBt6/f//58+fDw8NsNluj0SAQiKKiopmZmbGxsZmZGSwWW1hYiEQiJycnkUikXq+3Wq0oFOrWrVt7nocFjL9/QSKR5eXlIOfWg0B1dZhMpsdbBsbfDd5gfLfbrVar29raysvLDQaD2WxmMBg4HA6DwchkMqiEslgsxmAwWCxWJBKZTCalUonH42dmZthsNqR4mUyWmJjY09Oz55OwwPj7F1BXx+OoVKqmpiaQgeUteInxHQ6HQCB49uwZmUy22+0Oh8Nms5lMJkjfUOl8s9kM7bLicrkcDofVajUYDFDUl8lkGhsbKysrUyqVe76BETD+/gUY3+OAujrehZcY3+12b25uisXi1dXVXeS4W61WDocjFov3fIDvBsbfzwDjexxQZcG78B7jQyN3m822i0E6tEeVN+jeDYy/n6HT6RMTExqNZq87cnCAqiWDMb63QKFQSktLd73XIOBlzGZzbm7uG1WCA3gJFotFr9eDSmoeBBjfu5ifnw8ODm5oaHgG8BANDQ1BQUF4PH6v7y0AsPcYjca5ubnl5WWPtwyMvxvm5uZOnjwZGhoaBfAQd+7cOXXq1MLCwl7fWwBg73E4HCaTyWq1erxlYPzdQCaTMzIy2Gz2CsBD0Gi0x48fYzCYvb63AMBBBhh/N1AolMLCwj3PWjpImM3mrKwsMI8PAHyjAOPvBu+J1TkwgFid/QuU7uclQV+AVwOMvxu8wfhOp9NisUDZVbtuBMrSMplMZrP5zx7wjX6kgfH3L0tLS3A4XK1W73VHDg4Oh8NisYC6Ot7CmxrfZrOJxWKRSPR1B1itVqFQ+EItKpfLZbFYeDyeQqF44XiXy2U0GicnJ3NzcxkMhsPhUCqVHA7H4XC80YXY7XahUNjS0lJZWfmVBzgcDrFYXFtb29raajKZ3qjxNwIYf/+CQqGqqqpABpYH0el04+PjFArF4y0D4++GNzW+Uqns7u5ua2v7ugMUCkV7ezu0raVeryeRSAKBwOVySaXSxsbGlz3ocrnMZvPIyMiJEyfgcLjNZiMQCIWFhW+6aQ4k9Ozs7HPnzn3lAU6nUywWQ+E0Wq3261rAYrFvdN6XAcbfv4BKah4H1NXxLt7U+FAtBD6fv/0IFH1lsVigX202m0QigcbybDY7Kiqqv78fGuOLRCKlUgkdZrfb9Xq9w+GAUm0XFhZ8fHz6+/sdDodKpWIyma8Y49vtdq1WuzPey+VyOZ1OjUbz7NmzEye+fPkp0JSOWq3Oz88PCwuDkipdLtfW1tb2v/Bms7mzs9Pf33/npX3ld8OrAcbfv4AqCx4HZGB5F29kfJvNxmQyu7q6MBgMj8cbHBxsaWmZmZlpaGh48uQJGo22WCxUKrW7uxuLxW5tbc3MzHzyyScJCQkYDGZqaqqnp4dEIlmtVgaD0dXVVVFRUVhYyGAwnE7n0tLSmTNn+vv7lUplf3//8PCwTqdTqVRwOHxgYGB0dLSmpqa1tdXhcGxsbKBQqNHR0ba2NhwO53a7LRYLiUTq7e2trq6+ePHiFydOvNBti8WCwWAGBwdLS0tPnjx5584dnU5nsVjm5ua6urqysrKgEmw6nS45Ofk///N3aDRaLBaz2eyurq6ysrK8vLw3yh8Bxt+/AON7HFBXx7t4I+Nvbm7S6fT4+PgHcXF8Pr+6uvrLL78cGhqamJhITU0NDw9nMpmLi4v379/Pzs62WCzDw8Pvv//+vXv3pqenx8fHIyIiysrKdDodCoXq7+8fGBiAdjR0Op0UCgUyvlqtbmpqunLlilgs5vF4fX19GAzm2bNnH374YXFxsVqtfvr0aVVVFYvF6unpuRUcTKPRenp66uvr5+fnh4eHr1279sWJL3b2WafTtbS0dHZ2Qt8Kp06dCgsLMxgMarW6s7OTQCC0t7d/fvz46OioSqWKior67W//Y2RkRCAQIJHI4eFhOBzu7++fkZHx+i8pMP7+BRjf44AxvnfxRsZ3Op1SqTQrKyvo1i2tVtvT03PixBdMJlOtVvf19V29enVycpLP5z9+/DgxMdFut8/NzZ06daqmpkan0zGZzIiIiJycHJvNJhAISCRSX19fQGDAtWvXdhrfZrMhEIgjR44IBAKj0ahUKrlc7t27d4OCgng8HpPJDA8Pb21t1Wq18/Pz586dy8vLi42NHR8fN5vNMpmsrKzsxI4xvt1up1AoFy5cEAgEFotFIpE8fvw4LCxMp9NZrVYWi0Wj0bq6un7/+9+Xl5frdLq8vLwjR44olUqz2SwQCMhk8uDg4Pnz5319fV//JQXG37/w+XwikWgwGPa6IwcHlUr19OlTNBrt8ZaB8XfDm87jy+XyJ3l5wcHBBoOhv7//7NkzUqnUYrEgEAg/P7+JiQmJRJKampqUlAR5/NKlSx0dHS6Xa3V1NTo6Oi8vT6FQ1NXVpaamDgwMZGVlXbp0aafxt7a2Jicnjx79TCgUulwutVpdXl5+7dq1+fl5m802PT194sSJ5OTk4eHhzs7O2trampqaq1evLi4uut1uo9H47NmzL7/8/+fxrVYrAoH4+OOPoUl/rVb75MmT8PBwnU4nlUpTU1MrKiqIROK5s2dzcnIMBkNVVZXPlz7QeSsqKtLS0sbGxhITE0+ePPn6Lykw/v5lc3PTYrG8aZwY4BVYLBYmkykWiz3eMjD+bnhT4ysUioKCguDgYKvVOjIycubMGblcbrFYRkdH/fz80Gi0RCJJT09PSkpyuVxkMtnX17enp8flcvH5/NjY2MLCQhKJ5O/n39fXx+Vy8/PzfX19XS4XnU4/c+bM0NCQ3W6fnZ09evTo+vq60WiEwWBXr16FYngMBsPw8PCZM2dKSkqkUqlEIllbWxsfH/fx8ent7XW73RqNJj8///jx49u93drawuFwf/j976HNb5VKZVxcHDSPPzg4ePz48dXVVYlEcu7cudzcXIPBUFZWdtLn5Obm5uzs7KlTp5BIpFgsTklJAcYHAHYHVMn8m6jOC4y/G950Hp9Go0VGRp4/fx6DwRQVFX366acYDEan0yEQCF9f3+bm5tnZ2ZCQ27du3RIIBEwm8/Kly6GhoQsLCygU6urVq7GxsRMTE76+vpmZmXg8PjMz08fHZ3l5eXh4+KOPPiopKeFwOHV1dX/84IPp6WkkEnnq1Kng4OC5ubm5uTkEAkEgEHJycgIDA1tbW6enp5lMJovFunfv3qVLl3p7e8fGxmJjYz/88MPl5WXoHeZyucRicWBg4K1bt7q7u8fHx2/fvn3p0iUymTwyMvLB+++PjY0xmczTp0/HxMTI5fK2trZf/epXg4ODk5OTx48fLygooFKpCQkJn3z8sVQqfc2XFBgfAPgWAMbfDW8aq0On0+vq6iorK4eHh1tbW0tKSqanp41GI5fLbWpqGhoawmKxNTXV1dXVDAZDo9F0dXU9fvwYgUDMzMyUlZU1NzdTqdSurq4nT54QCAQcDldTUzM/P49GowsKCrq6uigUSnd3d3Fx8eTk5Pj4eG5ubkdHBwqFgsPhExMTarWaw+FUVlZmZ2d3d3dTqVSz2QwVgysqKhoaGpqeni4tLSUQCNs5flarFY/HZ2VlFRQUIJFIBAJRXV29sLAgkUiKioqampqEQmFPT09zc/PGxgafz79//35tba1UKm1tbc3Ly1tcXJydnS0pKeFyua/5kgLjAwDfAsD4u+FNV25NJpNcLlcoFBsbGwqFQi6XazQaaO8qlUqlVqt1Op1cLpfL5QaDAYpnFwgESqVSq9XKZDKFQmE2m7VarUgkgkIkNzY2dDod9FelUqnX66GWNRqNWq1eX19XqVQqlWpjY0Oj0TidTrvdrlAoeDyeTCYzGo0ul2tzc1MqlUJnsVgsCoVCq9Vu11FwuVw2mw06QKPRmEwmhUIB7Xohl8ulUqnNZoNOurm5abfbRSKRWCyGQv6FQqHBYIDafP00XWB8AOBbABh/N3hDXZ0DBjD+/kWv18vl8m+iCMyhxW63Q6M6j7cMjL8bgPE9DjD+/mVhYQEGg21sbOx1Rw4OWq12eHiYSCR6vGVg/N0AjO9xgPH3LyADy+NAObcgA8tbAMb3OMD4+xdQSc3jgJxb7wIY3+MA4+9fwBjf44C6Ot4FhUIpLS0FS1UexGw25+TkgF0P9yOzs7P19fUymWyvO3JwMBgMbW1tk5OTHm8ZGH834HC48+fPxcTExAE8xL17986ePftNLFXtU+x2e3l5eXx8/EOv5+rVq59/fiw8PHyv30QHh+io6JM+J69cvvw29yUpKQmqp7vzfQWMvxsIBMLNmzcrKysG7bIyAAAgAElEQVSbAR6itrY2ICAAj8fv9b31FqxW6+nTpyMiImK8mwcPHvj6+l65crmkpGSv30T7jKdPn37dnyrKKy5evOjr63v//v1d35ebN29mZma+kAUJjL8byGRyTk7O2tqaFuAh1tbWUlNTwTz+NhaL5cKFC83Nzd3ezcDAQGpqal5eHofD2es30cFBKBRmZWWlpqb29fXt7r709/c/efIkJyeHyWTufF8B4+8GCoVSUFAAysN6ELPZnJmZCebxt7FYLJcvX+ns7BzxbpBIZE5OTnFxMZjHf322trYkEsnMzAybzf7K5UBo47nc3FwEArG7+zI+Pl5eXp6fnw+M7wFArI7HAbE6LwAZv6OjY8i7GR8fz87OLioqAsZ/fYxG48jISEhISGtrq9FofPkAlUoFjdBHR0d3d1/GxsbKysqA8T0DML7HAcZ/AWD8A8zW1haZTL579y608dHLBwDjexfA+B4HGP8FDoDxt7a21tbWiEQil8sdGRlpamqi0Wh0Or21tbWvr0+hUECV++RyOYFAGBkZIZFIJpNJpVLR6XQmk4nBYBobG2dmZuh0el9fX1tbG4fDgQp6m0wmJpM5NTXV399Po9EsFotGo2EymWw2G4PBDA8P43A4BAKBQqEUCoVUKkWj0TgcTqvVQh1zuVx6vZ7BYNDpdBKJ1NraOjQ0tLKygkAgmpubFxYWzGaz2+1WKpXT09ONjY0wGEwsFlssFj6fT6fTl5eX29vbS0pK5ufnLRaLVqtdXl5eXl7G4/F1dXVPnz7l8/lOp9PpdIrFYhwOB4fDl5aWoDYtFsvS0lJfX19paemVK1dqa2v1ev3Ldx8Y37sAxvc4wPgvcACMb7FYZmdng27erK6u7u3tjYyMDAoKamlpefbs2c2bN9va2rRaLY/Ha25uHh0dHR8fj4+Pn5ycJBKJiYmPoe3eUlJSAgICSktLOzo6IiIisrOzRSKRxWLp7e0dHx/HYDDV1dUPHz6cnp5hsVhZWVmJiYnJycmZmZkIBOJOeHhWVpZQKGQymQUFBYODgzuNL5FICgoKYmJienp6ampqrl+/npGR0dbWlpiYGBcXRyKRHA7H5ORkT09PbW1taGjo06dPoQrhkZGRlZWVTU1NUVFRQUFBcDicyWQ+eZL38GFcU1NTdXV1UFDQ48eP6XQ6m83u6OgYHBx89uxZTk4OBoORSCQTExNDQ0MjIyPp6elHjx2tqqr6yuVAYHzvAhjf4wDjv8ABML7dbqfT6Uc/+6ympkYkEj19+vSzz44MDQ1JpdJ79+4lJSXx+fyOjo7k5GQqlapWq6OiovLz8wkEQnh4+P3792k0GgaD+fz48cbGRolEUl5e7ufnt7i4iMfj09PTiUSiTqfj8Xjh4eGZmZlMJvPhw4e3b9/u7+9fWlqSy+WPHj6MjY1ls9kcDqepqWlpaWl9fZ1Op5PJ5OXl5fX19czMzOvXr09PT4vFYn9//7i4OBqNNjAwcPPmzd7eXrPZvLKysrq6SqVSg4ODo6Oj6XR6V1fXpUuXWltbxWIxhUIJDwtPSEggkUhJSckhISHT09NSqRTaga6urq6qqqq8vJzBYDCZzOjo6MLCwqamptLS0sXFRbVajUajb9y8UV1dDcb4+wBgfI8DjP8CB8D4LpdLKpX6fPllT0+P2WweHx8/c+bM3Nyc3W7PyspKSEhgMBhpaWk3btxobW0dGxtLTk5ubW3lcrkPHz7MyMgQi8V8Pv/MmdMjIyNbW1swGOzKlavz8/MNDQ0PHjxgsVhut9vpdGZnZ0dERNDp9MzMzPj4eDab7XA4XC7X6Oho4I0bcDh8enoajUarVCoMBpOWlhYXF9fY2CgWi0tKSsLCwqCtPSMjI3NycmQyGYFACA0N6+jo0Gq1MzMztbW1nZ2dQUE3Q0NDaTQaHA4PDg6emJiAJm0KCgqio6PJZHJ+fkF8fPzy8rLb7ZZIJJGRkU+ePAkNDY2IiIDBYH19fYmJia2trY/iH2VnZ0Mbw7FYrPv379fV1QHj7wOA8T3OQTW+0+l0uVy7eOIBML7b7d7Y2Dhz5vTw8LDVakWj0RcvXlxYWIA0nZKSwmazExISwsPDMRjM6uoqk8lcX19Xq9WPHz/Oy8uTSCQikejChfMoFMrpdMJgsOvX/YhEYkNDw40bNxYXF6FT5OfnP378mMvl5ubmZmRkCAQC6HGNRnMnIiIxMbGiooJGo9nt9vX1dRKJRCAQ2Gy2yWSqqKiIiopaWlpyu93R96ILiwo3NjYIBMKdO3f6+vpIJNKjR4+am5s5HE58fPzdu3ch44eGhkLFD2w2W3l5eXFxsVAoLCwsSk5OWVlZcbvdy8vLmZmZbW1toaGhjx49Wlxc5HK5TCZzbW0tKTnpQdwDKCWKSqXevRvZ2NgIYnX2AcD4HudAGp9EIvX09CgUCpvN5nK5NBrN/Pz87Ows9Ourn3sAjG+z2ebn5997772ioiKJRNLQ0PCHP/yhs7PTZDKlpKQEBgZisdinT59eu3btWUsLjUZjs9kqlYrJZF67djU0NJRMJs/MzLz//vtVVVU6na6rq+uzzz7r7unBYDABAQGVlZV8Pp/FYuXn5/f09DCZzJCQED8/v+npaYvFAnWgqanp7NmzFRUVcrl8Z8dcLpdKpYqLizt58uT4+LhYLPb19b1z587y8jIWi71y5UphYeHAwMCVK1dqampWV1djY2PPnTs3MzMzMjLi6+tbWlpKo9Hm5uZaW1sJBILRaMzJybl27RoMBmMymQMDA11dXdA+oyEhIe3t7XQ6fWVlRaVStba2Xr9+va6ujsFgdHd3+/j4xMfHi0Sil98MwPjehbcZf2tr6412zHE4HEajUSaT2Wy2b7Rjr8/BMz6RSKyqqiosLFxcXOzs7ORyuUKhMCEh4caNG3q9/jAY32QyoVCo8PDw8vLy5eXlp0+fhoaGdnR0qNVqGAwGpVjz+fyKiorExMT6+vqRkRGRSDQ/Px8fH5+RkUEkEsfGxiIiImpqauRyOZFIfPDgQVd3t1Qq7evry8vLGxgYGBsbg5RNpVJTU1Pj4uLGxsa2V2jZbPa9e/cmJiagCJ9tnE4nn88vLCy8d+8eCoUikUiJiYnp6enQt86TJ0+qqqqIRGJBQUFubu709HRzc3NSUhIej4fD4SdPnrx582Z9ff3w8DCTyTSZTJubm9nZ2UeOHElISGhvb0ehUEKhcHNzc2Vlpbi4ODExEaqCKZVKhUJhWVlZ/KP4xsbGnp6ezMzMoqIiNpsNjO/teJXxXS6XWCwuKCh44da+AqPRODo6Wl1dDUWMeQMHzPhWq9XfPwCFQnE4HIlEAoPBVlZWDAZDQUHBqVOntFrtYTA+tLsym80WCAR6vV4sFi8vL0ObJCuVytXVVaVSCU22UCgUOp0uEolMJpNarYaWTDUajVwuZ7PZQqHQarUaDAYulyuVSjc3N3U6HYfDYTKZQqFQq9VCGyxzuVw2m71z/8Xl5eW+vj6RSPRCx1wul9FoFAgEbDZ7Y2NDpVJxudzV1VWdTmc2m0UiEbRXs0gkotFoa2trMpmMx+NpNJrR0dHAwMCamhoajSaVSq1Wq9vtttlsT548CQ8PHxgYYLPZarXabre73e6trS2xWEwikRgMxvr6utlsdjgcULgqlUqVSqUikUggEBgMBmB8b8fbjE+hUI4fP76wsOB2u6GP0NTU1Pj4OJ/PV6lUo6OjeDze4XBsbW0JhUIKhaJSqfLy8m7dugXG+N8Qcrn83XffpVKpDofDZDItLi7K5XKn09nU1OTr6wsZ32w2E4nEoaGhxcXFra0tu92u0+m2tragz/8BMP7r43Q6HQ4HFJ7/+mxubjocjq/8E/SlAoPBoJD5XXfshV7B4fCQkBAkErnzcZvNlpeX9/jxYyaT+XJ/HA4HtJK8/Yjdbrfb7a++WGB878KrjG8wGJqbm//pn/7p0aNHKBRqcXGxra0Ni8WOjo5mZmaSyeSWlhY/P7+ZmRmZTPbs2TMajcbj8a5evfq73/2utraWz+fv9RW43QfO+KOjoz/96U/j4+NHRkZgMFhMTAyVSrXb7Q0NDZDx5XJ5W1sbEomEJjGwWCyXy42JiZmenoaGqIfK+B6HQCBkZ2c3NTVJpdI3/SL5OmQyWVFR0bFjx0pLSxUKxfbjDAbj1q1bFy9eHBkZ+cpl2F0AjO9deJXxLRbL0NDQb3/724aGBhwOV1BQkJ6eLhaL5+fn/f39GxoamExmVFRUSEjI8+fPEQiEyWSSSCR37979/PPPMRiMUqnc6ytwuw+c8QkEws9//vOGhgYajdbX1/fpp5/Ozs5uG1+n001MTAQFBUGR43fv3oXCCvPy8kgkEjTpDIz/NohEosnJydXVVQ9uW6TX6xcXF6Hc4J1pU+vr62g0enx8fHV1FZrneXuA8b0LrzK+0+kkkUhHjhwhkUirq6t+fn4hISETExPt7e0xMTGdnZ02m21mZub48ePR0dFqtdrlcimVyszMzICAAKvV6qkR0FtywIwvEon+/d9/vbCwsLm5icfjjx49isFgIONfvHhRp9Pl5+cfPfrZ4OAgAoGIj4/PyspSq9Vra2smkwm6I8D4b4PT6fyzMye7aNPhcNjt9hemeqBzQafbXSTuywDjexdeZXyXy0Umk48ePcpkMldXV319fRMTEwUCAYfDodFoMpnMarVisdjIyMizZ8/Ozc253W7I+EFBQV6ie/eBM/76+vpvfvMbGo3mcDgWFhaOHz8OZR41NjZevnxZr9enpKScPOlDp9N5PB6VSuVyuTabzWw22+32QziPvx+BkrBe/ciuAcb3LrzQ+O+//35HR8fS0lJKSsp1v+tEIlEulwsEgvX1dSwWW1tbi8FgMjIyAgICGAyGSqXKysr64osvyGSyl4TrHCTjO51OCoXys5/9DIFA2Gw2FAr1+9//ob+/X6fT5ebmfvzxx0KhsL+//9NPPunt7V1fX+fz+RsbG0KhMDMzc35+Hszq7AKDwWCxWDw+gpFKpQMDA2g0Wq1Wbz+o0+lGRkbgcPj6+rrVarXb7VwuFw6Hz8/Pf2UC7S7Yx8aHkh2mp6fHx8fX19e/uRNZLBYWizUyMkIkEneG3+p0Oqh83erqqqfO5W3GFwqFkZGRKSkpFAqFTCYnJydnZ2f39/cTiUQOh9PX1zc6Omo2m2k02sOHD6GtL4eGhq5fv97c3Oyp9+hbcpCMb7FYJiYmrl+/3t3drVKpxsbGQkJCuru72Wx2eXl5aGgogUCQy+VFRUUJCQnPnj2bnJyUSCR8Pv/Ro0dYLBas3L4mGxsbfD7fZDK53e7h4eHx8XGNRuPB9lUq1dDQUHl5+fDw8PZSrU6nQyAQJSUl/f394+PjQ0NDIpFoYWHhzp07+flPJBKJp069j42vVqsbGhoiIu7Ozs5+cyeyWq1EIjE+Pr6wsAB6E0Do9XoYDBYRETE8POypc3mV8d1ut9VqZTAYc3NzGo3GZrOtrKxMTU0tLCxAaVlCoRD6JNhsNg6Hw+PxNjc3lUrl7OwsjUZ7ITllrzhIxrfZbEKhkEqlQjH4UFg3j8eTyWQcDodKpYpEIofDIZPJsFjszMyMQCAwm81ms5nNZms0msM5j/+Vk+DQPMlXTo7bbLaenp7GxkaoTA0ej985xP66J75i4sXlcu18lsvlQiKRJSUlGAxGLpdvxzETicT09PTBwUG5XE6n02dnZ2UymUQiiY2NTUtLEwqFf7bnr8P+Nr7dbu/q6goICBwbG4MetNvtFosFehGhF3r75d75ROf/sLNBh8Nhs9leWIJ3Op2bm5tsNjs5OTklJWV7Jd3hcFit1snJydu3b/f09Lzc+HZnoKQJqCmr1br9HyLU8s4D3N5nfPf/9BN6h21fgsvlgq50+zCXywVFB7tcLigGfO+6/CccJONDS3zQOx8Kx35h0W97sn5ra8tkMr0Qrw1xGIzvcDikUimTyeRwOP39/bW1tXg8HhquQf+yo9FoGAyGw+H0ej00rFldXZ2bm4PD4Ww2OyUlJS4ujkqlmkwmNpu9tLSk0+mcTqdCoSASicPDw0NDQ1wu12q1rq2tsVgsMpnc1dXV0NBAJpNfCNI3GAwMBgOBQPT09EBl+jc3N8vKyh49egQtv0M3CFJZaGjoxMSEyWRaWVmhUqlarVatVqekpEDFnKGsl+np6eHhYQqFsnP0+frsY+NDDAwM3Lp1C4FAuN1ui8WyuroKpQhxOByNRsPhcObm5hgMhk6nU6lUAoHAarUajUYmk7mduuJ2u51Op8lk4nK5CARiYGCAw+FA+Q42m00kEuFwuM7Ozjt37qSkpBiNRqfTaTQaWSwWCoWqqqoKDAzs7e21Wq3r6+tQ7h8ajebxeAaDgUajjY+PQ8VX7Xb72tra1NQUdLfMZrNKpSIQCMPDw3Nzc9vZ215o/P3OQTK+RzgMxlepVHV1dcHBwXV1dR0dHfHx8UFBQVNTUwaDAYlEDg4OLiwsjI2NPYyL6+/vX1hYuH8/NiEhobi4uLS0dGJiIjAw8NjRo4WFhXA4PCMjIy8vl8fjQVXsJycnyWRyfX19UlISBoNpamqCzoJGo7OysuLj4xkMxnY3zGbz4OAgEomkUqmdnZ0JCQnjiHE+nx8bG3vs2LHs7GwWiwUNMdVqdXZ29ocffvj48WM0Gp2bm5uVlcXhcFQqFTSVKhKJ8Hh8e3v77Ozs6OhoTk7OzMzMLsZVB8f4er0e8imLxerq6kpJSRkYGOjr67t7925LS4tWq0UikVlZWXQ6XS6XP3/+vLS0lMvlQl+wm5ubNBptaGgIgUBkZGSkpaWJRCKtVjs7O9vf349CoUpKSo4dO5aQkGAymcRiMRwOh8Phw8PDMTExJ06c6O3t5fP5JSUl9+7dKygoePLkyejo6NjYWG9v79zcXEVFRXt7O5VK7e7uplKp09PTvb29i4uL/f39MzMzc3NzXV1dUJk9NzD+NwAw/gscBuObzeaWlpZjx47BYDCpVEqn00NCQqAN7jMyMtBotMlk0mq16Wlp0dHRc3NzISG3b9++jUKh2Gw2l8uNiY0JunlzZGSEzWYnJiZGR0cxGIyBgYHs7GyoWCabzQ4MDKyuqa6trT19+jQMBjOZTEgk8tLlSxMTE9vdWFhYyM7OxuPx0KZdMTExSUlJNBoNquQMbdcFDS4tFkttbe2lS5eam5tXV1fT09NDQkJIJJJKpUpJScnNzeXxeJWVlenp6Xg8HoPB3AoKKikpUalUb/rKHBDjj42NkcnkwsJCBAKxtbXF4/GSk5Pj4x/B4fCIiIiioiKpVFpYUHjq1Kn29vaNjY2urq7W1tbtuTnofiwtLS0sLGRlZl66dGlqagqHw+Xm5k5NTW1sbOBwOGgBUyaTdXR05OXlCQQCuVze3tHu5+fX29urUChKSkpOnzr17NkzEonU39+fkJAwNjYGlVXy9/dvbGy8devWyMgIk8lksVgYDCYsLKyyspJKpdLpdLFYDPUEGN/jAOO/wGEwvtvthsPhFy5cmJubg+a7ysrKUlJS6uvrAwICodIgLpert7fXz89vYWHhwYMHiYmJ0Fy5wWDIyMhITk7m8Xhut7u4uBjauyonJyc5ORmqSGy1WhMTE0tKSp4/fx4QEIBGo6EwqkuXL8Hh8O0+PH369P79+xQKBZoCLSkpuXPnzuLiYnFx8ePHj6Gq9xBOp7O7uzsyMhKKcq6srLxz587CwgJk/IKCAhKJ9Ojho+ioaBgM1t/fn5WVBYPBdrGefBCMHxwcDIfD+/v74+Li5ufn3W633W5vbm4OCbk9MzNTUJAP/f9VWVkVFhaWkJCwtLSEQqEoFMp2I1AUVGdnZ2dnZ2Zmpq+v78DAwPPnz+/evQu5WCQS5eTkZGRk0On0pKSkrKwsaDoIh8NFRET09vYajcaOjo7g4GACgbC5uQmDwc6ePdvX14fFYuvq6tLT0ycmJh49enT9+vWYmJiOjg4ymZyTk3P58uXw8PDKysrtaB9gfI8DjP8Ch8T4IyMjly5dIhKJ0NpSYWFhd3c3DAa7cP7CxMQENJcyPDwcGxtLo9Hu37+flpYGfdj1en16enpqaipUJqSkpOTRo0cUCiUrKysqKgrSnN1uT01NbW1thcFgAQEBk5OTTqeTTCZfvnx5dHR0uw/Pnz8PCgrCYrHQr1VVVYmJiQwGo6SkJCkpic1mbx/pcrl6enqioqK2jX/37l0SiaRWq1NTU4uLixcXF2NiYjLSM2g0mkAgWFlZUSgUuwiOODjG7+3tDQ0NRaFQbrfb6XS2PW+Ljo5eXl7u6ekOCAh48uQJFotta2u7ceNGYWHh5OTkzmxmuVxeWVn54MEDEonU3t4eEBAAg8FaWlpu3rwBfQ/z+fy0tLSMjAwmk5mQkBAfHw8tDs/Ozt6+fRsGgxkMhvb29rCwsIWFBbvdDoPBzpw+PT4+zmaz6XT66uqqQqHA4/EtLS3379+HNrHkcDgdHR1paWm3bt2qq6uDegKM73GA8V/gkBgfgUB8+umndXV1fD6fTCbX1NQsLy/z+fyIOxEpKSl8Pt9oNEKz/Gw2+8aNG2FhYVCFIpPJlJ2dHRh4Aw6Hi8XihIQEf39/HA43NDR0/bpfS0sLtECYm5uLxWJbW1u/PHGiq7PTbDaTyeQzZ860tLRsL94yGIzQ0NDi4mKZTLa2tlZeXt7T08Pj8eLj42/dukUgELaVrdfrKysrL126BIfDoZKZly9fnpiYWF5eDgsLi42NoVKp5eXlEXcienv72Gz28vKyXC4/dPP4TqcTBusNCAgYGhoiEonQbpZqtRoq7NXS0mI0GgkEwtWrV0NCQkUiEYPBuHv3rp+fHx6P39mOQCCIj4+/d++eQqHo6e6+cvkyFBLr5+dXX1+v0WgwGMzt27cfP368trZWXlF+5coVPB6vUqlaWlouXbrU3t6u0Wiam5sDAgJwOJzD4ZiZmfH394c2TNBoNGtra2w2G41Ga7VaKF+po6MDj8eLRCI6nV5aWlpTUwP1BBjf4wDjv8AhMf7ExMQfP/ggMjKyo6NjenqaxWKZzeatra2ZmZmSkpKOjg4MBoNEIsViMYfDKSgoyM/Pn5+fN5lMdrsdiURGR99ra2uj0Wg1NTXZ2dlzc3Nisbi9vb2iomJoaAiJRM7NzYlEov7+/uSkpMHBQbVaLRaLi4qKYDDYdlKV1WqdmJgoLy+HwWBIJBLarnZ1dbWysjI3NxeHw23H26ytrbW1taWlpSGRSIVC0dHRkZmZiUaj8Xh8QUFBcXExg8FgMBjV1dV5eU/a29txOJxCoThcxne5XBsbG62trdA8CY/Hg8Phubm5z58/h8PhaDRaJBI5nU6BQFBcXFxdXW0ymQwGw/PnzzMzM9fW1nY2pdPpuru74+LiEAgEGo1OTU3t7u5eWVlpamq6f/9+TU1NX19fcXFxTnY2hUIhU8jp6emPHz9+/vx5T09PRkZGfX09Foutrq6OiYnp7e3d2NhQKBTQ0nx5efno6CiXyyWRSEVFRUNDQ1NTU1gslkgk1tTUtLa2Tk5OTk1NgVmdbw5g/Bc4JMYfGxvz8fFpamoik8k7h8M2m43P5y8uLi4vL2s0GqgCvkAgWF1dhaLjXS6XXq8nk8mrq6sqlUokEvF4POhPWq2WxWItLi4KBAKTyWQ2myGDr62tWSwWq9UqkUgkEsnOAE2LxbKysrK4uLiysqLT6RwOB3Q6Ho+nUCi2Y8GNRqNEIoH6YDAYpFIplGYBFdDn8/lQQoxMJiOTyVQqFSrWv4uo/P1tfIPBwOFwKBQKl8s1GAx6vR66H1BUE7QIbjabBQKBVCqFFk/W19e5XO4L343bkbbLy8sqlYrD4ayurprNZoVCgcPhsFgsn8+H/kVYW1uzWq1cLnd6eppEIq2trXG5XBaLBW2TRiaTodQYp9OpVqtJJNLMzAyTyTQYDGq1mkwmUygUPp+v1+sNBgOdTieRSFwuV6lUbge2A+N7HGD8FzgMxnc6nb29vT4+Pmg0+uWiflDKyNbW1nZw9nZ+ybZDofVe1/+w/SeHwwFVz9+ZV7V9pPurEr6cTieUobLzgBdOt/30na1tt7/z4Ncpgv8K9rHx3X/6Mu38YXcJaTuf+PINePnB7Rfd9RLbj79w2Mv3+IWuAuN7HGD8FzgMxjcajQ0NDWfPnu3p6XmdnSAPD/vb+AcPYHyPA4z/AofB+Hq9Ho/H9/f3Ly4u6vV676nkuucA43sXFAqluLjYU7sfANxut9lszs7Onpqa2uuOeAsWi+XatWt9fX0T3s3MzExBQQEU/vCm17i1tQUVFIKqmIAx/jYGg6GkpASKV9zdfZmamqqpqSkoKNiZXewGxt8dBALh+vXrmZmZuQAPkZGRcfXqVShRA+B2uy0Wy5EjR65fv37Tu7l9+/bx48d9fHwSExP3+k10cEhNTT1x4sQXX3xx69at3d2X4ODgCxcuJCYmcjicne8rYPzdIBKJ6urqSkpKygAeory8vKGhYWNjY6/vrbdgt9vr6+sLvJ7CwsK8vLy8vDzwcfAgJSUlubm5eXl5b3NfiouLEQjEdjUwCGD83QDFim0APApU+HCv7623AEUfqvYDarVapVLt9dvnoOGR+2I2m1/4TAHjAwAAwGEBGB8AAAAOC8D4AAAAcFgAxgcAAIDDAjA+AAAAHBaA8QEAAOCwAIwPAAAAhwVgfAAAADgsAOMDAN6I0+lcW1vbxWYa3z5Go1GpVO5ibz/A12G329Vq9c4dAD0FMD4A4I1Yrda6urpv4jPvcZaWloaHh7e3lAK8PXq9fnx8fOcu354CGB8A8EbMZnNUVNS+0CgSiSwvL39hxzrA26BUKuvr65FIpMdbBsYHALyRVxvfZrOxWCwMBqNWq7/pYkQsFguHw0ml0q+btwHG9zhKpbKhoQEYHwA4LJjN5nv37m0bHyolv7q6OjExUVlZ+fDhQ1/fi2fPnqXRaN/0XH9RUS/5tnMAAAm5SURBVNGpU6eCgoLS0tJaW1vxeLxcLrdardCegm63G41GV1RUAON7EJVK1djYiEKhPN4yMD4A4I2Yzea7d+/yeDyxWDwzM1NXVxcbG3vx4sUPPvjgZz/72Q9+8IP//b//n7//+7+fnJzU6XSmb5KwsLAf/vCH3/3ud3/0ox/927/922effXbz5s2MjIyurq7FxcX19fXBwcGysjJgfA8CjA8AHC4sFsu5c+ciIiKuXbv20Ucf/fM///P3v//9v/iLv/hfO/jRj36Umpr6/Pnz9l3R0dGx/cP2zy/Q09Nz/Pjx73//+zvP+5d/+Zc//vGP33333S+++OLGjRs3btzIz8/fxa6HgK8DGB8AOFxYLJaTJ09dvnzlv/7rv375y1/+6Ic//M53vvO//pT/839+eP/+/co3p6amprq6ury8vLKysq6urqKiAvr5ZRoaGj799NPvfe97L5z6r/7qr37605++++67J06cuHDhAjC+ZwHGBwAOF2azOSQkdHp6Go1Gt7Q8S0hIuHjx4ocffviLX/zir//6ryHt/t2P/26gv5/L5fLeEDabPTY2VlNTs7S0RCAQWltbYTAYg8F4+UiBQODv7/83f/M3/98Z/+7v/uM//uP48eO3bt168uRJX18fDod7+vRpaWkpmNXxIMD4AMDhYufKrcVikUqlVCp1amqqubn50aNHfn5+H3/88Ucffri0tPSmK7cajQaNRg8ODra2tmIwmP7+/u7ubjQabTQav/L4tLS0P/7xjz4+PsHBwTk5OZDlORyOSqWCTj01NQVWbj0LMD4AcLgwm83R0dEvR2eazeb19XU2mz05OdnX1yeXyx0Ox59tzel0QnE1brcbi8WmpKQsLCwIBILk5GQYDLaysiKXy78u+JJAIAwMDBAIBB6Pp1Kptra2tpuCQKFQwPieBRgfADhcfJ3xt3E4HDtDJL8Oi8XC4/EwGAwSidRqtZubmzU1NeHh4TweT6lUnjt7dmpqymKxvKKRzc3Nzc3NV0T9A+N7HGB8AOBw8WeN/zrYbLapqSkUCoXD4VJSUsbGxqhUqn+A/5dfftnT01NXV/f7997Ly8tbXV19m6o4wPgeBxgfADhceMT4TCYzJyeHRqPZbLbS0tLKysq5ubnAwMDk5OTZ2dmcnJzr1693d3evr6+/TRoXML7HAcYHAA4Xb298p9PZ09OTmJioUChcLldtbW1HRweJRIqLi1tYWNjc3CwpKampqXn70j2vNr7D4VAqlTKZbHNz8y1PdGCAFmM0Gs3XrcEA4wMAh4u3N77dbq+srMzNzVWpVG63OykpiUgkzs3NRUVF8fl8p9P54MGDoaEhk8n0ll39SuPrdDo2m41Go9va2lJTU8vKytbX19/yRAeG5eXlgoKC7Ozs7u7u2dnZ1dXVF+4CMD4AcLh4e+M7HI7KysqEhASFQrG8vJyTk7O2tjY1NZWYmLi+vm6z2e7fv4/FYm0221t2FYVCVVVVra2tmUwmDoeDRCKfPm3JyMjw9/f/8MMPf/WrX73zzjtnTp9ms9lveaIDw/T09LFjx/7+7//vb37zm6NHjwYHB+fl5bW1tc3MzAgEAovFotFompqagPEBgMPC2xvf5XLh8fjc3Fw0Go1CoYhEosFg6Ovre/r0qUaj4fP5BQUFLBbr7XcyQaPRUVFRubm5KSkpfn7+//3f//2LX/ziJz/5yc5M3ffee6+9vR0LwGLxeHxFRcW7774LvTLf+c53fvCDH7zzzjv/+q//duTIkaCgW1mZWVVVVSkpKcD4AMBhwSMrt1arlU6nEwgEkUhks9l0Ol1tbS2VSt3c3BwbG+vu7lYqlW9fbHlycvLEiRP/+bvfvfPOO9/97ov1GCB++ctfPnz48Mm3S0FBQWFhYX5+/rd83ldTUlJy586df/zHf3z5VfrOd77z/e9//x/+4R+OHDly8+ZNNBr9lrfmZYDxAQBvxCPGd7vdTqfTZrNBeyjS6fSWlhaJRCIWi9va2ggEgtVqffuuolCo6OjokuLi9PT0GzdufPTRRz//+c//9m//9rvf/e52LaD33nuvo7197lsESkGAwWATExPf5nn/LHg8vry8/N///d+3Lf+9733vxz/+8b/+678ePXo0JCQkLy+vrq4uLS0NjPEBgMOCp4wPsbm52dzc3N7eTqVSiURiRUXF2NjYa+br/lm2V25NJhOXy52ammpra8vJybl5M+ijjz76l3/5l5/85Cenv/V5fKvVSiaTS0tLGQzGt3ne12FqaurY0aPvvPPOr3/962PHjoWGhhYWFnZ3d2OxWJFIZLVawcotAHC48KzxrVbr+Pj4/Py8xWJZXl4eGRmRSCQe0b37a2J19Ho9VAqis7MzOzu7pqZGLpd75HSvydbWFhKJjImJmZ+f/zbP+zqw2eyy0tKC/HwYDDY7O8vj8cxm884DgPEBgMOF2WyOjIz0lPEdDgdUD8flcm1ubr66MMOb8updD10ul1qtVigU3348/sjISGlp6crKitvttlqtKysry8vLRqPRbDYLhUK9Xm+32wUCATSs/jY7ZjabZTKZTqf7ukUUlUoFdj0EAA4RZrP5wYMHGo1mrzvy55mcnKypqfHCcPv6+vrW1laFQqFSqZhMJhKJrKysnJ2dJRAIhYWFWCxWIBAUFRc3NjZ6W+dVKlVLS8vk5KTHWwbGBwC8ka2trbGxMYvFstcd+fPweLz5+XmDwbDXHXmRzMzMgYGBjY0NOBw+MTGBQqGysrIQCAQSifT393/69CmLxYqIiEhPTxeJRHvd2T/BZDItLi7yeDyPtwyMDwB4Iy6X69UlLb0Hu90OhQPtdUf+BK1Wm5iYODU1xePxkpKSnj9/DofDR0dHpVIpDofz9/Pv7OyUy+UpKSk1NTUKhWKv+/snOJ3Ozc3Nb2LPemB8AABwAFlaWsrJyaFQKBQKJS4ubmBggM1mQ/X9+/r6oqOj8Xg8l8vNyMjo6+vT6/V73d9vCWB8AABwAOnq6kpISMDhcAgEIiEhYXFxUa/Xa7Vag8FQVFRUWVm5traGRCLv3r3b3d2t0+n2xb9Tbw8wPgAAOIBUV1fHxMSg0ejJycnU1FQEAkGlUldXVzc2NvLy8hAIhM1mGxwcDAsLa2trV6vVwPgAAACwX5mbm0MikSKRSKFQIJFIJBLJYrFUKpVer5+ZmYGWahkMBhwOZzKZVqsVGB8AAAD2KxaLZbtInMlkksvlUOCT3W63WCzQoqjVavXCNedvFGB8AAAAOCwA4wMAAMBhARgfAAAADgvA+AAAAHBYAMYHAACAwwIwPgAAABwWgPEBAADgsACMDwAAAIeF/xc5iZ3H6TFEHgAAAABJRU5ErkJggg==" alt="" />
如果addr参数为NULL,内核会自己在内存地址空间中选择合适的地址建立映射。如果addr不是NULL,内给内核一个提示应该从什么地址开始映射,内核会选择addr之上的某个合适的地址开始映射。建立映射后,真正的映射首地址通过返回值可以得到。len参数是需要映射的那一部分文件的长度。off参数是从文件的什么位置开始映射,必须是页大小的整数倍(在32位体系统结构上通常是4K)。filedes是代表该文件的描述符。
prot参数有四种取值:
- PROT_EXEC 表示映射的这一段可执行,例如映射共享库
- PROT_READ 表示映射的这一段可读
- PROT_WRITE 表示映射的这一段可写
- PROT_NONE 表示映射的这一段不可访问
flag参数有很多种取值,以下是其中两种:
- MAP_SHARED 多个进程对同一个文件的映射是共享的,一个进程对映射的内存做了修改,另一个进程也会看到这种变化。
- MAP_PRIVATE 多个进程对同一个文件的映射不是共享的,一个进程对映射的内存做了修改,另一个进程并不会看到这种变化,也不会真的写到文件中去。
如果mmap成功则返回映射首地址,如果出错则返回常数MAP_FAILED。当进程终止时,该进程的映射内存会自动解除,也可以调用munmap解除映射。munmap成功返回0,出错返回-1。
mmap函数的底层也是一个函数调用,在执行程序时经常要用到这个系统调用来映射共享库到改进程的地址空间。