开放数据索引命名(ODIN)标识符技术规范 -- PPk开放技术社区 ( PPk Public Group ) 2020-05-05 http://ppkpub.org/ 1、ODIN简介 ODIN是Open Data Index Name即“开放数据索引命名”的缩写。广义上,ODIN 是指在对等网络环境下标识和交换数据内容索引的一种开放性系统,它遵从URI(统一资源标识符) 规范,并为基于数字加密货币区块链(Blockchain)的自主开放、安全可信的数据内容管理和价值权益管理提供了一个可扩展的框架。它包括4 个组成要素:标识符、解析系统、 元数据和规则(Policies) 。狭义上,ODIN 是指对等、可信地标识任何数据内容对象的一种永久性标识符。 2、ODIN根标识的技术方案 参考了XCP和OMNI等数字加密资产协议的技术原理,ODIN根标识的实现是通过将特定消息数据按比特币协议规范进行特定编码后,作为比特币交易广播到比特币网络上存入区块链。 每个ODIN根标识信息包括以下特性: (a)一个比特币源地址(必须是1打头的P2PK或P2PKH对应地址,对应ODIN消息生成者。建议输入列表里使用单一的私钥签名,如果输入列表里有多个地址私钥签名,以排在第一个的P2PK或P2PKH地址作为注册者) (b)一个比特币目的地址(必须是1打头的P2PK或P2PKH对应地址,对应受ODIN消息指向的目标个体,当具体消息定义不需要指定目标个体时,该地址可以为空) (c)若干个1-of-N多重签名输出比特币地址公钥,按照ODIN数据包格式定义编码生成,具体定义如下: 第一条1-of-N多重签名输出中, 第一个公钥固定是发送者的,第二个公钥固定是ODIN特征公钥(33个字节公钥,16进制HEX字符串"0320a0de360cc2ae8672db7d557086a4e7c8eca062c0a5a4ba9922dee0aacf3e12",对应地址为1PPkPubRnK2ry9PPVW7HJiukqbSnWzXkbi),可选的第三个公钥开始为具体ODIN消息内容编码而成(格式为:第一个字节为取值3,第二个字节为后续有效数据长度L,第3个字节开始从ODIN消息内容中按顺序每提取L个字节,总共33个字节对应一个比特币压缩公钥(如果不足33个字节的自动在尾部追加ASCII空格字符填满直到达到33字节); 可选第二条和更多1-of-N多重签名输出中,第一个公钥固定是发送者的,第二个公钥开始为具体ODIN消息内容编码而成。 注:N取值范围为3-16,按目前的比特币协议标准建议取值为3。对于1条1-of-N多重签名输出仍无法容纳的ODIN数据块,可依样扩展存入第2条,第3条等更多条多重签名输出记录中即可,如果不超出75个字节,可以选择存入后文的OP_RETURN备注消息。 (d)一条OP_RETURN备注消息(在标准的多重交易数据块无法容纳过长的ODIN数据包时,提供额外的不超过75个字节存储空间) (e)比特币源地址中有一定数量的比特币余额(建议有0.001BTC以上,用于生成从源地址发送到目的地址的若干有效交易条目以嵌入ODIN数据包。注: 因为比特币1-of-N多重签名交易的特点,这些比特币金额不会发生实际支出,将在下一个ODIN消息中被回收循环利用) (f)以比特币计的消息成本固定费用(缺省是0.00001 BTC),将支付给收录这个交易数据块的比特币网络矿工。 (g)一个比特币找零地址(与上述第一项的比特币源地址相同,用于按照比特币交易协议将输入交易的比特币金额在生成若干条满足嵌入ODIN数据包的交易条目后多出的金额回收到消息发送者账户) 上述的特性c是技术实现的关键,ODIN数据块会嵌入到比特币交易的多重签名输出数据块中,是1-of-N输出,每个数据块的第一个公钥固定是发送者的,因而输出的币值可以赎回循环使用。关于比特币多重签名交易的详细说明请参考比特币协议规范。 每个ODIN根标识信息数据块的格式按字节顺序定义如下: 第1字节 : 消息类型,1个字节。 第2字节到消息结束为按消息类型区分的不同消息数据,详见下文的“3、ODIN根标识的消息类型”。 3、ODIN根标识的消息类型 3.1 新注册ODIN根标识 比特币源地址:对应ODIN根标识注册者 比特币目的地址:对应ODIN根标识管理者(可选,为空表示管理者与注册者相同) 消息数据块的格式按字节顺序定义如下: 第1字节 : 消息类型,1个字节,取值为ASCII字符R 第2字节 : 消息正文数据格式,1个字节。 取值定义:ASCII字符, T 表示“UTF-8编码文本字符串”, D 表示“经deflate算法压缩得到的二进制数据,需解压后可得到UTF-8编码的原始文本字符串” G 表示“经gzip算法压缩得到的二进制数据,需解压后可得到UTF-8编码的原始文本字符串” 第3字节开始: 消息正文数据字节长度,采用比特币协议的可变长度整型(Varint)定义。当取值小于253时,采用1个字节存放;当取值大于等于253时小于65536时,采用3个字节存放,其中第一个字节固定为253。后面两个字节存放实际数据值(低位在前,高位在后);当取值大于等于65536时小于4294967295时,采用5个字节存放,其中第一个字节固定为254。后面四个字节存放实际数据值(低位在前,高位在后)。 后续到消息正文指定长度结束是按字节存放的消息正文数据,需根据第2字节的数据格式取值来获得原始消息文本,为UTF-8编码的JSON格式字符串,对应一个JSON对象数据,说明如下: { "ver":"说明:数据格式定义版本,最新为2", "title":"说明:名称备忘字符串", "email":"说明:个体的公开EMAIL,可选", "auth":"说明:配置权限,取值定义见下方注释", "pns_url":"说明:自定义的对等标识托管服务(Peer Naming Service)网址,可选,取值定义详见第4节", } 注:配置权限的取值说明:ASCII字符0,1或2 0表示“注册者或管理者任一都可以更新标识相关配置信息,当auth字段不存在或取值非法时,默认按该项处理”, 1表示“只有管理者能修改标识相关配置信息(注意:此设置下如果注册者地址不同于管理者将无法转移注册权)”, 2表示“注册者和管理者必须共同确认才能更新标识相关配置信息”, 消息正文举例: {"ver":1,"title":"PPk-Sample","email":"ppkpub@gmail.com","auth":"0"} 注:为了保证根标识短编号的唯一有效性,只要符合ODIN特征公钥及消息内容第1字节为R,则都需要记录为一条新的ODIN根标识,即使其后续消息正文不可用。对于登记内容有误的ODIN根标识允许后续修改正确。 3.2 更新ODIN根标识的基本信息 比特币源地址:对应有权限更新ODIN根标识配置数据的注册者或者管理者 比特币目的地址:对应ODIN根标识的新管理者(可选,为空表示不更改管理者身份) 消息数据块的格式按字节顺序定义如下: 第1字节 : 消息类型,1个字节,取值为ASCII字符U 第2-31字节 : 类似“351474.430”的标准ODIN根标识,30个字节,如果标识本身不足30字节,则在右侧用ASCII空格字符补足 第32字节 : 消息正文数据格式,1个字节。 取值定义:ASCII字符, T 表示“UTF-8编码文本字符串”, D 表示“经deflate算法压缩得到的二进制数据,需解压后可得到UTF-8编码的原始文本字符串” G 表示“经gzip算法压缩得到的二进制数据,需解压后可得到UTF-8编码的原始文本字符串” 第33字节开始: 消息正文数据字节长度,采用比特币协议的可变长度整型(Varint)定义。当取值小于253时,采用1个字节存放;当取值大于等于253时小于65536时,采用3个字节存放,其中第一个字节固定为253。后面两个字节存放实际数据值(低位在前,高位在后);当取值大于等于65536时小于4294967295时,采用5个字节存放,其中第一个字节固定为254。后面四个字节存放实际数据值(低位在前,高位在后)。 后续到消息正文指定长度结束是按字节存放的消息正文数据,需根据第32字节的数据格式取值来获得原始消息文本,为UTF-8编码的JSON格式字符串,对应一个JSON对象数据,说明如下: 消息正文定义: JSON格式字符串,对应一个JSON对象数据,说明如下: { "ver":"说明:数据格式定义版本,最新为2", "cmd":"说明。更新命令类型,取值为BI表示更新基本信息", "title":"说明:名称备忘字符串", "email":"说明:标识拥有者的公开EMAIL,可选", "auth":"说明:配置权限,取值定义见下方注释", "pns_url":"说明:自定义的对等标识托管服务(Peer Naming Service)网址,可选,取值定义详见第4节", } 注: 1.采用增量更新模式,只追加或更新请求中所列字段,未在更新请求中出现的字段将保持不变 2.配置权限的取值说明:ASCII字符0,1或2 0表示“注册者或管理者任一方都可以更新标识相关配置信息,当auth字段不存在或取值非法时,默认按该项处理”, 1表示“只有管理者能修改标识相关配置信息(注意:此设置下如果注册者地址不同于管理者将无法转移注册权)”, 2表示“注册者和管理者必须共同确认才能更新标识相关配置信息”, 消息正文举例: {"ver":1,"cmd":"BI","title":"PPk-Update-Sample"} 3.3 更新ODIN根标识的访问点配置 比特币源地址:对应有权限更新ODIN根标识配置数据的注册者或者管理者 比特币目的地址:空 消息数据块的格式按字节顺序定义如下: 第1字节 : 消息类型,1个字节,取值为ASCII字符U 第2-31字节 : 类似“351474.430”的标准ODIN根标识,30个字节,如果标识本身不足30字节,则在右侧用ASCII空格字符补足 第32字节 : 消息正文数据格式,1个字节。 取值定义:ASCII字符, T 表示“UTF-8编码文本字符串”, D 表示“经deflate算法压缩得到的二进制数据,需解压后可得到UTF-8编码的原始文本字符串” G 表示“经gzip算法压缩得到的二进制数据,需解压后可得到UTF-8编码的原始文本字符串” 第33字节开始: 消息正文数据字节长度,采用比特币协议的可变长度整型(Varint)定义。当取值小于253时,采用1个字节存放;当取值大于等于253时小于65536时,采用3个字节存放,其中第一个字节固定为253。后面两个字节存放实际数据值(低位在前,高位在后);当取值大于等于65536时小于4294967295时,采用5个字节存放,其中第一个字节固定为254。后面四个字节存放实际数据值(低位在前,高位在后)。 后续到消息正文指定长度结束是按字节存放的消息正文数据,需根据第32字节的数据格式取值来获得原始消息文本,为UTF-8编码的JSON格式字符串,对应一个JSON对象数据,说明如下: 消息正文定义: JSON格式字符串,对应一个JSON对象数据,说明如下: { "ver":"说明:数据格式定义版本,最新为2", "cmd":"说明。更新命令类型,取值AP表示更新AP访问点配置表", "ap_set":{ "AP记录项编号":{"url":"对应URL"}, "AP记录项编号":{"url":"对应URL"}, ... "AP记录项编号":{"url":"对应URL"}, } } 注:AP记录项默认从0开始以依次按1,2..,n顺序编号即可。当URL取值为""即长度为的字符串,表示该AP记录项置空,但该记录项不会删除,即不影响后续记录的编号。 消息正文举例: {"ver":1,"cmd":"AP","ap_set":{"0":{"url":"http://ap1.ppkpub.org/"},"1":{"url":""},"2":{"url":"http://ap2.ppkpub.org/"}}} 或 {"ver":1,"cmd":"AP","ap_set":{"ppk:123/":{"url":"http://ap1.ppkpub.org/","vd_set":{"type":"RsaVerificationKey2018","cert_uri":"ipfs:QmaZGNj6G2sgRESZDEQgQybwZrigRW4UHsxquvt1C3qdyt"} }}} 3.4 更新ODIN根标识的数据签名验证参数 比特币源地址:对应有权限更新ODIN根标识配置数据的注册者或者管理者 比特币目的地址:空 消息数据块的格式按字节顺序定义如下: 第1字节 : 消息类型,1个字节,取值为ASCII字符U 第2-31字节 : 类似“351474.430”的标准ODIN根标识,30个字节,如果标识本身不足30字节,则在右侧用ASCII空格字符补足 第32字节 : 消息正文数据格式,1个字节。 取值定义:ASCII字符, T 表示“UTF-8编码文本字符串”, D 表示“经deflate算法压缩得到的二进制数据,需解压后可得到UTF-8编码的原始文本字符串” G 表示“经gzip算法压缩得到的二进制数据,需解压后可得到UTF-8编码的原始文本字符串” 第33字节开始: 消息正文数据字节长度,采用比特币协议的可变长度整型(Varint)定义。当取值小于253时,采用1个字节存放;当取值大于等于253时小于65536时,采用3个字节存放,其中第一个字节固定为253。后面两个字节存放实际数据值(低位在前,高位在后);当取值大于等于65536时小于4294967295时,采用5个字节存放,其中第一个字节固定为254。后面四个字节存放实际数据值(低位在前,高位在后)。 后续到消息正文指定长度结束是按字节存放的消息正文数据,需根据第32字节的数据格式取值来获得原始消息文本,为UTF-8编码的JSON格式字符串,对应一个JSON对象数据,说明如下: 消息正文定义: JSON格式字符串,对应一个JSON对象数据,说明如下: { "ver":"说明:数据格式定义版本,最新为2", "cmd":"说明。更新命令类型,取值VD表示更新AP访问点所提供数据的验证参数", "vd_set":{ "type":"公钥编码类型,该字段不填写时默认取值为PEM,可选BASE64", "pubkey":"说明:验证所需要的公钥(对应编码类型的字符串)。在公钥较长(超过64字节)时,建议先用分布式存储如DAT/IPFS等来承载内容较大的公钥,然后将链接URI填入此字段。当该字段取值为空字符串时表示撤销已设置的验证公钥", } } 消息正文举例: {"ver":1,"cmd":"VD","vd_set":{"pubkey":"ipfs:QmaZGNj6G2sgRESZDEQgQybwZrigRW4UHsxquvt1C3qdyt"}} 或 {"ver":1,"cmd":"VD","vd_set":{"type":"BASE64","pubkey":"E48A37882B123499011339DD338920..............2011BBS"}} 注: 1.关于PEM公钥证书编码标准的定义可参考 https://tools.ietf.org/html/rfc1421 2.直接在比特币交易中嵌入过长的公钥(超过64字节)可能会因为交易打包容量限制被矿工拒绝,建议采用将公钥先上传到DAT/IPFS等分布式存储上获得较短的链接后存到链上。 3.5 转移ODIN根标识的注册者身份 比特币源地址:对应ODIN根标识的原注册者 比特币目的地址:对应ODIN根标识的新注册者 消息数据块的格式按字节顺序定义如下: 第1字节 : 消息类型,1个字节,取值为ASCII字符U 第2-31字节 : 类似“351474.430”的标准ODIN根标识,30个字节,如果标识本身不足30字节,则在右侧用ASCII空格字符补足 第32字节 : 消息正文数据格式,1个字节。 取值定义:ASCII字符, T 表示“UTF-8编码文本字符串”, D 表示“经deflate算法压缩得到的二进制数据,需解压后可得到UTF-8编码的原始文本字符串” G 表示“经gzip算法压缩得到的二进制数据,需解压后可得到UTF-8编码的原始文本字符串” 第33字节开始: 消息正文数据字节长度,采用比特币协议的可变长度整型(Varint)定义。当取值小于253时,采用1个字节存放;当取值大于等于253时小于65536时,采用3个字节存放,其中第一个字节固定为253。后面两个字节存放实际数据值(低位在前,高位在后);当取值大于等于65536时小于4294967295时,采用5个字节存放,其中第一个字节固定为254。后面四个字节存放实际数据值(低位在前,高位在后)。 后续到消息正文指定长度结束是按字节存放的消息正文数据,需根据第32字节的数据格式取值来获得原始消息文本,为UTF-8编码的JSON格式字符串,对应一个JSON对象数据,说明如下: 消息正文定义: JSON格式字符串,对应一个JSON对象数据,说明如下: { "ver":"说明:数据格式定义版本,最新为2", "cmd":"说明。更新命令类型,取值为TR表示转移注册者", } 消息正文举例: {"ver":1,"cmd":"TR"} 注: 1.转移注册者需要按标识更新权限设置进行确认后,需再得到新注册者的签名交易确认才能生效。 2.一旦转移注册者事务得到新注册者的确认并被区块收录生效时,如果该ODIN根标识仍存在其它未生效的转移注册者事务,则相应未生效的转移事务自动失效。 3.转移注册者确认生效时,该标识的管理权限将自动重置为默认的ASCII字符0(即注册者和管理者都可以修改),新注册者可以根据需要再自行修改。 3.5 确认对ODIN根标识的更新操作 比特币源地址:对应待确认ODIN根标识更新操作的当前注册者、当前管理者或作为转移目标的新注册者 比特币目的地址:无 消息数据块的格式按字节顺序定义如下: 第1字节 : 消息类型,1个字节,取值为ASCII字符U 第2-31字节 : 类似“351474.430”的标准ODIN根标识,30个字节,如果标识本身不足30字节,则在右侧用ASCII空格字符补足 第32字节 : 消息正文数据格式,1个字节。 取值定义:ASCII字符, T 表示“UTF-8编码文本字符串”, D 表示“经deflate算法压缩得到的二进制数据,需解压后可得到UTF-8编码的原始文本字符串” G 表示“经gzip算法压缩得到的二进制数据,需解压后可得到UTF-8编码的原始文本字符串” 第33字节开始: 消息正文数据字节长度,采用比特币协议的可变长度整型(Varint)定义。当取值小于253时,采用1个字节存放;当取值大于等于253时小于65536时,采用3个字节存放,其中第一个字节固定为253。后面两个字节存放实际数据值(低位在前,高位在后);当取值大于等于65536时小于4294967295时,采用5个字节存放,其中第一个字节固定为254。后面四个字节存放实际数据值(低位在前,高位在后)。 后续到消息正文指定长度结束是按字节存放的消息正文数据,需根据第32字节的数据格式取值来获得原始消息文本,为UTF-8编码的JSON格式字符串,对应一个JSON对象数据,说明如下: 消息正文定义: JSON格式字符串,对应一个JSON对象数据,说明如下: { "ver":"说明:数据格式定义版本,最新为2", "cmd":"说明。更新命令类型,取值为CU表示二次确认更新操作", "tx_list":[ "待确认操作对应交易记录标识1", "待确认操作对应交易记录标识2", "...", "待确认操作对应交易记录标识N" ] } 消息正文举例: {"ver":1,"cmd":"CU","tx_list":["432821.323","432823.222"]} 4. 关于自定义根标识解析应用托管服务 ODIN标识注册、更新和解析都默认都承载在比特币区块链上。用户可以选择自定义的标识托管服务(采用PTTP协议作为服务接口,支持区块链或网站等多种形式),负责提供更新和解析服务,配合日常应用管理将更方便,费用更低,同时可以衍生出更多应用场景(比如不同的英文转义名称对应不同的内容服务,类似以按域名区分的虚拟主机服务)。 通过设置ODIN根标识注册信息里的"pns_url"字段即可指定所要使用的标识解析应用托管服务网址,该字段不存在或者取值空字符串时表示为默认的比特币区块链,其它取值示例如下: 指向PTTP服务网址(会向该PPk网址返回结果中的ap设置所列节点发起解析请求): "pns_url":"ppk:btm/pns_sample*" 或者指向HTTP服务网址: "pns_url":"http://btm_pns_sample.org/" 或者指向特定的智能合约网址 "pns_url":"eth:pns_sample_contract/" 注: 1.注册标识以及更新标识的关键信息(包括注册者、管理者、管理权限和自定义标识解析应用托管网址)只能在比特币区块链上进行,除此之外的信息都可以在托管服务上进行更新并体现在标识解析结果里,托管服务还可以自行扩展标识属性字段。 2.如果根标识在比特币区块链上设置了有效的vd_set验证参数,则托管服务对该根标识相关的托管解析结果需要带上对应的私钥签名,以提供更好的解析安全性,避免在托管服务被攻击所导致的解析结果被篡改的可能风险。 3.托管服务处所更新设置的vd_set用于该标识的最终应用(如标识的身份验证)和对扩展子标识的签名验证。 4.标识解析请求者不需要处理"pns_url"字段,标识解析服务实现者会自动根据根标识注册者的设置,获取所指定托管服务的解析信息,并与比特币区块链上的基本信息合并在一起返回给标识解析请求者(同时将"pns_url"字段名改为"from_pns_url"表示已经调用pns解析处理,同时避免请求者重复处理)。 5、ODIN扩展标识的技术方案 ODIN扩展标识由对应父标识拥有者来具体定义,按照统一的解析接口,灵活选择技术方案实现器扩展标识服务。 6、ODIN标识的解析 6.1 自主解析一级ODIN标识前缀 一级标识解析服务需要从比特币区块链上同步全部一级ODIN的列表和配置数据,就可以自主解析任意一个一级ODIN标识前缀。 如果某个一级ODIN标识设置了自定义标识解析应用托管服务,则进一步按照PTTP协议调用所指定的解析服务接口获得最新的解析结果。 6.2 递归解析多级扩展ODIN标识前缀 ODIN标识作为PPk网络的一种特定内容资源,同样采用PTTP协议来提供解析服务。 假设一个多级ODIN标识为ppk:305678.1000/21.35/23.678/ISBN2890321345_P218* 其去掉资源后缀部分后的前缀为 ppk:305678.1000/21.35/23.678 先判断缓存中是否已有3级标识前缀 ppk:305678.1000/21.35/23.678* 起始对应的数据报文 如果没有,则递归判断缓存中是否已有2级标识前缀 ppk:305678.1000/21.35* 起始对应的数据报文 如果没有,则判断是否已有1级标识前缀 ppk:305678.1000* 对应的注册信息 如果没有,则返回无效数据 如有,则向1级标识对应AP发出对 ppk:305678.1000/21.35* 的兴趣报文并将收到的数据报文返回使用 如有,则向2级标识对应AP发出对 ppk:305678.1000/21.35/23.678* 的兴趣报文并将收到的数据报文返回使用 如果有,则返回缓存的数据报文 以此类推即可递归解析多级扩展ODIN标识前缀。 6.3 ODIN标识前缀解析结果 解析ODIN标识前缀所获得PTTP数据报文中的正文内容(content)是一个JSON编码字符串,包含指定该ODIN标识前缀的拥有者相关信息(包括:名称、AP列表、数据内容验证参数、登记时间戳UTC),具体定义如下: { "@context":"ppk:0/odin_spec*", "ver":"说明:ODIN标识协议定义版本,最新为2", "title":"说明:可选的标识名称字符串", "ap_set":{ "AP记录项标识":{"url":"对应AP服务URL"}, "AP记录项标识":{"url":"对应AP服务URL"}, ... "AP记录项标识":{"url":"对应AP服务URL"}, }, "vd_set":{ "type":"公钥编码类型,该字段不填写时默认取值为PEM,可选BASE64", "pubkey":"说明:验证所需要的公钥,具体由上述type取值来决定,无特殊说明则为默认采用PEM编码的字符串" }, ... //更多自定义字段,建议扩展字段取值加上前缀"x_"避免与上述基本字段冲突 } 注: (1) "ap_set"参数项一般从0开始以依次按1,2..,n顺序编号即可,也可以自定义标识编号。当URL取值为""即长度为的字符串,表示该AP记录项置空,但该记录项不会删除,即不影响后续记录的编号。 (2) "ap_set"参数项如果在JSON数据中不存在,则缺省从父级ODIN标识继承。 (3) "vd_set"参数项如果在JSON数据中不存在,则缺省从父级ODIN标识继承。 (4) 如果"vd_set"参数项存在,但其"pubkey"取值为空字符串或不提供,则表示忽略该ODIN标识子级资源的签名验证。 7、FAQ 7.1 ODIN根标识的消息数据大小有什么限制? 按既有的比特币协议定义,单个区块不能超过1MB,单条交易数据块一般在1KB左右,过大的数据包会需要很长时间的等待延迟才能被成功写入区块链,超过限制的会被比特币网络拒绝收录。 一般情况下,单个ODIN消息原始正文或经压缩后的长度最大不能超过65535字节,建议控制在1KB以下,对于超过1KB的消息可以适当增加支付给比特币网络矿工的成本费用,可以加快被收录入区块链的速度。 ------------------------------------------------------------------------------------------------- Released under the MIT License. Copyright (C) 2015-2020 PPk Public Group (ppkpub.org). Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.