
此文档根据Light Portal官方网站翻译。
https://light.dev.java.net/
什么是Light Portal?
Light Portal是一个基于Ajax与Java的开源Portal框架,它能够被无缝地集成到任何Java Web应用程序中或作为一个的Portal系统。
特点:
* Ajax 和基于JAVA的Portal框架
* 支持JSR168 Portlet API设计规范.
* 可以建立社会网络功能, 包括用户配置, 连接, 群组, 加上50种预先绑定的门户.
* 为所有用户提供个性化网页,最终用户可以方便地添加,修改或删除页面或子页面
* 包含多个预先建立的主题和用户界面窗口,还支持定制.
* 支持多种移动浏览器,如iPhone手机的Opera Mini等.
* 支持 Internationalizaiton (i18n).
* 支持 OpenID 验证
Light Portal的组织结构
下图显示了. Light Portal的主要组成部分。每个章节在后面都将详解
Applications
Applications兼容JSR 168 portlet。Light Portal推出了一套核心应用软件和社交网络应用,如用户配置文件,连接,团体,日历,电子邮件客户端,博客,论坛,搜索,事件,图片, RSS新闻阅读器和其他
Application Framework
Application Framework包括2部分,一个是AJAX UI Manager,另一个是Portal Server。开发者可以在核心应用中使用这些Framework API
* AJAX UI ManagerAJAX UI Manager 是一个 JavaScript library. 其职责包括提供门户网站,门户网站页面上, portlet中的窗口,并与服务器端异步.
* Portal ServerPortal Server is a web based application and a JSR 168 Portlet container.
Portal Server是一个基于网络的应用和兼容JSR 168 Portlet的容器
、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、
/////////////////////////////////////////////////////////////////////Portal实现原理
1.Portal用例
读者可以在下面三个网站上注册自己的用户,体会Portal的功能。
http://my.msn.com
http://my.yahoo.com
http://my.liferay.com
My MSN的功能最灵活强大,用户可以任意拖放操作栏目(column)和内容版块(content)的位置和个数。
My Liferay只能选择固定的栏目(column)布局,但可以在本栏目(column)内移动内容版块(content)的位置。
My Yahoo只能选择固定的栏目(column)布局,而且不能移动内容版块(content)的位置。
Portal的结构分为三层。
(1) Page
(2) Column,或者称为Pane
(3) Content,或者称为Portlet
我们来看看Portal的整个操作流程。
(1) 每个Column的下方都有一个[Add Content]按钮,让用户选择加入自己喜欢的内容。
从这里,我们知道,Portal系统里面有一个公用的Common Portlet Repository,供用户选用。
JSR168 Portlet规范里面定义了Portlet Deployment Discriptor。Common Portlet Repository以这个Portlet Deployment Discriptor的格式存放。
开源项目JetSpeed的XReg文件用来存放Common Portlet Repository的定义。
(2) 加入Content之后,用户的Page和Column里面就多了这个Content。下次用户登陆的时候,就会看到自己订制的Portal版面。
从这里,可以看出,Portal系统会纪录用户的个人Portal配置信息 – User Portal Config。
开源项目JetSpeed的PSML文件用来存放User Portal Config的定义。
------- 综上。
Add Content的整个流程为:
Common Portlet Repository --> Add Content --> Personal Portal Config
Display Portal的整个流程为:
从Personal Portal Config读取用户配置的Portlet ID --> 根据Portlet ID,从Common Portlet Repository查找详细的Portlet定义 --> 根据这个详细的Portlet定义显示这个Portlet。
2.Portal实现
我们考虑如何用Java来实现Portal。
2.1 Dynamic Include
首先,我们采用最简单的思路,我们用100个JSP文件(1.jsp, 2.jsp, 3.jsp, … 100.jsp等),代表100个Portlet。
用户页面MyPage.jsp包含用户选定的多个Portlet。
现在,假设用户选取的Portlet为1.jsp, 3.jsp, 7.jsp等3个Portlet,那么我们如何在MyPage.jsp中显示这些Portlet?最直观的做法是,用jsp:include。比如:
| |
| |
| |
由于 下面我们换成这种写法。 Java代码 1. 2. 3.<% request.getRequestDispatcher(”1.jsp”).include(request, response); /> 4. 5. 6.<% request.getRequestDispatcher(”3.jsp”).include(request, response); /> 7. 8. 9.<% request.getRequestDispatcher(”7.jsp”).include(request, response); /> 10. 11. <% request.getRequestDispatcher(”1.jsp”).include(request, response); /> <% request.getRequestDispatcher(”3.jsp”).include(request, response); /> <% request.getRequestDispatcher(”7.jsp”).include(request, response); /> 进一步改进MyPage.jsp。 Java代码 1.<% String[] fileNames = {“1.jsp”, “3.jsp”, “7.jsp”}; %> 2. 3.<% for(int i = 0; i < fileNames.length; i++) { 4. String fileName = fileName s[i]; %> 5. 6.<% request.getRequestDispatcher(fileName).include(request, response); /> 7. 8.<% } // end for %> 9. <% String[] fileNames = {“1.jsp”, “3.jsp”, “7.jsp”}; %> <% for(int i = 0; i < fileNames.length; i++) { String fileName = fileName s[i]; %> <% request.getRequestDispatcher(fileName).include(request, response); /> <% } // end for %> 其中的fileNames的内容可以各种各样,只要RequestDispatcher能够处理。 比如Velocity,fileNames = {“1.vm”, “3.vm”, “7.vm”}; 比如URL,fileNames = {“/portlet1.do”, “/portlet3.do”, “/portlet4.do”}; 我们可以看到,如果我们从用户配置中读取fileNames的内容,这就是一个简单的Portal实现。 Java代码 1.<% String[] fileNames = (String[])session.getAttribute(“portlets.config”); %> 2. 3.<% for(int i = 0; i < fileNames.length; i++) { 4. String fileName = fileNames[i]; %> 5. 6.<% request.getRequestDispatcher(fileName).include(request, response); /> 7. 8.<% } // end for %> 9. <% String[] fileNames = (String[])session.getAttribute(“portlets.config”); %> <% for(int i = 0; i < fileNames.length; i++) { String fileName = fileNames[i]; %> <% request.getRequestDispatcher(fileName).include(request, response); /> <% } // end for %> 2.2 Portlet Interface 下面我们来扩展这个例子。 假设每个Portlet都规定实现一个Portlet接口。 Java代码 1.interface Portlet { 2. void render(request, response); 3.}; 4. 5.MyPage.jsp如下: 6. 7.<% String[] portletClassNames = (String[])session.getAttribute(“portlets.config”); %> 8. 9.<% for(int i = 0; i < portletClassNames.length; i++) { 10. String className = portletClassNames[i]; 11. Portlet portlet = (Portlet)Class.forName(className).newInstance(); %> 12. 13.<% portlet. render (request, response); /> 14. 15.<% } // end for %> 16. 17. 18.Portlet类的示例代码如下: 19.public class Portlet7{ 20. public void render(request, response){ 21. request.getRequestDispatcher(“7.jsp”).include(request, response); 22. } 23.}; interface Portlet { void render(request, response); }; MyPage.jsp如下: <% String[] portletClassNames = (String[])session.getAttribute(“portlets.config”); %> <% for(int i = 0; i < portletClassNames.length; i++) { String className = portletClassNames[i]; Portlet portlet = (Portlet)Class.forName(className).newInstance(); %> <% portlet. render (request, response); /> <% } // end for %> Portlet类的示例代码如下: public class Portlet7{ public void render(request, response){ request.getRequestDispatcher(“7.jsp”).include(request, response); } }; 上述代码是Portal显示Portlet的核心流程的一个简化版本。 JSR168 Portlet规范里面定义了真正的Portlet接口定义。 2.3 Portlet Action Portlet的操作包括,最大化/最小化/恢复/关闭/编辑/帮助/上下移动,等等。 这些操作都有对应的Action类。 开源项目JetSpeed的module/actions/controls目录下面包含Maximize, Minimize, Close等Action类。 开源项目Liferay的portal/action目录下面包含Maximize, Minimize, Close等Action类。 Portal的操作不仅包括上述Portlet的操作,而且包括其它更高级别的操作。 比如,Add/Move Page, Add/Move Column, 换Layout, 换Skin,之类。 2.4 Portlet Cache 我们操作Portlet的时候,往往只操作某个特定的Portlet,或者只是变化Portlet的位置。这时候,页面中大多数的Porlet的内容是不变的,只有一小块Portlet变化。 我们需要把Portlet的内容缓存起来。Portlet接口有一个render(request, response)方法,我们可以订制定制response类,截获portlet的输出,保存到Portal系统的内容Cache当中。 比如,前面提到liferay开源项目,其StringServletResponse类把Portlet的输出保存到一个String当中。 ///////////////////////////////////////////////////////////////////// 主题:liferay开发环境搭建 最近开始研究liferay了,在网上看了很多帖子,受益不少,最终还是按照liferay中文的ppt介绍做的,终于把开发环境搭建做好了。 下面说说我最后一次做的过程吧: 我用的liferay是从liferay中文上下载下来的liferay4.1.3,现在官方的版本已经到了4.3.4了,最新版本以后再研究吧。 首先安装好jdk,ant,jikes,我的安装路径分别为为D:\\Java\\ant,D:\\Java\\jdk1.5.0,D:\\Java\\jikes。接下来添加环境变量: ANT_HOME D:\\Java\\ant JAVA_HOME D:\\Java\\jdk1.5.0 JIKES_HOME D:\\Java\\jikes PATH .;D:\\Java\\jdk1.5.0\\bin;D:\\Java\\ant\\bin;D:\\Java\\jikes\\bin; 下面我们开始安装Tomcat,声明一下,我现在用的tomcat并不是tomcat官网上的tomcat,而是已经内嵌了liferay的一个tomcat。 我下载的是liferay-portal-tomcat-jdk5-4.1.3.zip,现在的liferay中文提供的就是这个版本。 为了进行liferay环境的搭建,我们建立一个目录D:\\liferay,在这个目录下,建立一个tomcat的文件夹,然后把liferay-portal-tomcat-jdk5-4.1.3.zip解压缩到tomcat目录下,运行D:\\liferay\omcat\\bin\\startup.bat,出现类似于DOS的一个控制台窗口,等到信息提示:Server startup in XXXXX ms的时候,打开你的浏览器,输入http://localhost:8080,如果你能看到liferay的界面,那么恭喜你,liferay的安装成功了。 接下来我们要做的就是建立liferay的工程,以便进行下一步的开发。 我用的是MyEclipse5.5,以下以这个环境来进行说明。 在D:\\liferay目录下建立一个名为portal的文件夹,将liferay-portal-src-4.1.3.zip解压缩到portal目录下。运行MyEclipse,选择File->Switch Workspace...,选择我们建立的D:\\liferay,然后选择File->Import...,选择General->Existing Projects into Workspace,点击next,在Select root directory中填入D:\\liferay,你会发现Projects中,有一个portal的选项,选中它点击Finish。这时候,你应该在左面的Workspace中看到protal的项目了。 下面我们要生成liferay的扩展项目ext: 在portal的根目录下,有一个release.properties的文件,里面纪录的是我们将要生成的ext项目的信息。liferay不推荐直接更改release.properties中的信息,它允许你建立一个release.${user.name}.properties的文件去重写release.properties中的部分信息。需要注意的是:${user.name}是你的用户名,也就是点开开始菜单最上面显示的那一个名字。例如我的用户名是yzj,我的新文件就是release.yzj.properties。那么在portal的根目录下建立文件release.yzj.properties. 打开文件,输入以下信息: lp.eclipse.dir=D:/Java/eclipse(此处为你机器里面eclipse的目录) lp.ext.dir=D:/liferay/ext(此处为我们将要生成的ext项目的路径,不妨就设到我们刚才建立的D:\\liferay目录下) 值得提一下的是,上面路径的设定用的都是/,而不是\\。 下面开始运用ant生成扩展项目ext,在MyEclipse下,右键点击portal下的build.xml,选择Run as->ant build...。在弹出来的对话框中,依次选中clean,start,build-ext,点击Run。 等待操作完成,点击File->Import...,General->Existing Projects into Workspace,Select root directory中填入D:\\liferay,这个时候在Projects中,将会出现ext的选项,选中它点击Finish。这时候,左侧的Workspace应该出现了ext的项目了。 在ext的根目录下,有一个app.server.properties的文件,里面纪录的是服务器的配置信息。同样,我们不更改其中的信息,建立一个app.server.yzj.properties的文件(继续刚才的假设,你的用户名为yzj)。 在文件中输入以下信息: app.server.type=tomcat(此处说明我们用的服务器为tomcat) app.server.tomcat.dir=D:/liferay/tomcat(此处为tomcat的安装路径) 接下来在右键点击ext下的build.xml,Run as->ant build...,在弹出的窗口中选择deploy,等待操作完成。恭喜你,扩展项目的搭建就此完成。 ///////////////////////////////////////////////////////////////////// 请问各厂商(包括开源的)portal各有什么优势 我一直是用liferay的,我可以先说一下liferay的 从开发角度: 好处 开源,能够把握所有代码。开发时心里有底。 例子多。liferay中有大量的已开发好的portlet。可以作为新开发的参考和基础 和struts集成。有多种集成的方式,从PortletAction下继承后,可以采用168的习惯编写,也可以直接覆盖execute方法,采用struts的习惯编写。 还算lightweight,tomcat下就能跑,调试方便。 支持war方式的部署,所以开发和发布的时候可以模块化,同liferay主程序不会产生干扰。 不足 文档不够,很多时候是从代码里跟出结果的。 国际化不好,主要体现在对文字的i/o 上,因为liferay中很多是用stream而不是reader/writer。所以会出现乱码。 中文的翻译一蹋糊涂。不知道是不是用翻译软件翻译的(正在整理,稍有眉目后准备贡献出来) 还有一个就是liferay有很多对于168的扩展,比如他的tag,说不上是不是好处,你用了,就可以加快程序开发,甚至能完成一些困难的需求。但是就被绑定后无法迁移到其他的portal上。 从使用角度: 好处 有很多现有的portlet,可以拿来就是用。比如iframe portlet, journal, bbs, wiki, rss。 操作方便,甚至感觉不到有特别的操作方式,可以拖拽,关闭一个portlet,重新打开。 可以定义分组页面,一个组可以定义一套页面,普通用户不可修改这些页面的布局。在liferay中称为community。我们用这些来完成一些部门页面的设计。 不足 提示信息不够正确,有时候会直接抛出异常。 页面风格不够统一,某几个portlet的css显得很混乱,没有遵守168定义的css。 其他厂商的portal产品没有用过,希望有熟悉这些产品的朋友能够指教一下 //////////////////////////////////////////////////////////////////////////////////////////////// 主题:Portlet技术发展的思考 Portal这个概念出现很长的时间了,然而Portal应用是直到最近这两三年才蓬勃发展起来,这跟原来缺乏相关的规范有一定的关系。目前关于Portal方面存在两个重要的标准,均是2003年下半年正式通过的,分别为: 1、Java Portlet Specification 1.0 (JSR168), 2003年10月27日 2、Web Services for Remote Portlets 1.0, 2003年9月3日 这两个规范发布之后,得到各个Portal产商的支持,特别是JSR168标准更是得到OpenSource界的大力支持。许多开源项目都声称支持JSR168标准,具体项目列表可以参考:Open Source Portal in Java。 不过在对这些标准学习之后,我认识到除了实现一个支持标准的服务器之外,还有很多空间是值得我们去努力的。如果有人正在进行Portal方面的研究、实现,希望我的想法能够有所帮助。 Java Web Framework -> JSR168 我学习JSR168这个规范后,我就认识到开始一个JSR168 Portlet不会是一件愉快的事情。JSR168 Portlet十分类似于Servlet,现在还有谁愿意只是基于Servlet来开发Web应用呢?更进一步的问题是:开发人员需要直接编写JSR168 Portlet么?答案是不需要! 所谓Portlet本身来说就是一个Web应用,只是运行在Portal才被称为Portlet。业界已经有大量熟练的Java Web应用开发人员,让他们去重新学习一种新的Web应用模式、并且只能运行在在Portal中是不现实的,正确的方式应该是能够把普通的Java Web应用包装成JSR168 Portlet。这样开发人员依然按照原来的模式开发Web应用,只是在部署到Portal之前才包装成JSR168 Portlet。目前许多Java Web应用都是基于某些Web Framework(例如Struts)来实现,因此可以考虑基于这些Web Framework的包装方法。 对于这个包装器,我目前想到需要注意的地方有: 1、URL转换。Web应用中使用普通的URL,然而访问一个Portlet的URL有其特殊的格式,因此需要把指向自身的URL全部转换为Portlet格式。这些URL主要是HTML FORM中的ACTION属性。 2、Session范围。Session在Portlet中分为PORTLET_SCOPE和APPLICATION_SCOPE两种,为了避免冲突缺省情况下应该把Web应用中的Seesion变量都设置为PORTLET_SCOPE。 3、开发人员透明。Web应用是否包装为Portlet对Web应用本身不做更改,这样即使被包装为Portlet后,开发人员仍可当作普通的Web应用继续开发。 4、可选的Portlet特性。使得开发人员能够在Web应用中使用Portlet特性,当Web应用部署运行时这些特性自动失效,当部署到Portal中就可以利用到Portlet特性了。 Common Web Application -> WSRP WSRP规范致力于定义一个面向表示(presentation-oriented)的Web Services协议以及相应的接口集,面向表示的Web Services协议不仅提供商业逻辑还提供界面表示,应用程序可以容易的通过代理工具集成面向表示的Web Services。 在Portal应用中,经常有将现存的某个应用在Portal界面中显示的需求,而且该应用是运行在与Portal服务器不同的机器上的。这种需求在Portal项目中使极为常见的,解决的方法主要有:1、如果应用提供java接口,可以建立JSR168 Portlet使用该接口;2、如果应用存在Web界面,则可通过Web裁减(Web Clipping)技术来集成,Kapow公司是这一技术的领先者;或者通过HTML IFRAME技术作简单的集成。 WSRP规范出现后,我们有了更加方便的新选择,如果应用本身支持WSRP,那么Portal服务器可以直接集成该应用无需额外开发。但是目前支持WSRP的应用还太少,而且期待现存的应用自身增加WSRP支持也是不现实的。例如对一个现存的部署在Apapche Http Server上的PHP应用,用户当然希望无需对该应用进行任何更改就能够支持WSRP。 我曾写过一篇短文“WSRP实践&想法”阐述这方面的想法。我最希望看到这样的WSRP工具出现,安装在Web服务器上后,通过配置就能够将部署在该Web服务器上的应用以WSRP协议发布。 这样的工具主要的是两部分的功能: 1、当然是WSRP协议支持。可以参考已有的开源实现,我想其中的初期的重点是URL Wirting和Stateful Information,即URL的双向转换和状态信息的处理。 2、与现有应用的交互,可以从两个方向来实现: 2.1 利用服务器功能,例如Java Servlet Server提供javax.servlet.RequestDispatcher接口实现来完成对本服务器上的资源调用。这样做的优点的性能高效,缺点是不同的服务器要开发不同的版本; 2.2 采用类似HTTP Porxy的方式实现。优点是适应性强,不必理睬Web应用的具体实现、部署技术,缺点是性能会有影响。 以上就是我的一些想法,希望尽快看到相关的产品出现,这些开发Portal应用就会轻松很多。 //////////////////////////////////////////////////////////////////////////////////////////////////// 【原创】Liferay Portal学习笔记(一):安装 一、 简单安装 1)下载并安装 JDK1.5 1、 下载并安装 Windows Platform J2SE(TM) Development Kit 5.0 Update ,下载网址 http://java.sun.com/j2se/1.5.0/download.jsp 2、 在控制面板 --> 系统 --> 高级选项 --> 环境变量,新增一个用户变量 JAVA_HOME 并指向 JDK 的安装目录 2) 下载并安装 Liferay Portal 1. 下载并安装 Liferay Portal Professional 4.0.0 (Bundled with Tomcat and JDK 5.0), 下载网址 http://www.liferay.com/web/guest/download 2. 解压缩到一个目录,并确保硬盘上有足够的空间,我们称这个目录为 TOMCAT_HOME 3) 启动 TOMCAT 到 TOMCAT/bin 目录下,运行 startup.bat 。 你的 Apache Tomcat server 能够编译并运行 Liferay Portal 。默认情况下, portal 使用自带的 HSQL 数据库。在浏览器中输入 http://localhost:8080 ,将会看见 portal 首页。 二、 专业安装 1) 下载并安装 JDK1.5 1、 下载并安装 Windows Platform J2SE(TM) Development Kit 5.0 Update ,下载网址 http://java.sun.com/j2se/1.5.0/download.jsp 2、 在控制面板 --> 系统 --> 高级选项 --> 环境变量,新增一个用户变量 JAVA_HOME 并指向 JDK 的安装目录 2) 下载并安装 TOMCAT 1、 下载 apache-tomcat-5.5.17.zip 并解压缩到一个目录,我们称这个目录为 TOMCAT 。 3) 下载并安装 Liferay Portal 1、 下载 liferay-portal-4.0.0.war, 下载网址 http://www.liferay.com/web/guest/download 2、 解压缩 liferay-portal-4.0.0.war 到 TOMCAT 目录下并改名为 liferay ,然后将 liferay/WEB-INF/lib 下除 util-taglib.jar 外的其他 jar 包剪切到 TOMCAT/common/lib/ext 下 3、 在 TOMCAT/conf/Catalina/localhost 目录下,删除该目录下已有的文件,然后新建 ROOT.xml 文件(这里的 ROOT 必须是大写) ROOT.xml : < Context path = "" docBase = " ../liferay " debug = " 0 " reloadable = " true " crossContext = " true " > < Resource name = " jdbc/LiferayPool " auth = " Container " type = " javax.sql.DataSource " driverClassName = " org.hsqldb.jdbcDriver " url = " jdbc:hsqldb:test " username = " sa " password = "" maxActive = " 20 " /> < Resource name = " mail/MailSession " auth = " Container " type = " javax.mail.Session " mail.transport.protocol = " smtp " mail.smtp.host = " localhost " /> < Realm className = " org.apache.catalina.realm.JAASRealm " appName = " PortalRealm " userClassNames = " com.liferay.portal.security.jaas.PortalPrincipal " roleClassNames = " com.liferay.portal.security.jaas.PortalRole " debug = " 99 " useContextClassLoader = " false " /> Context > 4、 在TOMCAT/conf目录下,新建jaas.config文件 jaas.config : PortalRealm { com.liferay.portal.security.jaas.PortalLoginModule required; }; 5、 修改 TOMCAT/conf 目录下 catalina.properties 文件中的下面一段: common.loader=${catalina.home}/common/classes,${catalina.home}/common/i18n/*.jar,${catalina.home}/common/endorsed/*.jar,${catalina.home}/common/lib/*.jar,${catalina.home}/common/lib/ext/*.jar 6、 修改 TOMCAT/bin 目录下 catalina.bat 文件,增加下面内容: rem ----- Execute The Requested Command --------------------------------------- set JAVA_OPTS=-Xms128m -Xmx512m -Dfile.encoding=UTF8 -Duser.timezone=GMT+08 -Djava.security.auth.login.config=%CATALINA_HOME%/conf/jaas.config 7、 到 TOMCAT/bin 目录下,运行 startup.bat 。在浏览器中输入 http://localhost:8080 ,将会看见 portal 首页。 三、 连接数据库 1) 连接 HSQLDB 修改 TOMCAT/conf/Catalina/localhost/ROOT.xml 文件并将 SQL SERVER 驱动包 hsql.jar 拷贝到 TOMCAT/common/lib/ext 下 auth="Container" type="javax.sql.DataSource" driverClassName="org.hsqldb.jdbcDriver" url="jdbc:hsqldb:test" username="sa" password="" maxActive="20" /> 2) 连接 SQL SERVER 修改 TOMCAT/conf/Catalina/localhost/ROOT.xml 文件并将 SQL SERVER 驱动包 jtds-1.2.jar 拷贝到 TOMCAT/common/lib/ext 下 auth="Container" type="javax.sql.DataSource" driverClassName="net.sourceforge.jtds.jdbc.Driver" url="jdbc:jtds:sqlserver://localhost:1433;DatabaseName=lportal4" username="sa" password="sa" maxActive="100" /> ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// Liferay portal 6.0版本发布,一个非常值得关注的开源产品,产品内包含大量的开源实现。 Liferay portal 是一个完整的门户解决方案,基于J2EE的应用,使用了EJB以及JMS等技术,前台界面部分使用Struts MVC 框架,基于XML的portlet配置文件可以自由地动态扩展,使用了Web服务来支持一些远程信息的获取,使用 Lucene实现全文检索功能。 下载地址: http://sourceforge.net/projects/lportal/ //////////////////////////////////////////////////////////////////////////////////////////////////////
