Metadata-Version: 2.1
Name: insightoslog
Version: 1.0.12
Summary: InsightOS Log SDK - Unified log collection SDK
Home-page: https://gitee.com/hong-zhenhuang/InsightOSLogSDK
Author: InsightOS Team
Author-email: team@insightos.org
License: UNKNOWN
Platform: UNKNOWN
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.7
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Software Development :: Libraries
Requires-Python: >=3.7
Description-Content-Type: text/markdown

# InsightOS Log SDK 统一日志接口

[![版本](https://img.shields.io/badge/version-1.0.10-blue.svg)](https://github.com/HongZH-XMU/InsightOSLogSDK)
[![许可证](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)
[![C++](https://img.shields.io/badge/C++-17-orange.svg)](cpp/)
[![Go](https://img.shields.io/badge/Go-1.21+-88CCEE.svg)](go/)
[![Python](https://img.shields.io/badge/Python-3.8+-FFD700.svg)](python/)

InsightOS Log SDK 是一个跨语言的结构化日志 SDK，支持 C++、Go、Python 三种语言。提供统一 JSON 格式输出、链路追踪（Trace/Span）、跨线程/协程上下文传播、异步日志等功能。

---

## 目录

- [快速开始](#快速开始)
  - [C++ SDK](#1-c-sdk)
  - [Go SDK](#2-go-sdk)
  - [Python SDK](#3-python-sdk)
- [示例代码](#示例代码)
  - [C++ 示例](#c-示例)
  - [Go 示例](#go-示例)
  - [Python 示例](#python-示例)
- [功能特性](#功能特性)
- [日志结构](#日志结构)
- [配置文件](#配置文件)
- [API 参考](#api-参考)
- [输出模式](#输出模式)
- [文件滚动策略](#文件滚动策略)
- [依赖说明](#依赖说明)
- [测试覆盖](#测试覆盖)
- [打包发布](#打包发布)
- [更新日志](#更新日志)
- [贡献指南](#贡献指南)
- [许可证](#许可证)

---

## 快速开始

### 1. C++ SDK

#### 安装

**方式一：APT 在线安装（推荐）**

```bash
# 添加 APT 源（amd64）
echo "deb [trusted=yes arch=amd64] https://cdn.jsdelivr.net/gh/HongZH-XMU/insightoslog-apt@main/ stable main" | \
  sudo tee /etc/apt/sources.list.d/insightos.list

# 更新并安装
sudo apt update
sudo apt install libinsightoslog-dev
```

> arm64 架构：将上面 `arch=amd64` 改为 `arch=arm64` 即可。

**方式二：手动下载 deb 安装**

```bash
curl -LO https://cdn.jsdelivr.net/gh/HongZH-XMU/insightoslog-apt@main/pool/main/l/libinsightoslog-dev/libinsightoslog-dev_1.0.10_amd64.deb
sudo dpkg -i libinsightoslog-dev_amd64.deb
sudo apt install -f
```

**方式三：源码编译**

```bash
cd cpp
xmake f -m release
xmake
```

#### 编译运行

安装后直接编译，无需额外参数：

```bash
g++ -std=c++17 main.cpp -linsightoslog-log -lpthread -ldl -o myapp
./myapp
```

> 安装后需运行 `sudo ldconfig` 更新动态库缓存。

---

### 2. Go SDK

#### 安装

```bash
go env -w GOPROXY=https://goproxy.cn,direct
go env -w GOSUMDB=off
go get gitee.com/hong-zhenhuang/InsightOSLogSDK/go@v1.0.10
```

#### 编译运行

```bash
go build -o myapp main.go
./myapp
```

---

### 3. Python SDK

#### 安装

```bash
pip install insightoslog
```

#### 运行

```bash
python main.py
```

---

## 示例代码

### C++ 示例

用户代码只需包含一个头文件，使用两种调用风格：

```cpp
#include <insightoslog/wrapper/wrapper.hpp>

using namespace insightoslog;

int main() {
    // 初始化
    InitParam config;
    config.level = LogLevel::INFO;
    config.service_name = "MyService";
    config.output = "stdout";
    Logger::Init(config);

    // 开启链路
    Logger::StartNewTrace();

    // 方式一：IOSLOG_* 宏（推荐，带 caller：file/line/function）
    IOSLOG_INFO("服务启动成功");
    IOSLOG_INFO("用户 {} 登录了系统", "alice");
    IOSLOG_WARN("警告：value={} 超过阈值", 100);
    IOSLOG_ERROR("错误码: {}, 错误信息: {}", 5001, "Connection refused");

    // 方式二：LogBuilder 链式调用（带 caller）
    Logger::GetCurrentContext().log().info("处理请求")
        .on_request({{"method", "POST"}, {"path", "/api/users"}})
        .with_data(params, result)
        .latency(50)
        .send();

    // 方式三：Logger::Info 系列（不带 caller，适用于不需要 caller 信息的场景）
    Logger::Info("收到请求");

    // 方式四：RAII 上下文管理器（自动恢复上下文）
    {
        auto guard = Logger::WithContext("custom-trace-id", "custom-span-id");
        IOSLOG_INFO("在临时上下文中记录的日志");
    } // 离开作用域，自动恢复旧上下文

    // 方式五：闭包风格
    Logger::WithContext("closure-trace-id", "closure-span-id", []() {
        IOSLOG_INFO("闭包风格日志");
    }); // 自动恢复

    // HTTP Header 传播
    auto headers = Logger::GetPropagationHeaders();
    // 将 headers.trace_id / headers.span_id 放到 HTTP Header 中传递给下游

    // 关闭
    Logger::Shutdown();
    return 0;
}
```

完整示例见 [`examples/cpp/main.cpp`](examples/cpp/main.cpp)。

---

### Go 示例

```go
package main

import (
    log "gitee.com/hong-zhenhuang/InsightOSLogSDK/go"
)

func main() {
    // 初始化
    log.Init(log.InitParam{
        ServiceName: "MyService",
        Level:       log.LevelInfo,
        Output:      "stdout",
    })

    // 开启链路
    log.StartNewTrace()

    // 方式一：直接函数调用（推荐）
    log.Info("服务启动成功")
    log.Infof("用户 %s 登录了系统", "alice")

    // 方式二：Logger 类封装
    logger := log.NewLogger(log.LoggerInitParam{ServiceName: "MyService"})
    logger.Info("收到请求")

    // 方式三：建造者模式
    ctx := log.GetCurrentContext()
    ctx.Info("处理请求").
        OnRequest(log.EventRequest{Method: "POST", Path: "/api/users", LatencyMs: 50}).
        WithData(map[string]interface{}{"user": "alice"}, nil).
        Send()

    // 方式四：RAII 上下文管理器
    // defer 手动释放
    guard := log.WithContext("custom-trace-id", "custom-span-id")
    defer guard.Close()
    log.Info("在临时上下文中记录的日志")
    // 函数结束时 defer 自动恢复

    // 方式五：闭包风格（自动恢复上下文）
    log.WithContextFunc("closure-trace-id", "closure-span-id", func() {
        log.Info("闭包风格日志")
    })

    // 方式六：从已有 Context 创建
    existingCtx := log.Context{TraceID: "existing-trace", SpanID: "existing-span"}
    guard2 := log.WithContextFromCtx(existingCtx)
    defer guard2.Release()
    log.Info("从已有上下文创建的日志")

    // HTTP Header 传播
    headers := log.GetPropagationHeaders()
    // 将 headers.TraceID / headers.SpanID 放到 HTTP Header 中传递给下游

    log.Shutdown()
}
```

完整示例见 [`examples/go/main.go`](examples/go/main.go)。

---

### Python 示例

```python
import insightoslog as log

# 初始化
log.init({"service_name": "MyService", "level": "info", "output": "stdout"})

# 开启链路
log.start_new_trace()

# 方式一：直接函数调用（推荐）
log.info("服务启动成功")
log.info("用户 {} 登录了系统".format("alice"))

# 方式二：Logger 类封装
log.Logger.info("收到请求")

# 方式三：建造者模式
ctx = log.current_context()
ctx.info("处理请求") \
    .on_request({"method": "POST", "path": "/api/users"}) \
    .with_data({"user": "alice"}, None) \
    .latency(50) \
    .send()

# 方式四：上下文管理器
with log.Trace.start_new_trace():
    log.info("请求开始")
    # ... 业务逻辑 ...
    log.info("请求结束")

# HTTP Header 传播
headers = log.Trace.get_propagation_headers()
# 将 headers["trace_id"] / headers["span_id"] 放到 HTTP Header 中传递给下游

log.shutdown()
```

完整示例见 [`examples/python/main.py`](examples/python/main.py)。

---

## 功能特性

| 特性 | 说明 |
|------|------|
| **结构化 JSON 日志** | 按域组织的 JSON 输出，支持 `meta`、`resource`、`context`、`event`、`data`、`error`、`caller` 等域 |
| **链路追踪** | 自动生成 `trace_id` 和 `span_id`，支持 HTTP Header 传播和跨线程/协程自动继承 |
| **Caller 信息** | 编译时宏展开捕获调用点 file/line/function，精确到用户代码行 |
| **stdout 颜色输出** | 终端输出带 ANSI 颜色高亮，按日志级别着色，整条日志同一颜色 |
| **域过滤** | stdout 可按需过滤输出域（如只显示 `event`），文件输出全量域 |
| **异步日志** | 内存缓冲区 + 定时刷新，大幅提升高并发场景性能 |
| **敏感信息过滤** | 自动过滤密码、Token、API Key 等敏感信息 |
| **建造者模式** | 链式调用支持 `on_request`、`with_data`、`with_error`、`latency` 等方法 |
| **多语言统一** | C++ / Go / Python 三种语言 API 风格一致 |
| **文件滚动** | 按大小自动滚动，支持配置最大文件和单文件大小 |
| **上下文管理器** | C++/Go/Python 均支持 RAII 风格的 `with` 语句，自动恢复旧上下文 |
| **全局资源** | 支持设置全局 Resource 信息，所有日志自动附加 |
| **配置文件** | 支持 YAML 配置文件加载，便于部署管理 |

---

## 日志结构

终端输出格式（stdout）：

```
LEVEL YYYY-MM-DDTHH:MM:SS.sss+08:00 [PID] {"event":{"msg":"..."}}
```

完整 JSON 结构：

```json
{
  "meta": {
    "level": "INFO",
    "time": "2026-03-11T10:00:00.000+08:00"
  },
  "resource": {
    "type": "ability",
    "name": "MyService",
    "instance_id": "abc-123",
    "pid": 12345
  },
  "context": {
    "trace_id": "550436d474944d77a6833ba578d53e6d",
    "span_id": "767461a9d8ea41f29c3defe40a755ede",
    "parent_span_id": ""
  },
  "event": {
    "msg": "Ability onStart",
    "request": { "method": "POST", "latency_ms": 50 }
  },
  "data": {
    "param": {"key": "value"},
    "result": {"status": "ok"}
  },
  "error": {
    "type": "RuntimeError",
    "message": "connection failed"
  },
  "caller": {
    "file": "main.cpp",
    "line": 42,
    "function": "main"
  }
}
```

**stdout vs 文件输出区别：**

| 域 | stdout | 文件 |
|----|--------|------|
| `meta` | - | ✅ |
| `resource` | - | ✅ |
| `context` | - | ✅ |
| `event` | ✅（默认） | ✅ |
| `data` | - | ✅ |
| `error` | - | ✅ |
| `caller` | ✅（默认） | ✅ |

可通过 `stdout_fields` 配置覆盖默认行为。

---

## 配置文件

所有 SDK 均支持 `InsightOSLogConfig.yaml` 配置文件：

```yaml
level: INFO
service_type: "ability"
service_name: "MyService"
instance_id: "instance-001"
log_root: "/var/log/insightos"
output: "stdout"               # stdout 或 rotate_file

file:
  max_size: 5242880           # 单文件最大字节数 (5MB)
  max_files: 3                # 保留的旧日志文件数量

async:
  buffer_size: 4096           # 异步队列大小 (字节)
  flush_interval: 2            # 刷新间隔 (秒)

enable_tracing: true
stdout_fields: ["event", "caller"]  # stdout 输出域（可选）
```

---

## API 参考

### 初始化

| C++ | Go | Python |
|-----|-----|--------|
| `Logger::Init(config)` | `log.Init(param)` | `log.init(param)` |
| `Logger::InitFromConfig(path)` | `log.InitFromConfig(path)` | `log.init_from_config(path)` |
| `Logger::Shutdown()` | `log.Shutdown()` | `log.shutdown()` |
| `Logger::Flush()` | `log.Flush()` | `log.flush()` |
| `set_level(level)` | `log.SetLevel(level)` | `log.set_level(level)` |
| `get_level()` | `log.GetLevel()` | `log.get_level()` |

### 日志记录（便捷函数）

| 级别 | C++ | Go | Python |
|------|-----|-----|--------|
| TRACE | `IOSLOG_TRACE(msg, ...)` | `log.Trace(msg)` | `log.trace(msg)` |
| DEBUG | `IOSLOG_DEBUG(msg, ...)` | `log.Debug(msg)` | `log.debug(msg)` |
| INFO | `IOSLOG_INFO(msg, ...)` | `log.Info(msg)` | `log.info(msg)` |
| WARN | `IOSLOG_WARN(msg, ...)` | `log.Warn(msg)` | `log.warn(msg)` |
| ERROR | `IOSLOG_ERROR(msg, ...)` | `log.Error(msg)` | `log.error(msg)` |
| FATAL | `IOSLOG_FATAL(msg, ...)` | `log.Fatal(msg)` | `log.fatal(msg)` |

### 链路追踪

| 功能 | C++ | Go | Python |
|------|-----|-----|--------|
| 开启新链路 | `Logger::StartNewTrace()` | `log.StartNewTrace()` | `log.start_new_trace()` |
| 继续链路 | `Logger::ContinueTrace(trace_id, span_id)` | `log.ContinueTrace(trace_id, span_id)` | `log.continue_trace(trace_id, span_id)` |
| 注入链路 | `Logger::Inject(trace_id, span_id, parent_span_id)` | `log.Inject(trace_id, span_id, parent_span_id)` | `log.inject(trace_id, span_id, parent_span_id)` |
| 获取 Headers | `Logger::GetPropagationHeaders()` | `log.GetPropagationHeaders()` | `log.get_propagation_headers()` |
| 从 Header 提取 | `Logger::ExtractFromHeaders(headers)` | `log.ExtractFromHeaders(...)` | `log.extract_from_headers(...)` |
| 获取当前 Context | `Logger::GetCurrentContext()` | `log.GetCurrentContext()` | `log.current_context()` |
| 获取 TraceID | `Logger::GetTraceID()` | `log.GetTraceID()` | `log.get_trace_id()` |
| 获取 SpanID | `Logger::GetSpanID()` | `log.GetSpanID()` | `log.get_span_id()` |
| 生成 ID | `GenerateTraceID()` / `GenerateSpanID()` | `log.GenerateTraceID()` / `log.GenerateSpanID()` | `log.generate_trace_id()` / `log.generate_span_id()` |

### 上下文管理器（RAII）

|| 功能 | C++ | Go | Python |
||------|------|-----|--------|
|| 创建上下文管理器 | `WithContext(trace_id, span_id)` | `WithContext(traceID, spanID)` | `with_context(traceID, spanID)` |
|| 创建完整上下文 | `WithContext(trace_id, span_id, parent_span_id)` | `WithContextFull(traceID, spanID, parentSpanID)` | `with_context(traceID, spanID, parentSpanID)` |
|| 从已有 Context 创建 | `WithContextFromCtx(ctx)` | `WithContextFromCtx(ctx)` | `with_context_from_ctx(ctx)` |
|| 闭包风格 | `WithContext(tid, sid, [](...) {})` | `WithContextFunc(tid, sid, func() {})` | `with_context(tid, sid, func)` |
|| 释放/恢复上下文 | `guard.Release()` 或析构 | `guard.Close()` / `guard.Release()` | 自动 (`with` 语句) |
|| 获取保存的上下文 | `guard.GetContext()` | - | - |

### 上下文传播（跨线程/协程）

| 功能 | C++ | Go | Python |
|------|-----|-----|--------|
| 准备子线程 | `Logger::PrepareForChildThread()` | `log.PrepareForChildThread()` | `log.prepare_for_child_thread()` |
| 子线程继承 | `Logger::InheritFromPrepared()` | `log.InheritFromPrepared()` | `log.inherit_from_prepared()` |
| 自动继承 | `Logger::InheritFromParent()` | `log.InheritFromParent()` | `log.inherit_from_parent()` |

### 建造者模式

```cpp
// C++
ctx.log().info("msg")
    .on_request({...})
    .with_params({...})
    .with_result({...})
    .with_error({...})
    .latency(50)
    .truncate(true)
    .send();
```

```go
// Go
ctx.Info("msg").
    OnRequest(req).
    WithData(params, result).
    WithError(err).
    Latency(50).
    Send()
```

```python
# Python
ctx.info("msg") \
    .on_request(req) \
    .with_data(params, result) \
    .with_error(err) \
    .latency(50) \
    .send()
```

### 数据结构

| C++ | Go | Python |
|-----|-----|--------|
| `LogLevel` | `LogLevel` | `LogLevel` |
| `InitParam` | `InitParam` / `LoggerInitParam` | `InitParam` |
| `Context` | `Context` | `Context` / `LogContext` |
| `Resource` | `Resource` | `Resource` |
| `Caller` | `Caller` | `Caller` |
| `LogBuilder` | `LogBuilder` | `LogBuilder` |
| `Header::TRACE_ID` | `Header.TRACE_ID` | `HEADER_TRACE_ID` |

---

## 输出模式

| 模式 | 说明 | 颜色 | 格式化 |
|------|------|------|--------|
| `stdout` | 输出到终端 | ✅ 按级别着色 | 紧凑格式（可配置过滤域） |
| `rotate_file` | 输出到滚动日志文件 | ❌ | 完整 JSON（所有域） |

---

## 文件滚动策略

| 参数 | C++ | Go | Python | 默认值 |
|------|-----|-----|--------|--------|
| 单文件最大字节数 | `config.file.max_size` | `config.File.MaxSize` | `config.max_bytes` | 5MB |
| 保留文件数量 | `config.file.max_files` | `config.File.MaxFiles` | `config.backup_count` | 3 |

日志文件路径：`{log_root}/{service_type}/{service_name}.log`

---

## 依赖说明

| 语言 | 依赖 | 说明 |
|------|------|------|
| **C++** | spdlog, nlohmann_json, stduuid, fmt | APT 安装时自动拉取 |
| **Go** | google/uuid, uber-go/zap | go get 时自动拉取 |
| **Python** | 无外部依赖 | 使用标准库 |

---

## 测试覆盖

### C++ 测试 (`test/cpp/`)

| # | 测试 | 说明 |
|---|------|------|
| 1 | 基础初始化 | SDK 初始化测试 |
| 2 | 便捷宏 | `IOSLOG_INFO` 等宏 |
| 3 | fmt 格式化 | 格式化日志消息 |
| 4 | 建造者模式 | 链式调用 API |
| 5 | 请求/数据 | `on_request` / `with_data` |
| 6 | 错误日志 | 错误信息记录 |
| 7 | HTTP Header 传播 | 链路信息 Header 传播 |
| 8 | 跨线程传播 | Context 跨线程继承 |
| 9 | 嵌套 Span | 多级服务调用链路 |
| 10 | make_context | 手动创建 Context |
| 11 | LogBuilder 详细 | `truncate` / `latency` / `with_result` 等 |
| 12 | 多线程日志 | 并发写入测试 |
| 13 | ID 生成 | Trace ID / Span ID 生成 |
| 14 | Header 常量 | HTTP Header 常量验证 |
| 15 | 全局 Resource | Resource 信息测试 |
| 16 | 文件输出 | rotate_file 模式测试 |
| 17 | 异步日志 | 异步队列测试 |
| 18 | 配置文件加载 | InsightOSLogConfig.yaml 加载 |
| 19 | RefreshPID | PID 刷新测试 |
| 20 | stdout 域过滤 | `stdout_fields` 配置测试 |
| 21 | ContextGuard | RAII 上下文管理器基础功能 |
| 22 | 嵌套 WithContext | 嵌套作用域测试 |
| 23 | Trace WithContext | Trace 类的 WithContext 支持 |

运行测试：
```bash
cd test/cpp
xmake
xmake run test
```

### Go 测试 (`test/go/`)

**26 个测试用例**：Init、便捷宏、fmt 格式化、HTTP Header 传播、跨 goroutine 传播、Context 函数、多 goroutine 日志、全局 Resource、文件输出、异步日志、RefreshPID、配置加载、所有日志级别、LogBuilder、Context 链式方法、SetLevel/GetLevel、全局资源操作、Logger/Trace 类封装、Error 对象、敏感信息过滤、ContextWithLog、嵌套 WithContext、WithContextFuncFromCtx。

运行测试：
```bash
cd test/go
go test -v
```

### Python 测试 (`test/python/`)

**20 个测试函数**：基础初始化、日志级别、格式化、建造者模式、上下文管理器、错误日志、Context 传播、跨线程传播、ID 生成、Context 函数、嵌套 Span、多线程并发、Header 常量、全局 Resource、文件输出、异步日志、RefreshPID、敏感信息过滤、数据结构、LogLevel 类。

运行测试：
```bash
cd test/python
python3 test_main.py
```

---

## 打包发布

使用 `build_package.sh` 一键打包三个 SDK 并发布。

### 用法

```bash
# 默认版本，仅构建
./build_package.sh

# 指定版本
./build_package.sh 2.0.0

# 构建并发布到 PyPI
PYPI_TOKEN=xxx ./build_package.sh 1.0.0

# 构建并推送 APT 仓库
APT_REPO_REMOTE="git@github.com:HongZH-XMU/insightoslog-apt.git" \
  ./build_package.sh 1.0.0
```

### 发布方式

| 语言 | 平台 | 安装命令 |
|------|------|---------|
| **C++** | APT 在线仓库（jsDelivr） | `apt install libinsightoslog-dev` |
| **Go** | Go 官方模块代理 | `go get gitee.com/.../go@latest` |
| **Python** | PyPI | `pip install insightoslog` |

### 输出结构

```
dist/{VERSION}/
├── cpp/
│   └── libinsightoslog-dev_{VERSION}_{ARCH}.deb
├── go/
│   ├── logging_sdk.go     # 根模块入口
│   ├── go.mod             # 含 replace 指令
│   ├── impl/              # 核心实现子模块
│   └── wrapper/           # 面向对象封装子模块
└── python/
    └── insightoslog-{VERSION}-py3-none-any.whl
```



## 贡献指南

欢迎贡献代码！请遵循以下步骤：

### 开发环境

**C++**
- GCC 9+ 或 Clang 12+
- CMake 3.15+ 或 XMake
- C++17 标准

**Go**
- Go 1.21+

**Python**
- Python 3.8+

### 分支管理

```
main          # 稳定版本
develop       # 开发分支
feature/*     # 功能分支
bugfix/*      # 修复分支
```

### 提交流程

1. **Fork** 本仓库
2. 创建功能分支：`git checkout -b feature/your-feature`
3. 提交更改：`git commit -m 'Add some feature'`
4. 推送分支：`git push origin feature/your-feature`
5. 创建 **Pull Request**

### 代码规范

- C++：遵循 Google C++ Style Guide
- Go：遵循 Go Code Review Comments
- Python：遵循 PEP 8

### 测试要求

- 所有新增功能必须附带测试用例
- 所有测试通过后才能合并
- 保持测试覆盖率不下降

```bash
# 运行所有测试
cd test/cpp && xmake && xmake run test
cd test/go && go test -v
cd test/python && python3 test_main.py
```

---

## 许可证

MIT License

Copyright (c) 2026 InsightOS Team

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.


