在开源中国里,不知道大家有没有留意到一个Java开源组织——Dromara

这个组织是由Apache ShenYu(前身是Soul网关)的作者创立,多位Java开源作者参与的一个Java开源组织。

在开源中国社区,很多Java开源作者都是各自为战,独立运营项目。Domara组织的诞生就是为了联合Java开源的力量,共建社区,资源共享,共同推行中国Java开源事业的发展。

目前Dromara社区拥有几个GVP项目,和一些Star数量很高的项目。这些开源项目社区都很活跃,每一个都是能提高工作效率的精品开源作品。下面就来盘点下Dromara组织其中的几个开源项目,都是非常实用的工具,用好这些将会让你的生产效率大大提升!今天推荐给大家,希望对你有所帮助。



1

Sa-Token

首先我要介绍的是Sa-Token,可能是史上功能最全的轻量级 Java 权限认证框架。

简单的使用方式,丰富的特性,强大的功能,你有什么理由拒绝?


  • 官方网站:http://sa-token.dev33.cn/
  • Gitee托管仓库:https://gitee.com/dromara/sa-token
  • Github托管仓库:https://github.com/dromara/Sa-Token


这几款国产开源项目!是真滴牛逼..._git

Sa-Token 是一个轻量级 Java 权限认证框架,主要解决:登录认证、权限认证、Session会话、单点登录、OAuth2.0、微服务网关鉴权等一系列权限相关问题。

Sa-Token 的 API 设计非常简单,有多简单呢?以登录认证为例,你只需要:


// 在登录时写入当前会话的账号id
StpUtil.login(10001);

// 然后在需要校验登录处调用以下方法:
// 如果当前会话未登录,这句代码会抛出 `NotLoginException` 异常
StpUtil.checkLogin();


至此,我们已经借助 Sa-Token 完成登录认证!


此时的你小脑袋可能飘满了问号,就这么简单?自定义 Realm 呢?全局过滤器呢?我不用写各种配置文件吗?


没错,在 Sa-Token 中,登录认证就是如此简单,不需要任何的复杂前置工作,只需这一行简单的API调用,就可以完成会话登录认证!

另外,关注公号“终码一生”,回复关键词“资料”,获取视频教程和最新的面试资料!

当你受够 Shiro、SpringSecurity 等框架的三拜九叩之后,你就会明白,相对于这些传统老牌框架,Sa-Token 的 API 设计是多么的简单、优雅!

权限认证示例(只有具备 user:add 权限的会话才可以进入请求)

@SaCheckPermission("user:add")
@RequestMapping("/user/insert")
public String insert(SysUser user) {
// ...
return "用户增加";
}

将某个账号踢下线(待到对方再次访问系统时会抛出NotLoginException异常)

// 使账号id为 10001 的会话强制注销登录
StpUtil.logoutByLoginId(10001);

在 Sa-Token 中,绝大多数功能都可以 一行代码 完成:

StpUtil.login(10001); // 标记当前会话登录的账号id
StpUtil.getLoginId(); // 获取当前会话登录的账号id
StpUtil.isLogin(); // 获取当前会话是否已经登录, 返回true或false
StpUtil.logout(); // 当前会话注销登录
StpUtil.logoutByLoginId(10001); // 让账号为10001的会话注销登录(踢人下线)
StpUtil.hasRole("super-admin"); // 查询当前账号是否含有指定角色标识, 返回true或false
StpUtil.hasPermission("user:add"); // 查询当前账号是否含有指定权限, 返回true或false
StpUtil.getSession(); // 获取当前账号id的Session
StpUtil.getSessionByLoginId(10001); // 获取账号id为10001的Session
StpUtil.getTokenValueByLoginId(10001); // 获取账号id为10001的token令牌值
StpUtil.login(10001, "PC"); // 指定设备标识登录,常用于“同端互斥登录”
StpUtil.logoutByLoginId(10001, "PC"); // 指定设备标识进行强制注销 (不同端不受影响)
StpUtil.openSafe(120); // 在当前会话开启二级认证,有效期为120秒
StpUtil.checkSafe(); // 校验当前会话是否处于二级认证有效期内,校验失败会抛出异常
StpUtil.switchTo(10044); // 将当前会话身份临时切换为其它账号

即使不运行测试,相信您也能意会到绝大多数 API 的用法。

更多请参考:https://gitee.com/dromara/sa-token



2

Forest

一款极大程度解放你的Http接入工作的强大Http客户端框架。

Http协议很复杂吗?那是因为你还没有使用过Forest,虽然业内有很多其他优秀的Http客户端,但是你错过了Forest,将会错过一大片优雅美丽的森林。


  • 官方网站:http://forest.dtflyx.com
  • Gitee托管仓库:https://gitee.com/dromara/forest
  • Github托管仓库:https://github.com/dromara/forest


这几款国产开源项目!是真滴牛逼..._git_02

Forest 是一个开源的 Java HTTP 客户端框架,用来访问第三方服务 RESTful 接口。​

它能够将 HTTP 的请求参数绑定到 Java 接口上,之后调用 Java 接口就等于在发送 HTTP 请求。一切面向于接口。

很多公司需要在 Java 后台调用许多第三方 HTTP 接口,比如微信支付、友盟等等第三方平台。

公司内部还有很多服务是用世界最好语言写的,接口自然也只能通过 HTTP 接口来调用。于是日积月累下来,在 Java 代码中就有许许多多各式各样的 HTTP 调用接口,而且调用方式也不统一,有 HttpClient 写的、有 OkHttp 写的、有自己包装的,光公司内部不同人包装的 HTTP 工具类就有两三种。

而且 url 基本写死在代码中,很难维护,不同接口又有不同的参数传输方式,有 GET 、有 POST,有 JSON 传输的、有 XML 传输的。当有一个接口需要修改,完了,光找到代码在什么地方就要花半天时间。

而 Forest 能帮助我很好地将 HTTP 代码和业务代码解耦开来,请求调用者不必关心 HTTP 相关的细节。

自动拼接 HTTP 的各种参数

包括 URL、Header、Body 等等参数都能依靠 Java 注解来声明。

这里就举一个高德地图的栗子,来看看 Forest 是如何优雅的声明 HTTP 请求接口的:

/**
* 高德地图服务客户端接口
*/
@BaseRequest(baseURL = "http://ditu.amap.com")
public interface Amap {

/**
* 根据经纬度获取详细地址
* @param longitude 经度
* @param latitude 纬度
* @return 详细地址信息
*/
@Get("/service/regeo")
Map getLocation(@Query("longitude") String longitude, @Query("latitude") String latitude);

}

... ...

Amap amap = Forest.client(Amap.class);
// 发送请求查询经纬度
Map locationInfo = amap.getLocation("32.1242832", "56.3290434");


自动 JSON 和 XML 转换

其实,我们处理 HTTP 的工作时,除了浪费在组装各种请求参数外,大部分时间都花了在序列化和反序列化各种格式的数据上,如 JSON 和 XML。

以前用 HttpClient,这些重复的机械性工作都要自己来搞,很是麻烦。另外,关注公号“终码一生”,回复关键词“资料”,获取视频教程和最新的面试资料!

用 Forest 就方便多了,比如要 POST 一个 JSON 对象,直接挂个 @JSONBody 就好了,就是这么清爽。


// 直接将 MyUserInfo 转换成 JSON
// 将服务端响应返回的 JSON 数据转换成 Result<Boolean> 类对象
@Post("http://localhost:8080/user")
Result<Booelean> createUser(@JSONBody MyUserInfo user);


和 Retrofit 以及 Feign 的比较

之前也用过这两款开源框架,都很强大,但各有优缺点。

Retrofit 的主要的问题时和 OkHttp 绑的太死,有些功能被 OkHttp 限制住了,比如我想处理 Get 请求传输 Body 数据这种非标准的 HTTP 请求就很难办到,而 Forest 可以随意切换 OkHttp 和 HttpClient 作为后端,需要用哪个时用哪个。

Retrofit 注解的丰富性也不如 Forest,比如要实现 HTTP 网络代理就要自己去写代码,而 Forest 提供了 @HTTPProxy 注解,设置一下就完事了。

如果要扩展自定义注解都是基于 OkHttp 的拦截器,不是特别方便,而 Forest 拦截器要比 OkHttp 的方便很多,提供 onInvoke, beforeExecute, onSccuess, onError 等回调方法,等于把一个请求的生老病死都涵盖了。

而 Feign 的问题则是和 Spring 绑的太紧,很多功能需要依赖 Spring 去做,太加了 Spring 相关包又太重了。

Forest 的核心包基本涵盖了所有 HTTP 所需功能和注解,不依赖 Spring,要轻量许多,但又不失方便性。

更多请参考:https://gitee.com/dromara/forest



3

LiteFlow

一款超轻量,快速,稳定,可编排的组件式流程引擎/规则引擎。

解耦复杂系统的神器!如果你正在为设计一个复杂系统感到头痛,那么LiteFlow是你不二的选择,超低的学习成本,强大的编排功能,让你的系统变得更优雅!


  • 官方网站:https://yomahub.com/liteflow
  • Gitee托管仓库:https://gitee.com/dromara/liteFlow
  • Github托管仓库:https://github.com/dromara/liteflow


这几款国产开源项目!是真滴牛逼..._java_03

Liteflow为解耦复杂逻辑而生,如果你要对复杂业务逻辑进行新写或者重构,用liteflow最合适不过。它是一个轻量,快速的组件式流程引擎框架,组件编排,帮助解耦业务代码,让每一个业务片段都是一个组件。

使用Liteflow,你需要去把复杂的业务逻辑按代码片段拆分成一个个小组件,并定义一个规则流程配置。这样,所有的组件,就能按照你的规则配置去进行复杂的流转。同时Liteflow支持规则文件的热加载,即时完成修改生效。并提供多种持久化规则的方式的扩展。

使用LiteFLow,三大核心概念是组件,规则和上下文。

你需要这么像这样去定义你的组件

//这里普通组件
@LiteflowComponent(id = "a", name = "组件A描述")
public class ACmp extends NodeComponent {
@Override
public void process() {
//do your business
}
}

//这是条件组件
@LiteflowComponent(id = "b", name = "组件B描述")
public class BCondCmp extends NodeCondComponent {
@Override
public String processCond() {
//do your business
return "e";
}
}

然后去定义你的规则,LiteFlow支持xml,yml,json三种格式,这里以xml形式为例

<?xml version="1.0" encoding="UTF-8"?>
<flow>
<chain name="chain1">
<then value="a,b(c|d|e)"/> <!-- c为路由组件,用来路由到c,d,e -->
<then value="sub_chain"/> <!-- 子流程 -->
</chain>

<chain name="sub_chain">
<when value="f,g,h"/> <!-- when代表并行 -->
<then value="j,k" /> <!-- then代表串行 -->
</chain>
</flow>

这样你的系统就会按照规则文件定义的方式,去执行你的业务组件。是不是很简单。

那规则文件定义在哪呢,LiteFlow并不限定你的规则文件来源,可以是本地文件,可以是注册中心,可以是任何数据库。LiteFlow提供了非常自由的接口供你扩展,你想存储在哪里都行。改变规则文件,即可实时刷新你的规则流程!如果你想做一个灵活度高,伸缩性强的系统,LiteFlow是不是非常适合呢。

LiteFlow为每一个请求都去开辟申请了一个Slot,你可以理解为上下文,所有的组件共享这个Slot。你可以在任意组件里通过对Slot的访问来获得任意数据,也可以存放任意数据。你也可以扩展Slot,自定义这个slot的属性。

@LiteflowComponent(id = "a", name = "组件A描述")
public class ACmp extends NodeComponent {
@Override
public void process() {
Slot slot = this.getSlot();
//通过对slot的getData,setData,或者存取你自己扩展的slot属性
}
}

正因为有Slot的存在,才抹平了组件与组件之间的差异性,使得每一个业务组件之间无强依赖。这样的设计,就可以让你的系统高度自由化,组件复用,组件调换顺序得以方便的实现!

LiteFlow还支持2种脚本语言的接入,目前支持Groovy和QLExpress两种脚本语言。你可以在xml/yml/json定义脚本,以下以xml为例:

<?xml version="1.0" encoding="UTF-8"?>
<flow>
<nodes>
<node id="s1" name="普通脚本" type="script">
<![CDATA[
def a=3;
def b=2;
slot.setData("s1",a*b);
]]>
</node>

<node id="s2" name="条件脚本" type="cond_script">
<![CDATA[
count = slot.getData("count");
if(count > 100){
return "a";
}else{
return "b";
}
]]>
</node>
</nodes>

<chain name="chain1">
<then value="a,b,c,s1"/>
</chain>

<chain name="chain2">
<then value="d,s2(a|b)"/>
</chain>
</flow>

那么在什么地方定义是哪种语言的脚本呢,LiteFlow的脚本功能是一个SPI机制的实现,你依赖了哪个脚本包,就以哪种脚本的方式执行。

有了脚本语言的支持,连业务代码是不是都可以热部署了?香不香?

LiteFlow的功能远不止这些,想了解更多,请到官网文档去查看了解。相信LiteFlow会让你感到优雅和惊艳。

更多请参考:https://yomahub.com/liteflow



4

JPom

一款简而轻的低侵入式在线构建、自动部署、日常运维、项目监控软件

中小公司团队DevOps的福音!轻量且强大,你不试试?

  • 官方网站:https://jpom.io/
  • Gitee托管仓库:https://gitee.com/dromara/Jpom
  • Github托管仓库:https://github.com/dromara/Jpom


这几款国产开源项目!是真滴牛逼..._git_04

Jpom 是一款简而轻的低侵入式在线构建、自动部署、日常运维、项目监控软件

在中小公司或者团队中传统项目部署、运维流程通用的方法是登录服务器上传新的项目包,执行相应命令管理,如果管理多个项目则重复操作上述步骤。另外,关注公号“终码一生”,回复关键词“资料”,获取视频教程和最新的面试资料!

市面上有很许多 DevOps 软件但是这些软件基本都会是难上手,重依赖。Jpom 则是针对中小公司或者团队设计的一款低侵入,轻依赖的一款轻量级的 DevOps 软件。


项目主要功能及特点


  1. 创建、修改、删除项目、Jar包管理
  2. 实时查看控制台日志、备份日志、删除日志、导出日志
  3. 在线构建项目发布项目一键搞定
  4. 多节点管理、多节点自动分发
  5. 在线  SSH 终端,并且有终端日志和禁用命令
  6. 实时监控项目状态异常自动报警
  7. cpu、ram 监控、导出堆栈信息、查看项目进程端口、服务器状态监控
  8. 多用户管理,用户项目权限独立(上传、删除权限可控制),完善的操作日志
  9. 系统路径白名单模式,杜绝用户误操作系统文件
  10. 在线管理 Nginx 配置文件、ssl 证书文件


一键安装(Linux)(推荐)


插件端

如果服务端也需要被管理,在服务端上也需要安装插件端

安装的路径位于执行命令目录(数据、日志存放目录默认位于安装路径,如需要修改参考配置文件:extConfig.yml )

yum install -y wget && wget -O install.sh https://dromara.gitee.io/jpom/docs/install.sh && bash install.sh Agent

备用地址
yum install -y wget && wget -O install.sh https://cdn.jsdelivr.net/gh/dromara/Jpom/docs/install.sh && bash install.sh Agent

支持自动安装jdk环境
yum install -y wget && wget -O install.sh https://dromara.gitee.io/jpom/docs/install.sh && bash install.sh Agent jdk

启动成功后,插件端的端口为 2123


服务端

安装的路径位于执行命令目录(数据、日志存放目录默认位于安装路径,如需要修改参考配置文件:extConfig.yml )

如果需要修改数据、日志存储路径请参照 extConfig.yml 文件中 jpom.path 配置属性

yum install -y wget && wget -O install.sh https://dromara.gitee.io/jpom/docs/install.sh && bash install.sh Server

备用地址
yum install -y wget && wget -O install.sh https://cdn.jsdelivr.net/gh/dromara/Jpom/docs/install.sh && bash install.sh Server

支持自动安装jdk环境
yum install -y wget && wget -O install.sh https://dromara.gitee.io/jpom/docs/install.sh && bash install.sh Server jdk

支持自动安装jdk和maven环境
yum install -y wget && wget -O install.sh https://dromara.gitee.io/jpom/docs/install.sh && bash install.sh Server jdk+mvn

启动成功后,服务端的端口为 2122 访问管理页面 例如http://localhost:2122/

特别提醒:一键安装的时候注意执行命令不可在同一目录下,即Server端和Agent端不可安装在同一目录下


如无法访问,检查下是否开启了防火墙systemctl status firewalld,如状态显示为绿色Active: active (running)可临时关闭防火墙systemctl stop firewalld,然后重启防火墙firewall-cmd --reload(建议仅测试环境下使用,生产环境下慎用) 如关闭防火墙后仍无法访问,并且使用的是云服务器,还需要到云服务器管理后台中关闭防火墙


更多请参考:https://gitee.com/dromara/Jpom



5

Cubic

首先我要介绍的是Cubic,一站式问题定位平台!线程栈监控、线程池监控、动态arthas命令集、依赖分析等等等,强不强大,香不香?

  • 官方网站:https://cubic.jiagoujishu.com/
  • Gitee托管仓库:https://gitee.com/dromara/cubic
  • Github托管仓库:https://github.com/dromara/cubic


这几款国产开源项目!是真滴牛逼..._spring_05


介绍

一站式问题定位平台,还在为线上问题而烦恼吗?

线程栈监控、线程池监控、动态arthas命令集、依赖分析等等等,致力于应用级监控,帮助开发人员快速定位问题。

有什么特性

1、兼容性:整体监控不管你是IDC、ECS、Docker部署,都可完美兼容

2、易用:无需任何配置,开箱即用,基于agent无侵入接入,升级应用端无感知

3、强大:支持对应用的基础监控、堆栈监控、线程池监控等等

4、高扩展:提供良好的扩展接口,给你自主选择

使用后能带来怎样工作效率上的提升:

  • 权限认证
  • 实例列表
  • 实例心跳监测
  • 实例基础信息采集
  • 服务器信息采集
  • JVM基础信息采集
  • 启动参数采集
  • 依赖包检测
  • arthas动态命令集支持
  • 历史线程栈获取(分钟级)
  • 实时线程栈获取
  • 线程池监控


功能展示 

实例中心(展示当前实例信息)


这几款国产开源项目!是真滴牛逼..._spring_06

基础信息(点击实例-》展示当前实例的基础信息)

这几款国产开源项目!是真滴牛逼..._spring_07


依赖监控(点击实例-》展示当前实例的依赖包信息)

这几款国产开源项目!是真滴牛逼..._git_08


Arthas命令操作

这几款国产开源项目!是真滴牛逼..._git_09


线程池监控

这几款国产开源项目!是真滴牛逼..._git_10


实时线程栈

这几款国产开源项目!是真滴牛逼..._git_11


历史线程栈

这几款国产开源项目!是真滴牛逼..._spring_12


更多请参考:https://gitee.com/dromara/cubic



6

Sureness

丢掉Shiro吧,也别再用Spring Security了,简单易用多语言多框架支持,基于RESTAPI的强大国产鉴权框架,效率神器!


  • 官方网站:https://usthe.com/sureness
  • Gitee托管仓库:https://gitee.com/dromara/sureness
  • Github托管仓库:https://github.com/dromara/sureness


这几款国产开源项目!是真滴牛逼..._git_13

介绍

在主流的前后端分离架构中,如何通过有效快速的认证鉴权来保护后端提供的REST API变得尤为重要。对现存框架,不原生支持RESTful的Apache Shiro, 还是深度绑定Spring的Spring Security,或多或少都不是我们的理想型。

于是乎Sureness诞生了,我们希望能解决这些,提供一个面向REST API,无框架依赖,可以动态修改权限,多认证策略,更快速度,易用易扩展的认证鉴权框架。


特性

Sureness 是我们在深度使用 Apache Shiro 之后,吸取其优点全新设计开发的一个认证鉴权框架

  • 面向 REST API 的认证鉴权,基于 RBAC (用户-角色-资源)主要关注于对 API 的安全保护
  • 无特定Web框架依赖,开箱即用(已有 Spring Boot,Quarkus,Javalin,Ktor,Micronaut,Jfinal,Solon 等集成样例)
  • 支持动态修改权限配置(动态修改配置每个 API 谁有权访问)
  • 支持 Websocket ,主流 HTTP 容器 Servlet , JAX-RS,Spring Reactive
  • 支持多种认证策略, JWT, Basic Auth, Digest Auth ... 可扩展自定义认证方式
  • 基于改进的字典匹配树拥有的高性能
  • 良好的扩展接口, 样例和文档助急速理解扩展使用Sureness的低配置,易扩展,不耦合其他框架,希望能对系统多场景快速安全的保护


对比


Sureness

Shiro

Spring Security

多框架支持

支持

需改动支持

不支持

REST API

支持

需改动支持

支持

Websocket

支持

不支持

不支持

过滤链匹配

优化的字典匹配树

ant匹配

ant匹配

注解支持

支持

支持

支持

Servlet

支持

支持

支持

JAX-RS

支持

不支持

不支持

权限动态修改

支持

需改动支持

需改动支持

性能速度

较快

较慢

较慢

学习曲线

简单

简单

陡峭


更多请参考:https://gitee.com/dromara/sureness



7

TLog

十分钟即可接入,一款神器的日志框架,支持众多的框架和主流RPC,让你的日志马上升级,变得可追溯!

  • 官方网站:http://yomahub.com/tlog
  • Gitee托管仓库:https://gitee.com/dromara/TLog
  • Github托管仓库:https://github.com/dromara/TLog


这几款国产开源项目!是真滴牛逼..._java_14

介绍

随着微服务盛行,很多公司都把系统按照业务边界拆成了很多微服务,在排错查日志的时候。因为业务链路贯穿着很多微服务节点,导致定位某个请求的日志以及上下游业务的日志会变得有些困难。

这时候很多童鞋会开始考虑上SkyWalking,Pinpoint等分布式追踪系统来解决,基于OpenTracing规范,而且通常都是无侵入性的,并且有相对友好的管理界面来进行链路Span的查询。

但是搭建分布式追踪系统,熟悉以及推广到全公司的系统需要一定的时间周期,而且当中涉及到链路span节点的存储成本问题,全量采集还是部分采集?如果全量采集,就以SkyWalking的存储来举例,ES集群搭建至少需要5个节点。这就需要增加服务器成本。况且如果微服务节点多的话,一天下来产生几十G上百G的数据其实非常正常。如果想保存时间长点的话,也需要增加服务器磁盘的成本。

当然分布式追踪系统是一个最终的解决方案,如果您的公司已经上了分布式追踪系统,那TLog并不适用。另外,关注公号“终码一生”,回复关键词“资料”,获取视频教程和最新的面试资料!

TLog提供了一种最简单的方式来解决日志追踪问题,它不收集日志,也不需要另外的存储空间,它只是自动的对你的日志进行打标签,自动生成TraceId贯穿你微服务的一整条链路。并且提供上下游节点信息。适合中小型企业以及想快速解决日志追踪问题的公司项目使用。

为此TLog适配了三大日志框架,支持自动检测适配。支持dubbo,dubbox,spring cloud三大RPC框架,更重要的是,你的项目接入TLog,可能连十分钟就不需要 :)

项目特性

目前TLog的支持的特性如下:

  • 通过对日志打标签完成轻量级微服务日志追踪
  • 提供三种接入方式:javaagent完全无侵入接入,字节码一行代码接入,基于配置文件的接入
  • 对业务代码无侵入式设计,使用简单,10分钟即可接入
  • 支持常见的log4j,log4j2,logback三大日志框架,并提供自动检测,完成适配
  • 支持dubbo,dubbox,springcloud三大RPC框架
  • 支持Spring Cloud Gateway和Soul网关
  • 适配HttpClient和Okhttp的http调用标签传递
  • 支持三种任务框架,JDK的TimerTask,Quartz,XXL-JOB
  • 支持日志标签的自定义模板的配置,提供多个系统级埋点标签的选择
  • 支持异步线程的追踪,包括线程池,多级异步线程等场景
  • 几乎无性能损耗,快速稳定,经过压测,损耗在0.01%


接入方式

这几款国产开源项目!是真滴牛逼..._spring_15


使用后你的每行日志会变成以下格式

这几款国产开源项目!是真滴牛逼..._java_16


更多请参考:https://gitee.com/dromara/TLog


8

最后

其实Dromara开源社区还有最知名的项目(也是star最多的项目)——Hutool,那我为什么不写呢。我想说,这框架普及率太高了,几乎是可以取代apache common包,guava包的存在,程序员应该每个人都用下。一篇文章不足以写出Hutool这个框架的全面性和强大。

以上推荐的开源项目,也是Dromara Java社区里的精品项目,很多都已经是GVP项目了,用好这些框架/工具,真的能让工作效率大大提升。


PS:防止找不到本篇文章,可以收藏点赞,方便翻阅查找哦。


--- END ---