|  | @ -3,15 +3,18 @@ package com.yihu.hos.services;
 | 
	
		
			
				|  |  | import com.yihu.ehr.framework.model.Result;
 | 
	
		
			
				|  |  | import com.yihu.ehr.framework.util.operator.ClassFileUtil;
 | 
	
		
			
				|  |  | import com.yihu.ehr.framework.util.operator.StringUtil;
 | 
	
		
			
				|  |  | import com.yihu.hos.models.CamelContextQueue;
 | 
	
		
			
				|  |  | import com.yihu.hos.models.SystemPathMapping;
 | 
	
		
			
				|  |  | import com.yihu.hos.common.classLoader.DynamicClassLoader;
 | 
	
		
			
				|  |  | import com.yihu.hos.common.constants.Constant;
 | 
	
		
			
				|  |  | import com.yihu.hos.models.SystemCamelContext;
 | 
	
		
			
				|  |  | import com.yihu.hos.models.SystemClassMapping;
 | 
	
		
			
				|  |  | import org.apache.camel.builder.RouteBuilder;
 | 
	
		
			
				|  |  | import org.apache.logging.log4j.LogManager;
 | 
	
		
			
				|  |  | import org.apache.logging.log4j.Logger;
 | 
	
		
			
				|  |  | import org.springframework.stereotype.Service;
 | 
	
		
			
				|  |  | 
 | 
	
		
			
				|  |  | import java.net.URL;
 | 
	
		
			
				|  |  | import java.io.File;
 | 
	
		
			
				|  |  | import java.net.MalformedURLException;
 | 
	
		
			
				|  |  | import java.util.Map;
 | 
	
		
			
				|  |  | import java.util.concurrent.SynchronousQueue;
 | 
	
		
			
				|  |  | 
 | 
	
		
			
				|  |  | /**
 | 
	
		
			
				|  |  |  * Created by lingfeng on 2016/8/4.
 | 
	
	
		
			
				|  | @ -28,138 +31,167 @@ public class ESBCamelService {
 | 
	
		
			
				|  |  |      * @param path processor处理器定义涉及的class对应路径
 | 
	
		
			
				|  |  |      */
 | 
	
		
			
				|  |  |     public Result onProcessorAdded(String serviceFlow, String packageName, String className, String path) {
 | 
	
		
			
				|  |  |  /*
 | 
	
		
			
				|  |  |          * 当一个处理器进行添加时,要做以下处理
 | 
	
		
			
				|  |  |          * 1、首先根据serviceFlow的信息,在ESB-Broker Server的映射容器中寻
 | 
	
		
			
				|  |  |          * 找个业务系统定义的各种Server Class 文件在ESB-Broker Server节点本地存储的根路径
 | 
	
		
			
				|  |  |          * 2、然后按照packageName、className、contents的信息将这个class文件写入到正确的位置
 | 
	
		
			
				|  |  |          *
 | 
	
		
			
				|  |  |          * 注意:由于此时只是完成了class了文件的写入,所以这个class文件还没有被classloader进行初始化。
 | 
	
		
			
				|  |  |          * 另外由于,CamelContext并没有提供单独进行processor处理器加载的功能,而是随着routes实例的加载而加载
 | 
	
		
			
				|  |  |          * 而这个工作将在onRouteDefineChanged事件中完成,所以在完成processor-class文件的写入后,就不需要再做其它事情了。
 | 
	
		
			
				|  |  |          * */
 | 
	
		
			
				|  |  |         if(StringUtil.isEmpty(serviceFlow) || StringUtil.isEmpty(packageName)
 | 
	
		
			
				|  |  |                 || StringUtil.isEmpty(className) || StringUtil.isEmpty(path)) {
 | 
	
		
			
				|  |  |             logger.error("必要的入参数据不正确,请检查!");
 | 
	
		
			
				|  |  |             return Result.error("必要的入参数据不正确,请检查!");
 | 
	
		
			
				|  |  |         try {
 | 
	
		
			
				|  |  |             if(StringUtil.isEmpty(serviceFlow) || StringUtil.isEmpty(packageName)
 | 
	
		
			
				|  |  |                     || StringUtil.isEmpty(className) || StringUtil.isEmpty(path)) {
 | 
	
		
			
				|  |  |                 logger.error("必要的入参数据不正确,请检查!");
 | 
	
		
			
				|  |  |                 return Result.error("必要的入参数据不正确,请检查!");
 | 
	
		
			
				|  |  |             }
 | 
	
		
			
				|  |  |             this.createClassfile(serviceFlow, packageName, className, path, Constant.PROCESSOR);
 | 
	
		
			
				|  |  |             return Result.success("新增处理器成功!");
 | 
	
		
			
				|  |  |         } catch (Exception e) {
 | 
	
		
			
				|  |  |             logger.error(e);
 | 
	
		
			
				|  |  |             return Result.error("新增处理器失败!");
 | 
	
		
			
				|  |  |         }
 | 
	
		
			
				|  |  |         this.createClassfile(serviceFlow, packageName, className, path);
 | 
	
		
			
				|  |  |         return Result.success("新增处理器成功!");
 | 
	
		
			
				|  |  |     }
 | 
	
		
			
				|  |  | 
 | 
	
		
			
				|  |  |     /**
 | 
	
		
			
				|  |  |      * 当外界组件通知一个已有的processor处理器data部分发生变化时,该事件被触发。
 | 
	
		
			
				|  |  |      */
 | 
	
		
			
				|  |  |     public Result onProcessorDataChanged(String serviceFlow , String packageName , String className , String path) {
 | 
	
		
			
				|  |  |         if(StringUtil.isEmpty(serviceFlow) || StringUtil.isEmpty(packageName)
 | 
	
		
			
				|  |  |                 || StringUtil.isEmpty(className) || StringUtil.isEmpty(path)) {
 | 
	
		
			
				|  |  |             logger.error("必要的入参数据不正确,请检查!");
 | 
	
		
			
				|  |  |             return Result.error("必要的入参数据不正确,请检查!");
 | 
	
		
			
				|  |  |         try {
 | 
	
		
			
				|  |  |             if(StringUtil.isEmpty(serviceFlow) || StringUtil.isEmpty(packageName)
 | 
	
		
			
				|  |  |                     || StringUtil.isEmpty(className) || StringUtil.isEmpty(path)) {
 | 
	
		
			
				|  |  |                 logger.error("必要的入参数据不正确,请检查!");
 | 
	
		
			
				|  |  |                 return Result.error("必要的入参数据不正确,请检查!");
 | 
	
		
			
				|  |  |             }
 | 
	
		
			
				|  |  |             this.updateClassfile(serviceFlow, packageName, className, path, Constant.PROCESSOR);
 | 
	
		
			
				|  |  | 
 | 
	
		
			
				|  |  |             SystemCamelContext.getDefaultCamelContext().stopRoute(serviceFlow);
 | 
	
		
			
				|  |  |             SystemCamelContext.getDefaultCamelContext().removeRoute(serviceFlow);
 | 
	
		
			
				|  |  | 
 | 
	
		
			
				|  |  |             DynamicClassLoader classLoader = new DynamicClassLoader(DynamicClassLoader.class.getClassLoader());
 | 
	
		
			
				|  |  |             Class<RouteBuilder> routeBuilderClass = (Class<RouteBuilder>) classLoader.loadClass(ClassLoader.getSystemResource(Constant.EMPTY).getPath(), SystemClassMapping.getSystemClassNameMapping().get(serviceFlow + Constant.ROUTE));
 | 
	
		
			
				|  |  |             classLoader.loadClass(ClassLoader.getSystemResource(Constant.EMPTY).getPath(), SystemClassMapping.getSystemClassNameMapping().get(serviceFlow + Constant.PROCESSOR));
 | 
	
		
			
				|  |  | 
 | 
	
		
			
				|  |  |             if (routeBuilderClass != null) {
 | 
	
		
			
				|  |  |                 RouteBuilder routeBuilder = routeBuilderClass.newInstance();
 | 
	
		
			
				|  |  |                 SystemCamelContext.getDefaultCamelContext().addRoutes(routeBuilder);
 | 
	
		
			
				|  |  |             }
 | 
	
		
			
				|  |  |             return Result.success("修改处理器成功!");
 | 
	
		
			
				|  |  |         } catch (Exception e) {
 | 
	
		
			
				|  |  |             logger.error(e);
 | 
	
		
			
				|  |  |             return Result.error("修改路由失败!");
 | 
	
		
			
				|  |  |         }
 | 
	
		
			
				|  |  |         this.updateClassfile(serviceFlow, packageName, className, path);
 | 
	
		
			
				|  |  |         return Result.success("修改处理器成功!");
 | 
	
		
			
				|  |  |     }
 | 
	
		
			
				|  |  | 
 | 
	
		
			
				|  |  |     /**
 | 
	
		
			
				|  |  |      * 当外界组件通知一个新的RouteDefine路由被定义时,该事件被触发
 | 
	
		
			
				|  |  |      */
 | 
	
		
			
				|  |  |     public Result onRouteDefineAdded(String serviceFlow , String packageName , String className , String path) {
 | 
	
		
			
				|  |  | /*
 | 
	
		
			
				|  |  |          * 当一个新的路由定义事件发生时,要做以下几件事情:
 | 
	
		
			
				|  |  |          *
 | 
	
		
			
				|  |  |          * 1、根据serviceFlow的信息,在ESB-Broker Server的映射容器中寻
 | 
	
		
			
				|  |  |          * 找个业务系统定义的各种Server Class 文件在ESB-Broker Server节点本地存储的根路径
 | 
	
		
			
				|  |  |          * 2、然后按照packageName、className、contents的信息将这个class文件写入到正确的位置
 | 
	
		
			
				|  |  |          * 3、不能在本线程操作Apache Camel,只能通过一个同步队列通知Apache Camel主线程
 | 
	
		
			
				|  |  |          * */
 | 
	
		
			
				|  |  |         if(StringUtil.isEmpty(serviceFlow) || StringUtil.isEmpty(packageName)
 | 
	
		
			
				|  |  |                 || StringUtil.isEmpty(className) || StringUtil.isEmpty(path)) {
 | 
	
		
			
				|  |  |             logger.error("必要的入参数据不正确,请检查!");
 | 
	
		
			
				|  |  |             return Result.error("必要的入参数据不正确,请检查!");
 | 
	
		
			
				|  |  |         }
 | 
	
		
			
				|  |  |         // 第1、2两步处理过程,都是在这里完成
 | 
	
		
			
				|  |  |         this.createClassfile(serviceFlow, packageName, className, path);
 | 
	
		
			
				|  |  | 
 | 
	
		
			
				|  |  |         // 3、===============加载到CamelContext中
 | 
	
		
			
				|  |  |         SynchronousQueue<String> camelContextOperateQueue = CamelContextQueue.getCamelCamelContextQueue();
 | 
	
		
			
				|  |  |         try {
 | 
	
		
			
				|  |  |             camelContextOperateQueue.put(packageName + "." + className);
 | 
	
		
			
				|  |  |         } catch (InterruptedException e) {
 | 
	
		
			
				|  |  |             logger.error(e.getMessage() , e);
 | 
	
		
			
				|  |  |             if(StringUtil.isEmpty(serviceFlow) || StringUtil.isEmpty(packageName)
 | 
	
		
			
				|  |  |                     || StringUtil.isEmpty(className) || StringUtil.isEmpty(path)) {
 | 
	
		
			
				|  |  |                 logger.error("必要的入参数据不正确,请检查!");
 | 
	
		
			
				|  |  |                 return Result.error("必要的入参数据不正确,请检查!");
 | 
	
		
			
				|  |  |             }
 | 
	
		
			
				|  |  |             File systemClassRootPath = new File(ClassLoader.getSystemResource("").getPath() + "/" + serviceFlow);
 | 
	
		
			
				|  |  |             if (!systemClassRootPath.exists()) {
 | 
	
		
			
				|  |  |                 systemClassRootPath.mkdirs();
 | 
	
		
			
				|  |  |             }
 | 
	
		
			
				|  |  |             // 第1、2两步处理过程,都是在这里完成
 | 
	
		
			
				|  |  |             this.createClassfile(serviceFlow, packageName, className, path, Constant.ROUTE);
 | 
	
		
			
				|  |  | 
 | 
	
		
			
				|  |  |             // 3、===============加载到CamelContext中
 | 
	
		
			
				|  |  |             ClassLoader currentClassLoader = Thread.currentThread().getContextClassLoader();
 | 
	
		
			
				|  |  |             Class<RouteBuilder> routeBuilderClass = (Class<RouteBuilder>) currentClassLoader.loadClass(SystemClassMapping.getSystemClassNameMapping().get(serviceFlow + Constant.ROUTE));
 | 
	
		
			
				|  |  |             if(routeBuilderClass != null) {
 | 
	
		
			
				|  |  |                 RouteBuilder routeBuilder = routeBuilderClass.newInstance();
 | 
	
		
			
				|  |  |                 SystemCamelContext.getDefaultCamelContext().addRoutes(routeBuilder);
 | 
	
		
			
				|  |  |             }
 | 
	
		
			
				|  |  |             return Result.success("新增路由成功!");
 | 
	
		
			
				|  |  |         } catch (Exception e) {
 | 
	
		
			
				|  |  |             logger.error(e);
 | 
	
		
			
				|  |  |             return Result.error("新增路由失败!");
 | 
	
		
			
				|  |  |         }
 | 
	
		
			
				|  |  | 
 | 
	
		
			
				|  |  |         return Result.success("新增路由成功!");
 | 
	
		
			
				|  |  |     }
 | 
	
		
			
				|  |  | 
 | 
	
		
			
				|  |  |     /**
 | 
	
		
			
				|  |  |      * 当外界组件通知一个已有的RouteDefine路由定义被改变时,主要就是路由定义内容被改变时,该事件被触发。
 | 
	
		
			
				|  |  |      */
 | 
	
		
			
				|  |  |     public Result onRouteDefineChanged(String serviceFlow, String packageName, String className, String path) {
 | 
	
		
			
				|  |  |         if(StringUtil.isEmpty(serviceFlow) || StringUtil.isEmpty(packageName)
 | 
	
		
			
				|  |  |                 || StringUtil.isEmpty(className) || StringUtil.isEmpty(path)) {
 | 
	
		
			
				|  |  |             logger.error("必要的入参数据不正确,请检查!");
 | 
	
		
			
				|  |  |             return Result.error("必要的入参数据不正确,请检查!");
 | 
	
		
			
				|  |  |         try {
 | 
	
		
			
				|  |  |             if (StringUtil.isEmpty(serviceFlow) || StringUtil.isEmpty(packageName)
 | 
	
		
			
				|  |  |                     || StringUtil.isEmpty(className) || StringUtil.isEmpty(path)) {
 | 
	
		
			
				|  |  |                 logger.error("必要的入参数据不正确,请检查!");
 | 
	
		
			
				|  |  |                 return Result.error("必要的入参数据不正确,请检查!");
 | 
	
		
			
				|  |  |             }
 | 
	
		
			
				|  |  |             SystemCamelContext.getDefaultCamelContext().stopRoute(serviceFlow);
 | 
	
		
			
				|  |  |             SystemCamelContext.getDefaultCamelContext().removeRoute(serviceFlow);
 | 
	
		
			
				|  |  |             this.updateClassfile(serviceFlow, packageName, className, path, Constant.ROUTE);
 | 
	
		
			
				|  |  |             // 3、===============加载到CamelContext中
 | 
	
		
			
				|  |  |             DynamicClassLoader classLoader = new DynamicClassLoader(DynamicClassLoader.class.getClassLoader());
 | 
	
		
			
				|  |  |             Class<RouteBuilder> routeBuilderClass = (Class<RouteBuilder>) classLoader.loadClass(ClassLoader.getSystemResource(Constant.EMPTY).getPath(), SystemClassMapping.getSystemClassNameMapping().get(serviceFlow + Constant.ROUTE));
 | 
	
		
			
				|  |  |             if (routeBuilderClass != null) {
 | 
	
		
			
				|  |  |                 RouteBuilder routeBuilder = routeBuilderClass.newInstance();
 | 
	
		
			
				|  |  |                 SystemCamelContext.getDefaultCamelContext().addRoutes(routeBuilder);
 | 
	
		
			
				|  |  |             }
 | 
	
		
			
				|  |  |             return Result.success("修改路由成功!");
 | 
	
		
			
				|  |  |         } catch (Exception e) {
 | 
	
		
			
				|  |  |             return Result.error("修改路由失败!");
 | 
	
		
			
				|  |  |         }
 | 
	
		
			
				|  |  |         this.updateClassfile(serviceFlow, packageName, className, path);
 | 
	
		
			
				|  |  |         return Result.success("修改路由成功!");
 | 
	
		
			
				|  |  |     }
 | 
	
		
			
				|  |  | 
 | 
	
		
			
				|  |  |     /**
 | 
	
		
			
				|  |  |      * 当外界组件通知一个已有的RouteDefine路由定义被删除时,该事件被触发。
 | 
	
		
			
				|  |  |      */
 | 
	
		
			
				|  |  |     public Result onRouteDefineDelete(String serviceFlow, String packageName, String className) {
 | 
	
		
			
				|  |  |         if(StringUtil.isEmpty(serviceFlow) || StringUtil.isEmpty(packageName)
 | 
	
		
			
				|  |  |                 || StringUtil.isEmpty(className)) {
 | 
	
		
			
				|  |  |             logger.error("必要的入参数据不正确,请检查!");
 | 
	
		
			
				|  |  |             return Result.error("必要的入参数据不正确,请检查!");
 | 
	
		
			
				|  |  |         try {
 | 
	
		
			
				|  |  |             if(StringUtil.isEmpty(serviceFlow) || StringUtil.isEmpty(packageName)
 | 
	
		
			
				|  |  |                     || StringUtil.isEmpty(className)) {
 | 
	
		
			
				|  |  |                 logger.error("必要的入参数据不正确,请检查!");
 | 
	
		
			
				|  |  |                 return Result.error("必要的入参数据不正确,请检查!");
 | 
	
		
			
				|  |  |             }
 | 
	
		
			
				|  |  | 
 | 
	
		
			
				|  |  |             SystemCamelContext.getDefaultCamelContext().stopRoute(serviceFlow);
 | 
	
		
			
				|  |  |             SystemCamelContext.getDefaultCamelContext().removeRoute(serviceFlow);
 | 
	
		
			
				|  |  |             this.deleteClassfile(serviceFlow, packageName, className, Constant.PROCESSOR);
 | 
	
		
			
				|  |  |             return Result.success("删除路由成功!");
 | 
	
		
			
				|  |  |         } catch (Exception e) {
 | 
	
		
			
				|  |  |             return Result.error("删除路由失败!");
 | 
	
		
			
				|  |  |         }
 | 
	
		
			
				|  |  |         this.deleteClassfile(serviceFlow, packageName, className);
 | 
	
		
			
				|  |  |         return Result.success("删除路由成功!");
 | 
	
		
			
				|  |  |     }
 | 
	
		
			
				|  |  | 
 | 
	
		
			
				|  |  | 
 | 
	
		
			
				|  |  |     private void createClassfile(String serviceFlow, String packageName, String className, String path) {
 | 
	
		
			
				|  |  |     private void createClassfile(String serviceFlow, String packageName, String className, String path, String type) throws MalformedURLException {
 | 
	
		
			
				|  |  |         // 1、============
 | 
	
		
			
				|  |  |         Map<String, URL> systemPathMapping = SystemPathMapping.getSystemRootPathMapping();
 | 
	
		
			
				|  |  |         URL systemRootURL = systemPathMapping.get(serviceFlow);
 | 
	
		
			
				|  |  |         if(systemRootURL == null) {
 | 
	
		
			
				|  |  |             return;
 | 
	
		
			
				|  |  |         }
 | 
	
		
			
				|  |  |         File systemClassFlowPath = new File(ClassLoader.getSystemResource(Constant.EMPTY).getPath() + "/" + serviceFlow);
 | 
	
		
			
				|  |  |         // 记录到工具类中,以便其它线程需要时进行取用
 | 
	
		
			
				|  |  |         SystemClassMapping.getSystemClassNameMapping().put(serviceFlow + Constant.ROUTE, serviceFlow + Constant.DOT + packageName + Constant.DOT + className);
 | 
	
		
			
				|  |  | 
 | 
	
		
			
				|  |  |         // 2、============开始写入class文件
 | 
	
		
			
				|  |  |         ClassFileUtil.createClassfile(systemRootURL, packageName, className, path);
 | 
	
		
			
				|  |  | 
 | 
	
		
			
				|  |  |         ClassFileUtil.createClassfile(systemClassFlowPath.toURI().toURL(), packageName, className, path);
 | 
	
		
			
				|  |  |         // 完成
 | 
	
		
			
				|  |  |         logger.info("===================" + packageName + "." + className + ".class 生成过程结束");
 | 
	
		
			
				|  |  |         logger.info("===================" + packageName + Constant.DOT + className + ".class 生成过程结束");
 | 
	
		
			
				|  |  |     }
 | 
	
		
			
				|  |  | 
 | 
	
		
			
				|  |  |     private void updateClassfile(String serviceFlow, String packageName, String className, String path) {
 | 
	
		
			
				|  |  |     private void updateClassfile(String serviceFlow, String packageName, String className, String path, String type) {
 | 
	
		
			
				|  |  |         // 1、============
 | 
	
		
			
				|  |  |         Map<String, URL> systemPathMapping = SystemPathMapping.getSystemRootPathMapping();
 | 
	
		
			
				|  |  |         URL systemRootURL = systemPathMapping.get(serviceFlow);
 | 
	
		
			
				|  |  |         if(systemRootURL == null) {
 | 
	
		
			
				|  |  |         Map<String, String> systemClassNameMapping = SystemClassMapping.getSystemClassNameMapping();
 | 
	
		
			
				|  |  |         String systemClassName = systemClassNameMapping.get(serviceFlow + type);
 | 
	
		
			
				|  |  |         if(StringUtil.isEmpty(systemClassName)) {
 | 
	
		
			
				|  |  |             return;
 | 
	
		
			
				|  |  |         }
 | 
	
		
			
				|  |  | 
 | 
	
		
			
				|  |  |         String classPath = ClassLoader.getSystemResource("").getPath() + "/" + serviceFlow + "/" + packageName + "/" + className + ".class";
 | 
	
		
			
				|  |  |         // 2、============开始写入class文件
 | 
	
		
			
				|  |  |         ClassFileUtil.updateClassfile(systemRootURL, packageName, className, path);
 | 
	
		
			
				|  |  | 
 | 
	
		
			
				|  |  |         ClassFileUtil.updateClassfile(classPath, path);
 | 
	
		
			
				|  |  |         // 完成
 | 
	
		
			
				|  |  |         logger.info("===================" + packageName + "." + className + ".class 修改过程结束");
 | 
	
		
			
				|  |  |         logger.info("===================" + packageName + Constant.DOT + className + ".class 修改过程结束");
 | 
	
		
			
				|  |  |     }
 | 
	
		
			
				|  |  | 
 | 
	
		
			
				|  |  |     private void deleteClassfile(String serviceFlow, String packageName, String className) {
 | 
	
		
			
				|  |  |     private void deleteClassfile(String serviceFlow, String packageName, String className, String type) {
 | 
	
		
			
				|  |  |         // 1、============
 | 
	
		
			
				|  |  |         Map<String, URL> systemPathMapping = SystemPathMapping.getSystemRootPathMapping();
 | 
	
		
			
				|  |  |         URL systemRootURL = systemPathMapping.get(serviceFlow);
 | 
	
		
			
				|  |  |         if(systemRootURL == null) {
 | 
	
		
			
				|  |  |         Map<String, String> systemClassNameMapping = SystemClassMapping.getSystemClassNameMapping();
 | 
	
		
			
				|  |  |         String systemClassName = systemClassNameMapping.get(serviceFlow + type);
 | 
	
		
			
				|  |  |         if(StringUtil.isEmpty(systemClassName)) {
 | 
	
		
			
				|  |  |             return;
 | 
	
		
			
				|  |  |         }
 | 
	
		
			
				|  |  |         String classPath = ClassLoader.getSystemResource("").getPath() + "/" + serviceFlow + "/" + packageName + "/" + className + ".class";
 | 
	
		
			
				|  |  | 
 | 
	
		
			
				|  |  |         // 2、============开始写入class文件
 | 
	
		
			
				|  |  |         ClassFileUtil.deleteClassfile(systemRootURL, packageName, className);
 | 
	
		
			
				|  |  |         ClassFileUtil.deleteClassfile(classPath);
 | 
	
		
			
				|  |  | 
 | 
	
		
			
				|  |  |         // 完成
 | 
	
		
			
				|  |  |         logger.info("===================" + packageName + "." + className + ".class 删除过程结束");
 | 
	
		
			
				|  |  |         logger.info("===================" + packageName + Constant.DOT + className + ".class 删除过程结束");
 | 
	
		
			
				|  |  |     }
 | 
	
		
			
				|  |  | }
 |