您的位置:首页 > 软件问答

魔兽世界私服313(聊几款获得移动超能版认证的笔记本电脑)

导读魔兽世界私服313文章列表:1、聊几款获得移动超能版认证的笔记本电脑2、新蜂鸟开箱 没想到入门级产品都已经干得这么漂亮3、首发首日,装313台iPhone X的快递车被洗劫,价值244万

魔兽世界私服313文章列表:

魔兽世界私服313(聊几款获得移动超能版认证的笔记本电脑)

聊几款获得移动超能版认证的笔记本电脑

身为PC技术的上游供应商,Intel这几年一直在推出各种标准,比如早期的“UltraBook超极本”、“2 in 1二合一笔记本”等等,老玩家应该都比较熟悉,前者引领了笔记本电脑轻薄化,后者带来了翻转触屏功能。

针对目前的轻薄本市场,Intel在年初又推行出一套全新的认证标准,叫做“移动超能版”:

移动超能版有[六大标准],细说的话太复杂,一句话总结:拥有移动超能版认证的笔记本,都是中高端的优秀轻薄本。

今天我们就来举个栗子,聊几款最典型的[移动超能版]笔记本电脑:

戴尔 XPS13 9300

机身左侧

机身右侧

它的配置如下:

i7-1065G7 处理器

16GB 内存

1TB 固态硬盘

13.4英寸 4K分辨率(16:10) 90�I-P3色域 IPS触屏

厚 14.8mm

机身重 1.27kg

适配器重 221g

目前售价16999元

优点:屏幕素质极高,屏占比高,机身做工非常棒

缺点:接口种类单一,高负载下表面温度较高

上图是戴尔 XPS13 9300的拆机实拍图,双风扇 单热管 双散热鳍片的组合。

【购买建议】

Dell XPS13 9300是最新一批移动超能版笔记本,它的屏幕素质表现极强,4K分辨率的它实测色域容积为84.7�I P3,色域覆盖为84.6�I P3,平均△E为2.1,最大△E为4.07。

PCMark10实测续航在4K屏下能达到9小时12分钟(场景:现代办公),符合Intel移动超能版认证。

如果你对笔记本的颜值、做工,以及长续航时间和高性能有要求,那么这台戴尔XPS13 9300比较适合你。

如果你对翻转触屏有需求,这台电脑非常骚气:

惠普 Spectre x360 13

机身左侧

机身右侧

它的配置如下:

i7-1065G7 处理器

8GB 内存

1TB 固态硬盘

13.3英寸 1080p分辨率 100%sRGB色域 IPS触屏

厚 17mm

机身重 1.2kg

适配器重 350g

目前售价10188元

优点:做工精致,续航给力

缺点:i5版无16GB内存可选,触控笔需另购

上图是惠普 Spectre x360 13的拆机实拍图,3热管双风扇的组合。它不再使用主板倒装的设计,拆解简单了许多,厚度加大的同时散热模组也能得到升级。

【购买建议】

惠普Spectre x360 13同样通过了“Intel移动超能版”认证,其关键之一就是采用了i7-1065G7处理器。

续航是它的优势之一,经过PCmark10续航测试后,成绩为14小时50分钟(场景:现代办公)这个成绩远远超出intel所要求的9小时时长。

作为一台翻转触摸本,Spectre x360 13的表现不错,惠普也是非常擅长推出翻转本的品牌,如果你的预算在万元左右,那么这款超长续航的翻转本一定很适合你。

上面那两台电脑都很高级,但性价比一般,下面这台电脑依旧是移动超能版认证,且带有翻转触控功能,但相对更实惠一些:

联想 YOGA C940

机身左侧

机身右侧

它的配置如下:

i7-1065G7 处理器

16GB 内存

1TB 固态硬盘

14英寸 4K分辨率 90�I-P3色域 IPS触屏

厚 14.2mm

机身重 1.35kg

适配器重 334g

目前售价10999元

优点:广色域DC调光4K屏 标配压感笔 16GB内存

缺点:高负载下核心温度会比较高,并且拆机不易

上图是YOGA C940的拆机实拍图,双热管,一大一小双风扇的组合。

相比上一代C930多了一根热管,左侧风扇也明显加大。

【购买建议】

YOGA C940是咱们今天要聊的几台机器中最薄的,它的厚度仅有14.2mm,这也是移动超能版笔记本的特性之一,结合超薄机身与性能。

值得一提的是,移动超能版笔记本支持“即时工作”特性。

可以看上图,一样是休眠模式唤醒,搭载“即时工作”功能的笔电亮屏速度与手机一样迅速,这才是现代PC应有的使用体验。

这台售价万元的轻薄笔记本不仅保留了CNC工艺、玻璃面板,本身的性能也释放也不错,如果你对笔记本的存储配置要求较高,那么标配16GB内存和1TB固态的C940显然是你的菜。

一直在聊万元以上的移动超能版笔记本,那么主流价位是否有综合体验不错的认证产品呢?

华硕 灵耀14

机身左侧

机身右侧

它的配置如下:

i7-1065G7 处理器

16GB 内存

512GB 固态硬盘

14英寸 1080p分辨率 100%sRGB色域覆盖 IPS屏

电池容量 67Wh

厚 15.1mm

机身重 1.19kg

适配器重 209g

首发售价6499元

优点:同价位中做工较好,便携性和接口拓展性都不错

缺点:采用低性能QLC固态,耳机接口需要转接

上图是华硕 灵耀14的拆机实拍图,单热管单风扇的组合。

【购买建议】

这是我们今天的机器中最便宜的,但它配置并没有因此缩水,依然采用i7-1065G7处理器,保证日常使用的峰值性能以及不错的显卡性能发挥。

接口方面,灵耀14拥有两个Thunderbolt3接口,方便各类设备的拓展,甚至可以外接显卡拓展坞获得更好的性能。

需要注意的是,Thunderbolt3也是移动超能版认证中的必要条件。

所以如果你的预算是在7000元左右,对于续航能力和外接拓展的能力有一定的需求,那么灵耀14的综合表现不错,可以考虑购买。

客观地说,移动超能版认证机型普遍偏贵,但也有宏碁SF313这种5000元以内的性价比型号,并且无论是5000内还是大几万,WiFi6都是标配。

在我看来,该认证所带来的技术层面意义有限,但可以像当年普及Ultrabook超极本一样,不仅高端满足认证要求,入门级产品也能“接近认证要求”,做不到超薄,也能比较薄嘛~

我相信,这才是设立认证门槛,且能福利到消费者的关键所在。

新蜂鸟开箱 没想到入门级产品都已经干得这么漂亮

猜猜它卖多少钱?大胆点!

配备十代酷睿平台的笔记本电脑产品已经从高端逐步走向主流甚至曾经的入门级别产品,比如刚刚到达CHIP实验室的这款宏碁Swift 3 2020款(SF313-52-74F1)机型,已经全部更新为10nm的Ice Lake-U平台,并保持非常高的性价比,顶配机型也只要6000元出头,配备酷睿i5的中配机型价格不到5000元。

依然朴素的宏碁式双层无印刷瓦楞纸包装,标志着这款产品的市场定位。

再生纸卡挡、回收PET包装袋、回收PP屏幕保护膜,全面环保的包装。

专用圆形接口的65W电源,没有直接配USB-C接口电源。

线条简洁的外观设计,金属机身已经普及到入门级产品上。

重点在这里,除了十代酷睿平台之外,Iris Plus核显为超薄平台增色不少,无论是CPU还是GPU,传统的性能与面向未来的AI性能都进一步提升,大幅的!稍后的测试会带来更多详细数据,敬请期待。

主要升级特性一目了然,重点都看到了吗!

入门级产品配备全功能全速Thunderbolt 3接口!高规格,赞一个!当然,这个特性能下放,与十代酷睿直接将控制器集成在平台内有100%的关联度。用它一线连接,数据、网络、扩展、充电、显示,一个接口全部搞定。

漂亮的腰线,真实的轻薄,而不是靠视觉欺骗实现。

屏幕长宽比从曾经流行的16:9向3:2的变化,不仅使13英寸机型有了赶超14英寸机型的垂直视角,同时在确保全键盘尺寸前提下,带来了更大的触摸板。另一件有利的变化是位于触摸板下方的电池模块可以做得更大,整机续航时间更长。

三维尺寸变化,最显著的是整机宽度的缩小,几乎就是14英寸机型竖着裁掉了一块。

借由功耗低、性能更好的酷睿平台,Swift蜂鸟系列将轻薄再次演绎,今天的标准是56Wh电池、2K分辨率13英寸屏幕规格下,16mm厚1.19kg重,隐藏参数还包括Gb/s级别的Wi-Fi 6 、LPDDR4内存、NVMe SSD,性能表现详见稍后放出的测试。

---------------------------------------------------------

免责声明:

1.本文援引自互联网,旨在传递更多网络信息,仅代表作者本人观点,与本网站无关。

2.本文仅供读者参考,本网站未对该内容进行证实,对其原创性、真实性、完整性、及时性不作任何保证。

首发首日,装313台iPhone X的快递车被洗劫,价值244万人民币

据CNET报道,在iPhone X全球首发的今天,发生了一起恶意犯罪事件。

旧金山警方向KTSF电视台讲述称,三名身穿连帽衫的男子驾驶一部道奇厢式货车,抢劫了正向这里Apple Store(Stonestown店)运送iPhone X的UPS卡车。

卡车上的313台iPhone X遭洗劫,总价值370000美元(约合人民币244万元)。

据悉,事件发生在当地时间11月2日上午11点15到11点30期间,也就是北京时间今天凌晨2点左右。

据警方报告,一个门卫发现了嫌疑人卸箱的UPS卡车和道奇车并拍了照片。

知情人士透露,旧金山Stonestown苹果店称,当地3号开始的iPhone X首卖不会受到影响,预约用户仍可以按时到手。

另据新京报消息,11月3日早上六点半,记者在北京市朝阳区三里屯的苹果直营店看到,有50人左右正在排队。今日购买仍然需要网上提前预约,所以没有出现大面积排队的现象。

由难到易,这3种自动发送测试报告的神仙方法,建议码住

请点击输入图片描述(最多18字)

前言

每当测试结束后,测试人员都会输出一份详细的测试报告给到领导或者组内人员,那么当我们自动化测试结束后的时候,也可以让其自动发送测试报告。

这样领导和组内的成员就能看到自动化测试每次测试的内容了。安静先介绍下如何通过Python发送邮件,再通过简单的小例子在自动化测试过程中自动发送报告。

smtplib

smtplib是属于Python发送邮件的一个库。其简单的原理是通过SMTP的方式来实现发送报告的。SMTP(Simple Mail Transfer Protocol)即简单邮件传输协议,它是一组用于由源地址到目的地址传送邮件的规则,由它来控制信件的中转方式。

smtplib中对其SMTP的协议进行了一个封装,其中email是用来支持发送文本、图片和携带附件等功能。

登录邮箱

发送邮件前肯定需要登录邮箱了,这里安静先通过163的邮箱进行介绍,登录是通过smtplib这个库进行来完成的。

这里需要先确认发件人的邮箱是否开通了SMTP邮箱权限,可以登录到163邮箱中,选择SMTP/IMAP中选择开启SMTP服务。勾选后进行连接登录:

import smtplib# 创建smtplib服务smtp = smtplib.SMTP()# 服务器地址smtpserver = 'smtp.163.com'# 发送账号user = 'XXXXXXXX@163.com'# 发送密码password = 'xxxxxxx'# 收件人receivers = '821006052@qq.com'# 连接服务器smtp.connect(smtpserver)# 登录邮箱账号smtp.login(user, password)

(左右滑动查看完整代码)

邮件发送类型

邮件发送通过Python中的email的库来实现的,其中email发送邮件可以支持多类型,比如纯文本、纯图片、文本加附件等方法,这里安静会一个个进行介绍。

文本发送

发送邮件肯定包含发送人、收件人、邮件标题、邮件内容等内容,这里email中的Mimetext的方法可以帮助我们实现发送纯文本内容。

import smtplibfrom email.mime.text import MIMEText# 创建smtplib服务smtp = smtplib.SMTP()# 服务器地址smtpserver = 'smtp.163.com'# 发送账号user = 'xxxxxxx@163.com'# 发送密码password = 'xxxxxxx'# 收件人receivers = '821006052@qq.com'# 邮件标题subject = '自动化测试报告'# 发送内容 (文本内容,发送格式,编码格式)message = MIMEText('这是测试文本内容,自动化测试通过', 'HTML', 'utf-8')# 发送地址message['From'] = user# 接收地址message['To'] = receivers# 邮件标题message['subject'] =subject# 连接服务器smtp.connect(smtpserver)# 登录邮箱账号smtp.login(user, password)# 发送账号信息smtp.sendmail(user,receivers,message.as_string())# 关闭smtp.quit()

(左右滑动查看完整代码)

通过执行后可以发现,QQ邮箱已经成功的收到了邮件信息。

图片发送

正常发送邮件只需要将邮件全部都复制粘贴到邮件中就行了。但是这里我们通过Python进行发送邮箱,需要用到email中的MIMEimage的模块了。

这个模块可以帮助我们将我们需要的图片内容添加到邮件中,需要我们将本地的图片导入到html中,通过html中进行发送,如果你通过链接的形式发送会失败,邮件会识别成恶意链接,从而进行拦截。这里安静这接在上面的代码中进行加入HTML格式,将图片嵌套在html文本中发送:

import smtplibfrom email.mime.text import MIMETextfrom email.mime.image import MIMEImagefrom email.mime.multipart import MIMEMultipart# 创建smtplib服务smtp = smtplib.SMTP()# 服务器地址smtpserver = 'smtp.163.com'# 发送账号user = 'xxxxxx@163.com'# 发送密码password = 'xxxxxx'# 收件人receivers = '821006052@qq.com'# 邮件标题subject = '自动化测试报告中加入图片'# 发送内容 (文本内容,发送格式,编码格式)text = '''<html><head>自动化测试报告中带图片</head><body><p><p><img src="cid:anjing"></p><p></body></html>'''message = MIMEMultipart()body = MIMEText(text, 'html', 'utf-8')f = open('123.jpg','rb')mag = MIMEImage(f.read())f.close()# 定义图片ID在HTML中展示mag.add_header('Content-ID', 'anjing')# 添加图片信息message.attach(mag)# 添加正文message.attach(body)# 发送地址message['From'] = user# 接收地址message['To'] = receivers# 邮件标题message['subject'] =subject# 连接服务器smtp.connect(smtpserver)# 登录邮箱账号smtp.login(user, password)# 发送账号信息smtp.sendmail(user,receivers,message.as_string())# 关闭smtp.quit()

(左右滑动查看完整代码)

通过执行上面的代码可以看到QQ邮箱,已经接收到了邮件信息,打开邮箱清楚的看到,图片已经在文本中添加了。

附件发送

发送邮件需要带附件的情况下,我们可以使用email库中的MIMEMUltipart模块。

import smtplibfrom email.mime.text import MIMETextfrom email.mime.multipart import MIMEMultipart# 创建smtplib服务smtp = smtplib.SMTP()# 服务器地址smtpserver = 'smtp.163.com'# 发送账号user = 'xxxxxx@163.com'# 发送密码password = 'xxxxxx'# 收件人receivers = '821006052@qq.com'# 邮件标题subject = '自动化测试报告中附件'message = MIMEMultipart()body = MIMEText('自动化测试报告携带附件内容', 'html', 'utf-8')# 添加正文message.attach(body)att = MIMEText(open('123.jpg', 'rb').read(), 'base64', 'utf-8')att["Content-Type"] = 'application/octet-stream' # 死格式# filename 表示附件的名称att["Content-Disposition"] = 'attachment; filename="fujian.jpg"'# 邮件中添加附件message.attach(att)# 发送地址message['From'] = user# 接收地址message['To'] = receivers# 邮件标题message['subject'] =subject# 连接服务器smtp.connect(smtpserver)# 登录邮箱账号smtp.login(user, password)# 发送账号信息smtp.sendmail(user,receivers,message.as_string())# 关闭smtp.quit()

(左右滑动查看完整代码)

通过执行代码清楚的看到邮件中已经携带了附件内容,并且成功发送了。

zmail邮件

一些测试同学看到上面这么多代码估计脑袋就大,安静在给大家介绍一种简单方便的发送邮件库zmail,这个库的目的就是为了方便发送邮件。

但是要注意zmail这个库目前只支持Python3不支持Python2,想必都2021年了,没人再用Python2了吧。

安装:

pip install zmail

(左右滑动查看完整代码)

文本发送

继续从文本发送,先创建一个zmail服务,将其发件人邮箱账号以及邮箱授权码(163设置中的SMTP打开)进行连接通过zmail服务连接。编辑文本进行发送:

import zmail# 发件人username = 'xxxxxx@163.com'# 授权码密码password = 'xxxxxx'# 创建zmail服务server= zmail.server(username,password)# 邮件主题body = { 'subject': "自动化测试报告", # 邮件标题 "content_text": '这是邮件的文本内容,自动化测试结果', # 邮件文本}# 收件人receivers = '821006052@qq.com'# 发送邮件server.send_mail(receivers,body)

(左右滑动查看完整代码)

通过代码就可以看出来很清楚的就讲邮件内容展现出来,执行代码,成功的收到邮件信息。

图片发送

同样文本发送完成后,继续来我们的图片发送。这里可以通过图片的base64的格式加入到html的代码中,然后放入到文本中进行发送。

import zmail# 发件人username = 'xxxxx@163.com'# 授权码密码password = 'xxxxxx'# 创建zmail服务server= zmail.server(username,password)html = '''<p> 这是邮件的文本内容,自动化测试结果 </p><img src='data:image/jpg;base64,/9j/4AAQSkZJRgABAgAAAQABAAD//gAQTGF2YzU3LjI0LjEwMgD/2wBDAAgMDA4MDhAQEBAQEBMSExQUFBMTExMUFBQVFRUZGRkVFRUUFBUVGBgZGRscGxoaGRocHB4eHiQkIiIqKiszMz7/xAGiAAABBQEBAQEBAQAAAAAAAAAAAQIDBAUGBwgJCgsBAAMBAQEBAQEBAQEAAAAAAAABAgMEBQYHCAkKCxAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4 Tl5ufo6erx8vP09fb3 Pn6EQACAQIEBAMEBwUEBAABAncAAQIDEQQFITEGEkFRB2FxEyIygQgUQpGhscEJIzNS8BVictEKFiQ04SXxFxgZGiYnKCkqNTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqCg4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2dri4 Tl5ufo6ery8/T19vf4 fr/wAARCAH0AfQDARIAAhIAAxIA/9oADAMBAAIRAxEAPwD3aigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACsV9Y0yJ2je/skdTgq1xCrA hBcEGgAA2qarBgCpDA9CDkUAADqKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAA898VWetX1v5OnPGkRRxOvmBJJckYRSU UYBz 8XduIbisPxzros7U6fCx8 5X95jPyQHIPOR80mNuOfl3ZxkUAAHzRSUAAGja313YsXtriWAnqY3Zcj0OCM/jWdQAAe1aJ49uYpVj1MiaFuPOWNRJGezFUwrKO4C7u4zjB8VoAAPuu1uoL2CO4t5BLFIMq69COnfBBBBBB5BGK VvDfim40NxE4M1ozZeP JM9XiPHPTIPyt7daAAD60pAQwBHfmgAAWigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAAPFn8AveXTXN/qck7SHdJshVHJxwFdndVC8ADy8bRgAV7TQAAcTZeEtFsowgtI5zxl7gCV2wT1z8g iqoPeu2oAAM3 z7LyPs32W38jj9yIkEfDbvuYC/e5rSoAAPM9Y8E6dqQVrcLYSL1MMa Ww/2ogUGR2KlevOeK9MoAAPAv FbNn/kJDH/AF7c/wDo/wCtdXrvjaz0wvDahbu4GVOD 5jbHG5h9/nGVT3G4EUAAHp6rtULknAAyepx3P8AWvlaXUfFHiD/AFYvGikZlC28bRwYY4KM6gKyjgfvXbA6nrQAAfVW4A4yMntmvkC48K67bRtLJYy7V67Hjlb8Fjd3I9SBigAA wa I4NW1G1P7m8uouckLNIATnPI3YPPXNAAB9uV8v6f491W2ZRc Vdx5G7cgSTbxna0e1c/7ytQAAfUFYOlaxZazCZbSTdtwHRhteNmGQGX q5U4OCcGgAA3qKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAK858Q LrTRt8EX7 728J/yzjJxgytx2OQq/NxzjINAAB2WoajaaXAZ7qVYkBwM8lmPRVUZZj9PcngGvjfUtUutWuHuLpg7tjHULGq5wka5wq8/nz1JoAAPRdR8Sap4nnNhp0LJFJuHlqcSSIP4pXyFRe5GQvOGLV5Qs0iAhHZNwKttONynqrYxkex4oAAPojRfAVtbrHNqJ8 bO7yVP7lfQNxukPr0XqMEc1x/gbV71dQh08yF7aRZf3bc WQjPuQ9Vyw5H3TuJxnmgAA kY444UWONFjRRhURQqqPQKMACpaAAAooAAOZuvDukXr ZNYwM WYsq WWLdS5j27z3 bPNZ/inWRo myOjhbibMcA77j95wP9hec9NxUHrQAAfKuppBHf3aW PJWeVYtrbh5YchcNk5GOhyc1lUAAHqPgEzDWv3eNhgl83/c XGPfzNldv8PdMkhhuL6RFAn2xwN/FsQt5h9lZtoHPJQ 1AAB7bRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAVXiuIZy4iljkMbFHCMrbHXqjYztYdwaAACxRQAAFFAAAUUAABWJqmrWmkQGa6kCjB2oMGSQj FF4yeRnsM8kUAAGvJIkSM8jKiICzMxAVQOpJOAB618ja94nvdcba37i3H3YEY7TzndIeN7dMcADsBk0AAHa IfHMsxa30xjHFyGueRI4Ix 7DAGMcn5vv9CNteZ6VpUmpPK24RQW8bS3E7KWSJFBPKjBZmxhVHzHn0NAABgkEYJB5GR78kZ9 a1dT1GTU7kzuiRDYkaRRjEUSIoASNf4V749SaAADGpaAAAr6O8EeHHs1/tK5xvmiAgT5W2xvhvMJwcMwxjBGFJz14AADX8HeHBpMAu5txuriIZU5UQxsQwjwcfPwC 7oRtHQk oUAABRQAAFeX MNYlghGm2SvJeXakFY0LssJBDEAZ Z8EDAOFDHjigAA8X8Wa2dY1BtjZt7ctHCOcHn5pOv8ZHHT5Qtel GPBSQL9p1SJXkP rtmwyxj 9JjKs57L91R1 boAAHE F/CU2rMtzdAxWisODkNcYPKr0ITsz/AILk5x9QIixqqqoVVACqoAAAGAABjA9KAABsUSQxpHGoREUKqrwFVRgAVLQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAAHyFr73Ol65qK29xNEWnMhaJ3iP73EuDtYZ278fhmuk IFgYNTS6CnbdRDLZGDLF8hAHUfJ5f50AAFvw/44uYZYrfUW8 FiqCf/lrFwAC2P8AWL/eJ fknJxivF6AAD72r5g8OeMTo9rNbXCSTqBm2C7cI5ySrkkEIxIORuI545oAAPdtb1200O3MkzB5CP3UAI3yN29dqf3m7e54r5I1HULnVLl7m5fe749goAwFUDoAP/r80AAEmp6ndavcvc3L7mboo 5GvZEHOFHbv1JySaxaAADf0fSp9Zu0toeM8u5BKxqBksxAOPQZ6kgV774C0prOwku5AQ92QVBHIiTO08gMN7En0K7TQAAYHi82uh6Tb6RZqE89vMlxglkTBLOTlsu 3B9EI6DFcb46uDPrcicYgiijHBB 7vOc98ucHpjFAAB5pRQAAeq DtEW9kkv7mLzba0DEIOTLMoDBNv8QVTkgkAkqORmvcvDtqul6LaJIwTEXmyF/k2mUmRg2Txs3bTn0oAAOsR1kVWUhlYAqwOQQRkEEZyPSuDvvGei2J2 eblh1W2XzPx35WM HoAAO/rwO7 I5 dbWxHX5JJpM5Hq0SKMfQSUAAHvlfKc/jrXJWyk0UA/uxwxkfnKJG/WgAA pliRCSAMk5LdyT79fYegAFfJDeL9eb/AJfn/wC/cI/lGMUAAH17XxgniLWY2yuo3h/3pncfkxIoAAPs vlODxzrkLhnminH9ySGML09YxG/H 9QAAfVleUaR47stQlENzEbJ2ICEv5kbEkAAvsTacnuu3g5IoAAPV6KAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAAOd1vR4Nbs2tpSU5DxyDrHIAQGxkbhyQVPUHjBwa6KgAA INS0250q5e2uU2OvQ87XXJAdCQNynHB/rX2Dq2j2esweTdJnGSjrw8ZI6q3P4g5U4HHAoAAPieu01zw3eaJJh/38RyVmjRtgXPAc4wj45K547E0AAHIMV2qApB53HP3ueMDHGPrzTkR5WVFV5HbCoqgsxJPCgDJPXgDvQAAd94O0c6pqSSSRLLbW53TbiMZKt5YKn7wLDkYxgHNTaZ4e8SxxtPZrPbZ4x5v2d3xnqrshwMfx46jHegAA quAMDgCvi291HV2DWt5c3vy/ehmeQHrkb1Y5POCN34UAAF/xW6Prl80cnmqZF bO7ny1yoPohyo9hXG0AABRQAAa15qV7qDbrq5mn9A7Eqv8Aur91f AgVLYaTf6m220tpZucFgMIDjPzSNhF/E0AAGJXtmn/AA8uZGRr2ZII rRxnzJvpu2iMfX5se9AAB4nWzqtrFZahdW0LM8cMzxqWILHacfMQAM568CgAAz4YZJ3EcUbSuSMIgJZuegA5P4V0Phy5NrrOnyDb/x8JGdw4Cyny2PUchXJB7GgAA2rXwTrlyRm3W3UjO aRAB7FULyA/8AAK sqAAD5yj HN8UYyXdqrgHaqiR1J7BmKoVB5yQrfQ19G0AAHyHqnhXVtIDSPEJYQDmaE71Ud9wIDrx1JXb719bTRJPG8UgDJIrIyn JWGCPxBoAAPg tTULKXTbua1mGHibBwcgjqrA jKQR35oAAO98OeMJdGjW1mi8 38zdu3HzIg2N2wHKkdWC/Lkk8815dQAAfdVrdQXsKT28iyxSDKuvf RBHQg8g8GvlHw34ln0GUqQZbaRgZIsnKnp5kfOA/r/eAAPYgAAPrqqdrdQ3sEdxA4kikXcrDv8A4EHII6ggigAAuUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAABmX94LKHft8x2YRwxAhTLK33Y1J6Z6k/wqCe1cJ4vvZNPfSbjEjQpeBpVQgBiBlQRkMWwGK87eu7qKAADT1DQH1BkgeUC2MbefLlvtk0jE8bhiHZ0YbkO0gBVAru6AADDsdIstOCeTCu5EEYkYBpNgJO3efmxljW5QAAFFAABk3 mWWqR Xd28cwHQsMMvIJ2uMOucDO0845rWoAAPnDxh4WttLt47uxjZYtwSZCzvsJ 64znAJyG3N94rt6173qNkmo2dxavjE0bJkru2sR8r44yUbDD6UAAHxdYywwXcEk8YmiSRGkjPR0B5HPt68U27tJbK4lt5l2yRMyt/wE9RnGQeo9RQAAfcEMUUMapEiRoB8qooVQPYDAFcR4Q1ZNU0uJc/vrVVglBxn5Vwj9ScOvc/xBvSgAA7eeZLeKSaQ4SJGdj6KoJJ/IVwPjTUEs9LaDzBG94fJUnPCYzIcBWJG35D/vigAA WLmdrmeWZ/vSyPI3 87Fj pqrQAAW7ZZHniWIFpC6BABkl8jaAO/Nd74J083uro 50W1XzyVxyQygISQRhs8/7IPTrQAAfV1FAAAUUAABRQAAeAfEHSZmli1GJC8YjEU21c7CrMVdsdm3bc9sAdxXv3WgAA Cq9d8X GDY3AuLCCZoJEeSVURnSApjJ3AfKhByN3TB7UAAHkVLQAAfYnhWD7Nodgm8PmLzMjoPNYybe/K7tp9wa8 HuqtIk2nSMx8oedD3CoWAdfb5mBH1PSgAA9yooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAADy3x5aNcaUsolKeRMjCPC4lZyIxzwwZQxIxxjOR0I7PW7WO80y8hkV3Uwu2EyX3IN67QMZO5Rgd lAABNpF39u0 0uC4dpIULsP egXDjHbDggj2rxnwHrdtbK2mTYieWXzIXJ V2YKpjP91/lG3 9yOuMgAB7/RQAAFFAAAUUAABRQAAeMeOtE8 D7fBCGdObhlGZCoXCv1 4nR9ozjB6LXpWqatY6VCZLuVV4O2PgySf7KJ1bqM/wjPzEUAAHyjoutS6PfQ3CD92uUkjH8UTkFlzkEnjcuTgMB24rI1GW1nu5pLSEwQM37uNmLlRgDknn5jlsZOM4ycUAAG34h1t9bv2uBvjiUBIYyRlEHUnaBy5yx69cZIArkKAABa918DeHY5lTVbj5trsII/lIyvBkbqchvuj5SCufSgAA7nwdobaRYmSYYnutjuuGBjQD5IyDjDDJLcA5OO1ej0AABRQAAFFAAAUUAABRQAAFFAAB5frfgmy1WY3EMn2OVvv7EDo7Z U3JhvXB569evqFAAB5roPg630S4 0m4luJgrKpx5UYDDBygZix/3m289MgGvSqAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAAPlbxposWkX6SW xIrkM6xDP7tkI3cc/IxIK/iMYFfRWraNZ61AIbpM7TlJFwJIycZ2MQcbsDI6HA9BQAAeBaf481O0EUVwkNyi4Bd9wmK44JdWKsR3JQs3c55rQvvh3dpIPsdxFLGf e26N168Harqw6cjHJ6UAAGm3xIALAaduGSA32ojI7HH2fI lcJ/wAIbraqd1i5Y42bZ7baPXf 8Pbp05oAAOwl JE5x5dhEnrvmZ/5InvXDr4P15uli/TPMkCjB so546dfzoAALF54w1y/DAXAt1xkrbqIyMHqHyZfTPz1px ANZcjcbSPKKxLSscE9UOyNvmXvjKejGgAA81mle4kMksryuwyzyFmYnHQscsfTNfQlj8O7OIhru5lucEHYgEKEdw3Luf AspoAAPAbOxudQmENtC80hx8qjOBkDcx6KvIyTgCvtKy0 006PyrWCOBf8AYHLY7s3LMfdiTQAAfNM3gTWobdZVSGVzjdCkg8xOM8ltqHHQ7Gb2zX1TQAAfKmiahfeGpFZoZMXG9WtpPl81o32fLwWjdG3D5gd3THNfQ p6FYathp4iJVGEnjYxzJ9GHXHYPuA545oAANGwv4dRgSaIkBhko BInJG11ydpyD VVtJ086XaR2xmafZu cqFJBckcAnnBwT/ABYzQAAblFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAV5nrniz yb5LWO2NztCtPhjlVcHAXAOGxhju6gj60AAHplVreeO6hiniO5JUWRD0yrAEHHbg0AAFmigAAKKAAAooAACigAAKKAAAooAACuL8QeJLXQYwG/e3EgzHApwcf33PO1M8Dux6dDgAAOuM0ayLEXUO4YqmRuYLjJC9SBkZ teA D7 51fX57q7kZ5BaPtwSqqvmRgIFXC7RuJx6/N15oAAPoSigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAzdQvY9OtJ7qTG2GNnwSF3ED5UB55dsKPcivLPH pCK3gsQf9afNlAbB8tDhAR3DPlv8AtnQAAeGzT3WpXbSuXmluZcKQT8zMQoVepA6Ko6AcYrv/AAbYC91JZWU7YEWbcP7yvhBn7vznkjG75KAAD3/SbI6dp9rasctDEisdzMN2MttLc7dxO30XAwOlbNAAAUUAABRQAAFFAAAUUAABXnHinxOmiRiKDZJdSdFJyIl/vuoOcnPyDjue2CAAE/iTxPDocfloBNdOpKJkbU6YaXkHHOQP4sdq UnkaZ2eRmd3bczMxLEsSSSTnJJPJPNAABfM1xqd1mXdcTTuFzn53ZjgAHn2AGMY4xXvng/wq nEX16MTkERQ8fulbgu5/56MOAv8IJz8xwAAA3vCfhz w7dpJsG5nA34wfKQciINzk/3yPlyBjOMn0SgAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKQkKCSQABkk9APU/1oAAFpoYMAQQQRkEdCPUH VAAA6igAAKzNRvEsLK4uXOBFEzc45bHyjnjLNgD3NAAB80 J7l9U1uYIquIm zRqxVSfJ3FmJJxt3lyOeRisC2sZL6SIQfvXmkwiv8APl8bju YcepZe2WwAaAAD3bwLYfZtNa5YfPdP68eXEWVdo7ZbcffIreutc0nQIEt5LgFoIljWGP95LiNVADAfdOMY8wrmgAA7SvnjUvHl5cjy9PhFuCf9a 2WTBPy/8ATOMnoQd/XqMUAAH0DJLHCpeR0jUdWZgoGBk8nHYV4X4b0u91eb7ZeNcJbjbhnkPmXL8blJOd0Lfxfd/ur0OAAA91jkSZEkjYOjqGRlOQysMgg9wR0pyIsaqqjAUAAew6etAAA uP8Ra9FoVrvwHnkysMeR97H33G4N5a8Zx3IHGc0AAGd4o8SR6HAEiKPdSfcQnOxe8jqO3ZQcbj64NfN6/atYvVMivd3Fy5HynDk9j93YqoO3CqB2AoAAMYma8n58yaWV/9p5Hdj LMzE/Uk19VeHfC1voo86TbNdMOZCOI8jlYunqQX4LDsASKAADnvC3g8WBW8v0BuAcxRZDLDjo7YyrPnlOoXg/e6ew0AABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAB5H8QHuRp1ukZxFJPiXBILFULIpHRl Uk57qvBr029s4dQt5badd8cq7WH8iOuCpwQfUUAAHyvoPiK50J22kSwM3z2xdhk4wHjYqwU8c4 90PQVa8R F7nRHWWItNbknEio2YgCoAmPKKWZsLjAbHQdKAAD3VPF htAkzXiJuGTGVcyqeMqyIrNkE/Q9iRzXySHKkEY46A4bGe/PegAA9r8WeLbTULT7HYlpFZkeWVlKqyqQRGqsoYndgtuCgbe a8WKldodGGRuGdwLKemPb0NAABbhleN22BVcHKyoxjMfXlXUjjn VMijEzJGqSsXO1Uiw7s3RRtwCcsf8KAACMKxbG3IJUFd3XgYy2f8A9Ve2eH/AzF0udSGF6i1OCx/umVlPy pUc9j3FAABkeH/AAvNq6R3MhS3szwoVmeWQI HA5AAbDDc dv8KV9HoiRoqIqoqgKqqAFVQMAKBgAAdBQAAJFGkMaRxqERFCqoGAqqMAD8OlS0AAGPql6unWU9ywc WhICKXOe3y8cdzyBjNeN L79jI6uzbM7YwNy UfL YMON5ZjyynbjA7UAAHASHUNcuk81jd3EyhY1BVSwAJB42xJsALFF24yS3PNbXhi1mnukeKRbUh8GViGeRTxIsXHyvg/MV65oAAPYfD gWvh2AyyvH9okA8yViAqDP8Aq42bGFzjP94gH0FdU m2cu0ywrKwz80uXb5hyMtnjjp0oAAMm48SabCrFJftJAB2wbXyPZiyx8d/m XjNaZ0jTSCDZWuDnI8mPnJyc/L3PWgAA8tuvHc2Qtrp 4vyhllJYDP8cUafLx0/eV6UdC0ouX xQAlSrBV2qwbGdyrhW6D7wNAAB4TceMtddx88FuMfMkMcbY52k/vTKcgnkZHT617sug6QuMadZDHP oi7nP938vSgAA eIPG2twy7nuYrlckbJIYlU 48pYmHt82K961m3sbXTLyT7PbpiGQKRCn sdSi4GByzMAPrQAAZfhvxOmtgwyoIbpV3FBnY6jbllzkrjcMqx9xkZx5N4Mgl/tmAqWIjjlZyDlSmwpnJx/GUB7gj0oAAPpuigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAAEIDAggEEEEHoR6H tLQAAec3vgrSbvlBJbHAH7sqV UHHEivj32la7W/vI9PtJ7mQgLFGz8kDcQOEGSOWOFA7kigAA Rl0/zrl7aF/Ok88wQE7lL4l2 YF 6FxliM/Lk mauG6ijMb2wNpKGdhPGHVvmQgbUXdn5SRlCNueaAAD3yx0/R/Cse R1NwwAkmZS8z5POyJAzIm49EX03E4zXzQZ2d2YysTjcZQzCSR3O47mySSecls9KAAD7Ds9TsdQLC2uIpin3lVhuX6rwwrw/wAGRu q7o1YpFFJ5ruqswLYUIz4G3eRuQddqn3oAAPoasm/1G30 MtK67sErHn5nwCcADJ7YBxjJA70AAHN IdXt7GIRNl2kJHlKTufaAxGQRtGOpPHNeG3ktzql/JdMjxNv3AHIXY21FjG8EK 373XnNAABnGSbVHed2ZFjK7cnKqrdIxnqRg/dHXPc10Qt94jSBHRUjXIRd5VgxBaPrlmyDJwwVgB3oAAL9vbywy262kbKP8Ali0ZMqvg7jkfKUfJw3zDeB1r1nw/potbUSSRCN5CZFQ78xK5D7GD4O4NljkZBPtQAAdbCnlxov8AdUD/AD/SlkkSFGeRlRFGWZiFVQOpJOAB60AAEteVap46srOQRWsf24gZd1k2RL7KwSQufXau0ZHPWgAA9Vr5hu/G2tSunlyJbB8EJFbqx2nphpt 4np8uOlAAB9PV8q/2/4mhnVRPeCSVQBG9srE7c8JE8OM9dxRfqTQAAeg M9Qlnkh063D8OHlcBsM5GEhXA dsNkqvzZK7eRXG G9ZOmalKdRhnL3D/M8hZPs3mNuaVo2AU Y23e3ysoX5c9KAAD1/wAL6D/Y9rvlUC6mA83B3CMdo1P5F8dW7kAV3YIYAggg8gjoR6j lAAAtFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAB8169c30l/NHcTBijyD7O26NEhJ QBm2IQw2MHxuZhzkCvbdW0O01cL5yAOv/LRVTftAbC5ZWyAzZH8 TQAAfKLtcYlU7UBUEhc/w9NnJ hx0yau3dpJZvNCyh3h3E7twGFyj7fm ZQc8NhqAADNZI4naE YRwVIjUMCQM9ycfQ9qJZkmji2o48tNrjORuHCkMAW bjhuM9KAAD1qz8WWel6PFb2sRS74D7wdrsR81xvI YsoGA33MheVWvGTsA3F95OPlAIBHcHpgj29QaAADuo2kvpJLuSWW4kdl3ldqSjI6ybQMqoC4VPu4xxVrwnp0t9qPD7VjVvOdWLMUdfl2sVZM7to7HGfSgAA2rPT7q4cxxoXnRFZs7osM2MO3mKfLbdz8u48EgV75bWyWsQjQuwH8Tuzux7lmYkmgAAxtO0W2sMPjfLsRdzYONuTkcD5ssct1bvXS0AAFO4n8heEeV2DbERWOWCk4ZgpWMHGAz4H41coAAPB7/TPEXiL55oTbpkbIZJBHGgz1CrvkY8At5qq2T8vHFe8UAAHzdq/hNdJ0x7m4ui8u6NY44kxFGzn5x8xaSQbQduNh9RivWfFse/R5WDiMxy27iQ/wAGJ0G/ofugmgAA5zwFd2dxaSQ VCl5Cx8xggEssZPyyMdoPyklCAflwOma4G81BYlttf065t4LyUeXfW25NzyAjdIsOSTHIV3P9VbqTQAAfToQA56n1PX8PQe1cZoPiey1uHIZYZ0C bC5AIJ6tGSfmTdwD1HG4DNAABzXj63jktLOTLrILkRoVyRh1LEMo5YZjXHoa0tVMWq61Y2Cuki2yvc3Kg52rwqAkHGWOAV67GPrQAAdZpeRYWgJckQRgl4zExIUA5jIGzkcDHFa1AAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFVbm5htInmmcRxoMsx/oBkk gXkngUAAFqvn3XfFU99cx2ti00cDoAQiDzp2LZ4YMfkK4wFZDhm3 lAAB6JrniSPTMwxIXlwD5hRmijBPOdpDOfZemRuPavCreOSWdncPHJvcLlVeIyoceRhm25I 8A3TgdKAACO686/uZJ5DGXc73kZPLRypIBwMHywpGSPm uK6aDSft0LSRW8cifdm3vJEgdRhjuwfK2MRiJemDng0AAHHpaedceUimSWTCouwBbhuzqAPlVsb8nbuGCtfRvhnRotNhlkXYzTMNpGSY0UAeVvYliA4Y/jQAAfOuuaLdaQ0RuTGTKm7g5K9Eyy4 U m0sDjt0rs/iBJGNWgDoW22qHG4jcDLJxx0YY6 maAACz8Pjuu7rb5e1bdc5UCUszjnPPy/Kc/VatfDwr5uobMhWS3I3csdplySRkcEkds8UAAHvFFAAAUUAAFS5uEtYmkfccDhVGXc44RRxlm7VUgXz5pZmbcFYxRp/CnlnDNj z5yfQCgAA5sjXtSRmWSLSozzEuzzrlhyP3pb5IweDhV3jpkY57qgAA8Su/BGo3anz9bluCASqypKy7sdOZzj0J2/hXttAAB8Qadp0 qXcdpbhTJJnG87VG1SzEnngAH3rY1BDpuuXDBCqwXzOoX5SFEu9QvoduMUAACav4d1HRFia6jXZIWCsjb13DnaeBgkcgd8HHQ1794wmtbzw55/Xzfs81ue4LFTu6jH7tmDHtmgAA abO utPlSe2kkhZcDcmBuGc7W42sDgZDBhVfZnvtHXH3sdhnH5CgAA qPCniCTXbaTzowk8GwOy/6uRX3bXUZJU/IQw6cZHXAg8G6Zc6dYSm4Tymnl3iMptkVVUIN CeuMhf4c980AAHo9FAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFeTeIPFhgQw6aVkkK5 0/K0Y bGIs5V24JLcoMDrngAAOu1jX7XR1w376dhlYEZd3ThnJ 4mcDOCf7oOK a57yN0iMbPNMrs4ciTzMO5d2lZi6t85Ow8nBJbrigAA1b/UL/AFaVJrqWNOdirHIfLt8sUIaLlsSjncMsQc7scVXt7E305toLUmRQw8uUGO4jQAN945BxjbHlUx NAABW wXNssnmxS8Mgkkjk2iHJO1Nq5Jbk4znqOK gNB8PrpyJLNuMwHyjO3YrAZWURt5csgPVsEcDHTNAABymh Gmn z3NyoiRCCsXlhHkMW5FMse3ZyuCHHzMD2yMeykgDJ4xQAAYtyFjEECbo0b5Mr0VSpXHOevY46j3otpDPcSlxIhQ7VVihQr/ejwofngtu9RQAAcnqWoano5 aaF0kl2xAwbURdp2qdpBwoXnndk56VxfifXjfTx21k0bwow/fK/DSkspQchDgfd5HcjgigAA4rxNqM19drNNGkWbaNAFZXWUozMGxyyLlj8pOfc1zU8TpIWnVssisC6bMqRgMBgKwYD5JB8pxQAAelfDtXF9ctjCG35 bHPmJt TcMjG75tpxjqM8s8Ahk1Ns7CGspCGGc/wCuh Vv93t9aAAD6OooAACigAApW8BgM3zllklaRVI/1e4DcuedwL7nGem7HQCqd7q1hpoBurmKHJwAzfMeR0QZY9Rk4470AAGzXmt54zs7fzljjd3jGYy5VIZwDyY5F80kY5BKDPHSgAA9Kr5Zv9f13WyYYiy5Gfs1osgdgQcqwGZHXacnPyGgAAg8bJGNcuWV1k3xxNiMg WyqEKyehwmce4rmL7RdR02KOe6t3hSU4UsUyWxkgqGLL/wIDNAABnzXlxcpAk0zyLAvlwoc4ROuFxgenvwPSvRfAMME2qyCVEkKW5lj3AHbIskeHUEH5lzwe1AAB2ng/wy9u0WoXOUZBmFQCjMJEYMZQQcr8w2fdPGemK9roAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKrXFxHawvNK21I13Mev4ADJJPQAckkAUAAEV3eW1hEZrmVIUHdj1OCdqjlmbAOFXLHHAr5g1jWpNanDSiTy0VykZ2oYxIwGFIUbl4Ubm/iB6DFAAB0ureK7jUd8cMn2O3BjbdFJibazFSJTkFW6Eon3c4YtXm7LCiSO0EinbtYkDYpZePkOwg55DcjvzigAAZ9nRZdmdqv1aUYXHHzKMK3fcp9DXe6FoE2sSxTtI/lpvSacMEZSqjZGgDlzJgq7ZRVHPJPFAABj6Vo13PcpBFG7hnYNLjaiwn5fOO7 Lk4HzegBIr6bsrGKxj2puZiF3yPy8m0YBY8e AMDk tAABS0zRrTS1JiXdM4AluHJaWU4GSzHONxAJA4zXQUAAEckiRI0jsERFLMzHAVVGSSewA615d4z1IRRJZK4zIPMmiBKvJHkhYwdp V3B3FeflAPDUAAEVz4rin0/8AdsouZpXTy0ch4Iw77Xc4IJ2qMgfKxJ5xzXkcEDJMVnZbd/uh1KtxJ8xXKqfl27sn5m60AAHuvhvM1vPN5hMr4G0qyGH5eBtZmXnhgVynpmui0WFYNPgCtG4dfM3RhhGfMO4FAxPy4Ix69cDOKAAD5WOYZMTrvRGJMZVljUhwGBTIddmCpDYZulfS teHLTWUbd 6lO396gUMwXdtRjg/Llsn8PQUAAHznqOoSazcLcO0aOFCJHEg RU 6u1iMJnoAzck9a3NTgu9AuWhYIQ8R3OsauFt5SYyrfuyB9z0Xk8UAAGv4Djf 0nkMe3NvcKWAGC4lgJHHTaCOPfitLwND5l5JciGWELa Xudi3nbpAfN YA/w4 XKjBoAAPW728u4JEjt7F7kMuTJ5iIi9RjnOW7ndsXH3STxW7QAAeYXdt4l1AbC0NqMDdsbEb8ZOCrPMPmOMHjAr0 gAA8fg8Ebzuu7hJCy4fEYdiVzgq7bdvU7vkz/tCvYKAADhbfwhotv/y7ebhtw812YDrxtyFK4OCGBz/Fmu6oAAIY4o4VCRokaqMBUUKoA6AAYwPSpqAADy7x9bmbRd4/5YXEUh jbov5uK6DxXbtc6HfouMiISc9MQusrevO1Dj3oAAPnLws7W s2LKUVjIq/vD8pSUFGxjB3lW QevWsXRmVdTsC5wourfcTxgCVec9sUAAH2xRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAABga3bSXmmXcMQDSNEfLB/vr8y7eRh9wG05 VsHtW/QAAfGckeUMqkESEMQynYrDJ8re2FZsHI29yRX2E9tBIwd4YmYFSGZFLAqcqQSCcqeR6UAAHjWj EWuYPNv4/JMzCQoskofYGBWN4yxTBGcbhvTPqK9voAAKltbQ2cMcEEaxRRjCovQD8ySSckk8kkk81boAACigAAKKAADxHxfpL3V6Jh826FFVRuDKYy5yuM7yx4xgsuc16zfWCXybWeSMjo0bFSPrjGfbvgnBGTQAAfLdhpF5cSpBsO24n2q2SVDRjc7bCwU7V67sNtHy5zX0hpmkfYJZJGkV8jam1SgVSctldxXLEDJxu4HJoAAOnUBQAOABjinUAABRQAAfPXjyR49TgZGMZW1Q7xkZ/fSEAnJB2kcAr3q942WM6hCWi3N9kyJPM27QkrMwZNpBGO7HvQAAVfA8rPqs6u8zSC1fduYbCokh27U4IxliP973qPwNzqskp3jzLWXaGLMWAmiOdx5xt2jn lAAB79K/lI0mGbYCSFVmYgDJCquWZvQDk9KnoAAI0dZEV1OVZQwOCMgjI4OCK4aO6fR9VFlMxa11Bme0dnH7mUAb7fDMMISR5YXoWCgHJIAADvaKAAAooAACigAAzNRga5sbuBfvS280Y rxkD dadAAB8LRNzvJX5MNtK8NtIwuB645qYxjcwTHGUxuOZCO68d woAAPuIHIzVCxma4tLaVihaSGJyUzsJZASVzzt54zQAAaFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAAHiXjWzluby2ZUyqQ/wCsZ8IrGQ4DLg9fXj69queNYHkltmTc58mYGIAglN8RZ1cY5Bx8vpnHegAAzPB0TrqkryMrOLaRHKfcy0kTqAoAVSoB3YwvTGas EIZPtXmD/VxQm3bD5O47JQT3cY 63bJwBQAAe10UAAHN65pSatYyQkfvVDPbtuK7JghCkkfw84YenuK6SgAA888L61JfJJY3g2XtkPLky24yhflL8ksXUgCTkjJDA84HL MtCnWRtaspHSSJU81U3CTC/L5qsnPyrjd0woJzQAAe115/wCHPE9vrUaxSMkV2vDRbuJNoyXi6ZHBJXquD2oAAPQKKAAAooAAPjDUo9moXqCMhVuZlBXttmYfLngdhx9at6qXTVdS4DKbu5 VhuTmZ vI2njjPWgAA p9Ez/ZWn54P2S3/wDRS/5NZ/hhmOi2O4EFYyuDn B2Xv8ATjt6UAAHW0UAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAef8Aie2lmW3eMA7fMH8RYZ2vmNRndIyoyKO 6r3iNphbRLAheWSZUTp8nBYyZPQqqnH1NAABj H4I4rgmGO4jTZIGErZwWMbAKNg X72N3zLjA4qTw25Lunms xX8xW3uysXyqmXeyNwSR/Fg4HAoAAPRqKAAAooAAIpI0mjeORQ6OpVlPRlYYIPsQealoAAPlTXfDVz4dk 0xF5IA4MNwjFZIWzld AMMp6MMA8dDxX01fWUOo2strOCY5Vw2DgjBBBB55VgCO3HegAA8U0n4hbVWPUoWc9PPhC5IwOXi4Gc5JKEf7teUazpk2lXk1s6sqrITFu/jjJOx1PRgVHJ7NkHBBoAAPrG31/SbpN8d/a4xk7pFjYDOMskm11/EV8XA4Oev1oAAOhub2K5vbqUq5SeeWQfPggPIzBWHCn7xz lc/jd6cD19/egAA v/Cg26JZDfvwsgzz2mf5QT1C/dB9BU/hmJ4dE09ZDljAH6/wyEuo7dFYCgAA6yigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAADmteIFg5JgBDIR58nlR8NkgtyeVB4A56Vf1OMS2kgIUgbWIYkAhWBI4yegOKAADA0OCONnkDDc442fdeP5WBdQoTcpYgOPvBq0tMt1gaUKE2g4VlGDn LjJx1VTt4JGcUAAHR0UAABRQAAFFAAAUUAAHPazo8Gt2htpiU5DLIoUsjDuNwPHr0yK6GgAA apPh7qauyxy2jpuOx2eRDjsWXymwSOwZvrX0rQAAfIsXhbWnuXgWxb5cqXdQsPoWWVsBvUbSTX11QAAVLW3W0t4bdCSsMSRqW6kIoUE8DnA5q3QAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAAFO6XdBKMbsqeCBz7cgjmrTDIP0oAAMyxiSOMGM4DZYqDkbmwd3OW6dPrTbGNo1w0bRYJ4LK2dwBJynDemWGeuOKAADXooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACqd1IYYXlAZvLG/aoyzBeSoUZyWGQKAAC5UcbrKodDlWGQR/n86AACSigAAKKAACrA 7fyTh2XnGRg9OMfh3p8cfl7sEkFieecZ6j88nn1oAAJ6KAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAAPM9D1Ge0v59HvkZG8yR7N9vyPDy zcv8As/MpP 0rEMMVt6zoMWpvHcq0sdzApEbRyGLd1Kq7LlgFYkjbt6mgAA7GuC0/VbqyjS31ZW85I8tOiExvtUHG7JLybDlyq7chqAADva5U61HNlLdW3/LzINgALMpPf7pXkHb95fWgAA6SNtwJxj5mH5MRn8cZrOsWmYN5nTqpAXBLEltpGcjJ4zzQAAa9FAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAARuiuMMoYe49Rg/oSDUlAABhy6Vay5wHiJYNuidkPUEjjjDYwfbpitygAAaAF6AD6U6gAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAD/2Q=='/>'''# 邮件主题body = { 'subject': "自动化测试报告添加图片", # 邮件标题 "content_html": html, # html格式}# 收件人receivers = '821006052@qq.com'# 发送邮件server.send_mail(receivers,body)

(左右滑动查看完整代码)

通过代码执行后可以发现,邮件成功的收到了并且图片和文本都存在邮件中:

附件发送

通过上面的两个例子这里应该很清楚的就能知道了,我们只需要将附件信息直接写在我们的body文本中就行了。

import zmail# 发件人username = 'xxxxx@163.com'# 授权码密码password = 'xxxxx'# 创建zmail服务server= zmail.server(username,password)html = '''<p> 这个邮件中携带附件,自动化测试结果 </p><img src='data:image/jpg;base64,/9j/4AAQSkZJRgABAgAAAQABAAD//gAQTGF2YzU3LjI0LjEwMgD/2wBDAAgMDA4MDhAQEBAQEBMSExQUFBMTExMUFBQVFRUZGRkVFRUUFBUVGBgZGRscGxoaGRocHB4eHiQkIiIqKiszMz7/xAGiAAABBQEBAQEBAQAAAAAAAAAAAQIDBAUGBwgJCgsBAAMBAQEBAQEBAQEAAAAAAAABAgMEBQYHCAkKCxAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4 Tl5ufo6erx8vP09fb3 Pn6EQACAQIEBAMEBwUEBAABAncAAQIDEQQFITEGEkFRB2FxEyIygQgUQpGhscEJIzNS8BVictEKFiQ04SXxFxgZGiYnKCkqNTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqCg4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2dri4 Tl5ufo6ery8/T19vf4 fr/wAARCAH0AfQDARIAAhIAAxIA/9oADAMBAAIRAxEAPwD3aigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACsV9Y0yJ2je/skdTgq1xCrA hBcEGgAA2qarBgCpDA9CDkUAADqKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAA898VWetX1v5OnPGkRRxOvmBJJckYRSU UYBz 8XduIbisPxzros7U6fCx8 5X95jPyQHIPOR80mNuOfl3ZxkUAAHzRSUAAGja313YsXtriWAnqY3Zcj0OCM/jWdQAAe1aJ49uYpVj1MiaFuPOWNRJGezFUwrKO4C7u4zjB8VoAAPuu1uoL2CO4t5BLFIMq69COnfBBBBBB5BGK VvDfim40NxE4M1ozZeP JM9XiPHPTIPyt7daAAD60pAQwBHfmgAAWigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAAPFn8AveXTXN/qck7SHdJshVHJxwFdndVC8ADy8bRgAV7TQAAcTZeEtFsowgtI5zxl7gCV2wT1z8g iqoPeu2oAAM3 z7LyPs32W38jj9yIkEfDbvuYC/e5rSoAAPM9Y8E6dqQVrcLYSL1MMa Ww/2ogUGR2KlevOeK9MoAAPAv FbNn/kJDH/AF7c/wDo/wCtdXrvjaz0wvDahbu4GVOD 5jbHG5h9/nGVT3G4EUAAHp6rtULknAAyepx3P8AWvlaXUfFHiD/AFYvGikZlC28bRwYY4KM6gKyjgfvXbA6nrQAAfVW4A4yMntmvkC48K67bRtLJYy7V67Hjlb8Fjd3I9SBigAA wa I4NW1G1P7m8uouckLNIATnPI3YPPXNAAB9uV8v6f491W2ZRc Vdx5G7cgSTbxna0e1c/7ytQAAfUFYOlaxZazCZbSTdtwHRhteNmGQGX q5U4OCcGgAA3qKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAK858Q LrTRt8EX7 728J/yzjJxgytx2OQq/NxzjINAAB2WoajaaXAZ7qVYkBwM8lmPRVUZZj9PcngGvjfUtUutWuHuLpg7tjHULGq5wka5wq8/nz1JoAAPRdR8Sap4nnNhp0LJFJuHlqcSSIP4pXyFRe5GQvOGLV5Qs0iAhHZNwKttONynqrYxkex4oAAPojRfAVtbrHNqJ8 bO7yVP7lfQNxukPr0XqMEc1x/gbV71dQh08yF7aRZf3bc WQjPuQ9Vyw5H3TuJxnmgAA kY444UWONFjRRhURQqqPQKMACpaAAAooAAOZuvDukXr ZNYwM WYsq WWLdS5j27z3 bPNZ/inWRo myOjhbibMcA77j95wP9hec9NxUHrQAAfKuppBHf3aW PJWeVYtrbh5YchcNk5GOhyc1lUAAHqPgEzDWv3eNhgl83/c XGPfzNldv8PdMkhhuL6RFAn2xwN/FsQt5h9lZtoHPJQ 1AAB7bRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAVXiuIZy4iljkMbFHCMrbHXqjYztYdwaAACxRQAAFFAAAUUAABWJqmrWmkQGa6kCjB2oMGSQj FF4yeRnsM8kUAAGvJIkSM8jKiICzMxAVQOpJOAB618ja94nvdcba37i3H3YEY7TzndIeN7dMcADsBk0AAHa IfHMsxa30xjHFyGueRI4Ix 7DAGMcn5vv9CNteZ6VpUmpPK24RQW8bS3E7KWSJFBPKjBZmxhVHzHn0NAABgkEYJB5GR78kZ9 a1dT1GTU7kzuiRDYkaRRjEUSIoASNf4V749SaAADGpaAAAr6O8EeHHs1/tK5xvmiAgT5W2xvhvMJwcMwxjBGFJz14AADX8HeHBpMAu5txuriIZU5UQxsQwjwcfPwC 7oRtHQk oUAABRQAAFeX MNYlghGm2SvJeXakFY0LssJBDEAZ Z8EDAOFDHjigAA8X8Wa2dY1BtjZt7ctHCOcHn5pOv8ZHHT5Qtel GPBSQL9p1SJXkP rtmwyxj 9JjKs57L91R1 boAAHE F/CU2rMtzdAxWisODkNcYPKr0ITsz/AILk5x9QIixqqqoVVACqoAAAGAABjA9KAABsUSQxpHGoREUKqrwFVRgAVLQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAAHyFr73Ol65qK29xNEWnMhaJ3iP73EuDtYZ278fhmuk IFgYNTS6CnbdRDLZGDLF8hAHUfJ5f50AAFvw/44uYZYrfUW8 FiqCf/lrFwAC2P8AWL/eJ fknJxivF6AAD72r5g8OeMTo9rNbXCSTqBm2C7cI5ySrkkEIxIORuI545oAAPdtb1200O3MkzB5CP3UAI3yN29dqf3m7e54r5I1HULnVLl7m5fe749goAwFUDoAP/r80AAEmp6ndavcvc3L7mboo 5GvZEHOFHbv1JySaxaAADf0fSp9Zu0toeM8u5BKxqBksxAOPQZ6kgV774C0prOwku5AQ92QVBHIiTO08gMN7En0K7TQAAYHi82uh6Tb6RZqE89vMlxglkTBLOTlsu 3B9EI6DFcb46uDPrcicYgiijHBB 7vOc98ucHpjFAAB5pRQAAeq DtEW9kkv7mLzba0DEIOTLMoDBNv8QVTkgkAkqORmvcvDtqul6LaJIwTEXmyF/k2mUmRg2Txs3bTn0oAAOsR1kVWUhlYAqwOQQRkEEZyPSuDvvGei2J2 eblh1W2XzPx35WM HoAAO/rwO7 I5 dbWxHX5JJpM5Hq0SKMfQSUAAHvlfKc/jrXJWyk0UA/uxwxkfnKJG/WgAA pliRCSAMk5LdyT79fYegAFfJDeL9eb/AJfn/wC/cI/lGMUAAH17XxgniLWY2yuo3h/3pncfkxIoAAPs vlODxzrkLhnminH9ySGML09YxG/H 9QAAfVleUaR47stQlENzEbJ2ICEv5kbEkAAvsTacnuu3g5IoAAPV6KAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAAOd1vR4Nbs2tpSU5DxyDrHIAQGxkbhyQVPUHjBwa6KgAA INS0250q5e2uU2OvQ87XXJAdCQNynHB/rX2Dq2j2esweTdJnGSjrw8ZI6q3P4g5U4HHAoAAPieu01zw3eaJJh/38RyVmjRtgXPAc4wj45K547E0AAHIMV2qApB53HP3ueMDHGPrzTkR5WVFV5HbCoqgsxJPCgDJPXgDvQAAd94O0c6pqSSSRLLbW53TbiMZKt5YKn7wLDkYxgHNTaZ4e8SxxtPZrPbZ4x5v2d3xnqrshwMfx46jHegAA quAMDgCvi291HV2DWt5c3vy/ehmeQHrkb1Y5POCN34UAAF/xW6Prl80cnmqZF bO7ny1yoPohyo9hXG0AABRQAAa15qV7qDbrq5mn9A7Eqv8Aur91f AgVLYaTf6m220tpZucFgMIDjPzSNhF/E0AAGJXtmn/AA8uZGRr2ZII rRxnzJvpu2iMfX5se9AAB4nWzqtrFZahdW0LM8cMzxqWILHacfMQAM568CgAAz4YZJ3EcUbSuSMIgJZuegA5P4V0Phy5NrrOnyDb/x8JGdw4Cyny2PUchXJB7GgAA2rXwTrlyRm3W3UjO aRAB7FULyA/8AAK sqAAD5yj HN8UYyXdqrgHaqiR1J7BmKoVB5yQrfQ19G0AAHyHqnhXVtIDSPEJYQDmaE71Ud9wIDrx1JXb719bTRJPG8UgDJIrIyn JWGCPxBoAAPg tTULKXTbua1mGHibBwcgjqrA jKQR35oAAO98OeMJdGjW1mi8 38zdu3HzIg2N2wHKkdWC/Lkk8815dQAAfdVrdQXsKT28iyxSDKuvf RBHQg8g8GvlHw34ln0GUqQZbaRgZIsnKnp5kfOA/r/eAAPYgAAPrqqdrdQ3sEdxA4kikXcrDv8A4EHII6ggigAAuUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAABmX94LKHft8x2YRwxAhTLK33Y1J6Z6k/wqCe1cJ4vvZNPfSbjEjQpeBpVQgBiBlQRkMWwGK87eu7qKAADT1DQH1BkgeUC2MbefLlvtk0jE8bhiHZ0YbkO0gBVAru6AADDsdIstOCeTCu5EEYkYBpNgJO3efmxljW5QAAFFAABk3 mWWqR Xd28cwHQsMMvIJ2uMOucDO0845rWoAAPnDxh4WttLt47uxjZYtwSZCzvsJ 64znAJyG3N94rt6173qNkmo2dxavjE0bJkru2sR8r44yUbDD6UAAHxdYywwXcEk8YmiSRGkjPR0B5HPt68U27tJbK4lt5l2yRMyt/wE9RnGQeo9RQAAfcEMUUMapEiRoB8qooVQPYDAFcR4Q1ZNU0uJc/vrVVglBxn5Vwj9ScOvc/xBvSgAA7eeZLeKSaQ4SJGdj6KoJJ/IVwPjTUEs9LaDzBG94fJUnPCYzIcBWJG35D/vigAA WLmdrmeWZ/vSyPI3 87Fj pqrQAAW7ZZHniWIFpC6BABkl8jaAO/Nd74J083uro 50W1XzyVxyQygISQRhs8/7IPTrQAAfV1FAAAUUAABRQAAeAfEHSZmli1GJC8YjEU21c7CrMVdsdm3bc9sAdxXv3WgAA Cq9d8X GDY3AuLCCZoJEeSVURnSApjJ3AfKhByN3TB7UAAHkVLQAAfYnhWD7Nodgm8PmLzMjoPNYybe/K7tp9wa8 HuqtIk2nSMx8oedD3CoWAdfb5mBH1PSgAA9yooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAADy3x5aNcaUsolKeRMjCPC4lZyIxzwwZQxIxxjOR0I7PW7WO80y8hkV3Uwu2EyX3IN67QMZO5Rgd lAABNpF39u0 0uC4dpIULsP egXDjHbDggj2rxnwHrdtbK2mTYieWXzIXJ V2YKpjP91/lG3 9yOuMgAB7/RQAAFFAAAUUAABRQAAeMeOtE8 D7fBCGdObhlGZCoXCv1 4nR9ozjB6LXpWqatY6VCZLuVV4O2PgySf7KJ1bqM/wjPzEUAAHyjoutS6PfQ3CD92uUkjH8UTkFlzkEnjcuTgMB24rI1GW1nu5pLSEwQM37uNmLlRgDknn5jlsZOM4ycUAAG34h1t9bv2uBvjiUBIYyRlEHUnaBy5yx69cZIArkKAABa918DeHY5lTVbj5trsII/lIyvBkbqchvuj5SCufSgAA7nwdobaRYmSYYnutjuuGBjQD5IyDjDDJLcA5OO1ej0AABRQAAFFAAAUUAABRQAAFFAAB5frfgmy1WY3EMn2OVvv7EDo7Z U3JhvXB569evqFAAB5roPg630S4 0m4luJgrKpx5UYDDBygZix/3m289MgGvSqAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAAPlbxposWkX6SW xIrkM6xDP7tkI3cc/IxIK/iMYFfRWraNZ61AIbpM7TlJFwJIycZ2MQcbsDI6HA9BQAAeBaf481O0EUVwkNyi4Bd9wmK44JdWKsR3JQs3c55rQvvh3dpIPsdxFLGf e26N168Harqw6cjHJ6UAAGm3xIALAaduGSA32ojI7HH2fI lcJ/wAIbraqd1i5Y42bZ7baPXf 8Pbp05oAAOwl JE5x5dhEnrvmZ/5InvXDr4P15uli/TPMkCjB so546dfzoAALF54w1y/DAXAt1xkrbqIyMHqHyZfTPz1px ANZcjcbSPKKxLSscE9UOyNvmXvjKejGgAA81mle4kMksryuwyzyFmYnHQscsfTNfQlj8O7OIhru5lucEHYgEKEdw3Luf AspoAAPAbOxudQmENtC80hx8qjOBkDcx6KvIyTgCvtKy0 006PyrWCOBf8AYHLY7s3LMfdiTQAAfNM3gTWobdZVSGVzjdCkg8xOM8ltqHHQ7Gb2zX1TQAAfKmiahfeGpFZoZMXG9WtpPl81o32fLwWjdG3D5gd3THNfQ p6FYathp4iJVGEnjYxzJ9GHXHYPuA545oAANGwv4dRgSaIkBhko BInJG11ydpyD VVtJ086XaR2xmafZu cqFJBckcAnnBwT/ABYzQAAblFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAV5nrniz yb5LWO2NztCtPhjlVcHAXAOGxhju6gj60AAHplVreeO6hiniO5JUWRD0yrAEHHbg0AAFmigAAKKAAAooAACigAAKKAAAooAACuL8QeJLXQYwG/e3EgzHApwcf33PO1M8Dux6dDgAAOuM0ayLEXUO4YqmRuYLjJC9SBkZ teA D7 51fX57q7kZ5BaPtwSqqvmRgIFXC7RuJx6/N15oAAPoSigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAzdQvY9OtJ7qTG2GNnwSF3ED5UB55dsKPcivLPH pCK3gsQf9afNlAbB8tDhAR3DPlv8AtnQAAeGzT3WpXbSuXmluZcKQT8zMQoVepA6Ko6AcYrv/AAbYC91JZWU7YEWbcP7yvhBn7vznkjG75KAAD3/SbI6dp9rasctDEisdzMN2MttLc7dxO30XAwOlbNAAAUUAABRQAAFFAAAUUAABXnHinxOmiRiKDZJdSdFJyIl/vuoOcnPyDjue2CAAE/iTxPDocfloBNdOpKJkbU6YaXkHHOQP4sdq UnkaZ2eRmd3bczMxLEsSSSTnJJPJPNAABfM1xqd1mXdcTTuFzn53ZjgAHn2AGMY4xXvng/wq nEX16MTkERQ8fulbgu5/56MOAv8IJz8xwAAA3vCfhz w7dpJsG5nA34wfKQciINzk/3yPlyBjOMn0SgAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKQkKCSQABkk9APU/1oAAFpoYMAQQQRkEdCPUH VAAA6igAAKzNRvEsLK4uXOBFEzc45bHyjnjLNgD3NAAB80 J7l9U1uYIquIm zRqxVSfJ3FmJJxt3lyOeRisC2sZL6SIQfvXmkwiv8APl8bju YcepZe2WwAaAAD3bwLYfZtNa5YfPdP68eXEWVdo7ZbcffIreutc0nQIEt5LgFoIljWGP95LiNVADAfdOMY8wrmgAA7SvnjUvHl5cjy9PhFuCf9a 2WTBPy/8ATOMnoQd/XqMUAAH0DJLHCpeR0jUdWZgoGBk8nHYV4X4b0u91eb7ZeNcJbjbhnkPmXL8blJOd0Lfxfd/ur0OAAA91jkSZEkjYOjqGRlOQysMgg9wR0pyIsaqqjAUAAew6etAAA uP8Ra9FoVrvwHnkysMeR97H33G4N5a8Zx3IHGc0AAGd4o8SR6HAEiKPdSfcQnOxe8jqO3ZQcbj64NfN6/atYvVMivd3Fy5HynDk9j93YqoO3CqB2AoAAMYma8n58yaWV/9p5Hdj LMzE/Uk19VeHfC1voo86TbNdMOZCOI8jlYunqQX4LDsASKAADnvC3g8WBW8v0BuAcxRZDLDjo7YyrPnlOoXg/e6ew0AABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAB5H8QHuRp1ukZxFJPiXBILFULIpHRl Uk57qvBr029s4dQt5badd8cq7WH8iOuCpwQfUUAAHyvoPiK50J22kSwM3z2xdhk4wHjYqwU8c4 90PQVa8R F7nRHWWItNbknEio2YgCoAmPKKWZsLjAbHQdKAAD3VPF htAkzXiJuGTGVcyqeMqyIrNkE/Q9iRzXySHKkEY46A4bGe/PegAA9r8WeLbTULT7HYlpFZkeWVlKqyqQRGqsoYndgtuCgbe a8WKldodGGRuGdwLKemPb0NAABbhleN22BVcHKyoxjMfXlXUjjn VMijEzJGqSsXO1Uiw7s3RRtwCcsf8KAACMKxbG3IJUFd3XgYy2f8A9Ve2eH/AzF0udSGF6i1OCx/umVlPy pUc9j3FAABkeH/AAvNq6R3MhS3szwoVmeWQI HA5AAbDDc dv8KV9HoiRoqIqoqgKqqAFVQMAKBgAAdBQAAJFGkMaRxqERFCqoGAqqMAD8OlS0AAGPql6unWU9ywc WhICKXOe3y8cdzyBjNeN L79jI6uzbM7YwNy UfL YMON5ZjyynbjA7UAAHASHUNcuk81jd3EyhY1BVSwAJB42xJsALFF24yS3PNbXhi1mnukeKRbUh8GViGeRTxIsXHyvg/MV65oAAPYfD gWvh2AyyvH9okA8yViAqDP8Aq42bGFzjP94gH0FdU m2cu0ywrKwz80uXb5hyMtnjjp0oAAMm48SabCrFJftJAB2wbXyPZiyx8d/m XjNaZ0jTSCDZWuDnI8mPnJyc/L3PWgAA8tuvHc2Qtrp 4vyhllJYDP8cUafLx0/eV6UdC0ouX xQAlSrBV2qwbGdyrhW6D7wNAAB4TceMtddx88FuMfMkMcbY52k/vTKcgnkZHT617sug6QuMadZDHP oi7nP938vSgAA eIPG2twy7nuYrlckbJIYlU 48pYmHt82K961m3sbXTLyT7PbpiGQKRCn sdSi4GByzMAPrQAAZfhvxOmtgwyoIbpV3FBnY6jbllzkrjcMqx9xkZx5N4Mgl/tmAqWIjjlZyDlSmwpnJx/GUB7gj0oAAPpuigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAAEIDAggEEEEHoR6H tLQAAec3vgrSbvlBJbHAH7sqV UHHEivj32la7W/vI9PtJ7mQgLFGz8kDcQOEGSOWOFA7kigAA Rl0/zrl7aF/Ok88wQE7lL4l2 YF 6FxliM/Lk mauG6ijMb2wNpKGdhPGHVvmQgbUXdn5SRlCNueaAAD3yx0/R/Cse R1NwwAkmZS8z5POyJAzIm49EX03E4zXzQZ2d2YysTjcZQzCSR3O47mySSecls9KAAD7Ds9TsdQLC2uIpin3lVhuX6rwwrw/wAGRu q7o1YpFFJ5ruqswLYUIz4G3eRuQddqn3oAAPoasm/1G30 MtK67sErHn5nwCcADJ7YBxjJA70AAHN IdXt7GIRNl2kJHlKTufaAxGQRtGOpPHNeG3ktzql/JdMjxNv3AHIXY21FjG8EK 373XnNAABnGSbVHed2ZFjK7cnKqrdIxnqRg/dHXPc10Qt94jSBHRUjXIRd5VgxBaPrlmyDJwwVgB3oAAL9vbywy262kbKP8Ali0ZMqvg7jkfKUfJw3zDeB1r1nw/potbUSSRCN5CZFQ78xK5D7GD4O4NljkZBPtQAAdbCnlxov8AdUD/AD/SlkkSFGeRlRFGWZiFVQOpJOAB60AAEteVap46srOQRWsf24gZd1k2RL7KwSQufXau0ZHPWgAA9Vr5hu/G2tSunlyJbB8EJFbqx2nphpt 4np8uOlAAB9PV8q/2/4mhnVRPeCSVQBG9srE7c8JE8OM9dxRfqTQAAeg M9Qlnkh063D8OHlcBsM5GEhXA dsNkqvzZK7eRXG G9ZOmalKdRhnL3D/M8hZPs3mNuaVo2AU Y23e3ysoX5c9KAAD1/wAL6D/Y9rvlUC6mA83B3CMdo1P5F8dW7kAV3YIYAggg8gjoR6j lAAAtFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAB8169c30l/NHcTBijyD7O26NEhJ QBm2IQw2MHxuZhzkCvbdW0O01cL5yAOv/LRVTftAbC5ZWyAzZH8 TQAAfKLtcYlU7UBUEhc/w9NnJ hx0yau3dpJZvNCyh3h3E7twGFyj7fm ZQc8NhqAADNZI4naE YRwVIjUMCQM9ycfQ9qJZkmji2o48tNrjORuHCkMAW bjhuM9KAAD1qz8WWel6PFb2sRS74D7wdrsR81xvI YsoGA33MheVWvGTsA3F95OPlAIBHcHpgj29QaAADuo2kvpJLuSWW4kdl3ldqSjI6ybQMqoC4VPu4xxVrwnp0t9qPD7VjVvOdWLMUdfl2sVZM7to7HGfSgAA2rPT7q4cxxoXnRFZs7osM2MO3mKfLbdz8u48EgV75bWyWsQjQuwH8Tuzux7lmYkmgAAxtO0W2sMPjfLsRdzYONuTkcD5ssct1bvXS0AAFO4n8heEeV2DbERWOWCk4ZgpWMHGAz4H41coAAPB7/TPEXiL55oTbpkbIZJBHGgz1CrvkY8At5qq2T8vHFe8UAAHzdq/hNdJ0x7m4ui8u6NY44kxFGzn5x8xaSQbQduNh9RivWfFse/R5WDiMxy27iQ/wAGJ0G/ofugmgAA5zwFd2dxaSQ VCl5Cx8xggEssZPyyMdoPyklCAflwOma4G81BYlttf065t4LyUeXfW25NzyAjdIsOSTHIV3P9VbqTQAAfToQA56n1PX8PQe1cZoPiey1uHIZYZ0C bC5AIJ6tGSfmTdwD1HG4DNAABzXj63jktLOTLrILkRoVyRh1LEMo5YZjXHoa0tVMWq61Y2Cuki2yvc3Kg52rwqAkHGWOAV67GPrQAAdZpeRYWgJckQRgl4zExIUA5jIGzkcDHFa1AAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFVbm5htInmmcRxoMsx/oBkk gXkngUAAFqvn3XfFU99cx2ti00cDoAQiDzp2LZ4YMfkK4wFZDhm3 lAAB6JrniSPTMwxIXlwD5hRmijBPOdpDOfZemRuPavCreOSWdncPHJvcLlVeIyoceRhm25I 8A3TgdKAACO686/uZJ5DGXc73kZPLRypIBwMHywpGSPm uK6aDSft0LSRW8cifdm3vJEgdRhjuwfK2MRiJemDng0AAHHpaedceUimSWTCouwBbhuzqAPlVsb8nbuGCtfRvhnRotNhlkXYzTMNpGSY0UAeVvYliA4Y/jQAAfOuuaLdaQ0RuTGTKm7g5K9Eyy4 U m0sDjt0rs/iBJGNWgDoW22qHG4jcDLJxx0YY6 maAACz8Pjuu7rb5e1bdc5UCUszjnPPy/Kc/VatfDwr5uobMhWS3I3csdplySRkcEkds8UAAHvFFAAAUUAAFS5uEtYmkfccDhVGXc44RRxlm7VUgXz5pZmbcFYxRp/CnlnDNj z5yfQCgAA5sjXtSRmWSLSozzEuzzrlhyP3pb5IweDhV3jpkY57qgAA8Su/BGo3anz9bluCASqypKy7sdOZzj0J2/hXttAAB8Qadp0 qXcdpbhTJJnG87VG1SzEnngAH3rY1BDpuuXDBCqwXzOoX5SFEu9QvoduMUAACav4d1HRFia6jXZIWCsjb13DnaeBgkcgd8HHQ1794wmtbzw55/Xzfs81ue4LFTu6jH7tmDHtmgAA abO utPlSe2kkhZcDcmBuGc7W42sDgZDBhVfZnvtHXH3sdhnH5CgAA qPCniCTXbaTzowk8GwOy/6uRX3bXUZJU/IQw6cZHXAg8G6Zc6dYSm4Tymnl3iMptkVVUIN CeuMhf4c980AAHo9FAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFeTeIPFhgQw6aVkkK5 0/K0Y bGIs5V24JLcoMDrngAAOu1jX7XR1w376dhlYEZd3ThnJ 4mcDOCf7oOK a57yN0iMbPNMrs4ciTzMO5d2lZi6t85Ow8nBJbrigAA1b/UL/AFaVJrqWNOdirHIfLt8sUIaLlsSjncMsQc7scVXt7E305toLUmRQw8uUGO4jQAN945BxjbHlUx NAABW wXNssnmxS8Mgkkjk2iHJO1Nq5Jbk4znqOK gNB8PrpyJLNuMwHyjO3YrAZWURt5csgPVsEcDHTNAABymh Gmn z3NyoiRCCsXlhHkMW5FMse3ZyuCHHzMD2yMeykgDJ4xQAAYtyFjEECbo0b5Mr0VSpXHOevY46j3otpDPcSlxIhQ7VVihQr/ejwofngtu9RQAAcnqWoano5 aaF0kl2xAwbURdp2qdpBwoXnndk56VxfifXjfTx21k0bwow/fK/DSkspQchDgfd5HcjgigAA4rxNqM19drNNGkWbaNAFZXWUozMGxyyLlj8pOfc1zU8TpIWnVssisC6bMqRgMBgKwYD5JB8pxQAAelfDtXF9ctjCG35 bHPmJt TcMjG75tpxjqM8s8Ahk1Ns7CGspCGGc/wCuh Vv93t9aAAD6OooAACigAApW8BgM3zllklaRVI/1e4DcuedwL7nGem7HQCqd7q1hpoBurmKHJwAzfMeR0QZY9Rk4470AAGzXmt54zs7fzljjd3jGYy5VIZwDyY5F80kY5BKDPHSgAA9Kr5Zv9f13WyYYiy5Gfs1osgdgQcqwGZHXacnPyGgAAg8bJGNcuWV1k3xxNiMg WyqEKyehwmce4rmL7RdR02KOe6t3hSU4UsUyWxkgqGLL/wIDNAABnzXlxcpAk0zyLAvlwoc4ROuFxgenvwPSvRfAMME2qyCVEkKW5lj3AHbIskeHUEH5lzwe1AAB2ng/wy9u0WoXOUZBmFQCjMJEYMZQQcr8w2fdPGemK9roAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKrXFxHawvNK21I13Mev4ADJJPQAckkAUAAEV3eW1hEZrmVIUHdj1OCdqjlmbAOFXLHHAr5g1jWpNanDSiTy0VykZ2oYxIwGFIUbl4Ubm/iB6DFAAB0ureK7jUd8cMn2O3BjbdFJibazFSJTkFW6Eon3c4YtXm7LCiSO0EinbtYkDYpZePkOwg55DcjvzigAAZ9nRZdmdqv1aUYXHHzKMK3fcp9DXe6FoE2sSxTtI/lpvSacMEZSqjZGgDlzJgq7ZRVHPJPFAABj6Vo13PcpBFG7hnYNLjaiwn5fOO7 Lk4HzegBIr6bsrGKxj2puZiF3yPy8m0YBY8e AMDk tAABS0zRrTS1JiXdM4AluHJaWU4GSzHONxAJA4zXQUAAEckiRI0jsERFLMzHAVVGSSewA615d4z1IRRJZK4zIPMmiBKvJHkhYwdp V3B3FeflAPDUAAEVz4rin0/8AdsouZpXTy0ch4Iw77Xc4IJ2qMgfKxJ5xzXkcEDJMVnZbd/uh1KtxJ8xXKqfl27sn5m60AAHuvhvM1vPN5hMr4G0qyGH5eBtZmXnhgVynpmui0WFYNPgCtG4dfM3RhhGfMO4FAxPy4Ix69cDOKAAD5WOYZMTrvRGJMZVljUhwGBTIddmCpDYZulfS teHLTWUbd 6lO396gUMwXdtRjg/Llsn8PQUAAHznqOoSazcLcO0aOFCJHEg RU 6u1iMJnoAzck9a3NTgu9AuWhYIQ8R3OsauFt5SYyrfuyB9z0Xk8UAAGv4Djf 0nkMe3NvcKWAGC4lgJHHTaCOPfitLwND5l5JciGWELa Xudi3nbpAfN YA/w4 XKjBoAAPW728u4JEjt7F7kMuTJ5iIi9RjnOW7ndsXH3STxW7QAAeYXdt4l1AbC0NqMDdsbEb8ZOCrPMPmOMHjAr0 gAA8fg8Ebzuu7hJCy4fEYdiVzgq7bdvU7vkz/tCvYKAADhbfwhotv/y7ebhtw812YDrxtyFK4OCGBz/Fmu6oAAIY4o4VCRokaqMBUUKoA6AAYwPSpqAADy7x9bmbRd4/5YXEUh jbov5uK6DxXbtc6HfouMiISc9MQusrevO1Dj3oAAPnLws7W s2LKUVjIq/vD8pSUFGxjB3lW QevWsXRmVdTsC5wourfcTxgCVec9sUAAH2xRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAABga3bSXmmXcMQDSNEfLB/vr8y7eRh9wG05 VsHtW/QAAfGckeUMqkESEMQynYrDJ8re2FZsHI29yRX2E9tBIwd4YmYFSGZFLAqcqQSCcqeR6UAAHjWj EWuYPNv4/JMzCQoskofYGBWN4yxTBGcbhvTPqK9voAAKltbQ2cMcEEaxRRjCovQD8ySSckk8kkk81boAACigAAKKAADxHxfpL3V6Jh826FFVRuDKYy5yuM7yx4xgsuc16zfWCXybWeSMjo0bFSPrjGfbvgnBGTQAAfLdhpF5cSpBsO24n2q2SVDRjc7bCwU7V67sNtHy5zX0hpmkfYJZJGkV8jam1SgVSctldxXLEDJxu4HJoAAOnUBQAOABjinUAABRQAAfPXjyR49TgZGMZW1Q7xkZ/fSEAnJB2kcAr3q942WM6hCWi3N9kyJPM27QkrMwZNpBGO7HvQAAVfA8rPqs6u8zSC1fduYbCokh27U4IxliP973qPwNzqskp3jzLWXaGLMWAmiOdx5xt2jn lAAB79K/lI0mGbYCSFVmYgDJCquWZvQDk9KnoAAI0dZEV1OVZQwOCMgjI4OCK4aO6fR9VFlMxa11Bme0dnH7mUAb7fDMMISR5YXoWCgHJIAADvaKAAAooAACigAAzNRga5sbuBfvS280Y rxkD dadAAB8LRNzvJX5MNtK8NtIwuB645qYxjcwTHGUxuOZCO68d woAAPuIHIzVCxma4tLaVihaSGJyUzsJZASVzzt54zQAAaFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAAHiXjWzluby2ZUyqQ/wCsZ8IrGQ4DLg9fXj69queNYHkltmTc58mYGIAglN8RZ1cY5Bx8vpnHegAAzPB0TrqkryMrOLaRHKfcy0kTqAoAVSoB3YwvTGas EIZPtXmD/VxQm3bD5O47JQT3cY 63bJwBQAAe10UAAHN65pSatYyQkfvVDPbtuK7JghCkkfw84YenuK6SgAA888L61JfJJY3g2XtkPLky24yhflL8ksXUgCTkjJDA84HL MtCnWRtaspHSSJU81U3CTC/L5qsnPyrjd0woJzQAAe115/wCHPE9vrUaxSMkV2vDRbuJNoyXi6ZHBJXquD2oAAPQKKAAAooAAPjDUo9moXqCMhVuZlBXttmYfLngdhx9at6qXTVdS4DKbu5 VhuTmZ vI2njjPWgAA p9Ez/ZWn54P2S3/wDRS/5NZ/hhmOi2O4EFYyuDn B2Xv8ATjt6UAAHW0UAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAef8Aie2lmW3eMA7fMH8RYZ2vmNRndIyoyKO 6r3iNphbRLAheWSZUTp8nBYyZPQqqnH1NAABj H4I4rgmGO4jTZIGErZwWMbAKNg X72N3zLjA4qTw25Lunms xX8xW3uysXyqmXeyNwSR/Fg4HAoAAPRqKAAAooAAIpI0mjeORQ6OpVlPRlYYIPsQealoAAPlTXfDVz4dk 0xF5IA4MNwjFZIWzld AMMp6MMA8dDxX01fWUOo2strOCY5Vw2DgjBBBB55VgCO3HegAA8U0n4hbVWPUoWc9PPhC5IwOXi4Gc5JKEf7teUazpk2lXk1s6sqrITFu/jjJOx1PRgVHJ7NkHBBoAAPrG31/SbpN8d/a4xk7pFjYDOMskm11/EV8XA4Oev1oAAOhub2K5vbqUq5SeeWQfPggPIzBWHCn7xz lc/jd6cD19/egAA v/Cg26JZDfvwsgzz2mf5QT1C/dB9BU/hmJ4dE09ZDljAH6/wyEuo7dFYCgAA6yigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAADmteIFg5JgBDIR58nlR8NkgtyeVB4A56Vf1OMS2kgIUgbWIYkAhWBI4yegOKAADA0OCONnkDDc442fdeP5WBdQoTcpYgOPvBq0tMt1gaUKE2g4VlGDn LjJx1VTt4JGcUAAHR0UAABRQAAFFAAAUUAAHPazo8Gt2htpiU5DLIoUsjDuNwPHr0yK6GgAA apPh7qauyxy2jpuOx2eRDjsWXymwSOwZvrX0rQAAfIsXhbWnuXgWxb5cqXdQsPoWWVsBvUbSTX11QAAVLW3W0t4bdCSsMSRqW6kIoUE8DnA5q3QAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAAFO6XdBKMbsqeCBz7cgjmrTDIP0oAAMyxiSOMGM4DZYqDkbmwd3OW6dPrTbGNo1w0bRYJ4LK2dwBJynDemWGeuOKAADXooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACqd1IYYXlAZvLG/aoyzBeSoUZyWGQKAAC5UcbrKodDlWGQR/n86AACSigAAKKAACrA 7fyTh2XnGRg9OMfh3p8cfl7sEkFieecZ6j88nn1oAAJ6KAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAAPM9D1Ge0v59HvkZG8yR7N9vyPDy zcv8As/MpP 0rEMMVt6zoMWpvHcq0sdzApEbRyGLd1Kq7LlgFYkjbt6mgAA7GuC0/VbqyjS31ZW85I8tOiExvtUHG7JLybDlyq7chqAADva5U61HNlLdW3/LzINgALMpPf7pXkHb95fWgAA6SNtwJxj5mH5MRn8cZrOsWmYN5nTqpAXBLEltpGcjJ4zzQAAa9FAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAAFFAAAUUAABRQAARuiuMMoYe49Rg/oSDUlAABhy6Vay5wHiJYNuidkPUEjjjDYwfbpitygAAaAF6AD6U6gAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAAooAACigAAKKAAD/2Q=='/>'''# 邮件主题body = { 'subject': "自动化测试报告添加附件", # 邮件标题 "content_html": html, # html格式 "attachments": "123.jpg" # 附件}# 收件人receivers = '821006052@qq.com'# 发送邮件server.send_mail(receivers,body)

(左右滑动查看完整代码)

通过制定代码后发现,邮件已经成功发送且携带了附件内容。

yagmail

yagmail也是属于Python发送邮件的一个库,这种库相比前面两种依旧做了很大的简介,使用更加方便,因为属于Python的第三方库,我们安装。

安装:

pip install yagmail

(左右滑动查看完整代码)

发送文本

这里一样先将yagmail创建一个服务对象,通过将发件人的账号,授权码进行连接登录。

import yagmail# 发件人username = 'xxxxxx@163.com'# 授权码密码password = 'xxxxxx'# 创建yagmail服务,需要加上服务器地址server = yagmail.SMTP(username,password, host='smtp.163.com')# 收件人receivers = '821006052@qq.com'text = '这是测试报告内容' # 报告内容title = '自动化测试报告' # 邮件标题server.send(contents=text,to=receivers,subject=title)

(左右滑动查看完整代码)

通过发现yagmail的代码比zmail的代码更加简洁了一些,但是整体内容是差不多的。执行代码,发现我们已经将其报告发送成功了。

图片发送

yagmail中携带了发送图片的方法,直接将图片路径方进入就可以了,其中这里需要使用yagmai.inline的方法将图片添加到正文中:

import yagmail# 发件人username = 'xxxx@163.com'# 授权码密码password = 'xxxxx'# 创建yagmail服务,需要加上服务器地址server = yagmail.SMTP(username,password, host='smtp.163.com')# 收件人receivers = '821006052@qq.com'text = '这是测试报告内容加上图片显示内容' # 报告内容title = '自动化测试报告携带图片' # 邮件标题img = yagmail.inline('123.jpg') # 图片地址server.send(contents=text,to=receivers,subject=title,attachments=img)

(左右滑动查看完整代码)

执行代码发现,我们已经成功的将图片添加到了邮件中:

附件发送

附件形式yagmail中也提到了单独的方法,通过attachments的方法来添加附件文件。

import yagmail# 发件人username = 'xxxxxx@163.com'# 授权码密码password = 'xxxxx'# 创建yagmail服务,需要加上服务器地址server = yagmail.SMTP(username,password, host='smtp.163.com')# 收件人receivers = '821006052@qq.com'text = '这是测试报告内容加上附件内容' # 报告内容title = '自动化测试报告携带附件' # 邮件标题fujian = '123.jpg' # 附件server.send(contents=text,to=receivers,subject=title, attachments=fujian)

(左右滑动查看完整代码)

通过执行代码发现,我们已经成功的将邮件携带附件发送成功了。

实战演示

前面已经将Python几种发送报告的库都做了一个简单的介绍,安静在这里在给大家通过UnitTest生成一份测试报告,然后在通过邮件的形式发送出去来进行演示,方便大家记忆。

古话说,好记性不如烂笔头,脑子笨,咱多写几遍,就记住了。

UnitTest生成报告并发送报告

安静随便写几个测试用例,然后通过HTMLTestRunner的方式生成测试报告。

import unittestimport HTMLTestRunnerclass Test(unittest.TestCase): def test_01(self): print('测试用例1') def test_02(self): print('测试用例2') def test_03(self): print('测试用例3')if __name__ == '__main__': # 测试报告地址 fp = open('result.html', "wb") # 报告详情 runner = HTMLTestRunner.HTMLTestRunner(stream=fp, title=u'自动化测试报告,测试结果如下:', description=u'用例执行情况:') # 实例化 testunit = unittest.TestSuite() # 加载用例 testunit.addTests(unittest.TestLoader().loadTestsFromTestCase(Test)) # 执行用例 runner.run(testunit) # 关闭报告 fp.close()

(左右滑动查看完整代码)

通过执行代码发现测试报告已经生成了,接下来我们需要通过将其测试报告内容添加到邮件中然后在进行发送。

邮件加入测试报告结果

上面已经通过UnitTest单元测试框架生成了测试报告,接下来就是需要我们通过邮件库来进行发送了,安静这里选择了yagmail,别问为什么,想用哪个就用了。

import yagmail# 发件人username = 'xxxxxx@163.com'# 授权码密码password = 'xxxxxx'# 创建yagmail服务,需要加上服务器地址server = yagmail.SMTP(username,password, host='smtp.163.com')# 收件人receivers = '821006052@qq.com'with open('result.html', 'rb')as f: text = f.read()title = '自动化测试结果' # 邮件标题fujian = r'E:webresult.html' # 附件server.send(contents=text.decode('utf-8'), to=receivers, subject=title,attachments=fujian)

(左右滑动查看完整代码)

通过执行代码后发现测试报告内容已经成功发送了(这里有个问题就是排版可能发生了一些改变),但是整体的报告内容以及附件全部都发送了。

总结

安静分别简单的介绍了Python发送邮件的方法,其中有简单的,也有复杂操作的,但是据图使用哪种就要看个人的喜好了。

spark与spring集成做web接口

需要实现的功能:

写访问spark的接口,也就是从web上输入网址就能把我们需要的信息通过提交一个job然后返回给我们json数据。

成果展示:

通过url请求,然后的到一个wordcount的json结果(借助的是谷歌浏览器postman插件显示的,直接在浏览器上输入网址是一样的效果)

使用的关键技术:

java语言编程,springmvc框架,tomcat容器,spark框架,scala相关依赖

成体架构:

我使用的是maven构建的一个web工程,pom文件如下:

<dependencies>

<!-- https://mvnrepository.com/artifact/junit/junit -->

<dependency>

<groupId>junit</groupId>

<artifactId>junit</artifactId>

<version>4.12</version>

<scope>test</scope>

</dependency>

<!-- https://mvnrepository.com/artifact/org.apache.spark/spark-core_2.11 -->

<dependency>

<groupId>org.apache.spark</groupId>

<artifactId>spark-core_2.11</artifactId>

<version>1.6.3</version>

</dependency>

<!-- https://mvnrepository.com/artifact/org.apache.spark/spark-sql_2.11 -->

<dependency>

<groupId>org.apache.spark</groupId>

<artifactId>spark-sql_2.11</artifactId>

<version>1.6.3</version>

</dependency>

<!-- https://mvnrepository.com/artifact/org.scala-lang/scala-library -->

<dependency>

<groupId>org.scala-lang</groupId>

<artifactId>scala-library</artifactId>

<version>2.11.11</version>

</dependency>

<!-- https://mvnrepository.com/artifact/org.scala-lang/scala-reflect -->

<dependency>

<groupId>org.scala-lang</groupId>

<artifactId>scala-reflect</artifactId>

<version>2.11.11</version>

</dependency>

<!-- https://mvnrepository.com/artifact/org.scala-lang/scala-compiler -->

<dependency>

<groupId>org.scala-lang</groupId>

<artifactId>scala-compiler</artifactId>

<version>2.11.11</version>

</dependency>

<!-- spring框架的相关jar包 -->

<dependency>

<groupId>org.springframework</groupId>

<artifactId>spring-context</artifactId>

<version>4.3.4.RELEASE</version>

</dependency>

<!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->

<dependency>

<groupId>org.springframework</groupId>

<artifactId>spring-jdbc</artifactId>

<version>4.3.4.RELEASE</version>

</dependency>

<!-- https://mvnrepository.com/artifact/org.springframework/spring-web -->

<dependency>

<groupId>org.springframework</groupId>

<artifactId>spring-web</artifactId>

<version>4.3.4.RELEASE</version>

</dependency>

<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->

<dependency>

<groupId>org.springframework</groupId>

<artifactId>spring-webmvc</artifactId>

<version>4.3.4.RELEASE</version>

</dependency>

<!--添加持久层框架(mybatise)-->

<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->

<dependency>

<groupId>org.mybatis</groupId>

<artifactId>mybatis</artifactId>

<version>3.4.1</version>

</dependency>

<!--mybatise和spring整合包-->

<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring -->

<dependency>

<groupId>org.mybatis</groupId>

<artifactId>mybatis-spring</artifactId>

<version>1.3.0</version>

</dependency>

<!-- -->

<dependency>

<groupId>commons-DBCP</groupId>

<artifactId>commons-DBCP</artifactId>

<version>1.4</version>

</dependency>

<dependency>

<groupId>org.aspectj</groupId>

<artifactId>aspectjweaver</artifactId>

<version>1.8.9</version>

</dependency>

<!--添加连接池的jar包-->

<!-- https://mvnrepository.com/artifact/com.alibaba/druid -->

<dependency>

<groupId>com.alibaba</groupId>

<artifactId>druid</artifactId>

<version>1.0.18</version>

</dependency>

<!--添加数据库驱动-->

<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->

<dependency>

<groupId>mysql</groupId>

<artifactId>mysql-connector-java</artifactId>

<version>5.1.39</version>

</dependency>

<!-- 日志处理 -->

<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-api -->

<dependency>

<groupId>org.slf4j</groupId>

<artifactId>slf4j-api</artifactId>

<version>1.7.21</version>

</dependency>

<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-log4j12 -->

<dependency>

<groupId>org.slf4j</groupId>

<artifactId>slf4j-log4j12</artifactId>

<version>1.7.21</version>

</dependency>

<!-- https://mvnrepository.com/artifact/log4j/log4j -->

<dependency>

<groupId>log4j</groupId>

<artifactId>log4j</artifactId>

<version>1.2.17</version>

</dependency>

<!--json相关的依赖,不要使用jackson的依赖-->

<dependency>

<groupId>net.sf.json-lib</groupId>

<artifactId>json-lib</artifactId>

<version>2.4</version>

<classifier>jdk15</classifier>

</dependency>

</dependencies>

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

web.xml的配置(这里只配置了springmvc容器)

<?xml version="1.0" encoding="UTF-8"?>

<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">

<display-name>Archetype Created Web Application</display-name>

<!-- springmvc的前端控制器 -->

<servlet>

<servlet-name>manager</servlet-name>

<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

<!-- contextConfigLocation不是必须的, 如果不配置contextConfigLocation, springmvc的配置文件默认在:WEB-INF/servlet的name "-servlet.xml" -->

<init-param>

<param-name>contextConfigLocation</param-name>

<param-value>classpath:springmvc.xml</param-value>

</init-param>

<load-on-startup>1</load-on-startup>

</servlet>

<servlet-mapping>

<servlet-name>manager</servlet-name>

<url-pattern>/</url-pattern>

</servlet-mapping>

<!-- 解决post乱码 -->

<filter>

<filter-name>CharacterEncodingFilter</filter-name>

<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>

<init-param>

<param-name>encoding</param-name>

<param-value>utf-8</param-value>

</init-param>

</filter>

<filter-mapping>

<filter-name>CharacterEncodingFilter</filter-name>

<url-pattern>/*</url-pattern>

</filter-mapping>

<!-- 日志配置 -->

<context-param>

<param-name>log4jConfigLocation</param-name>

<param-value>classpath:log4j.properties</param-value>

</context-param>

<listener>

<listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>

</listener>

</web-app>

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

然后就是springMVC的配置文件

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"

xmlns:context="http://www.springframework.org/schema/context"

xmlns:mvc="http://www.springframework.org/schema/mvc"

xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd

http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd

http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

<!-- 配置包扫描器 -->

<context:component-scan base-package="com.zzrenfeng.zhsx.controller" />

<!-- 配置注解驱动 -->

<mvc:annotation-driven />

<context:component-scan base-package="com.zzrenfeng.zhsx.service"></context:component-scan>

<context:component-scan base-package="com.zzrenfeng.zhsx.spark.service"></context:component-scan>

<context:component-scan base-package="com.zzrenfeng.zhsx.spark.conf"></context:component-scan>

</beans>

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

配置文件就就没有了,如果有需要可以再去集成其他的,下面进入编码的介绍

对象和json相互转换的工具类:

(为什么使用手动的去转换,而没有使用jackson的相关依赖进行自动转换,是我在使用的时候发现使用jackson会对咱们的spark作业有影响,spark作业会异常终止掉)

package com.zzrenfeng.zhsx.util;

import java.lang.reflect.Field;

import java.util.ArrayList;

import java.util.HashMap;

import java.util.Iterator;

import java.util.List;

import java.util.Map;

import java.util.Set;

import net.sf.json.JSONArray;

import net.sf.json.JSONObject;

import net.sf.json.JsonConfig;

/**

* Json与javaBean之间的转换工具类

*

* @author

* @version

*

* {@code 现使用json-lib组件实现

* 需要

* json-lib-2.4-jdk15.jar

* ezmorph-1.0.6.jar

* commons-collections-3.1.jar

* commons-lang-2.0.jar

* 支持

* }

*/

public class JsonUtil {

/**

* 从一个JSON 对象字符格式中得到一个java对象

*

* @param jsonString

* @param beanCalss

* @return

*/

@SuppressWarnings("unchecked")

public static <T> T jsonToBean(String jsonString, Class<T> beanCalss) {

JSONObject jsonObject = JSONObject.fromObject(jsonString);

T bean = (T) JSONObject.toBean(jsonObject, beanCalss);

return bean;

}

/**

* 将java对象转换成json字符串

*

* @param bean

* @return

*/

public static String beanToJson(Object bean) {

JSONObject json = JSONObject.fromObject(bean);

return json.toString();

}

/**

* 将java对象转换成json字符串

*

* @param bean

* @return

*/

public static String beanToJson(Object bean, String[] _nory_changes, boolean nory) {

JSONObject json = null;

if(nory){//转换_nory_changes里的属性

Field[] fields = bean.getClass().getDeclaredFields();

String str = "";

for(Field field : fields){

// System.out.println(field.getName());

str =(":" field.getName());

}

fields = bean.getClass().getSuperclass().getDeclaredFields();

for(Field field : fields){

// System.out.println(field.getName());

str =(":" field.getName());

}

str =":";

for(String s : _nory_changes){

str = str.replace(":" s ":", ":");

}

json = JSONObject.fromObject(bean,configJson(str.split(":")));

}else{//转换除了_nory_changes里的属性

json = JSONObject.fromObject(bean,configJson(_nory_changes));

}

return json.toString();

}

private static JsonConfig configJson(String[] excludes) {

JsonConfig jsonConfig = new JsonConfig();

jsonConfig.setExcludes(excludes);

//

jsonConfig.setIgnoreDefaultExcludes(false);

//

// jsonConfig.setCycleDetectionStrategy(CycleDetectionStrategy.LENIENT);

// jsonConfig.registerJsonValueProcessor(Date.class,

//

// new DateJsonValueProcessor(datePattern));

return jsonConfig;

}

/**

* 将java对象List集合转换成json字符串

* @param beans

* @return

*/

@SuppressWarnings("unchecked")

public static String beanListToJson(List beans) {

StringBuffer rest = new StringBuffer();

rest.append("[");

int size = beans.size();

for (int i = 0; i < size; i ) {

rest.append(beanToJson(beans.get(i)) ((i<size-1)?",":""));

}

rest.append("]");

return rest.toString();

}

/**

*

* @param beans

* @param _no_changes

* @return

*/

@SuppressWarnings("unchecked")

public static String beanListToJson(List beans, String[] _nory_changes, boolean nory) {

StringBuffer rest = new StringBuffer();

rest.append("[");

int size = beans.size();

for (int i = 0; i < size; i ) {

try{

rest.append(beanToJson(beans.get(i),_nory_changes,nory));

if(i<size-1){

rest.append(",");

}

}catch(Exception e){

e.printStackTrace();

}

}

rest.append("]");

return rest.toString();

}

/**

* 从json HASH表达式中获取一个map,改map支持嵌套功能

*

* @param jsonString

* @return

*/

@SuppressWarnings({ "unchecked" })

public static Map jsonToMap(String jsonString) {

JSONObject jsonObject = JSONObject.fromObject(jsonString);

Iterator keyIter = jsonObject.keys();

String key;

Object value;

Map valueMap = new HashMap();

while (keyIter.hasNext()) {

key = (String) keyIter.next();

value = jsonObject.get(key).toString();

valueMap.put(key, value);

}

return valueMap;

}

/**

* map集合转换成json格式数据

* @param map

* @return

*/

public static String mapToJson(Map<String, ?> map, String[] _nory_changes, boolean nory){

String s_json = "{";

Set<String> key = map.keySet();

for (Iterator<?> it = key.iterator(); it.hasNext();) {

String s = (String) it.next();

if(map.get(s) == null){

}else if(map.get(s) instanceof List<?>){

s_json =(s ":" JsonUtil.beanListToJson((List<?>)map.get(s), _nory_changes, nory));

}else{

JSONObject json = JSONObject.fromObject(map);

s_json = (s ":" json.toString());;

}

if(it.hasNext()){

s_json =",";

}

}

s_json ="}";

return s_json;

}

/**

* 从json数组中得到相应java数组

*

* @param jsonString

* @return

*/

public static Object[] jsonToObjectArray(String jsonString) {

JSONArray jsonArray = JSONArray.fromObject(jsonString);

return jsonArray.toArray();

}

public static String listToJson(List<?> list) {

JSONArray jsonArray = JSONArray.fromObject(list);

return jsonArray.toString();

}

/**

* 从json对象集合表达式中得到一个java对象列表

*

* @param jsonString

* @param beanClass

* @return

*/

@SuppressWarnings("unchecked")

public static <T> List<T> jsonToBeanList(String jsonString, Class<T> beanClass) {

JSONArray jsonArray = JSONArray.fromObject(jsonString);

JSONObject jsonObject;

T bean;

int size = jsonArray.size();

List<T> list = new ArrayList<T>(size);

for (int i = 0; i < size; i ) {

jsonObject = jsonArray.getJSONObject(i);

bean = (T) JSONObject.toBean(jsonObject, beanClass);

list.add(bean);

}

return list;

}

/**

* 从json数组中解析出java字符串数组

*

* @param jsonString

* @return

*/

public static String[] jsonToStringArray(String jsonString) {

JSONArray jsonArray = JSONArray.fromObject(jsonString);

String[] stringArray = new String[jsonArray.size()];

int size = jsonArray.size();

for (int i = 0; i < size; i ) {

stringArray[i] = jsonArray.getString(i);

}

return stringArray;

}

/**

* 从json数组中解析出javaLong型对象数组

*

* @param jsonString

* @return

*/

public static Long[] jsonToLongArray(String jsonString) {

JSONArray jsonArray = JSONArray.fromObject(jsonString);

int size = jsonArray.size();

Long[] longArray = new Long[size];

for (int i = 0; i < size; i ) {

longArray[i] = jsonArray.getLong(i);

}

return longArray;

}

/**

* 从json数组中解析出java Integer型对象数组

*

* @param jsonString

* @return

*/

public static Integer[] jsonToIntegerArray(String jsonString) {

JSONArray jsonArray = JSONArray.fromObject(jsonString);

int size = jsonArray.size();

Integer[] integerArray = new Integer[size];

for (int i = 0; i < size; i ) {

integerArray[i] = jsonArray.getInt(i);

}

return integerArray;

}

/**

* 从json数组中解析出java Double型对象数组

*

* @param jsonString

* @return

*/

public static Double[] jsonToDoubleArray(String jsonString) {

JSONArray jsonArray = JSONArray.fromObject(jsonString);

int size = jsonArray.size();

Double[] doubleArray = new Double[size];

for (int i = 0; i < size; i ) {

doubleArray[i] = jsonArray.getDouble(i);

}

return doubleArray;

}

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

208

209

210

211

212

213

214

215

216

217

218

219

220

221

222

223

224

225

226

227

228

229

230

231

232

233

234

235

236

237

238

239

240

241

242

243

244

245

246

247

248

249

250

251

252

253

254

255

256

257

258

259

260

261

262

263

264

265

266

267

268

269

270

271

272

273

274

275

276

277

278

279

280

281

282

283

284

285

286

287

288

289

290

291

292

293

294

295

296

297

298

299

300

301

302

303

304

305

306

307

308

309

310

311

312

313

314

315

316

317

318

319

320

321

322

323

324

325

326

327

328

329

330

331

332

333

334

335

336

337

338

339

340

341

342

343

344

345

346

347

348

349

350

351

352

353

354

355

356

357

358

359

360

361

362

363

364

365

366

367

368

369

370

371

372

373

374

375

376

377

378

379

380

381

spark的工具类:(主要负责sparkcontext的初始化工作)

package com.zzrenfeng.zhsx.spark.conf;

import java.io.Serializable;

import org.apache.spark.SparkConf;

import org.apache.spark.api.java.JavaSparkContext;

import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;

import org.springframework.stereotype.Component;

@Component

public class ApplicationConfiguration implements Serializable{

private static final long serialVersionUID = 1L;

public SparkConf sparkconf(){

SparkConf conf = new SparkConf()

.setMaster("local[*]")

.setAppName("wc");

return conf;

}

public JavaSparkContext javaSparkContext(){

return new JavaSparkContext(sparkconf());

}

public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {

return new PropertySourcesPlaceholderConfigurer();

}

public String filePath(){

return "E:测试文件nlog.txt";

}

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

wordcount model类(对wordcount进行封装)

package com.zzrenfeng.zhsx.spark.domain;

import scala.Serializable;

public class WordCount implements Serializable{

/**

*

*/

private static final long serialVersionUID = 1L;

private String word;

private Integer count;

public WordCount(){}

public WordCount(String v1, int l) {

word = v1;

count = l;

}

public String getWord() {

return word;

}

public void setWord(String word) {

this.word = word;

}

public int getCount() {

return count;

}

public void setCount(int count) {

this.count = count;

}

@Override

public String toString() {

return "WordCount [word=" word ", count=" count "]";

}

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

spark service类,主要是负责spark word count的job任务逻辑

package com.zzrenfeng.zhsx.spark.service;

import java.util.Arrays;

import java.util.List;

import org.apache.spark.api.java.JavaPairRDD;

import org.apache.spark.api.java.JavaRDD;

import org.apache.spark.api.java.JavaSparkContext;

import org.apache.spark.api.java.function.FlatMapFunction;

import org.apache.spark.api.java.function.Function;

import org.apache.spark.api.java.function.Function2;

import org.apache.spark.api.java.function.PairFunction;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Component;

import scala.Tuple2;

import com.zzrenfeng.zhsx.spark.conf.ApplicationConfiguration;

import com.zzrenfeng.zhsx.spark.domain.WordCount;

@Component

public class SparkServiceTest implements java.io.Serializable{

@Autowired

ApplicationConfiguration applicationConfiguration;

public List<WordCount> doWordCount(){

JavaSparkContext javaSparkContext = applicationConfiguration.javaSparkContext();

System.out.println(javaSparkContext);

JavaRDD<String> file = javaSparkContext.textFile(applicationConfiguration.filePath());

JavaRDD<String> worlds = file.flatMap(new FlatMapFunction<String, String>() {

@Override

public Iterable<String> call(String t) throws Exception {

// TODO Auto-generated method stub

List<String> list = Arrays.asList(t.split(" "));

return list;

}

});

JavaRDD<WordCount> wordcount = worlds.map(new Function<String, WordCount>() {

@Override

public WordCount call(String v1) throws Exception {

return new WordCount(v1,1);

}

});

JavaPairRDD<String, Integer> pairwordCount = wordcount.mapToPair(new PairFunction<WordCount, String, Integer>() {

@Override

public Tuple2<String, Integer> call(WordCount t) throws Exception {

// TODO Auto-generated method stub

return new Tuple2<>(t.getWord() , new Integer(t.getCount()));

}

});

JavaPairRDD<String, Integer> worldCounts = pairwordCount.reduceByKey(new Function2<Integer, Integer, Integer>() {

@Override

public Integer call(Integer v1, Integer v2) throws Exception {

// TODO Auto-generated method stub

return v1 v2;

}

});

JavaRDD result = worldCounts.map(new Function<Tuple2<String,Integer>, WordCount>() {

@Override

public WordCount call(Tuple2<String, Integer> v1) throws Exception {

// TODO Auto-generated method stub

return new WordCount(v1._1,v1._2);

}

});

List<WordCount> list = result.collect();

javaSparkContext.close();

System.out.println(list.toString());

return list;

}

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

controller层,主要负责请求的拦截

package com.zzrenfeng.zhsx.controller;

import java.util.ArrayList;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Controller;

import org.springframework.ui.Model;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RequestMethod;

import org.springframework.web.bind.annotation.ResponseBody;

import com.zzrenfeng.zhsx.spark.domain.WordCount;

import com.zzrenfeng.zhsx.spark.service.SparkServiceTest;

import com.zzrenfeng.zhsx.util.JsonUtil;

@Controller

@RequestMapping("hello")

public class ControllerTest {

@Autowired

private SparkServiceTest sparkServiceTest;

@RequestMapping("wc")

@ResponseBody

public String wordCount(){

List<WordCount> list = sparkServiceTest.doWordCount();

return JsonUtil.listToJson(list);

}

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

进行启动,然后在浏览器上输入上面的拦截的url就可以看到开始出现的结果了。

应为这是个web接口,所以可以从各个端去调用,甚至可以用其他语言去调用。

现在可以愉快的去撸spark代码了,也许有人会问spark不应该用scala开发更好吗?

个人认为如果是纯粹的数据处理可以使用scala,编写起来太爽了,但是跟其他的集成的时候最好还是用java,毕竟有问题了还可以跟java大牛去讨论讨论。

欢迎有兴趣的一起来探讨

免责声明:本文由用户上传,如有侵权请联系删除!