Prompt:
This is a Markdown documentation from the AO documentation repository. Filename: token.md Path: ../ao-cookbook/src/zh/references/token.md
Note: This content continues in the next part.

Response:
# ao Token 和子账本规范

**状态:** DRAFT-1
**目标网络:** ao.TN.1

该规范描述了标准 ao Token 进程所必须的消息 handler 和函数。该标准提供用户控制和转移资产的能力，资产的稀缺性由进程维护。

每个符合标准的进程会实现一个余额账本，用来对进程代表的资产所有权进行编码。标准中提供了一系列函数进行账本修改，这些函数包含安全保护代码，保护 Token 所有权的稀缺性。

此外，该规范描述了一种名为 '子账本' 的进程类型。实现子账本后，可以将一定数量的 Token 从父进程转移到相同 Token 接口规范的子进程中。如果子账本进程的 `From-Module` 得到参与者的信任，这些子账本可以直接进行交易，而无需与父进程交换消息。即使父进程在拥堵状态，参与者也能使用子进程中的 Token。如果参与者信任子账本进程，可以认为这些进程之间的余额是等价的。因此，同一个 Token 可以由任意数量的进程并行处理。

# Token 进程（ Token Processes ）

Token 进程可以对多种类型的消息作出响应，类型在 `Action` 标签中指定。Token 支持的所有的 `Action` 消息类型如下：

| 名称     | 描述                                                          | 只读               |
| -------- | ------------------------------------------------------------- | ------------------ |
| Balance  | 获取一个标志符（identifier) 的余额                            | :heavy_check_mark: |
| Balances | 获取整个账本/账户的余额列表                                   | :heavy_check_mark: |
| Transfer | 函数调用者向一个或多个目标发送1个或多个单位，并选择通知目标。 | :x:                |
| Mint     | 如果你使用了具备 root 权限的进程，你可以增加 Token 供应量     | :x:                |

在本节的其余部分中，描述了生成符合规范和 Token 进程所需的标签，描述了每个 `Action` 消息的形式和它们的结果。

## （创建请求的参数）Spawning Parameters

每个符合规范的 Token 进程在其生成消息中必须携带以下特定的参数：

| 标签         | 描述                                                | 有没有强制性       |
| ------------ | --------------------------------------------------- | ------------------ |
| Name         | Token 的名称，也就是显示给用户的名称。              | :heavy_check_mark: |
| Ticker       | Token 的缩写名称，以便快速引用。                    | :heavy_check_mark: |
| Logo         | 应用程序希望在 Token 旁边显示的图片，以便快速识别。 | :heavy_check_mark: |
| Denomination | 当向用户显示数量和余额时， Token 精度度量。         | :x:                |

## 消息协议（Messaging Protocol）

### Balance(Target? : string)

返回目标的余额。如果未提供目标参数，返回消息发送者的余额。

`Action` 消息的例子:

```lua=
send({
    Target = "{TokenProcess Identifier}",
    Tags = {
        Action = "Balance",
        Target = "{IDENTIFIER}"
    }
})
```

消息返回结果的例子:

```
{
    Tags = {
        Balance = "50",
        Target = "LcldyO8wwiGDzC3iXzGofdO8JdR4S1_2A6Qtz-o33-0",
        Ticker = "FUN"
    }
}
```

### Balances()

返回 Token 中所有参与者的余额。

```lua
send({
    Target = "[TokenProcess Identifier]",
    Tags = {
        Action = "Balances",
        Limit = 1000, # TODO: Is this necessary if the user is paying for the compute and response?
        Cursor? = "BalanceIdentifer"
    }
})
```

消息返回结果的例子:

```lua
{
    Data = {
        "MV8B3MAKTsUOqyCzQ0Tsa2AR3TiWTBU1Dx0xM4MO-f4": 100,
        "LcldyO8wwiGDzC3iXzGofdO8JdR4S1_2A6Qtz-o33-0": 50
    }
}
```

### Transfer(Target, Quantity)

如果发送者拥有足够的余额，则向目标发送 `Quantity`，向接收者发出 `Credit-Notice`，向发送者发出 `Debit-Notice`。如果发送者余额不足，操作失败并通知发送者。

```lua
send({
    Target = "[TokenProcess Identifier]",
    Tags = {
        { name = "Action", value = "Transfer" },
        { name = "Recipient", value = "[ADDRESS]" },
        { name = "Quantity", value = "100" }
    }
})
```

在未设置 `Cast` 时，如果发送成功，则应发送通知消息。

```lua
ao.send({
    Target = "[Recipient Address]",
    Tags = {
        { name = "Action", value = "Credit-Notice" },
        { name = "Sender", value = "[ADDRESS]" },
        { name = "Quantity", value = "100"}
    }
})
```

接收者将从消息的 `From-Process` 标签中知道他们已收到该 Token 。

### Get-Info()

```lua
send({
    Target = "{Token}",
    Tags = {
        Action = "Info"
    }
})
```

### Mint() [optional]

实现 `Mint` 操作，允许特定用户创建更多 Token 余额。

```lua
send({
    Target ="{Token Process}",
    Tags = {
        Action = "Mint",
        Quantity = "1000"
    }
})
```

# 子账本进程（Subledger Processes）

子账本必须实现 Token 合约的完整消息协议（不包括 `Mint` 操作）。子账本必须为进程实现额外的功能和生成参数。接下来描述子账本和父账本的区别。

### （创建请求的参数）Spawning Parameters

每个符合规范的子账本的进程在其创建请求的消息中必须携带以下特定参数：

| Tag          | 描述                              | 有没有强制性 |
| ------------ | --------------------------------- | ------------ |
| Source-Token | 这个子账本代表的根进程的 `ID`。   | :x:          |
| Parent-Token | 这个子账本连接到的父进程的 `ID`。 | :x:          |

### `Credit-Notice` Handler

在收到 `Credit-Notice` 消息时，符合规范的子账本进程必须检查所涉及的进程是否是 `Parent-Token`。如果是，则子账本必须将 `Sender` 的余额增加指定数量。

### Transfer(Target, Quantity)

除了常规的 `Credit-Notice` 标签外，子账本进程还必须提供 `Source-Token` 和 `Parent-Token` 两个标签。接受者如果信任子账本进程的 `Module`，用户就可以在子账本中进行 `Source-Token` 上的存款那样的转账和进行借贷动作。

修改后的 `Credit-Notice` 结构如下：

```lua
ao.send({
    Target = "[Recipient Address]",
    Tags = {
        { name = "Action", value = "Credit-Notice" },
        { name = "Quantity", value = "100"},
        { name = "Source-Token", value = "[ADDRESS]" },
        { name = "Parent-Token", value = "[ADDRESS]" }
    }
})
```

### Withdraw(Target?, Quantity)

所有子账本必须允许余额持有者将他们的 Token 提取到父账本中。收到一个 `Action: Withdraw` 消息后，子账本必须向其 `Parent-Ledger` 发送一个 `Action` 消息，将请求的 Token 转移到调用者的地址，同时在本地扣除他们的账户。这个转移将会让调用者收到来自 `Parent-Ledger` 的 `Credit-Notice`。

```


Prompt: This is a Markdown documentation from the AO documentation repository. This is a continuation from the previous part. Filename: token.md Path: ../ao-cookbook/src/zh/references/token.md

Response:
ao.send({
    Target = "[Recipient Address]",
    Tags = {
        { name = "Action", value = "Credit-Notice" },
        { name = "Quantity", value = "100"},
        { name = "Source-Token", value = "[ADDRESS]" },
        { name = "Parent-Token", value = "[ADDRESS]" }
    }
})
```

### Withdraw(Target?, Quantity)

所有子账本必须允许余额持有者将他们的 Token 提取到父账本中。收到一个 `Action: Withdraw` 消息后，子账本必须向其 `Parent-Ledger` 发送一个 `Action` 消息，将请求的 Token 转移到调用者的地址，同时在本地扣除他们的账户。这个转移将会让调用者收到来自 `Parent-Ledger` 的 `Credit-Notice`。

```lua
send({
    Target = "[TokenProcess Identifier]",
    Tags = {
     { name = "Action", value = "Withdraw" },
     { name = "Recipient", value = "[ADDRESS]" },
     { name = "Quantity", value = "100" }
    }
})
```

# Token 例子

> 请注意: 在实现 Token 时，消息上的所有标签必须是 "string" 类型。你可以使用 `tostring` 函数将简单类型转换为字符串。

```lua
if not balances then
  balances = { [ao.id] = 100000000000000 }
end

if name ~= "Fun Coin" then
  name = "Fun Coin"
end

if ticker ~= "Fun" then
  ticker = "fun"
end

if denomination ~= 6 then
  denomination = 6
end

-- handler 处理传入的消息

handlers.add(
  "transfer",
  handlers.utils.hasMatchingTag("Action", "Transfer"),
  function (msg)
    assert(type(msg.Tags.Recipient) == 'string', 'Recipient is required!')
    assert(type(msg.Tags.Quantity) == 'string', 'Quantity is required!')

    if not balances[msg.From] then
      balances[msg.From] = 0
    end

    if not balances[msg.Tags.Recipient] then
      balances[msg.Tags.Recipient] = 0
    end

    local qty = tonumber(msg.Tags.Quantity)
    assert(type(qty) == 'number', 'qty must be number')
    -- handlers.utils.reply("Transfering qty")(msg)
    if balances[msg.From] >= qty then
      balances[msg.From] = balances[msg.From] - qty
      balances[msg.Tags.Recipient] = balances[msg.Tags.Recipient] + qty
      ao.send({
        Target = msg.From,
        Tags = {
          Action = "Debit-Notice",
          Quantity = tostring(qty)
        }
      })
      ao.send({
      Target = msg.Tags.Recipient,
      Tags = {
        Action = "Credit-Notice",
        Quantity = tostring(qty)
      }})
      -- if msg.Tags.Cast and msg.Tags.Cast == "true" then
      --   return
      -- end

    end
  end
)

handlers.add(
  "balance",
  handlers.utils.hasMatchingTag("Action", "Balance"),
  function (msg)
    assert(type(msg.Tags.Target) == "string", "Target Tag is required!")
    local bal = "0"
    if balances[msg.Tags.Target] then
      bal = tostring(balances[msg.Tags.Target])
    end
    ao.send({Target = msg.From, Tags = {
      Target = msg.From,
      Balance = bal,
      Ticker = ticker or ""
    }})
  end
)

local json = require("json")

handlers.add(
  "balances",
  handlers.utils.hasMatchingTag("Action", "Balances"),
  function (msg)
    ao.send({
      Target = msg.From,
      Data = json.encode(balances)
    })
  end

)

handlers.add(
  "info",
  handlers.utils.hasMatchingTag("Action", "Info"),
  function (msg)
    ao.send({Target = msg.From, Tags = {
      Name = name,
      Ticker = ticker,
      Denomination = tostring(denomination)
    }})
  end
)
```


Prompt: This is a Markdown documentation from the AO documentation repository. Filename: wasm.md Path: ../ao-cookbook/src/zh/references/wasm.md

Response:
# 认识 Web Assembly

WebAssembly（通常简称为 Wasm）是一种现代的二进制指令格式，为高级语言（如C、C++和Rust）提供了一个可迁移的编译目标。它可以支持在网络上部署客户端和服务器应用，并提供高水平的性能和效率。WebAssembly 是为了保持网络浏览器的安全性和沙盒功能而设计的，成为网络应用程序的选择之一。它是网络开发人员的关键技术，使他们能够用多种语言编写代码，并将代码编译为在浏览器中以接近原生速度运行的字节码。

WebAssembly 的重要性在于它能够弥合网络应用程序和本地应用程序之间的差距。它使得之前局限于桌面环境的复杂应用程序和游戏，能够在浏览器中以相当的性能运行。这为网络开发带来了新的可能性，包括创建高性能的网络应用程序、游戏，甚至将现有的桌面应用程序移植到网络上。WebAssembly 与 JavaScript 并行运行，通过使用更适合此类任务的语言编写性能关键组件，弥补了 JavaScript 的缺陷，从而增强了网络应用程序的功能和性能。


Prompt: This is a Markdown documentation from the AO documentation repository. Filename: community.md Path: ../ao-cookbook/src/zh/references/community.md

Response:
---
prev:
  text: "ao 编辑器设置"
  link: "/zh/references/editor-setup.md"
---

# 社区

[Autonomous Finance](https://www.autonomous.finance/)

- Autonomous Finance 是一个专注于 ao 网络内金融基础设施复杂性的研究和技术实体。

[BetterIdea](https://betteridea.dev/)

- 使用 BetterIDEa 构建更快、更智能、更高效的 AO 开发终极本地 Web IDE。

[Orbit](https://www.0rbit.co/)

- 0rbit 通过利用 ao 和 0rbit 节点的强大功能，将任何来自网络的数据提供给 ao 进程。用户向 0rbit ao 发送消息，0rbit 节点获取数据，然后用户进程接收数据。


Prompt: This is a Markdown documentation from the AO documentation repository. Filename: lua.md Path: ../ao-cookbook/src/zh/references/lua.md

Response:
# 认识 Lua

### 理解 Lua

- **背景**: Lua 是一种轻量、高级、多范式的编程语言，主要用于嵌入式系统和客户端。它因效率、简洁和灵活性而闻名。
- **核心特性**: Lua 提供了强大的数据描述构造、动态类型、高效的内存管理以及对面向对象编程的良好支持。

### 上手指南

1. **安装**: 访问 [Lua 的官方网站](http://www.lua.org/download.html) ，下载并安装 Lua。
2. **环境**: 你可以使用简单的文本编辑器和命令行，或者像 ZeroBrane Studio ，或带有 Lua 插件的 Eclipse 这样的集成开发环境（IDE）。

### 基础语法和概念 (在 aos 中的)

- **Hello World**:
  ```lua
  "Hello, World!"
  ```
- **变量和类型**: Lua 是动态类型的。基本类型包括 `nil`、`boolean`、`number`、`string`、`function`、`userdata`、`thread` 和 `table`。
- **控制结构**: 包括 `if`、 `while`、 `repeat...until` 和 `for`。
- **函数**: Lua 中的一等公民，支持闭包和高阶函数。
- **Tables**: Lua 中唯一的数据结构机制，可用于表示数组、集合、记录等。

### 动手试试

- **用 Lua 的交互模式进行实验**: 在你的终端中运行 `aos` 并尝试 Lua 命令。
- **写一些简单的脚本**: 创建 `.lua` 文件并使用 Lua 解释器运行它们。使用 `.load file.lua` 功能将 Lua 代码上传到你的 `aos` 进程中。

### 资源

- **官方文档**: [Lua 5.3 参考手册](https://www.lua.org/manual/5.3/)
- **在线教程**: 像 [Learn Lua](https://www.learn-lua.org/) 这样的网站非常适合进行交互式学习。
- **书籍**: 《Lua 编程》是一本全面的资源。（第一版可在 [网上](http://www.lua.org/pil/contents.html) 获取）
- **社区**: 加入像 [Lua 用户](http://lua-users.org/) 这样的论坛或社区，以获取支持和讨论。

### 最佳实践

- **保持极简**: Lua 的设计是简单灵活的。你要在代码中拥抱这种哲学。
- **性能**: 学习关于 Lua 的垃圾回收和高效利用 table 的知识。
- **集成**: 考虑 Lua 如何嵌入到其他应用程序中，特别是 C/C++ 项目中。

### 总结

Lua 是一种强大的语言，尤其在嵌入式系统和游戏开发领域。它的简单性和高效性让它成为特定用例的首选。祝你在 Lua 编程之旅中获得愉快的体验！


Prompt: This is a Markdown documentation from the AO documentation repository. Filename: ao.md Path: ../ao-cookbook/src/zh/references/ao.md

Response:
# ao 模块

版本: 0.0.3

`ao` 进程通信通过消息进行处理，每个进程用 ANS-104 DataItems 的格式接收消息，并且需要能够执行以下常见操作。

- isTrusted(msg) - 检查消息是否可信
- send(msg) - 将消息发给另一个进程
- spawn(module, msg) - 创建一个进程

这个 library 为 `ao` 开发者工具包提供了这些核心功能。开发者可以按需使用这个 library，但它是默认集成在开发者工具包里的。

## 属性

| 名称        | 描述                             | 类型   |
| ----------- | -------------------------------- | ------ |
| id          | 进程标识符 (TXID)                | string |
| \_module    | 模块标识符 (TXID)                | string |
| authorities | 可信任的交易集合                 | string |
| \_version   | library 的版本                   | string |
| env         | 交易评估环境                     | string |
| outbox      | 传出消息和生成新进程请求的发件箱 | object |

## 方法

### send(msg: Message\
) : Message\

send 方法接收一个完整的 Message 对象，或者包含部分属性的 Message 对象作为参数。它会在这个对象上另外添加特定的 `ao` 标签，并返回一个完整的消息对象，同时将它插入到 ao.outbox.Messages 的表中。

**传入参数**

- msg

Schema

```json
{
    "type": "object",
    "properties": {
        "Target": {
            "type": "string",
            "description": "Process/Wallet to send message to"
        },
        "Data": {
            "type": "any",
            "description": "data to send in message DataItem"
        },
        "Tags": {
            "type": "object or array<name,value>"
            "description": "This property can be an array of name,value objects or an object"
        }
    }
}
```

例子 1

```lua
local message = ao.send({
    Target = msg.From,
    Data = "ping",
    Tags = {
        {
            name = "Content-Type",
            value = "text/plain"
        }
    }
})
```

例子 2

```lua
local message = ao.send({
    Target = msg.From,
    Data = "ping",
    Tags = {
        "Content-Type" = "text/plain"
    }
})
```

**返回值**

Schema

```json
{
    "type": "object",
    "properties": {
        "Target": {
            "type": "string"
        },
        "Data": {
            "type": "any"
        },
        "Tags": {
            "type": "array"
            "description": "name/value array",
            "items": {
                "type": "object",
                "properties": {
                    "name": {"type": "string"},
                    "value":{"type":"string"}
                }
            }
        }
    }
}
```

### spawn(module : string, spawn : Spawn\
) : Spawn\

`spawn` 方法接收一个 TXID 模块作为第一个参数，以及一个完整的 Spawn 表，或者包含部分属性的 Spawn 表作为第二个参数。结果将返回一个完整的 Spawn 表。spawn 方法还会生成一个带有唯一引用标识符的 `Ref_` 标签。

**传入参数**

| 名称   | 描述                                              | 类型   |
| ------ | ------------------------------------------------- | ------ |
| module | TXID 是一个模块二进制文件的标识符，用于实例化进程 | string |
| spawn  | 包含完整或部分 `Data` 和 `Tags` 属性的 `spawn` 表 | table  |

Schema

module

```json
{
  "type": "string"
}
```

spawn

```json
{
  "type": "object",
  "properties": {
    "Data": { "type": "any" },
    "Tags": {
      "type": "object or array",
      "description": "can be either <name,value> array, or object"
    }
  }
}
```

**返回值**

Schema

```json
{
  "type": "object",
  "properties": {
    "Data": { "type": "any" },
    "Tags": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "name": { "type": "string" },
          "value": { "type": "string" }
        }
      }
    }
  }
}
```

### isTrusted(msg : Message\
) : boolean

在生成进程时，可以提供 0 个或多个 Authority 标签，ao library 会将这些值添加到 `ao` 属性中名为 `authorities` 的 table 数组中。这个数组为 ao.TN.1 提供了“权威证明”（Proof of Authority）功能。当消息到达 `handle` 方法时，开发者可以调用 `ao.isTrusted` 来验证消息是否来自可信来源。

**传入参数**

| 名称 | 描述                               | 类型  |
| ---- | ---------------------------------- | ----- |
| msg  | 用于检测这个进程是否可信的 Message | table |

Schema

```json
{
    "type": "object",
    "properties": {
        "Target": {
            "type": "string"
        },
        "Data": {
            "type": "any"
        },
        "Tags": {
            "type": "array"
            "description": "name/value array",
            "items": {
                "type": "object",
                "properties": {
                    "name": {"type": "string"},
                    "value":{"type":"string"}
                }
            }
        }
    }
}
```


Prompt: This is a Markdown documentation from the AO documentation repository. Filename: index.md Path: ../ao-cookbook/src/zh/references/index.md

Response:
---
prev:
  text: "aos 接口"
  link: "/zh/concepts/tour"
next:
  text: "Lua"
  link: "./lua"
---

# 参考

## 目录

- [Lua](lua)
- [Web Assembly](wasm)
- [ao 模块](ao)
- [Handlers](handlers)
- [代币](token)
- [加载 Arweave 数据](data)
- [定时消息](cron)
- [编辑器设置](editor-setup)


Prompt: This is a Markdown documentation from the AO documentation repository. Filename: handlers.md Path: ../ao-cookbook/src/zh/references/handlers.md

Response:
# Handlers (版本 0.0.3)

## 概览

Handlers library 提供了一种灵活的方式来管理和执行一系列基于模式的 handler。每个 handler 由一个匹配函数、一个处理函数和一个名称组成。这个 library 适用于需要根据不同的输入条件采取不同行动的场景。

## 模块结构

- `Handlers._version`: 代表 Handlers library 版本的字符串。
- `Handlers.list`: 存储注册的 handler 列表的表。

## 方法

### `Handlers.add(name, pattern, handler)`

添加一个新的 handler 或者根据名称更新已有的 handler。

### `Handlers.append(name, pattern, handle)`

在 handler 列表的末尾插入一个新的 handler。

#### 传入参数

- `pattern` (function 类型): 判断 handler 是否被执行的方法。
- `handle` (function 类型): handler 方法的执行函数。
- `name` (string 类型): handler 的唯一命名。

### `Handlers.prepend(name, pattern, handle)`

把一个新的 handler 加到 handler 列表的开头.

#### 传入参数

- 和 `handlers.append` 的一样。

### `Handlers.before(handleName)`

返回一个对象，可以在特定的 handler 前加入一个新的 handler。

#### 传入参数

- `handleName` (string 类型): 在新的 handler 加入前，需要给 handler 的命名。

#### 返回值

- 一个拥有 `add` 方法的对象，可以插入新的 handler。

### `Handlers.after(handleName)`

返回一个对象，可以在特定的 handler 后加入一个新的 handler。

#### 传入参数

- `handleName` (string 类型): 在新的 handler 加入后，需要给 handler 的命名。

#### 返回值

- 一个拥有 `add` 方法的对象，可以插入新的 handler。

### `Handlers.remove(name)`

根据名称从 handler 列表里移除一个 handler。

#### 传入参数

- `name` (string 类型): 要被移除的 handler 的名称。

### `Handlers.evaluate(msg, env)`

根据给定的消息和环境对每个 handler 进行评估。handler 按照它们在 handler 列表中出现的顺序依次调用。

#### 传入参数

- `msg` (table 类型): handler 要处理的消息。
- `env` (table 类型): handler 执行的环境。

#### 返回值

- `response` (类型取决于 handler 是否匹配): handler 的响应。如果没有匹配的 handler，返回一个默认消息。

## 使用案例

```lua
-- 定义模式和处理函数
local function myPattern(msg)
    -- 判断 handler 是否被执行
end

local function myHandle(msg, env, response)
    -- Handler 逻辑
end

-- 加一个新的 handler
Handlers.add("myHandler", myPattern, myHandle)

-- 评估一条消息
local response = handlers.evaluate({ key = "value" }, { envKey = "envValue" })
```

## 说明

- 根据 Handler 在 `handlers.list` 中的顺序执行
- 匹配函数返回 `0` 代表跳过 handler，返回 `-1` 代表在 handler 执行后中断，或者返回 `1` 代表继续执行下一个 handler。
- `evaluate` 方法可以从多个 handler 上连接响应。

## Handlers.utils

Handlers.utils 模块提供了两个常见的匹配模式函数和一个常见的处理函数。

- hasMatchingData(data)
- hasMatchingTag(name, value)
- reply(txt)

### Handlers.utils.hasMatchingData(data : string)

这个辅助函数返回一个需要消息参数的函数，因此你可以将它放入任何 handler 的匹配参数中。该函数会将传入消息的数据与作为参数提供的字符串进行比较。

```lua
Handlers.add("ping",
    Handlers.utils.hasMatchingData("ping"),
    ...
)
```

如果这个进入进程的消息有设置成 ”ping" 的数据，那么这个 handler 会匹配上它，并调用处理函数。

### Handlers.hasMatchingTag(name : string, value : string)

这个辅助函数返回一个需要消息参数的函数，因此你可以将它放入 Handlers 模块的任何匹配参数中。该函数会比较 Tag 的名称和数值，如果它们相等，则调用处理函数。

```lua
Handlers.add("ping",
    Handlers.utils.hasMatchingData("ping"),
    ...
)
```

### Handlers.reply(text : string)

这个辅助函数是一个简单的处理函数，就是将 text 的值放入发送消息的 Data 属性中。

```lua
Handlers.add("ping",
    Handlers.utils.hasMatchingData("ping"),
    Handlers.utils.reply("pong")
)
```


Prompt: This is a Markdown documentation from the AO documentation repository. Filename: editor-setup.md Path: ../ao-cookbook/src/zh/references/editor-setup.md

Response:
# 编辑器设置

内置的 ao 函数和实用工具不太好用。为了提升你的开发体验，建议你在你常用的文本编辑器中安装 [Lua Language Server](https://luals.github.io) 扩展插件，并添加 [ao插件](https://github.com/martonlederer/ao-definitions)。它们支持所有内置的 aos [模块](../guides/aos/index.md) 和 [全局变量](../guides/aos/intro#globals)。

## VS Code

安装 [sumneko.lua](https://marketplace.visualstudio.com/items?itemName=sumneko.lua) 扩展插件：

1. 在扩展市场中搜索 sumneko 的 "Lua"。
2. 下载并安装该扩展插件。
3. 打开 VS Code 命令面板，使用 `Shift + Command + P`（Mac）/ `Ctrl + Shift + P`（Windows/Linux），然后运行以下命令：

```
> Lua: Open Addon Manager
```

4. 在插件管理器中搜索 “ao”，它应该是第一个结果。点击 “启用”，然后就可以享受自动完成的功能了！

如果你不想为每个工作区重复这个过程，你可以从生成的工作区 `settings.json` 文件中复制 `Lua.workspace.library` 对象到你的全局 `settings.json` 文件中。

## 其他编辑器

1. 确认你的编辑器支持[语言服务器协议](https://microsoft.github.io/language-server-protocol/implementors/tools/)。
2. 按照 [luals.github.io](https://luals.github.io/#install) 上的指示安装 Lua 语言服务器。
3. 为语言服务器安装“ao”插件。


Prompt: This is a Markdown documentation from the AO documentation repository. Filename: data.md Path: ../ao-cookbook/src/zh/references/data.md

Response:
# 使用 ao 访问 Arweave 上的数据

在你的 ao 开发工作流程中，可能有时候你想要访问 arweave 上的数据。你的进程可以使用 ao 发送一条消息，然后 ao 网络会通过一个 Message 对象将数据提供给你的 Process 对象。

为了从 arweave 请求数据，你只需包含一个名为 `Load` 的 `Tag`，在该标签中，你可以使用数据的 TXID 来检索。

```lua

Send({
  Target = ao.id,
  Tags = {
    Load = "WFM_Mi2FUNGCeP7r99XyeE3ySurt07LHxEGfW-wuIdY",
    Action = "Data"
  }
})

```

这条消息通过处理到达进程时，在传入消息的 `Data` 属性中，有一个 DataItem 的引用。同时，DataItem 的 `Data` 将以 base64 的类型传递。

```lua
{
  Owner = "[Owner Address]"
  Target = "[Process Identifier]",
  Data = {
    Owner = "xDKpdiZ7H9n_SsdX_CMpkybMGIdin5AUciM00mQgxRE",
    Tags = {
      "Content-Type": "application/json"
    },
    Data = "[base64]",
    ...
  }
  ...
}

```

在 lua 中，你可以使用 “.base64” 模块将你的数据从 base64 解码回原始格式。

```lua
local base64 = require(".base64")

local data = base64.decode(Msg.Data.Data)
```

## 为什么从 Arweave 上面取数据

你的进程可能需要访问数据来做决策，或者你可能想要通过 `data` 加载功能，为你的进程添加特性。


Prompt: This is a Markdown documentation from the AO documentation repository. Filename: index.md Path: ../ao-cookbook/src/zh/welcome/index.md

Response:
---
next:
  text: "入门"
  link: "/zh/welcome/getting-started"
---

# 欢迎来到 ao

![ao logo](./ao-logo-grey.svg)

ao 是一个由无数进程组成的世界计算机。这些进程处在一个连贯的计算环境中，进程之间通过原生的消息进行无缝衔接，相互作用。

ao 是一个正在演化的去中心化程序生态系统，类比互联网，这里每个进程就像是一个个独立的网站。它们独立运行，但是又错综复杂的交织为一个统一的”联合体“。

## ao + aos: 火箭和火箭燃料

初次接触 ao，你可以使用操作系统 `aos` 与 ao 进行交互。

aos 是一个运行在进程中的抽象层，使得你可以轻松使用 ao 计算机的全部功能。 本手册将带你学习如何使用 aos，你会获得入门 ao 计算机所需的所有信息。

## 下一步

在接下来的教程中，我们将一起探索 ao，一起构建具备治理功能的聊天室、去中心化机器人等内容。

让我们开始吧！ 🚀


Prompt: This is a Markdown documentation from the AO documentation repository. Filename: getting-started.md Path: ../ao-cookbook/src/zh/welcome/getting-started.md

Response:
# 5分钟入门

我们将在 5 分钟内带你进行首次探险（第一次窥视兔子洞）。 🕳🐇

## 系统要求

aos 的本地客户端安装超级简单. 你需要有：

- [NodeJS](https://nodejs.org) 版本 20+. (查看 [此网页](https://nodejs.org/en/download/package-manager) 找到安装说明)。
- 一个称手的代码编辑器。

## 安装 aos

完成 NodeJS 安装后，你只需安装 aos 并运行它:

```sh
npm i -g https://get_ao.g8way.io
```

安装完成后，我们运行命令即可启动一个新的 aos 进程！

```sh
aos
```

aos 命令运行时，其实是你在使用密钥文件向 aos 验证你的身份的。如果没有指定，aos 会默认生成一个新的密钥文件并将其存储在本地 `~/.aos.json`。如果你有 Arweave 钱包，可以使用 `--wallet [location]` 参数使用指定钱包。

## 欢迎来到兔子洞

你刚刚启动的程序实例是本地客户端，它已准备好将消息发送到你的新进程（ao 计算机内的进程）。

连接后，你会看到以下内容：

```sh
          _____                   _______                   _____
         /\    \                 /::\    \                 /\    \
        /::\    \               /:::\    \               /::\    \
       /:::\    \             /::::\    \             /:::\    \
      /::::\    \           /::::::\    \           /::::\    \
     /::/\::\    \         /::/~~\::\    \         /::/\::\    \
    /::/__\::\    \       /::/    \::\    \       /::/__\::\    \
   /:::\   \::\    \     /::/    / \::\    \      \::\   \::\    \
  /::::\   \::\    \   /::/____/   \::\____\   ___\::\   \::\    \
 /::/\::\   \::\    \ |::|    |     |::|    | /\   \::\   \::\    \
/::/  \::\   \::\____\|::|____|     |::|    |/::\   \::\   \::\____\
\::/    \::\  /::/    / \::\    \   /::/    / \::\   \::\   \::/    /
 \/____/ \::\/::/    /   \::\    \ /::/    /   \::\   \::\   \/____/
          \::::/    /     \::\    /::/    /     \::\   \::\    \
           \:::/    /       \::\__/::/    /       \::\   \::\____\
           /::/    /         \::::::/    /         \::\  /::/    /
          /::/    /           \::::/    /           \::\/::/    /
         /::/    /             \:::/    /             \::::/    /
        /::/    /               \::/____/               \:::/    /
        \::/    /                 ~~                      \::/    /
         \/____/                                           \/____/

ao Operating System

aos - 1.4.1
2024 - Type ".exit" to exit
aos process:  1xM1_lDZ428sJHpTX7rtcR6SrDubyRVO06JEEWs_eWo

aos>
```

欢迎来到你在 ao 计算机的新家！现在看到的提示是你在这台去中心化机器中自己的个人服务器。 在接下来的教程里，我们将使用它探索 ao 的操作。

## 发送你的第一个命令

你所拥有的 aos 进程，已经驻留在 ao 计算机内部的服务器上，等待接收和执行你的命令。

为了让开发更加的简单，aos 使用 Lua 编程语言撰写命令。 还没学过 Lua？ 不要着急！ 这是一种超级简单、友好的语言。 看完本手册后你就顺带学会 Lua。

让我们打破僵局并输入：

```lua
aos> "Hello, ao!"
```

然后按 `[Enter]` 键。 你会看到 shell 签名并发布消息，请求结果，然后打印结果，如下所示：

```lua
"Hello, ao!"
```

## 呃。 有什么大不了的？

我们只是向进程发送一条消息，将其永久存储到 Arweave 中，然后要求分布式计算网络计算其结果。

虽然结果可能 _看起来_ 不是革命性的，但实际上你已经做了些相当牛逼的事。 你的进程是一个 _去中心化_ 服务器，不存在于地球上任何一个特定的地方。 它以数据形式存储在 Arweave 上，在不同机器之间复制，它分布在世界各地。 如果你愿意，在未来的任何时候，你都可以将此进程添加到一个新的计算单元中，计算单元通过日志重建进程状态（目前仅需一条命令就可以完成以上所有动作）。

你的新进程将获得如下特性：

- **灵巧安全**：你的服务器不驻留在地球上特定的地点。它无处不在又无处可寻 —— 不会被任何形式的物理破坏或篡改。
- **永久存在**：你的进程永远不会消失。它将始终以其 [✨全息状态✨](/zh/concepts/holographic-state) 存在于 Arweave 上，让你可以重新调用它并继续使用它。你无需再考虑维护的精力和费用，因为在进程运行过程中，已经支付了 $AR 进行永存。
- **无需许可**：你无需注册即可启动此服务器。使用它的权利都由去中心化的 Arweave 保证，无需获得谷歌、亚马逊或任何其他大型科技公司的批准。
- **无需信任**：你的服务器状态是 _数学上保证的_。这意味着你和其他人可以绝对地信任它，甚至不必信任它运行的底层硬件。此特性允许你构建无需信任的 _服务_ ：代码的执行完全由数学进行保障，不由任何特权的所有者控制和管理。

还有很多内容，但这些是基础知识。欢迎来到 ao 计算机，新朋友！ 我们很感激有你的加入。 🫡

## 下一步

在接下来的教程中，我们将一起探索 ao，一起构建具备治理功能的聊天室、去中心化机器人等内容。

我们继续...


Prompt: This is a Markdown documentation from the AO documentation repository. Filename: index.md Path: ../ao-cookbook/src/zh/welcome/testnet-info/index.md

Response:
---
prev:
  text: "入门"
  link: "../getting-started"
next:
  text: "CRED 和任务 FAQ"
  link: "/zh/welcome/legacynet-info/cred-and-quests"
---

# 参与 ao 测试网

2024年2月27日，`ao` 测试网上线，供开发者和早期用户探索这台超并行计算机。

## 什么是 ao 测试网？

ao 测试网允许用户免费与 ao 计算机交互，共同测试和构建主网。

你可以通过 aos 控制台连接 ao 计算机。 在接下来的文档中，你会发现许多可以尝试的任务，这些任务可以帮助你赚取 CRED 代币（测试网的代币）。

## 安装 aos 客户端

如果你已经装好 [NodeJS](https://nodejs.org)，你所需要做的就是安装 aos 并运行它：

```sh
npm i -g https://get_ao.g8way.io
```

安装后，我们只需运行以下命令即可启动新的 aos 进程！

```sh
aos
```

## 加入 ao 的原生社区聊天

ao 网络托管着许多聊天服务器，你可以直接从 aos 控制台与其他开发人员交谈。 要加载聊天客户端，请运行以下命令：

```lua
.load-blueprint chat
```

查看可用房间，你可以运行：

```lua
List()
```

加入房间并与其他开发者聊天，如下所示：

```lua
Join("Getting-Started", "yourName")
Say("Hi")
```

## AO 测试网的第一步

为了加快在 ao 中的构建速度，查看以下教程：

- 学习 [开始](/zh/tutorials/begin/) 教程来构建你自己的代币化聊天室
- 学习 [机器人和游戏](/zh/tutorials/bots-and-games/) 教程，构建一个在 ao-effect 竞技场中玩耍的机器人

## 帮助构建 ao 生态系统并赚取 CRED

ao 生态处于非常早期的阶段，充满机遇。 社区里有一个 `quest` 板块（任务板块），其中包含各种方法让你可以参与测试和构建软件以发展生态，同时赚 ao 原生代币 - legacynet CRED。

要列出当前可用的任务，请使用 `Join("Quests")` 和 `Say "/Quests"` 加入 `Quests` 聊天频道以接收任务列表。

玩得开心，如果需要帮助，请随时在 ao 聊天中向其他构建者寻求帮助！


Prompt: This is a Markdown documentation from the AO documentation repository. Filename: cred-and-quests.md Path: ../ao-cookbook/src/zh/welcome/testnet-info/cred-and-quests.md

Response:
# CRED 和任务 FAQ

::: info

`ao`生态系统目前还处于非常早期的阶段，充满机遇。社区任务板提供了许多参与测试和构建软件以发展生态系统的方法，同时还能赚取`ao`生态系统的原生货币：CRED。

:::

## 视频教程

<iframe width="680" height="350" src="https://www.youtube.com/embed/QA3OmkLcdRs?si=CLAZrIUhJ0aEGYxM" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>

## 什么是CRED?

CRED是`ao`测试网的原生货币，用于奖励完成任务的用户。

## CRED有什么用？

> CRED 代币是你的社交江湖地位，数字化身。
>
> 无论是谁，谁拥有最多的 CRED 代币，谁就是当之无愧的社交达人、也是你最值得信任的人。
>
> -Bobinstein (bobinstein), 来自 [Discord](https://discord.com/channels/1210396395643863101/1210606156582752436/1215723479672815647)

> [CRED] 的未来，充满无限可能。
>
> -Ros (rosmcmahon), 来自 [Discord](https://discord.com/channels/1210396395643863101/1210606156582752436/1217101371472478318)

## 如何获得 CRED？

你可以通过完成`ao`核心开发人员和社区贡献者制定的任务赚取 CRED。

## 想知道有哪些任务可以做吗？

ao 本地网络中有一个开发聊天室，您可以在那里查询任务信息。首先，启动 aos：

```sh
$ aos
```

接下来，加入 Quests 聊天室（如果你还没有加入的话）。你还可以将你的用户名/昵称作为第二个参数加入聊天室（可选）。

```lua
aos> Join("Quests")
# OR
aos> Join("Quests", "MyScreenName")
```

然后，你可以向聊天室发送 `/Quests` 命令。如果你加入了多个聊天室，还可以把第二个参数作为指定的聊天室名称，发送消息。

```lua
aos> Say("/Quests")
# OR
aos> Say("/Quests", "Quests")
```

几秒钟后，机器人会自动向聊天室发送所有可以做的任务信息。

## 如何查看任务详情？

你可以通过向`Quests` 聊天室发送命令 /Quests:[index] 了解更多详细信息，其中 [index] 应该替换为任务编号，例如：

```lua
aos> Say("/Quests:1", "Quests")
# OR
aos> Say("/Quests:2", "Quests")
```

### 任务1： "开始"

本文档的[开始](/tutorials/begin/index) 教程将详细介绍任务1的操作步骤。

### 任务 2：“机器人和游戏”

本教程的[机器人和游戏](/tutorials/bots-and-games/index)将详细介绍任务2的操作步骤

## 如何完成任务？

只要按照任务描述中的所有 步骤操作，包括提交领取奖励，就算完成任务啦！

## 如何获得 CRED？

每个任务的文本描述都会详细说明如何提交领取奖励的请求。 完成任务后，请务必按照任务描述中的指示提交领取奖励的请求。 只有完成任务的所有步骤，并提交请求，你才能获得CRED奖励。审核领取奖励的请求需要一些手动处理时间，请耐心等待。

## 我什么时候可以拿到我的CRED？

你的领取奖励请求会经过人工审核，以确认你是否完成了所有必要步骤。请在工作日耐心等待约 24 小时，以便处理你的请求。

## 如何查看/核实我当前的 CRED 余额？

你可以将`credUtils` 蓝图加载到你的 ao 进程中，以便快速查询你的 CRED 余额，甚至可以将 CRED 发送给朋友！

```lua
aos> .load-blueprint credUtils
Loading...  credUtils                                        # sample output
undefined                                                    # sample output
aos> CRED.balance
Your CRED balance has not been checked yet. Updating now.    # sample output
CRED Balance updated: 500.000                                # sample output
```

了解有关 [aos 蓝图](/guides/aos/blueprints/index)的更多信息。


Prompt: This is a Markdown documentation from the AO documentation repository. Filename: index.md Path: ../ao-cookbook/src/zh/guides/index.md

Response:
---
prev:
  text: "扩建竞技场"
  link: "zh/tutorials/bots-and-games/build-game"
next:
  text: "aos"
  link: "./aos/index"
---

# 指南

本指南旨在帮助你导览 **ao**和 **aos**，可以帮助你构建聊天室、去中心自治机器人等程序。

## 章节列表

- [aos](aos/index)
- [aoconnect](aoconnect/aoconnect)


Prompt: This is a Markdown documentation from the AO documentation repository. Filename: troubleshooting.md Path: ../ao-cookbook/src/zh/guides/aos/troubleshooting.md

Response:
# 使用 ao.link 进行故障排除

使用去中心计算机和网络，你需要能够排除故障，而不仅仅是你自己的代码。你需要跟踪进程和消息，这就是 [https://ao.link](https://ao.link) 工具箱的必要之处。

![ao.link homepage displaying ao network stats](aolink.png)

## 分析

AOLink 4种分析指标:

- 消息总数 (Total Messages)
- 用户总数 (Total Users)
- 进程总数 (Total Processes)
- 模块总数 (Total Modules)

这些指标可以让你快速了解 ao 网络的总体运行状况。

## 事件 (Events)

下面是 ao 计算机里的最新事件。 它们是一个已执行的消息列表。 这些事件可以是任何 ao 数据协议类型。 你可以单击进程 ID 或消息 ID 来获取详细信息。

![ao.link list of events](aolink-list-example.png)

### 消息细节

![ao.link message details displaying the message processed](aolink-message-details.png)

消息细节包括以下关键信息：

- From
- To
- Block Height
- Created
- Tags
- Data
- Result Type
- Data

如果你想进一步排除故障和调试，你可以通过单击 “Compute” 来查看 CU（计算单元）的结果。

![ao.link compute result example for debugging](aolink-compute-example.png)

### 进程细节

![ao.link displaying a process in details](aolink-process-details.png)

进程细节提供进程的详细信息，在标签（Tag）中查看该进程的实例化所使用的各个模块，这非常有用
左侧的图表显示的是进程的交互图。
在本例中，这是 DevChat，你可以看到通过注册和广播消息进行交互的所有进程。
这个例子是 DevChat 进程的实例，你可以看到通过注册和消息广播与之交互的所有进程

## 更多问题?

请随时访问 DataOS 的 Discord 社区。
https://discord.gg/4kF9HKZ4Wu

## 总结

AOLink 是一款很好的工具，用于追踪 ao 计算机中的事件，请试一试。此外 permaweb 上还有另一个扫描工具：https://ao_marton.g8way.io/ - 试一试吧！


Prompt: This is a Markdown documentation from the AO documentation repository. Filename: installing.md Path: ../ao-cookbook/src/zh/guides/aos/installing.md

Response:
# 安装 aos

安装 aos 只需要 `NodeJS` - https://nodejs.org

> 注意: 如果你使用的是 Windows 系统，最后使用 WSL 命令行.

```sh
npm i -g https://get_ao.g8way.io
```

安装完之后你可以输入 `aos` 来运行系统


Prompt:
This is a Markdown documentation from the AO documentation repository. Filename: token.md Path: ../ao-cookbook/src/zh/guides/aos/token.md
Note: This content continues in the next part.

Response:
# 在 ao 中创建 Token

创建 token 时，我们将遵循[Token 规范](../../references/token.md)中概述的原则，并使用ao中的[Lua 语言](../../references/lua.md)铸造。

### 创建 Token 的两种方式:

**1 - 使用 token 蓝图（token blueprint）:**

`.load-blueprint token`
使用蓝图将创建一个 token，其中所有 Handler 和状态都已经定义。这是创建 token 最简单的方法。加载蓝图后，你可以自定义这些 Handler 和状态。

你可以在此处了解更多有关蓝图的信息：[蓝图](../aos/blueprints/index.md)

::: info
虽然使用 token 蓝图虽然可以快速创建，但你仍然需要了解如何进行[加载和测试](token.html#loading-and-testing), 以便根据需要进行自定义。
:::

**2 - 从零开始构建:**

以下指南将指导你完成从零开始创建 token。这是创建 token 的一种更高级的方法，可以让你更好地理解 token 的工作原理。

## 准备工作

### **步骤 1：初始化 Token**

- 打开你的文本编辑器，最好是在与之前教程中使用的文件夹相同的位置中打开。
- 创建一个名为 `token.lua` 的新文件。
- 在 `token.lua` 文件中，首先，初始化 token 的状态，定义其余额、名称、代码等：

```lua
local json = require('json')

if not Balances then Balances = { [ao.id] = 100000000000000 } end

if Name ~= 'My Coin' then Name = 'My Coin' end

if Ticker ~= 'COIN' then Ticker = 'COIN' end

if Denomination ~= 10 then Denomination = 10 end

if not Logo then Logo = 'optional arweave TXID of logo image' end
```

![token.lua image 1](./token1.png)

让我们梳理一下我们所做的工作：

- `local json = require('json')`: 这行代码首先导入了一个模块供以后使用。

- `if not Balances then Balances = { [ao.id] = 100000000000000 } end`: 第2行代码正在初始化一个叫做 Balances 表格，此表格用于记录谁拥有 Token 和持有的数量。设置 ao.id 账户为初始的 token 持有者，并拥有所有 token 的初始余额。

- 接下来的 4 行，除了 `if Denomination`外，`if Name`、`if Ticker`、`if Denomination` 和 `if not Logo` 都是可选项，它们分别用于定义 token 的名称、代码、最小单位和LOGO。

::: info

`if Denomination ~= 10 then Denomination = 10 end` 表示我们应该将多少个 token 视为一个单位。
:::

### **步骤 2：信息和余额的 Handlers**

#### 消息的 Handlers

现在让我们添加第一个 Handler 来处理收到的消息。

```lua
Handlers.add('info', Handlers.utils.hasMatchingTag('Action', 'Info'), function(msg)
  ao.send(
      { Target = msg.From, Tags = { Name = Name, Ticker = Ticker, Logo = Logo, Denomination = tostring(Denomination) } })
end)
```

![Token.lua image 2](./token2.png)

::: info

此时，你可能已经注意到，我们正在 `token.lua` 文件中构建所有 Handler，而不是使用 `.editor`。

对于许多 handlers 和进程来说，使用 `.editor` 创建 handler 没有任何问题，但由于我们正在创建一个完整的进程来初始化 token 、设置信息、处理余额、转移，和铸造 Handler，因此最好将所有内容都保存在一个文件中。

这么做是为了让我们保持一致性，因为每次我们将 `token.lua` 文件重新加载到 `aos` 中时，每个 handler 都会更新。
:::

这段代码的意思是，如果有人发送一条带有标签 Action = "info" 的消息，那么我们的 token 将返回一条消息，其中包含所有之前定义的信息。注意的是， Target = msg.From，这是在告诉 ao 我们要回复向我们发送此消息的进程。

#### 信息（Info）和 token 余额（Balance）的Handlers

现在我们可以添加两个用于提供 token 余额信息的 Handler。

```lua
Handlers.add('balance', Handlers.utils.hasMatchingTag('Action', 'Balance'), function(msg)
  local bal = '0'

  -- If not Target is provided, then return the Senders balance
  if (msg.Tags.Target and Balances[msg.Tags.Target]) then
    bal = tostring(Balances[msg.Tags.Target])
  elseif Balances[msg.From] then
    bal = tostring(Balances[msg.From])
  end

  ao.send({
    Target = msg.From,
    Tags = { Target = msg.From, Balance = bal, Ticker = Ticker, Data = json.encode(tonumber(bal)) }
  })
end)

Handlers.add('balances', Handlers.utils.hasMatchingTag('Action', 'Balances'),
             function(msg) ao.send({ Target = msg.From, Data = json.encode(Balances) }) end)

```

以上代码的第一个Handler `Handlers.add('balance)'` 处理来自某个进程或用户查询自身余额的请求，然后它会回复一条包含余额信息的消息。第二个Handler `Handlers.add('balances)'` 获取整个 Balances 表。

### **步骤 3：转账(Transfer) Handlers**

在开始测试之前，我们将添加另外 2 个Handler，其中一个允许在进程或用户之间转移 token 。

```lua
Handlers.add('transfer', Handlers.utils.hasMatchingTag('Action', 'Transfer'), function(msg)
  assert(type(msg.Tags.Recipient) == 'string', 'Recipient is required!')
  assert(type(msg.Tags.Quantity) == 'string', 'Quantity is required!')

  if not Balances[msg.From] then Balances[msg.From] = 0 end

  if not Balances[msg.Tags.Recipient] then Balances[msg.Tags.Recipient] = 0 end

  local qty = tonumber(msg.Tags.Quantity)
  assert(type(qty) == 'number', 'qty must be number')

  if Balances[msg.From] >= qty then
    Balances[msg.From] = Balances[msg.From] - qty
    Balances[msg.Tags.Recipient] = Balances[msg.Tags.Recipient] + qty

    --[[
      Only Send the notifications to the Sender and Recipient
      if the Cast tag is not set on the Transfer message
    ]] --
    if not msg.Tags.Cast then
      -- Send Debit-Notice to the Sender
      ao.send({
        Target = msg.From,
        Tags = { Action = 'Debit-Notice', Recipient = msg.Tags.Recipient, Quantity = tostring(qty) }
      })
      -- Send Credit-Notice to the Recipient
      ao.send({
        Target = msg.Tags.Recipient,
        Tags = { Action = 'Credit-Notice', Sender = msg.From, Quantity = tostring(qty) }
      })
    end
  else
    ao.send({
      Target = msg.Tags.From,
      Tags = { Action = 'Transfer-Error', ['Message-Id'] = msg.Id, Error = 'Insufficient Balance!' }
    })
  end
end)
```

总之，这段代码会检查收件人标签 (Recipient Tag) 和数量标签 (Quantity Tag) 是否已提供。如果发送人和接收者的余额不存在，则初始化他们的余额。然后尝试将指定数量的 token 转移到接收者的余额账户。

```lua
Balances[msg.From] = Balances[msg.From] - qty
Balances[msg.Tags.Recipient] = Balances[msg.Tags.Recipient] + qty
```

如果转账成功，则向原始消息的发送者发送借记通知 (Debit-Notice)，并向接收者发送贷记通知 (Credit-Notice)。

```lua
-- Send Debit-Notice to the Sender
ao.send({
    Target = msg.From,
    Tags = { Action = 'Debit-Notice', Recipient = msg.Tags.Recipient, Quantity = tostring(qty) }
})
-- Send Credit-Notice to the Recipient
ao.send({
    Target = msg.Tags.Recipient,
    Tags = { Action = 'Credit-Notice', Sender = msg.From, Quantity = tostring(qty) }
})
```

如果账户余额不足 (insufficient balance) ，则会发送交易失败的消息。


Prompt: This is a Markdown documentation from the AO documentation repository. This is a continuation from the previous part. Filename: token.md Path: ../ao-cookbook/src/zh/guides/aos/token.md

Response:
的余额账户。

```lua
Balances[msg.From] = Balances[msg.From] - qty
Balances[msg.Tags.Recipient] = Balances[msg.Tags.Recipient] + qty
```

如果转账成功，则向原始消息的发送者发送借记通知 (Debit-Notice)，并向接收者发送贷记通知 (Credit-Notice)。

```lua
-- Send Debit-Notice to the Sender
ao.send({
    Target = msg.From,
    Tags = { Action = 'Debit-Notice', Recipient = msg.Tags.Recipient, Quantity = tostring(qty) }
})
-- Send Credit-Notice to the Recipient
ao.send({
    Target = msg.Tags.Recipient,
    Tags = { Action = 'Credit-Notice', Sender = msg.From, Quantity = tostring(qty) }
})
```

如果账户余额不足 (insufficient balance) ，则会发送交易失败的消息。

```lua
ao.send({
    Target = msg.Tags.From,
    Tags = { Action = 'Transfer-Error', ['Message-Id'] = msg.Id, Error = 'Insufficient Balance!' }
})
```

`if not msg.Tags.Cast then` 这行代码表示在 AO 协议中，如果设置了 Cast 标签就不会推送任何消息。

### **第 4 步：铸造（Mint） Handler**

最后，我们将添加一个 Handler，用于铸造新的 Token。

```lua
Handlers.add('mint', Handlers.utils.hasMatchingTag('Action', 'Mint'), function(msg, env)
  assert(type(msg.Tags.Quantity) == 'string', 'Quantity is required!')

  if msg.From == env.Process.Id then
    -- Add tokens to the token pool, according to Quantity
    local qty = tonumber(msg.Tags.Quantity)
    Balances[env.Process.Id] = Balances[env.Process.Id] + qty
  else
    ao.send({
      Target = msg.Tags.From,
      Tags = {
        Action = 'Mint-Error',
        ['Message-Id'] = msg.Id,
        Error = 'Only the Process Owner can mint new ' .. Ticker .. ' tokens!'
      }
    })
  end
end)
```

这段代码会检查数量标签(Quantity Tag)是否已提供，然后将指定的数量添加到 Balances 表。

## 加载和测试

当你创建了 `token.lua` 文件，或者你使用了 `.load-blueprint token` 命令，那么你就可以开始测试了。

#### 1 - 启动 aos 进程

确保你已通过在终端中运行 aos 来启动 aos 进程。

#### 2 - 加载 token.lua 文件

如果按照操作指南进行操作，则在 aos 进程所在的目录中会有一个 `token.lua` 文件。从 aos 提示符处加载此文件。

```sh
.load token.lua
```

#### 3 - 测试 Token

现在我们可以从同一个 aos 提示符向我们的 aos 进程 ID 发送消息，以查看是否正常工作。如果我们将 ao.id 用作目标，那么我们就是在向自己发送消息。

```sh
Send({ Target = ao.id, Action = "Info" })
```

这里应该会打印合约中定义的信息。检查最新收件箱消息以获取回复。

```sh
Inbox[#Inbox].Tags
```

这里应该会打印合约中定义的信息。

::: info
为了确保你能准确查看最新消息，请先运行`#Inbox`查看收件箱中的消息总数。
然后，运行最后一个消息编号以查看数据。

** Example: **
如果 `#Inbox`返回 `5`，则运行 `Inbox[5].Data` 查看数据。
:::

#### 4 - 转账

现在，尝试将 token 余额转账到另一个钱包或进程 ID。

::: info
如果你需要另一个进程 ID，可以在另一个终端窗口运行`aos [name]` 获取新的进程 ID。确保它与你当前使用的`aos [name]` 不同。

**示例:**

如果你在一个终端窗口中使用 aos，可以在另一个终端窗口中运行`aos test`获取新的进程 ID。
:::

```sh
Send({ Target = ao.id, Tags = { Action = "Transfer", Recipient = 'another wallet or processid', Quantity = '10000' }})
```

发送之后，终端会打印一条消息，发送方会看到类似于`借记通知 (Debit-Notice)` 的内容，而接收方则会看到`贷记通知 (Credit-Notice)` 的内容。

#### 5 - 检查余额

现在你已经转了一些 token ，让我们检查一下余额。

```sh
Send({ Target = ao.id, Tags = { Action = "Balances" }})
```

```sh
Inbox[#Inbox].Data
```

你会看到两个进程 ID 或钱包地址，每个地址都显示余额。第一个应该是你的发送进程 ID，第二个应该是接收者的进程 ID。

#### 6 - 铸造 token

最后，尝试铸造一些 token 。

```sh
Send({ Target = ao.id, Tags = { Action = "Mint", Quantity = '1000' }})
```

然后再次检查余额。

```sh
Send({ Target = ao.id, Tags = { Action = "Balances" }})
Inbox[#Inbox].Data
```

然后你会看到铸造 token 的进程 ID 的余额增加了。

## 结论

“创建 token”指南到此结束。学习构建自定义 token 可以为你的项目释放巨大的潜力；无论你是想创建新货币、游戏 token 、治理 token ，还是任何其他你能想到的东西。


Prompt: This is a Markdown documentation from the AO documentation repository. Filename: load.md Path: ../ao-cookbook/src/zh/guides/aos/load.md

Response:
# .load 命令

这个功能可以让你加载本地环境中的 lua 代码，给 aos 的开发者带来更好的开发体验。

在创建处理程序时你可能有大量代码，希望使用 vscode 等集成开发环境来管理它们。 你还可以安装 lua 扩展插件来做一些语法检查。

那么如何将本地的 lua 代码发布到你的 ao 进程中呢？ 这就是“.load”命令发挥作用的地方。

hello.lua

```lua
Handlers.add(
  "ping",
  Handlers.utils.hasMatchingData("ping"),
  Handlers.utils.reply("pong")
)
```

aos 脚本输入

```sh
.load hello.lua
```

十分简单! 🐶


Prompt: This is a Markdown documentation from the AO documentation repository. Filename: pingpong.md Path: ../ao-cookbook/src/zh/guides/aos/pingpong.md

Response:
# 创建一个 Pingpong 进程

这个教程将指导你在 aos 中创建一个简单的“ping-pong”过程。 在此过程中，每当进程收到带有数据“ping”的消息时，它都会自动回复“pong”。 这是 aos 中消息处理和进程间交互的基本示例。

## 步骤 1: 打开 `aos` CLI

- 首先打开命令行界面并输入 `aos` 进入 aos 环境。

## 步骤 2: 打开内置编辑器

- 在 aos CLI 中输入“.editor”打开内置文本编辑器。 你将在此处编写 pingpong 处理程序代码。

## 步骤 3: 添加 Pingpong Handler

- 在编辑器中，输入以下 Lua 代码来添加 pingpong 模式的处理程序：

  ```lua
  Handlers.add(
    "pingpong",
    Handlers.utils.hasMatchingData("ping"),
    Handlers.utils.reply("pong")
  )
  ```

- 这个 lua 脚本做了三个操作:
  1. 添加一个新的名为"pingpong"的 handler。
  2. 它使用 `Handlers.utils.hasMatchingData("ping")` 来检查收到的消息中是否有 "ping" 字段.
  3. 如果消息中包含 "ping", `Handlers.utils.reply("pong")` 会自动返回 "pong" 的消息.

## 步骤 4: 退出编辑器

- 在编写完代码后，输入 `.done` 并输入 Enter 来退出编辑器并运行脚本。

## 步骤 5: 测试 Pingpong 进程

- 为了测试进程，需要向进程发送带有 `ping` 的消息。你可以在 CLI 中使用下面的命令：
  ```lua
  Send({ Target = ao.id, Data = "ping" })
  ```
- 进程将在收件箱 `Inbox` 中收到带有 "pong" 的恢复消息。

## 步骤 6: 查看收件箱 Inbox

- 查看你的收件箱中是否有 "ping" 的消息，并确认是否发出了 “pong” 的回复消息。

```lua
Inbox[#Inbox].Data
```

## 步骤 7: 测试和观察

- 发送不同的消息进行测试，并观察“ping”消息如何触发“pong”响应。

## 步骤 8: 保存进程 (可选)

- 如果你想在将来使用此过程，请将处理程序代码保存在Lua文件中以便于加载

进入 aos 会话。

::: info

**额外提示:**

- **处理程序效率**: 简单的处理函数是关键. 确保它的执行效率并且只在正确的时候触发。

:::

## 结论

恭喜！ 您已经在 aos 中创建了一个基础的"ping-pong"进程。 本教程给理解 在aos 环境中的消息处理和进程交互奠定了基础。 随着您对这些概念越来越熟悉，您可以扩展到更复杂的流程和交互，探索 aos 的全部潜力。


Prompt: This is a Markdown documentation from the AO documentation repository. Filename: index.md Path: ../ao-cookbook/src/zh/guides/aos/index.md

Response:
---
prev:
  text: "指南"
  link: "../"
next:
  text: "概览"
  link: "zh/guides/aos/intro"
---

# aos

`ao` 是一台分布式计算的并行计算机，`aos` 是该计算机上的操作系统。

使用 `aos` 你可以与进程(processes)交互，并且非常简单地编写进程代码。 你所需要的只是一个终端和一个编辑器。

`aos` 选择 [lua](../../concepts/lua.md) 作为开发语言，这是一种健壮的动态语言，使用起来非常有趣。

如果你还没有这么做，请花 15 分钟浏览我们的[教程](../../tutorials/index)。

## 深入了解 `aos`

- [aos 概览](./intro)
- [安装](./installing)
- [`aos` CLI工具](./cli)
- [自定义提示符(prompt)](./prompt)
- [构建一个 Ping-Pong 服务](./pingpong)

## 开发者指南

- [编辑器初始化](editor)
- [使用 ao.link 进行故障排除](troubleshooting)
- [理解收件箱（Inbox）](inbox-and-handlers)
- [常见问题](faq)

### [**模块**](modules/index)

- [JSON](modules/json)
- [`ao`](modules/ao)
- [Base64](modules/base64)
- [Pretty](modules/pretty)
- [Utils](modules/utils)


Prompt: This is a Markdown documentation from the AO documentation repository. Filename: editor.md Path: ../ao-cookbook/src/zh/guides/aos/editor.md

Response:
# 编辑器初始化

记住所有的内建函数和工具集方法是非常困难的。为了改善你的开发体验，我们推荐将 [Lua Language Server](https://luals.github.io) 扩展添加到您的编辑器，并添加 [ao addon](https://github.com/martonlederer/ao-definitions) 插件。它支持所有的 aos [内置模块](../aos/modules/index)和[全局变量](../aos/intro#globals)。

## VS Code

安装 [sumneko.lua](https://marketplace.visualstudio.com/items?itemName=sumneko.lua) 扩展:

1. 在扩展市场中搜索 sumneko 的“Lua”插件
2. 下载并且安装插件
3. 使用 `Shift + Command + P` (Mac) / `Ctrl + Shift + P` (Windows/Linux) 打开 VS Code 命令面板，然后运行以下命令：

```
> Lua: Open Addon Manager
```

4. 在插件管理器中搜索“ao”，选中第一个结果，单击“启用”完成自动安装。

## 其他编辑器

1. 验证你的编辑器是否支持[语言服务器协议](https://microsoft.github.io/language-server-protocol/implementors/tools/)
2. 安装[luals.github.io](https://luals.github.io/#install)中的 Lua 语言服务
3. 安装 "ao" 语言扩展服务


Prompt: This is a Markdown documentation from the AO documentation repository. Filename: prompt.md Path: ../ao-cookbook/src/zh/guides/aos/prompt.md

Response:
# aos 中的自定义提示符(Prompt)

## 步骤 1: 启动 aos 并打开编辑器

- 登录 aos 命令行
- 输入 `.editor` 打开内置编辑器

## 步骤 2: 编写自定义提示符函数

- 在编辑器中，定义你的用户提示符函数，例如：
  ```lua
  function Prompt()
      return "YourName@aos> "
  end
  ```
  将 `"YourName@aos> "` 定义为你喜欢的文本。

## 步骤 3: 退出并运行你的代码

- 输入 `.done` 并输入 Enter 来退出编辑器并执行代码
- 你的 aos 将显示新的自定义提示符

## 步骤 4: 保存以供将来使用 (可选)

- 如果你希望在将来的 aos 会话中使用这个提示符，请将脚本保存在 Lua 文件中。
- 在后续会话中，加载此脚本以应用自定义提示。

## 更多提示符功能

自定义提示可以带来很多实用性和创造力。 你可以在提示符中执行以下操作：

- 创建一个函数来跟踪收件箱中的未读消息数量：

  ```lua
    --Example:
    function Prompt()
      return "YourName Inbox: [" .. #Inbox .. "] > "
    end
  ```

- 跟踪你聊天室进程中的成员数量。
- 跟踪你进程地址持有的指定Token的数量。

## 结论

现在你已经了解了如何使用自定义提示符，现在你已经迈出了优化 ao 开发体验的关键一步。


Prompt: This is a Markdown documentation from the AO documentation repository. Filename: cli.md Path: ../ao-cookbook/src/zh/guides/aos/cli.md

Response:
# CLI

这里有一些命令参数来与 aos 进行交互：

- [name] - 使用你的钱包地址创建或者加载一个进程
- --load [file] - 加载一个文件，可以多次调用
- --cron [interval] - 只在创建进程的时候使用
- --wallet [walletfile] - 使用一个指定的钱包

## 使用 aos 管理多进程

```sh
aos
```

使用默认`default`名称创建或者连接到进程

```sh
aos chatroom
```

使用 `chatroom` 创建或者连接进程

```sh
aos treasureRoom
```

使用 `treasureRoom` 创建或者连接进程

## load 标志

```sh
aos treasureRoom --load greeting.lua --load treasure.lua --load puzzle.lua
```

可以使用 `load` 标志来加载一个或者多个代码文件到我的进程

## CRON 标志

如果你想让进程创建定时响应函数，需要在创建进程是调用 `cron` 标志

```sh
aos chatroom --cron 2-minutes
```

## Tag 标志

使用 tag 标志，你可以为进程创建用户标识。（例如将它们用作静态环境变量）:

```sh
aos chatroom --tag-name Chat-Theme --tag-value Dark --tag-name Chat-Name --tag-value Mychat
```

上面的命令会在你创建进程的时候添加用户定义标识

```ts
// process data item tags
[
  ...
  { name: "Chat-Theme", value: "Dark" },
  { name: "Chat-Name", value: "Mychat" }
  ...
]
```


Prompt: This is a Markdown documentation from the AO documentation repository. Filename: intro.md Path: ../ao-cookbook/src/zh/guides/aos/intro.md

Response:
# 概览

aos 使用了与众不同的方式构建进程与合约，ao 计算机是一个去中心的计算机网络，可以在任何地方进行计算，aos 是一个统一的交互终端。 你可以使用 aos 作为你的个人操作系统、构建 ao 进程的开发环境、以及创建您的机器人军团。

让我们来回顾一些基本指令。

## 变量

如果你想通过控制台显示变量的内容，可以直接输入变量的名称

```lua
Name
```

## 收件箱 (Inbox)

`收件箱 (Inbox)` 是你进程收到的消息集合。

```lua
Inbox[1]
```

如果您想查看消息个数，在 `Inbox` 前面加入 `#` 符号

```lua
#Inbox
```

查看收件箱的消息个数是个非常常见的功能，为了更简单，您可以创建一个函数，返回收件箱的消息个数并显示出来。

使用 `.editor` 或者 `.load file` 来将这个函数加载到您的进程。

```lua
function Prompt()
  return "Inbox: " .. #Inbox .. " > "
end
```

**预期的结果:**

```sh
undefined
Inbox: 2 >
```

您的 Prompt 函数已经可以显示收件箱中的消息数量。

## 全局定义

aos 中定义了一些全局变量、函数可以让开发变得更加直观。

| 名称                   | 描述                                                                         | 类型         |
| ---------------------- | ---------------------------------------------------------------------------- | ------------ |
| Inbox                  | 这是一个 lua 表，存储所有接收到的消息                                        | Table(Array) |
| Send(Message)          | 这是交互环境中使用的全局函数，可以向其他进程发送消息                         | function     |
| Spawn(Module, Message) | 这是 aos 中的全局函数，可以创建一个进程                                      |
| Name                   | 初始化您的进程名称                                                           | string       |
| Owner                  | 这个字符串标识了进程的所有者，如果修改这个字段，可能会影响您与进程交互的能力 | string       |
| Handlers               | 一个 lua 表，可以让您创建消息的处理函数                                      | table        |
| Dump                   | 接受 lua 中的表(Table)类型，并打印用户友好的数据内容                         | function     |
| Utils                  | 一个功能实用库，具有map、reduce、filter等功能                                | module       |
| ao                     | 这是用于发送消息和生成进程的核心函数库                                       | module       |

## 模块

在aos中，有一些内置的 lua 模块可以使用，这些模块可以通过“require”函数引用。

| 名称    | 描述                                       |
| ------- | ------------------------------------------ |
| json    | json 数据的编码和解码                      |
| ao      | ao 核心函数库，包括 send 、 spawn          |
| .base64 | base64 数据的编解码                        |
| .pretty | 格式化输出数据，使用 tprint 函数格式化数据 |
| .utils  | 一个实用工具库                             |


Prompt: This is a Markdown documentation from the AO documentation repository. Filename: inbox-and-handlers.md Path: ../ao-cookbook/src/zh/guides/aos/inbox-and-handlers.md

Response:
# 理解收件箱(Inbox)

在 aos 中，进程通过 handlers 获取消息并且执行。未处理的消息将进入进程的收件箱(Inbox)

## 什么是 Handlers?

Handler 是一个函数，接收并且处理进程消息。它处理这些消息是通过将消息作为参数来进行的。

```lua
function main(Message, ao)
  ...dostuff
  return {
    Output = ...,
    Messages = {},
    Spawns = {}
  }

end
```

`main` 函数返回一个 lua Table，包含 `Output, Message, Spawns` 或者 `Error`。在 aos 中你可以给进程添加 `Handler` 方法来处理逻辑，`Handler` 中有三个参数：

1. Handler 名字
2. 匹配函数
3. 处理函数

```lua
Handlers.add("name",
  function (Msg)
    -- Does this message match (return true or false)
    return Msg.Action == "Register"
  end,
  function (Msg)
    print("Registered User.")
    table.insert(Members, Msg.From)
    ao.send({Target = Msg.From, Data = "Registered."})
  end
)
```

## 关于收件箱

收件箱会存储尚未处理的消息，它们在这里等待被处理。一旦消息被处理，它就会被从收件箱中移除。

> 示例：将收件箱视为语音邮件。 正如未接听的电话会被转至语音信箱，让你稍后处理一样，你的进程不立即处理的消息都会进入收件箱。未处理的消息将被存储在这里，直到你处理他们。

## 总结

一开始似乎所有邮件都会进入你的收件箱，如果它们在处理后就被删除，这可能会令人疑惑。 语音邮件的类比应该可以解释这种设计：就像你接听的电话不会转到语音邮件一样，你处理过的消息也不会出现在收件箱中。 这说明了收件箱和 Handler 的功能。


Prompt: This is a Markdown documentation from the AO documentation repository. Filename: faq.md Path: ../ao-cookbook/src/zh/guides/aos/faq.md

Response:
# FAQ

## 所有权 (Ownership)

  进程的所有权

使用 aos 控制台创建一个新的进程，你的钱包地址就是进程的所有者。**aos** 使用 **Owner** 全局变量来标记进程的所有者。如果你想转移进程的所有权，或者将它变成无人可以控制的进程，你可以重定义 **Owner** 变量将它给其他钱包地址，或者设置为 **nil**。

## JSON

  将数据编码为 json 格式

当你向其他进程或者外部服务发送数据，你可能希望使用 JSON 作为数据编码格式。使用 lua 的 json 模块，可以对 lua Table 中的值进行 **encode** 和 **decode** 操作。

```lua
Send({Target = Router, Data = require('json').encode({hello = "world"})})
```

## Send 和 ao.send 对比

  什么时候使用 Send 或 ao.send

这两个方法都会将消息发送到一个进程，区别是 `ao.send` 可以返回消息，以便于记录日志或者进行故障排查。`Send` 函数通常在控制台中使用，更方便访问。在 `handlers` 中更推荐使用 `ao.send`，但他们在 `aos`中是可以相互替换的。


Prompt: This is a Markdown documentation from the AO documentation repository. Filename: chatroom.md Path: ../ao-cookbook/src/zh/guides/aos/blueprints/chatroom.md

Response:
# 聊天室蓝图 (Chatroom Blueprint)

聊天室蓝图是预先设计好的模板，可帮助你在 ao 中快速构建聊天室。蓝图是入门的绝佳方式，并且可以根据你的需求进行定制。

## 解析聊天室蓝图

- **Members**: `Members`数组用于存储已注册聊天室的用户。

- **Register Handler**: `register` handler 用于进程加入聊天室。当进程发送带有标签 `Action = "Register"` 的消息时，handler会将进程添加到 `Members` 数组中，并向进程发送一条消息确认注册。

- **Broadcast Handler**: `broadcast` handler支持进程向聊天室的所有成员发送消息。当进程发送带有标签 Action = "Broadcast" 的消息时，handler会将该消息发送给聊天室的所有成员。

### 如何使用：

1. 打开文本编辑器。
2. 打开终端。
3. 启动你的 `aos` 进程。
4. 输入 `.load-blueprint chatroom`

### 验证蓝图是否已加载：

输入 `Handlers.list` 查看新加载的 Handlers。

## 聊天室蓝图中包含的内容：

```lua
Members = Members or {}

Handlers.add(
  "register",
  Handlers.utils.hasMatchingTag("Action", "Register"),
  function (msg)
    table.insert(Members, msg.From)
    Handlers.utils.reply("registered")(msg)
  end
)

Handlers.add(
  "broadcast",
  Handlers.utils.hasMatchingTag("Action", "Broadcast"),
  function (msg)
    for _, recipient in ipairs(Members) do
      ao.send({Target = recipient, Data = msg.Data})
    end
    Handlers.utils.reply("Broadcasted.")(msg)
  end
)
```


Prompt: This is a Markdown documentation from the AO documentation repository. Filename: token.md Path: ../ao-cookbook/src/zh/guides/aos/blueprints/token.md

Response:
# Token 蓝图

token 蓝图是预先设计好的模板，可帮助你在 ao 中快速创建一个 token。蓝图是入门的绝佳方式，并且可以根据你的需求进行定制。

## 解析 token 蓝图

- **Balances**: `Balances` 数组用于存储参与者的 token 余额。

- **Info Handler**: `info` handler 可以检索 token 参数，例如名称、代码、Logo 和面值。

- **Balance Handler**: `balance` handler 检索单个用户的 token 余额。

- **Balances Handler**: `balances` handler 检索所有用户的 token 余额。

- **Transfer Handler**: `transfer` handler 向其他用户发送 token 。

- **Mint Handler**: `mint` handler 铸造新的 token 。

### 如何使用：

1. 打开你的文本编辑器。
2. 打开终端。
3. 启动你的`aos`进程.
4. 输入`.load-blueprint token`

### 验证蓝图是否已加载：

输入 `Handlers.list` 查看新加载的handlers。

## token 蓝图包含的内容：

```lua
local bint = require('.bint')(256)
local ao = require('ao')
--[[
  This module implements the ao Standard Token Specification.

  Terms:
    Sender: the wallet or Process that sent the Message

  It will first initialize the internal state, and then attach handlers,
    according to the ao Standard Token Spec API:

    - Info(): return the token parameters, like Name, Ticker, Logo, and Denomination

    - Balance(Target?: string): return the token balance of the Target. If Target is not provided, the Sender
        is assumed to be the Target

    - Balances(): return the token balance of all participants

    - Transfer(Target: string, Quantity: number): if the Sender has a sufficient balance, send the specified Quantity
        to the Target. It will also issue a Credit-Notice to the Target and a Debit-Notice to the Sender

    - Mint(Quantity: number): if the Sender matches the Process Owner, then mint the desired Quantity of tokens, adding
        them the Processes' balance
]]
--
local json = require('json')

--[[
     Initialize State

     ao.id is equal to the Process.Id
   ]]
--
if not Balances then Balances = { [ao.id] = tostring(bint(10000 * 1e12)) } end

if Name ~= 'Points Coin' then Name = 'Points Coin' end

if Ticker ~= 'Points' then Ticker = 'PNTS' end

if Denomination ~= 12 then Denomination = 12 end

if not Logo then Logo = 'SBCCXwwecBlDqRLUjb8dYABExTJXLieawf7m2aBJ-KY' end

--[[
     Add handlers for each incoming Action defined by the ao Standard Token Specification
   ]]
--

--[[
     Info
   ]]
--
Handlers.add('info', Handlers.utils.hasMatchingTag('Action', 'Info'), function(msg)
  ao.send({
    Target = msg.From,
    Name = Name,
    Ticker = Ticker,
    Logo = Logo,
    Denomination = tostring(Denomination)
  })
end)

--[[
     Balance
   ]]
--
Handlers.add('balance', Handlers.utils.hasMatchingTag('Action', 'Balance'), function(msg)
  local bal = '0'

  -- If not Target is provided, then return the Senders balance
  if (msg.Tags.Target and Balances[msg.Tags.Target]) then
    bal = Balances[msg.Tags.Target]
  elseif Balances[msg.From] then
    bal = Balances[msg.From]
  end

  ao.send({
    Target = msg.From,
    Balance = bal,
    Ticker = Ticker,
    Account = msg.Tags.Target or msg.From,
    Data = bal
  })
end)

--[[
     Balances
   ]]
--
Handlers.add('balances', Handlers.utils.hasMatchingTag('Action', 'Balances'),
  function(msg) ao.send({ Target = msg.From, Data = json.encode(Balances) }) end)

--[[
     Transfer
   ]]
--
Handlers.add('transfer', Handlers.utils.hasMatchingTag('Action', 'Transfer'), function(msg)
  assert(type(msg.Recipient) == 'string', 'Recipient is required!')
  assert(type(msg.Quantity) == 'string', 'Quantity is required!')
  assert(bint.__lt(0, bint(msg.Quantity)), 'Quantity must be greater than 0')

  if not Balances[msg.From] then Balances[msg.From] = "0" end
  if not Balances[msg.Recipient] then Balances[msg.Recipient] = "0" end

  local qty = bint(msg.Quantity)
  local balance = bint(Balances[msg.From])
  if bint.__le(qty, balance) then
    Balances[msg.From] = tostring(bint.__sub(balance, qty))
    Balances[msg.Recipient] = tostring(bint.__add(Balances[msg.Recipient], qty))

    --[[
         Only send the notifications to the Sender and Recipient
         if the Cast tag is not set on the Transfer message
       ]]
    --
    if not msg.Cast then
      -- Send Debit-Notice to the Sender
      ao.send({
        Target = msg.From,
        Action = 'Debit-Notice',
        Recipient = msg.Recipient,
        Quantity = tostring(qty),
        Data = Colors.gray .. "You transferred " .. Colors.blue .. msg.Quantity .. Colors.gray .. " to " .. Colors.green .. msg.Recipient .. Colors.reset
      })
      -- Send Credit-Notice to the Recipient
      ao.send({
        Target = msg.Recipient,
        Action = 'Credit-Notice',
        Sender = msg.From,
        Quantity = tostring(qty),
        Data = Colors.gray .. "You received " .. Colors.blue .. msg.Quantity .. Colors.gray .. " from " .. Colors.green .. msg.From .. Colors.reset
      })
    end
  else
    ao.send({
      Target = msg.From,
      Action = 'Transfer-Error',
      ['Message-Id'] = msg.Id,
      Error = 'Insufficient Balance!'
    })
  end
end)

--[[
    Mint
   ]]
--
Handlers.add('mint', Handlers.utils.hasMatchingTag('Action', 'Mint'), function (msg)
  assert(type(msg.Quantity) == 'string', 'Quantity is required!')
  assert(bint.__lt(0, msg.Quantity), 'Quantity must be greater than zero!')

  if not Balances[ao.id] then Balances[ao.id] = "0" end

  if msg.From == ao.id then
    -- Add tokens to the token pool, according to Quantity
    Balances[msg.From] = tostring(bint.__add(Balances[Owner], msg.Quantity))
    ao.send({
      Target = msg.From,
      Data = Colors.gray .. "Successfully minted " .. Colors.blue .. msg.Quantity .. Colors.reset
    })
  else
    ao.send({
      Target = msg.From,
      Action = 'Mint-Error',
      ['Message-Id'] = msg.Id,
      Error = 'Only the Process Owner can mint new ' .. Ticker .. ' tokens!'
    })
  end
end)

```


Prompt: This is a Markdown documentation from the AO documentation repository. Filename: index.md Path: ../ao-cookbook/src/zh/guides/aos/blueprints/index.md

Response:
---
prev:
  text: "创建代币"
  link: "../token"
next:
  text: "聊天室蓝图"
  link: "./chatroom"
---

# 蓝图 Blueprints

蓝图是预先设计好的模板，可帮助你在 ao 中快速构建。蓝图是入门的绝佳方式，并且可以根据你的需求进行定制。

## 可用的蓝图

- [聊天室蓝图](chatroom)

- [CRED 蓝图](cred-utils)

- [质押蓝图](staking)

- [Token 蓝图](token)

- [投票蓝图](voting)


Prompt: This is a Markdown documentation from the AO documentation repository. Filename: cred-utils.md Path: ../ao-cookbook/src/zh/guides/aos/blueprints/cred-utils.md

Response:
# CRED Utils 蓝图

CRED Utils 蓝图是一个预先设计的模板，可帮助你快速的在`ao`测试网中查看你的 CRED 余额。

## 解密 CRED 工具蓝图

### `CRED` 信息表

- **CRED.balance**: 运行 `CRED.balance` 会显示您进程已知的最新 CRED 余额。如果您之前从未查询过余额，它将自动获取。如果你认为你的CRED最近发生变动，建议先运行`CRED.update`更新余额。

- **CRED.process**: 运行此命令会打印发行CRED代币的进程ID。

- **CRED.send**: 就像调用函数一样使用 `CRED.send(targetProcessId, amount)` 可以将 CRED 从您的 ao 进程发送到另一个 ao 进程。

  - `targetProcessId`: **string**: 接收方的43位字符的进程 ID。
  - `amount`: **integer**: 要发送的 CRED 单位数量。1 CRED等于1000份CRED。

- **CRED.update**: 运行`CRED.update`命令会向 CRED 发行方的进程发送消息，从而获取您最新的 CRED 余额。更新后的余额将由下文提到的 `UpdateCredBalance` 处理程序接收处理。

### Handler 定义

- **Credit Handler**: `CRED_Credit` handler支持 CRED 发行方进程（以及aos）在你的 CRED 余额增加时自动通知你。

- **Debit Handler**: `CRED_Debit` Handler支持 CRED 发行方进程（以及aos）在你的 CRED 余额减少时自动通知你。

- **Update Balance Handler**: `UpdateCredBalance` handler 接收所有 CRED.update 请求的响应。

## 如何使用蓝图

1. 打开终端。
2. 启动你的`aos` 进程。
3. 输入 `.load-blueprint credUtils`。
4. 输入 `CRED.balance`

## CRED 工具蓝图中包含的内容：

有关 `aos` 最新版本中提供的蓝图，请参阅 github 上`aos` [source code on GitHub](https://github.com/permaweb/aos/blob/main/blueprints/credUtils.lua)的源代码。

```lua
CRED_PROCESS = "Sa0iBLPNyJQrwpTTG-tWLQU-1QeUAJA73DdxGGiKoJc"

_CRED = { balance = "Your CRED balance has not been checked yet. Updating now." }

local credMeta = {
    __index = function(t, key)
        -- sends CRED balance request
        if key == "update" then
            Send({ Target = CRED_PROCESS, Action = "Balance", Tags = { Target = ao.id } })
            return "Balance update requested."
            -- prints local CRED balance, requests it if not set
        elseif key == "balance" then
            if _CRED.balance == "Your CRED balance has not been checked yet. Updating now." then
                Send({ Target = CRED_PROCESS, Action = "Balance", Tags = { Target = ao.id } })
            end
            return _CRED.balance
            -- prints CRED process ID
        elseif key == "process" then
            return CRED_PROCESS
            -- tranfers CRED
        elseif key == "send" then
            return function(target, amount)
                -- ensures amount is string
                amount = tostring(amount)
                print("sending " .. amount .. "CRED to " .. target)
                Send({ Target = CRED_PROCESS, Action = "Transfer", Recipient = target, Quantity = amount })
            end
        else
            return nil
        end
    end
}

CRED = setmetatable({}, credMeta)

-- Function to evaluate if a message is a balance update
local function isCredBalanceMessage(msg)
    if msg.From == CRED_PROCESS and msg.Tags.Balance then
        return true
    else
        return false
    end
end

-- Function to evaluate if a message is a Debit Notice
local function isDebitNotice(msg)
    if msg.From == CRED_PROCESS and msg.Tags.Action == "Debit-Notice" then
        return true
    else
        return false
    end
end

-- Function to evaluate if a message is a Credit Notice
local function isCreditNotice(msg)
    if msg.From == CRED_PROCESS and msg.Tags.Action == "Credit-Notice" then
        return true
    else
        return false
    end
end

local function formatBalance(balance)
    -- Ensure balance is treated as a string
    balance = tostring(balance)
    -- Check if balance length is more than 3 to avoid unnecessary formatting
    if #balance > 3 then
        -- Insert dot before the last three digits
        balance = balance:sub(1, -4) .. "." .. balance:sub(-3)
    end
    return balance
end

-- Handles Balance messages
Handlers.add(
    "UpdateCredBalance",
    isCredBalanceMessage,
    function(msg)
        local balance = nil
        if msg.Tags.Balance then
            balance = msg.Tags.Balance
        end
        -- Format the balance if it's not set
        if balance then
            -- Format the balance by inserting a dot after the first three digits from the right
            local formattedBalance = formatBalance(balance)
            _CRED.balance = formattedBalance
            print("CRED Balance updated: " .. _CRED.balance)
        else
            print("An error occurred while updating CRED balance")
        end
    end
)

-- Handles Debit notices
Handlers.add(
    "CRED_Debit",
    isDebitNotice,
    function(msg)
        print(msg.Data)
    end
)

-- Handles Credit notices
Handlers.add(
    "CRED_Credit",
    isCreditNotice,
    function(msg)
        print(msg.Data)
    end
)
```


Prompt: This is a Markdown documentation from the AO documentation repository. Filename: voting.md Path: ../ao-cookbook/src/zh/guides/aos/blueprints/voting.md

Response:
# 投票蓝图 (Voting Blueprint)

投票蓝图是预先设计好的模板，可帮助你在 ao 中快速构建投票系统。蓝图是入门的绝佳方式，并且可以根据你的需求进行定制。

## 前提条件

投票蓝图要求先加载 [Token 蓝图](./token.md)

## 解析投票蓝图

- **Balances**: The `Balances` 数组用于存储参与者的代币余额。

- **Votes**: `Votes` 数组用于存储投票参与者地址。

- **Vote Action Handler**: `vote` handler 用户进程进行投票。当进程发送带有标记 `Action = "Vote"` 的消息时，handler 会将投票信息添加到`Votes`数组中，并向流程发送消息，确认投票。

- **Finalization Handler**: `finalize` handler支持进程完成投票过程。当进程发送带有标签 `Action = "Finalize"`的消息时，Handler会处理投票信息并完成投票过程。

### 如何使用:

1. 打开你的文本编辑器。
2. 打开终端。
3. 启动你的`aos`进程.
4. 输入`.load-blueprint voting`

### 验证蓝图是否已加载：

输入 `Handlers.list` 查看新加载的 handlers。

## 投票蓝图包含的内容：

```lua
Balances = Balances or {}
Votes = Votes or {}

-- Vote Action Handler
Handlers.vote = function(msg)
  local quantity = Stakers[msg.From].amount
  local target = msg.Tags.Target
  local side = msg.Tags.Side
  local deadline = tonumber(msg['Block-Height']) + tonumber(msg.Tags.Deadline)
  assert(quantity > 0, "No staked tokens to vote")
  Votes[target] = Votes[target] or { yay = 0, nay = 0, deadline = deadline }
  Votes[target][side] = Votes[target][side] + quantity
end

-- Finalization Handler
local finalizationHandler = function(msg)
  local currentHeight = tonumber(msg['Block-Height'])
  -- Process voting
  for target, voteInfo in pairs(Votes) do
      if currentHeight >= voteInfo.deadline then
          if voteInfo.yay > voteInfo.nay then
              print("Handle Vote")
          end
          -- Clear the vote record after processing
          Votes[target] = nil
      end
  end
end

-- wrap function to continue handler flow
local function continue(fn)
  return function (msg)
    local result = fn(msg)
    if (result) == -1 then
      return 1
    end
    return result
  end
end

Handlers.add("vote",
  continue(Handlers.utils.hasMatchingTag("Action", "Vote")), Handlers.vote)
-- Finalization handler should be called for every message
Handlers.add("finalize", function (msg) return -1 end, finalizationHandler)
```


Prompt: This is a Markdown documentation from the AO documentation repository. Filename: staking.md Path: ../ao-cookbook/src/zh/guides/aos/blueprints/staking.md

Response:
# 质押蓝图 (Staking Blueprint)

质押蓝图是预先设计好的模板，可帮助你在 ao 中快速构建质押系统。蓝图是入门的绝佳方式，并且可以根据你的需求进行定制。

## 前提条件

质押蓝图要求先加载 [token 蓝图](./token.md)。

## 解析 staking 蓝图

- **Stakers**: `Stakers` 数组用于存储质押者。

- **Unstaking**:`Unstaking` 数组用于存储参与者的解除质押请求。

- **Stake Action Handler**: `stake`handler 用于进程质押代币。当进程发送带有标签`Action = "Stake"`的消息时，处理程序会将质押代币添加到`Stakers` 数组中，并向进程发送一条消息确认质押。

- **Unstake Action Handler**: `unstake` handler 用于进程解除质押代币。当进程发送带有标签`Action = "Unstake"`的消息时，处理程序会将解除质押请求添加到 `Unstaking` 数组中，并向进程发送一条消息确认解除质押。

- **Finalization Handler**: `finalize` handler支持进程完成质押过程。当进程发送带有标签 `Action = "Finalize"`的消息时，处理程序会处理解除质押请求并完成质押过程。

### 如何使用:

1. 打开文本编辑器。

2. 打开终端。

3. 启动`aos`流程。

4. 输入 `.load-blueprint staking`

### 验证蓝图已加载:

输入`Handlers.list`查看新加载的Handler。

## 质押蓝图中的内容:

```lua
Stakers = Stakers or {}
Unstaking = Unstaking or {}

-- Stake Action Handler
Handlers.stake = function(msg)
  local quantity = tonumber(msg.Tags.Quantity)
  local delay = tonumber(msg.Tags.UnstakeDelay)
  local height = tonumber(msg['Block-Height'])
  assert(Balances[msg.From] and Balances[msg.From] >= quantity, "Insufficient balance to stake")
  Balances[msg.From] = Balances[msg.From] - quantity
  Stakers[msg.From] = Stakers[msg.From] or {}
  Stakers[msg.From].amount = (Stakers[msg.From].amount or 0) + quantity
  Stakers[msg.From].unstake_at = height + delay
end

-- Unstake Action Handler
Handlers.unstake = function(msg)
  local quantity = tonumber(msg.Tags.Quantity)
  local stakerInfo = Stakers[msg.From]
  assert(stakerInfo and stakerInfo.amount >= quantity, "Insufficient staked amount")
  stakerInfo.amount = stakerInfo.amount - quantity
  Unstaking[msg.From] = {
      amount = quantity,
      release_at = stakerInfo.unstake_at
  }
end

-- Finalization Handler
local finalizationHandler = function(msg)
  local currentHeight = tonumber(msg['Block-Height'])
  -- Process unstaking
  for address, unstakeInfo in pairs(Unstaking) do
      if currentHeight >= unstakeInfo.release_at then
          Balances[address] = (Balances[address] or 0) + unstakeInfo.amount
          Unstaking[address] = nil
      end
  end

end

-- wrap function to continue handler flow
local function continue(fn)
  return function (msg)
    local result = fn(msg)
    if (result) == -1 then
      return 1
    end
    return result
  end
end

-- Registering Handlers
Handlers.add("stake",
  continue(Handlers.utils.hasMatchingTag("Action", "Stake")), Handlers.stake)
Handlers.add("unstake",
  continue(Handlers.utils.hasMatchingTag("Action", "Unstake")), Handlers.unstake)
-- Finalization handler should be called for every message
Handlers.add("finalize", function (msg) return -1 end, finalizationHandler)
```


Prompt: This is a Markdown documentation from the AO documentation repository. Filename: json.md Path: ../ao-cookbook/src/zh/guides/aos/modules/json.md

Response:
# JSON

JSON 模块支持你使用 JavaScript 对象表示法对对象进行编码和解码。

### 示例用法

```lua
local json = require("json")

json.encode({
  a_string = "This is a string",
  nums = { 1, 2, 3 }
})
```

## 模块函数

### `encode()`

将 Lua 对象转换为 JSON 字符串。

- **参数:**
  - `val`: `{any}` 需要格式化的对象
- **返回值:** 对象的 JSON 格式字符串

#### 示例

```lua
--[[
  prints:
  "[{"name":"John Doe","age":23},{"name":"Bruce Wayne",age:34}]"
]]--
print(json.encode({
  { name = "John Doe", age = 23 },
  { name = "Bruce Wayne", age = 34 }
}))

-- prints "false"
print(json.encode(false))
```

### `decode()`

此函数用于解析 JSON 字符串并转换为 Lua 对象。

- **参数:**
  - `val`: `{any}` 待解码的 JSON 字符串
- **返回值:** JSON 字符串对应的 Lua 对象（对于无效的 JSON 字符串会抛出错误）

#### 示例

```lua
--[[
  creates the following table:
  { hello = "world" }
]]--
json.decode('{ "hello": "world" }')

-- creates a boolean with true value
json.decode("true")
```


Prompt:
This is a Markdown documentation from the AO documentation repository. Filename: utils.md Path: ../ao-cookbook/src/zh/guides/aos/modules/utils.md
Note: This content continues in the next part.

Response:
# Utils 工具库

该工具库提供了通用的表格操作和验证功能。它同时支持链式调用 (curry-style) 和传统编程方式。

> **注意**: 务必确保提供给以下函数的输入与期望的类型相匹配。

### 使用示例

```lua
local utils = require(".utils")

local totalSupply = utils.reduce(
  function (acc, v) return acc + v end,
  0,
  { 2, 4, 9 }
)

print(totalSupply) -- prints 15
```

## 模块函数

### `concat()`

此函数将数组 `b` 连接到数组 `a`。

- **Parameters:**
  - `a`: `{table}` 基础数组
  - `b`: `{table}` 要连接到基础数组的数组
- **Returns:** 由 `a` 和 `b` 合并而成的统一数组

#### 示例

```lua
-- returns { 1, 2, 3, 4, 5, 6 }
concat({ 1, 2, 3 })({ 4, 5, 6 })

-- returns { "hello", "world", "and", "you" }
concat({ "hello", "world" }, { "and", "you" })
```

### `reduce()`

此函数对数组中的所有元素执行 reducer 函数，最终返回一个 (统一的) 结果。

- **Parameters:**
  - `fn`: `{function}` reducer 函数,它按顺序接收之前的结果、当前元素的值和键。
  - `initial`: `{any}` (可选) 初始值
  - `t`: `{table}` 要处理的数组
- **Returns:** 通过对所有表格元素运行 reducer 函数所得的单个结果

#### 示例

```lua
local sum = utils.reduce(
  function (acc, v) return acc + v end,
  0,
  { 1, 2, 3 }
)

print(sum) -- prints 6
```

```lua
local sum = utils
  .reduce(function (acc, v) return acc + v end)(0)({ 5, 4, 3 })

print(sum) -- prints 12
```

### `map()`

此函数创建一个新数组，其中包含了对提供的数组中的每个元素调用指定映射函数的结果。

- **Parameters:**
  - `fn`: `{function}` map 函数,接收当前数组元素和键。
  - `data`: `{table}` 要映射的数组
- **Returns:** 由映射函数处理后的结果组成的的新数组

#### 示例

```lua
-- returns { "Odd", "Even", "Odd" }
utils.map(
  function (val, key)
    return (val % 2 == 0 and "Even") or "Odd"
  end,
  { 3, 4, 7 }
)
```

```lua
-- returns { 4, 8, 12 }
utils.map(function (val, key) return val * 2 end)({ 2, 4, 6 })
```

### `filter()`

此函数根据提供的函数来处理原数组，并创建一个只包含通过过滤条件的元素的新数组。

- **Parameters:**
  - `fn`: `{function}` 过滤函数。它接收当前数组中的元素作为参数，并应该返回一个布尔值,以决定该元素应被保留 (`true`) 还是过滤掉(`false`)。
  - `data`: `{table}` 要过滤的数组
- **Returns:** 经过过滤的新数组

#### 示例

```lua
-- keeps even numbers
utils.filter(
  function (val) return val % 2 == 0 end,
  { 3, 4, 7 }
)
```

```lua
-- keeps only numbers
utils.filter(
  function (val) return type(val) == "number" end,
  { "hello", "world", 13, 44 }
)
```

### `find()`

该函数查找匹配指定条件的第一个元素并返回。

- **Parameters:**
  - `fn`: `{function}` 查找函数。它接收当前数组元素作为参数，如果该元素满足条件则返回`true`，否则返回 `false`。
  - `t`: `{table}` 要查找元素的数组
- **Returns:** 找到的符合条件的第一个元素，如果没有找到则返回 `nil` (表示空值)。

#### Examples

```lua
local users = {
  { name = "John", age = 50 },
  { name = "Victor", age = 37 },
  { name = "Maria", age = 33 }
}

-- returns the user "John"
utils.find(
  function (val) return user.name == "John" end,
  users
)
```

```lua
-- returns the user "Maria"
utils.find(function (val) return user.age == 33 end)(users)
```

### `reverse()`

将数组转换为反序。

- **Parameters:**
  - `data`: `{table}` 需要反序的数组
- **Returns:** 反序的数组

#### 示例

```lua
-- is: { 3, 2, 1 }
utils.reverse({ 1, 2, 3 })
```

### `includes()`

判断值是否在数组中。

- **Parameters:**
  - `val`: `{any}` 需要检查的元素
  - `t`: `{table}` 需要检查的数组
- **Returns:** 一个布尔值，判断提供的 val 值是否属于该数组。true 表示存在，false 表示不存在。

#### 示例

```lua
-- this is true
utils.includes("John", { "Victor", "John", "Maria" })
```

```lua
-- this is false
utils.includes(4)({ 3, 5, 7 })
```

### `keys()`

返回表格的键值。

- **Parameters:**
  - `table`: `{table}` 要获取键值的表格
- **Returns:** 键数组

#### 示例

```lua
-- returns { "hello", "name" }
utils.keys({ hello = "world", name = "John" })
```

### `values()`

返回表格的值。

- **Parameters:**
  - `table`: `{table}` 需要获取值的表格
- **Returns:** 值数组

#### 示例

```lua
-- returns { "world", "John" }
utils.values({ hello = "world", name = "John" })
```

### `propEq()`

该函数检查表格中指定属性的值是否等于提供的数值。

- **Parameters:**
  - `propName`: `{string}` 要比较的属性名称
  - `value`: `{any}` 要比较的值
  - `object`: `{table}` 要从中选择属性的对象（表格）
- **Returns:** 一个布尔值，判断属性值是否等于提供的数值，如果属性值存在且等于提供的数值，则返回 True，否则返回 False。

#### 示例

```lua
local user = { name = "John", age = 50 }

-- returns true
utils.propEq("age", 50, user)
```

```lua
local user = { name = "Maria", age = 33 }

-- returns false
utils.propEq("age", 45, user)
```

### `prop()`

该函数的作用是从对象（表格）中获取指定属性的值。

- **Parameters:**
  - `propName`: `{string}` 要获取的属性名称
  - `object`: `{table}` 要从中选择属性值的对象
- **Returns:** 属性值，如果未找到，则返回 `nil`。

#### 示例

```lua
local user = { name = "Maria", age = 33 }

-- returns "Maria"
utils.prop("name", user)
```

```lua
local user = { name = "John", age = 50 }

-- returns 50
utils.prop("age")(user)
```

### `compose()`

此函数支持你将多个数组操作链接在一起，然后以逆序的方式对提供的数组执行这些操作。

- **Parameters:**
  - `...`: `{function[]}` 一组数组操作函数
  - `v`: `{table}` 要执行这些函数的数组
- **Returns:** 来自所提供操作的最终结果

#### 示例

```lua
-- returns 12
utils.compose(
  utils.reduce(function (acc, val) return acc + val end, 0),
  utils


Prompt: This is a Markdown documentation from the AO documentation repository. This is a continuation from the previous part. Filename: utils.md Path: ../ao-cookbook/src/zh/guides/aos/modules/utils.md

Response:
，如果未找到，则返回 `nil`。

#### 示例

```lua
local user = { name = "Maria", age = 33 }

-- returns "Maria"
utils.prop("name", user)
```

```lua
local user = { name = "John", age = 50 }

-- returns 50
utils.prop("age")(user)
```

### `compose()`

此函数支持你将多个数组操作链接在一起，然后以逆序的方式对提供的数组执行这些操作。

- **Parameters:**
  - `...`: `{function[]}` 一组数组操作函数
  - `v`: `{table}` 要执行这些函数的数组
- **Returns:** 来自所提供操作的最终结果

#### 示例

```lua
-- returns 12
utils.compose(
  utils.reduce(function (acc, val) return acc + val end, 0),
  utils.map(function (val) return val * 2 end)
)({ 1, 2, 3 })
```


Prompt: This is a Markdown documentation from the AO documentation repository. Filename: ao.md Path: ../ao-cookbook/src/zh/guides/aos/modules/ao.md

Response:
# ao

内置全局库，用于发送消息、创建进程等。

### 示例

全局对象 `ao` 在你的进程中的任何地方都可以访问：

```lua
-- sends a message to another process ("Transfer" action)
ao.send({
  Target = "usjm4PCxUd5mtaon7zc97-dt-3qf67yPyqgzLnLqk5A",
  Action = "Transfer",
  Recipient = "XjvCPN31XCLPkBo9bUeB7vAK0VC6-eY52-CS-6Iho8F",
  Quantity = tostring(1045)
})
```

## 模块变量

- `ao.id`: `{string}` 保存你进程中的 Arweave ID
- `ao.authorities`: `{table}` 授权的调用者数组
- `ao._module`: `{string}` 进程的 WASM 基础模块，每次调用都会执行。
- `ao._ref`: `{number}` 消息计数器，记录发出消息的总数。
- `ao._version`: `{string}` ao global 库版本。
- `ao.env`: `{table}` 进程初始化环境信息。

### `ao.env`

全局变量`ao.env`保存了有关进程初始化消息的信息。它遵循以下结构:

```json
{
  "type": "object",
  "properties": {
    "Process": {
      "type": "object",
      "properties": {
        "Id": {
          "type": "string",
          "example": "A1b2C3d4E5f6G7h8I9j0K1L2M3N4O5P6Q7R8S9T0"
        },
        "Owner": {
          "type": "string",
          "example": "Xy9PqW3vR5sT8uB1nM6dK0gF2hL4jC7iE9rV3wX5"
        },
        "TagArray": {
          "type": "array",
          "items": {
            "type": "object",
            "properties": {
              "name": {
                "type": "string",
                "example": "App-Name"
              },
              "value": {
                "type": "string",
                "example": "aos"
              }
            }
          },
          "example": [{ "name": "App-Name", "value": "aos" }]
        },
        "Tags": {
          "type": "object",
          "propertyNames": {
            "type": "string"
          },
          "patternProperties": {
            "": {
              "type": "string"
            }
          },
          "example": {
            "App-Name": "aos"
          }
        }
      }
    }
  }
}
```

## 模块函数

### `log()`

log 将值或消息添加到 `Results.Output` 表中，后面可以使用 [`aoconnect`](/guides/aoconnect/aoconnect.html) 库进行读取，对于调试很有帮助。

- **Parameters:**
  - `txt`: `{any}` log 的值/消息内容
- **Returns:** `{void}`

#### Examples

```lua
...
ao.log("Breakpoint reached")
...
ao.log({
  Message = "Transferred " .. quantity .. " tokens to " .. target,
  Quantity = quantity,
  Recipient = target
})
```

### `send()`

向另一个进程发送消息。将消息放入进程的 outbox，并根据 AO 标准(ao specs compliant ) 标注消息的 tag

- **Parameters:**
  - `msg`: `{table}` 待发送的消息
- **Returns:** 已发送的消息，包含已应用的标签和`DataItem`字段。

> **Note:** `msg` 表的每个字段都会作为 `DataItem` 标签，但以下字段除外：`"Target"`, `"Data"`, `"Anchor"`, `"Tags"`，因为这些字段将直接作为根级别的`DataItem`字段使用。

#### Example

```lua
-- sends a message to "XjvCPN31XCLPkBo9bUeB7vAK0VC6-eY52-CS-6Iho8F"
-- with the tag { "name": "Action", "value": "Ping" }
ao.send({
  Target = "XjvCPN31XCLPkBo9bUeB7vAK0VC6-eY52-CS-6Iho8F",
  Action = "Ping"
})
```

### `spawn()`

创建新进程。

- **Parameters:**
  - `module`: `{string}` 新进程使用的模块的 Arweave 交易 ID
  - `msg`: `{table}` 初始化进程的消息，格式在上面`send`部分中
- **Returns:** 初始化的消息

#### Example

```lua
ao.spawn("n0BFH80b73mi9VAWUzyuG9gEC3LI2zU2BFxum0N8A9s", {
  ["Custom-Tag"]: "Custom-Value"
})
```


Prompt: This is a Markdown documentation from the AO documentation repository. Filename: index.md Path: ../ao-cookbook/src/zh/guides/aos/modules/index.md

Response:
---
prev:
  text: "质押蓝图"
  link: "../blueprints/staking"
next:
  text: "JSON"
  link: "./json"
---

# 模块

aos 内置模块文档。

- [JSON](./json)
- [ao](./ao)
- [Base64](./base64)
- [Pretty](./pretty)
- [Utils](./utils)


Prompt: This is a Markdown documentation from the AO documentation repository. Filename: pretty.md Path: ../ao-cookbook/src/zh/guides/aos/modules/pretty.md

Response:
# Pretty 模块

这个模块的作用是将输出格式化、易于理解和阅读

## 模块函数

### `tprint()`

将 table 结构转换为格式化的字符串

- **Parameters:**
  - `tbl`: `{table}` 需要格式化 table 结构
  - `indent`: `{number}` 可选参数，表格每一层的缩进量
- **Returns:** 转为字符串格式的表格结构

#### 示例

```lua
local pretty = require(".pretty")

local formatted = pretty.tprint({
  name = "John Doe",
  age = 22,
  friends = { "Maria", "Victor" }
}, 2)

-- prints the formatted table structure
print(formatted)
```


Prompt: This is a Markdown documentation from the AO documentation repository. Filename: base64.md Path: ../ao-cookbook/src/zh/guides/aos/modules/base64.md

Response:
# Base64 编码模块

一个小型 `base64` 模块，可以用于编码和解码 Base64 格式的文本。

> **注意:** 为了优化处理大段文本的性能，建议开启缓存功能，最高可以将效率提升一倍。

### 使用示例

```lua
local base64 = require(".base64")

local str = "This will be encoded"

-- is: "VGhpcyB3aWxsIGJlIGVuY29kZWQ="
local encoded = base64.encode(str)

-- is: "This will be encoded"
local decoded = base64.decode(encoded)

assert(decoded == str)
```

## 模块函数

### `encode()`

此函数使用默认编码器表对提供的字符串进行编码。 编码器可以自定义，并且可以为较大的数据块提供缓存功能。

- **Parameters:**
  - `str`: `{string}` 需要编码的字符串
  - `encoder`: `{table}` 自定义编码表（可选）
  - `usecache`: `{boolean}` 可选的针对大字符串使用的缓存 (默认关闭)
- **Returns:** Base64 编码后的字符串

#### 示例

```lua
-- prints: "SGVsbG8gd29ybGQ="
print(base64.encode("Hello world"))

-- customize encoder and allow caching
base64.encode(
  "Hello world",
  base64.makeencoder(nil, "-"),
  true
)
```

### `decode()`

此函数使用默认解码器表对Base64编码的字符串进行解码。解码器可以自定义，并提供缓存功能。

- **Parameters:**
  - `str`: `{string}` 待解码的 Base64 编码字符串
  - `decoder`: `{table}` 可选的自定义解码表
  - `usecache`: `{boolean}` 可选的针对大字符串使用的缓存（默认关闭）
- **Returns:** 解码后的字符串

#### 示例

```lua
-- prints: "Hello world"
print(base64.decode("SGVsbG8gd29ybGQ="))

-- customize decoder and allow caching
base64.decode(
  "SGVsbG8gd29ybGQ=",
  base64.makedecoder(nil, "-"),
  true
)
```

### `makeencoder()`

此函数支持创建一个自定义编码表，以定制 [`encode()`](#encode)函数的输出结果。

- **参数:**
  - `s62`: `{string}` 可选的自定义字符，用于替换标准的字符 62（默认为 "+"）
  - `s63`: `{string}` 可选的自定义字符，用于替换标准的字符 63（默认为 "/"）
  - `spad`: `{string}` 可选的自定义填充字符，用于替换标准的填充字符 "="
- **Returns:** 自定义的编码表

#### 示例

```lua
-- create custom encoder
local encoder = base64.makeencoder(nil, nil, "~")

-- prints "SGVsbG8gd29ybGQ~" instead of "SGVsbG8gd29ybGQ="
print(base64.encode("Hello world", encoder))
```

### `makedecoder()`

创建一个自定义解码表，以便解码[自定义编码](#makeencoder) 的 base64 字符串。

- **Parameters:**
  - `s62`: `{string}` 可选的自定义字符，用于替换标准的字符 62（默认为 "+"）
  - `s63`: `{string}` 可选的自定义字符，用于替换标准的字符 63（默认为 "/"）
  - `spad`: `{string}` 可选的自定义字符，用于替换标准的填充字符 "="
- **Returns:** 自定义解码器表

#### 示例

```lua
local encoder = base64.makeencoder(nil, nil, "~")
local decoder = base64.makedecoder(nil, nil, "~")

-- "SGVsbG8gd29ybGQ~"
local encoded = base64.encode("Hello world", encoder)

-- prints "Hello world"
print(base64.decode(encoded, decoder))
```


Prompt: This is a Markdown documentation from the AO documentation repository. Filename: spawning-processes.md Path: ../ao-cookbook/src/zh/guides/aoconnect/spawning-processes.md

Response:
# 创建一个进程

可以在[ao Processes](../../concepts/processes.md) 概念中找到关于进程的深入介绍。本指南聚焦于使用 ao connect 创建一个进程。

为了创建一个进程，你必须拥有已经上传到 Arweave 的一个 ao 模块的 TXID。模块是进程的源代码。进程本身是那个源码的实例化。

你还必须拥有一个调度单元（Scheduler Unit, SU）的钱包地址。指定的 SU 将作为此进程的调度器。这意味着系统中的所有节点都可以知道它们需要为此进程读写到这个 SU。你可以使用下面的地址。

## 调度器的钱包地址

```sh
_GQ33BkPtZrqxA84vM8Zk-N2aO0toNNu_C-l-rawrBA
```

## 在 NodeJS 中创建一个进程

```js
import { readFileSync } from "node:fs";

import { createDataItemSigner, spawn } from "@permaweb/aoconnect";

const wallet = JSON.parse(
  readFileSync("/path/to/arweave/wallet.json").toString(),
);

const processId = await spawn({
  // The Arweave TXID of the ao Module
  module: "module TXID",
  // The Arweave wallet address of a Scheduler Unit
  scheduler: "_GQ33BkPtZrqxA84vM8Zk-N2aO0toNNu_C-l-rawrBA",
  // A signer function containing your wallet
  signer: createDataItemSigner(wallet),
  /*
    Refer to a Processes' source code or documentation
    for tags that may effect its computation.
  */
  tags: [
    { name: "Authority", value: "fcoN_xJeisVsPXA-trzVAuIiqO3ydLQxM-L4XbrQKzY" },
    { name: "Another-Tag", value: "another-value" },
  ],
});
```

## 在浏览器中创建一个进程

```js
import { createDataItemSigner, spawn } from "@permaweb/ao-sdk";

const processId = await spawn({
  // The Arweave TXID of the ao Module
  module: "module TXID",
  // The Arweave wallet address of a Scheduler Unit
  scheduler: "_GQ33BkPtZrqxA84vM8Zk-N2aO0toNNu_C-l-rawrBA",
  // A signer function containing your wallet
  signer: createDataItemSigner(globalThis.arweaveWallet),
  /*
    Refer to a Processes' source code or documentation
    for tags that may effect its computation.
  */
  tags: [
    { name: "Authority", value: "fcoN_xJeisVsPXA-trzVAuIiqO3ydLQxM-L4XbrQKzY" },
    { name: "Another-Tag", value: "another-value" },
  ],
});
```


Prompt: This is a Markdown documentation from the AO documentation repository. Filename: monitoring-cron.md Path: ../ao-cookbook/src/zh/guides/aoconnect/monitoring-cron.md

Response:
# 监控 Cron

当使用 cron 消息时，ao 用户需要一种方式开始接收这些消息，通过使用这个监控方法，ao 用户可以启动 cron 消息的订阅服务。设置 cron 标签意味着你的进程将开始在其发件箱中生成 cron 结果，但如果你希望这些结果中的消息通过网络被推送，则需要监控这些结果。

```js
import { readFileSync } from "node:fs";
import { createDataItemSigner, monitor } from "@permaweb/aoconnect";

const wallet = JSON.parse(
  readFileSync("/path/to/arweave/wallet.json").toString(),
);

const result = await monitor({
  process: "process-id",
  signer: createDataItemSigner(wallet),
});
```

你可以通过调用 unmonitor 来停止监控

```js
import { readFileSync } from "node:fs";
import { createDataItemSigner, unmonitor } from "@permaweb/aoconnect";

const wallet = JSON.parse(
  readFileSync("/path/to/arweave/wallet.json").toString(),
);

const result = await unmonitor({
  process: "process-id",
  signer: createDataItemSigner(wallet),
});
```


Prompt: This is a Markdown documentation from the AO documentation repository. Filename: calling-dryrun.md Path: ../ao-cookbook/src/zh/guides/aoconnect/calling-dryrun.md

Response:
# 调用 DryRun

DryRun 是将消息对象发送到特定进程并获取返回的结果对象的过程，但内存不会被保存，这非常适合创建一个读取消息以返回内存的当前值。例如，一个代币的余额，或者一个转账的结果等。你可以使用 DryRun 来获取输出，而无需发送实际消息

```js
import { createDataItemSigner, dryrun } from "@permaweb/aoconnect";

const result = await dryrun({
  process: 'PROCESSID',
  data: '',
  tags: [{name: 'Action', value: 'Balance'},
  anchor: '1234',
  ...rest are optional (Id, Owner, etc)
});

console.log(result.Messages[0]);
```


Prompt: This is a Markdown documentation from the AO documentation repository. Filename: installing-connect.md Path: ../ao-cookbook/src/zh/guides/aoconnect/installing-connect.md

Response:
# 安装 ao connect

## 先决条件

---

为了在你的应用程序中安装 **ao connect**，你必须安装 NodeJS/NPM 18 或更高版本。

## 安装方法

### 使用 npm 安装

```sh
npm install --save @permaweb/aoconnect
```

### 使用 yarn 安装

```sh
yarn add @permaweb/aoconnect -D
```

安装完成后，你可以在 NodeJS 或 浏览器中使用 **aoconnect**。根据你的项目类型（模块系统），可以按照下面的方式引入 **aoconnect**

#### ESM（Node & 浏览器）即 type: module

```js
import {
  result,
  results,
  message,
  spawn,
  monitor,
  unmonitor,
  dryrun,
} from "@permaweb/aoconnect";
```

#### CJS（Node）即 type: `commonjs`

```js
const {
  result,
  results,
  message,
  spawn,
  monitor,
  unmonitor,
  dryrun,
} = require("@permaweb/aoconnect");
```


Prompt: This is a Markdown documentation from the AO documentation repository. Filename: reading-results.md Path: ../ao-cookbook/src/zh/guides/aoconnect/reading-results.md

Response:
# 从 ao 进程读取结果

在 ao 中，消息产生的结果通过计算单元（CU）提供。结果是包含以下字段的 JSON 对象：messages, spawns, output 和 error。

结果包含ao系统用来发送消息和生成进程的返回值。一个进程可以发送消息，就像你作为开发者可以通过在结果中返回消息和返回值一样。

你可能想要访问一个结果，以显示由你的消息生成的输出。或者，你可能想要看看生成了哪些消息等。你不需要自己取出结果中的消息和返回值并发送它们。它们由消息单元（MU）自动处理。对结果的调用还可以为你提供多个结果的分页列表。

## 获取单个结果

```js
import { result } from "@permaweb/aoconnect";

let { Messages, Spawns, Output, Error } = await result({
  // the arweave TXID of the message
  message: "message-id",
  // the arweave TXID of the process
  process: "process-id",
});
```

## 获取一组结果

```js
import { results } from "@permaweb/aoconnect";

// fetching the first page of results
let resultsOut = await results({
  process: "process-id",
  sort: "ASC",
  limit: 25,
});

// calling more with a cursor
let resultsOut2 = await results({
  process: "process-id",
  from: resultsOut.edges?.[resultsOut.edges.length - 1]?.cursor ?? null,
  sort: "ASC",
  limit: 25,
});
```


Prompt: This is a Markdown documentation from the AO documentation repository. Filename: aoconnect.md Path: ../ao-cookbook/src/zh/guides/aoconnect/aoconnect.md

Response:
---
prev:
  text: "Utils"
  link: "zh/guides/aos/modules/utils"
next:
  text: "安装 aoconnect"
  link: "zh/guides/aoconnect/installing-connect"
---

# aoconnect

**aoconnect** 是一个用于同 NodeJS系统或浏览器交互的 Javascript/Typescript 库。
本节中的指南提供了如何利用 **aoconnect** 的代码片段。所有的代码片段均用 Javascript 编写，但应该很容易转换为 Typescript。


Prompt: This is a Markdown documentation from the AO documentation repository. Filename: sending-messages.md Path: ../ao-cookbook/src/zh/guides/aoconnect/sending-messages.md

Response:
# Sending a Message to a Process

可以在 [ao Messages](../../concepts/messages.md) 概念中找到关于消息的深入探讨。本指南着重于使用 ao connect 向进程发送消息。

发送消息是你的应用与 ao 交互的核心方式。消息是输入到一个进程的。消息有五个部分你可以指定，分别是“目标（target）”，“数据（data）”，“标签（tags）”，“锚点（anchor）”，以及最后的消息“签名（signature）”。

请参考你的进程模块的源代码或文档，以了解消息如何在其计算中使用。ao connect 库将解析你在下面的代码中传递的参数，构造一个消息，并发送它。

## 在 NodeJS 中发送消息

```js
import { readFileSync } from "node:fs";

import { message, createDataItemSigner } from "@permaweb/aoconnect";

const wallet = JSON.parse(
  readFileSync("/path/to/arweave/wallet.json").toString(),
);

// The only 2 mandatory parameters here are process and signer
await message({
  /*
    The arweave TXID of the process, this will become the "target".
    This is the process the message is ultimately sent to.
  */
  process: "process-id",
  // Tags that the process will use as input.
  tags: [
    { name: "Your-Tag-Name-Here", value: "your-tag-value" },
    { name: "Another-Tag", value: "another-value" },
  ],
  // A signer function used to build the message "signature"
  signer: createDataItemSigner(wallet),
  /*
    The "data" portion of the message
    If not specified a random string will be generated
  */
  data: "any data",
})
  .then(console.log)
  .catch(console.error);
```

## 在浏览器中发送消息

```js
import { message, createDataItemSigner } from "@permaweb/aoconnect";

// The only 2 mandatory parameters here are process and signer
await message({
  /*
    The arweave TXID of the process, this will become the "target".
    This is the process the message is ultimately sent to.
  */
  process: "process-id",
  // Tags that the process will use as input.
  tags: [
    { name: "Your-Tag-Name-Here", value: "your-tag-value" },
    { name: "Another-Tag", value: "another-value" },
  ],
  // A signer function used to build the message "signature"
  signer: createDataItemSigner(globalThis.arweaveWallet),
  /*
    The "data" portion of the message.
    If not specified a random string will be generated
  */
  data: "any data",
})
  .then(console.log)
  .catch(console.error);
```


Prompt: This is a Markdown documentation from the AO documentation repository. Filename: connecting.md Path: ../ao-cookbook/src/zh/guides/aoconnect/connecting.md

Response:
# 连接到特定的 ao 节点

在你的代码中包含 **aoconnect** 时，你可以连接到特定的 MU（消息单元）和 CU（计算单元），并能够指定一个 Arweave 网关。这可以通过导入 `connect` 函数并从对 `connect` 函数的调用中提取函数来完成。

你希望了解在发送你的消息时调用了哪个 MU，以便稍后可以从指定的 MU 进行调试。你也可能想要从特定的 CU 读取结果。事实上，你可能出于某种其他原因偏好某个特定的 MU 和 CU。你可以指定其他的网关，默认的网关是即 ：arweave.net

## aoconnect 的导入

```js
// Here aoconnect will implicitly use the default nodes/units
import {
  result,
  results,
  message,
  spawn,
  monitor,
  unmonitor,
  dryrun,
} from "@permaweb/aoconnect";
```

## 连接到特定的 MU, CU, 和网关

```js
import { connect } from "@permaweb/aoconnect";

const { result, results, message, spawn, monitor, unmonitor, dryrun } = connect(
  {
    MU_URL: "https://mu.ao-testnet.xyz",
    CU_URL: "https://cu.ao-testnet.xyz",
    GATEWAY_URL: "https://arweave.net",
  },
);

// now spawn, message, and result can be used the same way as if they were imported directly
```

连接的这三个参数都是可选的，仅指定 1 个或 2 个，或者不指定都是有效的。例如，你可以仅传入 MU_URL。

```js
import { connect } from "@permaweb/aoconnect";

const { result, results, message, spawn, monitor, unmonitor, dryrun } = connect(
  {
    MU_URL: "https://ao-mu-1.onrender.com",
  },
);
```


Prompt: This is a Markdown documentation from the AO documentation repository. Filename: specs.md Path: ../ao-cookbook/src/zh/concepts/specs.md

Response:
# ao 规范

## 什么是 `ao` ？

`ao` 计算机是一个 [actor oriented](https://en.wikipedia.org/wiki/Actor_model) 的机器，它产生于遵守其核心数据协议的节点网络，运行在 [Arweave](https://arweave.org) 网络上。 本文档简要介绍了该协议及其功能以及技术细节，以便构建者可以创建与其集成的新实现和服务。

`ao` 计算机是一个单一的、统一的计算环境（[单系统映像](https://en.wikipedia.org/wiki/Single_system_image)），托管在分布式网络中的一组异构节点上。 `ao` 旨在提供一个环境，其中可以驻留任意数量的并行进程，并通过开放的消息传递层进行协调。 这种消息传递标准将机器的独立运行进程连接到一个 `"网络"` 中，就像网站在独立服务器上运行但通过超链接连接成一个有凝聚力的统一整体。

[了解更多](https://ao.g8way.io/specs)


Prompt: This is a Markdown documentation from the AO documentation repository. Filename: holographic-state.md Path: ../ao-cookbook/src/zh/concepts/holographic-state.md

Response: TODO


Prompt: This is a Markdown documentation from the AO documentation repository. Filename: lua.md Path: ../ao-cookbook/src/zh/concepts/lua.md

Response:
# 走马观花的学习下 Lua

在我们更深入地探索 ao 之前，让我们花点时间学习一下 Lua 的基础知识：你指挥 aos 进程的伙伴。

Lua 是一种简单的语言，没有什么惊喜。 如果你了解 Javascript，你会感觉它是一个简化、更纯粹的版本。 如果你从头开始学习，它看起来像是一门小型语言，专注于重要的事情：使用合理的语法进行极简的计算。

在本节中，我们将在短短几分钟内介绍 Lua 的基础知识。 如果你已经了解 Lua，请直接跳到[下一章](tour.md)

## 跳回到你的 aos 进程

出于本教程的目的，我们假设你已经完成了[入门](/zh/welcome/getting-started) 指南。 如果没有，请先完成。

如果你注销了进程，你可以随时通过在命令行上运行 `aos` 来重新打开它，也可以选择使用 `--wallet [location]` 指定你的密钥文件。

## 基本 Lua 表达式

在本入门书的其余部分中，我们将快速浏览 Lua 的核心功能和语法。

边推进边尝试你的 aos 进程中的示例，如果你觉得很直观明了，则可以跳过它们。

- **基本算术**：尝试一些基本算术，例如 `5 + 3`。 处理后，你将看到结果 `8`。 `+`、`-`、`*`、`/` 和 `^` 都按你的预期工作。 `%` 是 Lua 用于求模的符号。
- **设置变量**：输入 `a = 10` 并按 Enter 键。 这会将变量 `a` 设置为 10。按照惯例（语法上不强制），全局变量在 Lua 中以大写字母开头（例如 `Handlers`）。

- **使用变量**：现在输入 `a * 2`。 你将看到命令行上返回 `20`。
- **字符串连接**：通过执行 `"Hello, " .. ao.id` 向自己说 `Hello`。

## 尝试条件语句

- **If-Else**：与大多数编程语言一样，Lua 使用 if-else 块来有条件地执行代码。

  在你的 aos 进程中，输入 `.editor` 并按 Enter 键。 这将在命令行界面中打开一个内联文本编辑器。

  ```lua
  aos_coolness = 9001
  if aos_coolness > 9000 then
      return "aos is coolness is over 9000!"
  else
      return "Oh. 🤷"
  end
  ```

  在终端上完成编辑后，在新行中输入 `.done` 并按 Enter 键。 这将终止编辑模式并将表达式提交给你的进程进行求值。

  结果，你会看到 `aos is coolness is over 9000!`

  Lua 中的 `if` 语句还可以有额外的 `elseif [condition] then` 块，更便于写多级条件执行语句。

## Lua 中的循环

在 Lua 中循环代码有几种不同的方法。 以下是我们的最爱：

- **While 循环**：

  首先输入 `n = 0` 并按 Enter 键将计数器初始化为零。

  然后使用 `.editor` 再次打开内联编辑器。

  ```lua
  while n < 5 do
    n = n + 1
  end
  ```

  在新行中输入 `.done` 以执行 while 循环。 你只需运行 `n` 即可检查循环结果。

- **For 循环**：

  Lua 还可以在一组值之间执行 python 风格的 `for` 循环。 例如，使用 `.editor` 输入以下代码块：

  ```lua
  for m = 1, 100 do
    n = n + m
  end
  ```

  再次运行 `n` 来得到变量的新值。

## 上手函数

- **定义一个函数**：

  再次使用 `.editor` ，提交以下行：

  ```lua
  function greeting(name)
    return "Hello, " .. name
  end
  ```

  一旦提交，aos 将返回 `undefined`，因为 Lua 中的函数（和变量）定义不返回值。

  Lua 还具有 `匿名` 或 `高阶` 函数。 这些本质上允许你像使用普通数据一样使用函数本身 - 作为参数传递给其他函数等。以下示例定义了一个匿名函数，并且与上面的示例等效：

  ```lua
  greeting =
    function(name)
      return "Hello, " .. name
    end
  ```

- **调用函数**：使用 `greeting("Earthling")` 调用函数。 aos 将返回 `"Hello, Earthling"`。

## 用表定义深层对象

表是Lua 唯一的复合数据结构。 它们将 `键` 映射到 `值`，但也可以像传统数组一样使用。

- **创建一个简单的表**：输入 `ao_is = {"hyper", "parallel", "compute"}` 来创建一个简单的表。
- **访问表的元素**：使用 `ao_is[2]` 访问元素。 aos 将返回 `parallel`。 注意：Lua 中的下标是从 1 开始的！
- **统计表的元素**：Lua 中表的大小是通过运算符 `#` 读取的。 例如，运行 `#ao_is` 将返回 `3`。
- **设置命名元素**：输入 `ao_is["cool"] = true` 以向表中添加新的命名键。 命名元素也可以使用 `.` 运算符访问，例如 `ao_is.cool`。

## Lua 注意事项

aos 使用 Lua 是因为它是一种简单、明了的语言，大多数有经验的程序员都可以很快学会，而且由于它在 Roblox 等视频游戏中的使用，它也是一种越来越流行的首选编程语言。

尽管如此，该语言的一些问题很容易让新手 Lua 构建者犯错。 口味可能会有所不同，但以下是我们的 Lua [wat](https://www.destroyallsoftware.com/talks/wat) 的详尽列表：

- **记住：** 表索引从 1 开始，而不是 0！
- **记住：** `不等于` 用 `~=` 表示，而不是 `!=` 或类似的。
- **记住：** Lua 中的对象被称为 `表`，而不是它们更常见的名称。

## 继续前行

记住这些，你现在已经了解了使用 Lua 构建出色的去中心化进程所需的一切！ 在下一章中，我们将开始使用 Lua 和 aos 构建并行进程。


Prompt: This is a Markdown documentation from the AO documentation repository. Filename: index.md Path: ../ao-cookbook/src/zh/concepts/index.md

Response:
---
prev:
  text: "监控 Cron"
  link: "/zh/guides/aoconnect/monitoring-cron"
next:
  text: "规范"
  link: "./specs"
---

# 概念

ao在设计中内置了很多概念，但核心概念都是非常简单的原则：

- 两种核心类型：消息和进程
- 没有共享状态，只有全息状态
- 去中心化计算机（网格）

下面是一组概念文档，将 ao 系统分解为不同的部分。

- [规范](specs)
- [进程](processes)
- [消息](messages)
- [单元](units)
- [消息传递的工作原理](how-it-works)

[[toc]]


Prompt: This is a Markdown documentation from the AO documentation repository. Filename: processes.md Path: ../ao-cookbook/src/zh/concepts/processes.md

Response:
# 进程

进程之间具有通过消息传递进行通信的能力，包括在网络内接收和发送消息。 此外，它们还具有实例化更多进程的潜力，从而增强网络的计算结构。这种网络内数据传播和交互的动态方法被称为 `全息状态`，支撑网络状态的共享和持久化。

![流程图](process-diagram.png)

当使用 `aos` 构建进程时，你可以添加`处理程序`(`handlers`)，可以通过调用 `Handlers.add` 函数并传递 “name”、“match”函数和“handle”函数来添加这些处理程序。

![处理程序图](handler-diagram.png)

核心模块包含一个注入到处理函数中的帮助程序库，该库称为 `ao`。

```lua
{
    env = {
        Process = {
            Id = "5WzR7rJCuqCKEq02WUPhTjwnzllLjGu6SA7qhYpcKRs",
            Owner = "_r9LpP4FtClpsGX3TOohubyaeb0IQTZZMcxQ24tTsGo",
            Tags = {...}
        },
        Module = {
            Id = "UAUszdznoUPQvXRbrFuIIH6J0N_LnJ1h4Trej28UgrE",
            Owner = "_r9LpP4FtClpsGX3TOohubyaeb0IQTZZMcxQ24tTsGo",
            Tags = {..}
        }
    },
    id = "5WzR7rJCuqCKEq02WUPhTjwnzllLjGu6SA7qhYpcKRs",
    isTrusted = "function: 0x5468d0",
    result = "function: 0x547120",
    send = "function: 0x547618",
    spawn = "function: 0x5468b0"
}
```

在这个 `ao` 辅助库中要查看的主要函数是

- ao.send(Message) - 向进程发送消息
- ao.spawn(Module, Message) - 创建一个新进程

## ao.send 示例

```lua
ao.send({
    Target = Chatroom,
    Action = "Broadcast",
    Data = "Hello from my Process!"
})
```

## ao.spawn 示例

```lua
ao.spawn(ao.env.Module.Id, {
    ["Memory-Limit"] = "500-mb",
    ["Compute-Limit"] = "900000000000000000"
})
```

## ao.env

> 注意：`ao.env` 是开发人员创建进程时可能要用到的重要上下文数据。

`ao.env` 属性包含 `Process` 和 `Module` 引用对象

```lua
env = {
    Process = {
        Id = "5WzR7rJCuqCKEq02WUPhTjwnzllLjGu6SA7qhYpcKRs",
        Owner = "_r9LpP4FtClpsGX3TOohubyaeb0IQTZZMcxQ24tTsGo",
        Tags = {...}
    },
    Module = {
        Id = "UAUszdznoUPQvXRbrFuIIH6J0N_LnJ1h4Trej28UgrE",
        Owner = "_r9LpP4FtClpsGX3TOohubyaeb0IQTZZMcxQ24tTsGo",
        Tags = {..}
    }
}
```

`Process` 和 `Module` 都包含 `ao` 数据协议的属性。

## 概括

网络中的进程通过消息传递进行通信，并且可以创建新进程，从而形成共享和持久数据的 `"全息状态"`。 开发人员可以使用 `aos` 构建进程，通过 `Handlers.add` 函数添加具有特定名称、以及匹配和处理函数的处理程序。 核心模块中的 `ao` 辅助库有助于此过程，提供 `ao.send` 函数来分发消息以及 `ao.spawn` 函数来创建新模块，以及同等重要的 `ao.env` 属性，它包含进程和模块的必要信息。`ao` 数据协议概述了这些元素的结构和属性。


Prompt: This is a Markdown documentation from the AO documentation repository. Filename: tour.md Path: ../ao-cookbook/src/zh/concepts/tour.md

Response:
# aos 简明教程

欢迎来到 aos 快速入门！本教程将引导你了解 aos 环境中可用的关键全局函数和变量，让你对如何有效地与 aos 交互和使用有基本的了解。

## 1.收件箱(Inbox)简介

- **它是什么**：`Inbox` 是一个 Lua 表，用于存储进程收到但尚未处理的所有消息。
- **如何使用**：直接输入 `Inbox` 可以查看传入的消息。 迭代 `Inbox[x]` 来处理这些消息。

## 2. 使用 `Send(Message)` 发送消息

- **功能**：`Send(Message)` 是一个向其他进程发送消息的全局函数。
- **使用示例**：`Send({Target = "...", Data = "Hello, Process!"})` 发送一条带有数据 `Hello, Process!` 的消息到指定的进程。

## 3. 使用 `Spawn(Module, Message)` 创建进程

- **目的**：使用 `Spawn(Module, Message)` 创建新进程。
- **示例**：`Spawn("MyModule", {Data = "Start"})` 使用 `MyModule` 和提供的消息启动一个新进程。

## 4. 理解名称(Name)和所有者(Owner)

- **名称**：初始化时设置的字符串，代表进程的名称。
- **所有者**：表示进程的所有者。 更改此值可能会限制你与流程交互的能力。
- **重要提示**：将它们视为只读以避免出现问题。

## 5. 使用处理程序(Handlers)

- **它们是什么**：`Handlers` 是用于创建消息处理程序的辅助函数表。
- **用法**：在 `Handlers` 中定义处理程序，以根据模式匹配给不同的消息指定对应操作。

## 6. 使用 `Dump` 进行数据展示

- **功能**：`Dump` 将任何 Lua 表转换为适合打印的格式。
- **如何使用**：对于调试或查看复杂的表结构很有用。 示例：`Dump(Inbox)` 打印 `Inbox` 的内容。

## 7. 用好 Utils 模块

- **内容**：Utils 包含一系列功能实用程序，如 `map`、`reduce`和`filter`。
- **用法**：非常适合 Lua 中的数据操作和函数式编程模式。 例如，`Utils.map(myTable, function(x) return x * 2 end)` 将表中的值加倍。

## 8. 探索 ao 核心库

- **描述**：`ao` 是一个核心模块，包括消息处理和进程管理的关键功能。
- **主要功能**：包括发送消息（`send`）和生成进程（`spawn`）的函数以及环境变量。

## 结论

此简明教程向你介绍了 aos 环境中的主要全局变量和功能。 有了这些工具(在手边)，你可以创建和管理进程、处理消息，并利用 Lua 的功能在 aos 平台上构建高效且响应迅速的应用程序。 尝试这些功能以更深入地了解以便明白如何将它们集成到你的特定用例中。 在 aos 中玩的开心！