php 常用自定义函数

文件类

获取某个tp根目录下面的某个目录

//获取uploads 文件夹路径
function uploads_path(){
    return dirname(__DIR__).DIRECTORY_SEPARATOR.'uploads/';
}

获取文件路径最后一级目录

function getPathDir($path){
        return substr($path,0, strripos($path,'/'));
}

获取真实的后缀名

/*
@desc:获取文件真实后缀
@param   name    文件名
@return  suffix  文件后缀
*/
public function getfilesuffix($name) {
    $file = fopen($name, "rb");
    $bin = fread($file, 2); // 只读2字节
    fclose($file);
    $info = @unpack("C2chars", $bin);
    $code = intval($info['chars1'] . $info['chars2']);
    $suffix = "unknow";
    if($code == 255216){
        $suffix = "jpg";
    }elseif($code == 7173){
        $suffix = "gif";
    }elseif($code == 13780){
        $suffix = "png";
    }elseif($code == 6677){
        $suffix = "bmp";
    }elseif($code == 7798){
        $suffix = "exe";
    }elseif($code == 7784){
        $suffix = "midi";
    }elseif($code == 8297){
        $suffix = "rar";
    }elseif($code == 7368){
        $suffix = "mp3";
    }elseif($code == 0){
        $suffix = "mp4";
    }elseif($code == 8273){
        $suffix = "wav";
    }
    return $suffix;
}

获取文件路径不带扩展名

//获取文件路径不带扩展名
function getPathClearExt($path){
        return substr($path,0, strripos($path,'.'));
}

获取文件路径文件名

function getFileName($path){
        return substr($path,strripos($path,'/') + 1 );
}

获取文件路径扩展名

function getExt($path){
        return substr($path,strripos($path,'.') + 1 );
}

删除某个目录下的文件

/**
 * 删除某个目录下的文件
 *
 * 主要用来删除上传文件的临时文件
 */
function deleteFile($path){
    //如果是目录则继续
    if(is_dir($path)){
        //扫描一个文件夹内的所有文件夹和文件并返回数组
        $p = scandir($path);
        foreach($p as $val){
            //排除目录中的.和..
            if($val !="." && $val !=".."){
                //如果是目录则递归子目录,继续操作
                if(is_dir($path.$val)){
                    //子目录中操作删除文件夹和文件
                    deleteFile($path.$val.'/');
                    //目录清空后删除空文件夹
                    @rmdir($path.$val.'/');
                }else{
                    //如果是文件直接删除
                    unlink($path.$val);
                }
            }
        }
    }
}

读取文件夹下所有文件

/**
 * 读取文件夹下所有文件
 * @param $folder
 * @return mixed
 */
function scanfiles($dir){
    $arr = array();
    //列出文件下的目录
    $hander = scandir($dir);
    //遍历文件夹下所有文文件
    foreach ($hander as $v) {
        //判断文件夹下是否还有文件夹需要遍历
        if (is_dir($dir . '/' . $v) && $v != "." && $v != "..") {
            //有二级文件夹
            return false;
            //递归调用
            $arr[$v] = scanfiles($dir . '/' . $v);
        }else{
            //排除  "." " .."
            if($v != "." && $v != ".."){
                //文件存入
                $arr[]=$v;
            }
        }
    }
    return $arr;
}

读取文件内容至字符串中,同时去除换行、行首行尾空格

/**
* 读取文件内容至字符串中,同时去除换行、行首行尾空格
* @param string $filePath
* @return string|string[]|null
*/
function readFileAndTrim($filePath = ''){
    if(empty($filePath)){
        return '文件路径为空';
    }
        return preg_replace('/((\s)*(\n)+(\s)*)/i',',',file_get_contents($filePath));
}

复制文件(如果路径的目录不存在就创建)

function copyFile($src,$dest){
    if(empty($src) || empty($dest)){
        return false;
    }
    if(!file_exists($src)){
        return false;
    }
    if(!is_dir( getPathDir($dest) ) ){
        //目录不存在则创建
        if (!mkdir($concurrentDirectory = getPathDir($dest), 0777, true) && !is_dir($concurrentDirectory)) {
                throw new \RuntimeException(sprintf('Directory "%s" was not created', $concurrentDirectory));
        }
    }
    //复制文件 成功返回true 否则返回false
    return copy($src,$dest);
}

创建目录,可多级

/** 创建目录 可多级
*
* path 文件路径
*/
function mkdirs($path){
    if(!is_dir( getPathDir($path) ) ){
        //目录不存在则创建
            if (!mkdir($concurrentDirectory = getPathDir($path), 0777, true) && !is_dir($concurrentDirectory)) {
                throw new \RuntimeException(sprintf('Directory "%s" was not created', $concurrentDirectory));
            }
    }
}

随机数

任意字符随机

/**
 * 随机生成id,默认10位,不要O,o,0
 * @param integer $length 生成id的位数
 * @return string 生成的随机id
 */
function getRandomChar($length = 10){
    // 密码字符集,可任意添加你需要的字符
    //$chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
    $chars = 'ABCDEFGHIJKLMNPQRSTUVWXYZabcdefghijklmnpqrstuvwxyz123456789';
    $str = "";
    for ( $i = 0; $i < $length; $i++ ){
        $str .= $chars[ mt_rand(0, strlen($chars) - 1) ];
    }
    return $str ;
}

随机验证码

/**
 * @param int $len 生成随机数长度,默认为6
 * @return string
 */
//随机数
function getRandomCode($length = 6) {
    //取10的长度减1次方的值,例:length为6 10的5次方 100000
    $min = pow(10 , ($length - 1));
    //取10的长度次方的值,例:length为6 10的6次方减1 999999
    $max = pow(10, $length) - 1;
    //获取并返回该范围的数
    return mt_rand($min, $max);
}

字符串类

将id分割为2位一组的数组

/**
 * 将id分割为2位一组的数组
 * @param [type] $str  要分割的字符串
 * @return array
 */
function stringToArray($str = null){
    if($str === null){
        return false;
    }
    $arr = array();
    for($i = 0, $j = 0; $i < strlen($str); $i+=2,$j++){
        $arr[$j] = substr($str,$i,2);
    }
    return $arr;
}

字符串或数组编码转换

ANSI编码编码问题:

https://blog.csdn.net/qidizi/article/details/8790371

https://blog.csdn.net/qq_30736263/article/details/103290323

/**
 * 对数据进行编码转换
 * @param array/string $data 数组
 * @param string $output 转换后的编码
 * Created on 2016-7-13
 */
function array_iconv($data, $output = 'UTF-8') {
    //EUC-CN 为 ANSI编码
    $encode_arr = array('EUC-CN','UTF-8', 'CP936','ASCII','GBK','GB2312','BIG5','JIS','eucjp-win','sjis-win','EUC-JP');
    if (!is_array($data)) {
        $encoded = mb_detect_encoding($data, $encode_arr);
        return mb_convert_encoding($data, $output, $encoded);
    } else {
        foreach ($data as $key=>$val) {
            $encoded = mb_detect_encoding($data[$key], $encode_arr);
            $key = array_iconv($key, $output);
            if(is_array($val)) {
                $data[$key] = array_iconv($val, $output);
            } else {
                $data[$key] = mb_convert_encoding($data[$key], $output, $encoded);
            }
        }
        return $data;
    }
}

请求参数字符串转数组

/* 将一个字符串转变成键值对数组
 * @param    : string str 要处理的字符串 $str ='name=123&sex=1&num=12';
 * @param    : string sp 键值对分隔符
 * @param    : string kv 键值分隔符
 * @return    : array*/
function str2arr ($str,$sp="&",$kv="=")
{
    $arr = str_replace(array($kv,$sp),array('"=>"','","'),'array("'.$str.'")');
    eval("\$arr"." = $arr;");   // 把字符串作为PHP代码执行
    return $arr;
}

RGB转十六进制

/**
 * RGB转 十六进制
 * @param $rgb RGB颜色的字符串 如:rgb(255,255,255);
 * @return string 十六进制颜色值 如:#FFFFFF
 */
function RGBToHex($rgb) {
    $regexp = "/^rgb\(([0-9]{0,3})\,\s*([0-9]{0,3})\,\s*([0-9]{0,3})\)/";
    $re = preg_match($regexp, $rgb, $match);
    $re = array_shift($match);
    $hexColor = "#";
    $hex = array('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F');
    for ($i = 0; $i < 3; $i++) {
        $r = null;
        $c = $match[$i];
        $hexAr = array();
        while ($c > 16) {
            $r = $c % 16;
            $c = ($c / 16) >> 0;
            array_push($hexAr, $hex[$r]);
        }
        array_push($hexAr, $hex[$c]);
        $ret = array_reverse($hexAr);
        $item = implode('', $ret);
        $item = str_pad($item, 2, '0', STR_PAD_LEFT);
        $hexColor .= $item;
    }
    return $hexColor;
}

十六进制转RGB

/**
 * 十六进制 转 RGB
 */
function hexToRGB($hexColor) {
    $color = str_replace('#', '', $hexColor);
    if (strlen($color) > 3) {
        $rgb = array(
            'r' => hexdec(substr($color, 0, 2)),
            'g' => hexdec(substr($color, 2, 2)),
            'b' => hexdec(substr($color, 4, 2))
        );
    } else {
        $color = $hexColor;
        $r = substr($color, 0, 1) . substr($color, 0, 1);
        $g = substr($color, 1, 1) . substr($color, 1, 1);
        $b = substr($color, 2, 1) . substr($color, 2, 1);
        $rgb = array(
            'r' => hexdec($r),
            'g' => hexdec($g),
            'b' => hexdec($b)
        );
    }
    return $rgb;
}

判断类

判断一个字符串是否是颜色值

 /**
 * 判断字符串是否是颜色值,如:#FFFFFF
 * @param $str
 * @return bool
 */
function isColor($str){
    $match = '/^#([0-9a-fA-F]{6})$/';
    if(preg_match($match, $str)){
        return true;
    }
    return false;
}

判断字符串是否以什么开头

/**
 * @param string $str 被检索的字符串
 * @param string $headStr 开头字符串
 * @return bool
 */
function isStringHead($str = '',$headStr = ''){
    if(strlen($str) <= 0 || strlen($headStr) <= 0 ){
        return false;
    }
    if(substr($str, 0, strlen($headStr)) === $headStr){
        return true;
    }
    return false;
}

判断字符串是否以什么结尾

/**
 * @param string $str 被检索的字符串
 * @param string $EndStr 结尾字符串
 * @return bool
 */
function isStringEnd($str = '',$EndStr = ''){
    if(strlen($str) <= 0 || strlen($EndStr) <= 0 ){
        return false;
    }
    if(substr($str, strlen($str) - strlen($EndStr), strlen($EndStr)) === $EndStr){
        return true;
    }
    return false;
}

判断字符串是否符合ids的格式

/**
 * 正则匹配字符串,只能以数字开头和结尾,中间可以是数组和英文逗号,数量不限
 * @param $str 要校验的字符串
 * @return bool
 */
function matchStrIds($str){
    if(strlen($str) === 1){
        if(preg_match("/[0-9]/",$str)){
            return true;
        }
    }
    if(preg_match("/^[0-9]([0-9,])*[0-9]$/",$str)){
        return true;
    }
    return false;
}
dump(matchStr('123,45'));
dump(matchStr(',123,45'));
dump(matchStr('123,45,'));
dump(matchStr(',123,45'));
dump(matchStr('123,'));
dump(matchStr(','));
dump(matchStr(''));
dump(matchStr('12'));
dump(matchStr('1'));

/*
bool(true)
bool(false)
bool(false)
bool(false)
bool(false)
bool(false)
bool(false)
bool(true)
bool(true)
 */

数组类

对象转数组

/**
 * 对象转换成数组
 * @param $obj
 */
function objToArray($obj)
{
    return json_decode(json_encode($obj), true);
}

对象转数组

function objectToArray($e){
        $e = (array)$e;
        foreach ($e as $k => $v) {
            if (gettype($v) == 'resource') return;
            if (gettype($v) == 'object' || gettype($v) == 'array')//多级对象
                $e[$k] = (array)objectToArray($v);
        }
        return $e;
    }

数组转对象

public function arrayToObject($e){
    if (gettype($e) != 'array') {
        return false;
    }
    foreach ($e as $k => $v) {
        if (gettype($v) == 'array' || getType($v) == 'object')//多维数组
            $e[$k] = (object)arrayToObject($v);
    }
    return (object)$e;
}

对象数组自定义排序

 usort($result, function ($object1, $object2){
 //倒叙
        return $object1->create_time < $object2->create_time;
 });

数组多条件自定义排序

//type 为 2 保持不变 其他按type值升序, 如果type值相同,则按price升序
usort($data, function ($item1, $item2){
    if($item1['type'] === 2 || $item2['type'] === 2){
        //保持不变
        return 0;
    }

    if($item1['type'] == $item2['type']){
        return ($item1['price'] > $item2['price'])? +1 : -1;
    }else{
        //升序
        return ($item1['type'] > $item2['type'])? +1 : -1;
    }
});

删除关联数组的空值

/**
 * 删除数组中value为空的
 */
function delArrayEmptyValue($array = []){
    foreach ($array as $key => $value) {
        if(!isset($value) || empty($value)){
            unset($array[$key]);
        }
    }
    return $array;
}

过滤数组中的空值和重复值

function filterEmptyRepeatValue($arr = array()){
    $tmpArr = array();
    foreach ($arr as $key => $value) {
        if(!empty($value) && !in_array($value, $tmpArr)){
            array_push($tmpArr, $value);
        }
    }
    return $tmpArr;
}

数组转xml

//数组转换成xml
public static function arrayToXml($arr) {
    $xml = "<item>";
    foreach ($arr as $key => $val) {
        if (is_array($val)) {
                $xml .= "<" . $key . ">" . arrayToXml($val) . "</" . $key . ">";
        } else {
                $xml .= "<" . $key . ">" . $val . "</" . $key . ">";
        }
    }
    $xml .= "</item>";
    return $xml;
}

xml转数组

 //xml转换成数组
 public static function xmlToArray($xml) {

    //禁止引用外部xml实体
    libxml_disable_entity_loader(true);

    $xmlstring = simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA);

    $val = json_decode(json_encode($xmlstring), true);

    return $val;
}

数组转请求参数字符串

也可以使用http_build_query()

/**
 * 数组转请求参数字符串
 * @param $array 要处理的数组
 * @return string 如:name=123&sex=1&num=12
 */
function arrayToString($array){
    $string = [];
    if($array && is_array($array)){
        foreach ($array as $key=> $value){
            $string[] = $key.'='.$value;
        }
    }
    return implode('&',$string);
}

SHA256WithRSA签名和验签

生成签名

//生成 sha256WithRSA 签名
function getSign($content, $privateKey){
    $privateKey = "-----BEGIN RSA PRIVATE KEY-----\n" .
        wordwrap($privateKey, 64, "\n", true) .
        "\n-----END RSA PRIVATE KEY-----";

    $key = openssl_get_privatekey($privateKey);
    openssl_sign($content, $signature, $key, "SHA256");
    openssl_free_key($key);
    $sign = base64_encode($signature);
    return $sign;
}

验证签名

//验证 sha256WithRSA 签名
function verify($content, $sign, $publicKey){

    $publicKey = "-----BEGIN PUBLIC KEY-----\n" .
    wordwrap($publicKey, 64, "\n", true) .
    "\n-----END PUBLIC KEY-----";

    $key = openssl_get_publickey($publicKey);
    $ok = openssl_verify($content,base64_decode($sign), $key, 'SHA256');
    openssl_free_key($openssl_public_key);
    return $ok;
}

zip压缩与解压

压缩

/**
 * 压缩文件
 * @param array $files 待压缩文件 array('d:/test/1.txt','d:/test/2.jpg');【文件地址为绝对路径】
 * @param string $filePath 输出文件路径 【绝对文件地址】 如 d:/test/new.zip
 * @return string|bool
 */
function zip($files, $filePath)
{
    //检查参数
    if (empty($files) || empty($filePath)) {
        return false;
    }

    //压缩文件
    $zip = new ZipArchive();
    $zip->open($filePath, ZipArchive::CREATE);
    foreach ($files as $key => $file) {
        //检查文件是否存在
        if (!file_exists($file)) {
            return false;
        }
        $zip->addFile($file, basename($file));
    }
    $zip->close();

    return true;
}

解压

注意:最好使用winrar 工具压缩的压缩包,其他的压缩包工具解压出来文件名会乱码

/**
 * zip解压方法
 * @param string $filePath 压缩包所在地址 【绝对文件地址】d:/test/123.zip
 * @param string $path 解压路径 【绝对文件目录路径】d:/test
 * @return bool
 */
function unzip($filePath, $path)
{
    if (empty($path) || empty($filePath)) {
        return false;
    }

    $zip = new ZipArchive();

    if ($zip->open($filePath) === true) {
        $zip->extractTo($path);
        $zip->close();
        return true;
    } else {
        return false;
    }
}

图片类

图片转Base64编码

/**
 * 获取图片的Base64编码(不支持url)
 *
 * @param $img_file 传入本地图片地址
 *
 * @return string
 */
function imgToBase64($img_file) {

    $img_base64 = '';
    if (file_exists($img_file)) {
        $app_img_file = $img_file; // 图片路径
        $img_info = getimagesize($app_img_file); // 取得图片的大小,类型等

        //echo '<pre>' . print_r($img_info, true) . '</pre><br>';
        $fp = fopen($app_img_file, "r"); // 图片是否可读权限

        if ($fp) {
            $filesize = filesize($app_img_file);
            $content = fread($fp, $filesize);
            $file_content = chunk_split(base64_encode($content)); // base64编码
            switch ($img_info[2]) {           //判读图片类型
                case 1: $img_type = "gif";
                    break;
                case 2: $img_type = "jpg";
                    break;
                case 3: $img_type = "png";
                    break;
            }

            $img_base64 = 'data:image/' . $img_type . ';base64,' . $file_content;//合成图片的base64编码

        }
        fclose($fp);
    }

    return $img_base64; //返回图片的base64
}

Base64编码转png图片

     /**
     * base64 编码转png图片
     * @param string $image  base64 图片字符串
     * @param string $descPath 转换后图片保存路径
     * @return bool true 成功, false 失败
     */
    function base64ToPngImg($image = '', $descPath = '') {
        //判断是否有逗号 如果有就截取后半部分
        if (strstr($image, ",")) {
            $image = explode(',', $image);
            $image = $image[1];
        }
        //生成图片
        $r = file_put_contents($descPath, base64_decode($image));//返回的是字节数
        if (!$r) {
            return false;
        }
        return true;
    }
    
    //使用示例
    $image = "data:image/jpg;base64,/9j/4AAQSkZJRgABAQEAYABgAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wgARCAInAVoDASIAAhEBAxEB/8QAGgAAAgMBAQAAAAAAAAAAAAAAAwQAAQIFBv/EABgBAAMBAQAAAAAAAAAAAAAAAAABAgME/9oADAMBAAIQAxAAAAHhKOpzp0e3xu5NKKuqB5yXGm6EYStaIC+iGEsYkGu6m8n2CVcWjz9cCloMmmUk01m7iJnUDNyMu8xM1i2r6HqPF92K7u5uTE1Y6m4LzfNeR1jqd3h92KWUbAzzGmbc88rFiT3gg8byUL0MoZbEVPu8/oebmuSKb1yzd2FXdjxojCYCOGDjCeWaDe4LNEtVbS9qvXveM9fFFvG5LurDyyTie2fT73B70UstviNJ1caooyguTGhUYJQsgbG/pZxV0fHeg8wFao1xiXsLOXqq03nTpoX0bRxV/QCDyyXruW54RYIG12orU9T5jtE+j2Iuda1Ww8vz2ldc+p3eF3prmpOcwa8VlQzpU4AlbDBIcF4zYRwJk0eJ0EKWy0Jq3VO8qN1bZVDJvQYskQLDGVSyHXCn5Pm+u4dRznFjphbXdH6coWJU1IjyCzK2ufV7vC7irmcjrc1PmySohwmBYgyCooihmS0OHXMVx07up2O7Y76vk+gmilyQe5q6Q5ukYrVKqkvPTPB9Gin4rDnPuGury+wHXPgqm61hPyCxB6Z9bucLuq+Sk5zUA0ndR0V0jiEQewp5HAdUIaQ6A6I+WUWrm2ANqvVv+bbT9ATmvAxoW6NZlCzKqal5uNLVOGL83w/Q+d1yd7XE76fZ3W1NCJkXjlzguet3OH3JvjoP84OeYJajdgyBdrbE1aegaFdgzxu1xhr0YVI3o+V6OaGEmh89rpaaI0owg+cgb2BJBHb1525v0k4PTilPMeq8pcM+m8v6wOlqtKcVMM8cFlap6vd4XcnTj87oIC55NlqFctZEvolgHRSBnZYMnH7XFToHQVo7Oe1qb8ur6hCo5vrfPdpN8wGUZVYSHql/O1PqCeR6c36KqYz04/jfX+WvM3s/Ie0Bm6onAyBa8oDeGur3OH3JviIuoCSOBmpBm8hqXkVkGcNFXZTZ5XY55TA3yldYgzqgg6VOOYw1TQzCKhYR8quf5v2ILnzvQ6Dmegnd3F+UwMlC3r+N23lrGsOcD1hryGdZZ1e5wu5NcNB7ntKuJMOSg2uIsHkGjokCNBYG6h0+fNuGDE+y1z3m2JiVOhUACnXYTxgoorWSXpGC51nrYtozXJyVtzfRUbvGD1hoZBtB4SiCZ1e3wu7NcPnvqtInxhywmcAtVdCYzMj00o6n1Uekir1neE33+awx/IIzdwQNbQyHRAqWLb0DWkFsOs9K5x+UTT4mXDu825wPYWF1Wg8NKtnT7nC7kVw+e+g0tZJU2B5YVXrAMQVAwwg+n2VnBzpzd52hkgxM6OZdLWuL1SyUrlU3FVieroOnJc5QmmeZ00FDjynQpaq8NZHqNG3i1XiR1Yuj2+H3JrhKN85odVdScBwC3nUDemrADODj7WavPTnwgwKhvDOs3zOhSSH0kTYwwYmxdC2TPNSiFM4KDCBWSWzCK1oehtZIFhrQiAm/Ga1ly/2+J25rgcjtcqpy2lqp6KxIFkHmpZxVVO83kXQPznstrXe1N8oqPLa9K94tpz7iI9BsdGpXQsKZ6HyIqSjYT1C/QUcETeNNQehNaYCYBh1U143eN3L/AG+H25vi83oc9yN4JaiqkqIyQuFcyMp6Ses1tG3UTTfRX3zM9eVVyoqXGE9F5h9V6FnzDUaekLw+pnqNwdyg5eE5CStXG7qhUPWKTGpgA3mTXjyjJUudvidtVxUnRtYFqtMqYo+YbWNclB53VQ0QtjL3ZD1WR9jlO8nPRWajMyWgnYUaL4V6y51rGkG9J5Z6NPbaEXHYY2MkiwQWmedDNUlEQKebkH5HQTOWu3xO0q5AjJ3GLl6ZOWu5y2Mqx8TaTqzEiCJ25ZmhWEAUyoOylDm308KuPsQk71mw1edI0YDyv1zImOffOdCAnA6/hbjren4Ho6kYjBFJUDxxhFctdTl5GEaDemZpUuJ0+Uzi962ty28EowQqx9cFqtazogyJ63VpnFrA+MBgCclwLktPXoOH7KNHChJlrkRFQ4nC11N8PRG5oc7fNz2bk1FEn5HYTtG5b/KaklVD5eYzUsXnJPVRbS4tH6zpPnDIPqg2CY0RWwGHrOsTV4sYbV6qrOHC0jNnwq6PpuX1MtS2JWad5OVdMhNDl52bNgZhRiaeqtFeLeyyxbld2qng57YGuVGlkmSos1HTUOty29oSqA2u/wBCk1LRShKBqscWCLSpcBRGsYKWapoWprpY5w5pjGZee8Ewy94IBNY1LKwmzNNazkrgg5d65dTfOtrqa4pk+kpca5se56OkuIebKGXTnV5nUZUkc7MAwbVLzk4YBHJth00yZXUaaKM0sIyCpEIHQiTAwLkREynosVpgBmz1MD8Xn0CuuXInRiOdXVXbSu6FdSIkkC7qx66PMcEaTTVkEaWov0OdIJhO7GyoFacKq5LNcDN4rY3O7FEZmzS9sCPhZtYNFLnwbqhLPKQo9DNS0LIxtaStUmquIqXAq5AkkHp1N4WoIrR9TOF55XQ5jWZJqpdQGHOZaO4Lm6VPl5cT6ocDyZDgakIYJ86KTBIq9VOiecB7FupF98okQTlQV0iSROSUK5VhLoobacWhruBy03kdY2uowPeAVIySQJdQL3ix6lWmYoGc2wUUypplY+dHILcMuNC6pDVwpBbO+nlIi7zRDkk3JIEkgVJAhgxHbPwuthUXag01GENZ0ZfdrFyBUuBUuBVyBqZ0mRxIs0ZgTeNbNi82XQN6pqVeiBJIvjkzrq5K5ryCrMuKquRFSUEkgS7eTw/LwcXHz6KqTaYYRQzhtRkkiJJAklBd1AJ0Oc1FtHSrJu0ge02YBmMbEQrOqkVy6udXJSD+B863ty0a6Ig5tGsoJGLRbvLDJ0kBQJV1RJLCXUBoNmYpJESrgSrgSSBt1HrTSRGrzYTCkvoHQZzpvOsaFVUb5s3OrkzV2ElxOZ3SYs1AAq7hidHiYIwBOpIFXIEkgEOscS9EyPMuBUkCSQN9TmdGaqtrw+mHL+Vc5kUT6eatuSSxDBxdHNUvYDJrUaZGYKY8H1pmjTAGqrVBB7tNLDoEwyQJJAmswGKEwFaZ0HOz01xJQ4hkcCRPLabg8vB3jbCzkwrF3nQlVNAN1KiSWOpJLoRl7kmqvSMqOrCXrNudaq06l6QkHoojHJGSSJTWYNtjnvtXnWQsZqCA3hPbqrqrUm5s2xb53eJVuarVC93Tm8zQ6kwEXMvWbN1ekwZBjGuzQApmkA1vDVLMQXOpkA8y6FJIFtK7H0sXQqq6DGdQCurMzeryVXu5jNy60FyoAZLakmAkuAMBl9M3JUpQexlZqonq6sWrzoF8N4EtneWgBboE4YIS6tDp1HAFWo0M2DjLqiTeiSoqVcl3JQS6jB1mNXKoNTMAQbzri3YTDyMgisyrTu6sV6zoJKgZCxATtmhLCfwHMp7AtOkNlfMjI9YGxRhwtbi7zcmpdREzIy6kAV1TUqWF4IMSlnHpiNznNOiipYZtc5hNq86DV50EqUFyUEqxhu02Q3qiZh9Y1lclWyXWrJJkcuQLqZC5Vil50C9yMu5ArMkzKkiEVpNweZLJcgbbkBiSKlwyCyxIDHMkAb0gNEkTJuRVckzd3I3VSBckFVSBckC5IH//xAAvEAACAQIFAwQCAgIDAQEAAAAAAQIDEQQQEiExIDJBEyIwMyNCFDQFQyQ1QBVE/9oACAEBAAEFAsN9ZLtp9uJ7V/SESpuUv49QcWiPdm+wqFJfjKnNWrpUpX+TVlhquipF3Vi3Thvr8y7afZie3/8AALnXG8ZK2uRGbupq3sZogVFbKp9i2h4xNbSSk5ddi3VcRhKpHqoafR8y7afZiO2X/XEe6XNPKPIhV2Td3DeT3reK83TjUm5yztnYjE9MlG3UinLS6NTVFdOF7PMuIduI7W9P+O9dnrI1QZ7NBHgUXJehMcJFFflp71pcY2rd9NhRFTZCA47VEWzsWEajDVnCpF3XRhe3zLth24jir/1ma7BdouxNoVSZSqSc6C/LUZWd59CQoEKRGkememSojoInRaHG2SY1s0LnBT1QFnhe3zLth243ter0c/8AWLtP0yo84bvrzsPdiQyKIQuQpEYGk0ljSOA4FakSjbKDupIt7sHLTUXRh5Jw8viHbjRpywfoTP49Q9CoelNU9Mi3tsz9cqfbhucZLYRLZIpxuUqZGJYsWLFiw0VYFWkOJDZ8pmFf5Y9GF48viPGMKj/4pcuxyfpamanpVSR6s0vXmevI1OVGh2Yt3qERu7jzQpEYFi3VYlAnR2qUrNxsRezMJF64dGFPL4jxjSp9GcvqP1Hxkv68PbQrvceVCnqlShZJCRYt1uKZiKVnUViBbfCIhxnh00eXxHjGc1v6+c+wfBLP/VP24Vu7iPdmEp7RyXxYhbV0R5RhiK2zw82zy+FxjO6pLTQ9SIpxZZlbkeUZDlaHqMnxipWpC2iilHVOikor5Km6xK2jyjC8row638sXGM7q/wBJ+muRJ3RLkl3L6yr3V5fmfOVJ6XHEStHFWIYmEhSuX+GXGJXtXKMGs3lhefLFxjO+v9RFJx00SXpl4F4atVM1wJtNLmpvVqb1mrMirlLDxt/FiPB3Hh5wcJzgQncTybHNDrRR/IiKvFimmSKyupK04mD7MnlhefLEYzvxHYLszfdk+Id/Nee2InyjDwvJNRTxFiGJi3qUjSmJWFlJlS7JUps9KYoTQtSIz1Kp2zfvgYT6ujDd3liMZ34jg/15Ll92UikvyU961fbEuP44K7w0Nq1SoinTdWUklVo15RnTleIhjLF0j1IiszShwRiPbR5cTDK1LooRkpeWIxv2Vaba9KZ6f41TiOMD2XvC+uIqhOrJSp1JOdD7q/8AZa/49CN5UadoVKKkKikVMFcpYXROncREnlUm7PE1JFOtVc6de8qUtUTHO1FQd0rzoq1IY8qE25+WIxv2V21l/qyj3eRcz76Pdh/txC/5WjVSwNP3RRYdM0M9NijlEqCW2hxKmEqKWGouD/jqq6FJ01YxrvUSXp4eN5LjJ5Ybv8sRi/sxPcP6co92UU7y7qPGF78V/ahtSox0SiLKxbOPEsnEszQyELCHxVeupV+qjT0zzeWH+zyIxX24j7DTqpKkhqCcdN1NIUxVMqX14Uxf9lfRCREXQ83lY0mnOrK0XC8ow11KG8h5M0mH+zy+TF/biPsNSjGNW83zHLS2o0Z30EUlSwvbjF+eP9cpvZZXHIuL4LlSWpzdhLTToR00xjFuyh9j5eWL+2v9mljpScY0dLYsk2o6m8o/VhvqxnMfo/aDIsuah8CLlxv3rolInLTHD++dTcWbIclLRrfLyxX21ajjN1JPKHIuD9Mv9WHX4cWrxp/VDuEy+bTLtDqEaot2mXLlyUt8TO0cPG0Ie6ebF2lD7POWJ+6v9mUcl2qEjSrew1ol209qVeN40uyP2MQiUlBKpFrXE2LItlcuXJz0rxWXtXtpQjpiMfRR+18+TE/dW3q+nI0EfTtdGp6b9EuV2T7EfuQn74k46oUl6TdKEj0qiNNYbqQVPEOrJZXstWqY/fXgtTyYyPPm5SUfUfIjEfdVnJTu3lHtP1GKLNCH9vh8W3y/3QeVWG8KkoCxCJ4klqqypU9Cyqv3Q5bsqKvKKsuiPHgo/a+RGJ+6q71Mo9p+tiKZJXFBCtrTumSNUbeoR5i7EXdNXJU7FjQ2QpaS2XBe7pcVpbUoaKa6fD4uUftfIjFfYJkYpkuxQZZIujwmXNW8KsjVJlhwyTRriUprKxpNJYlKxcn2i2jbVUzYyO78yyp6FN8i4r/dNe4SZFaVvmmLl5RdmhZYiqr6mXZTryg6GIjVSyuTqaS7kJkotwUdykvd0Mh0U/slyIr/AHVPsQtujQi1mcjWUJXSZiKmil0QnKnKjjdUf5aZCTkSgpKCSWm049ukfEVZLpXa+Mqf2S58Lit90++ER5wXtJo8rOk9zFy6qUL0vUVF/wD0JkP8jG0MRTkpWYmJDhvm8lz5lnD7Jc5VvukvycF8owulwSRLlZMjs1usX3dFOGuVSOiL5EIVScXhK2sWTj0Mhyh5w+yXOVX7rbsSIrfgWT4mI4zoyK89dSxbPC8qeon3iPL5oycKkXdZ2zjx4zjL3T7sqn2yecO2RF5PiaFmyDs5U7PTZuncdPf0np1umRq+3Pyxd1N+xdGPxGgwmIqSmPoj3T7jxV7286b3YuTxMebEPfJcWJFTu6fNGOqpBbDyqTVOnUqOrV/x1Lew10Lun3LiUtMHU1ZLJEdyZFi4kSFvmhc2EcjKvd0rnBUxZPL/ACNYirulFU6bqKJ6uoTumslzPu8YqpsnYjK5bJlKdia2iyPEiWwnlcTF0NlTu6YK8qUdMVkypNU4Sbq1MLT01HVbE9R4TPBZXn3OWmE5apZU53HlT5lx5gSJkcmQQl0S4hTTKmHtHowcLyWbZifyRhTjBp3Su8k7lyOS5l3T2h0Kpk1v4nzS4kVCA8lsLKwzkirKtP8AHpy0Gl3w1P04o1Eq6PWuXuPi5wcC9riRyjylvWTcdEjS10U5jIdk+aXbIm94K7ZHJZMbIM9R5SiKCukQSupJDrolNyF7hnEuCPOSSFYjlFdDWzpInS053uqb/HU5g7QnWL3KXbMjkspEpboQkWZGIyJO98uBFt+V4vmhcDmkeozWxTLrOdK41YTKb9k3u5u2VPtmIQuCpLZcnAmXuLKJNnmAi9x9vi4hbiWS7S7NQqg5mtkax6wqhLTpNe3RT7ZnhPJvabuR4LiyQtyKKhfb9ctYmJNkYmhi2Sz0tdd/gpvZ85IlduWy1EZXyTLkRGqw+fKdhuxqN7QjYQh7JESeJ0T/AJVM0odJSP45/GPQROmi3w0uMrZ1ecrkXtEjnyraRbml6rIQhCPFhGJ+zKxdGpDmVJfFFWiIWTJ89EZWIzQndeEdyXtG9xC6P1/WcFI9GOTHSHFE9viR4IlspvbquRlYlNsc2KbRr1RERLiyQyQ+icrFyUr/ABQjc4PMc57j+OIiKGyIhZeZdEpWOSWy+GEHJxgoxkt0jWKVycrRTuT4+KJEb0pCEIvYRLPVpL3ZUe/wwnpKdTUWuOI4GkqSu07F7x+KPKelJ3aELnUXuRJZvcR4lz8UJOLhNtZVp5r40bsjEUS1hu2XAh9CJcP46dPOpU0pu+cSS+JH6xE0iU1LNMTH0z4+FK5CkWOCdYbv0RZJXXwo1CkiUriuRTIrJdco2LFhQJRt0KJFKJdE6yRKo5dceJKz+BGnVBbZ3ExbiXXa5awkWJQunFmhihYukOY5N/DEl2/AiHa7X9OLHFxEJiZHjqtnfKwxtj+OI+34ER4qEJi9ynCwiLIv4rEtlm0aDQOBa3wJjXwR5Q+NJTZypw0uJD4bZS4iiSt1Sjcat13E7rSaGaDSWzhyNkWkvMRq60WI9DGIt0SIcNXHDqcbko260JkXfKyHG445RVkLdq5yL2tP5ZEe3J9c4/BTY+jRuMgIQxcD+OYuMqiN0LNZNElZ9SFuskN5Mh0L5ZC4yZJXWk0vpmvgpvrpizQ/kfK46rI0lms5QLdUWJ3XRYgs18rOfjcS2TQ4jj0030wWaXzSPOb+B7pprokuiHPRDJfPI85v4WrjiWZYsOJbKjG7nHojkvnbyTzfzOI0KminHSmrpwNDFESEvnlxkn7sn89hR/8AM9zQaGS9s1UJVEh1UamQnf4pS0pVd08ln5/8tbuuXzTsKbI1L5N2Xqo9ViqNEJ3yk7shO+S/8P8A/8QAIREAAgMBAQADAAMBAAAAAAAAAAEQESACMBIxQBMhQVH/2gAIAQMBAT8BEPShsb9EPSzRXk9IcpTQ0IoWEPSHCwihoWUPxWELaH4LKFD+8ofgtJw8oe6KGhY5h5Q9rLKOeZeEPyqH9RzHT0/OhwhsvTys/wBf6Uv+jW1CHlZ5fLVM/i5O6+kUPKhDmyyzllnyPlCbKH4IcpHSjl45OWj5CHzhShjFDhFyos5cNDWunCl5uUKO2LnLhOX4cwxu2fKi7lw1hwtIs66leawhD6L03F6YsKHis1tYU0UJFYZe0PwUMosbF+SxfisUrSL8EWXClFl+q8a9VqhIXJ19FeqFiio69l4dCiivJeHXqheD8KKiihIW3i/xP8n/xAAgEQACAgMBAQADAQAAAAAAAAAAAQIRECAwIQMSMUBB/9oACAECAQE/AcLhFcGtlsxC0vVrVbra8oeq3XC9mLs92LZcHhasXZ4WrFxQ8WJEsLVi6Isk92LgtF+8PC1YuC0Sw92LgurF1visUUUUNFFFYY2LgxCxP6HzneJLVlDE92IR9J0M+bpi9Hu0MTFqxY+q9wiD84vEIje/1jaz8uEsIXg42JZWEyX6EsfPhIojHVaf4V6V6LRYeKK2Wv4+iWFz/JdGxSy82OY5F+i5zZDSiihjx8/0XwUhlCVLaWGVZFUuMlQpC3kMqyMaHwbok7Iw4MoSSw+Eo2KKXFjePSMr/iY0PzEMWWOQu84lkcWXiPdjj6LWH8D2h/Muf5+lljfBSXKVlM9XF4h+uct//8QAMRAAAQMCAwYFBAIDAQAAAAAAAQACEBEgITFxAxIwMkBBIlBRcoEzQmGRYqETI3CA/9oACAEBAAY/AtrpDNEEFtviTQtXKsRa2Boh0WOXA22kM0QQW21EBGo7p27XJZmOULlI+VzEfCABrhFIqvz0O6b9pQY7sN0QQW09wgIp2kfEFYgKqC+Zqeo23thuiCCef5rJv6X02r6f9p26DDtINFylcpTUNY3R0eOV229sN0QQR99jodBWa5lieyEHpCK5W7X2wzRBBfxrYdYMfMu9sE9KRbtKNp4YZogmprRTmXb9rL+1ylcpzWRuenKk06Gt209sM0hqb7pzQWaGK5ihjGTf0jX1TumrbtPbDNIam62MgQNJGqJQ9elda/2w3SGrZ62M0hsDSWKqrZXoTa8E/bDNIatnVtV9NqP+tq+k1DCmEDSPt+Vk39LIfpN0TG2DjngP9sM0gaLZQVzIaQNIK+Yp+EPwLsVnxDJtf7YZpA0Wy0g7xWbv0vuXKVi1fT/tfTCbQUk2ZRzcDNZ2HgP9sM0gaLZe2DrYZbom6r5TtbeyzHCyVYKN7/bDNIGi2ftj5sMjRBBP1W9FVQBeMlHsFSuHEdItdUfbDNI+EzdH2rJZjNY7QLmXdcq5AuVv6VFnD9YKEkgqrrvCjjRUCx8LpKENtdUnlhmkfCYK/bA1kWFHSDrDq+vDPeqNBgi52arTFYmAETRA3H2wzSW+2G63BFP0RgJ356ElM2YzdmgPS46QzQT8Q3JfUCzJWRXKF2C+pD0UNE3oqrf/AEi646QzSfiG1FUBu2YLJYkI490U1N6LcGZWgQu+IZpPwFkmqu+IMYLOPmGodCSt9yDPW/CsMnCizsNrYahw63bogu9MBwWQbDpBWSFXLuVg0JmiEU9LalVqs+F+SYAvEMgxksXBHElcsiW6QYEFsEKnaq8JxnFUDZqqxu+ir6cAY1hkFEArOHW5LF1lJcZqvWMAs7A2KpzvXgiGQUaS6+s1igVb/wA2F0UF4kQyHRisBVHL44eEZrNU4YHCFK1hkFGceJRucg1WBxtrAkm6tjYZJ6OrTiscIyinHbrDJNuN9IaLnkZ5Lw4lcoXiCqCgRxm6wyTxm20W4y3BxW67PijWGSeLS4lFyNoPFAoimdEJCIVLxb/jafEhsz4rhrDIPVi0uPZF57o7Q6C4QxVWfV79o2QOqAQaLgimLdvPSgWFxRd6red2WC/KqEJzhpVZx6KpCc62tu7XBYRXuq91VD0tytoZHFpFBwTFQqqvaMMrsFlbQwOLXgUCKB7oGMUQqKhWPBw4GHBpwaqsUjHgUszk2041LqKiP4VeNjbTpKKirFfKK3VnCaFZrKM1nGHCPQ07qhy81xWU59dXj18goOnp0lPK6qtmHUUHlFTP56ATgs+kxmg8qw6MeWBYhYeV1jFV8qqP+AY/+eDFPNMbKdH/AP/EACcQAAICAgEEAgMBAQEBAAAAAAABESEQMUEgUWFxgaEwkbHB8PHh/9oACAEBAAE/Ifqh7EAn6hCQTNl7Gk1fcaFy9MfWoSuEQLHyY2XspB6zSG5ciXxsa7bfUmT0JiZLZsglsEzJikUIIIIPrR4T9AQtAMT9yGpcvdJpw/Igf+w5eH7RUN4nX8AKG/eCGiC2FuBJ+BCxLwSkzCJ92kNJb6IzbCBE4WC1JRKOPCy7retl7Hhf0cwjEn3iTVyJC/62M3ewhol2RChxLwQXghIfnBsyDiBjJIggQZApkhLAaIIIxOCxFKaY2F1K/wCtiQzEw2d13saH+kb0v9Q2zlHUy8bgQt9sYu/8Bty5yY7dLeFhZMfA5wQu08Js6GIxB849xVMSpW2haWuels0f1sf6ce8/eWPqCKfCaRl8iGmI/IpMmZ2s0qfJ8gFiDeF7PEQY66Jdo7Y0iGNeZLqRYHMZMSMIjBvAfrDNRl+39M9C/wCvjH8YhbZUf2Gx9keOqkNIxHfHlxgkRB4yFaFmtBTPGeAYwnDEBSLUxXdEWELCBQy3XI8N+kaKRtIdy3jPB+MGcb3g/wD5RJPT2LsMVL7zV3hI2CJV5wssb2stDBChBZDDxZExiuMbQDQ7hyViYS6Tbr9Y/wB2JZLueZ+xS97fJ5X7HtmxHQSLn3PKn8YAnJFxpFWjPQIpeBSYFSZGhFGCCCCMJSZiSNxEwWmhirQ1wIWNMqdPo29R6PPo/sw/vYjVyp5HG9gTI7LENCgQ5ZDVkEGIIxBBAlJAsDXgjYuzEcYWO04kMfXmg+oJd5ZXSG/gxA6V7YynD3Ntiy57DClcDYBKFgsQR0IQhi9jjYWu9kWHBJJm0mhYfUmo1fAhJE53iO0BC4f1EoGkNFjjwojh2F1I57MaeQ+QLGWfJ3ES8iWlihCy+hE4EIPg3CUIeJvYw19JqHN9BjJiF3RfsMZe4Y+gES+QnG8NPYiJRthNJC0PkSsgMJXRTFaMQTJG8TlvFJ6CuOeQhGuPtMNfSasV99ieRKVpCVtwZ4hdh/6pA0j+RREp93tjiSvZGv2XB33swOYsTkiNbHKqwlIY9SbcDEUkxOBDnCELkBvTNMYkBxbMWNsN+6SNPQaYrSw+kw+jLGLKvARFF2iSz4MvDPFeyEP4hazHmTOHSQ0ka+GcgFeoOje7xp4hrQtBY5JPucNfQaLCNjrb1/mGWQ+9hCw08BksOnil9AObPifdMmYHnFFCFDF+Rs4I4WLwNLw5zWBtcCYtHZFh4LaVjA0PRxh6NSltDH8xoNQSetbQd6PtoTqLS+9kGv6sRe79ISjhvZA8s3Pc7HzMhVIEMNKuxBm0QzV6FrMbJjKHAr1RBMWPuzHtaMdCzGhUlRAjEKkuRF4TCs0AiUoTmS+wiBYfsthohnLNI2VS7ke8Cw0wrGrbYx/EaYEOMqaY23yRHsYeE9veNQ8gtvZxbesOUxd2S9oIEIT2hrLCMgSjbCpJSbFiDOoFsvsQ9AdxGWMY8ICLqUj2oLC4ex8fbDH8WF39FE+GPsMM1CxrT32PsG72KSwSH9IWQ+WxfYPJoIJDRkRrIksSJhq0JjI14UZnuQRrck+gvsQWO414+5GHsGh/Iei7LhPBaK9sbcOXsh4XuQMtJI5EFfMS7/QImJP0N2yjPSFtxFN4H9whRI8rBZY5FSEIyJRIWDT+8x7m1pPAn6oQ1DpYKh9iM09AWinwLfFjtIP+ikCKRxs/QjRm7I51S7k1p/JA8pCXFh4GJOK8lIcTyWzzeiYYniSShILgY3I/RJh7BeTCQok3e2Hf1C0bPQv/AE7Ca6Z/BU0QuS6yw6TNjX0ETtmpY9hn8kn2lPsJcfVEYMKLEmFEDpDKRlxDEkkkSob2NSTdYypXK/QkKMcjiWeINpw94NvVCGuRjgVwbZyW9sb6v+D2fTEcPedfKyBCYGr4LOJw89OWcHGYt07QzlDS9/QGhJ4oe1lvYpPs8cAhnGFfcg0+mMPfohYm30s7t5DEbj8DHL5KhS+yn/gQr7Q8yBfhEWNRt0KubDliQEJC6itMk4DlyeogiYFiQ0u2TAqTYaCW3SxIhjQ2x8LFfkwfwQtYiNiSmkJ909kFoerEWGn2ganSfJM3F8Entj16YRoeAsIvAs+gWHIqYO0JkO0MLccoTPskOoNur9M8X2TJVqTTl3YmGrm0hv23BFEUcFlka+tBaxsMLJV4EYGb0bh79EaDhEQSjQ9xnj6uP9iEtLwN8oFJR8CSi8wcTcQT/oRETwSKgT4gdOThIDT0xmv3D3GjshGlS8SNfE5FkzfYh3MsKSLHLGyrsVCc6e/RGhAEuNKz9NYSp7JkThfBHSluBRqT9wJDQXhwN2xUEl+7OBCQx7Vomtok0hSS8DG0kskyE2GCR5INUIboesaQPGQ7z/CNMCYYqeCLL5DIxL4hh3oXlC7BNhmCiInB3A3Y9X+hCfsXWgux/YxsKxyPU9BQQhCzGO1AtA+39sapIQsGEhwe4xsZI3HHqsCglKRA5Skl+T4LPwNGhDQ3cSiJKjZCDFxpQLNqbZ5DzGvhHbotDTiAscJgeB+ocEjIrYsPY1iUwqUjcvH2jYceqNCzez7IksRXhH9IeyBwLyMyrgTZR3hkxmJzIduh256EiIhpMlsWk59Fy2RAWUmOYhFQcdWhdOXmCODjFEQ8HnKb/YvpWDZ7PtnIxiSW4RpJZCjAm0wySs5mCe7LfcId4djFiMPcNkgl6RI2JQOonz3wAzGiNQRqyZmRAhDUMsmD8dEb/YteqFo2eyT3mg8FTSUhmWKYfJ+w0LKrF/UPoebhZxLgkmTFoYZpxJEEk/I2LKL9mhBIRGHsYSzO4eWQRit/s/yhaN3saTeRiVkuor4I/sJbJMhJOxv4OSVeBLtaVITNjhlY7Yiu5o4Hc4yUQWBwRLJw1I4D2MSPc0HmnIrPtC16oWhb+zYTYpReSErBs/qbjaBOFoYyRJNPYxHnEJLtENXcFG+RsH0iZbwsGloeh+jwdInEak22uCkE+XtC0kP0fTG/2LXqsGsJGJGiHxElFICeR4aZOj4kXuLQzh6ErLsKlqzQ3CFhC2cCOxJAiEPhq8JJNwjCmgyBqM/cN/s+iLYzEajkeZG7GhjQUFWmiTFzEH5GlREilhsVZO0C1IlhLqtrLwivRtqnYasVtwLEiBRbG1lo3BBj72MvrNK/LGNImuEMoIaHomCBxmtyKBOrEiJNFRKSLFqCiC7dKIteRKjSGJw1AJDaS2xOL8Bc1RjLzTYp7gmTL5N4JCDcIZcIe5sJwxCQ1lGO1BDdjS3o0Xo02a4QoktiVFkxokk5BXYIIcR0ITOWsUSJSOypXBvJtdy6TtcEQZjWOQxF3ig2WxpGNHsSXN1yobynA9wHaCBGiZ5qwtOF1BteCtlRcaG0+DQd/IqBDfcxw4IJmtDljIXtlUNEIVI2ilqBxeTXU+Sij8ic62NpalM0thKWuBsI2vslkLaNmw+B0f4Aw13gqGHAmdFx2xTkQ9YaFiXD5Ym5KII14fcim2kKOSWzypDJOAWaF7GkmBNvHLRBOKnoWpqiJ7HBzA+iJckjnpQhKMUhNITHmkljmGmhOHJQJvQYXAq0LBAkGghIE0NRNAI1hyEymR0yxoHlyM2w1VrQ4pV7E5UjaWh2rsX3CKaPTElWTLErFgbCjZBHJegoGk5b5JbIe8MirI73YwhIUQWsEkaIICy7ETgxBkPd4RQyeWmJvgescaRDCpomxXsOTpkuCW5+oWCTzCbudworZdMjJCR4Xn7nImUQ3OUjThI7xMaZFIa8jQExyWOhqEEWyDcCF20JqhezdoThPxHBQSqXI8oncMgVWM4RNDdQSN60xrpklJL6kIZacKgoh2lFChIQkMkiLi4djZyBtafKETjk2kdnJF0UKVNs2fdiNVyOxyZuKcij/uiTYcag3wIRIOD/AAvghQIQNIbFOCXc7ob7NtcEQqJFZI3bvPJJ+8bfCEDdF0l2NhZ/voZJQiE3oTrgWEzcXhhqbH3hOkSV+FbxE0M28WPCGnorC2JgTQ5obEpvQogmxFfknZicsXtsXT+SZpCR4HSSNjWMJISRjctxQktE/h2FoN3AgoIZEW5fUoDWTTNAxhKzkCCOXI2KJ7LUL/BaEEmEaYRiSEOEhm/4ntMUOglISENjHlAkdaE8IeEyxM/JbxITTzIigw8cYjWxdH+FDSIAxkJSbUI9hDmbgm34FnYQ2W3jqdh2EuAxs87rG5LRJH8THoQvkapYrWCpTTSGaDnfkESSybeFBnopkZXEhLHhgo6Ys345Ai1omcf62bUc/i3GnRwhpXIlRS4K0Ch8ipI+h8QJYVc3/EiUEoVYVEthjS8rTIHP4zVo3c2owSYnuJ8lUMi2MJYh4VuY/wALWFK0FAbSWR8vkY0voicGo/GVEngcNDGUpG2JQevSxqVBKZITsZz0KB7HGhQTMFPZm7ddScDz+Oi45ElDFEi0KbROQkmRLxh9LRIYlpHQyScQLtCthg7BsG/wvZdvxNIZYIYlJaDaDZ5g+i2LQhCyks9EEOaJTf42ss34dh6kogNHUA02hsFQ94jDdYTENSIoCbbHREiz3PcpobNfWiehyZBHVoNEOG2CURDK9DYveWoIsggSYjGLZjTAxKscCLc/gSgUTJ4tR2Gy3lZCokZfFIqnFF1QuKCwqjkbJEwZ9hSEiMaiGARqjRJxmF+BNDwwhNDg0KEKIxkxgxcNkPwNRMoGpFSJ6IXYrp1NWHoRJ2UQLCI7kDla60yF4TWELYOBxbI+BH4IppyNITG6kulqNeXNURsQ2xa6FP4AeGOEYZEzGxDfQtcigUdsJG8LMYZGGx7NWb4CZBeLQrLOYjqRbGIkajDG5JTkkJks6JyxsY/QmPHgkH2lgT7jsZtEl1QPExhUMVyDCFJgbkXXJOKo2FSyx9Cw6WzyGIJdDF0IogeicNHIQJYtE410LMyJY1Fm9YMQsLK0FgyZGhokcpZVDh0rxBBphRV1LobkROHsWmWculdEAbwWRBONE0tFcocMvBeFhKEhMc5eJJ6JxpEjEcOH0ODuLHC65FQm00OMTSigH/iEN4ZBvDy8YM1DgeHIhZ7nPXIkexa0LWaK6N5fVOEsIGkDCiKi8Ix/B5hrdxN4WHicokZLZQiRShYJ0LDnobF1LKy30avRNDZ5Y0oT5F1asTEzPg8TwvHLk1xI9t4UlIFhIn0t/gjH/9oADAMBAAIAAwAAABDDGry2pvlku9ziNvXywKdxZyP6mf7JR1Xkaooax1q0Qp4S+cPKM1Aga4VCwxzmrBU/Yjs4VxBzBXARyCwJQjsLLv5428DOtVtzZTeYgo148etEboi3z2uKdMz74cB2mHpx/r9+O4uQwoGDTbxxcj468/XMbWiRQmm+gZyD2zsXxIl/02Wn2+EyO8/gA75kevW+erJjSA2gjvHJSLe4LyLNGpvN1Foh3DJd/b71WXevXpz83MPZ9TsP5tIMvTddfq/ADFekH0gZvOINdPUr/VVUMnO03oVXYv8AFRmxwzlSGbRZQdYI0UqXFAIvnlc2gW10IroTDcmM3+ixqd5C/wCLJRG0NMaqJ3BLrKsJZcM0c5MVjOLA3jd3JDwZx2qB72TPvyzf8W++dsp7JAHt0lW+IKjLXgFys8hfzeqeI7Es/pa1KfJcCtv/AHRD/Ol09a2KqCJzZF8EbvFvv5sR2V9SAI0Q1G6s6W/IfMzZWE580/vONZU09fy7dvIxOd2eCDByAcsHauRZ3+/TnQARv3zqPo8v2/djfqPHPNtTbs/2vHLSuf8AsrwtylDAHFOu3nNrdcbPwGfhW6C4qSSXaJ9uNa1VaKPdNGKiWD6KKWCmmE0O6ie3fmkGKO226ODOaltuYEpInQGTFk7uoLuZG9STIdKITIMj3VxGIBwhV0cBIb8m9r/nvOf8cRImAMESiCcJzHDsYNlFroCX7pgPiGABd94OcwA0ExK0ayY/2dtuAq5wwcdLCADfe8chiii9i/8APoAHf3w//8QAHREBAQADAQEBAQEAAAAAAAAAAQAQESEgMUEwUf/aAAgBAwEBPxDwbPIjLZgMjbh/gp3Bj6l0T1tQRg1ag3DqO5ItvBj6nEG7h5HMhNwfIe3bgeTth/y2tZGF8et8l3GBLDLBOXxnIYcGN5J+X7C3bkgyflxH5btx4HJhOwnUGNRgHZalvmQyatZCS+o4m/IctWuS6kNqO2eFvBLJbcRgWpey7ghotV2wFrdrV928Ho3FrkW5Ih9hDAdXCXsxEYOSL8jG47HUuQS0YHIwYNrwPkTEAg5si/kW9Es+H56dyIz8wJH7u0EmRyL8hiS6wVC3bTBnUMiP9w5OGYPATyXBow27cxgB7IS6v3JPT4nK6iOyeM9McW4tAn7ClIeRpyQwZMCz5h+Q7EOrbuHdsW4j2+JbjqRN3zmd6JT5pFqMkYZa7gDVqftGE2r/AAj7Hk1gbcR0WpbfluHAw9tTJ2MJJgTMeQ02kluCCCJLbbS32IwMmPAGAiaiS1M1ajLCSS1gSQozD9tsSuvWtx0eBDbhiEQ7Aw2Q86gh5P3wYIi3qesYdR5JJfQxBhi7HubbiZvB5WGzHgtYk3bht/yBBqIM6tQtYG3/ADDqO+Fkjf7wDi6JNRDHrcQ5NZQwMPkfJLUfwLeY+n4GJ/KR6fYjwl88J4D0s9sMeUMHSI3JWAe1ySOQx7BFobR/D5w5GJYZiIj3/8QAHhEBAQEBAAMBAQEBAAAAAAAAAQARECAhMUEwUWH/2gAIAQIBAT8QZvjhbxmeIWeD4mz7m+PMNYYc23jbbZ99Dj1vgx5sttvAzLG+PB8m8+OPMskhyPSeJ/IIt4RZJyMfOJZN8eRvrj0Znj9vjuT5iREsa29+wkvmeBP8AhlkBL3bMSFuz9TET5rEsWWWS98LEMQcfADrH2XreOZHggiZ8xt9z4F9ZezbeAgiCZ81v2ZeG++Jw6z5OMjfvCGdlY/7IeZw4zPRCAsMY8FLkA4L3HTr0F+SDhfK89EEcYr8t3pf6xwnwCFgwlrxFjYepPcHM2ySNhjYSGJ79RgstWXq21bLCfBvuD1aOwDl95sGsGRe4II+3x1fFSR2GLVtgZJZD9t4DVezJMb0ONsWdWsNsPvgwgs4PxOHDYcMieDiljbGIlll5i9cy+XslgPnFMETPDqhOkTZ3bfAsi2cht6GSWB6mfcfpPSwmPfntq4Q/Y4kx/xL33wpldWQZL4LCuS09St849J5EsL1vMnxTSVaTkd9vmNvW0ofa+OviYlrfWDInxM7fcJaXx4ZZZzF/PAEuy6kFvhsWWP8wpeyXb9WRqQX+M9eb/HOJJaey0X++CJXD7/kcbJhZQ4R4fXhvmPWYe/Ieusee8ZZfII4T5HVwnFCyP4Ah7eLd9/xP4lHhr/D54vN+8bC+o8v/8QAKBABAAICAgIBBQEBAQEBAQAAAQARITFBURBhcYGRobHwIMHRMOHx/9oACAEBAAE/EBf924Z+959nz7jKH9j8w5nK5B+Zf8FjF/MKJS8mxMJHZKhcZgWr7gohhKj6X5gb+JY65/EroYiwzllC5bS7lvBL+FtxVf8AGZhpjBlm8eKIwBZlOTiOorCwNaHmYh4jOEkfGYJ0n7iulQfQUP2cD6jEteqby7+LMtZbcHMaiJbOJLSm+bSu662F6gT7YWMJytLd2vmJH3GPvCgCUCrgsDlqXYxUKmdAmAjWD1FWZwWRApfmX4C4KtSoELIsXEsTDyeY6FxlXqmOvQ0rDUcSqwCAgEo6hqHZtuXh/NQ0HrPzmGlOS/cGY4gvH9y0uS/3LtzU/CbQ2vSfiAjEOWVx+5gxABqD4ntQn5nyL/6mo+IhDyMcy1ceojCdMTFbBC8ThF0JsUlqZZrApMZSsApxEENdwCjw1xBRh4HjR/m/H8vPxf6n5rFOWCUs0xsx/IMzqyNlKi+kuWeKiuRzGY9B/mazjBHNcyu6S+iyOLpALvMpALNnRB3rv+Yq+qVCHQ7gWwUS4O5lwQTxGMJ+CBXf4qNgD8RLUW/EHm4vVRIahWoaH0QyumU4YJkAL4iWi9WYifiASXmGoeMF2/8AsSpzX3n4P9TEPbAFyW/qZVUPGHUn+2JMX7B+YcT6wj9z8NUaU/WMq+qw4J0ZChKg/pLfd5fuHELZiWwyol0Z0RKMIwtCAvRL6iWWmVkBct2wj4FMCowg5JYDXfhYjNRjVGh4PCwvw0mYv9zBI+9n4P8AUIdsxNmmRL4GO/JruR+0Zg3aP3FPvh+oQioeT8pBboNcV5DFSwHbcEubwO5ZjAYKlqYiHZ8w6P8AiGX/ABAvUB1K1qZ2JwENEbfSCilPpGBUWSA7lqKoWMrUMMFtRiZYaPNuubRv5eXfwEb7gyxEVpXhI8Qzuk2Ih6GIYu+Kl8A5iuKglsIraSkLPmCP+UCFHL/UqFdz2/8AIYCzwQ2GVbCUkOtuDbFZRBoScUTH4awM9MJgo4gVCaQDuOLiKJ1cAE2ZhqmskZxd4mC4FEzeHQ9uMfif+QUfpK/Ywjnf/aLcsA0vvAH/AKpZN7ntxOr76WJdvVuqIlgfWU+1tdBhzfOMsM/JSC8qBgvEo/t/8jM4ofiCEFuo10qBzGuG2AeJilRCviSyylJXcStVn2RL5i5cUqpiXdRWStLFbeoi6agho8L6qiR+N/5PwU0Pb9xHhieTcwDnP8ypreyYTD5T7vgmJ7H2xPYOUFhuh+bNgjmIYrVgzBBTEKjEBh1A4PNUYIyikQzEPQ/EdBKuUekQiF69TUdsGYFLwDEqlKJpn8zufhE/Pygxv/rAZUDcwLpfvxgHpfzCUv1hUwjB+f2TlgpR2zeiXCvayYzVq5cB3CIHJepWCHEOfCow0lRI+FdMsQFxxa1EwiszWv8A4Q6jUCMUg9g0Oo6QYv4uACOiOvYv5gepML4zH0f1gS1FGW1am5t6t/7HbCFlglzX1GDAUAYFiuvcXJSomipYcPxjhQGjQUZuVG8FTHljt8qiasWLzlCc4JScfFQ15O2LFiqNSGwcwKhsmTFkZmPolBgmkdxKXEHSLd/NRfaJse/7lgnlq+sUG2ixH6sVsq/LGlvKZeIqDr9EyQ9w4SgUjoKbbn4heoA//gKCJLxA6uZt2sbdSHWICtcPUICVXUZ4Hzco17CDCCQO4MrAqKRgbg4nBHlEo7IzB3cyCZD0QQYm2BjyZ/d9T8CP7r9x4vd+WbheDy2N5g3AcA/7Fk0ABQRy8HENaUANaKg9F/KJSueVioILwbgsex+5QYcgfaUjy/lFBxDcbvIkFbxUXuyxoYrUp0VDrYDxO8oDHpOSKNzSCbmxpH6YycIhQSUAViFkD4Uo3uWNT7ImkDEyB5MaQ/sX5mv4I8XX/UddG33WGo/7+GGvAPzD9zytR1b7rPbH7IKq5hgPD/cvSmbmLmEeE0ECGnI9uCvh1GhJvO4DaDBFExjUmJIwyykFZlZBZlVzVF4ZMkpY9Q+EGodkAblmk4i22OTmavf/ABiY3MP6sze9E5UEh6ftmiHOfwoa8cB2kV/KlYgxKi41ReMC66h+oWYZ2/mINdv1lSdZi4C1/FxjpBCsofMIGrm81GRTAXWZaluO2ZEqV4yjlidIm3Nv0nPnqViiPqZNEYe6MIqXKwY3c+VA+LpS94uWO8h3RxFjP4fc1SiHBbitBuJaPgv+wstcHqBVh0GK8H7WEFCnRHNTMtTcoMRNWMej78jIUDR6hJ6wnGpmnvMc5VfeLuQ1AYtX5QGCkE/FhGNWZuKjsttxL5ScDuFKxwQgWSwmBli6gKrTDibxx2LqplAexuoBN0MRU8iWSi+sO8y6LLRQHoREdhvxeKmPgGJ0o+Hf+OZq+Ir+BhBRqQi2Uvtil4z+qC1uN7hv5IrX2hBYdoSyndSzio/EyFXSjntD+Y+NymYFfeLJAEDiWcQLhmXBxD/+CHSyJIVpnQgXoL7lHNCibuLBsfBvUEupVUuQNxKZXq8XKjU61F1Htst/BMdXvXcqNVgxDUzJ1MjL8Fxnf+OZqfELBChxHmUPdA1NpvdW/hicwiKXKW2iv5EH9TMsHgnEMpj5hIMKfuxyG6KKx4sE2kwagBEz4L1lBEKx9jRuYAIzB6lWOC4yp0CDxdQNk887H0s0nEu7eRh/PibfHNESovh+415uj+JeYPClLXzD114FgUAOlIguWZXqBS32Ljq6dhYcSr2mDAZc17Y+yfAggjdn3YLetv7MRQ20SsrrxZXh1BtCDeE1YaXArG5KrCMEJgy3TbiHKbyHEfNL0uD/AOuZdBm6Z6mkoUUVbLC+pj/DiYKPwW/BR0v91DcqNZqLqDF6Sy8FMyJi/T8LMUwwS92i7QRdeT02fxKA2A0VVRTj3Kv48z5ml/cGnRkt+CDRKSNZUMV3CqS6JmoGmAkGoeBAVjGJWOmswQKwDCXKElI/KDiPITFUQDuVMdR/18eD+z3NXxM/WI2H9Ulae9KWyGo3qswBVCFxcMycwfxdzIjEr+STCFRvmZRftQ8fNOfrHY9f+5lUyLcwSAm4IbnERoTcxMlwDiDZk8IADq5j8KXDCXOzKk2t9hApYwLNfExK2eHTcIQUGJxFt+pYy5OgitsxN7m01FK/j5mp8TA9BEphMwrrtgaU+hr9RzEflgXayP8AlNzMW9P34Xh7cIDcqp3DJ+bY4RpblLHJmBdleIqIKvGDdIhtpjpUMrfiXEQiqYpQQDma7hdgBsBkeD6wXWEfQ8RmDcFUE/8A2PBUMukxWwVdqDqKy9X4h19zM/7uLH0jKPREf1alwmNLX/lBmGAVeB7nCX2SqoduNoHr/omEE9q41ADk0VuVGLPwP2jjTsQemgzC0vJijDcSwn1WIypo+sS4DF4aNB9vMGO5cziylBHNMtX9ZWeBq1loj0eB6kM/PhURVBhPcGR0EAqL6L9Isn3F/l5ij8IiiloC+IBpdsIJ/PFFbIbMESfEssvQmAwqc5fljav5mDMLZn0wnxcigDJYgEHCQ+9KlIV+UCfEvgb2URCd+nVuZUQ+tTKkTqwL7SPsRJWGxNSw454iIGXMMESGtkdLXA6hlXfEq5tXyMTqEe3uYwYIrp4ss6MzMY1WE1Za0NTD5p/V7ix+Izd6I5ElNOJ+UhuXNj1/cdwo+X/M5REXWHWe44IQgVTGUqTQRHBQDZ1BPMOYaVlYb9QCY1MONIXCA9w1GJtK8S8PqNkDiFGZQNByxbbsrUfWaGbqKlhMoDFwuB9F3jmCtpGW6twvRAEODwWiLaS6Gw5lEbjkx/l/UefzP4vcWPxEEvkuBMWqT48E/udxG2Ih7QswSgaOqvaJVTLMTNhiZbq8BI4jz+JRSZl266rmNaGTSxWNq2Ylag3EqRZEqYVRQx79woF8s+BzELUR0/qj4m2O2IFFOX54h7tlDRPXhUoqhbYFD1NJ4flv6Zoe47/tmafiWwy6DcScuRMxqwDkAiVYujk3zLgK7MNq8JxQfEXgdQfP3i6249SoQbGKAEOM1HqDNq/MfqfcWL0HTiKhFN5J/wDg0xorvcBAiIXT7Qq4p9IGSJsi9QzFhmbi5SA5Z7pU5kt9iYKYwTUjjtCdUpXFwyuiX0cTMZSxgtBMfmjs/u5o+ISOxq4TFAxxid3wGHtMkLlNdIYXBtzFBcArWl6iC0QoNn1KxNfxMGYdL1MZaRXtXbPfg8TsHkgNDA8pBGItRAcwas26gBuTuoi1DbkFsmIuoFu/aNsV0RYevAaIr+MyJUrjBM1S98fiZh80N39XNPxEfDE4kVpXMGM6qI6XcdxJbpQzF4tLjMcRWEDWZlaBlMahwRLM2+pZep7YhqYFc3GoltfJHDs33CTtS8S8CftKMi6GEjMZuGqkg6rOIjAahpe4pFDSk10QGqHN+C1C5PcW2HuFtmG7xLi5j8D9z8lFm/q5gD1Px/7hv5kCzil2uIViYiV0NHDFtNQiyuIaLi4oU/SKFCp1csFlTrEotY0lhsi/SX86mkGJXh6lfRWDjLCmrkvM/dk0kEQYgaodMqgbKiIC11DxrWUCfENFQ0ReA6KgTdsw0NBLq6TmXPxn7n56Ki/i5rgv4v7jgCMUnEzYzHVwonfJDsWQySymt4Ygo5zE2HcUcOkWLBWqj0FUxhPJKvk/uCcQMziADdWXKUArWy9wWRY5uaJRiZaH1jxUCmjAbS5axkIiBkbi3khHYJulyNBNGLFjZnygpfT9z89DX8s+PL4H7hHmXaZKmZlLimsymMC8RWWRU5hEsAYoAojbkTxLMgRbsy3tpMltZKEEXFMyqYFsBExT8TsFR8EQ8KNRtBowKJaLDPaQMpLgbkcNTBXL3Cv5hbYsvi5h1pMGdw/cT+13FOR9P3APkxt8osX5ixAumOWmPMGjMj3DQ0NqgIBb7hLLPoQDr1F1MqNVNZQuw4thFlkChHpCOlN9+p7gBzMSQKvmNl3HFHiPgJLeiMp2IF3BAm7gioVsqnH1i1K8fuOSCkGQqYqi+TTfxc/JR/3cwatAOZcw0sYjGJVvhIKB1HesTFMuvMLTEI7llTQRS2guGN8ohhuKHjaE1ZjTiGHa5g+2Gm7WCD/A3DkUc/EEAACAJig5l5xkxNbsfBM00yfuJc4uXGdxFL8Yp6/vx2x6/uFDAIg0L0QxZlhKFaiKzKteHUBCEriDhXMcTN/MJVoCX1MCFoRdQDyXBBYbnQcRGXcyOrlQCgEuYld3fgCoEDEILJMq1t9ExBBxHLzGbAFY/YYxZEAg4aM13LEF9XMO0GkgkbOmJ8PCpvT9ze9xtZ/LmCwbIUksJthguJU3Gq6xCLtgD5hYGsleJK3XcNjXMIMbpFtaiZhwQCxiY2NQQo7qYY6aI13uB4IeGN9ggBAHHgMIriiZTAEwE3NGIo++479Oi45ZuAMeQotJCLUOnTHn2eLns2YIvvx5s6vrFeyvhLhzEZDhAtTiK2m5klVaufMDUse+5azcArkDKitzC18xIrczDLbxFZKiPZA/WFMylkxEB8XMJ52D1c5gSqgiK8Mr5jxFGpLgpGZds+yRmVjCoikLrpVRPRQaThlKEgYHMAmhaELIAp9R3m0RMst7KTHO4CsMoWaxLFl+EUMyQxcbtDDGcVnMLh23Yqx7lg+5ldYw/uYDbe4jFfEQEvT7h+WNVLiDxcFjpv3FUJpu0PGMBC2XH8ZlzYDF1C7ggZe8XUKJuKMQQl1L4BLbqMpyuguZPB+8N1Wjb7mSNH3QHCYihQo1zFL17eoE29DxEAbdSuh6jlZWZdCGqNssrotQ5jcNe8TdMIjc5hLBbMY9y/nc2fmy5/Mafd+56VY6rWUXqbocz3m4U7hrMa3KnqmrlYlk0eWWGt3uCzGuII6xAFQoblrM9sMcMFR83WmpdS+Q/MLiS6UIcjb8wXRTwmQDJD2nTEtgVyDmWav+ZmcMxQm9xQSHdYgGLe5gQKinePLxCuXLXqUULsvEUyRzHELr1KC+xLz1cK44uXFq93Fqqq8za7gA9wJO9TtYu5UhinzZmE4cRW53Lrxs1cEEG2Coag0o1FSTgOpQJYVMekAXAvEKPbzLBb09wH0DV8ymTSU1K2Ve4LJgl2E40obLYCINYxC5yMG6iinmDgC2ZBstdxcluGeJYqq17jsKjO2oZT2wb5umUu1O2HML4cuRlEjNzlsyw1Ca2WNwMVNQCqs9zgIALZPUJYMqtVHcRw3LBd1BDRglB9JfUu26Z3LdWl7qXznqxVDRXNzEYCHFWe4rDQNkbKBSADe5fbV+Gbe/mDd43C4OeEUjghwpa9wdxsqCFO3EaCXtfLECxqXcr3ESrb4CZpnZ1KDDFUpYbruE4mcOooTFE5ZTmBYbllrohWXNbiqp/MRVuWMhxxCQsiuJQVXViMGrijC0bq42y0Gr0dsdQd0v/kqlVcEpBS85NRtcav3BLVdWQBTK5l+TuUAaPGtG+kU2QxLmZmCNQ0mLbf8ABAiqOS8BM1xBxL07hEzDwg6ljbmAgXHaZlRoZaW8QN/UyI+mMFxVRqqFzA3e4AqVv6ERKoXPEQtN1VsL5NrRFqdlXMwu9dTFgeR4lQLFn0Sv4W5lltqB5fWFORybgxsfVFSk8ZiwTniiJVX4yhv8YEy3B8qruYqxlf5IQcxD4yBbbFBWIkCGYS8SynFeFWGZLtNJyh/OkV1BCGdpa1dwUNVw9RnZ0dpqGXHNSwI205l4Ba4eohQ2ufQe2Ikss0T7mKhaG77gBoWXKF0YSHqFt7nyYWsote4MLVMKWY9MdeWOQustRnPmvB4N0gADvMTaVA1BoYswUWX/APhUwKWai8LOmY/rhKcsIxBWPSW1aPxMWqplTcdjPvxNlYKNPqMNlhhb+ZgVUMq8yq6NhBURyVGtRd1KvZIG0rKOEozUQNRSbm6JgcsFlUsU7bj4r/JuDCGg9eOdqBJVcFrZcNSv8DEGFiYCt5iTaHzB6xRTmPWL7xBHoOmWu4zeL9ErM0BtfXXxC+rjutw6uBeDkxO2aleZgT1Ml8TUpzAQvMblR/LHB/8AAhuAlgmoRr4dkCPDLw9yulf7SQKl48N43Ba7j4D5dEIsFFMt/V3KqBjDqBpxxuP21cYdx1MllQTkS+5+hGVmI7Uyf8ceTXgsMWW+oAAxzHtWoiVYiylqGY5a6MRDniEVNrMrp/sYoZhEYTQ0vo5iUk7n1DgXdyyEtL1GiWCtrFwzwzA7azEaXdaivwVKBO2e4sXJcrLoHBj/AFXm5f8ATqVtfjGlJWQ4iaDcU7Wqi1bfmilqCNKa/wDgMGEWLCH0I6RGsyUJq6IEIbKiDhVbud6O1PEoU2lxFWw8Kwuo1Xv/AFx/nK+4LaGo2ZhWXqCru5DNsqJXtEpH/wACD4STHilQHEEFrmSAcxyFh5htWksVLO5eJxfidy0EvuEIri8RW/B5Zf8AgRSDRsh1CiBG6cAdRClrl8EdSpiWn/4jHme4pTLbNIen4ZlhU9kBgsrtmWotNjMRVhxLJZllQs1KSNAtBkjtYEqV4f8AFAC5uE7BgCqlgYHuG2lG7Reqr35IgWwuYbPBv5if/AmxGCMGoPLmuI9CoIm8RCXzxLNhlSnEsgZC7iXNS4tMFsJVpI6Kxc9E0xH3CG4ngTETGJcW0bdQbvEfXO41E34wf4PCKyU4uWMjWHUf9kWZcZoDUsTyMdtRlMGJck1CyQlMAlQVPojti48JKxplLdR0Ewi1+oJxUyFqIgbmQlxBbAVi2H1ZjgjvWYBR1f8AoPKG+KgER/2QW/WV9QhQMnJFTk6I1hjuUyr7yzI7l30R0sW3w3cQOZQRzBv1AHBcEtGBBCNmOQwQwQpqhEFlcW//AIkAV9RfRRP9k1/MID1BlMkoheZSixj4s1zOQn6JuuVct3CBhDcA3AdwViBUCw3NmamKmWScR5STJagltNXqVAZ/26mauYr678lPk8BSO4ZHYYY/BFstp9w2GRJWCrzcqYrJuhqXL2IrJcQlUTglWVzCkOncNLFscCKjMPcYmC5lPUrmFbTCoZZ1/oxG0gchBnDc7qgN9xhBNaqV4zvUSMMqRcSq5x1cDmreowbbmwmJlgVD9rEcqUS0tLCYlTSs/SIsiQTRDtFJmIgl5YFDLh1lZDKmNxRVQEqAtzNrUv41EqV/i5nJqRgUtNRDVQyQXGXKQ7s/aXGIK7cwbfiOmi5Vx9RUph9V5nLgyiDkDRssW2YhceYShxDPEMGIq/4BWIbUZASOH1gla4YLxKQxG0ncoiCzqWoxX+SKcykGLNkva4tuIBMlxCkVeCIGD6ily2z33ABrL3bOC/QRJMpWJLCYqIN3OYalxZYWy+DxUcEbAgr4fDBlbiCkK7m5qIs4hmobd3EgK5viOw7f9Ec4JvMVUCtys2T6BEYn1h0Vfoh9H4hFWq+2WFUI6KmBLJdQXmYgXAE4llxiELXisp1F9rzioat3Cqo3a8xG67jYWqgN0YgZBIEbjRq7lq7sUb/0qZVaysXKLM4LLuOm4mkHJNMzFTNMHhWbgvLCXKBGkysAqKjwLEC9zLy5s3qEwitRxKgoq+kSYLLHgkpbUYua47hK/wA0T1CuOosYijCBuAWriOlyvghqBmHMwRFBeIYxFlxYFzUaEU6lLMx9QDKwAB4XwWYOJwsOeyLjolCZ5JWmbdEEKBIKalLIQLUInklI/wCIbsw5sIXMtbma0BsAe5ggOyYGJlKYfdLhllHfhZo3HVsbMQA8LX1K0+YNBLjyiq4ooMh9Ya+WaQxcKEZjWJYBzR4A3cLdR2xuvLtDR7xMgGohmAjIqvMCWwUoi2wCGfiG7izCXFghmWMagrwGX0lLumDZ46RQt3DTLyvqGj4ucfvDR7YuFj+oRjxB8GOwV3FaqjmFUNwSI0RgZlQpgqIUaY2RXDLU35Yysi48KuY0RUQZpfiXzLvBMB4FsWyXMwbhiLmGpvNZcP8AsM/VL/4mz8QxXxODti3ftncefUeS4zioWJmWgJyd9XABRggIpaaMSp1K9kUKCUbIYiw1DBNFsu0qo+CaS31JgIobgS3g5iwMWrYRkzHEuMiLIQ19Zw/MXaaB0Toho+bnruPPzXi4Qc0G2LxiD1DJOaidCB0gQixbS4NxYqDTLuYuVLCZRtlJNEMIxOFjCGC8y9voiMnEzd3cEQ0+m4uVfdwwj6IC2oYqaE4+WbMXL8SlQS76Jdh94kT6dwKfcQCSx5hvEoJXEwIqgw7QhrxbggonqLUXMKuOsTaYhBbDEGUebmD1lgJWYzlWX4sDTqI7J0xm4Un6IxLAuL2QDW6TiWQB46l5uvvuVpzENSXi4S8LDqPFzaGAS6G7ht8DOCViCz3FzLhDLUw58f/Z";
    $descPath = './20200909/test.png';
    dump(base64ToPngImg($image, $descPath));

给png透明图片添加水印

/**
 * 给图片添加水印
 * @param $from 要添加的图片
 * @param $to 保存路径
 * @param $ext 后缀
 * @return bool
 */
function saveWithWatermark($from,$to,$ext){
    $im = null;
    $ext = strtolower($ext);
    if($ext === 'jpg' || $ext === 'jpeg'){
        $im =  imagecreatefromjpeg($from);
    }else if($ext === 'png'){
        $im =  imagecreatefrompng($from);
    }else{
        return false;
    }
    $W = imagesx($im);
    $H = imagesy($im);
    //加载水印
    $watermark =  imagecreatefrompng(Env::get("root_path")."watermark.png");
    $w = imagesx($watermark);
    $h = imagesy($watermark);

    if($W*$h > $w*$H){
        $nw = $W;
        $nh = $nw * $h / $w;
    }else{
        $nh = $H;
        $nw = $nh * $w / $h;
    }

    imagecopyresampled($im,$watermark,0, 0, 0, 0, $nw, $nh, $w, $h);
    imagesavealpha($im, true);
    
    if(strtolower($ext) == 'png'){
        imagepng($im,$to,2);
    }else{
        imagejpeg($im,$to,80);
    }
    imagedestroy($im);
    return true;         
}

时间类

求两个日期之间相差的天数

     /**
     * 求两个日期之间相差的天数
     * (针对1970年1月1日之后,求之前可以采用泰勒公式)
     * @param string $day1
     * @param string $day2
     * @return number
     */
    function diffBetweenTwoDays($day1, $day2)
    {
        $second1 = strtotime($day1);
        $second2 = strtotime($day2);

        if ($second1 < $second2) {
            $tmp = $second2;
            $second2 = $second1;
            $second1 = $tmp;
        }
        return ($second1 - $second2) / 86400;
    }

    $day1 = "2020-11-12 14:24:00";
    //当前时间
    $day2 =  date('Y-m-d H:i:s',strtotime('now'));
    //向上取整
    $diff = ceil(diffBetweenTwoDays($day1, $day2));
    echo $diff . "\n";

计算从指定时间戳(秒级)到当前时间戳的剩余时间

/**
 * 计算从指定时间戳(秒级)到当前时间戳的剩余时间
 * @param $end_time 指定结束时间戳
 * @return string 例:剩余29天23小时52分钟
 */
function remainingTime($end_time){
    $left_time = $end_time - time();
    if ($left_time <= 0) {
        return '剩余时间为0';
    }

    $str = '剩余';
    $day = floor($left_time / 86400);
    $hour = floor(($left_time - $day * 86400) / 3600);
    $min = floor((($left_time - $day * 86400) - $hour * 3600) / 60);

    if ($day > 0) $str .= $day . '天';
    if ($hour > 0) $str .= $hour . '小时';
    if ($min > 0) $str .= $min . '分钟';
    return $str;
}