1 Star 1 Fork 0

Guanidine beryllium / ivr-dsl

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
贡献代码
同步代码
取消
提示: 由于 Git 不支持空文件夾,创建文件夹后会生成空的 .keep 文件
Loading...
README
Apache-2.0

IVR DSL Compiler

IVR DSL Compiler 是一个解析交互式语音应答(Interactive Voice Response,IVR)领域特定语言,并将其编译成 Java 代码的工具。运行 Compiler 工具,既可以编译一个以 IVR 语法编写的代码文件,也可以直接在命令行中输入单行 IVR 代码,并实时查看当下 IVR 程序的逻辑结构。



项目使用

IVR DSL Compiler 是在 Idea 编写的项目,并使用 maven 框架维护依赖。因此运行项目时也推荐在 Idea 下打开。

在 Idea 创建项目时选择 Get from Version Control,并输入项目的 url 可以直接将项目从 GitLab 中克隆下来,Idea 会自动加载 maven 并安装需要的依赖。在后台进程全部运行结束后,找到 src/main/java/priv/ivrdsl/Application.java 中的 main 接口即可直接运行。

image-20211218175821741

Application 提供了两种运行方式:

  • 无参数直接运行程序,Compiler 会把命令行作为输入流,在其中逐行输入 IVR 代码以逐步构建 IVR 程序。
  • 运行时添加参数,Compiler 会将参数的第一个字符串视为 IVR 脚本的存储路径,并根据该路径解析 IVR 脚本。如果脚本中有输出语句的话,可以在相关的位置找到输出。

项目包含了一个示例,IVR 脚本位于测试文件夹下:src/test/resources/test.ivr 。为 Application 添加参数 src/test/resources/test.ivr 即可运行文件解析。解析的结果包括两个位置:

  • 文件夹 src/main/java/priv/ivrdsl 中会生成 VoiceMenu.java 程序,可以直接在项目中运行、调试 IVR 程序。
  • 项目文件夹下会生成 release 文件夹(如果该文件夹原先不存在的话),其中包含 VoiceMenu.java 程序和一个由所有项目代码和依赖打包成的 jar 包。将 VoiceMenu.java 复制到其他项目中,并引入 jar 包,就可以在其他项目中运行 IVR 程序。

image-20211218180241508


脚本语法

IVR 领域特定语言是一种类似命令行语法的语言,主要结构为 <main class> [command] [command options] 形式,大小写不敏感,其中 [command] 可接受 9 种输入,以分别执行不同的操作。[command option] 的分隔符为 =option=value ,等号两边不能有空格。如果 value 中含有空格,需要将 option=value 整体用双引号 "" 包括起来,如 "-path=C:\JetBrains Projects\ivr dsl"

init

init 语句初始化一个 IVR 脚本。该语句只能出现在 IVR DSL 的开头,一个 Compiler 进程下如果已经初始化过了 IVR 脚本,再接收到 init 语句时,会抛出错误,中止解析进程。

init 语句的语法为:

Usage: init [options]
Options:
 -playback
   IVR 程序的欢迎语音
   Default: 欢迎致电Voice Menu
 -title
   IVR 程序的标题
   Default: Voice Menu

init 支持两个参数,分别为 -playback (欢迎语音)和 -title (接通电话时显示的标题),均可以省略。若某个参数省略,则 Compiler 会使用其默认值,这里就是 欢迎致电Voice MenuVoice Menu。因此一个合法的 init 语句可以是:

init
INIT -PLAYBACK=欢迎致电申国移动
init "-title=China Mobile" -playback=欢迎致电申国移动

:由于 JFrame 中输出中文字符导致乱码的问题尚未解决,-title 中输入中文会造成乱码,建议这里使用英文。)

add

add 语句向 IVR 脚本中添加一个事件,并指定触发该事件时执行的动作,其语法为:

Usage: add [options] 触发该事件的按键
Options:
 * -action
   事件触发时执行的动作
 -additions
   部分动作所需的补充信息
   Default: []
 * -event
   事件名称

其中 -action-event 参数为必选参数,如果在 add 语句中没有设置该参数,Compiler 进程会中止并抛出错误。“触发该事件的按键”为 add 语句的主参数,语句中没有 [option] 修饰的 value 即被认为是“触发该事件的按键”参数,同样为必选参数。

根据 IVR 常见的用途,add 语句对 -action 和按键可以接受的值做出了限定,其中按键值仅支持电话上的 12 个键:1,2,3,4,5,6,7,8,9,0,#,*,而 -action 支持的动作值及其含义则如下表:

ACTION 含义
1 back 返回上级菜单(不可以在主菜单下使用)
2 call 转接服务(通过 -additions 配置转接对象,触发时会播放语音“正在为您转接xxx”)
3 info 信息查询服务(通过 -additions 配置查询数据表,触发时会在指定的表中查询需要的数据)
4 hangup 结束通话
5 manual 转接人工服务
6 menu 创建菜单(客户触发该事件后进入次级菜单,为客户提供下一级的服务选项列表)
7 record 录音(如不在人工服务时段,可以让客户将需求通过录音保存下来)
8 replay 重听(重播当前菜单的选项列表)

-action 的值同样是大小写不敏感的,backBack 都被认为是返回动作 ACTION_BACK 。但忽略大小写后仍不在该列表下的动作是不被接受的,会在编译时抛出错误。

如表中所见,-additions 参数只有在动作为 infocall 时才有用,其他情况下包含 -additions 参数不会报错,但也不会有效果。而 infocall 中也可以没有 -additions 参数,不过这可能会导致运行 IVR 程序时出现不希望发生的错误,如数据表不存在等。

一个合法的 add 语句可以是:

add 1 -event=转接业务部门 -action=call -additions=业务部门
add 1 -event=转接业务部门 -action=call
add 2 -event=信息业务 -action=info -additions=tbData
add 3 -event=请挂机 -action=hangup
add -event=请挂机 -action=hangup 3
ADD -event=选择业务 -action=MENU #

remove

remove 语句删除一个事件(如果存在的话)或者一个事件树(如果该事件触发的动作是 menu)。用法为:

Usage: remove [options] 事件逻辑路径

其中事件逻辑路径设计到 IVR 事件树的概念,具体请参考 事件树:trigger-event 映射

因为 Compiler 将根节点的路径视为 "0" 而不是 "",所以要执行删除操作时,路径至少应当是长度为 2 的字符串。

如果删除的是 menu 动作的事件,则会将其下的次级菜单(以及可能的第三层菜单等)内的事件全部递归删除,这里不会有提示,因此建议在使用 status 命令查看事件树后再执行删除。

一个合法的 remove 语句可以是:

remove 0#
remove 0*59

status

status 语句不需要参数,用以查看当前事件的逻辑树。

image-20211218214028328

export

export 语句结束编译,并将当前的 IVR 逻辑转化成 Java 程序。其支持一个参数,含义为导出程序的存放路径,是 export 语句的主参数,不需要 [command option]

Usage: export [options] 项目导出路径

如果没有指定导出路径,则会在项目文件夹下创建一个名为 release 的文件夹(如果文件夹不存在的话),随后在其中生成一个表达 IVR 逻辑的 Java 程序 VoiceMenu.java 和运行程序需要的依赖包 ivrdsl-1.0.0-jar-with-dependencies.jar。若指定路径,则会在路径下创建 release 文件夹,并在其中包含上述的两个文件。

在其他项目中导入 jar 包后, VoiceMenu.java 就可以在那个项目中运行。

export 还有一个隐藏的可接受的参数 --debug,为布尔型参数,不需要 [value]。选择 --debug 参数后,Compiler 会在本项目内部生成 VoiceMenu.java,它可以直接编译运行。--debug 选项会忽略导出路径设置,不会生成 release 文件夹,不过 jar 包依然可以通过 mvn clean && mvn package 生成。该参数选项主要可用于调试。

一个合法的 export 语句可以是:

export
export ""
export "C:\JetBrains Projects"
export --debug

config

config 语句设置 IVR 运行时需要的配置。配置包括两个部分:

  • 语音合成 API:IVR 所需的语音合成,本项目使用了百度语音技术提供的 API。因此要正确运行 IVR,就需要在百度智能云平台注册并申请语音合成的 API。具体技术文档请参考百度智能云 - 语音合成config 语句提供了三个相关的参数 -appid -apikey-secretkey ,它们都可以在百度智能云平台的控制台中获取。
  • 数据库配置: add 语句 中支持的事件之一 info ,需要从数据库中查询需要的用户数据。因此对于一个查询事件,IVR 程序需要得到数据库的待查表格名、数据库驱动名、url、登录用户名、登录密码五项配置,config 语句提供了 -name-driver-url-user-passwd 五个参数用以分别配置。
Usage: config [options]
  Options:
    -apikey
      语音合成 apikey
    -appid
      语音合成 appid
    -driver
      数据库驱动
    -passwd, -password
      访问数据库的密码
    -secretkey
      语音合成 secretkey
    -name, -table
      数据库连接 待查关系表名
    -url
      数据库 url
    -user
      访问数据库的用户名

-appid-apikey-secretkey 三个配置项,每一个 IVR 程序只有一个,因此每次输入都会将之前的设置覆盖,导出前尚未设置的配置项会被设置成空串 ""

-name-driver-url-user-passwd 五个配置项具有依赖关系,一旦一个 config 语句中包括了这五个参数中的几个,但并不全包括的话,编译器会报错。一组配置可以设置一组数据库查询的信息,由于实际业务可能会需要对多个表做不同的查询,所以可以通过执行多条 config 语句来配置多个数据库连接。-name 参数值如果在之前已经出现过,则这一组配置将会覆盖先前同表的配置数据。

-name 参数也可替换成 -table-passwd 参数也可替换成 -password

API 和数据库配置分别生成于

src/main/resources/apikey.properties
src/main/resources/jdbc.xml

有需要时也可以手动修改。导出后配置文件就不可更改,需要更改配置需要重新编译 IVR 脚本。

一个合法的 config 语句可以是:

config -appid=25286979 -apikey=zQ6BhKR7zPchzhhRTikw0lwL -secretkey=RbOGe7GINgzOjvXg6fz3iUQrailYdlxe
config -table=tbDataPlan -driver=org.postgresql.Driver -url=jdbc:postgresql://117.78.10.141:8000/postgres -user=user86 -passwd=user86@bupt
config -appid=25286979
config -appid=25286979 -name=tbDataPlan -driver=org.postgresql.Driver -url=jdbc:postgresql://117.78.10.141:8000/postgres -user=user86 -password=user86@bupt

help

显示帮助。主要用于命令行逐行输入 IVR 脚本时使用。在其他命令后添加参数 -help-h? 也同样可以在命令行显示帮助。

help

一个合法的 help 语句可以是:

help
add -h
remove ?

begin & end

beginend 是一对控制符,表示被 beginend 包裹的 add 语句,其添加的事件和 begin 前的事件不属于同一层级(同一个菜单)中,而是属于下一层级(次级菜单)。更准确地说,beginend 中的事件,其事件树的绝对路径为:

begin 前的一个事件的绝对路径 + 新 add 的事件的 button

例如一个含有 begin-end 的脚本代码:

init
add 0 -event=事件样例 -action=menu
begin
    add 9 -event=子事件样例 -action=back
end

我们通过 status 查看事件树:

image-20211219123542861

显而易见,begin-end 中的事件“子事件样例”被设置成了“事件样例”的子事件,其绝对路径 "009" = "00" + "9"

当然,begin-end 也是可以嵌套的,可设计多层结构,例如:

init
add 0 -event=投诉 -action=menu
begin
    add 0 -event=投诉 -action=menu
    begin
        add 0 -event=请挂机 -action=hangup
    end
end

image-20211219124114284

从逻辑上来说,begin-end 是提供给 menu 使用的,每当添加了一个 menu 动作的事件后,建议在下面一行立即使用 begin-end 设计 menu 事件的子树。

Compiler 不会在编译时对 begin-end 的合法性作出检查,错误使用 begin-end 时,Compiler 可能并不会报错,但绝大多数情况执行结果会不正常,具体情况有:

  1. add 一个 menu 事件后,执行若干 removestatus 等非 add 语句(对于 remove 语句,要求其没有将 menu 事件 remove 掉),这不会造成任何影响,使用 begin 后依旧可以对 menu 事件的子树进行设计。
init
add 1 -event=test -action=manual
add 0 -event=父事件 -action=menu
status
remove 01
begin
	add 9 -event=子事件 -action=back
end

:heavy_check_mark: image-20211219130352979

  1. add 一个 menu 事件后,又添加了若干 add 语句,这个时候将无法再编辑 menu 事件的子树,即使通过 remove 将后面添加的所有事件删除,都不能完成需求。
init
add 0 -event=父事件 -action=menu
add 1 -event=test -action=manual
begin
	add 9 -event=子事件 -action=back
end

:heavy_exclamation_mark: image-20211219130739230

init
add 0 -event=父事件 -action=menu
add 1 -event=test -action=manual
remove 01
begin
	add 9 -event=子事件 -action=back
end

:heavy_exclamation_mark: image-20211219131057650

  1. add 一个 menu 事件后,直到结束都没有对 menu 事件的子树进行设计,此时如果触发 menu 事件,IVR 程序依然会进入次级菜单,但该菜单中没有任何选项可选,包括 back 动作,所以 IVR 程序进入次级菜单后将无法离开,只能挂断电话。
init
add 0 -event=test -action=menu
export --debug

:heavy_exclamation_mark: image-20211219131427723

  1. add 一个非 menu 事件后使用 begin-end ,这并不会使得触发该事件后进入次级菜单,而只会播放次级菜单的选项语音,随后继续完成该事件的动作,如 back 回到上级菜单,replay 重播当前菜单语音,而其他动作均会结束通话。
init
add 1 -event=test -action=manual
begin
	add 9 -event=子事件 -action=back
end
export --debug

:heavy_exclamation_mark: image-20211219131655862

  1. begin-end 在还没有创建过父节点时就出现。
init
begin
	add 0 -event=test -action=hangup
end

:heavy_exclamation_mark: image-20211219132135290

init
add 0 -event=父节点 -action=menu
begin
	begin
		add 0 -event=test -action=hangup
	end
end

:heavy_exclamation_mark: image-20211219132315767

很显然,没有哪个按键是“$”,这个子事件永远无法被到达。

  1. beginend 不成对,一般不会报错,但事件的逻辑树就未必是您想象的那样了。
init
add 0 -event=父节点 -action=menu
begin
	add 0 -event=test -action=hangup
add 1 -event=并不是第一层节点 -action=menu
begin
	add 0 -event=test -action=hangup
end

:heavy_exclamation_mark: image-20211219132701392

:warning: 由此可见,为了确保 IVR 设计正确,最好在每创建一个 menu 事件后就立刻使用 begin-end 编辑其子树,并保持良好的缩进习惯,请不要依赖 remove 删除其他碍事的事件。当然,写好一个文件并从文件编译绝对是一个比命令行更可靠的选择。

示例程序

IVR 脚本:test.ivr

image-20211219135533863

image-20211219135356898

生成程序:VoiceMenu.java

image-20211219135640924


运行 IVR 程序

IVR DSL Compiler 生成的 VoiceMenu.java 中为用户留下了一个接口方法 queryCase,它的类型为使用 @FunctionalInterface 注解的接口类 QueryCaseImpl。该接口用于配置数据库查询的条件。

举个例子,某个 IVR 程序根据用户的手机号码查询用户流量套餐和话费账单,这两个信息可以来自两个不同的查询业务,也就是不同的两个 info 动作,但条件一般都是一样的,也就是:

QueryCaseImpl queryCase = () ->
        "where phone_number = getUserPhoneNumber()";

也有的程序可能需要监听用户电话键盘上的按键输入,如考生查成绩需要在电话键盘上输入准考证号,这时候 queryCase 就可以被设计为:

QueryCaseImpl queryCase = () ->
        "where id = actionListened(ActionEvent event)";

这里的方法 getUserPhoneNumber()actionListened(ActionEvent event) 可以来自第三方,或者由用户自己编写。

IVR DSL Compiler 默认 queryCase 返回的是空串 "",即无条件,最终查询到的结果将是表中的第一行。

IVR 程序执行的实际查询语句为:

select * from "$tableName" $queryCase

$tableName 就是 add 语句 选择 action=info 时,参数 additions 设置的表名,由双引号引起,因此需要注意表名的大小写;而 $queryCase 则是由 queryCase() 方法确定。查询将表的第一列作为客户称呼,而第二列往后作为查询信息输出,因此在数据 ETL 时也应当注意不要在被查询表格中引入不需要的列项。


数据结构设计

事件树

IVR 的业务逻辑呈现为树状,具体表现为以初始状态“0”为树的根节点,每一个 event 都是“0”的子节点。如果一个 eventactionmenu,则意味着在该事件节点下存在另一组子节点。它们组成了 IVR 业务的一个次级菜单,在客户按下 menu 对应的按键后进入。而如果 action 不是 menu,那么这个 event 就已经成为了叶子结点。

对于这个逻辑树,我们令根节点的绝对路径为“0”。用户通过按键到达一个事件节点,则这个事件节点相对根节点的路径就是用户按键的顺序。因此可以将每一个事件节点的绝对路径表示为 "0" + 用户到达该节点的按键顺序

因此在 Compiler 中设计有一个数据结构 IvrMap,其中的一个成员变量为 Map<String, List<String>> 类型的 HashMap ,用以记录每一个事件节点绝对路径和事件信息(包括事件 event,动作 action 和补充信息 additions)的映射关系,我们称之为 trigger-event映射),以此表示 IVR 脚本的业务逻辑。

事件节点

一个事件由事件名(需符合 Java 命名规则)、语音播放中使用的事件名、触发按键、子事件集合、可能需要的补充信息、触发动作、事件结束后的处理这样一组变量就可以完全描述。

其中事件名和语音播放事件名之间一一对应,可以由一个哈希表 event2VoiceTextMap 表达。而事件名与其他几项共同描述一个事件,我们可以将其组成一个 JavaBean ,即 EventBean

枚举

动作 action ,按键 button 和命令 command 都存在一个可选的范围,因此分别为它们设计了枚举类,全部存放在类 EnumBean 内。并由于 valueOf 不可重载,另外设计了一个 getByCode 方法完成由字符串查找枚举值的工作。

语法解析

语法解析使用了 JCommander 提供的接口,将 DSL 设计成类似命令行命令的格式,以便调用接口完成解析。所有语句的解析工作都在 Commands 类中完成。

其他数据结构

一个事件下属子事件的按键集合:

List<String> possibleOptionList

事件对象名与按键路径的映射表:

HashMap<String, EventBean> event2TriggerMap

事件对象名与语音输出名称的映射表:

HashMap<String, String> event2VoiceTextMap

这些变量贯穿于整个 IVR 运行过程,且考虑到每一个 IVR 进程只需要一个,所以设置成 static 的全局静态变量,提供给整个程序使用,它们存放在 GlobalVariableBean 中。


项目结构

IVR DSL Compiler 大致上分为四个层次

分层 涉及文件夹 作用
终端显示层 priv.ivrdsl.view 配置 IVR 程序的 UI 界面
Service层 priv.ivrdsl.service 实现 IVR 解析,脚本运行逻辑等具体业务需求
Manager层 priv.ivrdsl.controller 处理配置文件,数据库查询等通用业务需求
priv.ivrdsl.util 为Service层提供工具类
Model层 priv.ivrdsl.model 项目数据结构
priv.ivrdsl.impl 项目接口
priv.ivrdsl.exception 项目自定义异常类型

而文件夹中每个类的具体作用,请参考 Javadoc 文档。


项目测试

项目为IVR DSL Compiler 的 Service 层,Manager 层和 Model 层的方法做了单元测试,包括预期异常测试和各工具类的测试,共有 18 个测试方法, 64 个测试案例。

image-20211218212223188

排除掉 priv.ivrdsl.view 包,接口类 Applicationexport --debug 生成的结果 VoiceMenu 以及 IVR 脚本程序才会用到的 EventBeanEventLogic 类后,测试代码覆盖 83% 的类,77% 的代码行,对项目中创建的方法完成了基本的测试。

image-20211218212311400

image-20211219005948060

image-20211219010135675

image-20211219010224321

image-20211219010316147

image-20211219010417731

完整的覆盖率报告:coverage


接口文档

通过以下命令生成 Javadoc 文档:

mvn clean -f pom.xml
mvn compile -f pom.xml
mvn lombok:delombok -f pom.xml
mvn javadoc:javadoc -f pom.xml

image-20211219003749827

image-20211219003433430

image-20211219003519994

image-20211219005033176

image-20211219003914042

image-20211219003637200

image-20211219003637201

image-20211219003701916

image-20211219004049153

完整的 Javadoc 文档:apidocs

Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright 2021 Guanidine Beryllium Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

简介

暂无描述 展开 收起
Java 等 4 种语言
Apache-2.0
取消

发行版

暂无发行版

贡献者

全部

近期动态

加载更多
不能加载更多了
Java
1
https://gitee.com/guapiii/ivr-dsl.git
git@gitee.com:guapiii/ivr-dsl.git
guapiii
ivr-dsl
ivr-dsl
main

搜索帮助