跳转到主要内容

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件.

当您初次登录到 developerWorks 时,将会为您创建一份概要信息。您在 developerWorks 概要信息中选择公开的信息将公开显示给其他人,但您可以随时修改这些信息的显示状态。您的姓名(除非选择隐藏)和昵称将和您在 developerWorks 发布的内容一同显示。

所有提交的信息确保安全。

  • 关闭 [x]

当您初次登录到 developerWorks 时,将会为您创建一份概要信息,您需要指定一个昵称。您的昵称将和您在 developerWorks 发布的内容显示在一起。

昵称长度在 3 至 31 个字符之间。 您的昵称在 developerWorks 社区中必须是唯一的,并且出于隐私保护的原因,不能是您的电子邮件地址。

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件.

所有提交的信息确保安全。

  • 关闭 [x]

利用 Cognos 进行数据挖掘

如何从 Cognos 中倒出数据供数据挖掘使用

袁辉, 软件工程师, IBM
袁辉的照片
袁辉,西北大学计算机系毕业,自 2009 年加入 IBM SPSS 以来,参与了 Modeler 与 Cognos 的集成开发。
杨家飞, 软件工程师, IBM
杨家飞的照片
杨家飞,IBM SPSS Modeler 软件工程师,主要关注 Cognos 以及 Entity Analytics。
张晓篱, 软件工程师, IBM
张晓篱
张晓篱,中国科学院毕业,2011 年加入 IBM,从事 Modeler 研发工作。

简介: 本文介绍了 Cognos 与数据挖掘 (Modeler) 的集成,通过实际案例介绍了整个集成的实现过程。

发布日期: 2011 年 10 月 20 日
级别: 中级
访问情况 : 1516 次浏览
评论: 


免费下载:IBM® Cognos® Express V9.5 或者 Cognos® 8 Business Intelligence Developer Edition V8.4 试用版
下载更多的 IBM 软件试用版,并加入 IBM 软件下载与技术交流群组,参与在线交流。

为什么数据挖掘能够跟 Cognos 集成

数据挖掘,就是对已有的数据运用统计学的算法,去除杂点数据,分析出数据中潜在的规律;而 Cognos 则主要是对已有的数据进行简单的建模后, 以各种样式的图形报表展示给企业的决策者,使得决策者根据基于历史数据展示的图形报表快速的做出决策;前者是对已有数据进行数据挖掘,后者是对已有数据的报表展示, 如果能够在向决策者展示报表之前对数据进行数据挖掘处理,则是非常有意义的,能够帮助决策者做出更加准确的决策。 Modeler 是 IMB SPSS 公司开发的一个数据挖掘软件,本文将以 Modeler 为例,来阐述如何实现 Modeler 跟 Cognos 的集成。


集成的整体架构


图 1. 实现该集成的整体架构
图片示例

在上图中,有四个模块:最上层的是 Modeler Server 层,是基于 c++ 语言实现的可运行于各个平台的一个服务程序,功能是对已有数据进行 数据挖掘运算;第四层是 Cognos Server;为了实现 Modeler 跟 Cognos 的集成,我们增加了 2 个模块,就是上图中的第二层和第三层,第三层是 一个由 Java 实现的 jar 包,通过与 Cognos Server 交互来实现此次集成所需要的所有与 Cognos Server 相关的功能;第二层则是由 c++ 语言 实现的一个动态库,通过 JNI 来调用第三层中实现的接口,供 Modeler Server 使用。可以看出,第二层和第三层就是连接 Modeler Server 跟 Cognos Server 交互的一个桥梁,通过第二层和第三层,Modeler Server 可以从 Cognos Server 中获得企业中已有的历史数据,然后对这些 数据进行数据挖掘处理,最后存储到 Cognos Server 中,Cognos Server 根据处理过的数据来生成报表,展示给企业的决策者,供其作出更加 准确的决策。


集成的实现

根据上面的描述,要实现 Modeler 跟 Cognos 的集成,我们只需要实现中间两层,即 CognosModule 跟 CognosDataManager。 第二层是简单的 JNI 调用 Java 接口的封装,在此不作深入介绍,本文将着重介绍第三层 CognosDataManager 的实现。

整个集成过程就是从 Cognos 中导出数据,供 Modeler 做数据挖掘处理,然后再将 Modeler 处理过的数据以 Package 的形式 publish 到 Cognos 中去, Cognos 可以基于此 Package 来生成报表,供决策者做出决策。所以整个集成过程分为两个阶段:第一阶段是从 Cognos 向 Modeler 导入数据 (import data),第二阶段是从 Modeler 向 Cognos 导出数据(export data)。

通过上面阐述,我们可以看出整个集成的过程实际上就是通过跟 Cognos Server 的交互,从 Cognos Server 中取出数据和向 Cognos Server 中写入数据的过程。要实现跟 Cognos Server 交互,我们需要使用 Cognos 提供的一组 jar 包,通过这些 Jar 包提 供的接口,我们可以轻松的跟 Cognos Server 交互。这些 jar 包可以从 Cognos 发布的 SDK 安装包中获得。所有用到的 Jar 包如下:

  • activation.jar
  • axis.jar
  • axisCognosClient.jar
  • commons-discovery.jar
  • commons-logging.jar
  • dom4j.jar
  • jaxen.jar
  • jaxrpc.jar
  • mail.jar
  • saaj.jar
  • wsdl4j-1.5.1.jar
  • xercesImpl.jar
  • xml-apis.jar

还有一个第三方 jar 包 castor-1.2.jar 在集成中也要用到。

这些 jar 包中,axisCognosClient.jar 提供了我们跟 Cognos Server 交互的所有接口,它依赖于其他所有的 jar 包。

Cognos Server 是以 Web Service 的方式向外提供服务,当我们调用 axisCognosClient.jar 中的接口跟 Cognos Server 通信时, 该 Jar 包负责将我们的输入转化成相应的 Web Service 请求发送给 Service, 然后将 Service 返回的应答在返回给我们,这样就完成了一次通信。

下面我们将分别阐述如何实现从 Cognos 向 Modeler 导入数据和从 Modeler 向 Cognos 导出数据。

1. Cognos 中的几个概念

在讨论集成之前,我们需要先了解以下 Cognos 中的几个概念:

  • Package:是 Cognos 中一个重要的概念,它是一个抽象的数据集对象,一个 Package 可以映射到一个数据库中的多个表上,用户可以通过 Package 获得这些数据库表中的数据。
  • Report:前面我们提到,一个公司的决策者总是希望看到自己所关注的某些历史数据的图形式报表展示,这个报表就是我们这里要说的 Report,Report 是基于 Package 设计 出来的,他包含了 Package 中所有或者部分数据映射(也就是决策者所关注的数据)
  • Report Specification:在 Cognos 中,每个 Report 对象都是以 XML 形式描述的,称之为 Report Specification。包含了两部分信息,一部分是 Query, 包含了该 Report 所映射到的在数据库中表和列的数据信息,通过这一部分,可以从数据库中查询出数据;另一部分是 Layout,用于对查询出的数据进行展示, 比如以饼状图、柱状图、表状等方式展示。

图 2. 使用浏览器访问 Cognos Server
图片示例

点击”IBM Cognos content”,进去后点击 Launch 下拉菜单,选择 Report Studio 菜单项来运行 Report Studio,如下图 :


图 3. 运行 Report Studio
图片示例

通过选择创建 Report 所依赖的 Package 后,选择”Create New”来基于此 Package 来创建一个新的 Report,如下图:


图 4. 创建一个 List 样式的 Report
图片示例

上图中,我们选择的是名为 TEST 的 pakcage,上图显示了 Cognos 所支持的 Report 的所有样式,这里我们选择 List 样式,来创建一个 List Report,如下图:


图 5. Package 的结构
图片示例

在上图左侧中,显示的是我们所选择的名为 TEST 的 package 的结构,最顶层的 TEST 表示 Package 名,第二层的 TEST 表示该 Package 下包含了一个名叫 TEST 的数据库表,称之为 Query Susbject( 当然一个 package 中可以包含多个数据库表的映射 ),TEST 下面的所有条目称之为 QueryItem,表示该表 中的所有列。然后我们将 TEST 表中的所有列选择到右边,这样就创建了一个包含数据库表 TEST 中所有列的一个 Report,运行该 Report 如下图:


图 6. 运行 Report
图片示例

因为之前我们选择 Report 的样式为 List 样式,所以运行结果将以列表形式显示该 Report 包含的所有列的所有数据,如下图:


图 7. Report 的运行结果
图片示例

点击图 5 中工具栏上的 XML 图标,可以查看该 Report 的 Report Specification,如下图(我将它拷贝到了 oXygen 工具中进行查看)。


图 8. Report Specification 示例
图片示例

在上图中,有五个红圈标注:第一个标注是 modelPath,表示的是该 Report 是基于哪个 Package 创建的;第二个标注是 Queries, 表示这部分是要从数据库中获取数据;第三个标注是 dateItem,表示的是数据库中的一列,根据它的 expression 属性可以看出他是 哪个数据库中的哪一列,比如 [CognosTest].[TEST].[Age],其中 CognosTest 是我们在 Cognos 中配置的 Data Source,表示一个数据 库连接,包含了数据库所在机器,数据库名,连接数据库的用户名密码等信息,这里只是通过引用该 Data Source 来访问数据库,TEST 表示 名为 TEST 的数据库表,Age 表示名为 Age 的数据库表中的列;第四个标注是 layouts,表示这些数据是以什么样的形式来展示给用户,第五个 标注是 List,表示这个 Report 将这些数据以一个 List 的方式展示给用户的。 Cognos 支持多种展示形式,包括自定义模板展示,如下图:


图 9. Cognos 数据展示格式
图片示例

2. 从 Cognos 向 Modeler 导入数据

从 Cognos 向 Modeler 导入数据,让 Modeler 对之进行数据挖掘和数据分析,需要实现以下几个部分的功能:

  • 连接 Cognos Server
  • 获得 Cognos Server 中所有的 Package
  • 获得用户选择的 Package 的 MetaData
  • 根据用户选择的 QueryItem,获得它们的存储类型,并且根据这些 QueryItem 来生成一个表状的 Report,通过 Report Service 提供的接口来 Render 此 List Report,从而得到一个二维表状数据。读取这些数据,供 Modeler 进行数据挖掘处理。

下面我们分别介绍这几部分的实现:

1) 连接 Cognos Server:

可以采用匿名或者指定的 credentials 来连接。如下图 :


图 10. 连接 Cognos Server
图片示例

在 Modeler 中,通过该 UI 获得用户连接 Cognos Server 的信息,这些信息包含了 2 部分内容,一部分是 Cognos Server 的 URL,用来 连接 Cognos Server,另一部分是 credentials,用来 LogonCognos Server,这些信息通过 Modeler Server 传递个图一中的第三层: CognosDataManger 层。所以该部分的实现包括两步:连接 Cognos Server 和 Logon Cognos Server. Cognos Server 是有 10 多个 Service 服务程序组成,每个 Service 服务负责不同的功能,在这个集成中,我们只使用到其中三种 Service 服 务,所以在连接是,我们只需要得到该三种 Service 服务:ContentManagerService、ReportService、MetadataService。


清单 1. 连接 Cognos Server
				
 public ContentManagerService_PortType connectToCognosServer(String CMURL) 
 { 
  // Create the service locators 
  cmServiceLocator = new ContentManagerService_ServiceLocator(); 		
  reportServiceLocator = new ReportService_ServiceLocator(); 		
  metadataServiceLocator = new MetadataService_ServiceLocator(); 		
  try 
  { 
    java.net.URL serverURL = new java.net.URL(CMURL); 
    //acquire references to services 
    cmService = cmServiceLocator.getcontentManagerService(serverURL); 
    repService = reportServiceLocator.getreportService(serverURL); 
    metadataService = metadataServiceLocator.getmetadataService(serverURL); 
    return cmService; 
  } 
  //handle uncaught exceptions 
  catch (MalformedURLException e) 
  { 
    System.out.println("Malformed URL:\n" + e.getMessage()); 
    return null; 
  } 
  catch (ServiceException e) 
  { 
    System.out.println("Service Exception:\n" + e.getMessage()); 
    return null; 
  } 
 } 
     


清单 2. Logon Cognos Server
				
 public void quickLogon( 
		 CRNConnect connection, 
		 String namespace, 
		 String uid, 
		 String pwd) 
		 throws Exception 
 { 
  StringBuffer credentialXML = new StringBuffer(); 

  credentialXML.append("<credential>"); 

  credentialXML.append("<namespace>"); 
  credentialXML.append(namespace); 
  credentialXML.append("</namespace>"); 

  credentialXML.append("<username>"); 
  credentialXML.append(uid); 
  credentialXML.append("</username>"); 

  credentialXML.append("<password>"); 
  credentialXML.append(pwd); 
  credentialXML.append("</password>"); 

  credentialXML.append("</credential>"); 

  String encodedCredentials = credentialXML.toString(); 
  credentialString = encodedCredentials; 

  connection.getCMService().logon(new XmlEncodedXML(encodedCredentials), 
  new SearchPathSingleObject[] {}); 
 } 
     

2) 获得 Cognos Server 中所有的 Package:

在连接成功后,我们需要获得该 Cognos Server 中的所有 Package 给 Modeler,让用户选择某一个 Package 来进行数据导入, 如下图 ( 图中橘黄色的文件夹表示一个文件夹,蓝色的文件夹表示一个 Package。在 Cognos Content 中,文件夹中可以存放 Package, report 等对象,Package 中也可以存放 Package,Report 等对象 )。


图 11. 获得 Cognos Server 中所有 Package,显示给用户
图片示例

我们可以通过 ContentManagerService 提供的 runQuery 接口来查询出所有的 package。


清单 3. 获得 Cognos Server 中所有的 Package
				
       List<CognosPropEnum> props = new ArrayList<CognosPropEnum>(); 
       props.add(CognosPropEnum.defaultName); 
       props.add(CognosPropEnum.searchPath); 
       String searchCondition = "CAMID(\"::Anonymous\")/folder[@name='My   Folders'] 
	       //package | /content//package"; 
       List<BaseClassWrapper> results =getCMService().runQuery(searchCondition, props); 
     

将查找到的所有 Package 按照其目录结构组织成一个 XML 格式的字符串返回给 Modeler。Modeler 展示这些 Package 给用户,如上图所示。

3) 获得用户选择的 Package 的 MetaData:

当用户选择了某一个 Package 后,我们需要得到该 Package 的 MetaData,通过这些 Metadata 来导入数据,如下图所示:


图 12. 获得用户指定的 Package 的 Metadata
图片示例

在上图中,如红圈所示,用户选择的是 My Folders 下面的名为 TEST 的 Package;Package content 部分显示 的就是得到的该 Package 的 MetaData,顶层的 TEST 表示 Package 名称;第二层的 CognosTest 是 Cognos Data Source, 表示一个数据库连接,他指定到一个特定的数据库上;第三层的 TEST 表示该数据库中的一个名为 TEST 的数据库表;Test 下 面的条目就是该表下的所有列。用户可以选择所有列或者你某些列到右边,根据所选列来导出数据。

该部分的实现是通过向 ReportService 发送 metadataRequest 请求来获取 Package 的 Metadata, 即调用 Report Service。


清单 4. 获取 Package 的 Metadata
				
    String sModel = sPackageSearchPath; 

    String sXML = 
	"<metadataRequest connection=\""
	    + sModel 
	    + "\">"
	    + "<Metadata Depth='' "
	    + "no_collections='1'>"
	    + "<Properties>"
	    + "<Property name='*/@name'/>"
	    + "<Property name='*/@datatype'/>"
	    + "<Property name='*/@_path'/>"
	    + "<Property name='*/@_ref'/>"					
            + "<Property name='*/@isNamespace'/>"
            + "<Property name='*/@usage'/>"
            + "<Property name='*/@namespace'/>"
            + "<Property name='*/@expression'/>"
            + "<Property name='*/@refobj'/>"
            + "<Property name='./folder'/>"
	    + "<Property name='./querySubject'/>"
	    + "<Property name='./queryItem'/>"
            + "<Property name='./queryItemFolder'/>"
            + "<Property name='./measure'/>"
            + "<Property name='./measureFolder'/>"
            + "<Property name='./dimension'/>"
            + "<Property name='./hierarchy'/>"
            + "<Property name='./rootCaption'/>"
            + "<Property name='./level'/>"
            + "<Property name='./filter'/>"
            + "<Property name='./calculation'/>"                
            + "<Property name='./folder/*'/>"
            + "</Properties>"
	    + "</Metadata>"
	    + "</metadataRequest>"; 
	  try { 
               return connection.getReportServiceWrapper().renderMetaDataRequest(sXML); 
	  } 
	  catch (CognosException e){ 
	      CognosLogUtil.writeException(e); 
	      return null; 
	  } 
     

在返回的 Medata 中包含了所有数据库表列的存储类型,如下图所示:


图 13. 从 Report Service 返回的 Package 的 Metadata
图片示例

4) 根据用户选择的 QueryItem,生成一个 List Report,通过 Report Service 的 runSpecification 接口来 Render 此 List Report,从而得到一个二维表状数据:


图 14. 用户选择 QueryItem 进行数据导出
图片示例

  • 根据用户选择的 QueryItem 来产生 List Report:

    要产成 Report,我们只需要生成它的 Report Specification 就可以,要生成 Report Specification, 必须根据 Report 的 schema 来生成,我们可以从 Cognos 的安装目录获得此文件(如:..\IBM\cognos\c10\schemas\rspec\7.0\ V5_report_one.xsd), 利用第三方库 castor 根据 schema 文件生成一批用来描述 report 的 java 源文件,用这些源文件中的对象来构造 Report 对象,最后将该 Report 对象 marshal 成一个 xml, 便得到了 Report Specification,在这次集成中,我们需要生成 List Report 以便得到二维表状数据,所以在生成 Report Specification 时要生成 List 样式的 Report。
  • 调用 ReportService 的 runSpecification 接口来运行此 List Report:


清单 5. 运行 Report Specification
				
Option runOptions[] = new Option[7]; 
int index = 0; 

RunOptionBoolean saveOutput = new RunOptionBoolean(); 
saveOutput.setName(RunOptionEnum.saveOutput); 
saveOutput.setValue(false); 
runOptions[index] = saveOutput; 
index++; 

RunOptionStringArray outputFormat = new RunOptionStringArray(); 
outputFormat.setName(RunOptionEnum.outputFormat); 

outputFormat.setValue(new String[]{"CSV"}); 
runOptions[index] = outputFormat; 
index++; 

RunOptionOutputEncapsulation outputEncapsulation = 
	 new RunOptionOutputEncapsulation(); 
outputEncapsulation.setName(RunOptionEnum.outputEncapsulation); 
outputEncapsulation.setValue(OutputEncapsulationEnum.none); 
runOptions[index] = outputEncapsulation; 
index++; 

RunOptionData data = new RunOptionData(); 
data.setName(RunOptionEnum.data); 
data.setValue(DataEnum.runWithAllData); 
runOptions[index] = data; 
index++; 

RunOptionEncoding encoding = new RunOptionEncoding(); 
encoding.setName(RunOptionEnum.attachmentEncoding); 
encoding.setValue(EncodingEnum.MIMECompressed); 
runOptions[index] = encoding; 
index++; 

RunOptionLanguageArray outputLocale = new RunOptionLanguageArray(); 
outputLocale.setName(RunOptionEnum.outputLocale); 
outputLocale.setValue(new String[]{Locale.getDefault().toString()}); 
runOptions[index] = outputLocale; 
index++; 

RunOptionBoolean prompt = new RunOptionBoolean(); 
prompt.setName(RunOptionEnum.prompt); 
prompt.setValue(false); 
runOptions[index] = prompt; 
index++; 


ParameterValue[] pv = new ParameterValue[] {}; 

Specification specification=new Specification(spec);   
ReportServiceReportSpecification reportSpec = 
					new ReportServiceReportSpecification(); 
reportSpec.setValue(specification); 
AsynchReply asynchReply = getReportService(). 
runSpecification(reportSpec, pv, runOptions); 

while( (asynchReply.getStatus() != AsynchReplyStatusEnum.complete) 
	&&(asynchReply.getStatus()!=AsynchReplyStatusEnum.conversationComplete)) 
   { 
   if (hasSecondaryRequest(asynchReply, "wait")) 
	 { 
		 asynchReply = getReportService().wait( 
		 asynchReply.getPrimaryRequest(), new ParameterValue[] {}, 
		 new Option[] {}); 
	 } 
	} 

   


清单 6. 获取运行 Report Specification 后的数据
				
       Object[] attachments = ((Stub) getReportService()).getAttachments(); 
       AttachmentPart pAttach = (AttachmentPart) attachments[0]; 
       if (pAttach.getAttachmentFile() == null) { 
         // 数据在 pAttach 对象中(内存中)
        }else{ 
        // 因为数据量大,数据生成在了临时目录下的临时文件中,文件路径为
        // pAttach.getAttachmentFile(), 通过读取该文件来读取数据
        } 
     

根据 pAttach 来读出数据,供 Modeler 进行数据挖掘和数据处理,至此,我们便完成了从 Cognos 中导出数据的所有实现,下图显示了导出的数据结果:


图 15. 从 Cognos 向 Modeler 导入的数据:
图片示例

3. 把 Modeler 处理后的数据导入到 Cognos 中

在 Modeler 对数据进行数据挖掘处理后,我们需要将数据导入到 Cognos 中去,用这些处理后的数据生成 Report,使得决策者做出更加准确的决策。 把数据导入到 Cognos 中,分为以下两步来实现:

1) 在 Cognos Server 所连接的数据库中创建一个新表并将数据写入其中:(这一步是基本数据库操作,不再做详细描述)。

2) 基于此表创建一个 package 并且 publish 到 Cognos 中: 根据数据库及表的信息,创建一个 ActionScript,里边包含了基于此表产生 package 并且 publish 该 package 到 Cognos Content 指定目录下的所有 Actions,然后调用 MetadataService 的 接口 updateMetadata 来执行这些 Action,从而实现了产生 package 并将之 publish 到 Cognos 中指定目录下的目的。


结束语

通过本文,您已经对数据挖掘与 Cognos 的集成有所了解,并且可以通过 Modeler 体会如何快速的将 Cognos 中的数据 导入到 Modeler 中进行数据挖掘处理后,再将处理后的数据导入到 Cognos 中去。


参考资料

学习

获得产品和技术

讨论

作者简介

袁辉的照片

袁辉,西北大学计算机系毕业,自 2009 年加入 IBM SPSS 以来,参与了 Modeler 与 Cognos 的集成开发。

杨家飞的照片

杨家飞,IBM SPSS Modeler 软件工程师,主要关注 Cognos 以及 Entity Analytics。

张晓篱

张晓篱,中国科学院毕业,2011 年加入 IBM,从事 Modeler 研发工作。

关于报告滥用的帮助

报告滥用

谢谢! 此内容已经标识给管理员注意。


关于报告滥用的帮助

报告滥用

报告滥用提交失败。 请稍后重试。


developerWorks:登录


需要一个 IBM ID?
忘记 IBM ID?


忘记密码?
更改您的密码

单击提交则表示您同意developerWorks 的条款和条件。 使用条款

 


当您初次登录到 developerWorks 时,将会为您创建一份概要信息。您在 developerWorks 概要信息中选择公开的信息将公开显示给其他人,但您可以随时修改这些信息的显示状态。您的姓名(除非选择隐藏)和昵称将和您在 developerWorks 发布的内容一同显示。

请选择您的昵称:

当您初次登录到 developerWorks 时,将会为您创建一份概要信息,您需要指定一个昵称。您的昵称将和您在 developerWorks 发布的内容显示在一起。

昵称长度在 3 至 31 个字符之间。 您的昵称在 developerWorks 社区中必须是唯一的,并且出于隐私保护的原因,不能是您的电子邮件地址。

(长度在 3 至 31 个字符之间)


单击提交则表示您同意developerWorks 的条款和条件。 使用条款.

 


为本文评分

评论

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=Information Management
ArticleID=766844
ArticleTitle=利用 Cognos 进行数据挖掘
publish-date=10202011

标签

Help
使用 搜索 文本框在 My developerWorks 中查找包含该标签的所有内容。

使用 滑动条 调节标签的数量。

热门标签 显示了特定专区最受欢迎的标签(例如 Java technology,Linux,WebSphere)。

我的标签 显示了特定专区您标记的标签(例如 Java technology,Linux,WebSphere)。

使用搜索文本框在 My developerWorks 中查找包含该标签的所有内容。热门标签 显示了特定专区最受欢迎的标签(例如 Java technology,Linux,WebSphere)。我的标签 显示了特定专区您标记的标签(例如 Java technology,Linux,WebSphere)。