消息传递机制(共4篇)
消息传递机制 篇1
一、消息的概念
对于一个win32程序来说消息的整个系统是非常重要的,程序的运行必须是在消息传递的前提下完成。消息从本质上说是系统确定的32位数值,根据它的唯一性确定事件,通过指令的形式告诉Windows程序已经发生。消息是以记录的形式发送给应用程序的,记录中不仅包括消息的类型,而且还包括的其它信息。
通常情况下,消息是由应用程序或者系统产生。应用程序产生消息使窗体执行任务,或者与其他应用程序中的窗口通讯。如果系统出现输入事件,它就会生成消息,比如说敲键盘,单击鼠标等都可以生成消息。系统也会生成消息,进而和应用程序的变化保持一致性,例如使用应用程序改变字体形式。
二、消息的发送和接收
1. 消息的发送
消息向窗口的发送形式分为三种:广播、寄送以及发送。被使用在消息发送过程的函数包括SendNotifyMessage、SendMessageCallback以及SendMessage等;被使用在消息寄送中的函数包括PostThreadMessage以及PostMessage等;被用在消息广播过程中的函数主要有:BroadcastSystemMessageEx和BroadcastSystemMessage。
(1)SendMessage函数
函数功能:这个函数可以把制定的消息传递给各个窗口。这个函数也是规定的窗口调用窗口程序,必须在窗口程序处理之后,消息才能够返回。
函数原型是LRESULT SendMessage,包括三个方面:,WPARAM wParam,UINT MsgLPARAM IParam,HWND hWnd。
(2)PostMessage函数
函数功能:这个函数把消息寄送或放入在规定窗口建立的线程相联系消息队列中,并不需要线程处理结束就可以返回消息。通过使用PeekMessage和GetMessage获取消息队列中的消息。
函数原型是B00L PostMessage,分为三个:WPARAM wParam,LPARAM lParam,UINT Msg,HWND hWnd。
2. 消息的接收
(1)GetMessage函数
函数功能:这个函数在调用线程的消息队列中选取一个消息,然后再储存在制定的结构中。这个函数可以获取和制定窗口相联系的消息,而且,这些消息也是PostThreadMesssge寄送的线程消息。这个函数可以获取某一范围内的消息值。GetMessage不可以获取属于其他应用程序或者线程的消息。
函数声明是BOOL GetMessage,主要包括UINT wMsgFilterMin以及LPMSG lpMsg等。
(2)PeekMessage函数
函数功能:这个函数是属于消息检查线程消息队列,而且把这个消息储存在相应的结构中。
函数原型,也就是BOOL PeekMessage,主要包括HWND hWnd,UINT wMSGfilterMin以及LPMSG IpMsg等。
(3)WaitMessage函数
函数功能:这个函数能够控制其他线程,当线程的消息队列中并不存在消息。这个函数将停止线程,当出现消息进入线程队列时,函数才返回。
函数原型,也就是BOOL WaitMessage。
三、消息处理
1. 窗口函数及其基本结构
窗口函数确定了在窗口显示区域内显示什么以及窗口怎样响应用户的输入。
传给窗口函数的message参数实际上是数值。为了方便编程在Windows头文件WINUSER.H中,为每一个消息定义了识别字,它们都是以“WM”(窗口消息)为自首的字符串。一般来说,Windows编程人员使用switch和case结构来确定窗口函数接受的消息并处理它。窗口函数处理完消息后,返回0。凡是窗口函数不予处理的消息传给名为DefWindowProc的Windows函数。从DefWindowProc返回的值再由窗口函数返回。在HELLOWIN中WndProc只选择处理三个消息:WM-CREATE、WM-PAINT和WM-DESTROY[2]。
2. 消息的处理方式
程序靠消息的流动而获得生命,而消息的处理方式是在窗口函数中借助switch/case结构对消息进行筛选和处理的,这也是windows编程最容易出错的地方。
为了简化switch/case的动作,也让程序代码的模块性更强,就将命令和命令处理函数关联起来,从而使窗口函数内容更模块化、更一般化。
(1)MFC消息处理的实现方式
MFC处理命令消息最基本、最关键的就是CCmdTarget类。MFC给这个类的设计带来了成员数据以及成员函数,其目的主要是处理消息映射问题,它能够生成很多的事件或消息类,比如:框架类、视图类以及控件类等。
(2)MFC消息映射的实现方法
MFC消息映射通过利用ClassWizard进而有效的完成消息映射过程。具体的,要在源码中加入消息映射数据,再得到消息处理函数。
一般来说,在进行类的定义时,其不仅带来了消息处理函数声明,而且也提供消息映射的宏,也就是DECLARE_MESSAGE_MAP。通过使用类的实现文件,完成消息处理过程,然后再利用IMPLEMENT_MESSAGE_MAP宏进行消息映射。通常情况下,在这一过程中使用的声明和实现都是通过MFC的ClassWizard进行维护的。
四、结束语
本文讨论了windows系统环境下的消息传递的各种机制,通过掌握windows系统环境下的消息发送和接收,这其中用到的消息发送函数有Sendmessage和PostMessage;用到的消息接收函数有GetMessage、PeekMessage和WaitMessage这其中存在的问题是这三种不同的消息发送和接收函数之间具体有什么更深的内在联系还需要进一步解决。窗口函数是消息处理的关键,整个消息处理的过程大部分都是由窗口函数来完成的,所以掌握窗口函数的基本结构也是比较重要的。用MFC所建立的代码是完全可移植的。程序员只要操作简单的数据对象的方法.便可实现消息传递。
摘要:在Windows系统中进行的程序编写是事件驱动,通过消息进行传递。因此,只有深入了解消息传递机制才能够完成Windows系统中程序编写,笔者根据自己对消息传递以及相关资料来分析消息传递机制。让大家大致知道消息的传递方向,再解释消息传递机制。消息传递机制主要包括的内容是消息的定义、消息的发送、消息和接收、消息的处理以及消息的处理中与之相关的窗口函数。
关键词:消息,消息发送和接收,消息处理,窗口函数,MFC消息
参考文献
[1]姜晓铭《Visual C++6.0程序设计》北京工业大学出版社2002.5。
[2]张正秋《windows应用程序捆绑核心编程》清华大学出版社2006.12。
[3]刘振安《Windows可视化程序设计》机械工业出版社2007.1。
消息传递机制 篇2
2007年,Google公司发布基于Linux内核的手机操作系统Android[1],该系统主要应用于智能手机、平板电脑、智能电视等产品。据全球著名调查研究机构Strategy Analytics发布的数据显示,2014 年第二季度Android系统占据全球智能手机市场份额84.6%[2]。Android操作系统凭借其开源、免费等特点,受到程序开发者的热烈欢迎。作为程序开发人员,掌握Android平台下手机软件的开发技术是移动互联网时代的要求。
Android应用程序由4 部分组成,分别是Activity、Content Provider、Service和Broadcast Receiver[3]。Activ-ity(活动、页面)是Android程序与用户交互的界面,是应用的“眼睛”;Content Provider(内容共享器)用于应用程序之间共享数据的容器;Service(服务)没有对应的用户界面,在后台运行,是应用的“手”;Broadcast Receiver(广播接收器)是应用的“耳朵”,接收系统或程序发送的消息,根据消息内容执行任务或反馈消息;如果Activity、Service、Broadcast Receiver这3个组件实现相互之间的通信,则需要使用Intent消息传递机制。
1 Intent机制分析
1.1 Intent机制简介
Intent封装了Android应用程序需要启动某个组件的意图,还可用于与被启动组件交换信息[4];通常情况下,一个Android应用程序中有多个Activity,普通程序开发者接触最多的就是Activity,因此本文主要介绍使用In-tent机制实现不同Activity之间的跳转,如表1所示。
1.2 使用Intent机制实现不同Actvity之间的跳转
使用Intent进行Activity之间的跳转时,后启动的Activity称为 “子Activity”,先启动的Activity称为 “父Activity”[4],分为以下3种类型:
(1)父Activity和子Activity之间不传递数据。
Intent intent=new Intent(FatherActivity.this,SonActivity.class);
startActivity(intent);
通过startActivity(Intent intent)方法启动Activity,启动后的两个Activity之间相互独立,没有任何关联。
(2)父Activity要向子Activity传递数据。很多情况下,先启动的Activity为了让用户对特定信息进行填写,在先启动的Activity关闭时,这些信息需要返回给后启动的Activity。
从当前的FatherActivity页面跳转到SonActivity页面后,使用getIntent()方法返回一个Intent对象;然后使用Intent对象调用getXXX方法获得FatherActivity页面传递的值;
SonActivity页面通过如下代码获得父Activity传递的内容;
(3)子Activity要向父Activity传递数据。某些情况下,后启动的Activity是为了让用户对特定信息进行选择,在后启动的Activity关闭时,这些信息需要返回给先启动的Activity。
以下代码位于父Activity页面中的方法:
以下代码位于子Activity页面返回方法:
2 设计与实现
Android开发环境搭建步骤:① 安装Java的运行环境;②安装Eclipse集成开发环境;③安装SDK套件,配置SDK安装路径;④ 通过USB线建立手机和电脑的连接,手机型号是Lenovo S880i,Android版本是4.0.4。
2.1 创建项目SontoFatherIntent
项目SontoFatherIntent的文件结构如图1所示,采用MVC设计模式[5,6],实现子页面向父页面传递用户名和密码信息,设计思路如下:
(1)父页面FatherActivity对应布局文件father_lay-out.xml;子页面SonActivity对应布局文件son_layout.xml。
(2)编写FatherActivity、SonActivity代码[6]。
(3)在AndroidManifest.xml文件中,注册父页面、子页面。
2.2 运行项目SontoFatherIntent
将项目运行在Lenovo S880i联想手机,点击“打开子页面”按钮,在子页面输入用户名“张三”和密码“123456”,如果点击“提交消息给父页面”按钮,则子页面关闭,并在父页面中显示“用户名是张三(换行)密码是123456”,如果点击“不提交消息给父页面”按钮,则子页面关闭,并在父页面中显示“没有从子页面返回任何信息”。
摘要:Android操作系统凭借其开源、可编程软件框架等特点受到编程人员的青睐。Android应用程序不同组件之间的通信采用Intent机制。重点介绍了使用Intent实现不同Activity组件间通信的3种类型。实验采用Eclipse开发环境,在联想手机Lenovo S880i演示了运行子Activity向父Activity传递数据的全部过程。
关键词:安卓操作系统,页面,父页面,子页面,Intent
参考文献
[1] 吴善崇,张权.Android平台安全机制浅析[J].实验科学与技术,2014,12(2):43-45.
[2] 李刚.疯狂Android讲义[M].北京:电子工业出版社,2011.
[3] 史书明.Android应用中消息传递方法分析[J].电脑知识与技术,2014,10(13):2984-3008.
[4] 黄艺峰,闫巧.基于Android平台电子词典的设计与实现[J].计算机应用,2011,31(2):228-232.
[5] 王涛.安卓系统消息传递方法研究[J].安阳工学院学报,2014,13(4):61-63.
消息传递机制 篇3
关键词:OMNeT++,INET,消息传递,协议扩展,数据封装
网络仿真是使用计算机技术构造拓扑结构,模拟网络协议的工作过程。网络仿真在设定网络特性参数,模拟网络流量的同时,能在网络的传输过程中对网络性能进行研究和分析。OMNe T++(Objective Modular Network Test Bed in C++)是开源的基于组件的模块化的开放网络仿真平台,是近年来在科学和工业领域里逐渐流行的一种优秀的网络仿真平台。OMNe T++是一种离散事件仿真器,具备强大完善的图形界面接口和可嵌入式仿真内核,OMNe T++可运行于多个操作系统平台,可以简便定义网络拓扑结构,具备编程、调试和跟踪支持等功能。
OMNe T++可以用于模拟通信网的业务流,通信协议的模型,排队网络以及多处理器和分布式系统。目前几乎所有的网络对象的基本模型之间的互连OM-Ne T++都能模仿,复杂的网络通信和拓扑结构都能得到高度切合实际的模拟和仿真。OMNe T++具有分层嵌入式模块,并且各模块以模块类型分类,模块之间通过在通道上传输信号来进行通信,同时它还具有灵活的模块参数及强大的拓扑描述语言。它是有效的描述实际系统结构的工具,和其他的仿真平台相比,它在表达模型的细节,定义网络拓扑结构、编程模型和调试跟踪等方面有极大的优势。
本文主要利用OMNe T++仿真平台,在分析INET模块的基础上,研究如何添加一个新的协议,为相关研究工作的进一步开展提供参考。
1 仿真建模过程及INET框架
OMNe T++仿真建模过程实际上是编译相关文件生成可执行文件的过程。首先,OMNe T++使用opp_msgc程序将msg文件转化成C++代码。然后编译所有的C++源文件,链接仿真内核和用户的接口库,形成一个仿真可执行文件。.NED文件可以使用Nedtool转化成C++文件进行链接,也可以在仿真程序开始执行时,原始的文本里动态加载。
INET是按照ISO的层次结构来组织源代码的,主要实现的源代码在/src目录下。INET框架为OM-Ne T++提供了Ethernet、ip、TCP、UDP和MPLS等功能,INET框架中的协议由简单模块表示,一个简单模块的外部接口由NED文件表示,具体实现在与NED文件同名的C++文件中实现。简单模块可使用NED语言自由组合用以表示网络中的主机及其他设备。在/src/node目录下的子目录中保存有预先设置好的主机、路由、交换机以及AP等网络设备。协议头以及数据包的组织形式主要在msg文件中描述,在模拟过程中可用opp_msgc工具转化成C++类文件。
在INET框架中,协议层间如需进行通信,则须按一定规则由消息传递的方式来进行操作。当一个上层协议要发一个数据包给一个下层协议时,上层协议通过向下层协议发送一个消息对象来模拟真实场景中发送数据包的过程,上层协议向下层协议封装并发送消息对象后,下层协议将上层协议发送的消息对象当成真实场景中的数据包接收,解开封装并回送。
在传输过程中,一般来说都需要在数据包中传递额外的信息。例如,当应用层模块需要通过TCP模块发送数据时,TCP模块需要连接标识符参数的值,当TCP模块发送报文(segment)给IP模块时,IP模块需要知道目标地址及TTL参数的值,当IP模块发送数据报(datagram)给以太网接口时,目标MAC地址需要在数据报中标出。这些额外的信息可以通过Control info附加在消息对象中。
Control info通过消息对象的c Message::set Control Info()成员函数来模拟数据包的附加信息。并且,Control info只能在相邻的协议层间传递附加信息,在网络之间通过host或路由器不能传递Control info。
2 协议间额外消息传输Control info类剖析
INET框架主要提供了IPControl Info,TCPCommand,UDPControl Info和Ieee802Ctrl这几个主要的Control info类。
如果要向IP层发送数据包,那么只要将IPControl Info对象中的数据设置好,并通过消息对象中的c Message::set Control Info()成员函数把IPControl Info对象附加到消息对象中。当IP层要向更高层发送数据包时,IP层也同样在消息对象上附加IPControl Info对象。INET框架中的IPControl Info类定义如下:
TCPCommand类用来为在TCP层和应用层之间传递的消息设置control info。conn Id用来标识应用与应用之间的本地连接,从内部看,TCP使用conn Id标识对来标识socket连接。TCPCommand类定义如下:
TCPConnect Info,TCPOpen Command,Tcp CommandCode,Tcp Status Ind,TCPStatus Info是TCPCommand类的子类。
TCPConnect Info子类的定义如下:TCPConnect Info对象发送TCP_I_ESTABLISHED类型的消息给各种应用,并给出本地及远程IP地址及端口。
TCPOpen Command子类也是INET框架提供的Control info,它用来开启主动或被动的TCP连接。local Addr,remote Addr,local Port,remote Port这几个参数可自动由协议来设置。local Addr参数是可选的,因为TCP协议可以从发送方发来的数据包获得local Addr参数的值。local Port参数也是可选的,因为TCP支持临时端口。send Queue Class,receive Queue Class和tcp Algorithm Class字段允许每次连接时作TCP设置。这些字段会分别包含TCPSend Queue,TCPReceive Queue和TCPAlgorithm子类名。Fork参数可用于开启被动的TCP连接,当接收到连接请求时,控制才开始起作用。当fork字段为true时,我们的连接模拟Unix操作系统中accept(2)syscall的语法,产生一个新的连接(新的conn Id),旧的连接(旧的conn Id)处于监听状态。当fork字段为false时,上面提到的操作将不会发生,TCP协议接收第一个连接(最初的conn Id),拒绝后面所有的连接并向发起连接的请求方发送RST报文(RST segment)。TCPOpen Command子类的定义如下
3 协议扩展
在深入了解OMNe T++的仿真模拟过程,INET框架的基本结构以及消息传递机制的基础上,我们可以考虑仿真模拟扩展新的协议。添加新协议首先要确定协议所处的ISO层次,从而决定源代码放置的位置。一个新的协议至少要包含四个文件:ned文件,msg文件,cc文件和h文件。ned文件用来定义新协议的模块,其中主要包括模块之间的连接门的定义和参数的设置等。在其他ned文件里可以使用新定义的协议模块。msg文件用来定义新协议的报文格式。在OMNe T++编译的时候,将会通过opp_msgc工具将此文件转换成**_m.cc和**_m.h文件。其中**为msg文件的文件名。
4 结论
OMNe T++是一种离散事件的仿真器,我们在分析它仿真过程的基础上,深入剖析了INET框架模拟数据包在各协议层间传递的机制与细节,并对Control info类进行了深入的研究,并简单论述了协议扩展的过程,为相关研究工作打下了坚实的基础。接下来,我们将力求利用OMNe T++实现对网络层协议扩展并进行仿真实验。
参考文献
[1]Varga A.OMNeT++simulation models[DB/OL].ht tp://www.om-netpp.org,2004.10.
[2]Varga A.ITPuite documentation[DB/OL].The INET Framework forOMNeT++,2005.03.
[3]Behrouz A F,Sophia C F.TCP/IP协议簇(第2版)[M].谢希仁译.北京:清华大学出版社,2004.
[4]COMER D E.用TCP/IP进行网际互连(卷一、卷二)[M].电子工业出版社,2000.
[5]Stevens W R.TCP/IP详解,卷一:协议[M].范建华,等译.北京:机械工业出版社,2000.
消息传递机制 篇4
即时消息传递(Instant Messaging,IM)是基于互联网协议的应用程序,它能够使应用不同类型设备的用户进行一对一的通信。IM最流行的形式是聊天,在聊天的同时可以在计算机之间交换短文本消息。
直接使用WinSock API函数来完成上述功能,不但要记忆很多的WinSock API函数调用格式,还要了解设计WinSock API网络编程的算法。对于编写Windows应用程序来说,还要涉及复杂的消息驱动机制,设计事件处理函数来处理套接字发送、接收数据等事件。
为了简化WinSock网络编程,使用户专注于应用程序算法的设计,Microsoft的基本类库(Microsoft Foundation Class或MFC)提供给Visual C++两个用于WinSock编程的类-CAsyncSocket和CSocket。这两个类在不同程度上对WinSock API函数进行了封装,在编程时使用经过封装的MFC WinSock类使编程工作大大简化,而且,这两个类都提供了事件处理函数,通过对事件处理函数进行重载,用户可以在应用程序中很方便地对套接字发送、接收数据等事件进行处理。
2. 有关定义
(1)套接字(socket)是对通信端点的一种抽象,一个正在被使用的套接字都有它的类型和与其相关的进程,提供了一种发送和接收数据的机制。
(2)Windows Sockets(Winsock)规范是一套网络编程接口,提供一套库函数调用和相关语义,是一个面向网络通信编程的API。应用程序调用Windows Sockets的API实现相互之间的通讯,Windows Sockets又利用下层的网络通讯协议功能和操作系统调用实现实际的通讯工作。
(3)MFC:Microsoft的基本类库(Microsoft Foundation Class或MFC)提供了两个用于WinSock编程的类-CAsyncSocket和CSocket。这两个类在不同程度上对WinSock API函数进行了封装。
3. 即时消息传递系统工作原理
即时消息传递系统的原理与打电话类似,当系统的一端正在等待另一端打开通信连接时,就像您在等待某人给您打电话时,一直在留心电话铃响。与此同时,另一端试图同第一端连接,这种方式就类似于向某人打电话。一旦两端间建立了连接,它们之间就可以互相发送和接收信息了,正像两个人打电话交谈一样。最后,如果一方或双方完成了对话,连接即被关闭,就像打完电话后把电话挂断一样。
4. 时消息传递系统工作流程
服务器要创建一个用于侦听的套接字,为该套接字分配地址之后,调用listen()函数使它处于侦听状态;客户机在创建套接字完毕后,为套接字分配地址,然后调用connect()函数,请求与服务器套接字连接;服务器套接字在收到客户机的连接请示后,调用accept()函数,该函数创建一个用于连接的套接字。应用该套接字和客户机上的连接套接字,用户就可以在服务器和客户机之间进行数据传输了。在结束传输之后,客户机调用closesocket()函数关闭套接字,服务器也调用该函数关闭用于侦听和连接的套接字。
5. 系统逻辑设计
5.1 用MFC AppWizard生成程序框架
在Visual C++的IDE环境下选择菜单File→New→Projects→MFC App Wizard(exe)→Project Name→“OK”→“NEXT”→Windows Sockets→“Finish”按钮,选择“OK”按钮,应用程序的框架就将自动创建。在创建了应用程序框架之后,可以布置程序的主对话框,向应用程序的主对话框添加控件。设计好对话框之后,选取View菜单中的ClassWizard菜单项,或直接按“Ctrl+W”,打开MFC ClassWizard,将对话框中的控件和变量相关联。
5.2 继承CAsync Socket类
选择Insert菜单中的New Class→选取Class type为Generic Class→在Base class的Derived From列中输入CAsyncSocket,→在As列中接受默认值public,点击“OK”按钮,就可以把这个新创建的类添加到应用程序中。
在该套接字类中添加一个成员变量,用作指向父对话框窗口的指针,指针变量的类型为CtalkDlg*(Cdialog的派生类),变量名为m-pDlg,访问权限为私有。最后,添加套接字类事件处理函数,这些函数将用于调用对话框中名称类似的那些函数。
5.3 建立连接
添加对套接字事件的处理函数,在对话框类中添加On Accept()事件处理函数和On Connect()事件处理函数。
现在可以编译和运行应用程序,启动两个副本,把其中一个设置为侦听模式,然后把另一个应用程序与之相连接。为此,先向对话框类()添加三个成员函数,这三个函数是套接字类()的事件处理函数需要调用的。把三个函数的类型都指定为void,访问权限为公共。指定第一个函数声明为On Send(),第二个函数的声明为On Receive,第三函数的声明为On Close。
5.4 发送和接收数据
两个应用程序间建立了连接,用户就能够在对话框窗口中的编辑框中输入文本消息,然后单击“发送”按钮,就应该可以把消息发送到另一个应用程序,一旦消息发送出去了,它将被添加到已发送消息的列表框中。
当“发送”按钮被单击之后,应用程序需要检查是否有消息输入了编辑框,获取该消息的长度,并发送该消息,然后把此消息添加到列表框中。为了在应用程序中添加此项功能,使用Class Wizard向“发送”按钮(ID:IDOK)的单击事件(BN-CLICKED)添加一个事件处理函数,注意不要接受默认的函数名,将函数名改成On Send Msg(),编辑该函数。
对于消息的接收方,当套接字的On Receive事件被触发时,表明一个消息已经到达了,可以用Receive()函数从套接字检索到该消息。如果消息被顺利检索到,需要把接收的字符数组转换成Cstring类型,并把接收的消息添加到已接收的消息的列表框中。通过编辑对话框类(CtalkDlg)的On Receive()函数。
5.5 终止连接
终止连接的操作后,应用程序会接收到一个On Close套接字事件,和建立连接的过程相反,连接的套接字需要断开,发送消息的控件需要置为禁用状态。在客户端,“连接”按钮控件由禁用状态变成可用,因为应用程序允许客户机程序改变某些参数,并打开与另一个服务器程序的连接。同时,服务器应用程序继续侦听是否有其他的连接请求,侦听的端口等信息不变。
6. 结束语
以上设计是基于客户/服务器模型的,一个服务器只能支持一个客户,因此它实际上是一个基于“点对点”模型。通过这个即时消息传递系统,用户可以在应用程序中很方便地对即时消息进行处理,而不必关心系统内部复杂的、抽象的源代码,极大地简化了程序设计,给一般程序设计人员提供了方便。
摘要:本文选择Visual C++开发工具,使用基于WinSock网络编程的类,对WinSock的API事件处理函数进行重载,用户可以在应用程序中很方便地对套接字发送、接收数据等事件进行处理,从而建立“点对点”即时消息传递模型。
关键词:IM模型,Winsock,MFC
参考文献
[1]Dreamtech软件研发组.即时消息传递系统编程源代码解析[M].姬孟洛译.北京:电子工业出版社,2007.